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"
13 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
[] = {
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
},
30 { "abstract-listen", &xioaddr_abstract_listen
},
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) */
37 { "creat", &addr_creat
},
38 { "create", &addr_creat
},
40 #if WITH_GENERICSOCKET
41 { "datagram", &xioaddr_socket_datagram
},
42 { "dgram", &xioaddr_socket_datagram
},
45 { "echo", &addr_pipe
},
48 { "exec", &addr_exec
},
54 { "fifo", &addr_pipe
},
57 { "file", &addr_open
},
60 { "gopen", &addr_gopen
},
63 { "if", &xioaddr_interface
},
65 #if (WITH_IP4 || WITH_IP6) && WITH_TCP
66 { "inet", &addr_tcp_connect
},
68 #if (WITH_IP4 || WITH_IP6) && WITH_TCP && WITH_LISTEN
69 { "inet-l", &addr_tcp_listen
},
70 { "inet-listen", &addr_tcp_listen
},
72 #if WITH_IP4 && WITH_TCP
73 { "inet4", &addr_tcp4_connect
},
75 #if WITH_IP4 && WITH_TCP && WITH_LISTEN
76 { "inet4-l", &addr_tcp4_listen
},
77 { "inet4-listen", &addr_tcp4_listen
},
79 #if WITH_IP6 && WITH_TCP
80 { "inet6", &addr_tcp6_connect
},
82 #if WITH_IP6 && WITH_TCP && WITH_LISTEN
83 { "inet6-l", &addr_tcp6_listen
},
84 { "inet6-listen", &addr_tcp6_listen
},
87 { "interface", &xioaddr_interface
},
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
},
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
},
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
},
117 #endif /* WITH_RAWIP */
119 { "local", &xioaddr_unix_connect
},
122 { "open", &addr_open
},
125 { "openssl", &addr_openssl
},
126 { "openssl-connect", &addr_openssl
},
128 { "openssl-listen", &addr_openssl_listen
},
132 { "pipe", &addr_pipe
},
135 { "proxy", &addr_proxy_connect
},
136 { "proxy-connect", &addr_proxy_connect
},
139 { "pty", &addr_pty
},
142 { "readline", &addr_readline
},
144 #if (WITH_IP4 || WITH_IP6) && WITH_SCTP
145 { "sctp", &addr_sctp_connect
},
146 { "sctp-connect", &addr_sctp_connect
},
148 { "sctp-l", &addr_sctp_listen
},
149 { "sctp-listen", &addr_sctp_listen
},
152 { "sctp4", &addr_sctp4_connect
},
153 { "sctp4-connect", &addr_sctp4_connect
},
155 { "sctp4-l", &addr_sctp4_listen
},
156 { "sctp4-listen", &addr_sctp4_listen
},
158 #endif /* WITH_IP4 */
160 { "sctp6", &addr_sctp6_connect
},
161 { "sctp6-connect", &addr_sctp6_connect
},
163 { "sctp6-l", &addr_sctp6_listen
},
164 { "sctp6-listen", &addr_sctp6_listen
},
166 #endif /* WITH_IP6 */
167 #endif /* (WITH_IP4 || WITH_IP6) && WITH_SCTP */
168 #if WITH_GENERICSOCKET
169 { "sendto", &xioaddr_socket_sendto
},
171 #if WITH_GENERICSOCKET
172 { "socket-connect", &xioaddr_socket_connect
},
173 { "socket-datagram", &xioaddr_socket_datagram
},
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
},
182 { "socks", &addr_socks4_connect
},
183 { "socks4", &addr_socks4_connect
},
186 { "socks4a", &addr_socks4a_connect
},
189 { "ssl", &addr_openssl
},
191 { "ssl-l", &addr_openssl_listen
},
195 { "stderr", &addr_stderr
},
196 { "stdin", &addr_stdin
},
197 { "stdio", &addr_stdio
},
198 { "stdout", &addr_stdout
},
201 { "system", &addr_system
},
203 #if (WITH_IP4 || WITH_IP6) && WITH_TCP
204 { "tcp", &addr_tcp_connect
},
205 { "tcp-connect", &addr_tcp_connect
},
207 #if (WITH_IP4 || WITH_IP6) && WITH_TCP && WITH_LISTEN
208 { "tcp-l", &addr_tcp_listen
},
209 { "tcp-listen", &addr_tcp_listen
},
211 #if WITH_IP4 && WITH_TCP
212 { "tcp4", &addr_tcp4_connect
},
213 { "tcp4-connect", &addr_tcp4_connect
},
215 #if WITH_IP4 && WITH_TCP && WITH_LISTEN
216 { "tcp4-l", &addr_tcp4_listen
},
217 { "tcp4-listen", &addr_tcp4_listen
},
219 #if WITH_IP6 && WITH_TCP
220 { "tcp6", &addr_tcp6_connect
},
221 { "tcp6-connect", &addr_tcp6_connect
},
223 #if WITH_IP6 && WITH_TCP && WITH_LISTEN
224 { "tcp6-l", &addr_tcp6_listen
},
225 { "tcp6-listen", &addr_tcp6_listen
},
228 { "tun", &xioaddr_tun
},
230 #if (WITH_IP4 || WITH_IP6) && WITH_UDP
231 { "udp", &addr_udp_connect
},
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
},
238 #if (WITH_IP4 || WITH_IP6) && WITH_UDP && WITH_LISTEN
239 { "udp-l", &addr_udp_listen
},
240 { "udp-listen", &addr_udp_listen
},
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
},
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
},
254 #if WITH_IP4 && WITH_UDP && WITH_LISTEN
255 { "udp4-l", &addr_udp4_listen
},
256 { "udp4-listen", &addr_udp4_listen
},
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
},
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
},
270 #if WITH_IP6 && WITH_UDP && WITH_LISTEN
271 { "udp6-l", &addr_udp6_listen
},
272 { "udp6-listen", &addr_udp6_listen
},
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
},
281 { "unix", &xioaddr_unix_client
},
282 { "unix-client", &xioaddr_unix_client
},
283 { "unix-connect", &xioaddr_unix_connect
},
285 #if WITH_UNIX && WITH_LISTEN
286 { "unix-l", &xioaddr_unix_listen
},
287 { "unix-listen", &xioaddr_unix_listen
},
290 { "unix-recv", &xioaddr_unix_recv
},
291 { "unix-recvfrom", &xioaddr_unix_recvfrom
},
292 { "unix-send", &xioaddr_unix_sendto
},
293 { "unix-sendto", &xioaddr_unix_sendto
},
297 # include "xiointegrate.c"
299 # include "xioaddrtab.c"
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
)
317 file
->dual
.stream
[0]->flags
= XIO_RDONLY
;
318 if ((file
->dual
.stream
[1] = (xiosingle_t
*)xioallocfd()) == NULL
)
320 file
->dual
.stream
[1]->flags
= XIO_WRONLY
;
324 static xiofile_t
*xioallocfd(void) {
327 if ((fd
= Calloc(1, sizeof(xiofile_t
))) == 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
;
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; */
345 fd
->stream
.dtype
= XIODATA_STREAM
;
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
;
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 */
366 if (xioinitialize() < 0) {
370 if ((xfd
= xioparse_dual(&addr
)) == NULL
) {
373 /*!! support n socks */
379 if (xioopen_dual(xfd
, xioflags
) < 0) {
380 /*!!! free something? */
387 static xiofile_t
*xioparse_dual(const char **addr
) {
391 /* we parse a single address */
392 if ((sfd1
= xioparse_single(addr
)) == 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 */
405 xfd
->tag
= XIO_TAG_DUAL
;
406 xfd
->dual
.stream
[0] = sfd1
;
407 if ((xfd
->dual
.stream
[1] = xioparse_single(addr
)) == NULL
) {
414 /* a truly single address */
415 xfd
= (xiofile_t
*)sfd1
; sfd1
= NULL
;
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
))
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
))
436 xioclose((xiofile_t
*)xfd
->dual
.stream
[0]);
443 return xioopen_single(xfd
, xioflags
);
447 static xiosingle_t
*xioparse_single(const char **addr
) {
451 const struct addrdesc
*addrdesc
= NULL
;
452 const char *ends
[4+1];
453 const char *hquotes
[] = {
457 const char *squotes
[] = {
461 const char *nests
[] = {
468 char token
[512], *tokp
;
474 /*ends[i++] = xioopts.chainsep;*/ /* default: "|" */
475 ends
[i
++] = xioopts
.pipesep
; /* default: "!!" */
476 ends
[i
++] = ","/*xioopts.comma*/; /* default: "," */
477 ends
[i
++] = ":"/*xioopts.colon*/; /* default: ":" */
480 if ((xfd
= xioallocfd()) == NULL
) {
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);
499 if ((sfd
->argv
[sfd
->argc
++] = strdup(token
)) == NULL
) {
500 Error1("strdup(\"%s\"): out of memory", token
);
506 } else if (isdigit(token
[0]&0xff) && token
[1] == '\0') {
507 Info1("interpreting address \"%s\" as file descriptor", token
);
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 */
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 */
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
);
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) {
559 int xioopen_single(xiofile_t
*xfd
, int xioflags
) {
560 const struct addrdesc
*addrdesc
;
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
;
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
);