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 const struct addrdesc xioaddr_udp_connect
= { "UDP-CONNECT", 1+XIO_RDWR
, 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>") };
25 const struct addrdesc xioaddr_udp_listen
= { "UDP-LISTEN", 1+XIO_RDWR
, 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>") };
26 #endif /* WITH_LISTEN */
27 const struct addrdesc xioaddr_udp_sendto
= { "UDP-SENDTO", 1+XIO_RDWR
, 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>") };
28 const struct addrdesc xioaddr_udp_recvfrom
= { "UDP-RECVFROM", 1+XIO_RDWR
, 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>") };
29 const struct addrdesc xioaddr_udp_recv
= { "UDP-RECV", 1+XIO_RDONLY
, 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>") };
30 const struct addrdesc xioaddr_udp_datagram
= { "UDP-DATAGRAM", 1+XIO_RDWR
, 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>") };
33 const struct addrdesc xioaddr_udp4_connect
= { "UDP4-CONNECT", 1+XIO_RDWR
, xioopen_ipapp_connect
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP4
|GROUP_IP_UDP
, SOCK_DGRAM
, IPPROTO_UDP
, PF_INET
HELP(":<host>:<port>") };
35 const struct addrdesc xioaddr_udp4_listen
= { "UDP4-LISTEN", 1+XIO_RDWR
, 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>") };
36 #endif /* WITH_LISTEN */
37 const struct addrdesc xioaddr_udp4_sendto
= { "UDP4-SENDTO", 1+XIO_RDWR
, xioopen_udp_sendto
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP4
|GROUP_IP_UDP
, PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<host>:<port>") };
38 const struct addrdesc xioaddr_udp4_datagram
= { "UDP4-DATAGRAM", 1+XIO_RDWR
, xioopen_udp_datagram
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP4
|GROUP_IP_UDP
|GROUP_RANGE
, PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<host>:<port>") };
39 const struct addrdesc xioaddr_udp4_recvfrom
= { "UDP4-RECVFROM", 1+XIO_RDWR
, 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>") };
40 const struct addrdesc xioaddr_udp4_recv
= { "UDP4-RECV", 1+XIO_RDONLY
, xioopen_udp_recv
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP4
|GROUP_IP_UDP
|GROUP_RANGE
, PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<port>") };
44 const struct addrdesc xioaddr_udp6_connect
= { "UDP6-CONNECT", 1+XIO_RDWR
, xioopen_ipapp_connect
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP6
|GROUP_IP_UDP
, SOCK_DGRAM
, IPPROTO_UDP
, PF_INET6
HELP(":<host>:<port>") };
46 const struct addrdesc xioaddr_udp6_listen
= { "UDP6-LISTEN", 1+XIO_RDWR
, 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>") };
47 #endif /* WITH_LISTEN */
48 const struct addrdesc xioaddr_udp6_sendto
= { "UDP6-SENDTO", 1+XIO_RDWR
, xioopen_udp_sendto
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP6
|GROUP_IP_UDP
, PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<host>:<port>") };
49 const struct addrdesc xioaddr_udp6_datagram
= { "UDP6-DATAGRAM", 1+XIO_RDWR
, xioopen_udp_datagram
,GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP6
|GROUP_IP_UDP
|GROUP_RANGE
, PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<host>:<port>") };
50 const struct addrdesc xioaddr_udp6_recvfrom
= { "UDP6-RECVFROM", 1+XIO_RDWR
, 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>") };
51 const struct addrdesc xioaddr_udp6_recv
= { "UDP6-RECV", 1+XIO_RDONLY
, xioopen_udp_recv
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_IP6
|GROUP_IP_UDP
|GROUP_RANGE
, PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
HELP(":<port>") };
57 int _xioopen_ipdgram_listen(struct single
*sfd
,
58 int xioflags
, union sockaddr_union
*us
, socklen_t uslen
,
59 struct opt
*opts
, int pf
, int socktype
, int ipproto
) {
60 union sockaddr_union themunion
;
61 union sockaddr_union
*them
= &themunion
;
68 unsigned char buff1
[1];
72 retropt_bool(opts
, OPT_FORK
, &dofork
);
75 if (!(xioflags
& XIO_MAYFORK
)) {
76 Error("option fork not allowed here");
81 retropt_int(opts
, OPT_MAX_CHILDREN
, &maxchildren
);
83 if (! dofork
&& maxchildren
) {
84 Error("option max-children not allowed without option fork");
88 #if WITH_IP4 /*|| WITH_IP6*/
89 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
90 if (xioparserange(rangename
, pf
, &sfd
->para
.socket
.range
,
91 sfd
->para
.socket
.ip
.ai_flags
)
97 sfd
->para
.socket
.dorange
= true;
102 xio_retropt_tcpwrap(sfd
, opts
);
103 #endif /* WITH_LIBWRAP */
105 if (retropt_ushort(opts
, OPT_SOURCEPORT
, &sfd
->para
.socket
.ip
.sourceport
)
107 sfd
->para
.socket
.ip
.dosourceport
= true;
109 retropt_bool(opts
, OPT_LOWPORT
, &sfd
->para
.socket
.ip
.lowport
);
112 xiosetchilddied(); /* set SIGCHLD handler */
115 while (true) { /* we loop with fork or prohibited packets */
116 /* now wait for some packet on this datagram socket, get its sender
117 address, connect there, and return */
118 union integral notnull
;
119 union integral reuseaddr
;
120 int doreuseaddr
= (dofork
!= 0);
122 union sockaddr_union _sockname
;
123 union sockaddr_union
*la
= &_sockname
; /* local address */
125 reuseaddr
.u_int
= dofork
;
127 if ((sfd
->fd
= xiosocket(opts
, pf
, socktype
, ipproto
, E_ERROR
)) < 0) {
128 return STAT_RETRYLATER
;
130 doreuseaddr
|= (retropt_2integrals(opts
, OPT_SO_REUSEADDR
,
131 &reuseaddr
, ¬null
) >= 0);
132 applyopts(sfd
, -1, opts
, PH_PASTSOCKET
);
134 /* SO_REUSEADDR handling of UDP sockets is helpful on Solaris */
136 if (Setsockopt(sfd
->fd
, opt_so_reuseaddr
.major
,
137 opt_so_reuseaddr
.minor
, &reuseaddr
.u_int
, sizeof(reuseaddr
.u_int
))
139 Warn6("setsockopt(%d, %d, %d, {%d}, "F_Zd
"): %s",
140 sfd
->fd
, opt_so_reuseaddr
.major
,
141 opt_so_reuseaddr
.minor
, reuseaddr
.u_int
, sizeof(reuseaddr
.u_int
),
145 applyopts_cloexec(sfd
->fd
, opts
);
146 applyopts(sfd
, -1, opts
, PH_PREBIND
);
147 applyopts(sfd
, -1, opts
, PH_BIND
);
148 if (Bind(sfd
->fd
, &us
->soa
, uslen
) < 0) {
149 Error4("bind(%d, {%s}, "F_socklen
"): %s", sfd
->fd
,
150 sockaddr_info(&us
->soa
, uslen
, infobuff
, sizeof(infobuff
)),
151 uslen
, strerror(errno
));
152 return STAT_RETRYLATER
;
154 /* under some circumstances bind() fills sockaddr with interesting info. */
155 if (Getsockname(sfd
->fd
, &us
->soa
, &uslen
) < 0) {
156 Error4("getsockname(%d, %p, {%d}): %s",
157 sfd
->fd
, &us
->soa
, uslen
, strerror(errno
));
159 applyopts(sfd
, -1, opts
, PH_PASTBIND
);
161 if (ipproto
== IPPROTO_UDP
) {
162 Notice1("listening on UDP %s",
163 sockaddr_info(&us
->soa
, uslen
, infobuff
, sizeof(infobuff
)));
165 Notice2("listening on PROTO%d %s", ipproto
,
166 sockaddr_info(&us
->soa
, uslen
, infobuff
, sizeof(infobuff
)));
170 readfd
.events
= POLLIN
|POLLERR
;
171 while (xiopoll(&readfd
, 1, NULL
) < 0) {
172 if (errno
!= EINTR
) break;
175 themlen
= socket_init(pf
, them
);
177 result
= Recvfrom(sfd
->fd
, buff1
, 1, MSG_PEEK
,
178 &them
->soa
, &themlen
);
179 } while (result
< 0 && errno
== EINTR
);
181 Error5("recvfrom(%d, %p, 1, MSG_PEEK, {%s}, {"F_socklen
"}): %s",
183 sockaddr_info(&them
->soa
, themlen
, infobuff
, sizeof(infobuff
)),
184 themlen
, strerror(errno
));
185 return STAT_RETRYLATER
;
188 Notice1("accepting UDP connection from %s",
189 sockaddr_info(&them
->soa
, themlen
, infobuff
, sizeof(infobuff
)));
191 if (xiocheckpeer(sfd
, them
, la
) < 0) {
192 Notice1("forbidding UDP connection from %s",
193 sockaddr_info(&them
->soa
, themlen
,
194 infobuff
, sizeof(infobuff
)));
197 Recv(sfd
->fd
, buff
, sizeof(buff
), 0); /* drop packet */
201 Info1("permitting UDP connection from %s",
202 sockaddr_info(&them
->soa
, themlen
, infobuff
, sizeof(infobuff
)));
205 pid
= xio_fork(false, E_ERROR
, sfd
->shutup
);
207 return STAT_RETRYLATER
;
210 if (pid
== 0) { /* child */
211 pid_t cpid
= Getpid();
212 xiosetenvulong("PID", cpid
, 1);
216 /* server: continue loop with socket()+recvfrom() */
217 /* This avoids the requirement of a sync (trigger) mechanism as with
218 RECVFROM addresses */
219 /* And when we dont close this we got awkward behaviour on Linux 2.4:
220 recvfrom gives 0 bytes with invalid socket address */
221 if (Close(sfd
->fd
) < 0) {
222 Info2("close(%d): %s", sfd
->fd
, strerror(errno
));
225 while (maxchildren
) {
226 if (num_child
< maxchildren
) break;
227 Notice("maxchildren are active, waiting");
228 /* UINT_MAX would even be nicer, but Openindiana works only
230 while (!Sleep(INT_MAX
)) ; /* any signal lets us continue */
232 Info("still listening");
236 } /* end of the big while loop */
238 applyopts(sfd
, -1, opts
, PH_CONNECT
);
239 if ((result
= Connect(sfd
->fd
, &them
->soa
, themlen
)) < 0) {
240 Error4("connect(%d, {%s}, "F_socklen
"): %s",
242 sockaddr_info(&them
->soa
, themlen
, infobuff
, sizeof(infobuff
)),
243 themlen
, strerror(errno
));
244 return STAT_RETRYLATER
;
247 /* set the env vars describing the local and remote sockets */
248 if (Getsockname(sfd
->fd
, &us
->soa
, &uslen
) < 0) {
249 Warn4("getsockname(%d, %p, {%d}): %s",
250 sfd
->fd
, &us
->soa
, uslen
, strerror(errno
));
252 xiosetsockaddrenv("SOCK", us
, uslen
, IPPROTO_UDP
);
253 xiosetsockaddrenv("PEER", them
, themlen
, IPPROTO_UDP
);
255 if (sfd
->howtoend
== END_UNSPEC
)
256 sfd
->howtoend
= END_SHUTDOWN
;
257 applyopts_fchown(sfd
->fd
, opts
);
258 applyopts(sfd
, -1, opts
, PH_LATE
);
260 if ((result
= _xio_openlate(sfd
, opts
)) < 0)
266 /* we expect the form: port */
267 int xioopen_ipdgram_listen(
273 const struct addrdesc
*addrdesc
)
275 struct single
*sfd
= &xfd
->stream
;
276 const char *portname
= argv
[1];
277 int pf
= addrdesc
->arg1
;
278 int ipproto
= addrdesc
->arg2
;
279 union sockaddr_union us
;
280 int socktype
= SOCK_DGRAM
;
284 xio_syntax(argv
[0], 1, argc
-1, addrdesc
->syntax
);
288 xioinit_ip(&pf
, xioparms
.default_ip
);
289 if (pf
== PF_UNSPEC
) {
290 #if WITH_IP4 && WITH_IP6
291 switch (xioparms
.default_ip
) {
292 case '4': pf
= PF_INET
; break;
293 case '6': pf
= PF_INET6
; break;
294 default: break; /* includes \0 */
303 retropt_socket_pf(opts
, &pf
);
304 retropt_int(opts
, OPT_SO_PROTOTYPE
, &ipproto
);
306 if (applyopts_single(sfd
, opts
, PH_INIT
) < 0)
308 applyopts(sfd
, -1, opts
, PH_INIT
);
310 uslen
= socket_init(pf
, &us
);
311 retropt_bind(opts
, pf
, socktype
, ipproto
,
312 (struct sockaddr
*)&us
, &uslen
, 1,
313 xfd
->stream
.para
.socket
.ip
.ai_flags
);
318 } else if (pf
== PF_INET
) {
319 us
.ip4
.sin_port
= parseport(portname
, ipproto
);
322 } else if (pf
== PF_INET6
) {
323 us
.ip6
.sin6_port
= parseport(portname
, ipproto
);
326 Error1("xioopen_ipdgram_listen(): unknown address family %d", pf
);
329 return _xioopen_ipdgram_listen(&xfd
->stream
, xioflags
, &us
, uslen
,
330 opts
, pf
, socktype
, ipproto
);
333 int xioopen_udp_sendto(
339 const struct addrdesc
*addrdesc
)
341 int pf
= addrdesc
->arg1
;
342 int socktype
= addrdesc
->arg2
;
343 int ipproto
= addrdesc
->arg3
;
347 xio_syntax(argv
[0], 2, argc
-1, addrdesc
->syntax
);
351 retropt_socket_pf(opts
, &pf
);
352 if ((result
= _xioopen_udp_sendto(argv
[1], argv
[2], opts
, xioflags
, xfd
,
353 addrdesc
->groups
, pf
, socktype
, ipproto
))
357 _xio_openlate(&xfd
->stream
, opts
);
362 applies and consumes the following option:
363 PH_INIT, PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE
365 OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
367 int _xioopen_udp_sendto(const char *hostname
, const char *servname
,
369 int xioflags
, xiofile_t
*xxfd
, groups_t groups
,
370 int pf
, int socktype
, int ipproto
) {
371 struct single
*sfd
= &xxfd
->stream
;
372 union sockaddr_union us
;
374 int feats
= 3; /* option bind supports address and port */
375 bool needbind
= false;
378 if (sfd
->howtoend
== END_UNSPEC
)
379 sfd
->howtoend
= END_SHUTDOWN
;
382 if (applyopts_single(sfd
, opts
, PH_INIT
) < 0)
384 applyopts(sfd
, -1, opts
, PH_INIT
);
386 sfd
->salen
= sizeof(sfd
->peersa
);
388 xioresolve(hostname
, servname
, pf
, socktype
, ipproto
,
389 &sfd
->peersa
, &sfd
->salen
,
390 sfd
->para
.socket
.ip
.ai_flags
))
394 if (pf
== PF_UNSPEC
) {
395 pf
= sfd
->peersa
.soa
.sa_family
;
397 uslen
= socket_init(pf
, &us
);
398 if (retropt_bind(opts
, pf
, socktype
, ipproto
, &us
.soa
, &uslen
, feats
,
399 sfd
->para
.socket
.ip
.ai_flags
)
404 if (retropt_ushort(opts
, OPT_SOURCEPORT
,
405 &sfd
->para
.socket
.ip
.sourceport
) >= 0) {
409 us
.ip4
.sin_port
= htons(sfd
->para
.socket
.ip
.sourceport
);
414 us
.ip6
.sin6_port
= htons(sfd
->para
.socket
.ip
.sourceport
);
421 retropt_bool(opts
, OPT_LOWPORT
, &sfd
->para
.socket
.ip
.lowport
);
423 sfd
->dtype
= XIODATA_RECVFROM
;
424 return _xioopen_dgram_sendto(needbind
?&us
:NULL
, uslen
,
425 opts
, xioflags
, sfd
, groups
,
426 pf
, socktype
, ipproto
,
427 sfd
->para
.socket
.ip
.lowport
);
431 int xioopen_udp_datagram(
437 const struct addrdesc
*addrdesc
)
439 struct single
*sfd
= &xxfd
->stream
;
440 int pf
= addrdesc
->arg1
;
441 int socktype
= addrdesc
->arg2
;
442 int ipproto
= addrdesc
->arg3
;
448 xio_syntax(argv
[0], 2, argc
-1, addrdesc
->syntax
);
452 if ((hostname
= strdup(argv
[1])) == NULL
) {
453 Error1("strdup(\"%s\"): out of memory", argv
[1]);
454 return STAT_RETRYLATER
;
457 /* only accept packets with correct remote ports */
458 if (retropt_ushort(opts
, OPT_SOURCEPORT
, &sfd
->para
.socket
.ip
.sourceport
)
460 sfd
->para
.socket
.ip
.dosourceport
= true;
463 retropt_socket_pf(opts
, &pf
);
466 _xioopen_udp_sendto(hostname
, argv
[2], opts
, xioflags
, xxfd
,
467 addrdesc
->groups
, pf
, socktype
, ipproto
);
469 if (result
!= STAT_OK
) {
473 if (sfd
->para
.socket
.ip
.dosourceport
) {
474 switch (sfd
->peersa
.soa
.sa_family
) {
478 sfd
->para
.socket
.ip
.sourceport
= ntohs(sfd
->peersa
.ip4
.sin_port
);
480 #endif /* WITH_IP4 */
483 sfd
->para
.socket
.ip
.sourceport
= ntohs(sfd
->peersa
.ip6
.sin6_port
);
485 #endif /* WITH_IP6 */
489 sfd
->dtype
= XIOREAD_RECV
|XIOWRITE_SENDTO
;
491 sfd
->para
.socket
.la
.soa
.sa_family
= sfd
->peersa
.soa
.sa_family
;
493 /* which reply packets will be accepted - determine by range option */
494 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
495 if (xioparserange(rangename
, pf
, &sfd
->para
.socket
.range
,
496 sfd
->para
.socket
.ip
.ai_flags
)
501 sfd
->para
.socket
.dorange
= true;
502 sfd
->dtype
|= XIOREAD_RECV_CHECKRANGE
;
507 xio_retropt_tcpwrap(sfd
, opts
);
508 #endif /* WITH_LIBWRAP */
510 _xio_openlate(sfd
, opts
);
515 int xioopen_udp_recvfrom(
521 const struct addrdesc
*addrdesc
)
523 struct single
*sfd
= &xfd
->stream
;
524 int pf
= addrdesc
->arg1
;
525 int socktype
= addrdesc
->arg2
;
526 int ipproto
= addrdesc
->arg3
;
527 union sockaddr_union us
;
528 socklen_t uslen
= sizeof(us
);
533 xio_syntax(argv
[0], 1, argc
-1, addrdesc
->syntax
);
537 xioinit_ip(&pf
, xioparms
.default_ip
);
538 sfd
->howtoend
= END_NONE
;
539 if (sfd
->howtoend
== END_UNSPEC
)
540 sfd
->howtoend
= END_NONE
;
541 retropt_socket_pf(opts
, &pf
);
542 if (pf
== PF_UNSPEC
) {
543 #if WITH_IP4 && WITH_IP6
544 switch (xioparms
.default_ip
) {
545 case '4': pf
= PF_INET
; break;
546 case '6': pf
= PF_INET6
; break;
547 default: break; /* includes \0 */
556 /* Set AI_PASSIVE, except when it is explicitely disabled */
557 ai_flags2
[0] = xfd
->stream
.para
.socket
.ip
.ai_flags
[0];
558 ai_flags2
[1] = xfd
->stream
.para
.socket
.ip
.ai_flags
[1];
559 if (!(ai_flags2
[1] & AI_PASSIVE
))
560 ai_flags2
[0] |= AI_PASSIVE
;
563 xioresolve(NULL
, argv
[1], pf
, socktype
, ipproto
, &us
, &uslen
,
568 if (pf
== PF_UNSPEC
) {
569 pf
= us
.soa
.sa_family
;
573 union sockaddr_union la
;
574 socklen_t lalen
= sizeof(la
);
576 if (retropt_bind(opts
, pf
, socktype
, ipproto
, &la
.soa
, &lalen
, 1,
577 sfd
->para
.socket
.ip
.ai_flags
)
581 case PF_INET
: us
.ip4
.sin_addr
= la
.ip4
.sin_addr
; break;
584 case PF_INET6
: us
.ip6
.sin6_addr
= la
.ip6
.sin6_addr
; break;
590 if (retropt_ushort(opts
, OPT_SOURCEPORT
, &sfd
->para
.socket
.ip
.sourceport
) >= 0) {
591 sfd
->para
.socket
.ip
.dosourceport
= true;
593 retropt_bool(opts
, OPT_LOWPORT
, &sfd
->para
.socket
.ip
.lowport
);
595 xfd
->stream
.dtype
= XIODATA_RECVFROM_ONE
;
597 _xioopen_dgram_recvfrom(sfd
, xioflags
, &us
.soa
, uslen
,
598 opts
, pf
, socktype
, ipproto
, E_ERROR
))
602 _xio_openlate(&xfd
->stream
, opts
);
607 int xioopen_udp_recv(
613 const struct addrdesc
*addrdesc
)
615 int pf
= addrdesc
->arg1
;
616 int socktype
= addrdesc
->arg2
;
617 int ipproto
= addrdesc
->arg3
;
618 union sockaddr_union us
;
619 socklen_t uslen
= sizeof(us
);
625 xio_syntax(argv
[0], 1, argc
-1, addrdesc
->syntax
);
629 retropt_socket_pf(opts
, &pf
);
630 if (pf
== PF_UNSPEC
) {
631 #if WITH_IP4 && WITH_IP6
632 switch (xioparms
.default_ip
) {
633 case '4': pf
= PF_INET
; break;
634 case '6': pf
= PF_INET6
; break;
635 default: break; /* includes \0 */
644 /* Set AI_PASSIVE, except when it is explicitely disabled */
645 ai_flags2
[0] = xfd
->stream
.para
.socket
.ip
.ai_flags
[0];
646 ai_flags2
[1] = xfd
->stream
.para
.socket
.ip
.ai_flags
[1];
647 if (!(ai_flags2
[1] & AI_PASSIVE
))
648 ai_flags2
[0] |= AI_PASSIVE
;
651 xioresolve(NULL
, argv
[1], pf
, socktype
, ipproto
, &us
, &uslen
,
656 if (pf
== PF_UNSPEC
) {
657 pf
= us
.soa
.sa_family
;
662 union sockaddr_union la
;
663 socklen_t lalen
= sizeof(la
);
665 if (retropt_bind(opts
, pf
, socktype
, ipproto
,
666 &xfd
->stream
.para
.socket
.la
.soa
, &lalen
, 1,
672 us
.ip4
.sin_addr
= xfd
->stream
.para
.socket
.la
.ip4
.sin_addr
; break;
676 us
.ip6
.sin6_addr
= xfd
->stream
.para
.socket
.la
.ip6
.sin6_addr
; break;
680 xfd
->stream
.para
.socket
.la
.soa
.sa_family
= pf
;
685 #if WITH_IP4 /*|| WITH_IP6*/
686 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
687 if (xioparserange(rangename
, pf
, &xfd
->stream
.para
.socket
.range
,
688 xfd
->stream
.para
.socket
.ip
.ai_flags
)
693 xfd
->stream
.para
.socket
.dorange
= true;
698 xio_retropt_tcpwrap(&xfd
->stream
, opts
);
699 #endif /* WITH_LIBWRAP */
701 if (retropt_ushort(opts
, OPT_SOURCEPORT
,
702 &xfd
->stream
.para
.socket
.ip
.sourceport
)
704 xfd
->stream
.para
.socket
.ip
.dosourceport
= true;
706 retropt_bool(opts
, OPT_LOWPORT
, &xfd
->stream
.para
.socket
.ip
.lowport
);
708 xfd
->stream
.dtype
= XIODATA_RECV
;
709 if ((result
= _xioopen_dgram_recv(&xfd
->stream
, xioflags
, &us
.soa
, uslen
,
710 opts
, pf
, socktype
, ipproto
, E_ERROR
))
714 _xio_openlate(&xfd
->stream
, opts
);
718 #endif /* _WITH_UDP && (WITH_IP4 || WITH_IP6) */