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(":<remote-address>:<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(":<host>:<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 /* we expect the form: port */
78 int xioopen_ipdgram_listen(int argc
, const char *argv
[], struct opt
*opts
,
79 int xioflags
, xiofile_t
*fd
,
80 unsigned groups
, int pf
, int ipproto
,
82 const char *portname
= argv
[1];
83 union sockaddr_union us
;
84 union sockaddr_union themunion
;
85 union sockaddr_union
*them
= &themunion
;
86 int socktype
= SOCK_DGRAM
;
93 unsigned char buff1
[1];
99 Error2("%s: wrong number of parameters (%d instead of 1)", argv
[0], argc
-1);
102 if (pf
== PF_UNSPEC
) {
103 #if WITH_IP4 && WITH_IP6
104 pf
= xioopts
.default_ip
=='6'?PF_INET6
:PF_INET
;
112 retropt_socket_pf(opts
, &pf
);
114 if (applyopts_single(&fd
->stream
, opts
, PH_INIT
) < 0) return -1;
115 applyopts(-1, opts
, PH_INIT
);
117 uslen
= socket_init(pf
, &us
);
118 retropt_bind(opts
, pf
, socktype
, IPPROTO_UDP
,
119 (struct sockaddr
*)&us
, &uslen
, 1,
120 fd
->stream
.para
.socket
.ip
.res_opts
[1],
121 fd
->stream
.para
.socket
.ip
.res_opts
[0]);
126 } else if (pf
== PF_INET
) {
127 us
.ip4
.sin_port
= parseport(portname
, ipproto
);
130 } else if (pf
== PF_INET6
) {
131 us
.ip6
.sin6_port
= parseport(portname
, ipproto
);
134 Error1("xioopen_ipdgram_listen(): unknown address family %d", pf
);
137 retropt_bool(opts
, OPT_FORK
, &dofork
);
140 if (!(xioflags
& XIO_MAYFORK
)) {
141 Error("option fork not allowed here");
146 retropt_int(opts
, OPT_MAX_CHILDREN
, &maxchildren
);
148 if (! dofork
&& maxchildren
) {
149 Error("option max-children not allowed without option fork");
153 #if WITH_IP4 /*|| WITH_IP6*/
154 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
155 if (xioparserange(rangename
, pf
, &fd
->stream
.para
.socket
.range
) < 0) {
160 fd
->stream
.para
.socket
.dorange
= true;
165 xio_retropt_tcpwrap(&fd
->stream
, opts
);
166 #endif /* WITH_LIBWRAP */
168 if (retropt_ushort(opts
, OPT_SOURCEPORT
, &fd
->stream
.para
.socket
.ip
.sourceport
)
170 fd
->stream
.para
.socket
.ip
.dosourceport
= true;
172 retropt_bool(opts
, OPT_LOWPORT
, &fd
->stream
.para
.socket
.ip
.lowport
);
175 xiosetchilddied(); /* set SIGCHLD handler */
178 while (true) { /* we loop with fork or prohibited packets */
179 /* now wait for some packet on this datagram socket, get its sender
180 address, connect there, and return */
181 int reuseaddr
= dofork
;
182 int doreuseaddr
= (dofork
!= 0);
184 union sockaddr_union _sockname
;
185 union sockaddr_union
*la
= &_sockname
; /* local address */
187 if ((fd
->stream
.fd
= xiosocket(opts
, pf
, socktype
, ipproto
, E_ERROR
)) < 0) {
188 return STAT_RETRYLATER
;
190 doreuseaddr
|= (retropt_int(opts
, OPT_SO_REUSEADDR
, &reuseaddr
) >= 0);
191 applyopts(fd
->stream
.fd
, opts
, PH_PASTSOCKET
);
193 if (Setsockopt(fd
->stream
.fd
, opt_so_reuseaddr
.major
,
194 opt_so_reuseaddr
.minor
, &reuseaddr
, sizeof(reuseaddr
))
196 Warn6("setsockopt(%d, %d, %d, {%d}, "F_Zd
"): %s",
197 fd
->stream
.fd
, opt_so_reuseaddr
.major
,
198 opt_so_reuseaddr
.minor
, reuseaddr
, sizeof(reuseaddr
),
202 applyopts_cloexec(fd
->stream
.fd
, opts
);
203 applyopts(fd
->stream
.fd
, opts
, PH_PREBIND
);
204 applyopts(fd
->stream
.fd
, opts
, PH_BIND
);
205 if (Bind(fd
->stream
.fd
, &us
.soa
, uslen
) < 0) {
206 Error4("bind(%d, {%s}, "F_socklen
"): %s", fd
->stream
.fd
,
207 sockaddr_info(&us
.soa
, uslen
, infobuff
, sizeof(infobuff
)),
208 uslen
, strerror(errno
));
209 return STAT_RETRYLATER
;
211 /* under some circumstances bind() fills sockaddr with interesting info. */
212 if (Getsockname(fd
->stream
.fd
, &us
.soa
, &uslen
) < 0) {
213 Error4("getsockname(%d, %p, {%d}): %s",
214 fd
->stream
.fd
, &us
.soa
, uslen
, strerror(errno
));
216 applyopts(fd
->stream
.fd
, opts
, PH_PASTBIND
);
218 Notice1("listening on UDP %s",
219 sockaddr_info(&us
.soa
, uslen
, infobuff
, sizeof(infobuff
)));
220 readfd
.fd
= fd
->stream
.fd
;
221 readfd
.events
= POLLIN
|POLLERR
;
222 while (xiopoll(&readfd
, 1, NULL
) < 0) {
223 if (errno
!= EINTR
) break;
226 themlen
= socket_init(pf
, them
);
228 result
= Recvfrom(fd
->stream
.fd
, buff1
, 1, MSG_PEEK
,
229 &them
->soa
, &themlen
);
230 } while (result
< 0 && errno
== EINTR
);
232 Error5("recvfrom(%d, %p, 1, MSG_PEEK, {%s}, {"F_socklen
"}): %s",
233 fd
->stream
.fd
, buff1
,
234 sockaddr_info(&them
->soa
, themlen
, infobuff
, sizeof(infobuff
)),
235 themlen
, strerror(errno
));
236 return STAT_RETRYLATER
;
239 Notice1("accepting UDP connection from %s",
240 sockaddr_info(&them
->soa
, themlen
, infobuff
, sizeof(infobuff
)));
242 if (xiocheckpeer(&fd
->stream
, them
, la
) < 0) {
245 Recv(fd
->stream
.fd
, buff
, sizeof(buff
), 0); /* drop packet */
246 Close(fd
->stream
.fd
);
249 Info1("permitting UDP connection from %s",
250 sockaddr_info(&them
->soa
, themlen
, infobuff
, sizeof(infobuff
)));
253 pid
= xio_fork(false, E_ERROR
);
255 return STAT_RETRYLATER
;
258 if (pid
== 0) { /* child */
259 pid_t cpid
= Getpid();
260 xiosetenvulong("PID", cpid
, 1);
264 /* server: continue loop with socket()+recvfrom() */
265 /* when we dont close this we get awkward behaviour on Linux 2.4:
266 recvfrom gives 0 bytes with invalid socket address */
267 if (Close(fd
->stream
.fd
) < 0) {
268 Info2("close(%d): %s", fd
->stream
.fd
, strerror(errno
));
271 while (maxchildren
) {
272 if (num_child
< maxchildren
) break;
273 Notice("maxchildren are active, waiting");
274 /* UINT_MAX would even be nicer, but Openindiana works only
276 while (!Sleep(INT_MAX
)) ; /* any signal lets us continue */
278 Info("still listening");
284 applyopts(fd
->stream
.fd
, opts
, PH_CONNECT
);
285 if ((result
= Connect(fd
->stream
.fd
, &them
->soa
, themlen
)) < 0) {
286 Error4("connect(%d, {%s}, "F_socklen
"): %s",
288 sockaddr_info(&them
->soa
, themlen
, infobuff
, sizeof(infobuff
)),
289 themlen
, strerror(errno
));
290 return STAT_RETRYLATER
;
293 /* set the env vars describing the local and remote sockets */
294 if (Getsockname(fd
->stream
.fd
, &us
.soa
, &uslen
) < 0) {
295 Warn4("getsockname(%d, %p, {%d}): %s",
296 fd
->stream
.fd
, &us
.soa
, uslen
, strerror(errno
));
298 xiosetsockaddrenv("SOCK", &us
, uslen
, IPPROTO_UDP
);
299 xiosetsockaddrenv("PEER", them
, themlen
, IPPROTO_UDP
);
301 fd
->stream
.howtoend
= END_SHUTDOWN
;
302 applyopts_fchown(fd
->stream
.fd
, opts
);
303 applyopts(fd
->stream
.fd
, opts
, PH_LATE
);
305 if ((result
= _xio_openlate(&fd
->stream
, opts
)) < 0)
313 int xioopen_udp_sendto(int argc
, const char *argv
[], struct opt
*opts
,
314 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
315 int pf
, int socktype
, int ipproto
) {
319 Error2("%s: wrong number of parameters (%d instead of 2)",
324 retropt_socket_pf(opts
, &pf
);
325 if ((result
= _xioopen_udp_sendto(argv
[1], argv
[2], opts
, xioflags
, xxfd
,
326 groups
, pf
, socktype
, ipproto
))
330 _xio_openlate(&xxfd
->stream
, opts
);
335 applies and consumes the following option:
336 PH_INIT, PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE
338 OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
341 int _xioopen_udp_sendto(const char *hostname
, const char *servname
,
343 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
344 int pf
, int socktype
, int ipproto
) {
345 xiosingle_t
*xfd
= &xxfd
->stream
;
346 union sockaddr_union us
;
348 int feats
= 3; /* option bind supports address and port */
349 bool needbind
= false;
352 xfd
->howtoend
= END_SHUTDOWN
;
355 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return -1;
356 applyopts(-1, opts
, PH_INIT
);
358 xfd
->salen
= sizeof(xfd
->peersa
);
360 xiogetaddrinfo(hostname
, servname
, pf
, socktype
, ipproto
,
361 &xfd
->peersa
, &xfd
->salen
,
362 xfd
->para
.socket
.ip
.res_opts
[0],
363 xfd
->para
.socket
.ip
.res_opts
[1]))
367 if (pf
== PF_UNSPEC
) {
368 pf
= xfd
->peersa
.soa
.sa_family
;
370 uslen
= socket_init(pf
, &us
);
371 if (retropt_bind(opts
, pf
, socktype
, ipproto
, &us
.soa
, &uslen
, feats
,
372 xfd
->para
.socket
.ip
.res_opts
[0],
373 xfd
->para
.socket
.ip
.res_opts
[1])
378 if (retropt_ushort(opts
, OPT_SOURCEPORT
,
379 &xfd
->para
.socket
.ip
.sourceport
) >= 0) {
383 us
.ip4
.sin_port
= htons(xfd
->para
.socket
.ip
.sourceport
);
388 us
.ip6
.sin6_port
= htons(xfd
->para
.socket
.ip
.sourceport
);
395 retropt_bool(opts
, OPT_LOWPORT
, &xfd
->para
.socket
.ip
.lowport
);
396 if (xfd
->para
.socket
.ip
.lowport
) {
400 /*!!! this is buggy */
401 us
.ip4
.sin_port
= htons(xfd
->para
.socket
.ip
.lowport
); break;
405 /*!!! this is buggy */
406 us
.ip6
.sin6_port
= htons(xfd
->para
.socket
.ip
.lowport
); break;
412 xfd
->dtype
= XIODATA_RECVFROM
;
413 return _xioopen_dgram_sendto(needbind
?&us
:NULL
, uslen
,
414 opts
, xioflags
, xfd
, groups
,
415 pf
, socktype
, ipproto
);
420 int xioopen_udp_datagram(int argc
, const char *argv
[], struct opt
*opts
,
421 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
422 int pf
, int socktype
, int ipproto
) {
423 xiosingle_t
*xfd
= &xxfd
->stream
;
429 Error2("%s: wrong number of parameters (%d instead of 2)",
434 if ((hostname
= strdup(argv
[1])) == NULL
) {
435 Error1("strdup(\"%s\"): out of memory", argv
[1]);
436 return STAT_RETRYLATER
;
439 retropt_socket_pf(opts
, &pf
);
441 _xioopen_udp_sendto(hostname
, argv
[2], opts
, xioflags
, xxfd
, groups
,
442 pf
, socktype
, ipproto
);
444 if (result
!= STAT_OK
) {
448 xfd
->dtype
= XIOREAD_RECV
|XIOWRITE_SENDTO
;
450 xfd
->para
.socket
.la
.soa
.sa_family
= xfd
->peersa
.soa
.sa_family
;
452 /* only accept packets with correct remote ports */
453 xfd
->para
.socket
.ip
.sourceport
= ntohs(xfd
->peersa
.ip4
.sin_port
);
454 xfd
->para
.socket
.ip
.dosourceport
= true;
456 /* which reply packets will be accepted - determine by range option */
457 if (retropt_string(opts
, OPT_RANGE
, &rangename
)
459 if (xioparserange(rangename
, pf
, &xfd
->para
.socket
.range
) < 0) {
463 xfd
->para
.socket
.dorange
= true;
464 xfd
->dtype
|= XIOREAD_RECV_CHECKRANGE
;
469 xio_retropt_tcpwrap(xfd
, opts
);
470 #endif /* WITH_LIBWRAP */
472 _xio_openlate(xfd
, opts
);
478 int xioopen_udp_recvfrom(int argc
, const char *argv
[], struct opt
*opts
,
479 int xioflags
, xiofile_t
*xfd
, unsigned groups
,
480 int pf
, int socktype
, int ipproto
) {
481 union sockaddr_union us
;
482 socklen_t uslen
= sizeof(us
);
486 Error2("%s: wrong number of parameters (%d instead of 1)",
491 xfd
->stream
.howtoend
= END_NONE
;
492 retropt_socket_pf(opts
, &pf
);
493 if (pf
== PF_UNSPEC
) {
494 #if WITH_IP4 && WITH_IP6
495 pf
= xioopts
.default_ip
=='6'?PF_INET6
:PF_INET
;
504 xiogetaddrinfo(NULL
, argv
[1], pf
, socktype
, ipproto
,
505 &us
, &uslen
, xfd
->stream
.para
.socket
.ip
.res_opts
[0],
506 xfd
->stream
.para
.socket
.ip
.res_opts
[1]))
510 if (pf
== PF_UNSPEC
) {
511 pf
= us
.soa
.sa_family
;
515 union sockaddr_union la
;
516 socklen_t lalen
= sizeof(la
);
518 if (retropt_bind(opts
, pf
, socktype
, ipproto
, &la
.soa
, &lalen
, 1,
519 xfd
->stream
.para
.socket
.ip
.res_opts
[0],
520 xfd
->stream
.para
.socket
.ip
.res_opts
[1])
524 case PF_INET
: us
.ip4
.sin_addr
= la
.ip4
.sin_addr
; break;
527 case PF_INET6
: us
.ip6
.sin6_addr
= la
.ip6
.sin6_addr
; break;
533 if (retropt_ushort(opts
, OPT_SOURCEPORT
, &xfd
->stream
.para
.socket
.ip
.sourceport
) >= 0) {
534 xfd
->stream
.para
.socket
.ip
.dosourceport
= true;
536 retropt_bool(opts
, OPT_LOWPORT
, &xfd
->stream
.para
.socket
.ip
.lowport
);
538 xfd
->stream
.dtype
= XIODATA_RECVFROM_ONE
;
540 _xioopen_dgram_recvfrom(&xfd
->stream
, xioflags
, &us
.soa
, uslen
,
541 opts
, pf
, socktype
, ipproto
, E_ERROR
))
545 _xio_openlate(&xfd
->stream
, opts
);
551 int xioopen_udp_recv(int argc
, const char *argv
[], struct opt
*opts
,
552 int xioflags
, xiofile_t
*xfd
, unsigned groups
,
553 int pf
, int socktype
, int ipproto
) {
554 union sockaddr_union us
;
555 socklen_t uslen
= sizeof(us
);
560 Error2("%s: wrong number of parameters (%d instead of 1)",
565 retropt_socket_pf(opts
, &pf
);
566 if (pf
== PF_UNSPEC
) {
567 #if WITH_IP4 && WITH_IP6
568 pf
= xioopts
.default_ip
=='6'?PF_INET6
:PF_INET
;
577 xiogetaddrinfo(NULL
, argv
[1], pf
, socktype
, ipproto
,
578 &us
, &uslen
, xfd
->stream
.para
.socket
.ip
.res_opts
[0],
579 xfd
->stream
.para
.socket
.ip
.res_opts
[1]))
583 if (pf
== PF_UNSPEC
) {
584 pf
= us
.soa
.sa_family
;
589 union sockaddr_union la
;
590 socklen_t lalen
= sizeof(la
);
592 if (retropt_bind(opts
, pf
, socktype
, ipproto
,
593 &xfd
->stream
.para
.socket
.la
.soa
, &lalen
, 1,
594 xfd
->stream
.para
.socket
.ip
.res_opts
[0],
595 xfd
->stream
.para
.socket
.ip
.res_opts
[1])
600 us
.ip4
.sin_addr
= xfd
->stream
.para
.socket
.la
.ip4
.sin_addr
; break;
604 us
.ip6
.sin6_addr
= xfd
->stream
.para
.socket
.la
.ip6
.sin6_addr
; break;
608 xfd
->stream
.para
.socket
.la
.soa
.sa_family
= pf
;
613 #if WITH_IP4 /*|| WITH_IP6*/
614 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
615 if (xioparserange(rangename
, pf
, &xfd
->stream
.para
.socket
.range
) < 0) {
618 xfd
->stream
.para
.socket
.dorange
= true;
623 xio_retropt_tcpwrap(&xfd
->stream
, opts
);
624 #endif /* WITH_LIBWRAP */
626 if (retropt_ushort(opts
, OPT_SOURCEPORT
,
627 &xfd
->stream
.para
.socket
.ip
.sourceport
)
629 xfd
->stream
.para
.socket
.ip
.dosourceport
= true;
631 retropt_bool(opts
, OPT_LOWPORT
, &xfd
->stream
.para
.socket
.ip
.lowport
);
633 xfd
->stream
.dtype
= XIODATA_RECV
;
634 if ((result
= _xioopen_dgram_recv(&xfd
->stream
, xioflags
, &us
.soa
, uslen
,
635 opts
, pf
, socktype
, ipproto
, E_ERROR
))
639 _xio_openlate(&xfd
->stream
, opts
);
643 #endif /* WITH_UDP && (WITH_IP4 || WITH_IP6) */