1 /* source: xio-udp.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this file contains the source for handling UDP addresses */
7 #include "xiosysincludes.h"
9 #if WITH_UDP && (WITH_IP4 || WITH_IP6)
12 #include "xio-socket.h"
16 #include "xio-ipapp.h"
17 #include "xio-tcpwrap.h"
23 int xioopen_udp_sendto(int argc
, const char *argv
[], struct opt
*opts
,
24 int xioflags
, xiofile_t
*xfd
, unsigned groups
,
25 int pf
, int socktype
, int ipproto
);
27 int xioopen_udp_datagram(int argc
, const char *argv
[], struct opt
*opts
,
28 int xioflags
, xiofile_t
*xfd
, unsigned groups
,
29 int pf
, int socktype
, int ipproto
);
31 int xioopen_udp_recvfrom(int argc
, const char *argv
[], struct opt
*opts
,
32 int xioflags
, xiofile_t
*xfd
, unsigned groups
,
33 int pf
, int socktype
, int ipproto
);
35 int xioopen_udp_recv(int argc
, const char *argv
[], struct opt
*opts
,
36 int xioflags
, xiofile_t
*xfd
, unsigned groups
,
37 int pf
, int socktype
, int ipproto
);
40 int _xioopen_udp_sendto(const char *hostname
, const char *servname
,
42 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
43 int pf
, int socktype
, int ipproto
);
45 const struct addrdesc addr_udp_connect
= { "udp-connect", 3, xioopen_ipapp_connect
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP4
|GROUP_SOCK_IP6
|GROUP_IP_UDP
, SOCK_DGRAM
, IPPROTO_UDP
, PF_UNSPEC
HELP(":<host>:<port>") };
47 const struct addrdesc addr_udp_listen
= { "udp-listen", 3, xioopen_ipdgram_listen
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP4
|GROUP_SOCK_IP6
|GROUP_IP_UDP
|GROUP_LISTEN
|GROUP_CHILD
|GROUP_RANGE
, PF_UNSPEC
, IPPROTO_UDP
, PF_UNSPEC
HELP(":<port>") };
48 #endif /* WITH_LISTEN */
49 const struct addrdesc addr_udp_sendto
= { "udp-sendto", 3, xioopen_udp_sendto
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP4
|GROUP_SOCK_IP6
|GROUP_IP_UDP
, PF_UNSPEC
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<host>:<port>") };
50 const struct addrdesc addr_udp_recvfrom
= { "udp-recvfrom", 3, xioopen_udp_recvfrom
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP4
|GROUP_SOCK_IP6
|GROUP_IP_UDP
|GROUP_CHILD
|GROUP_RANGE
, PF_UNSPEC
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<port>") };
51 const struct addrdesc addr_udp_recv
= { "udp-recv", 1, xioopen_udp_recv
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP4
|GROUP_SOCK_IP6
|GROUP_IP_UDP
|GROUP_RANGE
, PF_UNSPEC
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<port>") };
52 const struct addrdesc addr_udp_datagram
= { "udp-datagram", 3, xioopen_udp_datagram
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP4
|GROUP_SOCK_IP6
|GROUP_IP_UDP
|GROUP_RANGE
, PF_UNSPEC
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<host>:<port>") };
55 const struct addrdesc addr_udp4_connect
= { "udp4-connect", 3, xioopen_ipapp_connect
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP4
|GROUP_IP_UDP
, SOCK_DGRAM
, IPPROTO_UDP
, PF_INET
HELP(":<host>:<port>") };
57 const struct addrdesc addr_udp4_listen
= { "udp4-listen", 3, xioopen_ipdgram_listen
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP4
|GROUP_IP_UDP
|GROUP_LISTEN
|GROUP_CHILD
|GROUP_RANGE
, PF_INET
, IPPROTO_UDP
, PF_INET
HELP(":<port>") };
58 #endif /* WITH_LISTEN */
59 const struct addrdesc addr_udp4_sendto
= { "udp4-sendto", 3, xioopen_udp_sendto
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP4
|GROUP_IP_UDP
, PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<host>:<port>") };
60 const struct addrdesc addr_udp4_datagram
= { "udp4-datagram",3, xioopen_udp_datagram
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP4
|GROUP_IP_UDP
|GROUP_RANGE
, PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<host>:<port>") };
61 const struct addrdesc addr_udp4_recvfrom
= { "udp4-recvfrom", 3, xioopen_udp_recvfrom
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP4
|GROUP_IP_UDP
|GROUP_CHILD
|GROUP_RANGE
, PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<port>") };
62 const struct addrdesc addr_udp4_recv
= { "udp4-recv", 1, xioopen_udp_recv
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP4
|GROUP_IP_UDP
|GROUP_RANGE
, PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<port>") };
66 const struct addrdesc addr_udp6_connect
= { "udp6-connect", 3, xioopen_ipapp_connect
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP6
|GROUP_IP_UDP
, SOCK_DGRAM
, IPPROTO_UDP
, PF_INET6
HELP(":<host>:<port>") };
68 const struct addrdesc addr_udp6_listen
= { "udp6-listen", 3, xioopen_ipdgram_listen
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP6
|GROUP_IP_UDP
|GROUP_LISTEN
|GROUP_CHILD
|GROUP_RANGE
, PF_INET6
, IPPROTO_UDP
, 0 HELP(":<port>") };
69 #endif /* WITH_LISTEN */
70 const struct addrdesc addr_udp6_sendto
= { "udp6-sendto", 3, xioopen_udp_sendto
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP6
|GROUP_IP_UDP
, PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<host>:<port>") };
71 const struct addrdesc addr_udp6_datagram
= { "udp6-datagram", 3, xioopen_udp_datagram
,GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP6
|GROUP_IP_UDP
|GROUP_RANGE
, PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<host>:<port>") };
72 const struct addrdesc addr_udp6_recvfrom
= { "udp6-recvfrom", 3, xioopen_udp_recvfrom
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP6
|GROUP_IP_UDP
|GROUP_CHILD
|GROUP_RANGE
, PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<port>") };
73 const struct addrdesc addr_udp6_recv
= { "udp6-recv", 1, xioopen_udp_recv
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP6
|GROUP_IP_UDP
|GROUP_RANGE
, PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<port>") };
77 int _xioopen_ipdgram_listen(struct single
*sfd
,
78 int xioflags
, union sockaddr_union
*us
, socklen_t uslen
,
79 struct opt
*opts
, int pf
, int socktype
, int ipproto
) {
80 union sockaddr_union themunion
;
81 union sockaddr_union
*them
= &themunion
;
88 unsigned char buff1
[1];
92 retropt_bool(opts
, OPT_FORK
, &dofork
);
95 if (!(xioflags
& XIO_MAYFORK
)) {
96 Error("option fork not allowed here");
101 retropt_int(opts
, OPT_MAX_CHILDREN
, &maxchildren
);
103 if (! dofork
&& maxchildren
) {
104 Error("option max-children not allowed without option fork");
108 #if WITH_IP4 /*|| WITH_IP6*/
109 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
110 if (xioparserange(rangename
, pf
, &sfd
->para
.socket
.range
) < 0) {
115 sfd
->para
.socket
.dorange
= true;
120 xio_retropt_tcpwrap(sfd
, opts
);
121 #endif /* WITH_LIBWRAP */
123 if (retropt_ushort(opts
, OPT_SOURCEPORT
, &sfd
->para
.socket
.ip
.sourceport
)
125 sfd
->para
.socket
.ip
.dosourceport
= true;
127 retropt_bool(opts
, OPT_LOWPORT
, &sfd
->para
.socket
.ip
.lowport
);
130 xiosetchilddied(); /* set SIGCHLD handler */
133 while (true) { /* we loop with fork or prohibited packets */
134 /* now wait for some packet on this datagram socket, get its sender
135 address, connect there, and return */
136 int reuseaddr
= dofork
;
137 int doreuseaddr
= (dofork
!= 0);
139 union sockaddr_union _sockname
;
140 union sockaddr_union
*la
= &_sockname
; /* local address */
142 if ((sfd
->fd
= xiosocket(opts
, pf
, socktype
, ipproto
, E_ERROR
)) < 0) {
143 return STAT_RETRYLATER
;
145 doreuseaddr
|= (retropt_int(opts
, OPT_SO_REUSEADDR
, &reuseaddr
) >= 0);
146 applyopts(sfd
->fd
, opts
, PH_PASTSOCKET
);
148 if (Setsockopt(sfd
->fd
, opt_so_reuseaddr
.major
,
149 opt_so_reuseaddr
.minor
, &reuseaddr
, sizeof(reuseaddr
))
151 Warn6("setsockopt(%d, %d, %d, {%d}, "F_Zd
"): %s",
152 sfd
->fd
, opt_so_reuseaddr
.major
,
153 opt_so_reuseaddr
.minor
, reuseaddr
, sizeof(reuseaddr
),
157 applyopts_cloexec(sfd
->fd
, opts
);
158 applyopts(sfd
->fd
, opts
, PH_PREBIND
);
159 applyopts(sfd
->fd
, opts
, PH_BIND
);
160 if (Bind(sfd
->fd
, &us
->soa
, uslen
) < 0) {
161 Error4("bind(%d, {%s}, "F_socklen
"): %s", sfd
->fd
,
162 sockaddr_info(&us
->soa
, uslen
, infobuff
, sizeof(infobuff
)),
163 uslen
, strerror(errno
));
164 return STAT_RETRYLATER
;
166 /* under some circumstances bind() fills sockaddr with interesting info. */
167 if (Getsockname(sfd
->fd
, &us
->soa
, &uslen
) < 0) {
168 Error4("getsockname(%d, %p, {%d}): %s",
169 sfd
->fd
, &us
->soa
, uslen
, strerror(errno
));
171 applyopts(sfd
->fd
, opts
, PH_PASTBIND
);
173 if (ipproto
== IPPROTO_UDP
) {
174 Notice1("listening on UDP %s",
175 sockaddr_info(&us
->soa
, uslen
, infobuff
, sizeof(infobuff
)));
177 Notice2("listening on PROTO%d %s", ipproto
,
178 sockaddr_info(&us
->soa
, uslen
, infobuff
, sizeof(infobuff
)));
182 readfd
.events
= POLLIN
|POLLERR
;
183 while (xiopoll(&readfd
, 1, NULL
) < 0) {
184 if (errno
!= EINTR
) break;
187 themlen
= socket_init(pf
, them
);
189 result
= Recvfrom(sfd
->fd
, buff1
, 1, MSG_PEEK
,
190 &them
->soa
, &themlen
);
191 } while (result
< 0 && errno
== EINTR
);
193 Error5("recvfrom(%d, %p, 1, MSG_PEEK, {%s}, {"F_socklen
"}): %s",
195 sockaddr_info(&them
->soa
, themlen
, infobuff
, sizeof(infobuff
)),
196 themlen
, strerror(errno
));
197 return STAT_RETRYLATER
;
200 Notice1("accepting UDP connection from %s",
201 sockaddr_info(&them
->soa
, themlen
, infobuff
, sizeof(infobuff
)));
203 if (xiocheckpeer(sfd
, them
, la
) < 0) {
204 Notice1("forbidding UDP connection from %s",
205 sockaddr_info(&them
->soa
, themlen
,
206 infobuff
, sizeof(infobuff
)));
209 Recv(sfd
->fd
, buff
, sizeof(buff
), 0); /* drop packet */
213 Info1("permitting UDP connection from %s",
214 sockaddr_info(&them
->soa
, themlen
, infobuff
, sizeof(infobuff
)));
217 pid
= xio_fork(false, E_ERROR
);
219 return STAT_RETRYLATER
;
222 if (pid
== 0) { /* child */
223 pid_t cpid
= Getpid();
224 xiosetenvulong("PID", cpid
, 1);
228 /* server: continue loop with socket()+recvfrom() */
229 /* when we dont close this we get awkward behaviour on Linux 2.4:
230 recvfrom gives 0 bytes with invalid socket address */
231 if (Close(sfd
->fd
) < 0) {
232 Info2("close(%d): %s", sfd
->fd
, strerror(errno
));
235 while (maxchildren
) {
236 if (num_child
< maxchildren
) break;
237 Notice("maxchildren are active, waiting");
238 /* UINT_MAX would even be nicer, but Openindiana works only
240 while (!Sleep(INT_MAX
)) ; /* any signal lets us continue */
242 Info("still listening");
246 } /* end of the big while loop */
248 applyopts(sfd
->fd
, opts
, PH_CONNECT
);
249 if ((result
= Connect(sfd
->fd
, &them
->soa
, themlen
)) < 0) {
250 Error4("connect(%d, {%s}, "F_socklen
"): %s",
252 sockaddr_info(&them
->soa
, themlen
, infobuff
, sizeof(infobuff
)),
253 themlen
, strerror(errno
));
254 return STAT_RETRYLATER
;
257 /* set the env vars describing the local and remote sockets */
258 if (Getsockname(sfd
->fd
, &us
->soa
, &uslen
) < 0) {
259 Warn4("getsockname(%d, %p, {%d}): %s",
260 sfd
->fd
, &us
->soa
, uslen
, strerror(errno
));
262 xiosetsockaddrenv("SOCK", us
, uslen
, IPPROTO_UDP
);
263 xiosetsockaddrenv("PEER", them
, themlen
, IPPROTO_UDP
);
265 sfd
->howtoend
= END_SHUTDOWN
;
266 applyopts_fchown(sfd
->fd
, opts
);
267 applyopts(sfd
->fd
, opts
, PH_LATE
);
269 if ((result
= _xio_openlate(sfd
, opts
)) < 0)
275 /* we expect the form: port */
276 int xioopen_ipdgram_listen(int argc
, const char *argv
[], struct opt
*opts
,
277 int xioflags
, xiofile_t
*fd
,
278 unsigned groups
, int pf
, int ipproto
,
280 const char *portname
= argv
[1];
281 union sockaddr_union us
;
282 int socktype
= SOCK_DGRAM
;
286 Error2("%s: wrong number of parameters (%d instead of 1)", argv
[0], argc
-1);
289 if (pf
== PF_UNSPEC
) {
290 #if WITH_IP4 && WITH_IP6
291 pf
= xioopts
.default_ip
=='6'?PF_INET6
:PF_INET
;
299 retropt_socket_pf(opts
, &pf
);
300 retropt_int(opts
, OPT_SO_PROTOTYPE
, &ipproto
);
302 if (applyopts_single(&fd
->stream
, opts
, PH_INIT
) < 0) return -1;
303 applyopts(-1, opts
, PH_INIT
);
305 uslen
= socket_init(pf
, &us
);
306 retropt_bind(opts
, pf
, socktype
, ipproto
,
307 (struct sockaddr
*)&us
, &uslen
, 1,
308 fd
->stream
.para
.socket
.ip
.res_opts
[1],
309 fd
->stream
.para
.socket
.ip
.res_opts
[0]);
314 } else if (pf
== PF_INET
) {
315 us
.ip4
.sin_port
= parseport(portname
, ipproto
);
318 } else if (pf
== PF_INET6
) {
319 us
.ip6
.sin6_port
= parseport(portname
, ipproto
);
322 Error1("xioopen_ipdgram_listen(): unknown address family %d", pf
);
325 return _xioopen_ipdgram_listen(&fd
->stream
, xioflags
, &us
, uslen
,
326 opts
, pf
, socktype
, ipproto
);
330 int xioopen_udp_sendto(int argc
, const char *argv
[], struct opt
*opts
,
331 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
332 int pf
, int socktype
, int ipproto
) {
336 Error2("%s: wrong number of parameters (%d instead of 2)",
341 retropt_socket_pf(opts
, &pf
);
342 if ((result
= _xioopen_udp_sendto(argv
[1], argv
[2], opts
, xioflags
, xxfd
,
343 groups
, pf
, socktype
, ipproto
))
347 _xio_openlate(&xxfd
->stream
, opts
);
352 applies and consumes the following option:
353 PH_INIT, PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE
355 OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
358 int _xioopen_udp_sendto(const char *hostname
, const char *servname
,
360 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
361 int pf
, int socktype
, int ipproto
) {
362 xiosingle_t
*xfd
= &xxfd
->stream
;
363 union sockaddr_union us
;
365 int feats
= 3; /* option bind supports address and port */
366 bool needbind
= false;
369 xfd
->howtoend
= END_SHUTDOWN
;
372 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return -1;
373 applyopts(-1, opts
, PH_INIT
);
375 xfd
->salen
= sizeof(xfd
->peersa
);
377 xiogetaddrinfo(hostname
, servname
, pf
, socktype
, ipproto
,
378 &xfd
->peersa
, &xfd
->salen
,
379 xfd
->para
.socket
.ip
.res_opts
[0],
380 xfd
->para
.socket
.ip
.res_opts
[1]))
384 if (pf
== PF_UNSPEC
) {
385 pf
= xfd
->peersa
.soa
.sa_family
;
387 uslen
= socket_init(pf
, &us
);
388 if (retropt_bind(opts
, pf
, socktype
, ipproto
, &us
.soa
, &uslen
, feats
,
389 xfd
->para
.socket
.ip
.res_opts
[0],
390 xfd
->para
.socket
.ip
.res_opts
[1])
395 if (retropt_ushort(opts
, OPT_SOURCEPORT
,
396 &xfd
->para
.socket
.ip
.sourceport
) >= 0) {
400 us
.ip4
.sin_port
= htons(xfd
->para
.socket
.ip
.sourceport
);
405 us
.ip6
.sin6_port
= htons(xfd
->para
.socket
.ip
.sourceport
);
412 retropt_bool(opts
, OPT_LOWPORT
, &xfd
->para
.socket
.ip
.lowport
);
413 if (xfd
->para
.socket
.ip
.lowport
) {
417 /*!!! this is buggy */
418 us
.ip4
.sin_port
= htons(xfd
->para
.socket
.ip
.lowport
); break;
422 /*!!! this is buggy */
423 us
.ip6
.sin6_port
= htons(xfd
->para
.socket
.ip
.lowport
); break;
429 xfd
->dtype
= XIODATA_RECVFROM
;
430 return _xioopen_dgram_sendto(needbind
?&us
:NULL
, uslen
,
431 opts
, xioflags
, xfd
, groups
,
432 pf
, socktype
, ipproto
);
437 int xioopen_udp_datagram(int argc
, const char *argv
[], struct opt
*opts
,
438 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
439 int pf
, int socktype
, int ipproto
) {
440 xiosingle_t
*xfd
= &xxfd
->stream
;
446 Error2("%s: wrong number of parameters (%d instead of 2)",
451 if ((hostname
= strdup(argv
[1])) == NULL
) {
452 Error1("strdup(\"%s\"): out of memory", argv
[1]);
453 return STAT_RETRYLATER
;
456 /* only accept packets with correct remote ports */
457 if (retropt_ushort(opts
, OPT_SOURCEPORT
, &xfd
->para
.socket
.ip
.sourceport
)
459 xfd
->para
.socket
.ip
.dosourceport
= true;
460 xfd
->para
.socket
.ip
.sourceport
= ntohs(xfd
->peersa
.ip4
.sin_port
);
463 retropt_socket_pf(opts
, &pf
);
465 _xioopen_udp_sendto(hostname
, argv
[2], opts
, xioflags
, xxfd
, groups
,
466 pf
, socktype
, ipproto
);
468 if (result
!= STAT_OK
) {
472 xfd
->dtype
= XIOREAD_RECV
|XIOWRITE_SENDTO
;
474 xfd
->para
.socket
.la
.soa
.sa_family
= xfd
->peersa
.soa
.sa_family
;
476 /* which reply packets will be accepted - determine by range option */
477 if (retropt_string(opts
, OPT_RANGE
, &rangename
)
479 if (xioparserange(rangename
, pf
, &xfd
->para
.socket
.range
) < 0) {
483 xfd
->para
.socket
.dorange
= true;
484 xfd
->dtype
|= XIOREAD_RECV_CHECKRANGE
;
489 xio_retropt_tcpwrap(xfd
, opts
);
490 #endif /* WITH_LIBWRAP */
492 _xio_openlate(xfd
, opts
);
498 int xioopen_udp_recvfrom(int argc
, const char *argv
[], struct opt
*opts
,
499 int xioflags
, xiofile_t
*xfd
, unsigned groups
,
500 int pf
, int socktype
, int ipproto
) {
501 union sockaddr_union us
;
502 socklen_t uslen
= sizeof(us
);
506 Error2("%s: wrong number of parameters (%d instead of 1)",
511 xfd
->stream
.howtoend
= END_NONE
;
512 retropt_socket_pf(opts
, &pf
);
513 if (pf
== PF_UNSPEC
) {
514 #if WITH_IP4 && WITH_IP6
515 pf
= xioopts
.default_ip
=='6'?PF_INET6
:PF_INET
;
524 xiogetaddrinfo(NULL
, argv
[1], pf
, socktype
, ipproto
,
525 &us
, &uslen
, xfd
->stream
.para
.socket
.ip
.res_opts
[0],
526 xfd
->stream
.para
.socket
.ip
.res_opts
[1]))
530 if (pf
== PF_UNSPEC
) {
531 pf
= us
.soa
.sa_family
;
535 union sockaddr_union la
;
536 socklen_t lalen
= sizeof(la
);
538 if (retropt_bind(opts
, pf
, socktype
, ipproto
, &la
.soa
, &lalen
, 1,
539 xfd
->stream
.para
.socket
.ip
.res_opts
[0],
540 xfd
->stream
.para
.socket
.ip
.res_opts
[1])
544 case PF_INET
: us
.ip4
.sin_addr
= la
.ip4
.sin_addr
; break;
547 case PF_INET6
: us
.ip6
.sin6_addr
= la
.ip6
.sin6_addr
; break;
553 if (retropt_ushort(opts
, OPT_SOURCEPORT
, &xfd
->stream
.para
.socket
.ip
.sourceport
) >= 0) {
554 xfd
->stream
.para
.socket
.ip
.dosourceport
= true;
556 retropt_bool(opts
, OPT_LOWPORT
, &xfd
->stream
.para
.socket
.ip
.lowport
);
558 xfd
->stream
.dtype
= XIODATA_RECVFROM_ONE
;
560 _xioopen_dgram_recvfrom(&xfd
->stream
, xioflags
, &us
.soa
, uslen
,
561 opts
, pf
, socktype
, ipproto
, E_ERROR
))
565 _xio_openlate(&xfd
->stream
, opts
);
571 int xioopen_udp_recv(int argc
, const char *argv
[], struct opt
*opts
,
572 int xioflags
, xiofile_t
*xfd
, unsigned groups
,
573 int pf
, int socktype
, int ipproto
) {
574 union sockaddr_union us
;
575 socklen_t uslen
= sizeof(us
);
580 Error2("%s: wrong number of parameters (%d instead of 1)",
585 retropt_socket_pf(opts
, &pf
);
586 if (pf
== PF_UNSPEC
) {
587 #if WITH_IP4 && WITH_IP6
588 pf
= xioopts
.default_ip
=='6'?PF_INET6
:PF_INET
;
597 xiogetaddrinfo(NULL
, argv
[1], pf
, socktype
, ipproto
,
598 &us
, &uslen
, xfd
->stream
.para
.socket
.ip
.res_opts
[0],
599 xfd
->stream
.para
.socket
.ip
.res_opts
[1]))
603 if (pf
== PF_UNSPEC
) {
604 pf
= us
.soa
.sa_family
;
609 union sockaddr_union la
;
610 socklen_t lalen
= sizeof(la
);
612 if (retropt_bind(opts
, pf
, socktype
, ipproto
,
613 &xfd
->stream
.para
.socket
.la
.soa
, &lalen
, 1,
614 xfd
->stream
.para
.socket
.ip
.res_opts
[0],
615 xfd
->stream
.para
.socket
.ip
.res_opts
[1])
620 us
.ip4
.sin_addr
= xfd
->stream
.para
.socket
.la
.ip4
.sin_addr
; break;
624 us
.ip6
.sin6_addr
= xfd
->stream
.para
.socket
.la
.ip6
.sin6_addr
; break;
628 xfd
->stream
.para
.socket
.la
.soa
.sa_family
= pf
;
633 #if WITH_IP4 /*|| WITH_IP6*/
634 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
635 if (xioparserange(rangename
, pf
, &xfd
->stream
.para
.socket
.range
) < 0) {
638 xfd
->stream
.para
.socket
.dorange
= true;
643 xio_retropt_tcpwrap(&xfd
->stream
, opts
);
644 #endif /* WITH_LIBWRAP */
646 if (retropt_ushort(opts
, OPT_SOURCEPORT
,
647 &xfd
->stream
.para
.socket
.ip
.sourceport
)
649 xfd
->stream
.para
.socket
.ip
.dosourceport
= true;
651 retropt_bool(opts
, OPT_LOWPORT
, &xfd
->stream
.para
.socket
.ip
.lowport
);
653 xfd
->stream
.dtype
= XIODATA_RECV
;
654 if ((result
= _xioopen_dgram_recv(&xfd
->stream
, xioflags
, &us
.soa
, uslen
,
655 opts
, pf
, socktype
, ipproto
, E_ERROR
))
659 _xio_openlate(&xfd
->stream
, opts
);
663 #endif /* WITH_UDP && (WITH_IP4 || WITH_IP6) */