RES_AAONLY, RES_PRIMARY are deprecated
[socat.git] / xioopen.c
blobdbb65687ab33fc9823fe3c2826fc85f9cc4521f0
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 "nestlex.h"
13 static xiofile_t *xioallocfd(void);
15 xiosingle_t hugo;
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 { "-", &addr_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_CREAT
37 { "creat", &addr_creat },
38 { "create", &addr_creat },
39 #endif
40 #if WITH_GENERICSOCKET
41 { "datagram", &xioaddr_socket_datagram },
42 { "dgram", &xioaddr_socket_datagram },
43 #endif
44 #if WITH_PIPE
45 { "echo", &addr_pipe },
46 #endif
47 #if WITH_EXEC
48 { "exec", &addr_exec },
49 #endif
50 #if WITH_FDNUM
51 { "fd", &addr_fd },
52 #endif
53 #if WITH_PIPE
54 { "fifo", &addr_pipe },
55 #endif
56 #if WITH_FILE
57 { "file", &addr_open },
58 #endif
59 #if WITH_GOPEN
60 { "gopen", &addr_gopen },
61 #endif
62 #if WITH_INTERFACE
63 { "if", &xioaddr_interface },
64 #endif
65 #if (WITH_IP4 || WITH_IP6) && WITH_TCP
66 { "inet", &addr_tcp_connect },
67 #endif
68 #if (WITH_IP4 || WITH_IP6) && WITH_TCP && WITH_LISTEN
69 { "inet-l", &addr_tcp_listen },
70 { "inet-listen", &addr_tcp_listen },
71 #endif
72 #if WITH_IP4 && WITH_TCP
73 { "inet4", &addr_tcp4_connect },
74 #endif
75 #if WITH_IP4 && WITH_TCP && WITH_LISTEN
76 { "inet4-l", &addr_tcp4_listen },
77 { "inet4-listen", &addr_tcp4_listen },
78 #endif
79 #if WITH_IP6 && WITH_TCP
80 { "inet6", &addr_tcp6_connect },
81 #endif
82 #if WITH_IP6 && WITH_TCP && WITH_LISTEN
83 { "inet6-l", &addr_tcp6_listen },
84 { "inet6-listen", &addr_tcp6_listen },
85 #endif
86 #if WITH_INTERFACE
87 { "interface", &xioaddr_interface },
88 #endif
89 #if WITH_RAWIP
90 #if (WITH_IP4 || WITH_IP6)
91 { "ip", &addr_rawip_sendto },
92 { "ip-datagram", &addr_rawip_datagram },
93 { "ip-dgram", &addr_rawip_datagram },
94 { "ip-recv", &addr_rawip_recv },
95 { "ip-recvfrom", &addr_rawip_recvfrom },
96 { "ip-send", &addr_rawip_sendto },
97 { "ip-sendto", &addr_rawip_sendto },
98 #endif
99 #if WITH_IP4
100 { "ip4", &addr_rawip4_sendto },
101 { "ip4-datagram", &addr_rawip4_datagram },
102 { "ip4-dgram", &addr_rawip4_datagram },
103 { "ip4-recv", &addr_rawip4_recv },
104 { "ip4-recvfrom", &addr_rawip4_recvfrom },
105 { "ip4-send", &addr_rawip4_sendto },
106 { "ip4-sendto", &addr_rawip4_sendto },
107 #endif
108 #if WITH_IP6
109 { "ip6", &addr_rawip6_sendto },
110 { "ip6-datagram", &addr_rawip6_datagram },
111 { "ip6-dgram", &addr_rawip6_datagram },
112 { "ip6-recv", &addr_rawip6_recv },
113 { "ip6-recvfrom", &addr_rawip6_recvfrom },
114 { "ip6-send", &addr_rawip6_sendto },
115 { "ip6-sendto", &addr_rawip6_sendto },
116 #endif
117 #endif /* WITH_RAWIP */
118 #if WITH_UNIX
119 { "local", &xioaddr_unix_connect },
120 #endif
121 #if WITH_FILE
122 { "open", &addr_open },
123 #endif
124 #if WITH_OPENSSL
125 { "openssl", &addr_openssl },
126 { "openssl-connect", &addr_openssl },
127 #if WITH_LISTEN
128 { "openssl-listen", &addr_openssl_listen },
129 #endif
130 #endif
131 #if WITH_PIPE
132 { "pipe", &addr_pipe },
133 #endif
134 #if WITH_PROXY
135 { "proxy", &addr_proxy_connect },
136 { "proxy-connect", &addr_proxy_connect },
137 #endif
138 #if WITH_PTY
139 { "pty", &addr_pty },
140 #endif
141 #if WITH_READLINE
142 { "readline", &addr_readline },
143 #endif
144 #if (WITH_IP4 || WITH_IP6) && WITH_SCTP
145 { "sctp", &addr_sctp_connect },
146 { "sctp-connect", &addr_sctp_connect },
147 #if WITH_LISTEN
148 { "sctp-l", &addr_sctp_listen },
149 { "sctp-listen", &addr_sctp_listen },
150 #endif
151 #if WITH_IP4
152 { "sctp4", &addr_sctp4_connect },
153 { "sctp4-connect", &addr_sctp4_connect },
154 #if WITH_LISTEN
155 { "sctp4-l", &addr_sctp4_listen },
156 { "sctp4-listen", &addr_sctp4_listen },
157 #endif
158 #endif /* WITH_IP4 */
159 #if WITH_IP6
160 { "sctp6", &addr_sctp6_connect },
161 { "sctp6-connect", &addr_sctp6_connect },
162 #if WITH_LISTEN
163 { "sctp6-l", &addr_sctp6_listen },
164 { "sctp6-listen", &addr_sctp6_listen },
165 #endif
166 #endif /* WITH_IP6 */
167 #endif /* (WITH_IP4 || WITH_IP6) && WITH_SCTP */
168 #if WITH_GENERICSOCKET
169 { "sendto", &xioaddr_socket_sendto },
170 #endif
171 #if WITH_GENERICSOCKET
172 { "socket-connect", &xioaddr_socket_connect },
173 { "socket-datagram", &xioaddr_socket_datagram },
174 #if WITH_LISTEN
175 { "socket-listen", &xioaddr_socket_listen },
176 #endif /* WITH_LISTEN */
177 { "socket-recv", &xioaddr_socket_recv },
178 { "socket-recvfrom", &xioaddr_socket_recvfrom },
179 { "socket-sendto", &xioaddr_socket_sendto },
180 #endif
181 #if WITH_SOCKS4
182 { "socks", &addr_socks4_connect },
183 { "socks4", &addr_socks4_connect },
184 #endif
185 #if WITH_SOCKS4A
186 { "socks4a", &addr_socks4a_connect },
187 #endif
188 #if WITH_OPENSSL
189 { "ssl", &addr_openssl },
190 #if WITH_LISTEN
191 { "ssl-l", &addr_openssl_listen },
192 #endif
193 #endif
194 #if WITH_STDIO
195 { "stderr", &addr_stderr },
196 { "stdin", &addr_stdin },
197 { "stdio", &addr_stdio },
198 { "stdout", &addr_stdout },
199 #endif
200 #if WITH_SYSTEM
201 { "system", &addr_system },
202 #endif
203 #if (WITH_IP4 || WITH_IP6) && WITH_TCP
204 { "tcp", &addr_tcp_connect },
205 { "tcp-connect", &addr_tcp_connect },
206 #endif
207 #if (WITH_IP4 || WITH_IP6) && WITH_TCP && WITH_LISTEN
208 { "tcp-l", &addr_tcp_listen },
209 { "tcp-listen", &addr_tcp_listen },
210 #endif
211 #if WITH_IP4 && WITH_TCP
212 { "tcp4", &addr_tcp4_connect },
213 { "tcp4-connect", &addr_tcp4_connect },
214 #endif
215 #if WITH_IP4 && WITH_TCP && WITH_LISTEN
216 { "tcp4-l", &addr_tcp4_listen },
217 { "tcp4-listen", &addr_tcp4_listen },
218 #endif
219 #if WITH_IP6 && WITH_TCP
220 { "tcp6", &addr_tcp6_connect },
221 { "tcp6-connect", &addr_tcp6_connect },
222 #endif
223 #if WITH_IP6 && WITH_TCP && WITH_LISTEN
224 { "tcp6-l", &addr_tcp6_listen },
225 { "tcp6-listen", &addr_tcp6_listen },
226 #endif
227 #if WITH_TUN
228 { "tun", &xioaddr_tun },
229 #endif
230 #if (WITH_IP4 || WITH_IP6) && WITH_UDP
231 { "udp", &addr_udp_connect },
232 #endif
233 #if (WITH_IP4 || WITH_IP6) && WITH_UDP
234 { "udp-connect", &addr_udp_connect },
235 { "udp-datagram", &addr_udp_datagram },
236 { "udp-dgram", &addr_udp_datagram },
237 #endif
238 #if (WITH_IP4 || WITH_IP6) && WITH_UDP && WITH_LISTEN
239 { "udp-l", &addr_udp_listen },
240 { "udp-listen", &addr_udp_listen },
241 #endif
242 #if (WITH_IP4 || WITH_IP6) && WITH_UDP
243 { "udp-recv", &addr_udp_recv },
244 { "udp-recvfrom", &addr_udp_recvfrom },
245 { "udp-send", &addr_udp_sendto },
246 { "udp-sendto", &addr_udp_sendto },
247 #endif
248 #if WITH_IP4 && WITH_UDP
249 { "udp4", &addr_udp4_connect },
250 { "udp4-connect", &addr_udp4_connect },
251 { "udp4-datagram", &addr_udp4_datagram },
252 { "udp4-dgram", &addr_udp4_datagram },
253 #endif
254 #if WITH_IP4 && WITH_UDP && WITH_LISTEN
255 { "udp4-l", &addr_udp4_listen },
256 { "udp4-listen", &addr_udp4_listen },
257 #endif
258 #if WITH_IP4 && WITH_UDP
259 { "udp4-recv", &addr_udp4_recv },
260 { "udp4-recvfrom", &addr_udp4_recvfrom },
261 { "udp4-send", &addr_udp4_sendto },
262 { "udp4-sendto", &addr_udp4_sendto },
263 #endif
264 #if WITH_IP6 && WITH_UDP
265 { "udp6", &addr_udp6_connect },
266 { "udp6-connect", &addr_udp6_connect },
267 { "udp6-datagram", &addr_udp6_datagram },
268 { "udp6-dgram", &addr_udp6_datagram },
269 #endif
270 #if WITH_IP6 && WITH_UDP && WITH_LISTEN
271 { "udp6-l", &addr_udp6_listen },
272 { "udp6-listen", &addr_udp6_listen },
273 #endif
274 #if WITH_IP6 && WITH_UDP
275 { "udp6-recv", &addr_udp6_recv },
276 { "udp6-recvfrom", &addr_udp6_recvfrom },
277 { "udp6-send", &addr_udp6_sendto },
278 { "udp6-sendto", &addr_udp6_sendto },
279 #endif
280 #if WITH_UNIX
281 { "unix", &xioaddr_unix_client },
282 { "unix-client", &xioaddr_unix_client },
283 { "unix-connect", &xioaddr_unix_connect },
284 #endif
285 #if WITH_UNIX && WITH_LISTEN
286 { "unix-l", &xioaddr_unix_listen },
287 { "unix-listen", &xioaddr_unix_listen },
288 #endif
289 #if WITH_UNIX
290 { "unix-recv", &xioaddr_unix_recv },
291 { "unix-recvfrom", &xioaddr_unix_recvfrom },
292 { "unix-send", &xioaddr_unix_sendto },
293 { "unix-sendto", &xioaddr_unix_sendto },
294 #endif
295 #else /* !0 */
296 # if WITH_INTEGRATE
297 # include "xiointegrate.c"
298 # else
299 # include "xioaddrtab.c"
300 # endif
301 #endif /* !0 */
302 { NULL } /* end marker */
305 int xioopen_single(xiofile_t *xfd, int xioflags);
308 /* prepares a xiofile_t record for dual address type:
309 sets the tag and allocates memory for the substreams.
310 returns 0 on success, or <0 if an error occurred.
312 int xioopen_makedual(xiofile_t *file) {
313 file->tag = XIO_TAG_DUAL;
314 file->common.flags = XIO_RDWR;
315 if ((file->dual.stream[0] = (xiosingle_t *)xioallocfd()) == NULL)
316 return -1;
317 file->dual.stream[0]->flags = XIO_RDONLY;
318 if ((file->dual.stream[1] = (xiosingle_t *)xioallocfd()) == NULL)
319 return -1;
320 file->dual.stream[1]->flags = XIO_WRONLY;
321 return 0;
324 static xiofile_t *xioallocfd(void) {
325 xiofile_t *fd;
327 if ((fd = Calloc(1, sizeof(xiofile_t))) == NULL) {
328 return NULL;
330 /* some default values; 0's and NULL's need not be applied (calloc'ed) */
331 fd->common.tag = XIO_TAG_INVALID;
332 /* fd->common.addr = NULL; */
333 fd->common.flags = XIO_RDWR;
335 #if WITH_RETRY
336 /* fd->stream.retry = 0; */
337 /* fd->stream.forever = false; */
338 fd->stream.intervall.tv_sec = 1;
339 /* fd->stream.intervall.tv_nsec = 0; */
340 #endif /* WITH_RETRY */
341 /* fd->common.ignoreeof = false; */
342 /* fd->common.eof = 0; */
344 fd->stream.fd = -1;
345 fd->stream.dtype = XIODATA_STREAM;
346 #if _WITH_SOCKET
347 /* fd->stream.salen = 0; */
348 #endif /* _WITH_SOCKET */
349 fd->stream.howtoend = END_UNSPEC;
350 /* fd->stream.name = NULL; */
351 fd->stream.escape = -1;
352 /* fd->stream.para.exec.pid = 0; */
353 fd->stream.lineterm = LINETERM_RAW;
355 return fd;
359 /* parse the argument that specifies a two-directional data stream
360 and open the resulting address
362 xiofile_t *xioopen(const char *addr, /* address specification */
363 int xioflags) {
364 xiofile_t *xfd;
366 if (xioinitialize() < 0) {
367 return NULL;
370 if ((xfd = xioparse_dual(&addr)) == NULL) {
371 return NULL;
373 /*!! support n socks */
374 if (!sock[0]) {
375 sock[0] = xfd;
376 } else {
377 sock[1] = xfd;
379 if (xioopen_dual(xfd, xioflags) < 0) {
380 /*!!! free something? */
381 return NULL;
384 return xfd;
387 static xiofile_t *xioparse_dual(const char **addr) {
388 xiofile_t *xfd;
389 xiosingle_t *sfd1;
391 /* we parse a single address */
392 if ((sfd1 = xioparse_single(addr)) == NULL) {
393 return NULL;
396 /* and now we see if we reached a dual-address separator */
397 if (!strncmp(*addr, xioopts.pipesep, strlen(xioopts.pipesep))) {
398 /* yes we reached it, so we parse the second single address */
399 *addr += strlen(xioopts.pipesep);
401 if ((xfd = xioallocfd()) == NULL) {
402 free(sfd1); /*! and maybe have free some if its contents */
403 return NULL;
405 xfd->tag = XIO_TAG_DUAL;
406 xfd->dual.stream[0] = sfd1;
407 if ((xfd->dual.stream[1] = xioparse_single(addr)) == NULL) {
408 return NULL;
411 return xfd;
414 /* a truly single address */
415 xfd = (xiofile_t *)sfd1; sfd1 = NULL;
417 return xfd;
420 static int xioopen_dual(xiofile_t *xfd, int xioflags) {
422 if (xfd->tag == XIO_TAG_DUAL) {
423 /* a really dual address */
424 if ((xioflags&XIO_ACCMODE) != XIO_RDWR) {
425 Warn("unidirectional open of dual address");
427 if (((xioflags&XIO_ACCMODE)+1) & (XIO_RDONLY+1)) {
428 if (xioopen_single((xiofile_t *)xfd->dual.stream[0], XIO_RDONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC))
429 < 0) {
430 return -1;
433 if (((xioflags&XIO_ACCMODE)+1) & (XIO_WRONLY+1)) {
434 if (xioopen_single((xiofile_t *)xfd->dual.stream[1], XIO_WRONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC))
435 < 0) {
436 xioclose((xiofile_t *)xfd->dual.stream[0]);
437 return -1;
440 return 0;
443 return xioopen_single(xfd, xioflags);
447 static xiosingle_t *xioparse_single(const char **addr) {
448 xiofile_t *xfd;
449 xiosingle_t *sfd;
450 struct addrname *ae;
451 const struct addrdesc *addrdesc = NULL;
452 const char *ends[4+1];
453 const char *hquotes[] = {
454 "'",
455 NULL
457 const char *squotes[] = {
458 "\"",
459 NULL
461 const char *nests[] = {
462 "'", "'",
463 "(", ")",
464 "[", "]",
465 "{", "}",
466 NULL
468 char token[512], *tokp;
469 size_t len;
470 int i;
472 /* init */
473 i = 0;
474 /*ends[i++] = xioopts.chainsep;*/ /* default: "|" */
475 ends[i++] = xioopts.pipesep; /* default: "!!" */
476 ends[i++] = ","/*xioopts.comma*/; /* default: "," */
477 ends[i++] = ":"/*xioopts.colon*/; /* default: ":" */
478 ends[i++] = NULL;
480 if ((xfd = xioallocfd()) == NULL) {
481 return NULL;
483 sfd = &xfd->stream;
484 sfd->argc = 0;
486 len = sizeof(token); tokp = token;
487 if (nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests,
488 true, true, false) < 0) {
489 Error2("keyword too long, in address \"%s%s\"", token, *addr);
491 *tokp = '\0'; /*! len? */
492 ae = (struct addrname *)
493 keyw((struct wordent *)&addressnames, token,
494 sizeof(addressnames)/sizeof(struct addrname)-1);
496 if (ae) {
497 addrdesc = ae->desc;
498 /* keyword */
499 if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) {
500 Error1("strdup(\"%s\"): out of memory", token);
502 } else {
503 if (false) {
505 #if WITH_FDNUM
506 } else if (isdigit(token[0]&0xff) && token[1] == '\0') {
507 Info1("interpreting address \"%s\" as file descriptor", token);
508 addrdesc = &addr_fd;
509 if ((sfd->argv[sfd->argc++] = strdup("FD")) == NULL) {
510 Error("strdup(\"FD\"): out of memory");
512 if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) {
513 Error1("strdup(\"%s\"): out of memory", token);
515 /*! check argc overflow */
516 #endif /* WITH_FDNUM */
517 #if WITH_GOPEN
518 } else if (strchr(token, '/')) {
519 Info1("interpreting address \"%s\" as file name", token);
520 addrdesc = &addr_gopen;
521 if ((sfd->argv[sfd->argc++] = strdup("GOPEN")) == NULL) {
522 Error("strdup(\"GOPEN\"): out of memory");
524 if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) {
525 Error1("strdup(\"%s\"): out of memory", token);
527 /*! check argc overflow */
528 #endif /* WITH_GOPEN */
529 } else {
530 Error1("unknown device/address \"%s\"", token);
531 /*!!! free something*/ return NULL;
535 sfd->tag = XIO_TAG_RDWR;
536 sfd->addr = addrdesc;
538 while (!strncmp(*addr, xioopts.paramsep, strlen(xioopts.paramsep))) {
539 *addr += strlen(xioopts.paramsep);
540 len = sizeof(token); tokp = token;
541 if (nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests,
542 true, true, false) != 0) {
543 Error2("syntax error in address \"%s%s\"", token, *addr);
545 *tokp = '\0';
546 if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) {
547 Error1("strdup(\"%s\"): out of memory", token);
551 if (parseopts(addr, addrdesc->groups, &sfd->opts) < 0) {
552 free(xfd);
553 return NULL;
556 return sfd;
559 int xioopen_single(xiofile_t *xfd, int xioflags) {
560 const struct addrdesc *addrdesc;
561 int result;
563 if ((xioflags&XIO_ACCMODE) == XIO_RDONLY) {
564 xfd->tag = XIO_TAG_RDONLY;
565 } else if ((xioflags&XIO_ACCMODE) == XIO_WRONLY) {
566 xfd->tag = XIO_TAG_WRONLY;
567 } else if ((xioflags&XIO_ACCMODE) == XIO_RDWR) {
568 xfd->tag = XIO_TAG_RDWR;
569 } else {
570 Error1("invalid mode for address \"%s\"", xfd->stream.argv[0]);
572 xfd->stream.flags &= (~XIO_ACCMODE);
573 xfd->stream.flags |= (xioflags & XIO_ACCMODE);
574 addrdesc = xfd->stream.addr;
575 result = (*addrdesc->func)(xfd->stream.argc, xfd->stream.argv,
576 xfd->stream.opts, xioflags, xfd,
577 addrdesc->groups, addrdesc->arg1,
578 addrdesc->arg2, addrdesc->arg3);
579 return result;