nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* source: xio-socket.c */
2 /* Copyright Gerhard Rieger */
3 /* Published under the GNU General Public License V.2, see file COPYING */
4  
5 /* this file contains the source for socket related functions, and the
6 implementation of generic socket addresses */
7  
8 #include "xiosysincludes.h"
9  
10 #if _WITH_SOCKET
11  
12 #include "xioopen.h"
13 #include "xiosigchld.h"
14 #include "xio-ascii.h"
15 #include "xio-socket.h"
16 #include "xio-named.h"
17 #include "xio-unix.h"
18 #if WITH_IP4
19 #include "xio-ip4.h"
20 #endif /* WITH_IP4 */
21 #if WITH_IP6
22 #include "xio-ip6.h"
23 #endif /* WITH_IP6 */
24 #include "xio-ip.h"
25 #include "xio-listen.h"
26 #include "xio-ipapp.h" /*! not clean */
27 #include "xio-tcpwrap.h"
28  
29  
30 static
31 int xioopen_socket_connect(int argc, const char *argv[], struct opt *opts,
32 int xioflags, xiofile_t *xfd, unsigned groups,
33 int dummy1, int dummy2, int dummy3);
34 static
35 int xioopen_socket_listen(int argc, const char *argv[], struct opt *opts,
36 int xioflags, xiofile_t *xfd, unsigned groups,
37 int dummy1, int dummy2, int dummy3);
38 static
39 int xioopen_socket_sendto(int argc, const char *argv[], struct opt *opts,
40 int xioflags, xiofile_t *xfd, unsigned groups,
41 int dummy1, int dummy2, int dummy3);
42 static
43 int xioopen_socket_datagram(int argc, const char *argv[], struct opt *opts,
44 int xioflags, xiofile_t *xfd, unsigned groups,
45 int dummy1, int dummy2, int dummy3);
46 static
47 int xioopen_socket_recvfrom(int argc, const char *argv[], struct opt *opts,
48 int xioflags, xiofile_t *xfd, unsigned groups,
49 int dummy1, int socktype, int dummy3);
50 static
51 int xioopen_socket_recv(int argc, const char *argv[], struct opt *opts,
52 int xioflags, xiofile_t *xfd, unsigned groups,
53 int dumy1, int dummy2, int dummy3);
54  
55 static
56 int _xioopen_socket_sendto(const char *pfname, const char *type,
57 const char *proto, const char *address,
58 struct opt *opts, int xioflags, xiofile_t *xxfd,
59 unsigned groups);
60  
61 static int
62 xiolog_ancillary_socket(struct cmsghdr *cmsg, int *num,
63 char *typbuff, int typlen,
64 char *nambuff, int namlen,
65 char *envbuff, int envlen,
66 char *valbuff, int vallen);
67  
68  
69 #if WITH_GENERICSOCKET
70 /* generic socket addresses */
71 const struct xioaddr_endpoint_desc xioaddr_socket_connect3 = { XIOADDR_ENDPOINT, "socket-connect", 3, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_socket_connect, 0, 0, 0 HELP(":<domain>:<protocol>:<remote-address>") };
72 const union xioaddr_desc *xioaddrs_socket_connect[] = {
73 (union xioaddr_desc *)&xioaddr_socket_connect3,
74 NULL
75 };
76  
77 #if WITH_LISTEN
78 const struct xioaddr_endpoint_desc xioaddr_socket_listen3 = { XIOADDR_ENDPOINT, "socket-listen", 3, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_LISTEN|GROUP_RANGE|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_socket_listen, 0, 0, 0 HELP(":<domain>:<protocol>:<local-address>") };
79 const union xioaddr_desc *xioaddrs_socket_listen[] = {
80 (union xioaddr_desc *)&xioaddr_socket_listen3,
81 NULL
82 };
83 #endif /* WITH_LISTEN */
84  
85 const struct xioaddr_endpoint_desc xioaddr_socket_sendto4 = { XIOADDR_ENDPOINT, "socket-sendto", 4, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_socket_sendto, 0, 0, 0 HELP(":<domain>:<type>:<protocol>:<remote-address>") };
86 const union xioaddr_desc *xioaddrs_socket_sendto[] = {
87 (union xioaddr_desc *)&xioaddr_socket_sendto4,
88 NULL
89 };
90  
91 const struct xioaddr_endpoint_desc xioaddr_socket_datagram4 = { XIOADDR_ENDPOINT, "socket-datagram",4, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_socket_datagram, 0, 0, 0 HELP(":<domain>:<type>:<protocol>:<remote-address>") };
92 const union xioaddr_desc *xioaddrs_socket_datagram[] = {
93 (union xioaddr_desc *)&xioaddr_socket_datagram4,
94 NULL
95 };
96  
97 const struct xioaddr_endpoint_desc xioaddr_socket_recvfrom4 = { XIOADDR_ENDPOINT, "socket-recvfrom",4, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_RANGE|GROUP_CHILD, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_socket_recvfrom, 0, 0, 0 HELP(":<domain>:<type>:<protocol>:<local-address>") };
98 const union xioaddr_desc *xioaddrs_socket_recvfrom[] = {
99 (union xioaddr_desc *)&xioaddr_socket_recvfrom4,
100 NULL
101 };
102  
103 const struct xioaddr_endpoint_desc xioaddr_socket_recv4 = { XIOADDR_ENDPOINT, "socket-recv", 4, XIOBIT_RDONLY,GROUP_FD|GROUP_SOCKET|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_socket_recv, 0, 0, 0 HELP(":<domain>:<type>:<protocol>:<local-address>") };
104 const union xioaddr_desc *xioaddrs_socket_recv[] = {
105 (union xioaddr_desc *)&xioaddr_socket_recv4,
106 NULL
107 };
108 #endif /* WITH_GENERICSOCKET */
109  
110  
111 /* the following options apply not only to generic socket addresses but to all
112 addresses that have anything to do with sockets */
113 const struct optdesc opt_so_debug = { "so-debug", "debug", OPT_SO_DEBUG, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_DEBUG };
114 #ifdef SO_ACCEPTCONN /* AIX433 */
115 const struct optdesc opt_so_acceptconn={ "so-acceptconn","acceptconn",OPT_SO_ACCEPTCONN,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_ACCEPTCONN};
116 #endif /* SO_ACCEPTCONN */
117 const struct optdesc opt_so_broadcast= { "so-broadcast", "broadcast", OPT_SO_BROADCAST,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_BROADCAST};
118 const struct optdesc opt_so_reuseaddr= { "so-reuseaddr", "reuseaddr", OPT_SO_REUSEADDR,GROUP_SOCKET, PH_PREBIND, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_REUSEADDR};
119 const struct optdesc opt_so_keepalive= { "so-keepalive", "keepalive", OPT_SO_KEEPALIVE,GROUP_SOCKET, PH_FD, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_KEEPALIVE};
120 #if HAVE_STRUCT_LINGER
121 const struct optdesc opt_so_linger = { "so-linger", "linger", OPT_SO_LINGER, GROUP_SOCKET, PH_PASTSOCKET, TYPE_LINGER,OFUNC_SOCKOPT,SOL_SOCKET, SO_LINGER };
122 #else /* !HAVE_STRUCT_LINGER */
123 const struct optdesc opt_so_linger = { "so-linger", "linger", OPT_SO_LINGER, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_LINGER };
124 #endif /* !HAVE_STRUCT_LINGER */
125 const struct optdesc opt_so_oobinline= { "so-oobinline", "oobinline", OPT_SO_OOBINLINE,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_OOBINLINE};
126 const struct optdesc opt_so_sndbuf = { "so-sndbuf", "sndbuf", OPT_SO_SNDBUF, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_SNDBUF};
127 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 };
128 const struct optdesc opt_so_rcvbuf = { "so-rcvbuf", "rcvbuf", OPT_SO_RCVBUF, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_RCVBUF};
129 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 };
130 const struct optdesc opt_so_error = { "so-error", "error", OPT_SO_ERROR, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_ERROR};
131 const struct optdesc opt_so_type = { "so-type", "type", OPT_SO_TYPE, GROUP_SOCKET, PH_SOCKET, TYPE_INT, OFUNC_SPEC, SOL_SOCKET, SO_TYPE };
132 const struct optdesc opt_so_dontroute= { "so-dontroute", "dontroute", OPT_SO_DONTROUTE,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_DONTROUTE };
133 #ifdef SO_RCVLOWAT
134 const struct optdesc opt_so_rcvlowat = { "so-rcvlowat", "rcvlowat", OPT_SO_RCVLOWAT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_RCVLOWAT };
135 #endif
136 #ifdef SO_RCVTIMEO
137 const struct optdesc opt_so_rcvtimeo = { "so-rcvtimeo", "rcvtimeo", OPT_SO_RCVTIMEO, GROUP_SOCKET, PH_PASTSOCKET, TYPE_TIMEVAL,OFUNC_SOCKOPT,SOL_SOCKET,SO_RCVTIMEO };
138 #endif
139 #ifdef SO_SNDLOWAT
140 const struct optdesc opt_so_sndlowat = { "so-sndlowat", "sndlowat", OPT_SO_SNDLOWAT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_SNDLOWAT };
141 #endif
142 #ifdef SO_SNDTIMEO
143 const struct optdesc opt_so_sndtimeo = { "so-sndtimeo", "sndtimeo", OPT_SO_SNDTIMEO, GROUP_SOCKET, PH_PASTSOCKET, TYPE_TIMEVAL,OFUNC_SOCKOPT,SOL_SOCKET,SO_SNDTIMEO };
144 #endif
145 /* end of setsockopt options of UNIX98 standard */
146  
147 #ifdef SO_AUDIT /* AIX 4.3.3 */
148 const struct optdesc opt_so_audit = { "so-audit", "audit", OPT_SO_AUDIT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_AUDIT };
149 #endif /* SO_AUDIT */
150 #ifdef SO_ATTACH_FILTER
151 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};
152 #endif
153 #ifdef SO_DETACH_FILTER
154 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};
155 #endif
156 #ifdef SO_BINDTODEVICE /* Linux: man 7 socket */
157 const struct optdesc opt_so_bindtodevice={"so-bindtodevice","if",OPT_SO_BINDTODEVICE,GROUP_SOCKET,PH_PASTSOCKET,TYPE_NAME,OFUNC_SOCKOPT,SOL_SOCKET,SO_BINDTODEVICE};
158 #endif
159 #ifdef SO_BSDCOMPAT
160 const struct optdesc opt_so_bsdcompat= { "so-bsdcompat","bsdcompat",OPT_SO_BSDCOMPAT,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_BSDCOMPAT };
161 #endif
162 #ifdef SO_CKSUMRECV
163 const struct optdesc opt_so_cksumrecv= { "so-cksumrecv","cksumrecv",OPT_SO_CKSUMRECV,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_CKSUMRECV };
164 #endif /* SO_CKSUMRECV */
165 #ifdef SO_TIMESTAMP
166 const struct optdesc opt_so_timestamp= { "so-timestamp","timestamp",OPT_SO_TIMESTAMP,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_TIMESTAMP };
167 #endif
168 #ifdef SO_KERNACCEPT /* AIX 4.3.3 */
169 const struct optdesc opt_so_kernaccept={ "so-kernaccept","kernaccept",OPT_SO_KERNACCEPT,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_KERNACCEPT};
170 #endif /* SO_KERNACCEPT */
171 #ifdef SO_NO_CHECK
172 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 };
173 #endif
174 #ifdef SO_NOREUSEADDR /* AIX 4.3.3 */
175 const struct optdesc opt_so_noreuseaddr={"so-noreuseaddr","noreuseaddr",OPT_SO_NOREUSEADDR,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET, SO_NOREUSEADDR};
176 #endif /* SO_NOREUSEADDR */
177 #ifdef SO_PASSCRED
178 const struct optdesc opt_so_passcred = { "so-passcred", "passcred", OPT_SO_PASSCRED, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_PASSCRED};
179 #endif
180 #ifdef SO_PEERCRED
181 const struct optdesc opt_so_peercred = { "so-peercred", "peercred", OPT_SO_PEERCRED, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT3,OFUNC_SOCKOPT, SOL_SOCKET, SO_PEERCRED};
182 #endif
183 #ifdef SO_PRIORITY
184 const struct optdesc opt_so_priority = { "so-priority", "priority", OPT_SO_PRIORITY, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_PRIORITY};
185 #endif
186 #ifdef SO_REUSEPORT /* AIX 4.3.3, BSD, HP-UX */
187 const struct optdesc opt_so_reuseport= { "so-reuseport","reuseport",OPT_SO_REUSEPORT,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_REUSEPORT };
188 #endif /* defined(SO_REUSEPORT) */
189 #ifdef SO_SECURITY_AUTHENTICATION
190 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};
191 #endif
192 #ifdef SO_SECURITY_ENCRYPTION_NETWORK
193 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};
194 #endif
195 #ifdef SO_SECURITY_ENCRYPTION_TRANSPORT
196 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};
197 #endif
198 #ifdef SO_USE_IFBUFS
199 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};
200 #endif /* SO_USE_IFBUFS */
201 #ifdef SO_USELOOPBACK /* AIX433, Solaris, HP-UX */
202 const struct optdesc opt_so_useloopback={"so-useloopback","useloopback",OPT_SO_USELOOPBACK,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT, SOL_SOCKET, SO_USELOOPBACK};
203 #endif /* SO_USELOOPBACK */
204 #ifdef SO_DGRAM_ERRIND /* Solaris */
205 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};
206 #endif /* SO_DGRAM_ERRIND */
207 #ifdef SO_DONTLINGER /* Solaris */
208 const struct optdesc opt_so_dontlinger = {"so-dontlinger", "dontlinger", OPT_SO_DONTLINGER, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_DONTLINGER };
209 #endif
210 /* the SO_PROTOTYPE is OS defined on Solaris, HP-UX; we lend this for a more
211 general purpose */
212 const struct optdesc opt_so_prototype = {"so-prototype", "prototype", OPT_SO_PROTOTYPE, GROUP_SOCKET,PH_SOCKET, TYPE_INT,OFUNC_SPEC, SOL_SOCKET,SO_PROTOTYPE };
213 #ifdef FIOSETOWN
214 const struct optdesc opt_fiosetown = { "fiosetown", NULL, OPT_FIOSETOWN, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_IOCTL, FIOSETOWN };
215 #endif
216 #ifdef SIOCSPGRP
217 const struct optdesc opt_siocspgrp = { "siocspgrp", NULL, OPT_SIOCSPGRP, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_IOCTL, SIOCSPGRP };
218 #endif
219 const struct optdesc opt_bind = { "bind", NULL, OPT_BIND, GROUP_SOCKET, PH_BIND, TYPE_STRING,OFUNC_SPEC };
220 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) };
221 const struct optdesc opt_protocol_family = { "protocol-family", "pf", OPT_PROTOCOL_FAMILY, GROUP_SOCKET, PH_PRESOCKET, TYPE_STRING, OFUNC_SPEC };
222 const struct optdesc opt_protocol = { "protocol", NULL, OPT_PROTOCOL, GROUP_SOCKET, PH_PRESOCKET, TYPE_STRING, OFUNC_SPEC };
223  
224 /* generic setsockopt() options */
225 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 };
226 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 };
227 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 };
228  
229 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) };
230  
231  
232 #if WITH_GENERICSOCKET
233  
234 static
235 int xioopen_socket_connect(int argc, const char *argv[], struct opt *opts,
236 int xioflags, xiofile_t *xxfd, unsigned groups,
237 int dummy1, int dummy2, int dummy3) {
238 struct single *xfd = &xxfd->stream;
239 int rw = (xioflags&XIO_ACCMODE);
240 const char *pfname = argv[1];
241 const char *protname = argv[2];
242 const char *address = argv[3];
243 char *garbage;
244 int pf;
245 int proto;
246 int socktype = SOCK_STREAM;
247 int needbind = 0;
248 union sockaddr_union them; socklen_t themlen; size_t themsize;
249 union sockaddr_union us; socklen_t uslen = sizeof(us);
250 int result;
251  
252 if (argc != 4) {
253 Error2("%s: wrong number of parameters (%d instead of 3)",
254 argv[0], argc-1);
255 return STAT_NORETRY;
256 }
257  
258 pf = strtoul(pfname, &garbage, 0);
259 if (*garbage != '\0') {
260 Warn1("garbage in parameter: \"%s\"", garbage);
261 }
262  
263 proto = strtoul(protname, &garbage, 0);
264 if (*garbage != '\0') {
265 Warn1("garbage in parameter: \"%s\"", garbage);
266 }
267  
268 retropt_socket_pf(opts, &pf);
269 retropt_int(opts, OPT_SO_TYPE, &socktype);
270 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
271  
272 if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
273 applyopts(-1, opts, PH_INIT);
274 applyopts(-1, opts, PH_EARLY);
275  
276 themsize = 0;
277 if ((result =
278 dalan(address, (char *)&them.soa.sa_data, &themsize, sizeof(them)))
279 < 0) {
280 Error1("data too long: \"%s\"", address);
281 } else if (result > 0) {
282 Error1("syntax error in \"%s\"", address);
283 }
284 them.soa.sa_family = pf;
285 themlen = themsize +
286 #if HAVE_STRUCT_SOCKADDR_SALEN
287 sizeof(them.soa.sa_len) +
288 #endif
289 sizeof(them.soa.sa_family);
290  
291 xfd->dtype = XIOREAD_STREAM|XIOWRITE_STREAM;
292  
293 socket_init(0, &us);
294 if (retropt_bind(opts, 0 /*pf*/, socktype, proto, (struct sockaddr *)&us, &uslen, 3,
295 0, 0)
296 != STAT_NOACTION) {
297 needbind = true;
298 us.soa.sa_family = pf;
299 }
300  
301 if ((result =
302 xioopen_connect(xfd,
303 needbind?(struct sockaddr *)&us:NULL, uslen,
304 (struct sockaddr *)&them, themlen,
305 opts, pf, socktype, proto, false)) != 0) {
306 return result;
307 }
308 if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
309 if (!XIOWITHRD(rw)) xfd->rfd = -1;
310 if ((result = _xio_openlate(xfd, opts)) < 0) {
311 return result;
312 }
313 return STAT_OK;
314 }
315  
316 #if WITH_LISTEN
317 static
318 int xioopen_socket_listen(int argc, const char *argv[], struct opt *opts,
319 int xioflags, xiofile_t *xxfd, unsigned groups,
320 int dummy1, int dummy2, int dummy3) {
321 struct single *xfd = &xxfd->stream;
322 const char *pfname = argv[1];
323 const char *protname = argv[2];
324 const char *usname = argv[3];
325 char *garbage;
326 int pf;
327 int proto;
328 int socktype = SOCK_STREAM;
329 union sockaddr_union us; socklen_t uslen; size_t ussize;
330 struct opt *opts0;
331 int result;
332  
333 if (argc != 4) {
334 Error2("%s: wrong number of parameters (%d instead of 3)",
335 argv[0], argc-1);
336 return STAT_NORETRY;
337 }
338  
339 pf = strtoul(pfname, &garbage, 0);
340 if (*garbage != '\0') {
341 Warn1("garbage in parameter: \"%s\"", garbage);
342 }
343  
344 proto = strtoul(protname, &garbage, 0);
345 if (*garbage != '\0') {
346 Warn1("garbage in parameter: \"%s\"", garbage);
347 }
348  
349 retropt_socket_pf(opts, &pf);
350 retropt_int(opts, OPT_SO_TYPE, &socktype);
351 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
352  
353 socket_init(0, &us);
354 ussize = 0;
355 if ((result =
356 dalan(usname, (char *)&us.soa.sa_data, &ussize, sizeof(us)))
357 < 0) {
358 Error1("data too long: \"%s\"", usname);
359 } else if (result > 0) {
360 Error1("syntax error in \"%s\"", usname);
361 }
362 uslen = ussize + sizeof(us.soa.sa_family)
363 #if HAVE_STRUCT_SOCKADDR_SALEN
364 + sizeof(us.soa.sa_len)
365 #endif
366 ;
367 us.soa.sa_family = pf;
368  
369 if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
370 applyopts(-1, opts, PH_INIT);
371 applyopts(-1, opts, PH_EARLY);
372  
373 opts0 = copyopts(opts, GROUP_ALL);
374  
375 if ((result =
376 xioopen_listen(xfd, xioflags,
377 (struct sockaddr *)&us, uslen,
378 opts, opts0, 0/*instead of pf*/, socktype, proto))
379 != STAT_OK)
380 return result;
381 return STAT_OK;
382 }
383 #endif /* WITH_LISTEN */
384  
385 /* we expect the form: ...:domain:type:protocol:remote-address */
386 static
387 int xioopen_socket_sendto(int argc, const char *argv[], struct opt *opts,
388 int xioflags, xiofile_t *xxfd, unsigned groups,
389 int dummy1, int dummy2, int dummy3) {
390 int rw = (xioflags&XIO_ACCMODE);
391 int result;
392  
393 if (argc != 5) {
394 Error2("%s: wrong number of parameters (%d instead of 4)",
395 argv[0], argc-1);
396 return STAT_NORETRY;
397 }
398 if ((result =
399 _xioopen_socket_sendto(argv[1], argv[2], argv[3], argv[4],
400 opts, xioflags, xxfd, groups))
401 != STAT_OK) {
402 return result;
403 }
404 _xio_openlate(&xxfd->stream, opts);
405 if (XIOWITHWR(rw)) xxfd->stream.wfd = xxfd->stream.rfd;
406 if (!XIOWITHRD(rw)) xxfd->stream.rfd = -1;
407  
408 return STAT_OK;
409 }
410  
411 /*
412 returns the resulting FD in xfd->rfd, independend of xioflags
413 */
414 static
415 int _xioopen_socket_sendto(const char *pfname, const char *type,
416 const char *protname, const char *address,
417 struct opt *opts, int xioflags, xiofile_t *xxfd,
418 unsigned groups) {
419 xiosingle_t *xfd = &xxfd->stream;
420 int rw = (xioflags&XIO_ACCMODE);
421 char *garbage;
422 union sockaddr_union us = {{0}};
423 socklen_t uslen = 0; size_t ussize;
424 size_t themsize;
425 int pf;
426 int socktype = SOCK_RAW;
427 int proto;
428 bool needbind = false;
429 char *bindstring = NULL;
430 int result;
431  
432 pf = strtoul(pfname, &garbage, 0);
433 if (*garbage != '\0') {
434 Warn1("garbage in parameter: \"%s\"", garbage);
435 }
436  
437 socktype = strtoul(type, &garbage, 0);
438 if (*garbage != '\0') {
439 Warn1("garbage in parameter: \"%s\"", garbage);
440 }
441  
442 proto = strtoul(protname, &garbage, 0);
443 if (*garbage != '\0') {
444 Warn1("garbage in parameter: \"%s\"", garbage);
445 }
446  
447 retropt_socket_pf(opts, &pf);
448 retropt_int(opts, OPT_SO_TYPE, &socktype);
449 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
450  
451 xfd->peersa.soa.sa_family = pf;
452 themsize = 0;
453 if ((result =
454 dalan(address, (char *)&xfd->peersa.soa.sa_data, &themsize,
455 sizeof(xfd->peersa)))
456 < 0) {
457 Error1("data too long: \"%s\"", address);
458 } else if (result > 0) {
459 Error1("syntax error in \"%s\"", address);
460 }
461 xfd->salen = themsize + sizeof(sa_family_t)
462 #if HAVE_STRUCT_SOCKADDR_SALEN
463 + sizeof(xfd->peersa.soa.sa_len)
464 #endif
465 ;
466 #if HAVE_STRUCT_SOCKADDR_SALEN
467 xfd->peersa.soa.sa_len =
468 sizeof(xfd->peersa.soa.sa_len) + sizeof(xfd->peersa.soa.sa_family) +
469 themsize;
470 #endif
471  
472 /* ...res_opts[] */
473 if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
474 applyopts(-1, opts, PH_INIT);
475  
476 if (pf == PF_UNSPEC) {
477 pf = xfd->peersa.soa.sa_family;
478 }
479  
480 xfd->dtype = XIODATA_RECVFROM;
481  
482 if (retropt_string(opts, OPT_BIND, &bindstring) == 0) {
483 ussize = 0;
484 if ((result =
485 dalan(bindstring, (char *)&us.soa.sa_data, &ussize, sizeof(us)))
486 < 0) {
487 Error1("data too long: \"%s\"", bindstring);
488 } else if (result > 0) {
489 Error1("syntax error in \"%s\"", bindstring);
490 }
491 us.soa.sa_family = pf;
492 uslen = ussize + sizeof(sa_family_t)
493 #if HAVE_STRUCT_SOCKADDR_SALEN
494 + sizeof(us.soa.sa_len)
495 #endif
496 ;
497 needbind = true;
498 }
499  
500 if ((result =
501 _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
502 opts, xioflags, xfd, groups, pf, socktype, proto))
503 != STAT_OK) {
504 return result;
505 }
506 if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd;
507 if (!XIOWITHRD(rw)) xfd->rfd = -1;
508 return STAT_OK;
509 }
510  
511  
512 /* we expect the form: ...:domain:socktype:protocol:local-address */
513 static
514 int xioopen_socket_recvfrom(int argc, const char *argv[], struct opt *opts,
515 int xioflags, xiofile_t *xxfd, unsigned groups,
516 int dummy, int summy2, int dummy3) {
517 struct single *xfd = &xxfd->stream;
518 const char *pfname = argv[1];
519 const char *typename = argv[2];
520 const char *protname = argv[3];
521 const char *address = argv[4];
522 char *garbage;
523 union sockaddr_union *us = &xfd->para.socket.la;
524 socklen_t uslen; size_t ussize;
525 int pf, socktype, proto;
526 char *rangename;
527 int result;
528  
529 if (argc != 5) {
530 Error2("%s: wrong number of parameters (%d instead of 4)",
531 argv[0], argc-1);
532 return STAT_NORETRY;
533 }
534  
535 pf = strtoul(pfname, &garbage, 0);
536 if (*garbage != '\0') {
537 Warn1("garbage in parameter: \"%s\"", garbage);
538 }
539  
540 socktype = strtoul(typename, &garbage, 0);
541 if (*garbage != '\0') {
542 Warn1("garbage in parameter: \"%s\"", garbage);
543 }
544  
545 proto = strtoul(protname, &garbage, 0);
546 if (*garbage != '\0') {
547 Warn1("garbage in parameter: \"%s\"", garbage);
548 }
549  
550 retropt_socket_pf(opts, &pf);
551 retropt_int(opts, OPT_SO_TYPE, &socktype);
552 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
553  
554 ussize = 0;
555 if ((result =
556 dalan(address, (char *)&us->soa.sa_data, &ussize, sizeof(*us)))
557 < 0) {
558 Error1("data too long: \"%s\"", address);
559 } else if (result > 0) {
560 Error1("syntax error in \"%s\"", address);
561 }
562 us->soa.sa_family = pf;
563 uslen = ussize + sizeof(us->soa.sa_family)
564 #if HAVE_STRUCT_SOCKADDR_SALEN
565 + sizeof(us->soa.sa_len);
566 #endif
567 ;
568 xfd->dtype = XIOREAD_RECV|XIOWRITE_SENDTO;
569  
570 if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
571 if (xioparserange(rangename, 0, &xfd->para.socket.range) < 0) {
572 return STAT_NORETRY;
573 }
574 xfd->para.socket.dorange = true;
575 free(rangename);
576 }
577  
578 if ((result =
579 _xioopen_dgram_recvfrom(xfd, xioflags, &us->soa, uslen,
580 opts, pf, socktype, proto, E_ERROR))
581 != STAT_OK) {
582 return result;
583 }
584 _xio_openlate(xfd, opts);
585 return STAT_OK;
586 }
587  
588 /* we expect the form: ...:domain:type:protocol:local-address */
589 static
590 int xioopen_socket_recv(int argc, const char *argv[], struct opt *opts,
591 int xioflags, xiofile_t *xxfd, unsigned groups,
592 int dummy1, int dummy2, int dummy3) {
593 struct single *xfd = &xxfd->stream;
594 const char *pfname = argv[1];
595 const char *typename = argv[2];
596 const char *protname = argv[3];
597 const char *address = argv[4];
598 char *garbage;
599 union sockaddr_union us;
600 socklen_t uslen; size_t ussize;
601 int pf, socktype, proto;
602 char *rangename;
603 int result;
604  
605 if (argc != 5) {
606 Error2("%s: wrong number of parameters (%d instead of 4)",
607 argv[0], argc-1);
608 return STAT_NORETRY;
609 }
610  
611 pf = strtoul(pfname, &garbage, 0);
612 if (*garbage != '\0') {
613 Warn1("garbage in parameter: \"%s\"", garbage);
614 }
615  
616 socktype = strtoul(typename, &garbage, 0);
617 if (*garbage != '\0') {
618 Warn1("garbage in parameter: \"%s\"", garbage);
619 }
620  
621 proto = strtoul(protname, &garbage, 0);
622 if (*garbage != '\0') {
623 Warn1("garbage in parameter: \"%s\"", garbage);
624 }
625  
626 retropt_socket_pf(opts, &pf);
627 retropt_int(opts, OPT_SO_TYPE, &socktype);
628 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
629  
630 ussize = 0;
631 if ((result =
632 dalan(address, (char *)&us.soa.sa_data, &ussize, sizeof(us)))
633 < 0) {
634 Error1("data too long: \"%s\"", address);
635 } else if (result > 0) {
636 Error1("syntax error in \"%s\"", address);
637 }
638 us.soa.sa_family = pf;
639 uslen = ussize + sizeof(sa_family_t)
640 #if HAVE_STRUCT_SOCKADDR_SALEN
641 +sizeof(us.soa.sa_len)
642 #endif
643 ;
644 xfd->dtype = XIOREAD_RECV;
645 xfd->para.socket.la.soa.sa_family = pf;
646  
647 if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
648 if (xioparserange(rangename, 0, &xfd->para.socket.range) < 0) {
649 return STAT_NORETRY;
650 }
651 xfd->para.socket.dorange = true;
652 free(rangename);
653 }
654  
655 if ((result =
656 _xioopen_dgram_recv(xfd, xioflags, &us.soa,
657 uslen, opts, pf, socktype, proto, E_ERROR))
658 != STAT_OK) {
659 return result;
660 }
661 _xio_openlate(xfd, opts);
662 return STAT_OK;
663 }
664  
665  
666 /* we expect the form: ...:domain:type:protocol:remote-address */
667 static
668 int xioopen_socket_datagram(int argc, const char *argv[], struct opt *opts,
669 int xioflags, xiofile_t *xxfd, unsigned groups,
670 int dummy1, int dummy2, int dummy3) {
671 xiosingle_t *xfd = &xxfd->stream;
672 const char *pfname = argv[1];
673 const char *typename = argv[2];
674 const char *protname = argv[3];
675 const char *address = argv[4];
676 char *garbage;
677 char *rangename;
678 size_t themsize;
679 int pf;
680 int result;
681  
682 if (argc != 5) {
683 Error2("%s: wrong number of parameters (%d instead of 4)",
684 argv[0], argc-1);
685 return STAT_NORETRY;
686 }
687  
688 pf = strtoul(pfname, &garbage, 0);
689 if (*garbage != '\0') {
690 Warn1("garbage in parameter: \"%s\"", garbage);
691 }
692  
693 retropt_socket_pf(opts, &pf);
694 /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
695  
696 xfd->peersa.soa.sa_family = pf;
697 themsize = 0;
698 if ((result =
699 dalan(address, (char *)&xfd->peersa.soa.sa_data, &themsize,
700 sizeof(xfd->peersa)))
701 < 0) {
702 Error1("data too long: \"%s\"", address);
703 } else if (result > 0) {
704 Error1("syntax error in \"%s\"", address);
705 }
706 xfd->salen = themsize + sizeof(sa_family_t);
707 #if HAVE_STRUCT_SOCKADDR_SALEN
708 xfd->peersa.soa.sa_len =
709 sizeof(xfd->peersa.soa.sa_len) + sizeof(xfd->peersa.soa.sa_family) +
710 themsize;
711 #endif
712  
713 if ((result =
714 _xioopen_socket_sendto(pfname, typename, protname, address,
715 opts, xioflags, xxfd, groups))
716 != STAT_OK) {
717 return result;
718 }
719  
720 xfd->dtype = XIOREAD_RECV|XIOWRITE_SENDTO;
721  
722 xfd->para.socket.la.soa.sa_family = xfd->peersa.soa.sa_family;
723  
724 /* which reply sockets will accept - determine by range option */
725 if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
726 if (xioparserange(rangename, 0, &xfd->para.socket.range) < 0) {
727 free(rangename);
728 return STAT_NORETRY;
729 }
730 xfd->para.socket.dorange = true;
731 xfd->dtype |= XIOREAD_RECV_CHECKRANGE;
732 free(rangename);
733 }
734  
735 _xio_openlate(xfd, opts);
736 return STAT_OK;
737 }
738  
739 #endif /* WITH_GENERICSOCKET */
740  
741  
742 /* a subroutine that is common to all socket addresses that want to connect
743 to a peer address.
744 might fork.
745 returns the resulting FD in xfd->rfd
746 applies and consumes the following options:
747 PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT,
748 PH_CONNECTED, PH_LATE,
749 OFUNC_OFFSET,
750 OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
751 returns 0 on success.
752 */
753 int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
754 struct sockaddr *them, size_t themlen,
755 struct opt *opts, int pf, int socktype, int protocol,
756 bool alt, int level) {
757 int fcntl_flags = 0;
758 char infobuff[256];
759 union sockaddr_union la;
760 socklen_t lalen = themlen;
761 int _errno;
762 int result;
763  
764 if ((xfd->rfd = xiosocket(opts, pf, socktype, protocol, level)) < 0) {
765 return STAT_RETRYLATER;
766 }
767  
768 applyopts_offset(xfd, opts);
769 applyopts(xfd->rfd, opts, PH_PASTSOCKET);
770 applyopts(xfd->rfd, opts, PH_FD);
771  
772 applyopts_cloexec(xfd->rfd, opts);
773  
774 applyopts(xfd->rfd, opts, PH_PREBIND);
775 applyopts(xfd->rfd, opts, PH_BIND);
776 #if WITH_TCP || WITH_UDP
777 if (alt) {
778 union sockaddr_union sin, *sinp;
779 unsigned short *port, i, N;
780 div_t dv;
781  
782 /* prepare sockaddr for bind probing */
783 if (us) {
784 sinp = (union sockaddr_union *)us;
785 } else {
786 if (them->sa_family == AF_INET) {
787 socket_in_init(&sin.ip4);
788 #if WITH_IP6
789 } else {
790 socket_in6_init(&sin.ip6);
791 #endif
792 }
793 sinp = &sin;
794 }
795 if (them->sa_family == AF_INET) {
796 port = &sin.ip4.sin_port;
797 #if WITH_IP6
798 } else if (them->sa_family == AF_INET6) {
799 port = &sin.ip6.sin6_port;
800 #endif
801 } else {
802 port = 0; /* just to make compiler happy */
803 }
804 /* combine random+step variant to quickly find a free port when only
805 few are in use, and certainly find a free port in defined time even
806 if there are almost all in use */
807 /* dirt 1: having tcp/udp code in socket function */
808 /* dirt 2: using a time related system call for init of random */
809 {
810 /* generate a random port, with millisecond random init */
811 #if 0
812 struct timeb tb;
813 ftime(&tb);
814 srandom(tb.time*1000+tb.millitm);
815 #else
816 struct timeval tv;
817 struct timezone tz;
818 tz.tz_minuteswest = 0;
819 tz.tz_dsttime = 0;
820 if ((result = Gettimeofday(&tv, &tz)) < 0) {
821 Warn2("gettimeofday(%p, {0,0}): %s", &tv, strerror(errno));
822 }
823 srandom(tv.tv_sec*1000000+tv.tv_usec);
824 #endif
825 }
826 dv = div(random(), IPPORT_RESERVED-XIO_IPPORT_LOWER);
827 i = N = XIO_IPPORT_LOWER + dv.rem;
828 do { /* loop over lowport bind() attempts */
829 *port = htons(i);
830 if (Bind(xfd->rfd, (struct sockaddr *)sinp, sizeof(*sinp)) < 0) {
831 Msg4(errno==EADDRINUSE?E_INFO:level,
832 "bind(%d, {%s}, "F_socklen"): %s", xfd->rfd,
833 sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)),
834 sizeof(*sinp), strerror(errno));
835 if (errno != EADDRINUSE) {
836 Close(xfd->rfd);
837 return STAT_RETRYLATER;
838 }
839 } else {
840 break; /* could bind to port, good, continue past loop */
841 }
842 --i; if (i < XIO_IPPORT_LOWER) i = IPPORT_RESERVED-1;
843 if (i == N) {
844 Msg(level, "no low port available");
845 /*errno = EADDRINUSE; still assigned */
846 Close(xfd->rfd);
847 return STAT_RETRYLATER;
848 }
849 } while (i != N);
850 } else
851 #endif /* WITH_TCP || WITH_UDP */
852  
853 if (us) {
854 if (Bind(xfd->rfd, us, uslen) < 0) {
855 Msg4(level, "bind(%d, {%s}, "F_socklen"): %s",
856 xfd->rfd, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)),
857 uslen, strerror(errno));
858 Close(xfd->rfd);
859 return STAT_RETRYLATER;
860 }
861 }
862  
863 applyopts(xfd->rfd, opts, PH_PASTBIND);
864  
865 applyopts(xfd->rfd, opts, PH_CONNECT);
866  
867 if (xfd->para.socket.connect_timeout.tv_sec != 0 ||
868 xfd->para.socket.connect_timeout.tv_usec != 0) {
869 fcntl_flags = Fcntl(xfd->rfd, F_GETFL);
870 Fcntl_l(xfd->rfd, F_SETFL, fcntl_flags|O_NONBLOCK);
871 }
872  
873 result = Connect(xfd->rfd, (struct sockaddr *)them, themlen);
874 _errno = errno;
875 la.soa.sa_family = them->sa_family; lalen = sizeof(la);
876 if (Getsockname(xfd->rfd, &la.soa, &lalen) < 0) {
877 Msg4(level-1, "getsockname(%d, %p, {%d}): %s",
878 xfd->rfd, &la.soa, lalen, strerror(errno));
879 }
880 errno = _errno;
881 if (result < 0) {
882 if (errno == EINPROGRESS) {
883 if (xfd->para.socket.connect_timeout.tv_sec != 0 ||
884 xfd->para.socket.connect_timeout.tv_usec != 0) {
885 struct timeval timeout;
886 struct pollfd writefd;
887 int result;
888  
889 Info4("connect(%d, %s, "F_Zd"): %s",
890 xfd->rfd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
891 themlen, strerror(errno));
892 timeout = xfd->para.socket.connect_timeout;
893 writefd.fd = xfd->rfd;
894 writefd.events = (POLLOUT|POLLERR);
895 result = xiopoll(&writefd, 1, &timeout);
896 if (result < 0) {
897 Msg4(level, "xiopoll({%d,POLLOUT|POLLER},,{"F_tv_sec"."F_tv_usec"): %s",
898 xfd->rfd, timeout.tv_sec, timeout.tv_usec, strerror(errno));
899 return STAT_RETRYLATER;
900 }
901 if (result == 0) {
902 Msg2(level, "connecting to %s: %s",
903 sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
904 strerror(ETIMEDOUT));
905 return STAT_RETRYLATER;
906 }
907 if (writefd.revents & POLLERR) {
908 #if 0
909 unsigned char dummy[1];
910 Read(xfd->rfd, &dummy, 1); /* get error message */
911 Msg2(level, "connecting to %s: %s",
912 sockaddr_info(them, infobuff, sizeof(infobuff)),
913 strerror(errno));
914 #else
915 Connect(xfd->rfd, them, themlen); /* get error message */
916 Msg4(level, "connect(%d, %s, "F_Zd"): %s",
917 xfd->rfd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
918 themlen, strerror(errno));
919 #endif
920 return STAT_RETRYLATER;
921 }
922 /* otherwise OK */
923 Fcntl_l(xfd->rfd, F_SETFL, fcntl_flags);
924 } else {
925 Warn4("connect(%d, %s, "F_Zd"): %s",
926 xfd->rfd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
927 themlen, strerror(errno));
928 }
929 } else if (pf == PF_UNIX && errno == EPROTOTYPE) {
930 /* this is for UNIX domain sockets: a connect attempt seems to be
931 the only way to distinguish stream and datagram sockets */
932 int _errno = errno;
933 Info4("connect(%d, %s, "F_Zd"): %s",
934 xfd->rfd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
935 themlen, strerror(errno));
936 #if 0
937 Info("assuming datagram socket");
938 xfd->dtype = DATA_RECVFROM;
939 xfd->salen = themlen;
940 memcpy(&xfd->peersa.soa, them, xfd->salen);
941 #endif
942 /*!!! and remove bind socket */
943 Close(xfd->rfd); xfd->rfd = -1;
944 errno = _errno;
945 return -1;
946 } else {
947 Msg4(level, "connect(%d, %s, "F_Zd"): %s",
948 xfd->rfd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
949 themlen, strerror(errno));
950 Close(xfd->rfd);
951 return STAT_RETRYLATER;
952 }
953 } else { /* result >= 0 */
954 Notice1("successfully connected from local address %s",
955 sockaddr_info(&la.soa, themlen, infobuff, sizeof(infobuff)));
956 }
957  
958 applyopts_fchown(xfd->rfd, opts); /* OPT_USER, OPT_GROUP */
959 applyopts(xfd->rfd, opts, PH_CONNECTED);
960 applyopts(xfd->rfd, opts, PH_LATE);
961  
962 return STAT_OK;
963 }
964  
965  
966 /* a subroutine that is common to all socket addresses that want to connect
967 to a peer address.
968 might fork.
969 applies and consumes the following option:
970 PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT,
971 PH_CONNECTED, PH_LATE,
972 OFUNC_OFFSET,
973 OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
974 returns the resulting FD in xfd->rfd, independend of xioflags
975 returns 0 on success.
976 */
977 int xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
978 struct sockaddr *them, size_t themlen,
979 struct opt *opts, int pf, int socktype, int protocol,
980 bool alt) {
981 bool dofork = false;
982 struct opt *opts0;
983 char infobuff[256];
984 int level;
985 int result;
986  
987 retropt_bool(opts, OPT_FORK, &dofork);
988  
989 opts0 = copyopts(opts, GROUP_ALL);
990  
991 Notice1("opening connection to %s",
992 sockaddr_info(them, themlen, infobuff, sizeof(infobuff)));
993  
994 do { /* loop over retries and forks */
995  
996 #if WITH_RETRY
997 if (xfd->forever || xfd->retry) {
998 level = E_INFO;
999 } else
1000 #endif /* WITH_RETRY */
1001 level = E_ERROR;
1002 result =
1003 _xioopen_connect(xfd, us, uslen, them, themlen, opts,
1004 pf, socktype, protocol, alt, level);
1005 switch (result) {
1006 case STAT_OK: break;
1007 #if WITH_RETRY
1008 case STAT_RETRYLATER:
1009 if (xfd->forever || xfd->retry) {
1010 --xfd->retry;
1011 if (result == STAT_RETRYLATER) {
1012 Nanosleep(&xfd->intervall, NULL);
1013 }
1014 dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
1015 continue;
1016 }
1017 return STAT_NORETRY;
1018 #endif /* WITH_RETRY */
1019 default:
1020 return result;
1021 }
1022  
1023 if (dofork) {
1024 xiosetchilddied(); /* set SIGCHLD handler */
1025 }
1026  
1027 #if WITH_RETRY
1028 if (dofork) {
1029 pid_t pid;
1030 int level = E_ERROR;
1031 if (xfd->forever || xfd->retry) {
1032 level = E_WARN; /* most users won't expect a problem here,
1033 so Notice is too weak */
1034 }
1035  
1036 while ((pid = xio_fork(false, level)) < 0) {
1037 --xfd->retry;
1038 if (xfd->forever || xfd->retry) {
1039 dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
1040 Nanosleep(&xfd->intervall, NULL); continue;
1041 }
1042 return STAT_RETRYLATER;
1043 }
1044  
1045 if (pid == 0) { /* child process */
1046 break;
1047 }
1048  
1049 /* parent process */
1050 Notice1("forked off child process "F_pid, pid);
1051 Close(xfd->rfd);
1052 /* with and without retry */
1053 Nanosleep(&xfd->intervall, NULL);
1054 dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
1055 continue; /* with next socket() bind() connect() */
1056 } else
1057 #endif /* WITH_RETRY */
1058 {
1059 break;
1060 }
1061 #if 0
1062 if ((result = _xio_openlate(fd, opts)) < 0)
1063 return result;
1064 #endif
1065 } while (true);
1066  
1067 return 0;
1068 }
1069  
1070  
1071 /* common to xioopen_udp_sendto, ..unix_sendto, ..rawip
1072 applies and consumes the following option:
1073 PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE
1074 OFUNC_OFFSET
1075 OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
1076 returns the resulting FD in xfd->rfd, independend of xioflags
1077 */
1078 int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
1079 union sockaddr_union *us, socklen_t uslen,
1080 struct opt *opts,
1081 int xioflags, xiosingle_t *xfd, unsigned groups,
1082 int pf, int socktype, int ipproto) {
1083 int level = E_ERROR;
1084 union sockaddr_union la; socklen_t lalen = sizeof(la);
1085 char infobuff[256];
1086  
1087 if ((xfd->rfd = xiosocket(opts, pf, socktype, ipproto, level)) < 0) {
1088 return STAT_RETRYLATER;
1089 }
1090  
1091 applyopts_offset(xfd, opts);
1092 applyopts_single(xfd, opts, PH_PASTSOCKET);
1093 applyopts(xfd->rfd, opts, PH_PASTSOCKET);
1094 applyopts(xfd->rfd, opts, PH_FD);
1095  
1096 applyopts_cloexec(xfd->rfd, opts);
1097  
1098 applyopts(xfd->rfd, opts, PH_PREBIND);
1099 applyopts(xfd->rfd, opts, PH_BIND);
1100  
1101 if (us) {
1102 if (Bind(xfd->rfd, (struct sockaddr *)us, uslen) < 0) {
1103 Msg4(level, "bind(%d, {%s}, "F_socklen"): %s",
1104 xfd->rfd, sockaddr_info((struct sockaddr *)us, uslen, infobuff, sizeof(infobuff)),
1105 uslen, strerror(errno));
1106 Close(xfd->rfd);
1107 return STAT_RETRYLATER;
1108 }
1109 }
1110  
1111 applyopts(xfd->rfd, opts, PH_PASTBIND);
1112  
1113 /*applyopts(xfd->rfd, opts, PH_CONNECT);*/
1114  
1115 if (Getsockname(xfd->rfd, &la.soa, &lalen) < 0) {
1116 Warn4("getsockname(%d, %p, {%d}): %s",
1117 xfd->rfd, &la.soa, lalen, strerror(errno));
1118 }
1119  
1120 applyopts_fchown(xfd->rfd, opts);
1121 applyopts(xfd->rfd, opts, PH_CONNECTED);
1122 applyopts(xfd->rfd, opts, PH_LATE);
1123  
1124 /* xfd->dtype = DATA_RECVFROM; *//* no, the caller must set this (ev _SKIPIP) */
1125 Notice1("successfully prepared local socket %s",
1126 sockaddr_info(&la.soa, lalen, infobuff, sizeof(infobuff)));
1127  
1128 return STAT_OK;
1129 }
1130  
1131  
1132 /* when the recvfrom address (with option fork) receives a packet it keeps this
1133 packet in the IP stacks input queue and forks a sub process. The sub process
1134 then reads this packet for processing its data.
1135 There is a problem because the parent process would find the same packet
1136 again if it calls select()/poll() before the child process reads the
1137 packet.
1138 To solve this problem we implement the following mechanism:
1139 The sub process sends a SIGUSR1 when it has read the packet (or a SIGCHLD if
1140 it dies before). The parent process waits until it receives that signal and
1141 only then continues to listen.
1142 To prevent a signal from another process to trigger our loop, we pass the
1143 pid of the sub process to the signal handler in xio_waitingfor. The signal
1144 handler sets xio_hashappened if the pid matched.
1145 */
1146 static pid_t xio_waitingfor; /* info from recv loop to signal handler:
1147 indicates the pid of the child process
1148 that should send us the USR1 signal */
1149 static bool xio_hashappened; /* info from signal handler to loop: child
1150 process has read ("consumed") the packet */
1151 /* this is the signal handler for USR1 and CHLD */
1152 void xiosigaction_hasread(int signum
1153 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
1154 , siginfo_t *siginfo, void *ucontext
1155 #endif
1156 ) {
1157 pid_t pid;
1158 int _errno;
1159 int status = 0;
1160 bool wassig = false;
1161  
1162 _errno = errno;
1163 diag_in_handler = 1;
1164 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
1165 Debug5("xiosigaction_hasread(%d, {%d,%d,%d,"F_pid"}, )",
1166 signum, siginfo->si_signo, siginfo->si_errno, siginfo->si_code,
1167 siginfo->si_pid);
1168 #else
1169 Debug1("xiosigaction_hasread(%d)", signum);
1170 #endif
1171 if (signum == SIGCHLD) {
1172 do {
1173 pid = Waitpid(-1, &status, WNOHANG);
1174 if (pid == 0) {
1175 Msg(wassig?E_INFO:E_WARN,
1176 "waitpid(-1, {}, WNOHANG): no child has exited");
1177 Info("xiosigaction_hasread() finished");
1178 Debug("xiosigaction_hasread() ->");
1179 diag_in_handler = 0;
1180 errno = _errno;
1181 return;
1182 } else if (pid < 0 && errno == ECHILD) {
1183 Msg(wassig?E_INFO:E_WARN,
1184 "waitpid(-1, {}, WNOHANG): "F_strerror);
1185 Info("xiosigaction_hasread() finished");
1186 Debug("xiosigaction_hasread() ->");
1187 diag_in_handler = 0;
1188 errno = _errno;
1189 return;
1190 }
1191 wassig = true;
1192 if (pid < 0) {
1193 Warn1("waitpid(-1, {%d}, WNOHANG): F_strerror", status);
1194 Info("xiosigaction_hasread() finished");
1195 Debug("xiosigaction_hasread() ->");
1196 diag_in_handler = 0;
1197 errno = _errno;
1198 return;
1199 }
1200 if (pid == xio_waitingfor) {
1201 xio_hashappened = true;
1202 Debug("xiosigaction_hasread() ->");
1203 diag_in_handler = 0;
1204 errno = _errno;
1205 return;
1206 }
1207 } while (1);
1208 }
1209 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
1210 if (xio_waitingfor == siginfo->si_pid) {
1211 xio_hashappened = true;
1212 }
1213 #else
1214 xio_hashappened = true;
1215 #endif
1216 #if !HAVE_SIGACTION
1217 Signal(sig, xiosigaction_hasread);
1218 #endif /* !HAVE_SIGACTION */
1219 Debug("xiosigaction_hasread() ->");
1220 diag_in_handler = 0;
1221 errno = _errno;
1222 return;
1223 }
1224  
1225  
1226 /* waits for incoming packet, checks its source address and port. Depending
1227 on fork option, it may fork a subprocess.
1228 Returns STAT_OK if a the packet was accepted; with fork option, this is already in
1229 a new subprocess!
1230 Other return values indicate a problem; this can happen in the master
1231 process or in a subprocess.
1232 This function does not retry. If you need retries, handle this is a
1233 loop in the calling function.
1234 after fork, we set the forever/retry of the child process to 0
1235 applies and consumes the following options:
1236 PH_INIT, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_EARLY, PH_PREOPEN, PH_FD,
1237 PH_CONNECTED, PH_LATE, PH_LATE2
1238 OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, cloexec, OPT_RANGE, tcpwrap
1239 */
1240 int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
1241 struct sockaddr *us, socklen_t uslen,
1242 struct opt *opts,
1243 int pf, int socktype, int proto, int level) {
1244 int rw = (xioflags&XIO_ACCMODE);
1245 int s;
1246 char *rangename;
1247 bool dofork = false;
1248 pid_t pid; /* mostly int; only used with fork */
1249 char infobuff[256];
1250 char lisname[256];
1251 bool drop = false; /* true if current packet must be dropped */
1252 int result;
1253  
1254 retropt_bool(opts, OPT_FORK, &dofork);
1255  
1256 if (dofork) {
1257 if (!(xioflags & XIO_MAYFORK)) {
1258 Error("option fork not allowed here");
1259 return STAT_NORETRY;
1260 }
1261 xfd->flags |= XIO_DOESFORK;
1262 }
1263  
1264 if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
1265  
1266 #if 1
1267 if (dofork) {
1268 #if HAVE_SIGACTION
1269 struct sigaction act;
1270 memset(&act, 0, sizeof(struct sigaction));
1271 act.sa_flags = SA_NOCLDSTOP/*|SA_RESTART*/
1272 #ifdef SA_NOMASK
1273 |SA_NOMASK
1274 #endif
1275 ;
1276 #if HAVE_SIGACTION
1277 act.sa_sigaction = childdied;
1278 #else
1279 act.sa_handler = childdied;
1280 #endif
1281 if (Sigaction(SIGCHLD, &act, NULL) < 0) {
1282 /*! man does not say that errno is defined */
1283 Warn2("sigaction(SIGCHLD, %p, NULL): %s", childdied, strerror(errno));
1284 }
1285 #else /* HAVE_SIGACTION */
1286 if (Signal(SIGCHLD, childdied) == SIG_ERR) {
1287 Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
1288 }
1289 #endif /* !HAVE_SIGACTION */
1290 }
1291 #endif /* 1 */
1292  
1293 if ((s = xiosocket(opts, pf, socktype, proto, level)) < 0) {
1294 return STAT_RETRYLATER;
1295 }
1296 if (XIOWITHRD(rw)) xfd->rfd = s;
1297 if (XIOWITHWR(rw)) xfd->wfd = s;
1298  
1299 applyopts_single(xfd, opts, PH_PASTSOCKET);
1300 applyopts(xfd->rfd, opts, PH_PASTSOCKET);
1301  
1302 applyopts_cloexec(xfd->rfd, opts);
1303  
1304 applyopts(xfd->rfd, opts, PH_PREBIND);
1305 applyopts(xfd->rfd, opts, PH_BIND);
1306 if ((us != NULL) && Bind(xfd->rfd, (struct sockaddr *)us, uslen) < 0) {
1307 Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->rfd,
1308 sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
1309 strerror(errno));
1310 Close(xfd->rfd);
1311 return STAT_RETRYLATER;
1312 }
1313  
1314 #if WITH_UNIX
1315 if (pf == AF_UNIX && us != NULL) {
1316 applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD);
1317 }
1318 #endif
1319  
1320 applyopts(xfd->rfd, opts, PH_PASTBIND);
1321 #if WITH_UNIX
1322 if (pf == AF_UNIX && us != NULL) {
1323 /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
1324 applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY);
1325 applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN);
1326 }
1327 #endif /* WITH_UNIX */
1328  
1329 /* for generic sockets, this has already been retrieved */
1330 if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
1331 if (xioparserange(rangename, pf, &xfd->para.socket.range)
1332 < 0) {
1333 free(rangename);
1334 return STAT_NORETRY;
1335 }
1336 free(rangename);
1337 xfd->para.socket.dorange = true;
1338 }
1339  
1340 #if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
1341 xio_retropt_tcpwrap(xfd, opts);
1342 #endif /* && (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
1343  
1344 if (xioopts.logopt == 'm') {
1345 Info("starting recvfrom loop, switching to syslog");
1346 diag_set('y', xioopts.syslogfac); xioopts.logopt = 'y';
1347 } else {
1348 Info("starting recvfrom loop");
1349 }
1350  
1351 if (dofork) {
1352 #if HAVE_SIGACTION
1353 {
1354 struct sigaction act;
1355 memset(&act, 0, sizeof(struct sigaction));
1356 act.sa_flags = SA_NOCLDSTOP|SA_RESTART
1357 #ifdef SA_SIGINFO /* not on Linux 2.0(.33) */
1358 |SA_SIGINFO
1359 #endif
1360 #ifdef SA_NOMASK
1361 |SA_NOMASK
1362 #endif
1363 ;
1364 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
1365 act.sa_sigaction = xiosigaction_hasread;
1366 #else /* Linux 2.0(.33) does not have sigaction.sa_sigaction */
1367 act.sa_handler = xiosigaction_hasread;
1368 #endif
1369 sigfillset(&act.sa_mask);
1370 if (Sigaction(SIGUSR1, &act, NULL) < 0) {
1371 /*! Linux man does not explicitely say that errno is defined */
1372 Warn1("sigaction(SIGUSR1, {&xiosigaction_subaddr_ok}, NULL): %s", strerror(errno));
1373 }
1374 if (Sigaction(SIGCHLD, &act, NULL) < 0) {
1375 /*! Linux man does not explicitely say that errno is defined */
1376 Warn1("sigaction(SIGCHLD, {&xiosigaction_subaddr_ok}, NULL): %s", strerror(errno));
1377 }
1378 }
1379 #else /* !HAVE_SIGACTION */
1380 /*!!!*/
1381 if (Signal(SIGUSR1, xiosigaction_hasread) == SIG_ERR) {
1382 Warn1("signal(SIGUSR1, xiosigaction_hasread): %s", strerror(errno));
1383 }
1384 if (Signal(SIGCHLD, xiosigaction_hasread) == SIG_ERR) {
1385 Warn1("signal(SIGCHLD, xiosigaction_hasread): %s", strerror(errno));
1386 }
1387 #endif /* !HAVE_SIGACTION */
1388 }
1389  
1390 while (true) { /* but we only loop if fork option is set */
1391 char peername[256];
1392 union sockaddr_union _peername;
1393 union sockaddr_union _sockname;
1394 union sockaddr_union *pa = &_peername; /* peer address */
1395 union sockaddr_union *la = &_sockname; /* local address */
1396 socklen_t palen = sizeof(_peername); /* peer address size */
1397 char ctrlbuff[1024]; /* ancillary messages */
1398 struct msghdr msgh = {0};
1399  
1400 socket_init(pf, pa);
1401  
1402 if (drop) {
1403 char *dummy[2];
1404  
1405 Recv(xfd->rfd, dummy, sizeof(dummy), 0);
1406 drop = true;
1407 }
1408  
1409 /* loop until select()/poll() returns valid */
1410 do {
1411 struct pollfd readfd;
1412 /*? int level = E_ERROR;*/
1413 if (us != NULL) {
1414 Notice1("receiving on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname)));
1415 } else {
1416 Notice1("receiving IP protocol %u", proto);
1417 }
1418 readfd.fd = xfd->rfd;
1419 readfd.events = POLLIN;
1420 if (xiopoll(&readfd, 1, NULL) > 0) {
1421 break;
1422 }
1423  
1424 if (errno == EINTR) {
1425 continue;
1426 }
1427  
1428 Msg2(level, "xiopoll({%d,,},,-1): %s", xfd->rfd, strerror(errno));
1429 Close(xfd->rfd);
1430 return STAT_RETRYLATER;
1431 } while (true);
1432  
1433 msgh.msg_name = pa;
1434 msgh.msg_namelen = palen;
1435 #if HAVE_STRUCT_MSGHDR_MSGCONTROL
1436 msgh.msg_control = ctrlbuff;
1437 #endif
1438 #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
1439 msgh.msg_controllen = sizeof(ctrlbuff);
1440 #endif
1441 if (xiogetpacketsrc(xfd->rfd, &msgh) < 0) {
1442 return STAT_RETRYLATER;
1443 }
1444 palen = msgh.msg_namelen;
1445  
1446 Notice1("receiving packet from %s"/*"src"*/,
1447 sockaddr_info((struct sockaddr *)pa, palen, peername, sizeof(peername))/*,
1448 sockaddr_info(&la->soa, sockname, sizeof(sockname))*/);
1449  
1450 xiodopacketinfo(&msgh, true, true);
1451  
1452 if (xiocheckpeer(xfd, pa, la) < 0) {
1453 /* drop packet */
1454 char buff[512];
1455 Recv(xfd->rfd, buff, sizeof(buff), 0);
1456 continue;
1457 }
1458 Info1("permitting packet from %s",
1459 sockaddr_info((struct sockaddr *)pa, palen,
1460 infobuff, sizeof(infobuff)));
1461  
1462 /* set the env vars describing the local and remote sockets */
1463 /*xiosetsockaddrenv("SOCK", la, lalen, proto);*/
1464 xiosetsockaddrenv("PEER", pa, palen, proto);
1465  
1466 applyopts(xfd->rfd, opts, PH_FD);
1467  
1468 applyopts(xfd->rfd, opts, PH_CONNECTED);
1469  
1470 xfd->peersa = *(union sockaddr_union *)pa;
1471 xfd->salen = palen;
1472  
1473 if (dofork) {
1474 sigset_t mask_sigchldusr1;
1475  
1476 /* we must prevent that the current packet triggers another fork;
1477 therefore we wait for a signal from the recent child: USR1
1478 indicates that is has consumed the last packet; CHLD means it has
1479 terminated */
1480 /* block SIGCHLD and SIGUSR1 until parent is ready to react */
1481 sigemptyset(&mask_sigchldusr1);
1482 sigaddset(&mask_sigchldusr1, SIGCHLD);
1483 sigaddset(&mask_sigchldusr1, SIGUSR1);
1484 Sigprocmask(SIG_BLOCK, &mask_sigchldusr1, NULL);
1485  
1486 if ((pid = xio_fork(false, level)) < 0) {
1487 Close(xfd->rfd);
1488 Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL);
1489 return STAT_RETRYLATER;
1490 }
1491  
1492 if (pid == 0) { /* child */
1493 /* no reason to block SIGCHLD in child process */
1494 Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL);
1495 xfd->ppid = Getppid(); /* send parent a signal when packet has
1496 been consumed */
1497  
1498 #if WITH_RETRY
1499 /* !? */
1500 xfd->retry = 0;
1501 xfd->forever = 0;
1502 level = E_ERROR;
1503 #endif /* WITH_RETRY */
1504  
1505 #if WITH_UNIX
1506 /* with UNIX sockets: only listening parent is allowed to remove
1507 the socket file */
1508 xfd->opt_unlink_close = false;
1509 #endif /* WITH_UNIX */
1510  
1511 break;
1512 }
1513  
1514 /* server: continue loop with listen */
1515 xio_waitingfor = pid;
1516 /* now we are ready to handle signals */
1517 Sigprocmask(SIG_UNBLOCK, &mask_sigchldusr1, NULL);
1518  
1519 while (!xio_hashappened) {
1520 Sleep(UINT_MAX); /* any signal lets us continue */
1521 }
1522 xio_waitingfor = 0; /* so this child will not set hashappened again */
1523 xio_hashappened = false;
1524  
1525 Info("continue listening");
1526 } else {
1527 break;
1528 }
1529 }
1530 if ((result = _xio_openlate(xfd, opts)) != 0)
1531 return STAT_NORETRY;
1532  
1533 return STAT_OK;
1534 }
1535  
1536  
1537 /* returns STAT_* */
1538 int _xioopen_dgram_recv(struct single *xfd, int xioflags,
1539 struct sockaddr *us, socklen_t uslen,
1540 struct opt *opts, int pf, int socktype, int proto,
1541 int level) {
1542 int rw = (xioflags&XIO_ACCMODE);
1543 int s;
1544 char *rangename;
1545 char infobuff[256];
1546  
1547 if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
1548  
1549 if ((s = xiosocket(opts, pf, socktype, proto, level)) < 0) {
1550 return STAT_RETRYLATER;
1551 }
1552 if (XIOWITHRD(rw)) xfd->rfd = s;
1553 if (XIOWITHWR(rw)) xfd->wfd = s;
1554  
1555 applyopts_single(xfd, opts, PH_PASTSOCKET);
1556 applyopts(xfd->rfd, opts, PH_PASTSOCKET);
1557  
1558 applyopts_cloexec(xfd->rfd, opts);
1559  
1560 applyopts(xfd->rfd, opts, PH_PREBIND);
1561 applyopts(xfd->rfd, opts, PH_BIND);
1562 if ((us != NULL) && Bind(xfd->rfd, (struct sockaddr *)us, uslen) < 0) {
1563 Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", xfd->rfd,
1564 sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
1565 strerror(errno));
1566 Close(xfd->rfd);
1567 return STAT_RETRYLATER;
1568 }
1569  
1570 #if WITH_UNIX
1571 if (pf == AF_UNIX && us != NULL) {
1572 applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD);
1573 }
1574 #endif
1575  
1576 applyopts(xfd->rfd, opts, PH_PASTBIND);
1577 #if WITH_UNIX
1578 if (pf == AF_UNIX && us != NULL) {
1579 /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
1580 applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY);
1581 applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN);
1582 }
1583 #endif /* WITH_UNIX */
1584  
1585 #if WITH_IP4 /*|| WITH_IP6*/
1586 if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
1587 if (xioparserange(rangename, pf, &xfd->para.socket.range)
1588 < 0) {
1589 free(rangename);
1590 return STAT_NORETRY;
1591 }
1592 free(rangename);
1593 xfd->para.socket.dorange = true;
1594 }
1595 #endif
1596  
1597 #if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
1598 xio_retropt_tcpwrap(xfd, opts);
1599 #endif /* && (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
1600  
1601 if (xioopts.logopt == 'm') {
1602 Info("starting recvfrom loop, switching to syslog");
1603 diag_set('y', xioopts.syslogfac); xioopts.logopt = 'y';
1604 } else {
1605 Info("starting recvfrom loop");
1606 }
1607  
1608 return STAT_OK;
1609 }
1610  
1611  
1612 int retropt_socket_pf(struct opt *opts, int *pf) {
1613 char *pfname;
1614  
1615 if (retropt_string(opts, OPT_PROTOCOL_FAMILY, &pfname) >= 0) {
1616 if (isdigit(pfname[0])) {
1617 *pf = strtoul(pfname, NULL /*!*/, 0);
1618 #if WITH_IP4
1619 } else if (!strcasecmp("inet", pfname) ||
1620 !strcasecmp("inet4", pfname) ||
1621 !strcasecmp("ip4", pfname) ||
1622 !strcasecmp("ipv4", pfname) ||
1623 !strcasecmp("2", pfname)) {
1624 *pf = PF_INET;
1625 #endif /* WITH_IP4 */
1626 #if WITH_IP6
1627 } else if (!strcasecmp("inet6", pfname) ||
1628 !strcasecmp("ip6", pfname) ||
1629 !strcasecmp("ipv6", pfname) ||
1630 !strcasecmp("10", pfname)) {
1631 *pf = PF_INET6;
1632 #endif /* WITH_IP6 */
1633 } else {
1634 Error1("unknown protocol family \"%s\"", pfname);
1635 /*! Warn("falling back to INET");*/
1636 }
1637 free(pfname);
1638 return 0;
1639 }
1640 return -1;
1641 }
1642  
1643  
1644 /* this function calls recvmsg(..., MSG_PEEK, ...) to obtain information about
1645 the arriving packet. in msgh the msg_name pointer must refer to an (empty)
1646 sockaddr storage. */
1647 int xiogetpacketsrc(int fd, struct msghdr *msgh) {
1648 char peekbuff[1];
1649 #if HAVE_STRUCT_IOVEC
1650 struct iovec iovec;
1651 #endif
1652  
1653 #if HAVE_STRUCT_IOVEC
1654 iovec.iov_base = peekbuff;
1655 iovec.iov_len = sizeof(peekbuff);
1656 msgh->msg_iov = &iovec;
1657 msgh->msg_iovlen = 1;
1658 #endif
1659 #if HAVE_STRUCT_MSGHDR_MSGFLAGS
1660 msgh->msg_flags = 0;
1661 #endif
1662 if (Recvmsg(fd, msgh, MSG_PEEK
1663 #ifdef MSG_TRUNC
1664 |MSG_TRUNC
1665 #endif
1666 ) < 0) {
1667 Warn1("recvmsg(): %s", strerror(errno));
1668 return STAT_RETRYLATER;
1669 }
1670 return STAT_OK;
1671 }
1672  
1673  
1674 /* works through the ancillary messages found in the given socket header record
1675 and logs the relevant information (E_DEBUG, E_INFO).
1676 calls protocol/layer specific functions for handling the messages
1677 creates appropriate environment vars if withenv is set */
1678 int xiodopacketinfo(struct msghdr *msgh, bool withlog, bool withenv) {
1679 #if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)
1680 struct cmsghdr *cmsg;
1681  
1682 /* parse ancillary messages */
1683 cmsg = CMSG_FIRSTHDR(msgh);
1684 while (cmsg != NULL) {
1685 int num = 0; /* number of data components of a ancill.msg */
1686 int i;
1687 char typbuff[16], *typp;
1688 char nambuff[128], *namp;
1689 char valbuff[256], *valp;
1690 char envbuff[256], *envp;
1691  
1692 if (withlog) {
1693 xiodump(CMSG_DATA(cmsg),
1694 cmsg->cmsg_len-((char *)CMSG_DATA(cmsg)-(char *)cmsg),
1695 valbuff, sizeof(valbuff)-1, 0);
1696 Debug4("ancillary message: len="F_cmsg_len", level=%d, type=%d, data=%s",
1697 cmsg->cmsg_len, cmsg->cmsg_level, cmsg->cmsg_type,
1698 valbuff);
1699 }
1700  
1701 /* try to get the anc.msg. contents in handy components, protocol/level
1702 dependent */
1703 switch (cmsg->cmsg_level) {
1704 case SOL_SOCKET:
1705 xiolog_ancillary_socket(cmsg, &num, typbuff, sizeof(typbuff)-1,
1706 nambuff, sizeof(nambuff)-1,
1707 envbuff, sizeof(envbuff)-1,
1708 valbuff, sizeof(valbuff)-1);
1709 break;
1710 #if WITH_IP4 || WITH_IP6
1711 case SOL_IP:
1712 xiolog_ancillary_ip(cmsg, &num, typbuff, sizeof(typbuff)-1,
1713 nambuff, sizeof(nambuff)-1,
1714 envbuff, sizeof(envbuff)-1,
1715 valbuff, sizeof(valbuff)-1);
1716 break;
1717 #endif /* WITH_IP4 || WITH_IP6 */
1718 #if WITH_IP6
1719 case SOL_IPV6:
1720 xiolog_ancillary_ip6(cmsg, &num, typbuff, sizeof(typbuff)-1,
1721 nambuff, sizeof(nambuff)-1,
1722 envbuff, sizeof(envbuff)-1,
1723 valbuff, sizeof(valbuff)-1);
1724 break;
1725 #endif /* WITH_IP6 */
1726 default:
1727 num = 1;
1728 snprintf(typbuff, sizeof(typbuff)-1, "LEVEL%u", cmsg->cmsg_level);
1729 snprintf(nambuff, sizeof(nambuff)-1, "type%u", cmsg->cmsg_type);
1730 xiodump(CMSG_DATA(cmsg),
1731 cmsg->cmsg_len-((char *)CMSG_DATA(cmsg)-(char *)cmsg),
1732 valbuff, sizeof(valbuff)-1, 0);
1733 }
1734 /* here the info is in typbuff (one string), nambuff (num consecutive
1735 strings), and valbuff (num consecutive strings) */
1736 i = 0;
1737 typp = typbuff; namp = nambuff; envp = envbuff; valp = valbuff;
1738 while (i < num) {
1739 if (withlog) {
1740 Info3("ancillary message: %s: %s=%s", typp, namp, valp);
1741 }
1742 if (withenv) {
1743 if (*envp) {
1744 xiosetenv(envp, valp, 1, NULL);
1745 } else if (!strcasecmp(typp+strlen(typp)-strlen(namp), namp)) {
1746 xiosetenv(typp, valp, 1, NULL);
1747 } else {
1748 xiosetenv2(typp, namp, valp, 1, NULL);
1749 }
1750 }
1751 if (++i == num) break;
1752 namp = strchr(namp, '\0')+1;
1753 envp = strchr(envp, '\0')+1;
1754 valp = strchr(valp, '\0')+1;
1755 }
1756 cmsg = CMSG_NXTHDR(msgh, cmsg);
1757 }
1758 return 0;
1759 #else /* !(defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)) */
1760 return -1;
1761 #endif /* !(defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)) */
1762 }
1763  
1764  
1765 /* check if peer address is within permitted range.
1766 return >= 0 if so. */
1767 int xiocheckrange(union sockaddr_union *sa, struct xiorange *range) {
1768 switch (sa->soa.sa_family) {
1769 #if WITH_IP4
1770 case PF_INET:
1771 return
1772 xiocheckrange_ip4(&sa->ip4, range);
1773 #endif /* WITH_IP4 */
1774 #if WITH_IP6
1775 case PF_INET6:
1776 return
1777 xiocheckrange_ip6(&sa->ip6, range);
1778 #endif /* WITH_IP6 */
1779 #if 0
1780 case PF_UNSPEC:
1781 {
1782 socklen_t i;
1783 for (i = 0; i < sizeof(sa->soa.sa_data); ++i) {
1784 if ((range->netmask.soa.sa_data[i] & sa->soa.sa_data[i]) != range->netaddr.soa.sa_data[i]) {
1785 return -1;
1786 }
1787 }
1788 return 0;
1789 }
1790 #endif
1791 }
1792 return -1;
1793 }
1794  
1795 int xiocheckpeer(xiosingle_t *xfd,
1796 union sockaddr_union *pa, union sockaddr_union *la) {
1797 char infobuff[256];
1798 int result;
1799  
1800 #if WITH_IP4
1801 if (xfd->para.socket.dorange) {
1802 if (pa == NULL) { return -1; }
1803 if (xiocheckrange(pa, &xfd->para.socket.range) < 0) {
1804 char infobuff[256];
1805 Warn1("refusing connection from %s due to range option",
1806 sockaddr_info((struct sockaddr *)pa, 0,
1807 infobuff, sizeof(infobuff)));
1808 return -1;
1809 }
1810 Info1("permitting connection from %s due to range option",
1811 sockaddr_info((struct sockaddr *)pa, 0,
1812 infobuff, sizeof(infobuff)));
1813 }
1814 #endif /* WITH_IP4 */
1815  
1816 #if WITH_TCP || WITH_UDP
1817 if (xfd->para.socket.ip.dosourceport) {
1818 if (pa == NULL) { return -1; }
1819 #if WITH_IP4
1820 if (pa->soa.sa_family == AF_INET &&
1821 ntohs(((struct sockaddr_in *)pa)->sin_port) != xfd->para.socket.ip.sourceport) {
1822 Warn1("refusing connection from %s due to wrong sourceport",
1823 sockaddr_info((struct sockaddr *)pa, 0,
1824 infobuff, sizeof(infobuff)));
1825 return -1;
1826 }
1827 #endif /* WITH_IP4 */
1828 #if WITH_IP6
1829 if (pa->soa.sa_family == AF_INET6 &&
1830 ntohs(((struct sockaddr_in6 *)pa)->sin6_port) != xfd->para.socket.ip.sourceport) {
1831 Warn1("refusing connection from %s due to wrong sourceport",
1832 sockaddr_info((struct sockaddr *)pa, 0,
1833 infobuff, sizeof(infobuff)));
1834 return -1;
1835 }
1836 #endif /* WITH_IP6 */
1837 Info1("permitting connection from %s due to sourceport option",
1838 sockaddr_info((struct sockaddr *)pa, 0,
1839 infobuff, sizeof(infobuff)));
1840 } else if (xfd->para.socket.ip.lowport) {
1841 if (pa == NULL) { return -1; }
1842 if (pa->soa.sa_family == AF_INET &&
1843 ntohs(((struct sockaddr_in *)pa)->sin_port) >= IPPORT_RESERVED) {
1844 Warn1("refusing connection from %s due to lowport option",
1845 sockaddr_info((struct sockaddr *)pa, 0,
1846 infobuff, sizeof(infobuff)));
1847 return -1;
1848 }
1849 #if WITH_IP6
1850 else if (pa->soa.sa_family == AF_INET6 &&
1851 ntohs(((struct sockaddr_in6 *)pa)->sin6_port) >=
1852 IPPORT_RESERVED) {
1853 Warn1("refusing connection from %s due to lowport option",
1854 sockaddr_info((struct sockaddr *)pa, 0,
1855 infobuff, sizeof(infobuff)));
1856 return -1;
1857 }
1858 #endif /* WITH_IP6 */
1859 Info1("permitting connection from %s due to lowport option",
1860 sockaddr_info((struct sockaddr *)pa, 0,
1861 infobuff, sizeof(infobuff)));
1862 }
1863 #endif /* WITH_TCP || WITH_UDP */
1864  
1865 #if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
1866 result = xio_tcpwrap_check(xfd, la, pa);
1867 if (result < 0) {
1868 char infobuff[256];
1869 Warn1("refusing connection from %s due to tcpwrapper option",
1870 sockaddr_info((struct sockaddr *)pa, 0,
1871 infobuff, sizeof(infobuff)));
1872 return -1;
1873 } else if (result > 0) {
1874 Info1("permitting connection from %s due to tcpwrapper option",
1875 sockaddr_info((struct sockaddr *)pa, 0,
1876 infobuff, sizeof(infobuff)));
1877 }
1878 #endif /* (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
1879  
1880 return 0; /* permitted */
1881 }
1882  
1883  
1884 #if HAVE_STRUCT_CMSGHDR
1885 /* converts the ancillary message in *cmsg into a form useable for further
1886 processing. knows the specifics of common message types.
1887 returns the number of resulting syntax elements in *num
1888 returns a sequence of \0 terminated type strings in *typbuff
1889 returns a sequence of \0 terminated name strings in *nambuff
1890 returns a sequence of \0 terminated value strings in *valbuff
1891 the respective len parameters specify the available space in the buffers
1892 returns STAT_OK or other STAT_*
1893 */
1894 static int
1895 xiolog_ancillary_socket(struct cmsghdr *cmsg, int *num,
1896 char *typbuff, int typlen,
1897 char *nambuff, int namlen,
1898 char *envbuff, int envlen,
1899 char *valbuff, int vallen) {
1900 const char *cmsgtype, *cmsgname, *cmsgenvn;
1901 size_t msglen;
1902 struct timeval *tv;
1903 int rc = STAT_OK;
1904  
1905 #if defined(CMSG_DATA)
1906  
1907 msglen = cmsg->cmsg_len-((char *)CMSG_DATA(cmsg)-(char *)cmsg);
1908 switch (cmsg->cmsg_type) {
1909 #ifdef SO_PASSCRED
1910 case SO_PASSCRED: /* this is really a UNIX/LOCAL message */
1911 /*! needs implementation */
1912 #endif /* SO_PASSCRED */
1913 #ifdef SO_RIGHTS
1914 case SO_RIGHTS: /* this is really a UNIX/LOCAL message */
1915 /*! needs implementation */
1916 #endif
1917 default: /* binary data */
1918 snprintf(typbuff, typlen, "SOCKET.%u", cmsg->cmsg_type);
1919 nambuff[0] = '\0'; strncat(nambuff, "data", namlen-1);
1920 xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
1921 return STAT_OK;
1922 #ifdef SO_TIMESTAMP
1923 # ifdef SCM_TIMESTAMP
1924 case SCM_TIMESTAMP:
1925 # else
1926 case SO_TIMESTAMP:
1927 # endif
1928 tv = (struct timeval *)CMSG_DATA(cmsg);
1929 cmsgtype =
1930 #ifdef SCM_TIMESTAMP
1931 "SCM_TIMESTAMP" /* FreeBSD */
1932 #else
1933 "SO_TIMESTAMP" /* Linux */
1934 #endif
1935 ;
1936 cmsgname = "timestamp";
1937 cmsgenvn = "TIMESTAMP";
1938 { time_t t = tv->tv_sec; ctime_r(&t, valbuff); }
1939 snprintf(strchr(valbuff, '\0')-1/*del \n*/, vallen-strlen(valbuff)+1, ", %06ld usecs", (long)tv->tv_usec);
1940 break;
1941 #endif /* defined(SO_TIMESTAMP) */
1942 ;
1943 }
1944 /* when we come here we provide a single parameter
1945 with type in cmsgtype, name in cmsgname,
1946 and value already in valbuff */
1947 *num = 1;
1948 if (strlen(cmsgtype) >= typlen) rc = STAT_WARNING;
1949 typbuff[0] = '\0'; strncat(typbuff, cmsgtype, typlen-1);
1950 if (strlen(cmsgname) >= namlen) rc = STAT_WARNING;
1951 nambuff[0] = '\0'; strncat(nambuff, cmsgname, namlen-1);
1952 if (strlen(cmsgenvn) >= envlen) rc = STAT_WARNING;
1953 envbuff[0] = '\0'; strncat(envbuff, cmsgenvn, envlen-1);
1954 return rc;
1955 #else /* !defined(CMSG_DATA) */
1956  
1957 return STAT_NORETRY;
1958  
1959 #endif /* !defined(CMSG_DATA) */
1960 }
1961 #endif /* HAVE_STRUCT_CMSGHDR */
1962  
1963  
1964 /* return the name of the interface with given index
1965 or NULL if is fails
1966 The system call requires an arbitrary socket; the calling program may
1967 provide one in parameter ins to avoid creation of a dummy socket. ins must
1968 be <0 if it does not specify a socket fd. */
1969 char *xiogetifname(int ind, char *val, int ins) {
1970 #if !HAVE_PROTOTYPE_LIB_if_indextoname
1971 int s;
1972 struct ifreq ifr;
1973  
1974 if (ins >= 0) {
1975 s = ins;
1976 } else {
1977 if ((s = Socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
1978 Error1("socket(PF_INET, SOCK_DGRAM, IPPROTO_IP): %s", strerror(errno));
1979 return NULL;
1980 }
1981 }
1982  
1983 #if HAVE_STRUCT_IFREQ_IFR_INDEX
1984 ifr.ifr_index = ind;
1985 #elif HAVE_STRUCT_IFREQ_IFR_IFINDEX
1986 ifr.ifr_ifindex = ind;
1987 #endif
1988 #ifdef SIOCGIFNAME
1989 if(Ioctl(s, SIOCGIFNAME, &ifr) < 0) {
1990 #if HAVE_STRUCT_IFREQ_IFR_INDEX
1991 Info3("ioctl(%d, SIOCGIFNAME, {..., ifr_index=%d, ...}: %s",
1992 s, ifr.ifr_index, strerror(errno));
1993 #elif HAVE_STRUCT_IFREQ_IFR_IFINDEX
1994 Info3("ioctl(%d, SIOCGIFNAME, {..., ifr_ifindex=%d, ...}: %s",
1995 s, ifr.ifr_ifindex, strerror(errno));
1996 #endif
1997 if (ins < 0) Close(s);
1998 return NULL;
1999 }
2000 #endif /* SIOCGIFNAME */
2001 if (ins < 0) Close(s);
2002 strcpy(val, ifr.ifr_name);
2003 return val;
2004 #else /* HAVE_PROTOTYPE_LIB_if_indextoname */
2005 return if_indextoname(ind, val);
2006 #endif /* HAVE_PROTOTYPE_LIB_if_indextoname */
2007 }
2008  
2009  
2010 /* parses a network specification consisting of an address and a mask. */
2011 int xioparsenetwork(const char *rangename, int pf, struct xiorange *range) {
2012 size_t addrlen = 0, masklen = 0;
2013 int result;
2014  
2015 switch (pf) {
2016 #if WITH_IP4
2017 case PF_INET:
2018 return xioparsenetwork_ip4(rangename, range);
2019 break;
2020 #endif /* WITH_IP4 */
2021 #if WITH_IP6
2022 case PF_INET6:
2023 return xioparsenetwork_ip6(rangename, range);
2024 break;
2025 #endif /* WITH_IP6 */
2026 case PF_UNSPEC:
2027 {
2028 char *addrname;
2029 const char *maskname;
2030 if ((maskname = strchr(rangename, ':')) == NULL) {
2031 Error1("syntax error in range \"%s\": use <addr>:<mask>", rangename);
2032 return STAT_NORETRY;
2033 }
2034 ++maskname; /* skip ':' */
2035 if ((addrname = Malloc(maskname-rangename)) == NULL) {
2036 return STAT_NORETRY;
2037 }
2038 strncpy(addrname, rangename, maskname-rangename-1); /* ok */
2039 addrname[maskname-rangename-1] = '\0';
2040 result =
2041 dalan(addrname, (char *)&range->netaddr.soa.sa_data, &addrlen,
2042 sizeof(range->netaddr)-(size_t)(&((struct sockaddr *)0)->sa_data)
2043 /* data length */);
2044 if (result < 0) {
2045 Error1("data too long: \"%s\"", addrname);
2046 free(addrname); return STAT_NORETRY;
2047 } else if (result > 0) {
2048 Error1("syntax error in \"%s\"", addrname);
2049 free(addrname); return STAT_NORETRY;
2050 }
2051 free(addrname);
2052 result =
2053 dalan(maskname, (char *)&range->netmask.soa.sa_data, &masklen,
2054 sizeof(range->netaddr)-(size_t)(&((struct sockaddr *)0)->sa_data)
2055 /* data length */);
2056 if (result < 0) {
2057 Error1("data too long: \"%s\"", maskname);
2058 return STAT_NORETRY;
2059 } else if (result > 0) {
2060 Error1("syntax error in \"%s\"", maskname);
2061 return STAT_NORETRY;
2062 }
2063 if (addrlen != masklen) {
2064 Error2("network address is "F_Zu" bytes long, mask is "F_Zu" bytes long",
2065 addrlen, masklen);
2066 /* recover by padding the shorter component with 0 */
2067 memset((char *)&range->netaddr.soa.sa_data+addrlen, 0,
2068 MAX(0, addrlen-masklen));
2069 memset((char *)&range->netmask.soa.sa_data+masklen, 0,
2070 MAX(0, masklen-addrlen));
2071 }
2072 }
2073 break;
2074 default:
2075 Error1("range option not supported with address family %d", pf);
2076 return STAT_NORETRY;
2077 }
2078 return STAT_OK;
2079 }
2080  
2081  
2082 /* parses a string of form address/bits or address:mask, and fills the fields
2083 of the range union. The addr component is masked with mask. */
2084 int xioparserange(const char *rangename, int pf, struct xiorange *range) {
2085 int i;
2086 if (xioparsenetwork(rangename, pf, range) < 0) {
2087 return -1;
2088 }
2089 /* we have parsed the address and mask; now we make sure that the stored
2090 address has 0 where mask is 0, to simplify comparisions */
2091 switch (pf) {
2092 #if WITH_IP4
2093 case PF_INET:
2094 range->netaddr.ip4.sin_addr.s_addr &= range->netmask.ip4.sin_addr.s_addr;
2095 break;
2096 #endif /* WITH_IP4 */
2097 #if WITH_IP6
2098 case PF_INET6:
2099 return xiorange_ip6andmask(range);
2100 break;
2101 #endif /* WITH_IP6 */
2102 case PF_UNSPEC:
2103 for (i = 0; i < sizeof(range->netaddr); ++i) {
2104 ((char *)&range->netaddr)[i] &= ((char *)&range->netmask)[i];
2105 }
2106 break;
2107 default:
2108 Error1("range option not supported with address family %d", pf);
2109 return STAT_NORETRY;
2110 }
2111 return 0;
2112 }
2113  
2114  
2115 /* set environment variables describing (part of) a socket address, e.g.
2116 SOCAT_SOCKADDR. lr (local/remote) specifies a string like "SOCK" or "PEER".
2117 proto should correspond to the third parameter of socket(2) and is used to
2118 determine the presence of port information. */
2119 int xiosetsockaddrenv(const char *lr,
2120 union sockaddr_union *sau, socklen_t salen,
2121 int proto) {
2122 # define XIOSOCKADDRENVLEN 256
2123 char namebuff[XIOSOCKADDRENVLEN];
2124 char valuebuff[XIOSOCKADDRENVLEN];
2125 int idx = 0, result;
2126  
2127 strcpy(namebuff, lr);
2128 switch (sau->soa.sa_family) {
2129 #if WITH_UNIX
2130 case PF_UNIX:
2131 result =
2132 xiosetsockaddrenv_unix(idx, strchr(namebuff, '\0'), XIOSOCKADDRENVLEN-strlen(lr),
2133 valuebuff, XIOSOCKADDRENVLEN,
2134 &sau->un, salen, proto);
2135 xiosetenv(namebuff, valuebuff, 1, NULL);
2136 break;
2137 #endif /* WITH_UNIX */
2138 #if WITH_IP4
2139 case PF_INET:
2140 do {
2141 result =
2142 xiosetsockaddrenv_ip4(idx, strchr(namebuff, '\0'), XIOSOCKADDRENVLEN-strlen(lr),
2143 valuebuff, XIOSOCKADDRENVLEN,
2144 &sau->ip4, proto);
2145 xiosetenv(namebuff, valuebuff, 1, NULL);
2146 namebuff[strlen(lr)] = '\0'; ++idx;
2147 } while (result > 0);
2148 break;
2149 #endif /* WITH_IP4 */
2150 #if WITH_IP6
2151 case PF_INET6:
2152 strcpy(namebuff, lr);
2153 do {
2154 result =
2155 xiosetsockaddrenv_ip6(idx, strchr(namebuff, '\0'), XIOSOCKADDRENVLEN-strlen(lr),
2156 valuebuff, XIOSOCKADDRENVLEN,
2157 &sau->ip6, proto);
2158 xiosetenv(namebuff, valuebuff, 1, NULL);
2159 namebuff[strlen(lr)] = '\0'; ++idx;
2160 } while (result > 0);
2161 break;
2162 #endif /* WITH_IP6 */
2163 #if LATER
2164 case PF_PACKET:
2165 result = xiosetsockaddrenv_packet(lr, (void *)sau, proto); break;
2166 #endif
2167 default:
2168 result = -1;
2169 break;
2170 }
2171 return result;
2172 # undef XIOSOCKADDRENVLEN
2173 }
2174  
2175 #endif /* _WITH_SOCKET */
2176  
2177 /* these do sockets internally */
2178  
2179 /* retrieves options so-type and so-prototype from opts, calls socket, and
2180 ev. generates an appropriate error message.
2181 returns 0 on success or -1 if an error occurred. */
2182 int
2183 xiosocket(struct opt *opts, int pf, int socktype, int proto, int msglevel) {
2184 int result;
2185  
2186 retropt_int(opts, OPT_SO_TYPE, &socktype);
2187 retropt_int(opts, OPT_SO_PROTOTYPE, &proto);
2188 result = Socket(pf, socktype, proto);
2189 if (result < 0) {
2190 Msg4(msglevel, "socket(%d, %d, %d): %s",
2191 pf, socktype, proto, strerror(errno));
2192 return -1;
2193 }
2194 return result;
2195 }
2196  
2197 /* retrieves options so-type and so-prototype from opts, calls socketpair, and
2198 ev. generates an appropriate error message.
2199 returns 0 on success or -1 if an error occurred. */
2200 int
2201 xiosocketpair(struct opt *opts, int pf, int socktype, int proto, int sv[2]) {
2202 int result;
2203  
2204 retropt_int(opts, OPT_SO_TYPE, &socktype);
2205 retropt_int(opts, OPT_SO_PROTOTYPE, &proto);
2206 result = xiosocketpair2(pf, socktype, proto, sv);
2207 return result;
2208 }