nexmon – Blame information for rev 1
?pathlinks?
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 | } |