1 /* source: xio-socket.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 socket related functions, and the
6 implementation of generic socket addresses */
8 #include "xiosysincludes.h"
13 #include "xio-ascii.h"
14 #include "xio-socket.h"
15 #include "xio-named.h"
24 #include "xio-listen.h"
25 #include "xio-ipapp.h" /*! not clean */
26 #include "xio-tcpwrap.h"
30 int xioopen_socket_connect(int argc
, const char *argv
[], struct opt
*opts
,
31 int xioflags
, xiofile_t
*xfd
, unsigned groups
,
32 int dummy1
, int dummy2
, int dummy3
);
34 int xioopen_socket_listen(int argc
, const char *argv
[], struct opt
*opts
,
35 int xioflags
, xiofile_t
*xfd
, unsigned groups
,
36 int dummy1
, int dummy2
, int dummy3
);
38 int xioopen_socket_sendto(int argc
, const char *argv
[], struct opt
*opts
,
39 int xioflags
, xiofile_t
*xfd
, unsigned groups
,
40 int dummy1
, int dummy2
, int dummy3
);
42 int xioopen_socket_datagram(int argc
, const char *argv
[], struct opt
*opts
,
43 int xioflags
, xiofile_t
*xfd
, unsigned groups
,
44 int dummy1
, int dummy2
, int dummy3
);
46 int xioopen_socket_recvfrom(int argc
, const char *argv
[], struct opt
*opts
,
47 int xioflags
, xiofile_t
*xfd
, unsigned groups
,
48 int dummy1
, int socktype
, int dummy3
);
50 int xioopen_socket_recv(int argc
, const char *argv
[], struct opt
*opts
,
51 int xioflags
, xiofile_t
*xfd
, unsigned groups
,
52 int dumy1
, int dummy2
, int dummy3
);
55 int _xioopen_socket_sendto(const char *pfname
, const char *type
,
56 const char *proto
, const char *address
,
57 struct opt
*opts
, int xioflags
, xiofile_t
*xxfd
,
61 xiolog_ancillary_socket(struct cmsghdr
*cmsg
, int *num
,
62 char *typbuff
, int typlen
,
63 char *nambuff
, int namlen
,
64 char *envbuff
, int envlen
,
65 char *valbuff
, int vallen
);
68 #if WITH_GENERICSOCKET
69 /* generic socket addresses */
70 const struct addrdesc xioaddr_socket_connect
= { "socket-connect", 1, xioopen_socket_connect
, GROUP_FD
|GROUP_SOCKET
|GROUP_CHILD
|GROUP_RETRY
, 0, 0, 0 HELP(":<domain>:<protocol>:<remote-address>") };
72 const struct addrdesc xioaddr_socket_listen
= { "socket-listen", 1, xioopen_socket_listen
, GROUP_FD
|GROUP_SOCKET
|GROUP_LISTEN
|GROUP_RANGE
|GROUP_CHILD
|GROUP_RETRY
, 0, 0, 0 HELP(":<domain>:<protocol>:<local-address>") };
73 #endif /* WITH_LISTEN */
74 const struct addrdesc xioaddr_socket_sendto
= { "socket-sendto", 3, xioopen_socket_sendto
, GROUP_FD
|GROUP_SOCKET
, 0, 0, 0 HELP(":<domain>:<type>:<protocol>:<remote-address>") };
75 const struct addrdesc xioaddr_socket_datagram
= { "socket-datagram", 3, xioopen_socket_datagram
, GROUP_FD
|GROUP_SOCKET
|GROUP_RANGE
, 0, 0, 0 HELP(":<domain>:<type>:<protocol>:<remote-address>") };
76 const struct addrdesc xioaddr_socket_recvfrom
= { "socket-recvfrom", 3, xioopen_socket_recvfrom
, GROUP_FD
|GROUP_SOCKET
|GROUP_RANGE
|GROUP_CHILD
, 0, 0, 0 HELP(":<domain>:<type>:<protocol>:<local-address>") };
77 const struct addrdesc xioaddr_socket_recv
= { "socket-recv", 1, xioopen_socket_recv
, GROUP_FD
|GROUP_SOCKET
|GROUP_RANGE
, 0, 0, 0 HELP(":<domain>:<type>:<protocol>:<local-address>") };
78 #endif /* WITH_GENERICSOCKET */
81 /* the following options apply not only to generic socket addresses but to all
82 addresses that have anything to do with sockets */
83 const struct optdesc opt_so_debug
= { "so-debug", "debug", OPT_SO_DEBUG
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_DEBUG
};
84 #ifdef SO_ACCEPTCONN /* AIX433 */
85 const struct optdesc opt_so_acceptconn
={ "so-acceptconn","acceptconn",OPT_SO_ACCEPTCONN
,GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_ACCEPTCONN
};
86 #endif /* SO_ACCEPTCONN */
87 const struct optdesc opt_so_broadcast
= { "so-broadcast", "broadcast", OPT_SO_BROADCAST
,GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_BROADCAST
};
88 const struct optdesc opt_so_reuseaddr
= { "so-reuseaddr", "reuseaddr", OPT_SO_REUSEADDR
,GROUP_SOCKET
, PH_PREBIND
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_REUSEADDR
};
89 const struct optdesc opt_so_keepalive
= { "so-keepalive", "keepalive", OPT_SO_KEEPALIVE
,GROUP_SOCKET
, PH_FD
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_KEEPALIVE
};
90 #if HAVE_STRUCT_LINGER
91 const struct optdesc opt_so_linger
= { "so-linger", "linger", OPT_SO_LINGER
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_LINGER
,OFUNC_SOCKOPT
,SOL_SOCKET
, SO_LINGER
};
92 #else /* !HAVE_STRUCT_LINGER */
93 const struct optdesc opt_so_linger
= { "so-linger", "linger", OPT_SO_LINGER
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_LINGER
};
94 #endif /* !HAVE_STRUCT_LINGER */
95 const struct optdesc opt_so_oobinline
= { "so-oobinline", "oobinline", OPT_SO_OOBINLINE
,GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_OOBINLINE
};
96 const struct optdesc opt_so_sndbuf
= { "so-sndbuf", "sndbuf", OPT_SO_SNDBUF
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_SNDBUF
};
97 const struct optdesc opt_so_sndbuf_late
={ "so-sndbuf-late","sndbuf-late",OPT_SO_SNDBUF_LATE
,GROUP_SOCKET
,PH_LATE
,TYPE_INT
,OFUNC_SOCKOPT
,SOL_SOCKET
,SO_SNDBUF
};
98 const struct optdesc opt_so_rcvbuf
= { "so-rcvbuf", "rcvbuf", OPT_SO_RCVBUF
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_RCVBUF
};
99 const struct optdesc opt_so_rcvbuf_late
={"so-rcvbuf-late","rcvbuf-late",OPT_SO_RCVBUF_LATE
,GROUP_SOCKET
,PH_LATE
,TYPE_INT
,OFUNC_SOCKOPT
,SOL_SOCKET
,SO_RCVBUF
};
100 const struct optdesc opt_so_error
= { "so-error", "error", OPT_SO_ERROR
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_ERROR
};
101 const struct optdesc opt_so_type
= { "so-type", "type", OPT_SO_TYPE
, GROUP_SOCKET
, PH_SOCKET
, TYPE_INT
, OFUNC_SPEC
, SOL_SOCKET
, SO_TYPE
};
102 const struct optdesc opt_so_dontroute
= { "so-dontroute", "dontroute", OPT_SO_DONTROUTE
,GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_DONTROUTE
};
104 const struct optdesc opt_so_rcvlowat
= { "so-rcvlowat", "rcvlowat", OPT_SO_RCVLOWAT
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_RCVLOWAT
};
107 const struct optdesc opt_so_sndlowat
= { "so-sndlowat", "sndlowat", OPT_SO_SNDLOWAT
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_SNDLOWAT
};
109 /* end of setsockopt options of UNIX98 standard */
111 #ifdef SO_AUDIT /* AIX 4.3.3 */
112 const struct optdesc opt_so_audit
= { "so-audit", "audit", OPT_SO_AUDIT
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_AUDIT
};
113 #endif /* SO_AUDIT */
114 #ifdef SO_ATTACH_FILTER
115 const struct optdesc opt_so_attach_filter
={"so-attach-filter","attachfilter",OPT_SO_ATTACH_FILTER
,GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT
,OFUNC_SOCKOPT
,SOL_SOCKET
,SO_ATTACH_FILTER
};
117 #ifdef SO_DETACH_FILTER
118 const struct optdesc opt_so_detach_filter
={"so-detach-filter","detachfilter",OPT_SO_DETACH_FILTER
,GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT
,OFUNC_SOCKOPT
,SOL_SOCKET
,SO_DETACH_FILTER
};
120 #ifdef SO_BINDTODEVICE /* Linux: man 7 socket */
121 const struct optdesc opt_so_bindtodevice
={"so-bindtodevice","if",OPT_SO_BINDTODEVICE
,GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_NAME
,OFUNC_SOCKOPT
,SOL_SOCKET
,SO_BINDTODEVICE
};
124 const struct optdesc opt_so_bsdcompat
= { "so-bsdcompat","bsdcompat",OPT_SO_BSDCOMPAT
,GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_BSDCOMPAT
};
127 const struct optdesc opt_so_cksumrecv
= { "so-cksumrecv","cksumrecv",OPT_SO_CKSUMRECV
,GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_CKSUMRECV
};
128 #endif /* SO_CKSUMRECV */
130 const struct optdesc opt_so_timestamp
= { "so-timestamp","timestamp",OPT_SO_TIMESTAMP
,GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_TIMESTAMP
};
132 #ifdef SO_KERNACCEPT /* AIX 4.3.3 */
133 const struct optdesc opt_so_kernaccept
={ "so-kernaccept","kernaccept",OPT_SO_KERNACCEPT
,GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_KERNACCEPT
};
134 #endif /* SO_KERNACCEPT */
136 const struct optdesc opt_so_no_check
= { "so-no-check", "nocheck",OPT_SO_NO_CHECK
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_NO_CHECK
};
138 #ifdef SO_NOREUSEADDR /* AIX 4.3.3 */
139 const struct optdesc opt_so_noreuseaddr
={"so-noreuseaddr","noreuseaddr",OPT_SO_NOREUSEADDR
,GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT
,OFUNC_SOCKOPT
,SOL_SOCKET
, SO_NOREUSEADDR
};
140 #endif /* SO_NOREUSEADDR */
142 const struct optdesc opt_so_passcred
= { "so-passcred", "passcred", OPT_SO_PASSCRED
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_PASSCRED
};
145 const struct optdesc opt_so_peercred
= { "so-peercred", "peercred", OPT_SO_PEERCRED
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT3
,OFUNC_SOCKOPT
, SOL_SOCKET
, SO_PEERCRED
};
148 const struct optdesc opt_so_priority
= { "so-priority", "priority", OPT_SO_PRIORITY
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_PRIORITY
};
150 #ifdef SO_REUSEPORT /* AIX 4.3.3, BSD, HP-UX, Linux >=3.9 */
151 const struct optdesc opt_so_reuseport
= { "so-reuseport","reuseport",OPT_SO_REUSEPORT
,GROUP_SOCKET
, PH_PREBIND
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_REUSEPORT
};
152 #endif /* defined(SO_REUSEPORT) */
153 #ifdef SO_SECURITY_AUTHENTICATION
154 const struct optdesc opt_so_security_authentication
={"so-security-authentication","securityauthentication",OPT_SO_SECURITY_AUTHENTICATION
,GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT
,OFUNC_SOCKOPT
,SOL_SOCKET
,SO_SECURITY_AUTHENTICATION
};
156 #ifdef SO_SECURITY_ENCRYPTION_NETWORK
157 const struct optdesc opt_so_security_encryption_network
={"so-security-encryption-network","securityencryptionnetwork",OPT_SO_SECURITY_ENCRYPTION_NETWORK
,GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT
,OFUNC_SOCKOPT
,SOL_SOCKET
,SO_SECURITY_ENCRYPTION_NETWORK
};
159 #ifdef SO_SECURITY_ENCRYPTION_TRANSPORT
160 const struct optdesc opt_so_security_encryption_transport
={"so-security-encryption-transport","securityencryptiontransport",OPT_SO_SECURITY_ENCRYPTION_TRANSPORT
,GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT
,OFUNC_SOCKOPT
,SOL_SOCKET
,SO_SECURITY_ENCRYPTION_TRANSPORT
};
163 const struct optdesc opt_so_use_ifbufs
={ "so-use-ifbufs","useifbufs",OPT_SO_USE_IFBUFS
,GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_USE_IFBUFS
};
164 #endif /* SO_USE_IFBUFS */
165 #ifdef SO_USELOOPBACK /* AIX433, Solaris, HP-UX */
166 const struct optdesc opt_so_useloopback
={"so-useloopback","useloopback",OPT_SO_USELOOPBACK
,GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT
,OFUNC_SOCKOPT
, SOL_SOCKET
, SO_USELOOPBACK
};
167 #endif /* SO_USELOOPBACK */
168 #ifdef SO_DGRAM_ERRIND /* Solaris */
169 const struct optdesc opt_so_dgram_errind
={"so-dgram-errind","dgramerrind",OPT_SO_DGRAM_ERRIND
,GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT
,OFUNC_SOCKOPT
,SOL_SOCKET
,SO_DGRAM_ERRIND
};
170 #endif /* SO_DGRAM_ERRIND */
171 #ifdef SO_DONTLINGER /* Solaris */
172 const struct optdesc opt_so_dontlinger
= {"so-dontlinger", "dontlinger", OPT_SO_DONTLINGER
, GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT
,OFUNC_SOCKOPT
,SOL_SOCKET
,SO_DONTLINGER
};
174 /* the SO_PROTOTYPE is OS defined on Solaris, HP-UX; we lend this for a more
176 const struct optdesc opt_so_prototype
= {"so-prototype", "prototype", OPT_SO_PROTOTYPE
, GROUP_SOCKET
,PH_SOCKET
, TYPE_INT
,OFUNC_SPEC
, SOL_SOCKET
,SO_PROTOTYPE
};
178 const struct optdesc opt_fiosetown
= { "fiosetown", NULL
, OPT_FIOSETOWN
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_IOCTL
, FIOSETOWN
};
181 const struct optdesc opt_siocspgrp
= { "siocspgrp", NULL
, OPT_SIOCSPGRP
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_IOCTL
, SIOCSPGRP
};
183 const struct optdesc opt_bind
= { "bind", NULL
, OPT_BIND
, GROUP_SOCKET
, PH_BIND
, TYPE_STRING
,OFUNC_SPEC
};
184 const struct optdesc opt_connect_timeout
= { "connect-timeout", NULL
, OPT_CONNECT_TIMEOUT
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_TIMEVAL
, OFUNC_OFFSET
, XIO_OFFSETOF(para
.socket
.connect_timeout
) };
185 const struct optdesc opt_protocol_family
= { "protocol-family", "pf", OPT_PROTOCOL_FAMILY
, GROUP_SOCKET
, PH_PRESOCKET
, TYPE_STRING
, OFUNC_SPEC
};
186 const struct optdesc opt_protocol
= { "protocol", NULL
, OPT_PROTOCOL
, GROUP_SOCKET
, PH_PRESOCKET
, TYPE_STRING
, OFUNC_SPEC
};
188 /* generic setsockopt() options */
189 const struct optdesc opt_setsockopt_int
= { "setsockopt-int", "sockopt-int", OPT_SETSOCKOPT_INT
, GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT_INT_INT
, OFUNC_SOCKOPT_GENERIC
, 0, 0 };
190 const struct optdesc opt_setsockopt_bin
= { "setsockopt-bin", "sockopt-bin", OPT_SETSOCKOPT_BIN
, GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT_INT_BIN
, OFUNC_SOCKOPT_GENERIC
, 0, 0 };
191 const struct optdesc opt_setsockopt_string
= { "setsockopt-string", "sockopt-string", OPT_SETSOCKOPT_STRING
, GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT_INT_STRING
, OFUNC_SOCKOPT_GENERIC
, 0, 0 };
193 const struct optdesc opt_null_eof
= { "null-eof", NULL
, OPT_NULL_EOF
, GROUP_SOCKET
, PH_INIT
, TYPE_BOOL
, OFUNC_OFFSET
, XIO_OFFSETOF(para
.socket
.null_eof
) };
196 #if WITH_GENERICSOCKET
199 int xioopen_socket_connect(int argc
, const char *argv
[], struct opt
*opts
,
200 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
201 int dummy1
, int dummy2
, int dummy3
) {
202 struct single
*xfd
= &xxfd
->stream
;
203 const char *pfname
= argv
[1];
204 const char *protname
= argv
[2];
205 const char *address
= argv
[3];
209 int socktype
= SOCK_STREAM
;
211 union sockaddr_union them
; socklen_t themlen
; size_t themsize
;
212 union sockaddr_union us
; socklen_t uslen
= sizeof(us
);
216 Error2("%s: wrong number of parameters (%d instead of 3)",
221 pf
= strtoul(pfname
, &garbage
, 0);
222 if (*garbage
!= '\0') {
223 Warn1("garbage in parameter: \"%s\"", garbage
);
226 proto
= strtoul(protname
, &garbage
, 0);
227 if (*garbage
!= '\0') {
228 Warn1("garbage in parameter: \"%s\"", garbage
);
231 retropt_socket_pf(opts
, &pf
);
232 retropt_int(opts
, OPT_SO_TYPE
, &socktype
);
233 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
234 xfd
->howtoend
= END_SHUTDOWN
;
236 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return -1;
237 applyopts(-1, opts
, PH_INIT
);
238 applyopts(-1, opts
, PH_EARLY
);
242 dalan(address
, (char *)&them
.soa
.sa_data
, &themsize
, sizeof(them
)))
244 Error1("data too long: \"%s\"", address
);
245 } else if (result
> 0) {
246 Error1("syntax error in \"%s\"", address
);
248 them
.soa
.sa_family
= pf
;
250 #if HAVE_STRUCT_SOCKADDR_SALEN
251 sizeof(them
.soa
.sa_len
) +
253 sizeof(them
.soa
.sa_family
);
255 xfd
->dtype
= XIOREAD_STREAM
|XIOWRITE_STREAM
;
258 if (retropt_bind(opts
, 0 /*pf*/, socktype
, proto
, (struct sockaddr
*)&us
, &uslen
, 3,
262 us
.soa
.sa_family
= pf
;
267 needbind
?(struct sockaddr
*)&us
:NULL
, uslen
,
268 (struct sockaddr
*)&them
, themlen
,
269 opts
, pf
, socktype
, proto
, false)) != 0) {
272 if ((result
= _xio_openlate(xfd
, opts
)) < 0) {
280 int xioopen_socket_listen(int argc
, const char *argv
[], struct opt
*opts
,
281 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
282 int dummy1
, int dummy2
, int dummy3
) {
283 struct single
*xfd
= &xxfd
->stream
;
284 const char *pfname
= argv
[1];
285 const char *protname
= argv
[2];
286 const char *usname
= argv
[3];
290 int socktype
= SOCK_STREAM
;
291 union sockaddr_union us
; socklen_t uslen
; size_t ussize
;
296 Error2("%s: wrong number of parameters (%d instead of 3)",
301 pf
= strtoul(pfname
, &garbage
, 0);
302 if (*garbage
!= '\0') {
303 Warn1("garbage in parameter: \"%s\"", garbage
);
306 proto
= strtoul(protname
, &garbage
, 0);
307 if (*garbage
!= '\0') {
308 Warn1("garbage in parameter: \"%s\"", garbage
);
311 retropt_socket_pf(opts
, &pf
);
312 retropt_int(opts
, OPT_SO_TYPE
, &socktype
);
313 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
314 xfd
->howtoend
= END_SHUTDOWN
;
319 dalan(usname
, (char *)&us
.soa
.sa_data
, &ussize
, sizeof(us
)))
321 Error1("data too long: \"%s\"", usname
);
322 } else if (result
> 0) {
323 Error1("syntax error in \"%s\"", usname
);
325 uslen
= ussize
+ sizeof(us
.soa
.sa_family
)
326 #if HAVE_STRUCT_SOCKADDR_SALEN
327 + sizeof(us
.soa
.sa_len
)
330 us
.soa
.sa_family
= pf
;
332 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return -1;
333 applyopts(-1, opts
, PH_INIT
);
334 applyopts(-1, opts
, PH_EARLY
);
336 opts0
= copyopts(opts
, GROUP_ALL
);
339 xioopen_listen(xfd
, xioflags
,
340 (struct sockaddr
*)&us
, uslen
,
341 opts
, opts0
, 0/*instead of pf*/, socktype
, proto
))
346 #endif /* WITH_LISTEN */
348 /* we expect the form: ...:domain:type:protocol:remote-address */
350 int xioopen_socket_sendto(int argc
, const char *argv
[], struct opt
*opts
,
351 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
352 int dummy1
, int dummy2
, int dummy3
) {
356 Error2("%s: wrong number of parameters (%d instead of 4)",
361 _xioopen_socket_sendto(argv
[1], argv
[2], argv
[3], argv
[4],
362 opts
, xioflags
, xxfd
, groups
))
366 _xio_openlate(&xxfd
->stream
, opts
);
371 int _xioopen_socket_sendto(const char *pfname
, const char *type
,
372 const char *protname
, const char *address
,
373 struct opt
*opts
, int xioflags
, xiofile_t
*xxfd
,
375 xiosingle_t
*xfd
= &xxfd
->stream
;
377 union sockaddr_union us
= {{0}};
378 socklen_t uslen
= 0; size_t ussize
;
381 int socktype
= SOCK_RAW
;
383 bool needbind
= false;
384 char *bindstring
= NULL
;
387 pf
= strtoul(pfname
, &garbage
, 0);
388 if (*garbage
!= '\0') {
389 Warn1("garbage in parameter: \"%s\"", garbage
);
392 socktype
= strtoul(type
, &garbage
, 0);
393 if (*garbage
!= '\0') {
394 Warn1("garbage in parameter: \"%s\"", garbage
);
397 proto
= strtoul(protname
, &garbage
, 0);
398 if (*garbage
!= '\0') {
399 Warn1("garbage in parameter: \"%s\"", garbage
);
402 retropt_socket_pf(opts
, &pf
);
403 retropt_int(opts
, OPT_SO_TYPE
, &socktype
);
404 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
405 xfd
->howtoend
= END_SHUTDOWN
;
407 xfd
->peersa
.soa
.sa_family
= pf
;
410 dalan(address
, (char *)&xfd
->peersa
.soa
.sa_data
, &themsize
,
411 sizeof(xfd
->peersa
)))
413 Error1("data too long: \"%s\"", address
);
414 } else if (result
> 0) {
415 Error1("syntax error in \"%s\"", address
);
417 xfd
->salen
= themsize
+ sizeof(sa_family_t
)
418 #if HAVE_STRUCT_SOCKADDR_SALEN
419 + sizeof(xfd
->peersa
.soa
.sa_len
)
422 #if HAVE_STRUCT_SOCKADDR_SALEN
423 xfd
->peersa
.soa
.sa_len
=
424 sizeof(xfd
->peersa
.soa
.sa_len
) + sizeof(xfd
->peersa
.soa
.sa_family
) +
429 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return -1;
430 applyopts(-1, opts
, PH_INIT
);
432 if (pf
== PF_UNSPEC
) {
433 pf
= xfd
->peersa
.soa
.sa_family
;
436 xfd
->dtype
= XIODATA_RECVFROM
;
438 if (retropt_string(opts
, OPT_BIND
, &bindstring
) == 0) {
441 dalan(bindstring
, (char *)&us
.soa
.sa_data
, &ussize
, sizeof(us
)))
443 Error1("data too long: \"%s\"", bindstring
);
444 } else if (result
> 0) {
445 Error1("syntax error in \"%s\"", bindstring
);
447 us
.soa
.sa_family
= pf
;
448 uslen
= ussize
+ sizeof(sa_family_t
)
449 #if HAVE_STRUCT_SOCKADDR_SALEN
450 + sizeof(us
.soa
.sa_len
)
457 _xioopen_dgram_sendto(needbind
?&us
:NULL
, uslen
,
458 opts
, xioflags
, xfd
, groups
, pf
, socktype
, proto
);
462 /* we expect the form: ...:domain:socktype:protocol:local-address */
464 int xioopen_socket_recvfrom(int argc
, const char *argv
[], struct opt
*opts
,
465 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
466 int dummy
, int summy2
, int dummy3
) {
467 struct single
*xfd
= &xxfd
->stream
;
468 const char *pfname
= argv
[1];
469 const char *typename
= argv
[2];
470 const char *protname
= argv
[3];
471 const char *address
= argv
[4];
473 union sockaddr_union
*us
= &xfd
->para
.socket
.la
;
474 socklen_t uslen
; size_t ussize
;
475 int pf
, socktype
, proto
;
480 Error2("%s: wrong number of parameters (%d instead of 4)",
485 pf
= strtoul(pfname
, &garbage
, 0);
486 if (*garbage
!= '\0') {
487 Warn1("garbage in parameter: \"%s\"", garbage
);
490 socktype
= strtoul(typename
, &garbage
, 0);
491 if (*garbage
!= '\0') {
492 Warn1("garbage in parameter: \"%s\"", garbage
);
495 proto
= strtoul(protname
, &garbage
, 0);
496 if (*garbage
!= '\0') {
497 Warn1("garbage in parameter: \"%s\"", garbage
);
500 retropt_socket_pf(opts
, &pf
);
501 retropt_int(opts
, OPT_SO_TYPE
, &socktype
);
502 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
503 xfd
->howtoend
= END_NONE
;
507 dalan(address
, (char *)&us
->soa
.sa_data
, &ussize
, sizeof(*us
)))
509 Error1("data too long: \"%s\"", address
);
510 } else if (result
> 0) {
511 Error1("syntax error in \"%s\"", address
);
513 us
->soa
.sa_family
= pf
;
514 uslen
= ussize
+ sizeof(us
->soa
.sa_family
)
515 #if HAVE_STRUCT_SOCKADDR_SALEN
516 + sizeof(us
->soa
.sa_len
);
519 xfd
->dtype
= XIOREAD_RECV
|XIOWRITE_SENDTO
;
521 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
522 if (xioparserange(rangename
, 0, &xfd
->para
.socket
.range
) < 0) {
525 xfd
->para
.socket
.dorange
= true;
530 _xioopen_dgram_recvfrom(xfd
, xioflags
, &us
->soa
, uslen
,
531 opts
, pf
, socktype
, proto
, E_ERROR
))
535 _xio_openlate(xfd
, opts
);
539 /* we expect the form: ...:domain:type:protocol:local-address */
541 int xioopen_socket_recv(int argc
, const char *argv
[], struct opt
*opts
,
542 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
543 int dummy1
, int dummy2
, int dummy3
) {
544 struct single
*xfd
= &xxfd
->stream
;
545 const char *pfname
= argv
[1];
546 const char *typename
= argv
[2];
547 const char *protname
= argv
[3];
548 const char *address
= argv
[4];
550 union sockaddr_union us
;
551 socklen_t uslen
; size_t ussize
;
552 int pf
, socktype
, proto
;
557 Error2("%s: wrong number of parameters (%d instead of 4)",
562 pf
= strtoul(pfname
, &garbage
, 0);
563 if (*garbage
!= '\0') {
564 Warn1("garbage in parameter: \"%s\"", garbage
);
567 socktype
= strtoul(typename
, &garbage
, 0);
568 if (*garbage
!= '\0') {
569 Warn1("garbage in parameter: \"%s\"", garbage
);
572 proto
= strtoul(protname
, &garbage
, 0);
573 if (*garbage
!= '\0') {
574 Warn1("garbage in parameter: \"%s\"", garbage
);
577 retropt_socket_pf(opts
, &pf
);
578 retropt_int(opts
, OPT_SO_TYPE
, &socktype
);
579 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
580 xfd
->howtoend
= END_NONE
;
584 dalan(address
, (char *)&us
.soa
.sa_data
, &ussize
, sizeof(us
)))
586 Error1("data too long: \"%s\"", address
);
587 } else if (result
> 0) {
588 Error1("syntax error in \"%s\"", address
);
590 us
.soa
.sa_family
= pf
;
591 uslen
= ussize
+ sizeof(sa_family_t
)
592 #if HAVE_STRUCT_SOCKADDR_SALEN
593 +sizeof(us
.soa
.sa_len
)
596 xfd
->dtype
= XIOREAD_RECV
;
597 xfd
->para
.socket
.la
.soa
.sa_family
= pf
;
599 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
600 if (xioparserange(rangename
, 0, &xfd
->para
.socket
.range
) < 0) {
603 xfd
->para
.socket
.dorange
= true;
608 _xioopen_dgram_recv(xfd
, xioflags
, &us
.soa
,
609 uslen
, opts
, pf
, socktype
, proto
, E_ERROR
))
613 _xio_openlate(xfd
, opts
);
618 /* we expect the form: ...:domain:type:protocol:remote-address */
620 int xioopen_socket_datagram(int argc
, const char *argv
[], struct opt
*opts
,
621 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
622 int dummy1
, int dummy2
, int dummy3
) {
623 xiosingle_t
*xfd
= &xxfd
->stream
;
624 const char *pfname
= argv
[1];
625 const char *typename
= argv
[2];
626 const char *protname
= argv
[3];
627 const char *address
= argv
[4];
635 Error2("%s: wrong number of parameters (%d instead of 4)",
640 pf
= strtoul(pfname
, &garbage
, 0);
641 if (*garbage
!= '\0') {
642 Warn1("garbage in parameter: \"%s\"", garbage
);
645 retropt_socket_pf(opts
, &pf
);
646 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
647 xfd
->howtoend
= END_SHUTDOWN
;
649 xfd
->peersa
.soa
.sa_family
= pf
;
652 dalan(address
, (char *)&xfd
->peersa
.soa
.sa_data
, &themsize
,
653 sizeof(xfd
->peersa
)))
655 Error1("data too long: \"%s\"", address
);
656 } else if (result
> 0) {
657 Error1("syntax error in \"%s\"", address
);
659 xfd
->salen
= themsize
+ sizeof(sa_family_t
);
660 #if HAVE_STRUCT_SOCKADDR_SALEN
661 xfd
->peersa
.soa
.sa_len
=
662 sizeof(xfd
->peersa
.soa
.sa_len
) + sizeof(xfd
->peersa
.soa
.sa_family
) +
667 _xioopen_socket_sendto(pfname
, typename
, protname
, address
,
668 opts
, xioflags
, xxfd
, groups
))
673 xfd
->dtype
= XIOREAD_RECV
|XIOWRITE_SENDTO
;
675 xfd
->para
.socket
.la
.soa
.sa_family
= xfd
->peersa
.soa
.sa_family
;
677 /* which reply sockets will accept - determine by range option */
678 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
679 if (xioparserange(rangename
, 0, &xfd
->para
.socket
.range
) < 0) {
683 xfd
->para
.socket
.dorange
= true;
684 xfd
->dtype
|= XIOREAD_RECV_CHECKRANGE
;
688 _xio_openlate(xfd
, opts
);
692 #endif /* WITH_GENERICSOCKET */
695 /* a subroutine that is common to all socket addresses that want to connect
698 applies and consumes the following options:
699 PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT,
700 PH_CONNECTED, PH_LATE,
702 OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
703 returns 0 on success.
705 int _xioopen_connect(struct single
*xfd
, struct sockaddr
*us
, size_t uslen
,
706 struct sockaddr
*them
, size_t themlen
,
707 struct opt
*opts
, int pf
, int socktype
, int protocol
,
708 bool alt
, int level
) {
711 union sockaddr_union la
;
712 socklen_t lalen
= themlen
;
716 if ((xfd
->fd
= xiosocket(opts
, pf
, socktype
, protocol
, level
)) < 0) {
717 return STAT_RETRYLATER
;
720 applyopts_offset(xfd
, opts
);
721 applyopts(xfd
->fd
, opts
, PH_PASTSOCKET
);
722 applyopts(xfd
->fd
, opts
, PH_FD
);
724 applyopts_cloexec(xfd
->fd
, opts
);
726 applyopts(xfd
->fd
, opts
, PH_PREBIND
);
727 applyopts(xfd
->fd
, opts
, PH_BIND
);
728 #if WITH_TCP || WITH_UDP
730 union sockaddr_union sin
, *sinp
;
731 unsigned short *port
, i
, N
;
734 /* prepare sockaddr for bind probing */
736 sinp
= (union sockaddr_union
*)us
;
738 if (them
->sa_family
== AF_INET
) {
739 socket_in_init(&sin
.ip4
);
742 socket_in6_init(&sin
.ip6
);
747 if (them
->sa_family
== AF_INET
) {
748 port
= &sin
.ip4
.sin_port
;
750 } else if (them
->sa_family
== AF_INET6
) {
751 port
= &sin
.ip6
.sin6_port
;
754 port
= 0; /* just to make compiler happy */
756 /* combine random+step variant to quickly find a free port when only
757 few are in use, and certainly find a free port in defined time even
758 if there are almost all in use */
759 /* dirt 1: having tcp/udp code in socket function */
760 /* dirt 2: using a time related system call for init of random */
762 /* generate a random port, with millisecond random init */
766 srandom(tb
.time
*1000+tb
.millitm
);
770 tz
.tz_minuteswest
= 0;
772 if ((result
= Gettimeofday(&tv
, &tz
)) < 0) {
773 Warn2("gettimeofday(%p, {0,0}): %s", &tv
, strerror(errno
));
775 srandom(tv
.tv_sec
*1000000+tv
.tv_usec
);
778 dv
= div(random(), IPPORT_RESERVED
-XIO_IPPORT_LOWER
);
779 i
= N
= XIO_IPPORT_LOWER
+ dv
.rem
;
780 do { /* loop over lowport bind() attempts */
782 if (Bind(xfd
->fd
, (struct sockaddr
*)sinp
, sizeof(*sinp
)) < 0) {
783 Msg4(errno
==EADDRINUSE
?E_INFO
:level
,
784 "bind(%d, {%s}, "F_Zd
"): %s", xfd
->fd
,
785 sockaddr_info(&sinp
->soa
, sizeof(*sinp
), infobuff
, sizeof(infobuff
)),
786 sizeof(*sinp
), strerror(errno
));
787 if (errno
!= EADDRINUSE
) {
789 return STAT_RETRYLATER
;
792 break; /* could bind to port, good, continue past loop */
794 --i
; if (i
< XIO_IPPORT_LOWER
) i
= IPPORT_RESERVED
-1;
796 Msg(level
, "no low port available");
797 /*errno = EADDRINUSE; still assigned */
799 return STAT_RETRYLATER
;
803 #endif /* WITH_TCP || WITH_UDP */
806 if (Bind(xfd
->fd
, us
, uslen
) < 0) {
807 Msg4(level
, "bind(%d, {%s}, "F_Zd
"): %s",
808 xfd
->fd
, sockaddr_info(us
, uslen
, infobuff
, sizeof(infobuff
)),
809 uslen
, strerror(errno
));
811 return STAT_RETRYLATER
;
815 applyopts(xfd
->fd
, opts
, PH_PASTBIND
);
817 applyopts(xfd
->fd
, opts
, PH_CONNECT
);
819 if (xfd
->para
.socket
.connect_timeout
.tv_sec
!= 0 ||
820 xfd
->para
.socket
.connect_timeout
.tv_usec
!= 0) {
821 fcntl_flags
= Fcntl(xfd
->fd
, F_GETFL
);
822 Fcntl_l(xfd
->fd
, F_SETFL
, fcntl_flags
|O_NONBLOCK
);
825 result
= Connect(xfd
->fd
, (struct sockaddr
*)them
, themlen
);
827 la
.soa
.sa_family
= them
->sa_family
; lalen
= sizeof(la
);
828 if (Getsockname(xfd
->fd
, &la
.soa
, &lalen
) < 0) {
829 Msg4(level
-1, "getsockname(%d, %p, {%d}): %s",
830 xfd
->fd
, &la
.soa
, lalen
, strerror(errno
));
834 if (errno
== EINPROGRESS
) {
835 if (xfd
->para
.socket
.connect_timeout
.tv_sec
!= 0 ||
836 xfd
->para
.socket
.connect_timeout
.tv_usec
!= 0) {
837 struct timeval timeout
;
838 struct pollfd writefd
;
841 Info4("connect(%d, %s, "F_Zd
"): %s",
842 xfd
->fd
, sockaddr_info(them
, themlen
, infobuff
, sizeof(infobuff
)),
843 themlen
, strerror(errno
));
844 timeout
= xfd
->para
.socket
.connect_timeout
;
845 writefd
.fd
= xfd
->fd
;
846 writefd
.events
= (POLLOUT
|POLLERR
);
847 result
= xiopoll(&writefd
, 1, &timeout
);
849 Msg4(level
, "xiopoll({%d,POLLOUT|POLLERR},,{"F_tv_sec
"."F_tv_usec
"): %s",
850 xfd
->fd
, timeout
.tv_sec
, timeout
.tv_usec
, strerror(errno
));
851 return STAT_RETRYLATER
;
854 Msg2(level
, "connecting to %s: %s",
855 sockaddr_info(them
, themlen
, infobuff
, sizeof(infobuff
)),
856 strerror(ETIMEDOUT
));
857 return STAT_RETRYLATER
;
859 if (writefd
.revents
& POLLERR
) {
861 unsigned char dummy
[1];
862 Read(xfd
->fd
, &dummy
, 1); /* get error message */
863 Msg2(level
, "connecting to %s: %s",
864 sockaddr_info(them
, infobuff
, sizeof(infobuff
)),
867 Connect(xfd
->fd
, them
, themlen
); /* get error message */
868 Msg4(level
, "connect(%d, %s, "F_Zd
"): %s",
869 xfd
->fd
, sockaddr_info(them
, themlen
, infobuff
, sizeof(infobuff
)),
870 themlen
, strerror(errno
));
872 return STAT_RETRYLATER
;
875 Fcntl_l(xfd
->fd
, F_SETFL
, fcntl_flags
);
877 Warn4("connect(%d, %s, "F_Zd
"): %s",
878 xfd
->fd
, sockaddr_info(them
, themlen
, infobuff
, sizeof(infobuff
)),
879 themlen
, strerror(errno
));
881 } else if (pf
== PF_UNIX
&& errno
== EPROTOTYPE
) {
882 /* this is for UNIX domain sockets: a connect attempt seems to be
883 the only way to distinguish stream and datagram sockets */
885 Info4("connect(%d, %s, "F_Zd
"): %s",
886 xfd
->fd
, sockaddr_info(them
, themlen
, infobuff
, sizeof(infobuff
)),
887 themlen
, strerror(errno
));
889 Info("assuming datagram socket");
890 xfd
->dtype
= DATA_RECVFROM
;
891 xfd
->salen
= themlen
;
892 memcpy(&xfd
->peersa
.soa
, them
, xfd
->salen
);
894 /*!!! and remove bind socket */
895 Close(xfd
->fd
); xfd
->fd
= -1;
899 Msg4(level
, "connect(%d, %s, "F_Zd
"): %s",
900 xfd
->fd
, sockaddr_info(them
, themlen
, infobuff
, sizeof(infobuff
)),
901 themlen
, strerror(errno
));
903 return STAT_RETRYLATER
;
905 } else { /* result >= 0 */
906 Notice1("successfully connected from local address %s",
907 sockaddr_info(&la
.soa
, themlen
, infobuff
, sizeof(infobuff
)));
910 applyopts_fchown(xfd
->fd
, opts
); /* OPT_USER, OPT_GROUP */
911 applyopts(xfd
->fd
, opts
, PH_CONNECTED
);
912 applyopts(xfd
->fd
, opts
, PH_LATE
);
918 /* a subroutine that is common to all socket addresses that want to connect
921 applies and consumes the following option:
922 PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT,
923 PH_CONNECTED, PH_LATE,
925 OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
926 returns 0 on success.
928 int xioopen_connect(struct single
*xfd
, struct sockaddr
*us
, size_t uslen
,
929 struct sockaddr
*them
, size_t themlen
,
930 struct opt
*opts
, int pf
, int socktype
, int protocol
,
938 retropt_bool(opts
, OPT_FORK
, &dofork
);
940 opts0
= copyopts(opts
, GROUP_ALL
);
942 Notice1("opening connection to %s",
943 sockaddr_info(them
, themlen
, infobuff
, sizeof(infobuff
)));
945 do { /* loop over retries and forks */
948 if (xfd
->forever
|| xfd
->retry
) {
951 #endif /* WITH_RETRY */
954 _xioopen_connect(xfd
, us
, uslen
, them
, themlen
, opts
,
955 pf
, socktype
, protocol
, alt
, level
);
959 case STAT_RETRYLATER
:
960 if (xfd
->forever
|| xfd
->retry
) {
962 if (result
== STAT_RETRYLATER
) {
963 Nanosleep(&xfd
->intervall
, NULL
);
965 dropopts(opts
, PH_ALL
); opts
= copyopts(opts0
, GROUP_ALL
);
969 #endif /* WITH_RETRY */
975 xiosetchilddied(); /* set SIGCHLD handler */
982 if (xfd
->forever
|| xfd
->retry
) {
983 level
= E_WARN
; /* most users won't expect a problem here,
984 so Notice is too weak */
987 while ((pid
= xio_fork(false, level
)) < 0) {
989 if (xfd
->forever
|| xfd
->retry
) {
990 dropopts(opts
, PH_ALL
); opts
= copyopts(opts0
, GROUP_ALL
);
991 Nanosleep(&xfd
->intervall
, NULL
); continue;
993 return STAT_RETRYLATER
;
996 if (pid
== 0) { /* child process */
1000 /* parent process */
1002 /* with and without retry */
1003 Nanosleep(&xfd
->intervall
, NULL
);
1004 dropopts(opts
, PH_ALL
); opts
= copyopts(opts0
, GROUP_ALL
);
1005 continue; /* with next socket() bind() connect() */
1007 #endif /* WITH_RETRY */
1012 if ((result
= _xio_openlate(fd
, opts
)) < 0)
1021 /* common to xioopen_udp_sendto, ..unix_sendto, ..rawip
1022 applies and consumes the following option:
1023 PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE
1025 OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
1027 int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
1028 union sockaddr_union
*us
, socklen_t uslen
,
1030 int xioflags
, xiosingle_t
*xfd
, unsigned groups
,
1031 int pf
, int socktype
, int ipproto
) {
1032 int level
= E_ERROR
;
1033 union sockaddr_union la
; socklen_t lalen
= sizeof(la
);
1036 if ((xfd
->fd
= xiosocket(opts
, pf
, socktype
, ipproto
, level
)) < 0) {
1037 return STAT_RETRYLATER
;
1040 applyopts_offset(xfd
, opts
);
1041 applyopts_single(xfd
, opts
, PH_PASTSOCKET
);
1042 applyopts(xfd
->fd
, opts
, PH_PASTSOCKET
);
1043 applyopts(xfd
->fd
, opts
, PH_FD
);
1045 applyopts_cloexec(xfd
->fd
, opts
);
1047 applyopts(xfd
->fd
, opts
, PH_PREBIND
);
1048 applyopts(xfd
->fd
, opts
, PH_BIND
);
1051 if (Bind(xfd
->fd
, (struct sockaddr
*)us
, uslen
) < 0) {
1052 Msg4(level
, "bind(%d, {%s}, "F_socklen
"): %s",
1053 xfd
->fd
, sockaddr_info((struct sockaddr
*)us
, uslen
, infobuff
, sizeof(infobuff
)),
1054 uslen
, strerror(errno
));
1056 return STAT_RETRYLATER
;
1060 applyopts(xfd
->fd
, opts
, PH_PASTBIND
);
1062 /*applyopts(xfd->fd, opts, PH_CONNECT);*/
1064 if (Getsockname(xfd
->fd
, &la
.soa
, &lalen
) < 0) {
1065 Warn4("getsockname(%d, %p, {%d}): %s",
1066 xfd
->fd
, &la
.soa
, lalen
, strerror(errno
));
1069 applyopts_fchown(xfd
->fd
, opts
);
1070 applyopts(xfd
->fd
, opts
, PH_CONNECTED
);
1071 applyopts(xfd
->fd
, opts
, PH_LATE
);
1073 /* xfd->dtype = DATA_RECVFROM; *//* no, the caller must set this (ev _SKIPIP) */
1074 Notice1("successfully prepared local socket %s",
1075 sockaddr_info(&la
.soa
, lalen
, infobuff
, sizeof(infobuff
)));
1081 /* when the recvfrom address (with option fork) receives a packet it keeps this
1082 packet in the IP stacks input queue and forks a sub process. The sub process
1083 then reads this packet for processing its data.
1084 There is a problem because the parent process would find the same packet
1085 again if it calls select()/poll() before the child process reads the
1087 To solve this problem we implement the following mechanism:
1088 The sub process sends a SIGUSR1 when it has read the packet (or a SIGCHLD if
1089 it dies before). The parent process waits until it receives that signal and
1090 only then continues to listen.
1091 To prevent a signal from another process to trigger our loop, we pass the
1092 pid of the sub process to the signal handler in xio_waitingfor. The signal
1093 handler sets xio_hashappened if the pid matched.
1095 static pid_t xio_waitingfor
; /* info from recv loop to signal handler:
1096 indicates the pid of the child process
1097 that should send us the USR1 signal */
1098 static bool xio_hashappened
; /* info from signal handler to loop: child
1099 process has read ("consumed") the packet */
1100 /* this is the signal handler for USR1 and CHLD */
1101 void xiosigaction_hasread(int signum
1102 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
1103 , siginfo_t
*siginfo
, void *ucontext
1109 bool wassig
= false;
1112 diag_in_handler
= 1;
1113 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
1114 Debug5("xiosigaction_hasread(%d, {%d,%d,%d,"F_pid
"}, )",
1115 signum
, siginfo
->si_signo
, siginfo
->si_errno
, siginfo
->si_code
,
1118 Debug1("xiosigaction_hasread(%d)", signum
);
1120 if (signum
== SIGCHLD
) {
1122 pid
= Waitpid(-1, &status
, WNOHANG
);
1124 Msg(wassig
?E_INFO
:E_WARN
,
1125 "waitpid(-1, {}, WNOHANG): no child has exited");
1126 Info("xiosigaction_hasread() finished");
1127 Debug("xiosigaction_hasread() ->");
1128 diag_in_handler
= 0;
1131 } else if (pid
< 0 && errno
== ECHILD
) {
1132 Msg(wassig
?E_INFO
:E_WARN
,
1133 "waitpid(-1, {}, WNOHANG): "F_strerror
);
1134 Info("xiosigaction_hasread() finished");
1135 Debug("xiosigaction_hasread() ->");
1136 diag_in_handler
= 0;
1142 Warn1("waitpid(-1, {%d}, WNOHANG): "F_strerror
, status
);
1143 Info("xiosigaction_hasread() finished");
1144 Debug("xiosigaction_hasread() ->");
1145 diag_in_handler
= 0;
1149 if (pid
== xio_waitingfor
) {
1150 xio_hashappened
= true;
1151 Debug("xiosigaction_hasread() ->");
1152 diag_in_handler
= 0;
1158 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
1159 if (xio_waitingfor
== siginfo
->si_pid
) {
1160 xio_hashappened
= true;
1163 xio_hashappened
= true;
1166 Signal(sig
, xiosigaction_hasread
);
1167 #endif /* !HAVE_SIGACTION */
1168 Debug("xiosigaction_hasread() ->");
1169 diag_in_handler
= 0;
1175 /* waits for incoming packet, checks its source address and port. Depending
1176 on fork option, it may fork a subprocess.
1177 Returns STAT_OK if a the packet was accepted; with fork option, this is already in
1179 Other return values indicate a problem; this can happen in the master
1180 process or in a subprocess.
1181 This function does not retry. If you need retries, handle this is a
1182 loop in the calling function.
1183 after fork, we set the forever/retry of the child process to 0
1184 applies and consumes the following options:
1185 PH_INIT, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_EARLY, PH_PREOPEN, PH_FD,
1186 PH_CONNECTED, PH_LATE, PH_LATE2
1187 OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, cloexec, OPT_RANGE, tcpwrap
1189 int _xioopen_dgram_recvfrom(struct single
*xfd
, int xioflags
,
1190 struct sockaddr
*us
, socklen_t uslen
,
1192 int pf
, int socktype
, int proto
, int level
) {
1194 bool dofork
= false;
1195 pid_t pid
; /* mostly int; only used with fork */
1198 bool drop
= false; /* true if current packet must be dropped */
1201 retropt_bool(opts
, OPT_FORK
, &dofork
);
1204 if (!(xioflags
& XIO_MAYFORK
)) {
1205 Error("option fork not allowed here");
1206 return STAT_NORETRY
;
1208 xfd
->flags
|= XIO_DOESFORK
;
1211 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return STAT_NORETRY
;
1213 if ((xfd
->fd
= xiosocket(opts
, pf
, socktype
, proto
, level
)) < 0) {
1214 return STAT_RETRYLATER
;
1217 applyopts_single(xfd
, opts
, PH_PASTSOCKET
);
1218 applyopts(xfd
->fd
, opts
, PH_PASTSOCKET
);
1220 applyopts_cloexec(xfd
->fd
, opts
);
1222 applyopts(xfd
->fd
, opts
, PH_PREBIND
);
1223 applyopts(xfd
->fd
, opts
, PH_BIND
);
1224 if ((us
!= NULL
) && Bind(xfd
->fd
, (struct sockaddr
*)us
, uslen
) < 0) {
1225 Msg4(level
, "bind(%d, {%s}, "F_socklen
"): %s", xfd
->fd
,
1226 sockaddr_info(us
, uslen
, infobuff
, sizeof(infobuff
)), uslen
,
1229 return STAT_RETRYLATER
;
1233 if (pf
== AF_UNIX
&& us
!= NULL
) {
1234 applyopts_named(((struct sockaddr_un
*)us
)->sun_path
, opts
, PH_FD
);
1238 applyopts(xfd
->fd
, opts
, PH_PASTBIND
);
1240 if (pf
== AF_UNIX
&& us
!= NULL
) {
1241 /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
1242 applyopts_named(((struct sockaddr_un
*)us
)->sun_path
, opts
, PH_EARLY
);
1243 applyopts_named(((struct sockaddr_un
*)us
)->sun_path
, opts
, PH_PREOPEN
);
1245 #endif /* WITH_UNIX */
1247 /* for generic sockets, this has already been retrieved */
1248 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
1249 if (xioparserange(rangename
, pf
, &xfd
->para
.socket
.range
)
1252 return STAT_NORETRY
;
1255 xfd
->para
.socket
.dorange
= true;
1258 #if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
1259 xio_retropt_tcpwrap(xfd
, opts
);
1260 #endif /* && (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
1262 if (xioopts
.logopt
== 'm') {
1263 Info("starting recvfrom loop, switching to syslog");
1264 diag_set('y', xioopts
.syslogfac
); xioopts
.logopt
= 'y';
1266 Info("starting recvfrom loop");
1272 struct sigaction act
;
1273 memset(&act
, 0, sizeof(struct sigaction
));
1274 act
.sa_flags
= SA_NOCLDSTOP
/*|SA_RESTART*/
1275 #ifdef SA_SIGINFO /* not on Linux 2.0(.33) */
1282 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
1283 act
.sa_sigaction
= xiosigaction_hasread
;
1284 #else /* Linux 2.0(.33) does not have sigaction.sa_sigaction */
1285 act
.sa_handler
= xiosigaction_hasread
;
1287 sigfillset(&act
.sa_mask
);
1288 if (Sigaction(SIGUSR1
, &act
, NULL
) < 0) {
1289 /*! Linux man does not explicitely say that errno is defined */
1290 Warn1("sigaction(SIGUSR1, {&xiosigaction_subaddr_ok}, NULL): %s", strerror(errno
));
1292 if (Sigaction(SIGCHLD
, &act
, NULL
) < 0) {
1293 /*! Linux man does not explicitely say that errno is defined */
1294 Warn1("sigaction(SIGCHLD, {&xiosigaction_subaddr_ok}, NULL): %s", strerror(errno
));
1297 #else /* !HAVE_SIGACTION */
1299 if (Signal(SIGUSR1
, xiosigaction_hasread
) == SIG_ERR
) {
1300 Warn1("signal(SIGUSR1, xiosigaction_hasread): %s", strerror(errno
));
1302 if (Signal(SIGCHLD
, xiosigaction_hasread
) == SIG_ERR
) {
1303 Warn1("signal(SIGCHLD, xiosigaction_hasread): %s", strerror(errno
));
1305 #endif /* !HAVE_SIGACTION */
1308 while (true) { /* but we only loop if fork option is set */
1310 union sockaddr_union _peername
;
1311 union sockaddr_union _sockname
;
1312 union sockaddr_union
*pa
= &_peername
; /* peer address */
1313 union sockaddr_union
*la
= &_sockname
; /* local address */
1314 socklen_t palen
= sizeof(_peername
); /* peer address size */
1315 char ctrlbuff
[1024]; /* ancillary messages */
1316 struct msghdr msgh
= {0};
1318 socket_init(pf
, pa
);
1323 Recv(xfd
->fd
, dummy
, sizeof(dummy
), 0);
1327 /* loop until select()/poll() returns valid */
1329 struct pollfd readfd
;
1330 /*? int level = E_ERROR;*/
1332 Notice1("receiving on %s", sockaddr_info(us
, uslen
, lisname
, sizeof(lisname
)));
1334 Notice1("receiving IP protocol %u", proto
);
1336 readfd
.fd
= xfd
->fd
;
1337 readfd
.events
= POLLIN
;
1338 if (xiopoll(&readfd
, 1, NULL
) > 0) {
1342 if (errno
== EINTR
) {
1346 Msg2(level
, "poll({%d,,},,-1): %s", xfd
->fd
, strerror(errno
));
1348 return STAT_RETRYLATER
;
1352 msgh
.msg_namelen
= palen
;
1353 #if HAVE_STRUCT_MSGHDR_MSGCONTROL
1354 msgh
.msg_control
= ctrlbuff
;
1356 #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
1357 msgh
.msg_controllen
= sizeof(ctrlbuff
);
1359 if (xiogetpacketsrc(xfd
->fd
, &msgh
) < 0) {
1360 return STAT_RETRYLATER
;
1362 palen
= msgh
.msg_namelen
;
1364 Notice1("receiving packet from %s"/*"src"*/,
1365 sockaddr_info((struct sockaddr
*)pa
, palen
, peername
, sizeof(peername
))/*,
1366 sockaddr_info(&la->soa, sockname, sizeof(sockname))*/);
1368 xiodopacketinfo(&msgh
, true, true);
1370 if (xiocheckpeer(xfd
, pa
, la
) < 0) {
1373 Recv(xfd
->fd
, buff
, sizeof(buff
), 0);
1376 Info1("permitting packet from %s",
1377 sockaddr_info((struct sockaddr
*)pa
, palen
,
1378 infobuff
, sizeof(infobuff
)));
1380 /* set the env vars describing the local and remote sockets */
1381 /*xiosetsockaddrenv("SOCK", la, lalen, proto);*/
1382 xiosetsockaddrenv("PEER", pa
, palen
, proto
);
1384 applyopts(xfd
->fd
, opts
, PH_FD
);
1386 applyopts(xfd
->fd
, opts
, PH_CONNECTED
);
1388 xfd
->peersa
= *(union sockaddr_union
*)pa
;
1392 sigset_t mask_sigchldusr1
;
1394 /* we must prevent that the current packet triggers another fork;
1395 therefore we wait for a signal from the recent child: USR1
1396 indicates that is has consumed the last packet; CHLD means it has
1398 /* block SIGCHLD and SIGUSR1 until parent is ready to react */
1399 sigemptyset(&mask_sigchldusr1
);
1400 sigaddset(&mask_sigchldusr1
, SIGCHLD
);
1401 sigaddset(&mask_sigchldusr1
, SIGUSR1
);
1402 Sigprocmask(SIG_BLOCK
, &mask_sigchldusr1
, NULL
);
1404 if ((pid
= xio_fork(false, level
)) < 0) {
1406 Sigprocmask(SIG_UNBLOCK
, &mask_sigchldusr1
, NULL
);
1407 return STAT_RETRYLATER
;
1410 if (pid
== 0) { /* child */
1411 /* no reason to block SIGCHLD in child process */
1412 Sigprocmask(SIG_UNBLOCK
, &mask_sigchldusr1
, NULL
);
1413 xfd
->ppid
= Getppid(); /* send parent a signal when packet has
1421 #endif /* WITH_RETRY */
1424 /* with UNIX sockets: only listening parent is allowed to remove
1426 xfd
->opt_unlink_close
= false;
1427 #endif /* WITH_UNIX */
1432 /* server: continue loop with listen */
1433 xio_waitingfor
= pid
;
1434 /* now we are ready to handle signals */
1435 Sigprocmask(SIG_UNBLOCK
, &mask_sigchldusr1
, NULL
);
1437 while (!xio_hashappened
) {
1438 Sleep(UINT_MAX
); /* any signal lets us continue */
1440 xio_waitingfor
= 0; /* so this child will not set hashappened again */
1441 xio_hashappened
= false;
1443 Info("continue listening");
1448 if ((result
= _xio_openlate(xfd
, opts
)) != 0)
1449 return STAT_NORETRY
;
1455 /* returns STAT_* */
1456 int _xioopen_dgram_recv(struct single
*xfd
, int xioflags
,
1457 struct sockaddr
*us
, socklen_t uslen
,
1458 struct opt
*opts
, int pf
, int socktype
, int proto
,
1463 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return STAT_NORETRY
;
1465 if ((xfd
->fd
= xiosocket(opts
, pf
, socktype
, proto
, level
)) < 0) {
1466 return STAT_RETRYLATER
;
1469 applyopts_single(xfd
, opts
, PH_PASTSOCKET
);
1470 applyopts(xfd
->fd
, opts
, PH_PASTSOCKET
);
1472 applyopts_cloexec(xfd
->fd
, opts
);
1474 applyopts(xfd
->fd
, opts
, PH_PREBIND
);
1475 applyopts(xfd
->fd
, opts
, PH_BIND
);
1476 if ((us
!= NULL
) && Bind(xfd
->fd
, (struct sockaddr
*)us
, uslen
) < 0) {
1477 Msg4(level
, "bind(%d, {%s}, "F_socklen
"): %s", xfd
->fd
,
1478 sockaddr_info(us
, uslen
, infobuff
, sizeof(infobuff
)), uslen
,
1481 return STAT_RETRYLATER
;
1485 if (pf
== AF_UNIX
&& us
!= NULL
) {
1486 applyopts_named(((struct sockaddr_un
*)us
)->sun_path
, opts
, PH_FD
);
1490 applyopts_single(xfd
, opts
, PH_PASTBIND
);
1491 applyopts(xfd
->fd
, opts
, PH_PASTBIND
);
1493 if (pf
== AF_UNIX
&& us
!= NULL
) {
1494 /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
1495 applyopts_named(((struct sockaddr_un
*)us
)->sun_path
, opts
, PH_EARLY
);
1496 applyopts_named(((struct sockaddr_un
*)us
)->sun_path
, opts
, PH_PREOPEN
);
1498 #endif /* WITH_UNIX */
1500 #if WITH_IP4 /*|| WITH_IP6*/
1501 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
1502 if (xioparserange(rangename
, pf
, &xfd
->para
.socket
.range
)
1505 return STAT_NORETRY
;
1508 xfd
->para
.socket
.dorange
= true;
1512 #if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
1513 xio_retropt_tcpwrap(xfd
, opts
);
1514 #endif /* && (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
1516 if (xioopts
.logopt
== 'm') {
1517 Info("starting recvfrom loop, switching to syslog");
1518 diag_set('y', xioopts
.syslogfac
); xioopts
.logopt
= 'y';
1520 Info("starting recvfrom loop");
1527 int retropt_socket_pf(struct opt
*opts
, int *pf
) {
1530 if (retropt_string(opts
, OPT_PROTOCOL_FAMILY
, &pfname
) >= 0) {
1531 if (isdigit(pfname
[0])) {
1532 *pf
= strtoul(pfname
, NULL
/*!*/, 0);
1534 } else if (!strcasecmp("inet", pfname
) ||
1535 !strcasecmp("inet4", pfname
) ||
1536 !strcasecmp("ip4", pfname
) ||
1537 !strcasecmp("ipv4", pfname
) ||
1538 !strcasecmp("2", pfname
)) {
1540 #endif /* WITH_IP4 */
1542 } else if (!strcasecmp("inet6", pfname
) ||
1543 !strcasecmp("ip6", pfname
) ||
1544 !strcasecmp("ipv6", pfname
) ||
1545 !strcasecmp("10", pfname
)) {
1547 #endif /* WITH_IP6 */
1549 Error1("unknown protocol family \"%s\"", pfname
);
1550 /*! Warn("falling back to INET");*/
1559 /* this function calls recvmsg(..., MSG_PEEK, ...) to obtain information about
1560 the arriving packet. in msgh the msg_name pointer must refer to an (empty)
1561 sockaddr storage. */
1562 int xiogetpacketsrc(int fd
, struct msghdr
*msgh
) {
1564 #if HAVE_STRUCT_IOVEC
1568 #if HAVE_STRUCT_IOVEC
1569 iovec
.iov_base
= peekbuff
;
1570 iovec
.iov_len
= sizeof(peekbuff
);
1571 msgh
->msg_iov
= &iovec
;
1572 msgh
->msg_iovlen
= 1;
1574 #if HAVE_STRUCT_MSGHDR_MSGFLAGS
1575 msgh
->msg_flags
= 0;
1577 if (Recvmsg(fd
, msgh
, MSG_PEEK
1582 Warn1("recvmsg(): %s", strerror(errno
));
1583 return STAT_RETRYLATER
;
1589 /* works through the ancillary messages found in the given socket header record
1590 and logs the relevant information (E_DEBUG, E_INFO).
1591 calls protocol/layer specific functions for handling the messages
1592 creates appropriate environment vars if withenv is set */
1593 int xiodopacketinfo(struct msghdr
*msgh
, bool withlog
, bool withenv
) {
1594 #if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)
1595 struct cmsghdr
*cmsg
;
1597 /* parse ancillary messages */
1598 cmsg
= CMSG_FIRSTHDR(msgh
);
1599 while (cmsg
!= NULL
) {
1600 int num
= 0; /* number of data components of a ancill.msg */
1602 char typbuff
[16], *typp
;
1603 char nambuff
[128], *namp
;
1604 char valbuff
[256], *valp
;
1605 char envbuff
[256], *envp
;
1608 xiodump(CMSG_DATA(cmsg
),
1609 cmsg
->cmsg_len
-((char *)CMSG_DATA(cmsg
)-(char *)cmsg
),
1610 valbuff
, sizeof(valbuff
)-1, 0);
1611 Debug4("ancillary message: len="F_cmsg_len
", level=%d, type=%d, data=%s",
1612 cmsg
->cmsg_len
, cmsg
->cmsg_level
, cmsg
->cmsg_type
,
1616 /* try to get the anc.msg. contents in handy components, protocol/level
1618 switch (cmsg
->cmsg_level
) {
1620 xiolog_ancillary_socket(cmsg
, &num
, typbuff
, sizeof(typbuff
)-1,
1621 nambuff
, sizeof(nambuff
)-1,
1622 envbuff
, sizeof(envbuff
)-1,
1623 valbuff
, sizeof(valbuff
)-1);
1625 #if WITH_IP4 || WITH_IP6
1627 xiolog_ancillary_ip(cmsg
, &num
, typbuff
, sizeof(typbuff
)-1,
1628 nambuff
, sizeof(nambuff
)-1,
1629 envbuff
, sizeof(envbuff
)-1,
1630 valbuff
, sizeof(valbuff
)-1);
1632 #endif /* WITH_IP4 || WITH_IP6 */
1635 xiolog_ancillary_ip6(cmsg
, &num
, typbuff
, sizeof(typbuff
)-1,
1636 nambuff
, sizeof(nambuff
)-1,
1637 envbuff
, sizeof(envbuff
)-1,
1638 valbuff
, sizeof(valbuff
)-1);
1640 #endif /* WITH_IP6 */
1643 snprintf(typbuff
, sizeof(typbuff
)-1, "LEVEL%u", cmsg
->cmsg_level
);
1644 snprintf(nambuff
, sizeof(nambuff
)-1, "type%u", cmsg
->cmsg_type
);
1645 xiodump(CMSG_DATA(cmsg
),
1646 cmsg
->cmsg_len
-((char *)CMSG_DATA(cmsg
)-(char *)cmsg
),
1647 valbuff
, sizeof(valbuff
)-1, 0);
1649 /* here the info is in typbuff (one string), nambuff (num consecutive
1650 strings), and valbuff (num consecutive strings) */
1652 typp
= typbuff
; namp
= nambuff
; envp
= envbuff
; valp
= valbuff
;
1655 Info3("ancillary message: %s: %s=%s", typp
, namp
, valp
);
1659 xiosetenv(envp
, valp
, 1, NULL
);
1660 } else if (!strcasecmp(typp
+strlen(typp
)-strlen(namp
), namp
)) {
1661 xiosetenv(typp
, valp
, 1, NULL
);
1663 xiosetenv2(typp
, namp
, valp
, 1, NULL
);
1666 if (++i
== num
) break;
1667 namp
= strchr(namp
, '\0')+1;
1668 envp
= strchr(envp
, '\0')+1;
1669 valp
= strchr(valp
, '\0')+1;
1671 cmsg
= CMSG_NXTHDR(msgh
, cmsg
);
1674 #else /* !(defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)) */
1676 #endif /* !(defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)) */
1680 /* check if peer address is within permitted range.
1681 return >= 0 if so. */
1682 int xiocheckrange(union sockaddr_union
*sa
, struct xiorange
*range
) {
1683 switch (sa
->soa
.sa_family
) {
1687 xiocheckrange_ip4(&sa
->ip4
, range
);
1688 #endif /* WITH_IP4 */
1692 xiocheckrange_ip6(&sa
->ip6
, range
);
1693 #endif /* WITH_IP6 */
1698 for (i
= 0; i
< sizeof(sa
->soa
.sa_data
); ++i
) {
1699 if ((range
->netmask
.soa
.sa_data
[i
] & sa
->soa
.sa_data
[i
]) != range
->netaddr
.soa
.sa_data
[i
]) {
1710 int xiocheckpeer(xiosingle_t
*xfd
,
1711 union sockaddr_union
*pa
, union sockaddr_union
*la
) {
1716 if (xfd
->para
.socket
.dorange
) {
1717 if (pa
== NULL
) { return -1; }
1718 if (xiocheckrange(pa
, &xfd
->para
.socket
.range
) < 0) {
1720 Warn1("refusing connection from %s due to range option",
1721 sockaddr_info((struct sockaddr
*)pa
, 0,
1722 infobuff
, sizeof(infobuff
)));
1725 Info1("permitting connection from %s due to range option",
1726 sockaddr_info((struct sockaddr
*)pa
, 0,
1727 infobuff
, sizeof(infobuff
)));
1729 #endif /* WITH_IP4 */
1731 #if WITH_TCP || WITH_UDP
1732 if (xfd
->para
.socket
.ip
.dosourceport
) {
1733 if (pa
== NULL
) { return -1; }
1735 if (pa
->soa
.sa_family
== AF_INET
&&
1736 ntohs(((struct sockaddr_in
*)pa
)->sin_port
) != xfd
->para
.socket
.ip
.sourceport
) {
1737 Warn1("refusing connection from %s due to wrong sourceport",
1738 sockaddr_info((struct sockaddr
*)pa
, 0,
1739 infobuff
, sizeof(infobuff
)));
1742 #endif /* WITH_IP4 */
1744 if (pa
->soa
.sa_family
== AF_INET6
&&
1745 ntohs(((struct sockaddr_in6
*)pa
)->sin6_port
) != xfd
->para
.socket
.ip
.sourceport
) {
1746 Warn1("refusing connection from %s due to wrong sourceport",
1747 sockaddr_info((struct sockaddr
*)pa
, 0,
1748 infobuff
, sizeof(infobuff
)));
1751 #endif /* WITH_IP6 */
1752 Info1("permitting connection from %s due to sourceport option",
1753 sockaddr_info((struct sockaddr
*)pa
, 0,
1754 infobuff
, sizeof(infobuff
)));
1755 } else if (xfd
->para
.socket
.ip
.lowport
) {
1756 if (pa
== NULL
) { return -1; }
1757 if (pa
->soa
.sa_family
== AF_INET
&&
1758 ntohs(((struct sockaddr_in
*)pa
)->sin_port
) >= IPPORT_RESERVED
) {
1759 Warn1("refusing connection from %s due to lowport option",
1760 sockaddr_info((struct sockaddr
*)pa
, 0,
1761 infobuff
, sizeof(infobuff
)));
1765 else if (pa
->soa
.sa_family
== AF_INET6
&&
1766 ntohs(((struct sockaddr_in6
*)pa
)->sin6_port
) >=
1768 Warn1("refusing connection from %s due to lowport option",
1769 sockaddr_info((struct sockaddr
*)pa
, 0,
1770 infobuff
, sizeof(infobuff
)));
1773 #endif /* WITH_IP6 */
1774 Info1("permitting connection from %s due to lowport option",
1775 sockaddr_info((struct sockaddr
*)pa
, 0,
1776 infobuff
, sizeof(infobuff
)));
1778 #endif /* WITH_TCP || WITH_UDP */
1780 #if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
1781 result
= xio_tcpwrap_check(xfd
, la
, pa
);
1784 Warn1("refusing connection from %s due to tcpwrapper option",
1785 sockaddr_info((struct sockaddr
*)pa
, 0,
1786 infobuff
, sizeof(infobuff
)));
1788 } else if (result
> 0) {
1789 Info1("permitting connection from %s due to tcpwrapper option",
1790 sockaddr_info((struct sockaddr
*)pa
, 0,
1791 infobuff
, sizeof(infobuff
)));
1793 #endif /* (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
1795 return 0; /* permitted */
1799 #if HAVE_STRUCT_CMSGHDR
1800 /* converts the ancillary message in *cmsg into a form useable for further
1801 processing. knows the specifics of common message types.
1802 returns the number of resulting syntax elements in *num
1803 returns a sequence of \0 terminated type strings in *typbuff
1804 returns a sequence of \0 terminated name strings in *nambuff
1805 returns a sequence of \0 terminated value strings in *valbuff
1806 the respective len parameters specify the available space in the buffers
1807 returns STAT_OK or other STAT_*
1810 xiolog_ancillary_socket(struct cmsghdr
*cmsg
, int *num
,
1811 char *typbuff
, int typlen
,
1812 char *nambuff
, int namlen
,
1813 char *envbuff
, int envlen
,
1814 char *valbuff
, int vallen
) {
1815 const char *cmsgtype
, *cmsgname
, *cmsgenvn
;
1820 #if defined(CMSG_DATA)
1822 msglen
= cmsg
->cmsg_len
-((char *)CMSG_DATA(cmsg
)-(char *)cmsg
);
1823 switch (cmsg
->cmsg_type
) {
1825 case SO_PASSCRED
: /* this is really a UNIX/LOCAL message */
1826 /*! needs implementation */
1827 #endif /* SO_PASSCRED */
1829 case SO_RIGHTS
: /* this is really a UNIX/LOCAL message */
1830 /*! needs implementation */
1832 default: /* binary data */
1833 snprintf(typbuff
, typlen
, "SOCKET.%u", cmsg
->cmsg_type
);
1834 nambuff
[0] = '\0'; strncat(nambuff
, "data", namlen
-1);
1835 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
1838 # ifdef SCM_TIMESTAMP
1843 tv
= (struct timeval
*)CMSG_DATA(cmsg
);
1845 #ifdef SCM_TIMESTAMP
1846 "SCM_TIMESTAMP" /* FreeBSD */
1848 "SO_TIMESTAMP" /* Linux */
1851 cmsgname
= "timestamp";
1852 cmsgenvn
= "TIMESTAMP";
1853 { time_t t
= tv
->tv_sec
; ctime_r(&t
, valbuff
); }
1854 snprintf(strchr(valbuff
, '\0')-1/*del \n*/, vallen
-strlen(valbuff
)+1, ", %06ld usecs", (long)tv
->tv_usec
);
1856 #endif /* defined(SO_TIMESTAMP) */
1859 /* when we come here we provide a single parameter
1860 with type in cmsgtype, name in cmsgname,
1861 and value already in valbuff */
1863 if (strlen(cmsgtype
) >= typlen
) rc
= STAT_WARNING
;
1864 typbuff
[0] = '\0'; strncat(typbuff
, cmsgtype
, typlen
-1);
1865 if (strlen(cmsgname
) >= namlen
) rc
= STAT_WARNING
;
1866 nambuff
[0] = '\0'; strncat(nambuff
, cmsgname
, namlen
-1);
1867 if (strlen(cmsgenvn
) >= envlen
) rc
= STAT_WARNING
;
1868 envbuff
[0] = '\0'; strncat(envbuff
, cmsgenvn
, envlen
-1);
1871 #else /* !defined(CMSG_DATA) */
1873 return STAT_NORETRY
;
1875 #endif /* !defined(CMSG_DATA) */
1877 #endif /* HAVE_STRUCT_CMSGHDR */
1880 /* return the name of the interface with given index
1882 The system call requires an arbitrary socket; the calling program may
1883 provide one in parameter ins to avoid creation of a dummy socket. ins must
1884 be <0 if it does not specify a socket fd. */
1885 char *xiogetifname(int ind
, char *val
, int ins
) {
1886 #if !HAVE_PROTOTYPE_LIB_if_indextoname
1893 if ((s
= Socket(PF_INET
, SOCK_DGRAM
, IPPROTO_IP
)) < 0) {
1894 Error1("socket(PF_INET, SOCK_DGRAM, IPPROTO_IP): %s", strerror(errno
));
1899 #if HAVE_STRUCT_IFREQ_IFR_INDEX
1900 ifr
.ifr_index
= ind
;
1901 #elif HAVE_STRUCT_IFREQ_IFR_IFINDEX
1902 ifr
.ifr_ifindex
= ind
;
1905 if(Ioctl(s
, SIOCGIFNAME
, &ifr
) < 0) {
1906 #if HAVE_STRUCT_IFREQ_IFR_INDEX
1907 Info3("ioctl(%d, SIOCGIFNAME, {..., ifr_index=%d, ...}: %s",
1908 s
, ifr
.ifr_index
, strerror(errno
));
1909 #elif HAVE_STRUCT_IFREQ_IFR_IFINDEX
1910 Info3("ioctl(%d, SIOCGIFNAME, {..., ifr_ifindex=%d, ...}: %s",
1911 s
, ifr
.ifr_ifindex
, strerror(errno
));
1913 if (ins
< 0) Close(s
);
1916 #endif /* SIOCGIFNAME */
1917 if (ins
< 0) Close(s
);
1918 strcpy(val
, ifr
.ifr_name
);
1920 #else /* HAVE_PROTOTYPE_LIB_if_indextoname */
1921 return if_indextoname(ind
, val
);
1922 #endif /* HAVE_PROTOTYPE_LIB_if_indextoname */
1926 /* parses a network specification consisting of an address and a mask. */
1927 int xioparsenetwork(const char *rangename
, int pf
, struct xiorange
*range
) {
1928 size_t addrlen
= 0, masklen
= 0;
1934 return xioparsenetwork_ip4(rangename
, range
);
1936 #endif /* WITH_IP4 */
1939 return xioparsenetwork_ip6(rangename
, range
);
1941 #endif /* WITH_IP6 */
1945 const char *maskname
;
1946 if ((maskname
= strchr(rangename
, ':')) == NULL
) {
1947 Error1("syntax error in range \"%s\": use <addr>:<mask>", rangename
);
1948 return STAT_NORETRY
;
1950 ++maskname
; /* skip ':' */
1951 if ((addrname
= Malloc(maskname
-rangename
)) == NULL
) {
1952 return STAT_NORETRY
;
1954 strncpy(addrname
, rangename
, maskname
-rangename
-1); /* ok */
1955 addrname
[maskname
-rangename
-1] = '\0';
1957 dalan(addrname
, (char *)&range
->netaddr
.soa
.sa_data
, &addrlen
,
1958 sizeof(range
->netaddr
)-(size_t)(&((struct sockaddr
*)0)->sa_data
)
1961 Error1("data too long: \"%s\"", addrname
);
1962 free(addrname
); return STAT_NORETRY
;
1963 } else if (result
> 0) {
1964 Error1("syntax error in \"%s\"", addrname
);
1965 free(addrname
); return STAT_NORETRY
;
1969 dalan(maskname
, (char *)&range
->netmask
.soa
.sa_data
, &masklen
,
1970 sizeof(range
->netaddr
)-(size_t)(&((struct sockaddr
*)0)->sa_data
)
1973 Error1("data too long: \"%s\"", maskname
);
1974 return STAT_NORETRY
;
1975 } else if (result
> 0) {
1976 Error1("syntax error in \"%s\"", maskname
);
1977 return STAT_NORETRY
;
1979 if (addrlen
!= masklen
) {
1980 Error2("network address is "F_Zu
" bytes long, mask is "F_Zu
" bytes long",
1982 /* recover by padding the shorter component with 0 */
1983 memset((char *)&range
->netaddr
.soa
.sa_data
+addrlen
, 0,
1984 MAX(0, addrlen
-masklen
));
1985 memset((char *)&range
->netmask
.soa
.sa_data
+masklen
, 0,
1986 MAX(0, masklen
-addrlen
));
1991 Error1("range option not supported with address family %d", pf
);
1992 return STAT_NORETRY
;
1998 /* parses a string of form address/bits or address:mask, and fills the fields
1999 of the range union. The addr component is masked with mask. */
2000 int xioparserange(const char *rangename
, int pf
, struct xiorange
*range
) {
2002 if (xioparsenetwork(rangename
, pf
, range
) < 0) {
2005 /* we have parsed the address and mask; now we make sure that the stored
2006 address has 0 where mask is 0, to simplify comparisions */
2010 range
->netaddr
.ip4
.sin_addr
.s_addr
&= range
->netmask
.ip4
.sin_addr
.s_addr
;
2012 #endif /* WITH_IP4 */
2015 return xiorange_ip6andmask(range
);
2017 #endif /* WITH_IP6 */
2019 for (i
= 0; i
< sizeof(range
->netaddr
); ++i
) {
2020 ((char *)&range
->netaddr
)[i
] &= ((char *)&range
->netmask
)[i
];
2024 Error1("range option not supported with address family %d", pf
);
2025 return STAT_NORETRY
;
2031 /* set environment variables describing (part of) a socket address, e.g.
2032 SOCAT_SOCKADDR. lr (local/remote) specifies a string like "SOCK" or "PEER".
2033 proto should correspond to the third parameter of socket(2) and is used to
2034 determine the presence of port information. */
2035 int xiosetsockaddrenv(const char *lr
,
2036 union sockaddr_union
*sau
, socklen_t salen
,
2038 # define XIOSOCKADDRENVLEN 256
2039 char namebuff
[XIOSOCKADDRENVLEN
];
2040 char valuebuff
[XIOSOCKADDRENVLEN
];
2041 int idx
= 0, result
;
2043 strcpy(namebuff
, lr
);
2044 switch (sau
->soa
.sa_family
) {
2048 xiosetsockaddrenv_unix(idx
, strchr(namebuff
, '\0'), XIOSOCKADDRENVLEN
-strlen(lr
),
2049 valuebuff
, XIOSOCKADDRENVLEN
,
2050 &sau
->un
, salen
, proto
);
2051 xiosetenv(namebuff
, valuebuff
, 1, NULL
);
2053 #endif /* WITH_UNIX */
2058 xiosetsockaddrenv_ip4(idx
, strchr(namebuff
, '\0'), XIOSOCKADDRENVLEN
-strlen(lr
),
2059 valuebuff
, XIOSOCKADDRENVLEN
,
2061 xiosetenv(namebuff
, valuebuff
, 1, NULL
);
2062 namebuff
[strlen(lr
)] = '\0'; ++idx
;
2063 } while (result
> 0);
2065 #endif /* WITH_IP4 */
2068 strcpy(namebuff
, lr
);
2071 xiosetsockaddrenv_ip6(idx
, strchr(namebuff
, '\0'), XIOSOCKADDRENVLEN
-strlen(lr
),
2072 valuebuff
, XIOSOCKADDRENVLEN
,
2074 xiosetenv(namebuff
, valuebuff
, 1, NULL
);
2075 namebuff
[strlen(lr
)] = '\0'; ++idx
;
2076 } while (result
> 0);
2078 #endif /* WITH_IP6 */
2081 result
= xiosetsockaddrenv_packet(lr
, (void *)sau
, proto
); break;
2088 # undef XIOSOCKADDRENVLEN
2091 #endif /* _WITH_SOCKET */
2093 /* these do sockets internally */
2095 /* retrieves options so-type and so-prototype from opts, calls socket, and
2096 ev. generates an appropriate error message.
2097 returns 0 on success or -1 if an error occurred. */
2099 xiosocket(struct opt
*opts
, int pf
, int socktype
, int proto
, int msglevel
) {
2102 retropt_int(opts
, OPT_SO_TYPE
, &socktype
);
2103 retropt_int(opts
, OPT_SO_PROTOTYPE
, &proto
);
2104 result
= Socket(pf
, socktype
, proto
);
2106 Msg4(msglevel
, "socket(%d, %d, %d): %s",
2107 pf
, socktype
, proto
, strerror(errno
));
2113 /* retrieves options so-type and so-prototype from opts, calls socketpair, and
2114 ev. generates an appropriate error message.
2115 returns 0 on success or -1 if an error occurred. */
2117 xiosocketpair(struct opt
*opts
, int pf
, int socktype
, int proto
, int sv
[2]) {
2120 retropt_int(opts
, OPT_SO_TYPE
, &socktype
);
2121 retropt_int(opts
, OPT_SO_PROTOTYPE
, &proto
);
2122 result
= Socketpair(pf
, socktype
, proto
, sv
);
2124 Error5("socketpair(%d, %d, %d, %p): %s",
2125 pf
, socktype
, proto
, sv
, strerror(errno
));