1 /* source: xio-udp.c */
2 /* Copyright Gerhard Rieger */
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
;
92 unsigned char buff1
[1];
98 Error2("%s: wrong number of parameters (%d instead of 1)", argv
[0], argc
-1);
101 if (pf
== PF_UNSPEC
) {
102 #if WITH_IP4 && WITH_IP6
103 pf
= xioopts
.default_ip
=='6'?PF_INET6
:PF_INET
;
111 retropt_socket_pf(opts
, &pf
);
113 if (applyopts_single(&fd
->stream
, opts
, PH_INIT
) < 0) return -1;
114 applyopts(-1, opts
, PH_INIT
);
116 uslen
= socket_init(pf
, &us
);
117 retropt_bind(opts
, pf
, socktype
, IPPROTO_UDP
,
118 (struct sockaddr
*)&us
, &uslen
, 1,
119 fd
->stream
.para
.socket
.ip
.res_opts
[1],
120 fd
->stream
.para
.socket
.ip
.res_opts
[0]);
125 } else if (pf
== PF_INET
) {
126 us
.ip4
.sin_port
= parseport(portname
, ipproto
);
129 } else if (pf
== PF_INET6
) {
130 us
.ip6
.sin6_port
= parseport(portname
, ipproto
);
133 Error1("xioopen_ipdgram_listen(): unknown address family %d", pf
);
136 retropt_bool(opts
, OPT_FORK
, &dofork
);
139 if (!(xioflags
& XIO_MAYFORK
)) {
140 Error("option fork not allowed here");
145 #if WITH_IP4 /*|| WITH_IP6*/
146 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
147 if (xioparserange(rangename
, pf
, &fd
->stream
.para
.socket
.range
) < 0) {
152 fd
->stream
.para
.socket
.dorange
= true;
157 xio_retropt_tcpwrap(&fd
->stream
, opts
);
158 #endif /* WITH_LIBWRAP */
160 if (retropt_ushort(opts
, OPT_SOURCEPORT
, &fd
->stream
.para
.socket
.ip
.sourceport
)
162 fd
->stream
.para
.socket
.ip
.dosourceport
= true;
164 retropt_bool(opts
, OPT_LOWPORT
, &fd
->stream
.para
.socket
.ip
.lowport
);
167 xiosetchilddied(); /* set SIGCHLD handler */
170 while (true) { /* we loop with fork or prohibited packets */
171 /* now wait for some packet on this datagram socket, get its sender
172 address, connect there, and return */
173 int reuseaddr
= dofork
;
174 int doreuseaddr
= (dofork
!= 0);
176 union sockaddr_union _sockname
;
177 union sockaddr_union
*la
= &_sockname
; /* local address */
179 if ((fd
->stream
.fd
= xiosocket(opts
, pf
, socktype
, ipproto
, E_ERROR
)) < 0) {
180 return STAT_RETRYLATER
;
182 doreuseaddr
|= (retropt_int(opts
, OPT_SO_REUSEADDR
, &reuseaddr
) >= 0);
183 applyopts(fd
->stream
.fd
, opts
, PH_PASTSOCKET
);
185 if (Setsockopt(fd
->stream
.fd
, opt_so_reuseaddr
.major
,
186 opt_so_reuseaddr
.minor
, &reuseaddr
, sizeof(reuseaddr
))
188 Warn6("setsockopt(%d, %d, %d, {%d}, "F_Zd
"): %s",
189 fd
->stream
.fd
, opt_so_reuseaddr
.major
,
190 opt_so_reuseaddr
.minor
, reuseaddr
, sizeof(reuseaddr
),
194 applyopts_cloexec(fd
->stream
.fd
, opts
);
195 applyopts(fd
->stream
.fd
, opts
, PH_PREBIND
);
196 applyopts(fd
->stream
.fd
, opts
, PH_BIND
);
197 if (Bind(fd
->stream
.fd
, &us
.soa
, uslen
) < 0) {
198 Error4("bind(%d, {%s}, "F_socklen
"): %s", fd
->stream
.fd
,
199 sockaddr_info(&us
.soa
, uslen
, infobuff
, sizeof(infobuff
)),
200 uslen
, strerror(errno
));
201 return STAT_RETRYLATER
;
203 /* under some circumstances bind() fills sockaddr with interesting info. */
204 if (Getsockname(fd
->stream
.fd
, &us
.soa
, &uslen
) < 0) {
205 Error4("getsockname(%d, %p, {%d}): %s",
206 fd
->stream
.fd
, &us
.soa
, uslen
, strerror(errno
));
208 applyopts(fd
->stream
.fd
, opts
, PH_PASTBIND
);
210 Notice1("listening on UDP %s",
211 sockaddr_info(&us
.soa
, uslen
, infobuff
, sizeof(infobuff
)));
212 readfd
.fd
= fd
->stream
.fd
;
213 readfd
.events
= POLLIN
|POLLERR
;
214 while (xiopoll(&readfd
, 1, NULL
) < 0) {
215 if (errno
!= EINTR
) break;
218 themlen
= socket_init(pf
, them
);
220 result
= Recvfrom(fd
->stream
.fd
, buff1
, 1, MSG_PEEK
,
221 &them
->soa
, &themlen
);
222 } while (result
< 0 && errno
== EINTR
);
224 Error5("recvfrom(%d, %p, 1, MSG_PEEK, {%s}, {"F_socklen
"}): %s",
225 fd
->stream
.fd
, buff1
,
226 sockaddr_info(&them
->soa
, themlen
, infobuff
, sizeof(infobuff
)),
227 themlen
, strerror(errno
));
228 return STAT_RETRYLATER
;
231 Notice1("accepting UDP connection from %s",
232 sockaddr_info(&them
->soa
, themlen
, infobuff
, sizeof(infobuff
)));
234 if (xiocheckpeer(&fd
->stream
, them
, la
) < 0) {
237 Recv(fd
->stream
.fd
, buff
, sizeof(buff
), 0); /* drop packet */
238 Close(fd
->stream
.fd
);
241 Info1("permitting UDP connection from %s",
242 sockaddr_info(&them
->soa
, themlen
, infobuff
, sizeof(infobuff
)));
245 pid
= xio_fork(false, E_ERROR
);
247 return STAT_RETRYLATER
;
250 if (pid
== 0) { /* child */
254 /* server: continue loop with socket()+recvfrom() */
255 /* when we dont close this we get awkward behaviour on Linux 2.4:
256 recvfrom gives 0 bytes with invalid socket address */
257 if (Close(fd
->stream
.fd
) < 0) {
258 Info2("close(%d): %s", fd
->stream
.fd
, strerror(errno
));
266 applyopts(fd
->stream
.fd
, opts
, PH_CONNECT
);
267 if ((result
= Connect(fd
->stream
.fd
, &them
->soa
, themlen
)) < 0) {
268 Error4("connect(%d, {%s}, "F_socklen
"): %s",
270 sockaddr_info(&them
->soa
, themlen
, infobuff
, sizeof(infobuff
)),
271 themlen
, strerror(errno
));
272 return STAT_RETRYLATER
;
275 /* set the env vars describing the local and remote sockets */
276 if (Getsockname(fd
->stream
.fd
, &us
.soa
, &uslen
) < 0) {
277 Warn4("getsockname(%d, %p, {%d}): %s",
278 fd
->stream
.fd
, &us
.soa
, uslen
, strerror(errno
));
280 xiosetsockaddrenv("SOCK", &us
, uslen
, IPPROTO_UDP
);
281 xiosetsockaddrenv("PEER", them
, themlen
, IPPROTO_UDP
);
283 fd
->stream
.howtoend
= END_SHUTDOWN
;
284 applyopts_fchown(fd
->stream
.fd
, opts
);
285 applyopts(fd
->stream
.fd
, opts
, PH_LATE
);
287 if ((result
= _xio_openlate(&fd
->stream
, opts
)) < 0)
295 int xioopen_udp_sendto(int argc
, const char *argv
[], struct opt
*opts
,
296 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
297 int pf
, int socktype
, int ipproto
) {
301 Error2("%s: wrong number of parameters (%d instead of 2)",
306 retropt_socket_pf(opts
, &pf
);
307 if ((result
= _xioopen_udp_sendto(argv
[1], argv
[2], opts
, xioflags
, xxfd
,
308 groups
, pf
, socktype
, ipproto
))
312 _xio_openlate(&xxfd
->stream
, opts
);
317 applies and consumes the following option:
318 PH_INIT, PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE
320 OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
323 int _xioopen_udp_sendto(const char *hostname
, const char *servname
,
325 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
326 int pf
, int socktype
, int ipproto
) {
327 xiosingle_t
*xfd
= &xxfd
->stream
;
328 union sockaddr_union us
;
330 int feats
= 3; /* option bind supports address and port */
331 bool needbind
= false;
334 xfd
->howtoend
= END_SHUTDOWN
;
337 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return -1;
338 applyopts(-1, opts
, PH_INIT
);
340 xfd
->salen
= sizeof(xfd
->peersa
);
342 xiogetaddrinfo(hostname
, servname
, pf
, socktype
, ipproto
,
343 &xfd
->peersa
, &xfd
->salen
,
344 xfd
->para
.socket
.ip
.res_opts
[0],
345 xfd
->para
.socket
.ip
.res_opts
[1]))
349 if (pf
== PF_UNSPEC
) {
350 pf
= xfd
->peersa
.soa
.sa_family
;
352 uslen
= socket_init(pf
, &us
);
353 if (retropt_bind(opts
, pf
, socktype
, ipproto
, &us
.soa
, &uslen
, feats
,
354 xfd
->para
.socket
.ip
.res_opts
[0],
355 xfd
->para
.socket
.ip
.res_opts
[1])
360 if (retropt_ushort(opts
, OPT_SOURCEPORT
,
361 &xfd
->para
.socket
.ip
.sourceport
) >= 0) {
365 us
.ip4
.sin_port
= htons(xfd
->para
.socket
.ip
.sourceport
);
370 us
.ip6
.sin6_port
= htons(xfd
->para
.socket
.ip
.sourceport
);
377 retropt_bool(opts
, OPT_LOWPORT
, &xfd
->para
.socket
.ip
.lowport
);
378 if (xfd
->para
.socket
.ip
.lowport
) {
382 /*!!! this is buggy */
383 us
.ip4
.sin_port
= htons(xfd
->para
.socket
.ip
.lowport
); break;
387 /*!!! this is buggy */
388 us
.ip6
.sin6_port
= htons(xfd
->para
.socket
.ip
.lowport
); break;
394 xfd
->dtype
= XIODATA_RECVFROM
;
395 return _xioopen_dgram_sendto(needbind
?&us
:NULL
, uslen
,
396 opts
, xioflags
, xfd
, groups
,
397 pf
, socktype
, ipproto
);
402 int xioopen_udp_datagram(int argc
, const char *argv
[], struct opt
*opts
,
403 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
404 int pf
, int socktype
, int ipproto
) {
405 xiosingle_t
*xfd
= &xxfd
->stream
;
411 Error2("%s: wrong number of parameters (%d instead of 2)",
416 if ((hostname
= strdup(argv
[1])) == NULL
) {
417 Error1("strdup(\"%s\"): out of memory", argv
[1]);
418 return STAT_RETRYLATER
;
421 retropt_socket_pf(opts
, &pf
);
423 _xioopen_udp_sendto(hostname
, argv
[2], opts
, xioflags
, xxfd
, groups
,
424 pf
, socktype
, ipproto
);
426 if (result
!= STAT_OK
) {
430 xfd
->dtype
= XIOREAD_RECV
|XIOWRITE_SENDTO
;
432 xfd
->para
.socket
.la
.soa
.sa_family
= xfd
->peersa
.soa
.sa_family
;
434 /* only accept packets with correct remote ports */
435 xfd
->para
.socket
.ip
.sourceport
= ntohs(xfd
->peersa
.ip4
.sin_port
);
436 xfd
->para
.socket
.ip
.dosourceport
= true;
438 /* which reply packets will be accepted - determine by range option */
439 if (retropt_string(opts
, OPT_RANGE
, &rangename
)
441 if (xioparserange(rangename
, pf
, &xfd
->para
.socket
.range
) < 0) {
445 xfd
->para
.socket
.dorange
= true;
446 xfd
->dtype
|= XIOREAD_RECV_CHECKRANGE
;
451 xio_retropt_tcpwrap(xfd
, opts
);
452 #endif /* WITH_LIBWRAP */
454 _xio_openlate(xfd
, opts
);
460 int xioopen_udp_recvfrom(int argc
, const char *argv
[], struct opt
*opts
,
461 int xioflags
, xiofile_t
*xfd
, unsigned groups
,
462 int pf
, int socktype
, int ipproto
) {
463 union sockaddr_union us
;
464 socklen_t uslen
= sizeof(us
);
468 Error2("%s: wrong number of parameters (%d instead of 1)",
473 xfd
->stream
.howtoend
= END_NONE
;
474 retropt_socket_pf(opts
, &pf
);
475 if (pf
== PF_UNSPEC
) {
476 #if WITH_IP4 && WITH_IP6
477 pf
= xioopts
.default_ip
=='6'?PF_INET6
:PF_INET
;
486 xiogetaddrinfo(NULL
, argv
[1], pf
, socktype
, ipproto
,
487 &us
, &uslen
, xfd
->stream
.para
.socket
.ip
.res_opts
[0],
488 xfd
->stream
.para
.socket
.ip
.res_opts
[1]))
492 if (pf
== PF_UNSPEC
) {
493 pf
= us
.soa
.sa_family
;
497 union sockaddr_union la
;
498 socklen_t lalen
= sizeof(la
);
500 if (retropt_bind(opts
, pf
, socktype
, ipproto
, &la
.soa
, &lalen
, 1,
501 xfd
->stream
.para
.socket
.ip
.res_opts
[0],
502 xfd
->stream
.para
.socket
.ip
.res_opts
[1])
506 case PF_INET
: us
.ip4
.sin_addr
= la
.ip4
.sin_addr
; break;
509 case PF_INET6
: us
.ip6
.sin6_addr
= la
.ip6
.sin6_addr
; break;
515 if (retropt_ushort(opts
, OPT_SOURCEPORT
, &xfd
->stream
.para
.socket
.ip
.sourceport
) >= 0) {
516 xfd
->stream
.para
.socket
.ip
.dosourceport
= true;
518 retropt_bool(opts
, OPT_LOWPORT
, &xfd
->stream
.para
.socket
.ip
.lowport
);
520 xfd
->stream
.dtype
= XIODATA_RECVFROM_ONE
;
522 _xioopen_dgram_recvfrom(&xfd
->stream
, xioflags
, &us
.soa
, uslen
,
523 opts
, pf
, socktype
, ipproto
, E_ERROR
))
527 _xio_openlate(&xfd
->stream
, opts
);
533 int xioopen_udp_recv(int argc
, const char *argv
[], struct opt
*opts
,
534 int xioflags
, xiofile_t
*xfd
, unsigned groups
,
535 int pf
, int socktype
, int ipproto
) {
536 union sockaddr_union us
;
537 socklen_t uslen
= sizeof(us
);
542 Error2("%s: wrong number of parameters (%d instead of 1)",
547 retropt_socket_pf(opts
, &pf
);
548 if (pf
== PF_UNSPEC
) {
549 #if WITH_IP4 && WITH_IP6
550 pf
= xioopts
.default_ip
=='6'?PF_INET6
:PF_INET
;
559 xiogetaddrinfo(NULL
, argv
[1], pf
, socktype
, ipproto
,
560 &us
, &uslen
, xfd
->stream
.para
.socket
.ip
.res_opts
[0],
561 xfd
->stream
.para
.socket
.ip
.res_opts
[1]))
565 if (pf
== PF_UNSPEC
) {
566 pf
= us
.soa
.sa_family
;
571 union sockaddr_union la
;
572 socklen_t lalen
= sizeof(la
);
574 if (retropt_bind(opts
, pf
, socktype
, ipproto
,
575 &xfd
->stream
.para
.socket
.la
.soa
, &lalen
, 1,
576 xfd
->stream
.para
.socket
.ip
.res_opts
[0],
577 xfd
->stream
.para
.socket
.ip
.res_opts
[1])
582 us
.ip4
.sin_addr
= xfd
->stream
.para
.socket
.la
.ip4
.sin_addr
; break;
586 us
.ip6
.sin6_addr
= xfd
->stream
.para
.socket
.la
.ip6
.sin6_addr
; break;
590 xfd
->stream
.para
.socket
.la
.soa
.sa_family
= pf
;
595 #if WITH_IP4 /*|| WITH_IP6*/
596 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
597 if (xioparserange(rangename
, pf
, &xfd
->stream
.para
.socket
.range
) < 0) {
600 xfd
->stream
.para
.socket
.dorange
= true;
605 xio_retropt_tcpwrap(&xfd
->stream
, opts
);
606 #endif /* WITH_LIBWRAP */
608 if (retropt_ushort(opts
, OPT_SOURCEPORT
,
609 &xfd
->stream
.para
.socket
.ip
.sourceport
)
611 xfd
->stream
.para
.socket
.ip
.dosourceport
= true;
613 retropt_bool(opts
, OPT_LOWPORT
, &xfd
->stream
.para
.socket
.ip
.lowport
);
615 xfd
->stream
.dtype
= XIODATA_RECV
;
616 if ((result
= _xioopen_dgram_recv(&xfd
->stream
, xioflags
, &us
.soa
, uslen
,
617 opts
, pf
, socktype
, ipproto
, E_ERROR
))
621 _xio_openlate(&xfd
->stream
, opts
);
625 #endif /* WITH_UDP && (WITH_IP4 || WITH_IP6) */