1 /* source: xio-socket.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 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_rcvtimeo
= { "so-rcvtimeo", "rcvtimeo", OPT_SO_RCVTIMEO
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_TIMEVAL
,OFUNC_SOCKOPT
,SOL_SOCKET
,SO_RCVTIMEO
};
110 const struct optdesc opt_so_sndlowat
= { "so-sndlowat", "sndlowat", OPT_SO_SNDLOWAT
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_SNDLOWAT
};
113 const struct optdesc opt_so_sndtimeo
= { "so-sndtimeo", "sndtimeo", OPT_SO_SNDTIMEO
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_TIMEVAL
,OFUNC_SOCKOPT
,SOL_SOCKET
,SO_SNDTIMEO
};
115 /* end of setsockopt options of UNIX98 standard */
117 #ifdef SO_AUDIT /* AIX 4.3.3 */
118 const struct optdesc opt_so_audit
= { "so-audit", "audit", OPT_SO_AUDIT
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_AUDIT
};
119 #endif /* SO_AUDIT */
120 #ifdef SO_ATTACH_FILTER
121 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
};
123 #ifdef SO_DETACH_FILTER
124 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
};
126 #ifdef SO_BINDTODEVICE /* Linux: man 7 socket */
127 const struct optdesc opt_so_bindtodevice
={"so-bindtodevice","if",OPT_SO_BINDTODEVICE
,GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_NAME
,OFUNC_SOCKOPT
,SOL_SOCKET
,SO_BINDTODEVICE
};
130 const struct optdesc opt_so_bsdcompat
= { "so-bsdcompat","bsdcompat",OPT_SO_BSDCOMPAT
,GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_BSDCOMPAT
};
133 const struct optdesc opt_so_cksumrecv
= { "so-cksumrecv","cksumrecv",OPT_SO_CKSUMRECV
,GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_CKSUMRECV
};
134 #endif /* SO_CKSUMRECV */
136 const struct optdesc opt_so_timestamp
= { "so-timestamp","timestamp",OPT_SO_TIMESTAMP
,GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_TIMESTAMP
};
138 #ifdef SO_KERNACCEPT /* AIX 4.3.3 */
139 const struct optdesc opt_so_kernaccept
={ "so-kernaccept","kernaccept",OPT_SO_KERNACCEPT
,GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_KERNACCEPT
};
140 #endif /* SO_KERNACCEPT */
142 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
};
144 #ifdef SO_NOREUSEADDR /* AIX 4.3.3 */
145 const struct optdesc opt_so_noreuseaddr
={"so-noreuseaddr","noreuseaddr",OPT_SO_NOREUSEADDR
,GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT
,OFUNC_SOCKOPT
,SOL_SOCKET
, SO_NOREUSEADDR
};
146 #endif /* SO_NOREUSEADDR */
148 const struct optdesc opt_so_passcred
= { "so-passcred", "passcred", OPT_SO_PASSCRED
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_PASSCRED
};
151 const struct optdesc opt_so_peercred
= { "so-peercred", "peercred", OPT_SO_PEERCRED
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT3
,OFUNC_SOCKOPT
, SOL_SOCKET
, SO_PEERCRED
};
154 const struct optdesc opt_so_priority
= { "so-priority", "priority", OPT_SO_PRIORITY
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_PRIORITY
};
156 #ifdef SO_REUSEPORT /* AIX 4.3.3, BSD, HP-UX */
157 const struct optdesc opt_so_reuseport
= { "so-reuseport","reuseport",OPT_SO_REUSEPORT
,GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_SOCKET
, SO_REUSEPORT
};
158 #endif /* defined(SO_REUSEPORT) */
159 #ifdef SO_SECURITY_AUTHENTICATION
160 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
};
162 #ifdef SO_SECURITY_ENCRYPTION_NETWORK
163 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
};
165 #ifdef SO_SECURITY_ENCRYPTION_TRANSPORT
166 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
};
169 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
};
170 #endif /* SO_USE_IFBUFS */
171 #ifdef SO_USELOOPBACK /* AIX433, Solaris, HP-UX */
172 const struct optdesc opt_so_useloopback
={"so-useloopback","useloopback",OPT_SO_USELOOPBACK
,GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT
,OFUNC_SOCKOPT
, SOL_SOCKET
, SO_USELOOPBACK
};
173 #endif /* SO_USELOOPBACK */
174 #ifdef SO_DGRAM_ERRIND /* Solaris */
175 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
};
176 #endif /* SO_DGRAM_ERRIND */
177 #ifdef SO_DONTLINGER /* Solaris */
178 const struct optdesc opt_so_dontlinger
= {"so-dontlinger", "dontlinger", OPT_SO_DONTLINGER
, GROUP_SOCKET
,PH_PASTSOCKET
,TYPE_INT
,OFUNC_SOCKOPT
,SOL_SOCKET
,SO_DONTLINGER
};
180 /* the SO_PROTOTYPE is OS defined on Solaris, HP-UX; we lend this for a more
182 const struct optdesc opt_so_prototype
= {"so-prototype", "prototype", OPT_SO_PROTOTYPE
, GROUP_SOCKET
,PH_SOCKET
, TYPE_INT
,OFUNC_SPEC
, SOL_SOCKET
,SO_PROTOTYPE
};
184 const struct optdesc opt_fiosetown
= { "fiosetown", NULL
, OPT_FIOSETOWN
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_IOCTL
, FIOSETOWN
};
187 const struct optdesc opt_siocspgrp
= { "siocspgrp", NULL
, OPT_SIOCSPGRP
, GROUP_SOCKET
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_IOCTL
, SIOCSPGRP
};
189 const struct optdesc opt_bind
= { "bind", NULL
, OPT_BIND
, GROUP_SOCKET
, PH_BIND
, TYPE_STRING
,OFUNC_SPEC
};
190 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
) };
191 const struct optdesc opt_protocol_family
= { "protocol-family", "pf", OPT_PROTOCOL_FAMILY
, GROUP_SOCKET
, PH_PRESOCKET
, TYPE_STRING
, OFUNC_SPEC
};
192 const struct optdesc opt_protocol
= { "protocol", NULL
, OPT_PROTOCOL
, GROUP_SOCKET
, PH_PRESOCKET
, TYPE_STRING
, OFUNC_SPEC
};
194 /* generic setsockopt() options */
195 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 };
196 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 };
197 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 };
199 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
) };
202 #if WITH_GENERICSOCKET
205 int xioopen_socket_connect(int argc
, const char *argv
[], struct opt
*opts
,
206 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
207 int dummy1
, int dummy2
, int dummy3
) {
208 struct single
*xfd
= &xxfd
->stream
;
209 const char *pfname
= argv
[1];
210 const char *protname
= argv
[2];
211 const char *address
= argv
[3];
215 int socktype
= SOCK_STREAM
;
217 union sockaddr_union them
; socklen_t themlen
; size_t themsize
;
218 union sockaddr_union us
; socklen_t uslen
= sizeof(us
);
222 Error2("%s: wrong number of parameters (%d instead of 3)",
227 pf
= strtoul(pfname
, &garbage
, 0);
228 if (*garbage
!= '\0') {
229 Warn1("garbage in parameter: \"%s\"", garbage
);
232 proto
= strtoul(protname
, &garbage
, 0);
233 if (*garbage
!= '\0') {
234 Warn1("garbage in parameter: \"%s\"", garbage
);
237 retropt_socket_pf(opts
, &pf
);
238 retropt_int(opts
, OPT_SO_TYPE
, &socktype
);
239 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
240 xfd
->howtoend
= END_SHUTDOWN
;
242 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return -1;
243 applyopts(-1, opts
, PH_INIT
);
244 applyopts(-1, opts
, PH_EARLY
);
248 dalan(address
, (char *)&them
.soa
.sa_data
, &themsize
, sizeof(them
)))
250 Error1("data too long: \"%s\"", address
);
251 } else if (result
> 0) {
252 Error1("syntax error in \"%s\"", address
);
254 them
.soa
.sa_family
= pf
;
256 #if HAVE_STRUCT_SOCKADDR_SALEN
257 sizeof(them
.soa
.sa_len
) +
259 sizeof(them
.soa
.sa_family
);
261 xfd
->dtype
= XIOREAD_STREAM
|XIOWRITE_STREAM
;
264 if (retropt_bind(opts
, 0 /*pf*/, socktype
, proto
, (struct sockaddr
*)&us
, &uslen
, 3,
268 us
.soa
.sa_family
= pf
;
273 needbind
?(struct sockaddr
*)&us
:NULL
, uslen
,
274 (struct sockaddr
*)&them
, themlen
,
275 opts
, pf
, socktype
, proto
, false)) != 0) {
278 if ((result
= _xio_openlate(xfd
, opts
)) < 0) {
286 int xioopen_socket_listen(int argc
, const char *argv
[], struct opt
*opts
,
287 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
288 int dummy1
, int dummy2
, int dummy3
) {
289 struct single
*xfd
= &xxfd
->stream
;
290 const char *pfname
= argv
[1];
291 const char *protname
= argv
[2];
292 const char *usname
= argv
[3];
296 int socktype
= SOCK_STREAM
;
297 union sockaddr_union us
; socklen_t uslen
; size_t ussize
;
302 Error2("%s: wrong number of parameters (%d instead of 3)",
307 pf
= strtoul(pfname
, &garbage
, 0);
308 if (*garbage
!= '\0') {
309 Warn1("garbage in parameter: \"%s\"", garbage
);
312 proto
= strtoul(protname
, &garbage
, 0);
313 if (*garbage
!= '\0') {
314 Warn1("garbage in parameter: \"%s\"", garbage
);
317 retropt_socket_pf(opts
, &pf
);
318 retropt_int(opts
, OPT_SO_TYPE
, &socktype
);
319 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
320 xfd
->howtoend
= END_SHUTDOWN
;
325 dalan(usname
, (char *)&us
.soa
.sa_data
, &ussize
, sizeof(us
)))
327 Error1("data too long: \"%s\"", usname
);
328 } else if (result
> 0) {
329 Error1("syntax error in \"%s\"", usname
);
331 uslen
= ussize
+ sizeof(us
.soa
.sa_family
)
332 #if HAVE_STRUCT_SOCKADDR_SALEN
333 + sizeof(us
.soa
.sa_len
)
336 us
.soa
.sa_family
= pf
;
338 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return -1;
339 applyopts(-1, opts
, PH_INIT
);
340 applyopts(-1, opts
, PH_EARLY
);
342 opts0
= copyopts(opts
, GROUP_ALL
);
345 xioopen_listen(xfd
, xioflags
,
346 (struct sockaddr
*)&us
, uslen
,
347 opts
, opts0
, 0/*instead of pf*/, socktype
, proto
))
352 #endif /* WITH_LISTEN */
354 /* we expect the form: ...:domain:type:protocol:remote-address */
356 int xioopen_socket_sendto(int argc
, const char *argv
[], struct opt
*opts
,
357 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
358 int dummy1
, int dummy2
, int dummy3
) {
362 Error2("%s: wrong number of parameters (%d instead of 4)",
367 _xioopen_socket_sendto(argv
[1], argv
[2], argv
[3], argv
[4],
368 opts
, xioflags
, xxfd
, groups
))
372 _xio_openlate(&xxfd
->stream
, opts
);
377 int _xioopen_socket_sendto(const char *pfname
, const char *type
,
378 const char *protname
, const char *address
,
379 struct opt
*opts
, int xioflags
, xiofile_t
*xxfd
,
381 xiosingle_t
*xfd
= &xxfd
->stream
;
383 union sockaddr_union us
= {{0}};
384 socklen_t uslen
= 0; size_t ussize
;
387 int socktype
= SOCK_RAW
;
389 bool needbind
= false;
390 char *bindstring
= NULL
;
393 pf
= strtoul(pfname
, &garbage
, 0);
394 if (*garbage
!= '\0') {
395 Warn1("garbage in parameter: \"%s\"", garbage
);
398 socktype
= strtoul(type
, &garbage
, 0);
399 if (*garbage
!= '\0') {
400 Warn1("garbage in parameter: \"%s\"", garbage
);
403 proto
= strtoul(protname
, &garbage
, 0);
404 if (*garbage
!= '\0') {
405 Warn1("garbage in parameter: \"%s\"", garbage
);
408 retropt_socket_pf(opts
, &pf
);
409 retropt_int(opts
, OPT_SO_TYPE
, &socktype
);
410 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
411 xfd
->howtoend
= END_SHUTDOWN
;
413 xfd
->peersa
.soa
.sa_family
= pf
;
416 dalan(address
, (char *)&xfd
->peersa
.soa
.sa_data
, &themsize
,
417 sizeof(xfd
->peersa
)))
419 Error1("data too long: \"%s\"", address
);
420 } else if (result
> 0) {
421 Error1("syntax error in \"%s\"", address
);
423 xfd
->salen
= themsize
+ sizeof(sa_family_t
)
424 #if HAVE_STRUCT_SOCKADDR_SALEN
425 + sizeof(xfd
->peersa
.soa
.sa_len
)
428 #if HAVE_STRUCT_SOCKADDR_SALEN
429 xfd
->peersa
.soa
.sa_len
=
430 sizeof(xfd
->peersa
.soa
.sa_len
) + sizeof(xfd
->peersa
.soa
.sa_family
) +
435 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return -1;
436 applyopts(-1, opts
, PH_INIT
);
438 if (pf
== PF_UNSPEC
) {
439 pf
= xfd
->peersa
.soa
.sa_family
;
442 xfd
->dtype
= XIODATA_RECVFROM
;
444 if (retropt_string(opts
, OPT_BIND
, &bindstring
) == 0) {
447 dalan(bindstring
, (char *)&us
.soa
.sa_data
, &ussize
, sizeof(us
)))
449 Error1("data too long: \"%s\"", bindstring
);
450 } else if (result
> 0) {
451 Error1("syntax error in \"%s\"", bindstring
);
453 us
.soa
.sa_family
= pf
;
454 uslen
= ussize
+ sizeof(sa_family_t
)
455 #if HAVE_STRUCT_SOCKADDR_SALEN
456 + sizeof(us
.soa
.sa_len
)
463 _xioopen_dgram_sendto(needbind
?&us
:NULL
, uslen
,
464 opts
, xioflags
, xfd
, groups
, pf
, socktype
, proto
);
468 /* we expect the form: ...:domain:socktype:protocol:local-address */
470 int xioopen_socket_recvfrom(int argc
, const char *argv
[], struct opt
*opts
,
471 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
472 int dummy
, int summy2
, int dummy3
) {
473 struct single
*xfd
= &xxfd
->stream
;
474 const char *pfname
= argv
[1];
475 const char *typename
= argv
[2];
476 const char *protname
= argv
[3];
477 const char *address
= argv
[4];
479 union sockaddr_union
*us
= &xfd
->para
.socket
.la
;
480 socklen_t uslen
; size_t ussize
;
481 int pf
, socktype
, proto
;
486 Error2("%s: wrong number of parameters (%d instead of 4)",
491 pf
= strtoul(pfname
, &garbage
, 0);
492 if (*garbage
!= '\0') {
493 Warn1("garbage in parameter: \"%s\"", garbage
);
496 socktype
= strtoul(typename
, &garbage
, 0);
497 if (*garbage
!= '\0') {
498 Warn1("garbage in parameter: \"%s\"", garbage
);
501 proto
= strtoul(protname
, &garbage
, 0);
502 if (*garbage
!= '\0') {
503 Warn1("garbage in parameter: \"%s\"", garbage
);
506 retropt_socket_pf(opts
, &pf
);
507 retropt_int(opts
, OPT_SO_TYPE
, &socktype
);
508 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
509 xfd
->howtoend
= END_NONE
;
513 dalan(address
, (char *)&us
->soa
.sa_data
, &ussize
, sizeof(*us
)))
515 Error1("data too long: \"%s\"", address
);
516 } else if (result
> 0) {
517 Error1("syntax error in \"%s\"", address
);
519 us
->soa
.sa_family
= pf
;
520 uslen
= ussize
+ sizeof(us
->soa
.sa_family
)
521 #if HAVE_STRUCT_SOCKADDR_SALEN
522 + sizeof(us
->soa
.sa_len
);
525 xfd
->dtype
= XIOREAD_RECV
|XIOWRITE_SENDTO
;
527 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
528 if (xioparserange(rangename
, 0, &xfd
->para
.socket
.range
) < 0) {
531 xfd
->para
.socket
.dorange
= true;
536 _xioopen_dgram_recvfrom(xfd
, xioflags
, &us
->soa
, uslen
,
537 opts
, pf
, socktype
, proto
, E_ERROR
))
541 _xio_openlate(xfd
, opts
);
545 /* we expect the form: ...:domain:type:protocol:local-address */
547 int xioopen_socket_recv(int argc
, const char *argv
[], struct opt
*opts
,
548 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
549 int dummy1
, int dummy2
, int dummy3
) {
550 struct single
*xfd
= &xxfd
->stream
;
551 const char *pfname
= argv
[1];
552 const char *typename
= argv
[2];
553 const char *protname
= argv
[3];
554 const char *address
= argv
[4];
556 union sockaddr_union us
;
557 socklen_t uslen
; size_t ussize
;
558 int pf
, socktype
, proto
;
563 Error2("%s: wrong number of parameters (%d instead of 4)",
568 pf
= strtoul(pfname
, &garbage
, 0);
569 if (*garbage
!= '\0') {
570 Warn1("garbage in parameter: \"%s\"", garbage
);
573 socktype
= strtoul(typename
, &garbage
, 0);
574 if (*garbage
!= '\0') {
575 Warn1("garbage in parameter: \"%s\"", garbage
);
578 proto
= strtoul(protname
, &garbage
, 0);
579 if (*garbage
!= '\0') {
580 Warn1("garbage in parameter: \"%s\"", garbage
);
583 retropt_socket_pf(opts
, &pf
);
584 retropt_int(opts
, OPT_SO_TYPE
, &socktype
);
585 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
586 xfd
->howtoend
= END_NONE
;
590 dalan(address
, (char *)&us
.soa
.sa_data
, &ussize
, sizeof(us
)))
592 Error1("data too long: \"%s\"", address
);
593 } else if (result
> 0) {
594 Error1("syntax error in \"%s\"", address
);
596 us
.soa
.sa_family
= pf
;
597 uslen
= ussize
+ sizeof(sa_family_t
)
598 #if HAVE_STRUCT_SOCKADDR_SALEN
599 +sizeof(us
.soa
.sa_len
)
602 xfd
->dtype
= XIOREAD_RECV
;
603 xfd
->para
.socket
.la
.soa
.sa_family
= pf
;
605 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
606 if (xioparserange(rangename
, 0, &xfd
->para
.socket
.range
) < 0) {
609 xfd
->para
.socket
.dorange
= true;
614 _xioopen_dgram_recv(xfd
, xioflags
, &us
.soa
,
615 uslen
, opts
, pf
, socktype
, proto
, E_ERROR
))
619 _xio_openlate(xfd
, opts
);
624 /* we expect the form: ...:domain:type:protocol:remote-address */
626 int xioopen_socket_datagram(int argc
, const char *argv
[], struct opt
*opts
,
627 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
628 int dummy1
, int dummy2
, int dummy3
) {
629 xiosingle_t
*xfd
= &xxfd
->stream
;
630 const char *pfname
= argv
[1];
631 const char *typename
= argv
[2];
632 const char *protname
= argv
[3];
633 const char *address
= argv
[4];
641 Error2("%s: wrong number of parameters (%d instead of 4)",
646 pf
= strtoul(pfname
, &garbage
, 0);
647 if (*garbage
!= '\0') {
648 Warn1("garbage in parameter: \"%s\"", garbage
);
651 retropt_socket_pf(opts
, &pf
);
652 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
653 xfd
->howtoend
= END_SHUTDOWN
;
655 xfd
->peersa
.soa
.sa_family
= pf
;
658 dalan(address
, (char *)&xfd
->peersa
.soa
.sa_data
, &themsize
,
659 sizeof(xfd
->peersa
)))
661 Error1("data too long: \"%s\"", address
);
662 } else if (result
> 0) {
663 Error1("syntax error in \"%s\"", address
);
665 xfd
->salen
= themsize
+ sizeof(sa_family_t
);
666 #if HAVE_STRUCT_SOCKADDR_SALEN
667 xfd
->peersa
.soa
.sa_len
=
668 sizeof(xfd
->peersa
.soa
.sa_len
) + sizeof(xfd
->peersa
.soa
.sa_family
) +
673 _xioopen_socket_sendto(pfname
, typename
, protname
, address
,
674 opts
, xioflags
, xxfd
, groups
))
679 xfd
->dtype
= XIOREAD_RECV
|XIOWRITE_SENDTO
;
681 xfd
->para
.socket
.la
.soa
.sa_family
= xfd
->peersa
.soa
.sa_family
;
683 /* which reply sockets will accept - determine by range option */
684 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
685 if (xioparserange(rangename
, 0, &xfd
->para
.socket
.range
) < 0) {
689 xfd
->para
.socket
.dorange
= true;
690 xfd
->dtype
|= XIOREAD_RECV_CHECKRANGE
;
694 _xio_openlate(xfd
, opts
);
698 #endif /* WITH_GENERICSOCKET */
701 /* a subroutine that is common to all socket addresses that want to connect
704 applies and consumes the following options:
705 PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT,
706 PH_CONNECTED, PH_LATE,
708 OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
709 returns 0 on success.
711 int _xioopen_connect(struct single
*xfd
, struct sockaddr
*us
, size_t uslen
,
712 struct sockaddr
*them
, size_t themlen
,
713 struct opt
*opts
, int pf
, int socktype
, int protocol
,
714 bool alt
, int level
) {
717 union sockaddr_union la
;
718 socklen_t lalen
= themlen
;
722 if ((xfd
->fd
= xiosocket(opts
, pf
, socktype
, protocol
, level
)) < 0) {
723 return STAT_RETRYLATER
;
726 applyopts_offset(xfd
, opts
);
727 applyopts(xfd
->fd
, opts
, PH_PASTSOCKET
);
728 applyopts(xfd
->fd
, opts
, PH_FD
);
730 applyopts_cloexec(xfd
->fd
, opts
);
732 applyopts(xfd
->fd
, opts
, PH_PREBIND
);
733 applyopts(xfd
->fd
, opts
, PH_BIND
);
734 #if WITH_TCP || WITH_UDP
736 union sockaddr_union sin
, *sinp
;
737 unsigned short *port
, i
, N
;
740 /* prepare sockaddr for bind probing */
742 sinp
= (union sockaddr_union
*)us
;
744 if (them
->sa_family
== AF_INET
) {
745 socket_in_init(&sin
.ip4
);
748 socket_in6_init(&sin
.ip6
);
753 if (them
->sa_family
== AF_INET
) {
754 port
= &sin
.ip4
.sin_port
;
756 } else if (them
->sa_family
== AF_INET6
) {
757 port
= &sin
.ip6
.sin6_port
;
760 port
= 0; /* just to make compiler happy */
762 /* combine random+step variant to quickly find a free port when only
763 few are in use, and certainly find a free port in defined time even
764 if there are almost all in use */
765 /* dirt 1: having tcp/udp code in socket function */
766 /* dirt 2: using a time related system call for init of random */
768 /* generate a random port, with millisecond random init */
772 srandom(tb
.time
*1000+tb
.millitm
);
776 tz
.tz_minuteswest
= 0;
778 if ((result
= Gettimeofday(&tv
, &tz
)) < 0) {
779 Warn2("gettimeofday(%p, {0,0}): %s", &tv
, strerror(errno
));
781 srandom(tv
.tv_sec
*1000000+tv
.tv_usec
);
784 dv
= div(random(), IPPORT_RESERVED
-XIO_IPPORT_LOWER
);
785 i
= N
= XIO_IPPORT_LOWER
+ dv
.rem
;
786 do { /* loop over lowport bind() attempts */
788 if (Bind(xfd
->fd
, (struct sockaddr
*)sinp
, sizeof(*sinp
)) < 0) {
789 Msg4(errno
==EADDRINUSE
?E_INFO
:level
,
790 "bind(%d, {%s}, "F_Zd
"): %s", xfd
->fd
,
791 sockaddr_info(&sinp
->soa
, sizeof(*sinp
), infobuff
, sizeof(infobuff
)),
792 sizeof(*sinp
), strerror(errno
));
793 if (errno
!= EADDRINUSE
) {
795 return STAT_RETRYLATER
;
798 break; /* could bind to port, good, continue past loop */
800 --i
; if (i
< XIO_IPPORT_LOWER
) i
= IPPORT_RESERVED
-1;
802 Msg(level
, "no low port available");
803 /*errno = EADDRINUSE; still assigned */
805 return STAT_RETRYLATER
;
809 #endif /* WITH_TCP || WITH_UDP */
812 if (Bind(xfd
->fd
, us
, uslen
) < 0) {
813 Msg4(level
, "bind(%d, {%s}, "F_Zd
"): %s",
814 xfd
->fd
, sockaddr_info(us
, uslen
, infobuff
, sizeof(infobuff
)),
815 uslen
, strerror(errno
));
817 return STAT_RETRYLATER
;
821 applyopts(xfd
->fd
, opts
, PH_PASTBIND
);
823 applyopts(xfd
->fd
, opts
, PH_CONNECT
);
825 if (xfd
->para
.socket
.connect_timeout
.tv_sec
!= 0 ||
826 xfd
->para
.socket
.connect_timeout
.tv_usec
!= 0) {
827 fcntl_flags
= Fcntl(xfd
->fd
, F_GETFL
);
828 Fcntl_l(xfd
->fd
, F_SETFL
, fcntl_flags
|O_NONBLOCK
);
831 result
= Connect(xfd
->fd
, (struct sockaddr
*)them
, themlen
);
833 la
.soa
.sa_family
= them
->sa_family
; lalen
= sizeof(la
);
834 if (Getsockname(xfd
->fd
, &la
.soa
, &lalen
) < 0) {
835 Msg4(level
-1, "getsockname(%d, %p, {%d}): %s",
836 xfd
->fd
, &la
.soa
, lalen
, strerror(errno
));
840 if (errno
== EINPROGRESS
) {
841 if (xfd
->para
.socket
.connect_timeout
.tv_sec
!= 0 ||
842 xfd
->para
.socket
.connect_timeout
.tv_usec
!= 0) {
843 struct timeval timeout
;
844 struct pollfd writefd
;
847 Info4("connect(%d, %s, "F_Zd
"): %s",
848 xfd
->fd
, sockaddr_info(them
, themlen
, infobuff
, sizeof(infobuff
)),
849 themlen
, strerror(errno
));
850 timeout
= xfd
->para
.socket
.connect_timeout
;
851 writefd
.fd
= xfd
->fd
;
852 writefd
.events
= (POLLOUT
|POLLERR
);
853 result
= xiopoll(&writefd
, 1, &timeout
);
855 Msg4(level
, "xiopoll({%d,POLLOUT|POLLERR},,{"F_tv_sec
"."F_tv_usec
"): %s",
856 xfd
->fd
, timeout
.tv_sec
, timeout
.tv_usec
, strerror(errno
));
857 return STAT_RETRYLATER
;
860 Msg2(level
, "connecting to %s: %s",
861 sockaddr_info(them
, themlen
, infobuff
, sizeof(infobuff
)),
862 strerror(ETIMEDOUT
));
863 return STAT_RETRYLATER
;
865 if (writefd
.revents
& POLLERR
) {
867 unsigned char dummy
[1];
868 Read(xfd
->fd
, &dummy
, 1); /* get error message */
869 Msg2(level
, "connecting to %s: %s",
870 sockaddr_info(them
, infobuff
, sizeof(infobuff
)),
873 Connect(xfd
->fd
, them
, themlen
); /* get error message */
874 Msg4(level
, "connect(%d, %s, "F_Zd
"): %s",
875 xfd
->fd
, sockaddr_info(them
, themlen
, infobuff
, sizeof(infobuff
)),
876 themlen
, strerror(errno
));
878 return STAT_RETRYLATER
;
881 Fcntl_l(xfd
->fd
, F_SETFL
, fcntl_flags
);
883 Warn4("connect(%d, %s, "F_Zd
"): %s",
884 xfd
->fd
, sockaddr_info(them
, themlen
, infobuff
, sizeof(infobuff
)),
885 themlen
, strerror(errno
));
887 } else if (pf
== PF_UNIX
&& errno
== EPROTOTYPE
) {
888 /* this is for UNIX domain sockets: a connect attempt seems to be
889 the only way to distinguish stream and datagram sockets */
891 Info4("connect(%d, %s, "F_Zd
"): %s",
892 xfd
->fd
, sockaddr_info(them
, themlen
, infobuff
, sizeof(infobuff
)),
893 themlen
, strerror(errno
));
895 Info("assuming datagram socket");
896 xfd
->dtype
= DATA_RECVFROM
;
897 xfd
->salen
= themlen
;
898 memcpy(&xfd
->peersa
.soa
, them
, xfd
->salen
);
900 /*!!! and remove bind socket */
901 Close(xfd
->fd
); xfd
->fd
= -1;
905 Msg4(level
, "connect(%d, %s, "F_Zd
"): %s",
906 xfd
->fd
, sockaddr_info(them
, themlen
, infobuff
, sizeof(infobuff
)),
907 themlen
, strerror(errno
));
909 return STAT_RETRYLATER
;
911 } else { /* result >= 0 */
912 Notice1("successfully connected from local address %s",
913 sockaddr_info(&la
.soa
, themlen
, infobuff
, sizeof(infobuff
)));
916 applyopts_fchown(xfd
->fd
, opts
); /* OPT_USER, OPT_GROUP */
917 applyopts(xfd
->fd
, opts
, PH_CONNECTED
);
918 applyopts(xfd
->fd
, opts
, PH_LATE
);
924 /* a subroutine that is common to all socket addresses that want to connect
927 applies and consumes the following option:
928 PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT,
929 PH_CONNECTED, PH_LATE,
931 OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
932 returns 0 on success.
934 int xioopen_connect(struct single
*xfd
, struct sockaddr
*us
, size_t uslen
,
935 struct sockaddr
*them
, size_t themlen
,
936 struct opt
*opts
, int pf
, int socktype
, int protocol
,
944 retropt_bool(opts
, OPT_FORK
, &dofork
);
946 opts0
= copyopts(opts
, GROUP_ALL
);
948 Notice1("opening connection to %s",
949 sockaddr_info(them
, themlen
, infobuff
, sizeof(infobuff
)));
951 do { /* loop over retries and forks */
954 if (xfd
->forever
|| xfd
->retry
) {
957 #endif /* WITH_RETRY */
960 _xioopen_connect(xfd
, us
, uslen
, them
, themlen
, opts
,
961 pf
, socktype
, protocol
, alt
, level
);
965 case STAT_RETRYLATER
:
966 if (xfd
->forever
|| xfd
->retry
) {
968 if (result
== STAT_RETRYLATER
) {
969 Nanosleep(&xfd
->intervall
, NULL
);
971 dropopts(opts
, PH_ALL
); opts
= copyopts(opts0
, GROUP_ALL
);
975 #endif /* WITH_RETRY */
981 xiosetchilddied(); /* set SIGCHLD handler */
988 if (xfd
->forever
|| xfd
->retry
) {
989 level
= E_WARN
; /* most users won't expect a problem here,
990 so Notice is too weak */
993 while ((pid
= xio_fork(false, level
)) < 0) {
995 if (xfd
->forever
|| xfd
->retry
) {
996 dropopts(opts
, PH_ALL
); opts
= copyopts(opts0
, GROUP_ALL
);
997 Nanosleep(&xfd
->intervall
, NULL
); continue;
999 return STAT_RETRYLATER
;
1002 if (pid
== 0) { /* child process */
1006 /* parent process */
1008 /* with and without retry */
1009 Nanosleep(&xfd
->intervall
, NULL
);
1010 dropopts(opts
, PH_ALL
); opts
= copyopts(opts0
, GROUP_ALL
);
1011 continue; /* with next socket() bind() connect() */
1013 #endif /* WITH_RETRY */
1018 if ((result
= _xio_openlate(fd
, opts
)) < 0)
1027 /* common to xioopen_udp_sendto, ..unix_sendto, ..rawip
1028 applies and consumes the following option:
1029 PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE
1031 OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
1033 int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
1034 union sockaddr_union
*us
, socklen_t uslen
,
1036 int xioflags
, xiosingle_t
*xfd
, unsigned groups
,
1037 int pf
, int socktype
, int ipproto
) {
1038 int level
= E_ERROR
;
1039 union sockaddr_union la
; socklen_t lalen
= sizeof(la
);
1042 if ((xfd
->fd
= xiosocket(opts
, pf
, socktype
, ipproto
, level
)) < 0) {
1043 return STAT_RETRYLATER
;
1046 applyopts_offset(xfd
, opts
);
1047 applyopts_single(xfd
, opts
, PH_PASTSOCKET
);
1048 applyopts(xfd
->fd
, opts
, PH_PASTSOCKET
);
1049 applyopts(xfd
->fd
, opts
, PH_FD
);
1051 applyopts_cloexec(xfd
->fd
, opts
);
1053 applyopts(xfd
->fd
, opts
, PH_PREBIND
);
1054 applyopts(xfd
->fd
, opts
, PH_BIND
);
1057 if (Bind(xfd
->fd
, (struct sockaddr
*)us
, uslen
) < 0) {
1058 Msg4(level
, "bind(%d, {%s}, "F_socklen
"): %s",
1059 xfd
->fd
, sockaddr_info((struct sockaddr
*)us
, uslen
, infobuff
, sizeof(infobuff
)),
1060 uslen
, strerror(errno
));
1062 return STAT_RETRYLATER
;
1066 applyopts(xfd
->fd
, opts
, PH_PASTBIND
);
1068 /*applyopts(xfd->fd, opts, PH_CONNECT);*/
1070 if (Getsockname(xfd
->fd
, &la
.soa
, &lalen
) < 0) {
1071 Warn4("getsockname(%d, %p, {%d}): %s",
1072 xfd
->fd
, &la
.soa
, lalen
, strerror(errno
));
1075 applyopts_fchown(xfd
->fd
, opts
);
1076 applyopts(xfd
->fd
, opts
, PH_CONNECTED
);
1077 applyopts(xfd
->fd
, opts
, PH_LATE
);
1079 /* xfd->dtype = DATA_RECVFROM; *//* no, the caller must set this (ev _SKIPIP) */
1080 Notice1("successfully prepared local socket %s",
1081 sockaddr_info(&la
.soa
, lalen
, infobuff
, sizeof(infobuff
)));
1087 /* when the recvfrom address (with option fork) receives a packet it keeps this
1088 packet in the IP stacks input queue and forks a sub process. The sub process
1089 then reads this packet for processing its data.
1090 There is a problem because the parent process would find the same packet
1091 again if it calls select()/poll() before the child process reads the
1093 To solve this problem we implement the following mechanism:
1094 The sub process sends a SIGUSR1 when it has read the packet (or a SIGCHLD if
1095 it dies before). The parent process waits until it receives that signal and
1096 only then continues to listen.
1097 To prevent a signal from another process to trigger our loop, we pass the
1098 pid of the sub process to the signal handler in xio_waitingfor. The signal
1099 handler sets xio_hashappened if the pid matched.
1101 static pid_t xio_waitingfor
; /* info from recv loop to signal handler:
1102 indicates the pid of the child process
1103 that should send us the USR1 signal */
1104 static bool xio_hashappened
; /* info from signal handler to loop: child
1105 process has read ("consumed") the packet */
1106 /* this is the signal handler for USR1 and CHLD */
1107 void xiosigaction_hasread(int signum
1108 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
1109 , siginfo_t
*siginfo
, void *ucontext
1115 bool wassig
= false;
1118 diag_in_handler
= 1;
1119 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
1120 Debug5("xiosigaction_hasread(%d, {%d,%d,%d,"F_pid
"}, )",
1121 signum
, siginfo
->si_signo
, siginfo
->si_errno
, siginfo
->si_code
,
1124 Debug1("xiosigaction_hasread(%d)", signum
);
1126 if (signum
== SIGCHLD
) {
1128 pid
= Waitpid(-1, &status
, WNOHANG
);
1130 Msg(wassig
?E_INFO
:E_WARN
,
1131 "waitpid(-1, {}, WNOHANG): no child has exited");
1132 Info("xiosigaction_hasread() finished");
1133 Debug("xiosigaction_hasread() ->");
1134 diag_in_handler
= 0;
1137 } else if (pid
< 0 && errno
== ECHILD
) {
1138 Msg(wassig
?E_INFO
:E_WARN
,
1139 "waitpid(-1, {}, WNOHANG): "F_strerror
);
1140 Info("xiosigaction_hasread() finished");
1141 Debug("xiosigaction_hasread() ->");
1142 diag_in_handler
= 0;
1148 Warn1("waitpid(-1, {%d}, WNOHANG): "F_strerror
, status
);
1149 Info("xiosigaction_hasread() finished");
1150 Debug("xiosigaction_hasread() ->");
1151 diag_in_handler
= 0;
1155 if (pid
== xio_waitingfor
) {
1156 xio_hashappened
= true;
1157 Debug("xiosigaction_hasread() ->");
1158 diag_in_handler
= 0;
1164 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
1165 if (xio_waitingfor
== siginfo
->si_pid
) {
1166 xio_hashappened
= true;
1169 xio_hashappened
= true;
1172 Signal(sig
, xiosigaction_hasread
);
1173 #endif /* !HAVE_SIGACTION */
1174 Debug("xiosigaction_hasread() ->");
1175 diag_in_handler
= 0;
1181 /* waits for incoming packet, checks its source address and port. Depending
1182 on fork option, it may fork a subprocess.
1183 Returns STAT_OK if a the packet was accepted; with fork option, this is already in
1185 Other return values indicate a problem; this can happen in the master
1186 process or in a subprocess.
1187 This function does not retry. If you need retries, handle this is a
1188 loop in the calling function.
1189 after fork, we set the forever/retry of the child process to 0
1190 applies and consumes the following options:
1191 PH_INIT, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_EARLY, PH_PREOPEN, PH_FD,
1192 PH_CONNECTED, PH_LATE, PH_LATE2
1193 OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, cloexec, OPT_RANGE, tcpwrap
1195 int _xioopen_dgram_recvfrom(struct single
*xfd
, int xioflags
,
1196 struct sockaddr
*us
, socklen_t uslen
,
1198 int pf
, int socktype
, int proto
, int level
) {
1200 bool dofork
= false;
1201 pid_t pid
; /* mostly int; only used with fork */
1204 bool drop
= false; /* true if current packet must be dropped */
1207 retropt_bool(opts
, OPT_FORK
, &dofork
);
1210 if (!(xioflags
& XIO_MAYFORK
)) {
1211 Error("option fork not allowed here");
1212 return STAT_NORETRY
;
1214 xfd
->flags
|= XIO_DOESFORK
;
1217 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return STAT_NORETRY
;
1219 if ((xfd
->fd
= xiosocket(opts
, pf
, socktype
, proto
, level
)) < 0) {
1220 return STAT_RETRYLATER
;
1223 applyopts_single(xfd
, opts
, PH_PASTSOCKET
);
1224 applyopts(xfd
->fd
, opts
, PH_PASTSOCKET
);
1226 applyopts_cloexec(xfd
->fd
, opts
);
1228 applyopts(xfd
->fd
, opts
, PH_PREBIND
);
1229 applyopts(xfd
->fd
, opts
, PH_BIND
);
1230 if ((us
!= NULL
) && Bind(xfd
->fd
, (struct sockaddr
*)us
, uslen
) < 0) {
1231 Msg4(level
, "bind(%d, {%s}, "F_socklen
"): %s", xfd
->fd
,
1232 sockaddr_info(us
, uslen
, infobuff
, sizeof(infobuff
)), uslen
,
1235 return STAT_RETRYLATER
;
1239 if (pf
== AF_UNIX
&& us
!= NULL
) {
1240 applyopts_named(((struct sockaddr_un
*)us
)->sun_path
, opts
, PH_FD
);
1244 applyopts(xfd
->fd
, opts
, PH_PASTBIND
);
1246 if (pf
== AF_UNIX
&& us
!= NULL
) {
1247 /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
1248 applyopts_named(((struct sockaddr_un
*)us
)->sun_path
, opts
, PH_EARLY
);
1249 applyopts_named(((struct sockaddr_un
*)us
)->sun_path
, opts
, PH_PREOPEN
);
1251 #endif /* WITH_UNIX */
1253 /* for generic sockets, this has already been retrieved */
1254 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
1255 if (xioparserange(rangename
, pf
, &xfd
->para
.socket
.range
)
1258 return STAT_NORETRY
;
1261 xfd
->para
.socket
.dorange
= true;
1264 #if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
1265 xio_retropt_tcpwrap(xfd
, opts
);
1266 #endif /* && (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
1268 if (xioopts
.logopt
== 'm') {
1269 Info("starting recvfrom loop, switching to syslog");
1270 diag_set('y', xioopts
.syslogfac
); xioopts
.logopt
= 'y';
1272 Info("starting recvfrom loop");
1278 struct sigaction act
;
1279 memset(&act
, 0, sizeof(struct sigaction
));
1280 act
.sa_flags
= SA_NOCLDSTOP
/*|SA_RESTART*/
1281 #ifdef SA_SIGINFO /* not on Linux 2.0(.33) */
1288 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
1289 act
.sa_sigaction
= xiosigaction_hasread
;
1290 #else /* Linux 2.0(.33) does not have sigaction.sa_sigaction */
1291 act
.sa_handler
= xiosigaction_hasread
;
1293 sigfillset(&act
.sa_mask
);
1294 if (Sigaction(SIGUSR1
, &act
, NULL
) < 0) {
1295 /*! Linux man does not explicitely say that errno is defined */
1296 Warn1("sigaction(SIGUSR1, {&xiosigaction_subaddr_ok}, NULL): %s", strerror(errno
));
1298 if (Sigaction(SIGCHLD
, &act
, NULL
) < 0) {
1299 /*! Linux man does not explicitely say that errno is defined */
1300 Warn1("sigaction(SIGCHLD, {&xiosigaction_subaddr_ok}, NULL): %s", strerror(errno
));
1303 #else /* !HAVE_SIGACTION */
1305 if (Signal(SIGUSR1
, xiosigaction_hasread
) == SIG_ERR
) {
1306 Warn1("signal(SIGUSR1, xiosigaction_hasread): %s", strerror(errno
));
1308 if (Signal(SIGCHLD
, xiosigaction_hasread
) == SIG_ERR
) {
1309 Warn1("signal(SIGCHLD, xiosigaction_hasread): %s", strerror(errno
));
1311 #endif /* !HAVE_SIGACTION */
1314 while (true) { /* but we only loop if fork option is set */
1316 union sockaddr_union _peername
;
1317 union sockaddr_union _sockname
;
1318 union sockaddr_union
*pa
= &_peername
; /* peer address */
1319 union sockaddr_union
*la
= &_sockname
; /* local address */
1320 socklen_t palen
= sizeof(_peername
); /* peer address size */
1321 char ctrlbuff
[1024]; /* ancillary messages */
1322 struct msghdr msgh
= {0};
1324 socket_init(pf
, pa
);
1329 Recv(xfd
->fd
, dummy
, sizeof(dummy
), 0);
1333 /* loop until select()/poll() returns valid */
1335 struct pollfd readfd
;
1336 /*? int level = E_ERROR;*/
1338 Notice1("receiving on %s", sockaddr_info(us
, uslen
, lisname
, sizeof(lisname
)));
1340 Notice1("receiving IP protocol %u", proto
);
1342 readfd
.fd
= xfd
->fd
;
1343 readfd
.events
= POLLIN
;
1344 if (xiopoll(&readfd
, 1, NULL
) > 0) {
1348 if (errno
== EINTR
) {
1352 Msg2(level
, "poll({%d,,},,-1): %s", xfd
->fd
, strerror(errno
));
1354 return STAT_RETRYLATER
;
1358 msgh
.msg_namelen
= palen
;
1359 #if HAVE_STRUCT_MSGHDR_MSGCONTROL
1360 msgh
.msg_control
= ctrlbuff
;
1362 #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
1363 msgh
.msg_controllen
= sizeof(ctrlbuff
);
1365 if (xiogetpacketsrc(xfd
->fd
, &msgh
) < 0) {
1366 return STAT_RETRYLATER
;
1368 palen
= msgh
.msg_namelen
;
1370 Notice1("receiving packet from %s"/*"src"*/,
1371 sockaddr_info((struct sockaddr
*)pa
, palen
, peername
, sizeof(peername
))/*,
1372 sockaddr_info(&la->soa, sockname, sizeof(sockname))*/);
1374 xiodopacketinfo(&msgh
, true, true);
1376 if (xiocheckpeer(xfd
, pa
, la
) < 0) {
1379 Recv(xfd
->fd
, buff
, sizeof(buff
), 0);
1382 Info1("permitting packet from %s",
1383 sockaddr_info((struct sockaddr
*)pa
, palen
,
1384 infobuff
, sizeof(infobuff
)));
1386 /* set the env vars describing the local and remote sockets */
1387 /*xiosetsockaddrenv("SOCK", la, lalen, proto);*/
1388 xiosetsockaddrenv("PEER", pa
, palen
, proto
);
1390 applyopts(xfd
->fd
, opts
, PH_FD
);
1392 applyopts(xfd
->fd
, opts
, PH_CONNECTED
);
1394 xfd
->peersa
= *(union sockaddr_union
*)pa
;
1398 sigset_t mask_sigchldusr1
;
1400 /* we must prevent that the current packet triggers another fork;
1401 therefore we wait for a signal from the recent child: USR1
1402 indicates that is has consumed the last packet; CHLD means it has
1404 /* block SIGCHLD and SIGUSR1 until parent is ready to react */
1405 sigemptyset(&mask_sigchldusr1
);
1406 sigaddset(&mask_sigchldusr1
, SIGCHLD
);
1407 sigaddset(&mask_sigchldusr1
, SIGUSR1
);
1408 Sigprocmask(SIG_BLOCK
, &mask_sigchldusr1
, NULL
);
1410 if ((pid
= xio_fork(false, level
)) < 0) {
1412 Sigprocmask(SIG_UNBLOCK
, &mask_sigchldusr1
, NULL
);
1413 return STAT_RETRYLATER
;
1416 if (pid
== 0) { /* child */
1417 /* no reason to block SIGCHLD in child process */
1418 Sigprocmask(SIG_UNBLOCK
, &mask_sigchldusr1
, NULL
);
1419 xfd
->ppid
= Getppid(); /* send parent a signal when packet has
1427 #endif /* WITH_RETRY */
1430 /* with UNIX sockets: only listening parent is allowed to remove
1432 xfd
->opt_unlink_close
= false;
1433 #endif /* WITH_UNIX */
1438 /* server: continue loop with listen */
1439 xio_waitingfor
= pid
;
1440 /* now we are ready to handle signals */
1441 Sigprocmask(SIG_UNBLOCK
, &mask_sigchldusr1
, NULL
);
1443 while (!xio_hashappened
) {
1444 Sleep(UINT_MAX
); /* any signal lets us continue */
1446 xio_waitingfor
= 0; /* so this child will not set hashappened again */
1447 xio_hashappened
= false;
1449 Info("continue listening");
1454 if ((result
= _xio_openlate(xfd
, opts
)) != 0)
1455 return STAT_NORETRY
;
1461 /* returns STAT_* */
1462 int _xioopen_dgram_recv(struct single
*xfd
, int xioflags
,
1463 struct sockaddr
*us
, socklen_t uslen
,
1464 struct opt
*opts
, int pf
, int socktype
, int proto
,
1469 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return STAT_NORETRY
;
1471 if ((xfd
->fd
= xiosocket(opts
, pf
, socktype
, proto
, level
)) < 0) {
1472 return STAT_RETRYLATER
;
1475 applyopts_single(xfd
, opts
, PH_PASTSOCKET
);
1476 applyopts(xfd
->fd
, opts
, PH_PASTSOCKET
);
1478 applyopts_cloexec(xfd
->fd
, opts
);
1480 applyopts(xfd
->fd
, opts
, PH_PREBIND
);
1481 applyopts(xfd
->fd
, opts
, PH_BIND
);
1482 if ((us
!= NULL
) && Bind(xfd
->fd
, (struct sockaddr
*)us
, uslen
) < 0) {
1483 Msg4(level
, "bind(%d, {%s}, "F_socklen
"): %s", xfd
->fd
,
1484 sockaddr_info(us
, uslen
, infobuff
, sizeof(infobuff
)), uslen
,
1487 return STAT_RETRYLATER
;
1491 if (pf
== AF_UNIX
&& us
!= NULL
) {
1492 applyopts_named(((struct sockaddr_un
*)us
)->sun_path
, opts
, PH_FD
);
1496 applyopts(xfd
->fd
, opts
, PH_PASTBIND
);
1498 if (pf
== AF_UNIX
&& us
!= NULL
) {
1499 /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
1500 applyopts_named(((struct sockaddr_un
*)us
)->sun_path
, opts
, PH_EARLY
);
1501 applyopts_named(((struct sockaddr_un
*)us
)->sun_path
, opts
, PH_PREOPEN
);
1503 #endif /* WITH_UNIX */
1505 #if WITH_IP4 /*|| WITH_IP6*/
1506 if (retropt_string(opts
, OPT_RANGE
, &rangename
) >= 0) {
1507 if (xioparserange(rangename
, pf
, &xfd
->para
.socket
.range
)
1510 return STAT_NORETRY
;
1513 xfd
->para
.socket
.dorange
= true;
1517 #if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
1518 xio_retropt_tcpwrap(xfd
, opts
);
1519 #endif /* && (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
1521 if (xioopts
.logopt
== 'm') {
1522 Info("starting recvfrom loop, switching to syslog");
1523 diag_set('y', xioopts
.syslogfac
); xioopts
.logopt
= 'y';
1525 Info("starting recvfrom loop");
1532 int retropt_socket_pf(struct opt
*opts
, int *pf
) {
1535 if (retropt_string(opts
, OPT_PROTOCOL_FAMILY
, &pfname
) >= 0) {
1536 if (isdigit(pfname
[0])) {
1537 *pf
= strtoul(pfname
, NULL
/*!*/, 0);
1539 } else if (!strcasecmp("inet", pfname
) ||
1540 !strcasecmp("inet4", pfname
) ||
1541 !strcasecmp("ip4", pfname
) ||
1542 !strcasecmp("ipv4", pfname
) ||
1543 !strcasecmp("2", pfname
)) {
1545 #endif /* WITH_IP4 */
1547 } else if (!strcasecmp("inet6", pfname
) ||
1548 !strcasecmp("ip6", pfname
) ||
1549 !strcasecmp("ipv6", pfname
) ||
1550 !strcasecmp("10", pfname
)) {
1552 #endif /* WITH_IP6 */
1554 Error1("unknown protocol family \"%s\"", pfname
);
1555 /*! Warn("falling back to INET");*/
1564 /* this function calls recvmsg(..., MSG_PEEK, ...) to obtain information about
1565 the arriving packet. in msgh the msg_name pointer must refer to an (empty)
1566 sockaddr storage. */
1567 int xiogetpacketsrc(int fd
, struct msghdr
*msgh
) {
1569 #if HAVE_STRUCT_IOVEC
1573 #if HAVE_STRUCT_IOVEC
1574 iovec
.iov_base
= peekbuff
;
1575 iovec
.iov_len
= sizeof(peekbuff
);
1576 msgh
->msg_iov
= &iovec
;
1577 msgh
->msg_iovlen
= 1;
1579 #if HAVE_STRUCT_MSGHDR_MSGFLAGS
1580 msgh
->msg_flags
= 0;
1582 if (Recvmsg(fd
, msgh
, MSG_PEEK
1587 Warn1("recvmsg(): %s", strerror(errno
));
1588 return STAT_RETRYLATER
;
1594 /* works through the ancillary messages found in the given socket header record
1595 and logs the relevant information (E_DEBUG, E_INFO).
1596 calls protocol/layer specific functions for handling the messages
1597 creates appropriate environment vars if withenv is set */
1598 int xiodopacketinfo(struct msghdr
*msgh
, bool withlog
, bool withenv
) {
1599 #if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)
1600 struct cmsghdr
*cmsg
;
1602 /* parse ancillary messages */
1603 cmsg
= CMSG_FIRSTHDR(msgh
);
1604 while (cmsg
!= NULL
) {
1605 int num
= 0; /* number of data components of a ancill.msg */
1607 char typbuff
[16], *typp
;
1608 char nambuff
[128], *namp
;
1609 char valbuff
[256], *valp
;
1610 char envbuff
[256], *envp
;
1613 xiodump(CMSG_DATA(cmsg
),
1614 cmsg
->cmsg_len
-((char *)CMSG_DATA(cmsg
)-(char *)cmsg
),
1615 valbuff
, sizeof(valbuff
)-1, 0);
1616 Debug4("ancillary message: len="F_cmsg_len
", level=%d, type=%d, data=%s",
1617 cmsg
->cmsg_len
, cmsg
->cmsg_level
, cmsg
->cmsg_type
,
1621 /* try to get the anc.msg. contents in handy components, protocol/level
1623 switch (cmsg
->cmsg_level
) {
1625 xiolog_ancillary_socket(cmsg
, &num
, typbuff
, sizeof(typbuff
)-1,
1626 nambuff
, sizeof(nambuff
)-1,
1627 envbuff
, sizeof(envbuff
)-1,
1628 valbuff
, sizeof(valbuff
)-1);
1630 #if WITH_IP4 || WITH_IP6
1632 xiolog_ancillary_ip(cmsg
, &num
, typbuff
, sizeof(typbuff
)-1,
1633 nambuff
, sizeof(nambuff
)-1,
1634 envbuff
, sizeof(envbuff
)-1,
1635 valbuff
, sizeof(valbuff
)-1);
1637 #endif /* WITH_IP4 || WITH_IP6 */
1640 xiolog_ancillary_ip6(cmsg
, &num
, typbuff
, sizeof(typbuff
)-1,
1641 nambuff
, sizeof(nambuff
)-1,
1642 envbuff
, sizeof(envbuff
)-1,
1643 valbuff
, sizeof(valbuff
)-1);
1645 #endif /* WITH_IP6 */
1648 snprintf(typbuff
, sizeof(typbuff
)-1, "LEVEL%u", cmsg
->cmsg_level
);
1649 snprintf(nambuff
, sizeof(nambuff
)-1, "type%u", cmsg
->cmsg_type
);
1650 xiodump(CMSG_DATA(cmsg
),
1651 cmsg
->cmsg_len
-((char *)CMSG_DATA(cmsg
)-(char *)cmsg
),
1652 valbuff
, sizeof(valbuff
)-1, 0);
1654 /* here the info is in typbuff (one string), nambuff (num consecutive
1655 strings), and valbuff (num consecutive strings) */
1657 typp
= typbuff
; namp
= nambuff
; envp
= envbuff
; valp
= valbuff
;
1660 Info3("ancillary message: %s: %s=%s", typp
, namp
, valp
);
1664 xiosetenv(envp
, valp
, 1, NULL
);
1665 } else if (!strcasecmp(typp
+strlen(typp
)-strlen(namp
), namp
)) {
1666 xiosetenv(typp
, valp
, 1, NULL
);
1668 xiosetenv2(typp
, namp
, valp
, 1, NULL
);
1671 if (++i
== num
) break;
1672 namp
= strchr(namp
, '\0')+1;
1673 envp
= strchr(envp
, '\0')+1;
1674 valp
= strchr(valp
, '\0')+1;
1676 cmsg
= CMSG_NXTHDR(msgh
, cmsg
);
1679 #else /* !(defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)) */
1681 #endif /* !(defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)) */
1685 /* check if peer address is within permitted range.
1686 return >= 0 if so. */
1687 int xiocheckrange(union sockaddr_union
*sa
, struct xiorange
*range
) {
1688 switch (sa
->soa
.sa_family
) {
1692 xiocheckrange_ip4(&sa
->ip4
, range
);
1693 #endif /* WITH_IP4 */
1697 xiocheckrange_ip6(&sa
->ip6
, range
);
1698 #endif /* WITH_IP6 */
1703 for (i
= 0; i
< sizeof(sa
->soa
.sa_data
); ++i
) {
1704 if ((range
->netmask
.soa
.sa_data
[i
] & sa
->soa
.sa_data
[i
]) != range
->netaddr
.soa
.sa_data
[i
]) {
1715 int xiocheckpeer(xiosingle_t
*xfd
,
1716 union sockaddr_union
*pa
, union sockaddr_union
*la
) {
1721 if (xfd
->para
.socket
.dorange
) {
1722 if (pa
== NULL
) { return -1; }
1723 if (xiocheckrange(pa
, &xfd
->para
.socket
.range
) < 0) {
1725 Warn1("refusing connection from %s due to range option",
1726 sockaddr_info((struct sockaddr
*)pa
, 0,
1727 infobuff
, sizeof(infobuff
)));
1730 Info1("permitting connection from %s due to range option",
1731 sockaddr_info((struct sockaddr
*)pa
, 0,
1732 infobuff
, sizeof(infobuff
)));
1734 #endif /* WITH_IP4 */
1736 #if WITH_TCP || WITH_UDP
1737 if (xfd
->para
.socket
.ip
.dosourceport
) {
1738 if (pa
== NULL
) { return -1; }
1740 if (pa
->soa
.sa_family
== AF_INET
&&
1741 ntohs(((struct sockaddr_in
*)pa
)->sin_port
) != xfd
->para
.socket
.ip
.sourceport
) {
1742 Warn1("refusing connection from %s due to wrong sourceport",
1743 sockaddr_info((struct sockaddr
*)pa
, 0,
1744 infobuff
, sizeof(infobuff
)));
1747 #endif /* WITH_IP4 */
1749 if (pa
->soa
.sa_family
== AF_INET6
&&
1750 ntohs(((struct sockaddr_in6
*)pa
)->sin6_port
) != xfd
->para
.socket
.ip
.sourceport
) {
1751 Warn1("refusing connection from %s due to wrong sourceport",
1752 sockaddr_info((struct sockaddr
*)pa
, 0,
1753 infobuff
, sizeof(infobuff
)));
1756 #endif /* WITH_IP6 */
1757 Info1("permitting connection from %s due to sourceport option",
1758 sockaddr_info((struct sockaddr
*)pa
, 0,
1759 infobuff
, sizeof(infobuff
)));
1760 } else if (xfd
->para
.socket
.ip
.lowport
) {
1761 if (pa
== NULL
) { return -1; }
1762 if (pa
->soa
.sa_family
== AF_INET
&&
1763 ntohs(((struct sockaddr_in
*)pa
)->sin_port
) >= IPPORT_RESERVED
) {
1764 Warn1("refusing connection from %s due to lowport option",
1765 sockaddr_info((struct sockaddr
*)pa
, 0,
1766 infobuff
, sizeof(infobuff
)));
1770 else if (pa
->soa
.sa_family
== AF_INET6
&&
1771 ntohs(((struct sockaddr_in6
*)pa
)->sin6_port
) >=
1773 Warn1("refusing connection from %s due to lowport option",
1774 sockaddr_info((struct sockaddr
*)pa
, 0,
1775 infobuff
, sizeof(infobuff
)));
1778 #endif /* WITH_IP6 */
1779 Info1("permitting connection from %s due to lowport option",
1780 sockaddr_info((struct sockaddr
*)pa
, 0,
1781 infobuff
, sizeof(infobuff
)));
1783 #endif /* WITH_TCP || WITH_UDP */
1785 #if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
1786 result
= xio_tcpwrap_check(xfd
, la
, pa
);
1789 Warn1("refusing connection from %s due to tcpwrapper option",
1790 sockaddr_info((struct sockaddr
*)pa
, 0,
1791 infobuff
, sizeof(infobuff
)));
1793 } else if (result
> 0) {
1794 Info1("permitting connection from %s due to tcpwrapper option",
1795 sockaddr_info((struct sockaddr
*)pa
, 0,
1796 infobuff
, sizeof(infobuff
)));
1798 #endif /* (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
1800 return 0; /* permitted */
1804 #if HAVE_STRUCT_CMSGHDR
1805 /* converts the ancillary message in *cmsg into a form useable for further
1806 processing. knows the specifics of common message types.
1807 returns the number of resulting syntax elements in *num
1808 returns a sequence of \0 terminated type strings in *typbuff
1809 returns a sequence of \0 terminated name strings in *nambuff
1810 returns a sequence of \0 terminated value strings in *valbuff
1811 the respective len parameters specify the available space in the buffers
1812 returns STAT_OK or other STAT_*
1815 xiolog_ancillary_socket(struct cmsghdr
*cmsg
, int *num
,
1816 char *typbuff
, int typlen
,
1817 char *nambuff
, int namlen
,
1818 char *envbuff
, int envlen
,
1819 char *valbuff
, int vallen
) {
1820 const char *cmsgtype
, *cmsgname
, *cmsgenvn
;
1825 #if defined(CMSG_DATA)
1827 msglen
= cmsg
->cmsg_len
-((char *)CMSG_DATA(cmsg
)-(char *)cmsg
);
1828 switch (cmsg
->cmsg_type
) {
1830 case SO_PASSCRED
: /* this is really a UNIX/LOCAL message */
1831 /*! needs implementation */
1832 #endif /* SO_PASSCRED */
1834 case SO_RIGHTS
: /* this is really a UNIX/LOCAL message */
1835 /*! needs implementation */
1837 default: /* binary data */
1838 snprintf(typbuff
, typlen
, "SOCKET.%u", cmsg
->cmsg_type
);
1839 nambuff
[0] = '\0'; strncat(nambuff
, "data", namlen
-1);
1840 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
1843 # ifdef SCM_TIMESTAMP
1848 tv
= (struct timeval
*)CMSG_DATA(cmsg
);
1850 #ifdef SCM_TIMESTAMP
1851 "SCM_TIMESTAMP" /* FreeBSD */
1853 "SO_TIMESTAMP" /* Linux */
1856 cmsgname
= "timestamp";
1857 cmsgenvn
= "TIMESTAMP";
1858 { time_t t
= tv
->tv_sec
; ctime_r(&t
, valbuff
); }
1859 snprintf(strchr(valbuff
, '\0')-1/*del \n*/, vallen
-strlen(valbuff
)+1, ", %06ld usecs", (long)tv
->tv_usec
);
1861 #endif /* defined(SO_TIMESTAMP) */
1864 /* when we come here we provide a single parameter
1865 with type in cmsgtype, name in cmsgname,
1866 and value already in valbuff */
1868 if (strlen(cmsgtype
) >= typlen
) rc
= STAT_WARNING
;
1869 typbuff
[0] = '\0'; strncat(typbuff
, cmsgtype
, typlen
-1);
1870 if (strlen(cmsgname
) >= namlen
) rc
= STAT_WARNING
;
1871 nambuff
[0] = '\0'; strncat(nambuff
, cmsgname
, namlen
-1);
1872 if (strlen(cmsgenvn
) >= envlen
) rc
= STAT_WARNING
;
1873 envbuff
[0] = '\0'; strncat(envbuff
, cmsgenvn
, envlen
-1);
1876 #else /* !defined(CMSG_DATA) */
1878 return STAT_NORETRY
;
1880 #endif /* !defined(CMSG_DATA) */
1882 #endif /* HAVE_STRUCT_CMSGHDR */
1885 /* return the name of the interface with given index
1887 The system call requires an arbitrary socket; the calling program may
1888 provide one in parameter ins to avoid creation of a dummy socket. ins must
1889 be <0 if it does not specify a socket fd. */
1890 char *xiogetifname(int ind
, char *val
, int ins
) {
1891 #if !HAVE_PROTOTYPE_LIB_if_indextoname
1898 if ((s
= Socket(PF_INET
, SOCK_DGRAM
, IPPROTO_IP
)) < 0) {
1899 Error1("socket(PF_INET, SOCK_DGRAM, IPPROTO_IP): %s", strerror(errno
));
1904 #if HAVE_STRUCT_IFREQ_IFR_INDEX
1905 ifr
.ifr_index
= ind
;
1906 #elif HAVE_STRUCT_IFREQ_IFR_IFINDEX
1907 ifr
.ifr_ifindex
= ind
;
1910 if(Ioctl(s
, SIOCGIFNAME
, &ifr
) < 0) {
1911 #if HAVE_STRUCT_IFREQ_IFR_INDEX
1912 Info3("ioctl(%d, SIOCGIFNAME, {..., ifr_index=%d, ...}: %s",
1913 s
, ifr
.ifr_index
, strerror(errno
));
1914 #elif HAVE_STRUCT_IFREQ_IFR_IFINDEX
1915 Info3("ioctl(%d, SIOCGIFNAME, {..., ifr_ifindex=%d, ...}: %s",
1916 s
, ifr
.ifr_ifindex
, strerror(errno
));
1918 if (ins
< 0) Close(s
);
1921 #endif /* SIOCGIFNAME */
1922 if (ins
< 0) Close(s
);
1923 strcpy(val
, ifr
.ifr_name
);
1925 #else /* HAVE_PROTOTYPE_LIB_if_indextoname */
1926 return if_indextoname(ind
, val
);
1927 #endif /* HAVE_PROTOTYPE_LIB_if_indextoname */
1931 /* parses a network specification consisting of an address and a mask. */
1932 int xioparsenetwork(const char *rangename
, int pf
, struct xiorange
*range
) {
1933 size_t addrlen
= 0, masklen
= 0;
1939 return xioparsenetwork_ip4(rangename
, range
);
1941 #endif /* WITH_IP4 */
1944 return xioparsenetwork_ip6(rangename
, range
);
1946 #endif /* WITH_IP6 */
1950 const char *maskname
;
1951 if ((maskname
= strchr(rangename
, ':')) == NULL
) {
1952 Error1("syntax error in range \"%s\": use <addr>:<mask>", rangename
);
1953 return STAT_NORETRY
;
1955 ++maskname
; /* skip ':' */
1956 if ((addrname
= Malloc(maskname
-rangename
)) == NULL
) {
1957 return STAT_NORETRY
;
1959 strncpy(addrname
, rangename
, maskname
-rangename
-1); /* ok */
1960 addrname
[maskname
-rangename
-1] = '\0';
1962 dalan(addrname
, (char *)&range
->netaddr
.soa
.sa_data
, &addrlen
,
1963 sizeof(range
->netaddr
)-(size_t)(&((struct sockaddr
*)0)->sa_data
)
1966 Error1("data too long: \"%s\"", addrname
);
1967 free(addrname
); return STAT_NORETRY
;
1968 } else if (result
> 0) {
1969 Error1("syntax error in \"%s\"", addrname
);
1970 free(addrname
); return STAT_NORETRY
;
1974 dalan(maskname
, (char *)&range
->netmask
.soa
.sa_data
, &masklen
,
1975 sizeof(range
->netaddr
)-(size_t)(&((struct sockaddr
*)0)->sa_data
)
1978 Error1("data too long: \"%s\"", maskname
);
1979 return STAT_NORETRY
;
1980 } else if (result
> 0) {
1981 Error1("syntax error in \"%s\"", maskname
);
1982 return STAT_NORETRY
;
1984 if (addrlen
!= masklen
) {
1985 Error2("network address is "F_Zu
" bytes long, mask is "F_Zu
" bytes long",
1987 /* recover by padding the shorter component with 0 */
1988 memset((char *)&range
->netaddr
.soa
.sa_data
+addrlen
, 0,
1989 MAX(0, addrlen
-masklen
));
1990 memset((char *)&range
->netmask
.soa
.sa_data
+masklen
, 0,
1991 MAX(0, masklen
-addrlen
));
1996 Error1("range option not supported with address family %d", pf
);
1997 return STAT_NORETRY
;
2003 /* parses a string of form address/bits or address:mask, and fills the fields
2004 of the range union. The addr component is masked with mask. */
2005 int xioparserange(const char *rangename
, int pf
, struct xiorange
*range
) {
2007 if (xioparsenetwork(rangename
, pf
, range
) < 0) {
2010 /* we have parsed the address and mask; now we make sure that the stored
2011 address has 0 where mask is 0, to simplify comparisions */
2015 range
->netaddr
.ip4
.sin_addr
.s_addr
&= range
->netmask
.ip4
.sin_addr
.s_addr
;
2017 #endif /* WITH_IP4 */
2020 return xiorange_ip6andmask(range
);
2022 #endif /* WITH_IP6 */
2024 for (i
= 0; i
< sizeof(range
->netaddr
); ++i
) {
2025 ((char *)&range
->netaddr
)[i
] &= ((char *)&range
->netmask
)[i
];
2029 Error1("range option not supported with address family %d", pf
);
2030 return STAT_NORETRY
;
2036 /* set environment variables describing (part of) a socket address, e.g.
2037 SOCAT_SOCKADDR. lr (local/remote) specifies a string like "SOCK" or "PEER".
2038 proto should correspond to the third parameter of socket(2) and is used to
2039 determine the presence of port information. */
2040 int xiosetsockaddrenv(const char *lr
,
2041 union sockaddr_union
*sau
, socklen_t salen
,
2043 # define XIOSOCKADDRENVLEN 256
2044 char namebuff
[XIOSOCKADDRENVLEN
];
2045 char valuebuff
[XIOSOCKADDRENVLEN
];
2046 int idx
= 0, result
;
2048 strcpy(namebuff
, lr
);
2049 switch (sau
->soa
.sa_family
) {
2053 xiosetsockaddrenv_unix(idx
, strchr(namebuff
, '\0'), XIOSOCKADDRENVLEN
-strlen(lr
),
2054 valuebuff
, XIOSOCKADDRENVLEN
,
2055 &sau
->un
, salen
, proto
);
2056 xiosetenv(namebuff
, valuebuff
, 1, NULL
);
2058 #endif /* WITH_UNIX */
2063 xiosetsockaddrenv_ip4(idx
, strchr(namebuff
, '\0'), XIOSOCKADDRENVLEN
-strlen(lr
),
2064 valuebuff
, XIOSOCKADDRENVLEN
,
2066 xiosetenv(namebuff
, valuebuff
, 1, NULL
);
2067 namebuff
[strlen(lr
)] = '\0'; ++idx
;
2068 } while (result
> 0);
2070 #endif /* WITH_IP4 */
2073 strcpy(namebuff
, lr
);
2076 xiosetsockaddrenv_ip6(idx
, strchr(namebuff
, '\0'), XIOSOCKADDRENVLEN
-strlen(lr
),
2077 valuebuff
, XIOSOCKADDRENVLEN
,
2079 xiosetenv(namebuff
, valuebuff
, 1, NULL
);
2080 namebuff
[strlen(lr
)] = '\0'; ++idx
;
2081 } while (result
> 0);
2083 #endif /* WITH_IP6 */
2086 result
= xiosetsockaddrenv_packet(lr
, (void *)sau
, proto
); break;
2093 # undef XIOSOCKADDRENVLEN
2096 #endif /* _WITH_SOCKET */
2098 /* these do sockets internally */
2100 /* retrieves options so-type and so-prototype from opts, calls socket, and
2101 ev. generates an appropriate error message.
2102 returns 0 on success or -1 if an error occurred. */
2104 xiosocket(struct opt
*opts
, int pf
, int socktype
, int proto
, int msglevel
) {
2107 retropt_int(opts
, OPT_SO_TYPE
, &socktype
);
2108 retropt_int(opts
, OPT_SO_PROTOTYPE
, &proto
);
2109 result
= Socket(pf
, socktype
, proto
);
2111 Msg4(msglevel
, "socket(%d, %d, %d): %s",
2112 pf
, socktype
, proto
, strerror(errno
));
2118 /* retrieves options so-type and so-prototype from opts, calls socketpair, and
2119 ev. generates an appropriate error message.
2120 returns 0 on success or -1 if an error occurred. */
2122 xiosocketpair(struct opt
*opts
, int pf
, int socktype
, int proto
, int sv
[2]) {
2125 retropt_int(opts
, OPT_SO_TYPE
, &socktype
);
2126 retropt_int(opts
, OPT_SO_PROTOTYPE
, &proto
);
2127 result
= Socketpair(pf
, socktype
, proto
, sv
);
2129 Error5("socketpair(%d, %d, %d, %p): %s",
2130 pf
, socktype
, proto
, sv
, strerror(errno
));