version 1.7.3.0
[socat.git] / xio-udp.c
blob4426d43c2efef9f45c97a026421002856fc21fb5
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)
11 #include "xioopen.h"
12 #include "xio-socket.h"
13 #include "xio-ip4.h"
14 #include "xio-ip6.h"
15 #include "xio-ip.h"
16 #include "xio-ipapp.h"
17 #include "xio-tcpwrap.h"
19 #include "xio-udp.h"
22 static
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);
26 static
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);
30 static
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);
34 static
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);
39 static
40 int _xioopen_udp_sendto(const char *hostname, const char *servname,
41 struct opt *opts,
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>") };
46 #if WITH_LISTEN
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>") };
54 #if WITH_IP4
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>") };
56 #if WITH_LISTEN
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>") };
63 #endif /* WITH_IP4 */
65 #if WITH_IP6
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>") };
67 #if WITH_LISTEN
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>") };
74 #endif /* WITH_IP6 */
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,
81 int protname) {
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;
87 struct pollfd readfd;
88 bool dofork = false;
89 pid_t pid;
90 char *rangename;
91 char infobuff[256];
92 unsigned char buff1[1];
93 socklen_t uslen;
94 socklen_t themlen;
95 int result;
97 if (argc != 2) {
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;
104 #elif WITH_IP6
105 pf = PF_INET6;
106 #else
107 pf = PF_INET;
108 #endif
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]);
122 if (false) {
124 #if WITH_IP4
125 } else if (pf == PF_INET) {
126 us.ip4.sin_port = parseport(portname, ipproto);
127 #endif
128 #if WITH_IP6
129 } else if (pf == PF_INET6) {
130 us.ip6.sin6_port = parseport(portname, ipproto);
131 #endif
132 } else {
133 Error1("xioopen_ipdgram_listen(): unknown address family %d", pf);
136 retropt_bool(opts, OPT_FORK, &dofork);
138 if (dofork) {
139 if (!(xioflags & XIO_MAYFORK)) {
140 Error("option fork not allowed here");
141 return STAT_NORETRY;
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) {
148 free(rangename);
149 return STAT_NORETRY;
151 free(rangename);
152 fd->stream.para.socket.dorange = true;
154 #endif
156 #if WITH_LIBWRAP
157 xio_retropt_tcpwrap(&fd->stream, opts);
158 #endif /* WITH_LIBWRAP */
160 if (retropt_ushort(opts, OPT_SOURCEPORT, &fd->stream.para.socket.ip.sourceport)
161 >= 0) {
162 fd->stream.para.socket.ip.dosourceport = true;
164 retropt_bool(opts, OPT_LOWPORT, &fd->stream.para.socket.ip.lowport);
166 if (dofork) {
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);
175 char infobuff[256];
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);
184 if (doreuseaddr) {
185 if (Setsockopt(fd->stream.fd, opt_so_reuseaddr.major,
186 opt_so_reuseaddr.minor, &reuseaddr, sizeof(reuseaddr))
187 < 0) {
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),
191 strerror(errno));
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);
219 do {
220 result = Recvfrom(fd->stream.fd, buff1, 1, MSG_PEEK,
221 &them->soa, &themlen);
222 } while (result < 0 && errno == EINTR);
223 if (result < 0) {
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) {
235 /* drop packet */
236 char buff[512];
237 Recv(fd->stream.fd, buff, sizeof(buff), 0); /* drop packet */
238 Close(fd->stream.fd);
239 continue;
241 Info1("permitting UDP connection from %s",
242 sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)));
244 if (dofork) {
245 pid = xio_fork(false, E_ERROR);
246 if (pid < 0) {
247 return STAT_RETRYLATER;
250 if (pid == 0) { /* child */
251 break;
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));
261 continue;
263 break;
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",
269 fd->stream.fd,
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)
288 return result;
290 return 0;
294 static
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) {
298 int result;
300 if (argc != 3) {
301 Error2("%s: wrong number of parameters (%d instead of 2)",
302 argv[0], argc-1);
303 return STAT_NORETRY;
306 retropt_socket_pf(opts, &pf);
307 if ((result = _xioopen_udp_sendto(argv[1], argv[2], opts, xioflags, xxfd,
308 groups, pf, socktype, ipproto))
309 != STAT_OK) {
310 return result;
312 _xio_openlate(&xxfd->stream, opts);
313 return STAT_OK;
317 applies and consumes the following option:
318 PH_INIT, PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE
319 OFUNC_OFFSET
320 OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
322 static
323 int _xioopen_udp_sendto(const char *hostname, const char *servname,
324 struct opt *opts,
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;
329 socklen_t uslen;
330 int feats = 3; /* option bind supports address and port */
331 bool needbind = false;
332 int result;
334 xfd->howtoend = END_SHUTDOWN;
336 /* ...res_opts[] */
337 if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
338 applyopts(-1, opts, PH_INIT);
340 xfd->salen = sizeof(xfd->peersa);
341 if ((result =
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]))
346 != STAT_OK) {
347 return result;
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])
356 != STAT_NOACTION) {
357 needbind = true;
360 if (retropt_ushort(opts, OPT_SOURCEPORT,
361 &xfd->para.socket.ip.sourceport) >= 0) {
362 switch (pf) {
363 #if WITH_IP4
364 case PF_INET:
365 us.ip4.sin_port = htons(xfd->para.socket.ip.sourceport);
366 break;
367 #endif
368 #if WITH_IP6
369 case PF_INET6:
370 us.ip6.sin6_port = htons(xfd->para.socket.ip.sourceport);
371 break;
372 #endif
374 needbind = true;
377 retropt_bool(opts, OPT_LOWPORT, &xfd->para.socket.ip.lowport);
378 if (xfd->para.socket.ip.lowport) {
379 switch (pf) {
380 #if WITH_IP4
381 case PF_INET:
382 /*!!! this is buggy */
383 us.ip4.sin_port = htons(xfd->para.socket.ip.lowport); break;
384 #endif
385 #if WITH_IP6
386 case PF_INET6:
387 /*!!! this is buggy */
388 us.ip6.sin6_port = htons(xfd->para.socket.ip.lowport); break;
389 #endif
391 needbind = true;
394 xfd->dtype = XIODATA_RECVFROM;
395 return _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
396 opts, xioflags, xfd, groups,
397 pf, socktype, ipproto);
401 static
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;
406 char *rangename;
407 char *hostname;
408 int result;
410 if (argc != 3) {
411 Error2("%s: wrong number of parameters (%d instead of 2)",
412 argv[0], argc-1);
413 return STAT_NORETRY;
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);
422 result =
423 _xioopen_udp_sendto(hostname, argv[2], opts, xioflags, xxfd, groups,
424 pf, socktype, ipproto);
425 free(hostname);
426 if (result != STAT_OK) {
427 return result;
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)
440 >= 0) {
441 if (xioparserange(rangename, pf, &xfd->para.socket.range) < 0) {
442 free(rangename);
443 return STAT_NORETRY;
445 xfd->para.socket.dorange = true;
446 xfd->dtype |= XIOREAD_RECV_CHECKRANGE;
447 free(rangename);
450 #if WITH_LIBWRAP
451 xio_retropt_tcpwrap(xfd, opts);
452 #endif /* WITH_LIBWRAP */
454 _xio_openlate(xfd, opts);
455 return STAT_OK;
459 static
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);
465 int result;
467 if (argc != 2) {
468 Error2("%s: wrong number of parameters (%d instead of 1)",
469 argv[0], argc-1);
470 return STAT_NORETRY;
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;
478 #elif WITH_IP6
479 pf = PF_INET6;
480 #else
481 pf = PF_INET;
482 #endif
485 if ((result =
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]))
489 != STAT_OK) {
490 return result;
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])
503 != STAT_NOACTION) {
504 switch (pf) {
505 #if WITH_IP4
506 case PF_INET: us.ip4.sin_addr = la.ip4.sin_addr; break;
507 #endif
508 #if WITH_IP6
509 case PF_INET6: us.ip6.sin6_addr = la.ip6.sin6_addr; break;
510 #endif
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;
521 if ((result =
522 _xioopen_dgram_recvfrom(&xfd->stream, xioflags, &us.soa, uslen,
523 opts, pf, socktype, ipproto, E_ERROR))
524 != STAT_OK) {
525 return result;
527 _xio_openlate(&xfd->stream, opts);
528 return STAT_OK;
532 static
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);
538 char *rangename;
539 int result;
541 if (argc != 2) {
542 Error2("%s: wrong number of parameters (%d instead of 1)",
543 argv[0], argc-1);
544 return STAT_NORETRY;
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;
551 #elif WITH_IP6
552 pf = PF_INET6;
553 #else
554 pf = PF_INET;
555 #endif
558 if ((result =
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]))
562 != STAT_OK) {
563 return result;
565 if (pf == PF_UNSPEC) {
566 pf = us.soa.sa_family;
569 #if 1
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])
578 != STAT_NOACTION) {
579 switch (pf) {
580 #if WITH_IP4
581 case PF_INET:
582 us.ip4.sin_addr = xfd->stream.para.socket.la.ip4.sin_addr; break;
583 #endif
584 #if WITH_IP6
585 case PF_INET6:
586 us.ip6.sin6_addr = xfd->stream.para.socket.la.ip6.sin6_addr; break;
587 #endif
589 } else {
590 xfd->stream.para.socket.la.soa.sa_family = pf;
593 #endif
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) {
598 return STAT_NORETRY;
600 xfd->stream.para.socket.dorange = true;
602 #endif
604 #if WITH_LIBWRAP
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)
610 >= 0) {
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))
618 != STAT_OK) {
619 return result;
621 _xio_openlate(&xfd->stream, opts);
622 return result;
625 #endif /* WITH_UDP && (WITH_IP4 || WITH_IP6) */