Version 1.8.0.0
[socat.git] / xioopen.c
blobbe17e3b62d402b17efaed223be11db0373826d5b
1 /* source: xioopen.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this is the source file of the extended open function */
7 #include "xiosysincludes.h"
9 #include "xioopen.h"
10 #include "xiomodes.h"
11 #include "xiohelp.h"
12 #include "nestlex.h"
14 static xiofile_t *xioallocfd(void);
16 static xiosingle_t *xioparse_single(const char **addr);
17 static xiofile_t *xioparse_dual(const char **addr);
18 static int xioopen_dual(xiofile_t *xfd, int xioflags);
20 const struct addrname addressnames[] = {
21 #if 1
22 #if WITH_STDIO
23 { "-", &xioaddr_stdio },
24 #endif
25 #if defined(WITH_UNIX) && defined(WITH_ABSTRACT_UNIXSOCKET)
26 { "ABSTRACT", &xioaddr_abstract_client },
27 { "ABSTRACT-CLIENT", &xioaddr_abstract_client },
28 { "ABSTRACT-CONNECT", &xioaddr_abstract_connect },
29 #if WITH_LISTEN
30 { "ABSTRACT-LISTEN", &xioaddr_abstract_listen },
31 #endif
32 { "ABSTRACT-RECV", &xioaddr_abstract_recv },
33 { "ABSTRACT-RECVFROM", &xioaddr_abstract_recvfrom },
34 { "ABSTRACT-SENDTO", &xioaddr_abstract_sendto },
35 #endif /* defined(WITH_UNIX) && defined(WITH_ABSTRACT_UNIXSOCKET) */
36 #if WITH_LISTEN && WITH_FDNUM
37 { "ACCEPT", &xioaddr_accept_fd },
38 { "ACCEPT-FD", &xioaddr_accept_fd },
39 #endif
40 #if WITH_CREAT
41 { "CREAT", &xioaddr_creat },
42 { "CREATE", &xioaddr_creat },
43 #endif
44 #if WITH_GENERICSOCKET
45 { "DATAGRAM", &xioaddr_socket_datagram },
46 #endif
47 #if (WITH_IP4 || WITH_IP6) && WITH_DCCP
48 { "DCCP", &xioaddr_dccp_connect },
49 { "DCCP-CONNECT", &xioaddr_dccp_connect },
50 #if WITH_LISTEN
51 { "DCCP-L", &xioaddr_dccp_listen },
52 { "DCCP-LISTEN", &xioaddr_dccp_listen },
53 #endif
54 #if WITH_IP4
55 { "DCCP4", &xioaddr_dccp4_connect },
56 { "DCCP4-CONNECT", &xioaddr_dccp4_connect },
57 #if WITH_LISTEN
58 { "DCCP4-L", &xioaddr_dccp4_listen },
59 { "DCCP4-LISTEN", &xioaddr_dccp4_listen },
60 #endif
61 #endif /* WITH_IP4 */
62 #if WITH_IP6
63 { "DCCP6", &xioaddr_dccp6_connect },
64 { "DCCP6-CONNECT", &xioaddr_dccp6_connect },
65 #if WITH_LISTEN
66 { "DCCP6-L", &xioaddr_dccp6_listen },
67 { "DCCP6-LISTEN", &xioaddr_dccp6_listen },
68 #endif
69 #endif /* WITH_IP6 */
70 #endif /* (WITH_IP4 || WITH_IP6) && WITH_DCCP */
71 #if WITH_GENERICSOCKET
72 { "DGRAM", &xioaddr_socket_datagram },
73 #endif
74 #if WITH_OPENSSL
75 { "DTLS", &xioaddr_openssl_dtls_client },
76 { "DTLS-C", &xioaddr_openssl_dtls_client },
77 { "DTLS-CLIENT", &xioaddr_openssl_dtls_client },
78 { "DTLS-CONNECT", &xioaddr_openssl_dtls_client },
79 #if WITH_LISTEN
80 { "DTLS-L", &xioaddr_openssl_dtls_server },
81 { "DTLS-LISTEN", &xioaddr_openssl_dtls_server },
82 { "DTLS-SERVER", &xioaddr_openssl_dtls_server },
83 #endif
84 #endif
85 #if WITH_PIPE
86 { "ECHO", &xioaddr_pipe },
87 #endif
88 #if WITH_EXEC
89 { "EXEC", &xioaddr_exec },
90 #endif
91 #if WITH_FDNUM
92 { "FD", &xioaddr_fd },
93 #endif
94 #if WITH_PIPE
95 { "FIFO", &xioaddr_pipe },
96 #endif
97 #if WITH_FILE
98 { "FILE", &xioaddr_open },
99 #endif
100 #if WITH_GOPEN
101 { "GOPEN", &xioaddr_gopen },
102 #endif
103 #if WITH_INTERFACE
104 { "IF", &xioaddr_interface },
105 #endif
106 #if (WITH_IP4 || WITH_IP6) && WITH_TCP
107 { "INET", &xioaddr_tcp_connect },
108 #endif
109 #if (WITH_IP4 || WITH_IP6) && WITH_TCP && WITH_LISTEN
110 { "INET-L", &xioaddr_tcp_listen },
111 { "INET-LISTEN", &xioaddr_tcp_listen },
112 #endif
113 #if WITH_IP4 && WITH_TCP
114 { "INET4", &xioaddr_tcp4_connect },
115 #endif
116 #if WITH_IP4 && WITH_TCP && WITH_LISTEN
117 { "INET4-L", &xioaddr_tcp4_listen },
118 { "INET4-LISTEN", &xioaddr_tcp4_listen },
119 #endif
120 #if WITH_IP6 && WITH_TCP
121 { "INET6", &xioaddr_tcp6_connect },
122 #endif
123 #if WITH_IP6 && WITH_TCP && WITH_LISTEN
124 { "INET6-L", &xioaddr_tcp6_listen },
125 { "INET6-LISTEN", &xioaddr_tcp6_listen },
126 #endif
127 #if WITH_INTERFACE
128 { "INTERFACE", &xioaddr_interface },
129 #endif
130 #if WITH_RAWIP
131 #if (WITH_IP4 || WITH_IP6)
132 { "IP", &xioaddr_rawip_sendto },
133 { "IP-DATAGRAM", &xioaddr_rawip_datagram },
134 { "IP-DGRAM", &xioaddr_rawip_datagram },
135 { "IP-RECV", &xioaddr_rawip_recv },
136 { "IP-RECVFROM", &xioaddr_rawip_recvfrom },
137 { "IP-SEND", &xioaddr_rawip_sendto },
138 { "IP-SENDTO", &xioaddr_rawip_sendto },
139 #endif
140 #if WITH_IP4
141 { "IP4", &xioaddr_rawip4_sendto },
142 { "IP4-DATAGRAM", &xioaddr_rawip4_datagram },
143 { "IP4-DGRAM", &xioaddr_rawip4_datagram },
144 { "IP4-RECV", &xioaddr_rawip4_recv },
145 { "IP4-RECVFROM", &xioaddr_rawip4_recvfrom },
146 { "IP4-SEND", &xioaddr_rawip4_sendto },
147 { "IP4-SENDTO", &xioaddr_rawip4_sendto },
148 #endif
149 #if WITH_IP6
150 { "IP6", &xioaddr_rawip6_sendto },
151 { "IP6-DATAGRAM", &xioaddr_rawip6_datagram },
152 { "IP6-DGRAM", &xioaddr_rawip6_datagram },
153 { "IP6-RECV", &xioaddr_rawip6_recv },
154 { "IP6-RECVFROM", &xioaddr_rawip6_recvfrom },
155 { "IP6-SEND", &xioaddr_rawip6_sendto },
156 { "IP6-SENDTO", &xioaddr_rawip6_sendto },
157 #endif
158 #endif /* WITH_RAWIP */
159 #if WITH_UNIX
160 { "LOCAL", &xioaddr_unix_connect },
161 #endif
162 #if WITH_FILE
163 { "OPEN", &xioaddr_open },
164 #endif
165 #if WITH_OPENSSL
166 { "OPENSSL", &xioaddr_openssl },
167 { "OPENSSL-CONNECT", &xioaddr_openssl },
168 { "OPENSSL-DTLS-CLIENT", &xioaddr_openssl_dtls_client },
169 { "OPENSSL-DTLS-CONNECT", &xioaddr_openssl_dtls_client },
170 #if WITH_LISTEN
171 { "OPENSSL-DTLS-LISTEN", &xioaddr_openssl_dtls_server },
172 { "OPENSSL-DTLS-SERVER", &xioaddr_openssl_dtls_server },
173 { "OPENSSL-LISTEN", &xioaddr_openssl_listen },
174 #endif
175 #endif
176 #if WITH_PIPE
177 { "PIPE", &xioaddr_pipe },
178 #endif
179 #if WITH_POSIXMQ
180 { "POSIXMQ-BIDIRECTIONAL", &xioaddr_posixmq_bidir },
181 { "POSIXMQ-READ", &xioaddr_posixmq_read },
182 { "POSIXMQ-RECEIVE", &xioaddr_posixmq_receive },
183 { "POSIXMQ-RECV", &xioaddr_posixmq_receive },
184 { "POSIXMQ-SEND", &xioaddr_posixmq_send },
185 #endif
186 #if WITH_PROXY
187 { "PROXY", &xioaddr_proxy_connect },
188 { "PROXY-CONNECT", &xioaddr_proxy_connect },
189 #endif
190 #if WITH_PTY
191 { "PTY", &xioaddr_pty },
192 #endif
193 #if WITH_READLINE
194 { "READLINE", &xioaddr_readline },
195 #endif
196 #if (WITH_IP4 || WITH_IP6) && WITH_SCTP
197 { "SCTP", &xioaddr_sctp_connect },
198 { "SCTP-CONNECT", &xioaddr_sctp_connect },
199 #if WITH_LISTEN
200 { "SCTP-L", &xioaddr_sctp_listen },
201 { "SCTP-LISTEN", &xioaddr_sctp_listen },
202 #endif
203 #if WITH_IP4
204 { "SCTP4", &xioaddr_sctp4_connect },
205 { "SCTP4-CONNECT", &xioaddr_sctp4_connect },
206 #if WITH_LISTEN
207 { "SCTP4-L", &xioaddr_sctp4_listen },
208 { "SCTP4-LISTEN", &xioaddr_sctp4_listen },
209 #endif
210 #endif /* WITH_IP4 */
211 #if WITH_IP6
212 { "SCTP6", &xioaddr_sctp6_connect },
213 { "SCTP6-CONNECT", &xioaddr_sctp6_connect },
214 #if WITH_LISTEN
215 { "SCTP6-L", &xioaddr_sctp6_listen },
216 { "SCTP6-LISTEN", &xioaddr_sctp6_listen },
217 #endif
218 #endif /* WITH_IP6 */
219 #endif /* (WITH_IP4 || WITH_IP6) && WITH_SCTP */
220 #if WITH_GENERICSOCKET
221 { "SENDTO", &xioaddr_socket_sendto },
222 #endif
223 #if WITH_SHELL
224 { "SHELL", &xioaddr_shell },
225 #endif
226 #if WITH_GENERICSOCKET
227 { "SOCKET-CONNECT", &xioaddr_socket_connect },
228 { "SOCKET-DATAGRAM", &xioaddr_socket_datagram },
229 #if WITH_LISTEN
230 { "SOCKET-LISTEN", &xioaddr_socket_listen },
231 #endif /* WITH_LISTEN */
232 { "SOCKET-RECV", &xioaddr_socket_recv },
233 { "SOCKET-RECVFROM", &xioaddr_socket_recvfrom },
234 { "SOCKET-SENDTO", &xioaddr_socket_sendto },
235 #endif
236 #if WITH_SOCKETPAIR
237 { "SOCKETPAIR", &xioaddr_socketpair },
238 #endif
239 #if WITH_SOCKS4
240 { "SOCKS", &xioaddr_socks4_connect },
241 { "SOCKS4", &xioaddr_socks4_connect },
242 #endif
243 #if WITH_SOCKS4A
244 { "SOCKS4A", &xioaddr_socks4a_connect },
245 #endif
246 #if WITH_SOCKS5
247 { "SOCKS5", &xioaddr_socks5_connect },
248 { "SOCKS5-BIND", &xioaddr_socks5_listen },
249 { "SOCKS5-CONNECT", &xioaddr_socks5_connect },
250 { "SOCKS5-LISTEN", &xioaddr_socks5_listen },
251 #endif
252 #if WITH_OPENSSL
253 { "SSL", &xioaddr_openssl },
254 #if WITH_LISTEN
255 { "SSL-L", &xioaddr_openssl_listen },
256 #endif
257 #endif
258 #if WITH_STDIO
259 { "STDERR", &xioaddr_stderr },
260 { "STDIN", &xioaddr_stdin },
261 { "STDIO", &xioaddr_stdio },
262 { "STDOUT", &xioaddr_stdout },
263 #endif
264 #if WITH_SYSTEM
265 { "SYSTEM", &xioaddr_system },
266 #endif
267 #if (WITH_IP4 || WITH_IP6) && WITH_TCP
268 { "TCP", &xioaddr_tcp_connect },
269 { "TCP-CONNECT", &xioaddr_tcp_connect },
270 #endif
271 #if (WITH_IP4 || WITH_IP6) && WITH_TCP && WITH_LISTEN
272 { "TCP-L", &xioaddr_tcp_listen },
273 { "TCP-LISTEN", &xioaddr_tcp_listen },
274 #endif
275 #if WITH_IP4 && WITH_TCP
276 { "TCP4", &xioaddr_tcp4_connect },
277 { "TCP4-CONNECT", &xioaddr_tcp4_connect },
278 #endif
279 #if WITH_IP4 && WITH_TCP && WITH_LISTEN
280 { "TCP4-L", &xioaddr_tcp4_listen },
281 { "TCP4-LISTEN", &xioaddr_tcp4_listen },
282 #endif
283 #if WITH_IP6 && WITH_TCP
284 { "TCP6", &xioaddr_tcp6_connect },
285 { "TCP6-CONNECT", &xioaddr_tcp6_connect },
286 #endif
287 #if WITH_IP6 && WITH_TCP && WITH_LISTEN
288 { "TCP6-L", &xioaddr_tcp6_listen },
289 { "TCP6-LISTEN", &xioaddr_tcp6_listen },
290 #endif
291 #if WITH_TUN
292 { "TUN", &xioaddr_tun },
293 #endif
294 #if (WITH_IP4 || WITH_IP6) && WITH_UDP
295 { "UDP", &xioaddr_udp_connect },
296 #endif
297 #if (WITH_IP4 || WITH_IP6) && WITH_UDP
298 { "UDP-CONNECT", &xioaddr_udp_connect },
299 { "UDP-DATAGRAM", &xioaddr_udp_datagram },
300 { "UDP-DGRAM", &xioaddr_udp_datagram },
301 #endif
302 #if (WITH_IP4 || WITH_IP6) && WITH_UDP && WITH_LISTEN
303 { "UDP-L", &xioaddr_udp_listen },
304 { "UDP-LISTEN", &xioaddr_udp_listen },
305 #endif
306 #if (WITH_IP4 || WITH_IP6) && WITH_UDP
307 { "UDP-RECV", &xioaddr_udp_recv },
308 { "UDP-RECVFROM", &xioaddr_udp_recvfrom },
309 { "UDP-SEND", &xioaddr_udp_sendto },
310 { "UDP-SENDTO", &xioaddr_udp_sendto },
311 #endif
312 #if WITH_IP4 && WITH_UDP
313 { "UDP4", &xioaddr_udp4_connect },
314 { "UDP4-CONNECT", &xioaddr_udp4_connect },
315 { "UDP4-DATAGRAM", &xioaddr_udp4_datagram },
316 { "UDP4-DGRAM", &xioaddr_udp4_datagram },
317 #endif
318 #if WITH_IP4 && WITH_UDP && WITH_LISTEN
319 { "UDP4-L", &xioaddr_udp4_listen },
320 { "UDP4-LISTEN", &xioaddr_udp4_listen },
321 #endif
322 #if WITH_IP4 && WITH_UDP
323 { "UDP4-RECV", &xioaddr_udp4_recv },
324 { "UDP4-RECVFROM", &xioaddr_udp4_recvfrom },
325 { "UDP4-SEND", &xioaddr_udp4_sendto },
326 { "UDP4-SENDTO", &xioaddr_udp4_sendto },
327 #endif
328 #if WITH_IP6 && WITH_UDP
329 { "UDP6", &xioaddr_udp6_connect },
330 { "UDP6-CONNECT", &xioaddr_udp6_connect },
331 { "UDP6-DATAGRAM", &xioaddr_udp6_datagram },
332 { "UDP6-DGRAM", &xioaddr_udp6_datagram },
333 #endif
334 #if WITH_IP6 && WITH_UDP && WITH_LISTEN
335 { "UDP6-L", &xioaddr_udp6_listen },
336 { "UDP6-LISTEN", &xioaddr_udp6_listen },
337 #endif
338 #if WITH_IP6 && WITH_UDP
339 { "UDP6-RECV", &xioaddr_udp6_recv },
340 { "UDP6-RECVFROM", &xioaddr_udp6_recvfrom },
341 { "UDP6-SEND", &xioaddr_udp6_sendto },
342 { "UDP6-SENDTO", &xioaddr_udp6_sendto },
343 #endif
344 #if (WITH_IP4 || WITH_IP6) && WITH_UDPLITE
345 { "UDPLITE", &xioaddr_udplite_connect },
346 { "UDPLITE-CONNECT", &xioaddr_udplite_connect },
347 { "UDPLITE-DATAGRAM", &xioaddr_udplite_datagram },
348 { "UDPLITE-DGRAM", &xioaddr_udplite_datagram },
349 #endif
350 #if (WITH_IP4 || WITH_IP6) && WITH_UDPLITE && WITH_LISTEN
351 { "UDPLITE-L", &xioaddr_udplite_listen },
352 { "UDPLITE-LISTEN", &xioaddr_udplite_listen },
353 #endif
354 #if (WITH_IP4 || WITH_IP6) && WITH_UDPLITE
355 { "UDPLITE-RECV", &xioaddr_udplite_recv },
356 { "UDPLITE-RECVFROM", &xioaddr_udplite_recvfrom },
357 { "UDPLITE-SEND", &xioaddr_udplite_sendto },
358 { "UDPLITE-SENDTO", &xioaddr_udplite_sendto },
359 #endif
360 #if WITH_IP4 && WITH_UDPLITE
361 { "UDPLITE4", &xioaddr_udplite4_connect },
362 { "UDPLITE4-CONNECT", &xioaddr_udplite4_connect },
363 { "UDPLITE4-DATAGRAM", &xioaddr_udplite4_datagram },
364 { "UDPLITE4-DGRAM", &xioaddr_udplite4_datagram },
365 #endif
366 #if WITH_IP4 && WITH_UDPLITE && WITH_LISTEN
367 { "UDPLITE4-L", &xioaddr_udplite4_listen },
368 { "UDPLITE4-LISTEN", &xioaddr_udplite4_listen },
369 #endif
370 #if WITH_IP4 && WITH_UDPLITE
371 { "UDPLITE4-RECV", &xioaddr_udplite4_recv },
372 { "UDPLITE4-RECVFROM", &xioaddr_udplite4_recvfrom },
373 { "UDPLITE4-SEND", &xioaddr_udplite4_sendto },
374 { "UDPLITE4-SENDTO", &xioaddr_udplite4_sendto },
375 #endif
376 #if WITH_IP6 && WITH_UDPLITE
377 { "UDPLITE6", &xioaddr_udplite6_connect },
378 { "UDPLITE6-CONNECT", &xioaddr_udplite6_connect },
379 { "UDPLITE6-DATAGRAM", &xioaddr_udplite6_datagram },
380 { "UDPLITE6-DGRAM", &xioaddr_udplite6_datagram },
381 #endif
382 #if WITH_IP6 && WITH_UDPLITE && WITH_LISTEN
383 { "UDPLITE6-L", &xioaddr_udplite6_listen },
384 { "UDPLITE6-LISTEN", &xioaddr_udplite6_listen },
385 #endif
386 #if WITH_IP6 && WITH_UDPLITE
387 { "UDPLITE6-RECV", &xioaddr_udplite6_recv },
388 { "UDPLITE6-RECVFROM", &xioaddr_udplite6_recvfrom },
389 { "UDPLITE6-SEND", &xioaddr_udplite6_sendto },
390 { "UDPLITE6-SENDTO", &xioaddr_udplite6_sendto },
391 #endif
392 #if WITH_UNIX
393 { "UNIX", &xioaddr_unix_client },
394 { "UNIX-CLIENT", &xioaddr_unix_client },
395 { "UNIX-CONNECT", &xioaddr_unix_connect },
396 #endif
397 #if WITH_UNIX && WITH_LISTEN
398 { "UNIX-L", &xioaddr_unix_listen },
399 { "UNIX-LISTEN", &xioaddr_unix_listen },
400 #endif
401 #if WITH_UNIX
402 { "UNIX-RECV", &xioaddr_unix_recv },
403 { "UNIX-RECVFROM", &xioaddr_unix_recvfrom },
404 { "UNIX-SEND", &xioaddr_unix_sendto },
405 { "UNIX-SENDTO", &xioaddr_unix_sendto },
406 #endif
407 #if WITH_VSOCK
408 { "VSOCK", &xioaddr_vsock_connect },
409 { "VSOCK-CONNECT", &xioaddr_vsock_connect },
410 #endif
411 #if WITH_VSOCK && WITH_LISTEN
412 { "VSOCK-L", &xioaddr_vsock_listen },
413 { "VSOCK-LISTEN", &xioaddr_vsock_listen },
414 #endif
415 #else /* !0 */
416 # if WITH_INTEGRATE
417 # include "xiointegrate.c"
418 # else
419 # include "xioaddrtab.c"
420 # endif
421 #endif /* !0 */
422 { NULL } /* end marker */
425 int xioopen_single(xiofile_t *xfd, int xioflags);
428 /* prepares a xiofile_t record for dual address type:
429 sets the tag and allocates memory for the substreams.
430 returns 0 on success, or <0 if an error occurred.
432 int xioopen_makedual(xiofile_t *file) {
433 file->tag = XIO_TAG_DUAL;
434 file->common.flags = XIO_RDWR;
435 if ((file->dual.stream[0] = (xiosingle_t *)xioallocfd()) == NULL)
436 return -1;
437 file->dual.stream[0]->flags = XIO_RDONLY;
438 if ((file->dual.stream[1] = (xiosingle_t *)xioallocfd()) == NULL)
439 return -1;
440 file->dual.stream[1]->flags = XIO_WRONLY;
441 return 0;
444 static xiofile_t *xioallocfd(void) {
445 xiofile_t *fd;
447 if ((fd = Calloc(1, sizeof(xiofile_t))) == NULL) {
448 return NULL;
450 /* some default values; 0's and NULL's need not be applied (calloc'ed) */
451 fd->common.tag = XIO_TAG_INVALID;
452 /* fd->common.addr = NULL; */
453 fd->common.flags = XIO_RDWR;
455 #if WITH_RETRY
456 /* fd->stream.retry = 0; */
457 /* fd->stream.forever = false; */
458 fd->stream.intervall.tv_sec = 1;
459 /* fd->stream.intervall.tv_nsec = 0; */
460 #endif /* WITH_RETRY */
461 /* fd->common.ignoreeof = false; */
462 /* fd->common.eof = 0; */
463 fd->stream.triggerfd = -1;
464 fd->stream.fd = -1;
465 fd->stream.dtype = XIODATA_STREAM;
466 #if _WITH_SOCKET
467 /* fd->stream.salen = 0; */
468 #endif /* _WITH_SOCKET */
469 fd->stream.howtoend = END_UNSPEC;
470 /* fd->stream.name = NULL; */
471 fd->stream.escape = -1;
472 /* fd->stream.para.exec.pid = 0; */
473 fd->stream.lineterm = LINETERM_RAW;
474 #if WITH_RESOLVE
475 #if HAVE_RES_RETRANS
476 fd->stream.para.socket.ip.res.retrans = -1;
477 #endif
478 #if HAVE_RES_RETRY
479 fd->stream.para.socket.ip.res.retry = -1;
480 #endif
481 #endif /* WITH_RESOLVE */
482 return fd;
486 /* parse the argument that specifies a two-directional data stream
487 and open the resulting address
489 xiofile_t *xioopen(const char *addr, /* address specification */
490 int xioflags) {
491 xiofile_t *xfd;
493 Debug1("xioopen(\"%s\")", addr);
495 if ((xfd = xioparse_dual(&addr)) == NULL) {
496 return NULL;
498 /*!! support n socks */
499 if (!sock[0]) {
500 sock[0] = xfd;
501 } else {
502 sock[1] = xfd;
504 if (xioopen_dual(xfd, xioflags) < 0) {
505 /*!!! free something? */
506 return NULL;
509 return xfd;
512 /* parse an address string that might contain !!
513 return NULL on error */
514 static xiofile_t *xioparse_dual(const char **addr) {
515 xiofile_t *xfd;
516 xiosingle_t *sfd1;
518 /* we parse a single address */
519 if ((sfd1 = xioparse_single(addr)) == NULL) {
520 return NULL;
523 /* and now we see if we reached a dual-address separator */
524 if (!strncmp(*addr, xioparms.pipesep, strlen(xioparms.pipesep))) {
525 /* yes we reached it, so we parse the second single address */
526 *addr += strlen(xioparms.pipesep);
528 if ((xfd = xioallocfd()) == NULL) {
529 free(sfd1); /*! and maybe have free some if its contents */
530 return NULL;
532 xfd->tag = XIO_TAG_DUAL;
533 xfd->dual.stream[0] = sfd1;
534 if ((xfd->dual.stream[1] = xioparse_single(addr)) == NULL) {
535 return NULL;
538 return xfd;
541 /* a truly single address */
542 xfd = (xiofile_t *)sfd1; sfd1 = NULL;
544 return xfd;
547 static int xioopen_dual(xiofile_t *xfd, int xioflags) {
549 if (xfd->tag == XIO_TAG_DUAL) {
550 /* a really dual address */
551 if ((xioflags&XIO_ACCMODE) != XIO_RDWR) {
552 Warn("unidirectional open of dual address");
554 if (((xioflags&XIO_ACCMODE)+1) & (XIO_RDONLY+1)) {
555 if (xioopen_single((xiofile_t *)xfd->dual.stream[0], XIO_RDONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC))
556 < 0) {
557 return -1;
560 if (((xioflags&XIO_ACCMODE)+1) & (XIO_WRONLY+1)) {
561 if (xioopen_single((xiofile_t *)xfd->dual.stream[1], XIO_WRONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC))
562 < 0) {
563 xioclose((xiofile_t *)xfd->dual.stream[0]);
564 return -1;
567 return 0;
570 return xioopen_single(xfd, xioflags);
574 static xiosingle_t *xioparse_single(const char **addr) {
575 const char *addr0 = *addr; /* save for error messages */
576 xiofile_t *xfd;
577 xiosingle_t *sfd;
578 struct addrname *ae;
579 const struct addrdesc *addrdesc = NULL;
580 const char *ends[4+1];
581 const char *hquotes[] = {
582 "'",
583 NULL
585 const char *squotes[] = {
586 "\"",
587 NULL
589 const char *nests[] = {
590 "'", "'",
591 "(", ")",
592 "[", "]",
593 "{", "}",
594 NULL
596 char token[512], *tokp;
597 size_t len;
598 int i;
599 int result;
601 /* init */
602 i = 0;
603 /*ends[i++] = xioparms.chainsep;*/ /* default: "|" */
604 ends[i++] = xioparms.pipesep; /* default: "!!" */
605 ends[i++] = ","/*xioparms.comma*/; /* default: "," */
606 ends[i++] = ":"/*xioparms.colon*/; /* default: ":" */
607 ends[i++] = NULL;
609 if ((xfd = xioallocfd()) == NULL) {
610 return NULL;
612 sfd = &xfd->stream;
613 sfd->argc = 0;
615 len = sizeof(token); tokp = token;
616 result = nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests,
617 true, true, false);
618 if (result < 0) {
619 Error2("keyword too long, in address \"%s%s\"", token, *addr);
620 } else if (result > 0){
621 Error1("unexpected end of address \"%s\"", *addr);
623 *tokp = '\0'; /*! len? */
624 ae = (struct addrname *)
625 keyw((struct wordent *)&addressnames, token,
626 sizeof(addressnames)/sizeof(struct addrname)-1);
628 if (ae) {
629 addrdesc = ae->desc;
630 /* keyword */
631 if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) {
632 Error1("strdup(\"%s\"): out of memory", token);
634 } else {
635 if (false) {
637 #if WITH_FDNUM
638 } else if (isdigit(token[0]&0xff) && token[1] == '\0') {
639 Info1("interpreting address \"%s\" as file descriptor", token);
640 addrdesc = &xioaddr_fd;
641 if ((sfd->argv[sfd->argc++] = strdup("FD")) == NULL) {
642 Error("strdup(\"FD\"): out of memory");
644 if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) {
645 Error1("strdup(\"%s\"): out of memory", token);
647 /*! check argc overflow */
648 #endif /* WITH_FDNUM */
649 #if WITH_GOPEN
650 } else if (strchr(token, '/')) {
651 Info1("interpreting address \"%s\" as file name", token);
652 addrdesc = &xioaddr_gopen;
653 if ((sfd->argv[sfd->argc++] = strdup("GOPEN")) == NULL) {
654 Error("strdup(\"GOPEN\"): out of memory");
656 if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) {
657 Error1("strdup(\"%s\"): out of memory", token);
659 /*! check argc overflow */
660 #endif /* WITH_GOPEN */
661 } else {
662 Error1("unknown device/address \"%s\"", token);
663 /*!!! free something*/ return NULL;
667 sfd->tag = XIO_TAG_RDWR;
668 sfd->addr = addrdesc;
670 while (!strncmp(*addr, xioparms.paramsep, strlen(xioparms.paramsep))) {
671 *addr += strlen(xioparms.paramsep);
672 len = sizeof(token); tokp = token;
673 result = nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests,
674 true, true, false);
675 if (result < 0) {
676 Error1("address \"%s\" too long", addr0);
677 } else if (result > 0){
678 Error1("unexpected end of address \"%s\"", addr0);
680 *tokp = '\0';
681 if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) {
682 Error1("strdup(\"%s\"): out of memory", token);
686 if (parseopts(addr, addrdesc->groups, &sfd->opts) < 0) {
687 free(xfd);
688 return NULL;
691 return sfd;
694 int xioopen_single(xiofile_t *xfd, int xioflags) {
695 struct single *sfd = &xfd->stream;
696 const struct addrdesc *addrdesc;
697 const char *modetext[4] = { "none", "read-only", "write-only", "read-write" } ;
698 /* Values to be saved until xioopen() is finished */
699 char *orig_dir = NULL;
700 bool have_umask = false;
701 mode_t orig_umask, tmp_umask;
702 int result;
703 /* Values to be saved until xioopen() is finished */
704 #if WITH_RESOLVE && HAVE_RESOLV_H
705 int do_res;
706 struct __res_state save_res;
707 #endif /* WITH_RESOLVE && HAVE_RESOLV_H */
708 #if WITH_NAMESPACES
709 int save_netfd = -1;
710 #endif
712 addrdesc = xfd->stream.addr;
713 if (((xioflags+1)&XIO_ACCMODE) & ~(addrdesc->directions)) {
714 Warn2("address is opened in %s mode but only supports %s", modetext[(xioflags+1)&XIO_ACCMODE], modetext[addrdesc->directions]);
716 if ((xioflags&XIO_ACCMODE) == XIO_RDONLY) {
717 xfd->tag = XIO_TAG_RDONLY;
718 } else if ((xioflags&XIO_ACCMODE) == XIO_WRONLY) {
719 xfd->tag = XIO_TAG_WRONLY;
720 } else if ((xioflags&XIO_ACCMODE) == XIO_RDWR) {
721 xfd->tag = XIO_TAG_RDWR;
722 } else {
723 Error1("invalid mode for address \"%s\"", xfd->stream.argv[0]);
725 xfd->stream.flags &= (~XIO_ACCMODE);
726 xfd->stream.flags |= (xioflags & XIO_ACCMODE);
728 /* Apply "temporary" process properties, save value for later restore */
730 if (applyopts_single(sfd, sfd->opts, PH_OFFSET) < 0)
731 return -1;
733 #if WITH_NAMESPACES
734 if ((save_netfd = xio_apply_namespace(sfd->opts)) < 0)
735 return -1;
736 #endif /* WITH_NAMESPACES */
738 #if WITH_RESOLVE && HAVE_RESOLV_H
739 if ((do_res = xio_res_init(sfd, &save_res)) < 0)
740 return STAT_NORETRY;
741 #endif /* WITH_RESOLVE && HAVE_RESOLV_H */
743 if (xio_chdir(sfd->opts, &orig_dir) < 0)
744 return STAT_NORETRY;
746 if (retropt_mode(xfd->stream.opts, OPT_UMASK, &tmp_umask) >= 0) {
747 Info1("changing umask to 0%3o", tmp_umask);
748 orig_umask = Umask(tmp_umask);
749 have_umask = true;
752 /* Call the specific xioopen function */
753 result = (*addrdesc->func)(xfd->stream.argc, xfd->stream.argv,
754 xfd->stream.opts, xioflags, xfd,
755 addrdesc);
757 /* Restore process properties */
758 if (have_umask) {
759 Info1("restoring umask to 0%3o", orig_umask);
760 Umask(orig_umask);
763 if (orig_dir != NULL) {
764 if (Chdir(orig_dir) < 0) {
765 Error2("chdir(\"%s\"): %s", orig_dir, strerror(errno));
766 free(orig_dir);
767 return STAT_NORETRY;
769 free(orig_dir);
772 #if WITH_RESOLVE && HAVE_RESOLV_H
773 if (do_res)
774 xio_res_restore(&save_res);
775 #endif /* WITH_RESOLVE && HAVE_RESOLV_H */
777 #if WITH_NAMESPACES
778 if (save_netfd > 0) {
779 xio_reset_namespace(save_netfd);
781 #endif /* WITH_NAMESPACES */
783 return result;
786 int xio_syntax(
787 const char *addr,
788 int expectnum,
789 int isnum,
790 const char *syntax)
792 return xiohelp_syntax(addr, expectnum, isnum, syntax);