nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* source: xioopen.c */
2 /* Copyright Gerhard Rieger */
3 /* Published under the GNU General Public License V.2, see file COPYING */
4  
5 /* this is the source file of the extended open function */
6  
7 #include "xiosysincludes.h"
8  
9 #include "xioopen.h"
10 #include "xiomodes.h"
11 #include "nestlex.h"
12  
13 #include "xiosigchld.h"
14  
15 void *xioopenleftthenengine(void *thread_void);
16 static xiosingle_t *xioparse_single(const char **addr);
17  
18 static int
19 xioopen_inter_single(xiofile_t *xfd, int xioflags);
20 static int
21 xioopen_endpoint_single(xiofile_t *xfd, int xioflags);
22 static int
23 xioopen_unoverload(xiosingle_t *sfd,
24 int mayleft, /* what may be on left side: or'd
25 XIOBIT_RDWR, XIOBIT_RDONLY,
26 XIOBIT_WRONLY */
27 int *isleft, /* what the selected address desc
28 provides on left side: XIO_RDWR,
29 XIO_RDONLY, or XIO_WRONLY */
30 int mayright, /* what may be on right side: or'd
31 XIOBIT_RDWR, XIOBIT_RDONLY,
32 XIOBIT_WRONLY */
33 int *isright); /* what the selected address desc
34 provides on right side: XIO_RDWR,
35 XIO_RDONLY, or XIO_WRONLY */
36  
37  
38 const struct xioaddrname address_names[] = {
39 #if 1
40 #if WITH_STDIO
41 { "-", xioaddrs_stdio },
42 #endif
43 #if defined(WITH_UNIX) && defined(WITH_ABSTRACT_UNIXSOCKET)
44 { "abstract", xioaddrs_abstract_client },
45 { "abstract-client", xioaddrs_abstract_client },
46 { "abstract-connect", xioaddrs_abstract_connect },
47 #if WITH_LISTEN
48 { "abstract-listen", xioaddrs_abstract_listen },
49 #endif
50 { "abstract-recv", xioaddrs_abstract_recv },
51 { "abstract-recvfrom", xioaddrs_abstract_recvfrom },
52 { "abstract-sendto", xioaddrs_abstract_sendto },
53 #endif /* defined(WITH_UNIX) && defined(WITH_ABSTRACT_UNIXSOCKET) */
54 #if WITH_CREAT
55 { "creat", xioaddrs_creat },
56 { "create", xioaddrs_creat },
57 #endif
58 #if WITH_GENERICSOCKET
59 { "datagram", xioaddrs_socket_datagram },
60 { "dgram", xioaddrs_socket_datagram },
61 #endif
62 #if WITH_PIPE
63 { "echo", xioaddrs_pipe },
64 #endif
65 #if WITH_EXEC
66 { "exec", xioaddrs_exec },
67 { "exec1", xioaddrs_exec1 },
68 { "exec2", xioaddrs_exec },
69 #endif
70 #if WITH_FDNUM
71 { "fd", xioaddrs_fdnum },
72 #endif
73 #if WITH_PIPE
74 { "fifo", xioaddrs_pipe },
75 #endif
76 #if WITH_FILE
77 { "file", xioaddrs_open },
78 #endif
79 #if WITH_GOPEN
80 { "gopen", xioaddrs_gopen },
81 #endif
82 #if WITH_INTERFACE
83 { "if", xioaddrs_interface },
84 #endif
85 #if (WITH_IP4 || WITH_IP6) && WITH_TCP
86 { "inet", xioaddrs_tcp_connect },
87 #endif
88 #if (WITH_IP4 || WITH_IP6) && WITH_TCP && WITH_LISTEN
89 { "inet-l", xioaddrs_tcp_listen },
90 { "inet-listen", xioaddrs_tcp_listen },
91 #endif
92 #if WITH_IP4 && WITH_TCP
93 { "inet4", xioaddrs_tcp4_connect },
94 #endif
95 #if WITH_IP4 && WITH_TCP && WITH_LISTEN
96 { "inet4-l", xioaddrs_tcp4_listen },
97 { "inet4-listen", xioaddrs_tcp4_listen },
98 #endif
99 #if WITH_IP6 && WITH_TCP
100 { "inet6", xioaddrs_tcp6_connect },
101 #endif
102 #if WITH_IP6 && WITH_TCP && WITH_LISTEN
103 { "inet6-l", xioaddrs_tcp6_listen },
104 { "inet6-listen", xioaddrs_tcp6_listen },
105 #endif
106 #if WITH_INTERFACE
107 { "interface", xioaddrs_interface },
108 #endif
109 #if WITH_RAWIP
110 #if (WITH_IP4 || WITH_IP6)
111 { "ip", xioaddrs_rawip_sendto },
112 { "ip-datagram", xioaddrs_rawip_datagram },
113 { "ip-dgram", xioaddrs_rawip_datagram },
114 { "ip-recv", xioaddrs_rawip_recv },
115 { "ip-recvfrom", xioaddrs_rawip_recvfrom },
116 { "ip-send", xioaddrs_rawip_sendto },
117 { "ip-sendto", xioaddrs_rawip_sendto },
118 #endif
119 #if WITH_IP4
120 { "ip4", xioaddrs_rawip4_sendto },
121 { "ip4-datagram", xioaddrs_rawip4_datagram },
122 { "ip4-dgram", xioaddrs_rawip4_datagram },
123 { "ip4-recv", xioaddrs_rawip4_recv },
124 { "ip4-recvfrom", xioaddrs_rawip4_recvfrom },
125 { "ip4-send", xioaddrs_rawip4_sendto },
126 { "ip4-sendto", xioaddrs_rawip4_sendto },
127 #endif
128 #if WITH_IP6
129 { "ip6", xioaddrs_rawip6_sendto },
130 { "ip6-datagram", xioaddrs_rawip6_datagram },
131 { "ip6-dgram", xioaddrs_rawip6_datagram },
132 { "ip6-recv", xioaddrs_rawip6_recv },
133 { "ip6-recvfrom", xioaddrs_rawip6_recvfrom },
134 { "ip6-send", xioaddrs_rawip6_sendto },
135 { "ip6-sendto", xioaddrs_rawip6_sendto },
136 #endif
137 #endif /* WITH_RAWIP */
138 #if WITH_UNIX
139 { "local", xioaddrs_unix_connect },
140 #endif
141 #if WITH_NOP
142 { "nop", xioaddrs_nop },
143 #endif
144 #if WITH_FILE
145 { "open", xioaddrs_open },
146 #endif
147 #if WITH_OPENSSL
148 { "openssl", xioaddrs_openssl_connect },
149 { "openssl-client", xioaddrs_openssl_connect },
150 { "openssl-connect", xioaddrs_openssl_connect },
151 #if WITH_LISTEN
152 { "openssl-listen", xioaddrs_openssl_listen },
153 { "openssl-server", xioaddrs_openssl_listen },
154 #endif
155 #endif
156 #if WITH_PIPE
157 { "pipe", xioaddrs_pipe },
158 #endif
159 #if WITH_PROXY
160 { "proxy", xioaddrs_proxy_connect },
161 { "proxy-connect", xioaddrs_proxy_connect },
162 #endif
163 #if WITH_PTY
164 { "pty", xioaddrs_pty },
165 #endif
166 #if WITH_READLINE
167 { "readline", xioaddrs_readline },
168 #endif
169 #if (WITH_IP4 || WITH_IP6) && WITH_SCTP
170 { "sctp", xioaddrs_sctp_connect },
171 { "sctp-connect", xioaddrs_sctp_connect },
172 #if WITH_LISTEN
173 { "sctp-l", xioaddrs_sctp_listen },
174 { "sctp-listen", xioaddrs_sctp_listen },
175 #endif
176 #if WITH_IP4
177 { "sctp4", xioaddrs_sctp4_connect },
178 { "sctp4-connect", xioaddrs_sctp4_connect },
179 #if WITH_LISTEN
180 { "sctp4-l", xioaddrs_sctp4_listen },
181 { "sctp4-listen", xioaddrs_sctp4_listen },
182 #endif
183 #endif /* WITH_IP4 */
184 #if WITH_IP6
185 { "sctp6", xioaddrs_sctp6_connect },
186 { "sctp6-connect", xioaddrs_sctp6_connect },
187 #if WITH_LISTEN
188 { "sctp6-l", xioaddrs_sctp6_listen },
189 { "sctp6-listen", xioaddrs_sctp6_listen },
190 #endif
191 #endif /* WITH_IP6 */
192 #endif /* (WITH_IP4 || WITH_IP6) && WITH_SCTP */
193 #if WITH_GENERICSOCKET
194 { "sendto", xioaddrs_socket_sendto },
195 #endif
196 #if WITH_GENERICSOCKET
197 { "socket-connect", xioaddrs_socket_connect },
198 { "socket-datagram", xioaddrs_socket_datagram },
199 #if WITH_LISTEN
200 { "socket-listen", xioaddrs_socket_listen },
201 #endif /* WITH_LISTEN */
202 { "socket-recv", xioaddrs_socket_recv },
203 { "socket-recvfrom", xioaddrs_socket_recvfrom },
204 { "socket-sendto", xioaddrs_socket_sendto },
205 #endif
206 #if WITH_SOCKS4
207 { "socks", xioaddrs_socks4_connect },
208 { "socks-client", xioaddrs_socks4_connect },
209 { "socks4", xioaddrs_socks4_connect },
210 { "socks4-client", xioaddrs_socks4_connect },
211 #endif
212 #if WITH_SOCKS4A
213 { "socks4a", xioaddrs_socks4a_connect },
214 { "socks4a-client", xioaddrs_socks4a_connect },
215 #endif
216 #if WITH_SOCKS5
217 { "socks5", xioaddrs_socks5_client },
218 { "socks5-client", xioaddrs_socks5_client },
219 #endif
220 #if WITH_OPENSSL
221 { "ssl", xioaddrs_openssl_connect },
222 #if WITH_LISTEN
223 { "ssl-l", xioaddrs_openssl_listen },
224 { "ssl-s", xioaddrs_openssl_listen },
225 #endif
226 #endif
227 #if WITH_STDIO
228 { "stderr", xioaddrs_stderr },
229 { "stdin", xioaddrs_stdin },
230 { "stdio", xioaddrs_stdio },
231 { "stdout", xioaddrs_stdout },
232 #endif
233 #if WITH_SYSTEM
234 { "system", xioaddrs_system },
235 { "system1", xioaddrs_system1 },
236 { "system2", xioaddrs_system },
237 #endif
238 #if (WITH_IP4 || WITH_IP6) && WITH_TCP
239 { "tcp", xioaddrs_tcp_connect },
240 { "tcp-connect", xioaddrs_tcp_connect },
241 #endif
242 #if (WITH_IP4 || WITH_IP6) && WITH_TCP && WITH_LISTEN
243 { "tcp-l", xioaddrs_tcp_listen },
244 { "tcp-listen", xioaddrs_tcp_listen },
245 #endif
246 #if WITH_IP4 && WITH_TCP
247 { "tcp4", xioaddrs_tcp4_connect },
248 { "tcp4-connect", xioaddrs_tcp4_connect },
249 #endif
250 #if WITH_IP4 && WITH_TCP && WITH_LISTEN
251 { "tcp4-l", xioaddrs_tcp4_listen },
252 { "tcp4-listen", xioaddrs_tcp4_listen },
253 #endif
254 #if WITH_IP6 && WITH_TCP
255 { "tcp6", xioaddrs_tcp6_connect },
256 { "tcp6-connect", xioaddrs_tcp6_connect },
257 #endif
258 #if WITH_IP6 && WITH_TCP && WITH_LISTEN
259 { "tcp6-l", xioaddrs_tcp6_listen },
260 { "tcp6-listen", xioaddrs_tcp6_listen },
261 #endif
262 #if WITH_TEST
263 { "test", xioaddrs_test },
264 { "testrev", xioaddrs_testrev },
265 { "testuni", xioaddrs_testuni },
266 #endif
267 #if WITH_TUN
268 { "tun", xioaddrs_tun },
269 #endif
270 #if (WITH_IP4 || WITH_IP6) && WITH_UDP
271 { "udp", xioaddrs_udp_connect },
272 { "udp-connect", xioaddrs_udp_connect },
273 { "udp-datagram", xioaddrs_udp_datagram },
274 { "udp-dgram", xioaddrs_udp_datagram },
275 #endif
276 #if (WITH_IP4 || WITH_IP6) && WITH_UDP && WITH_LISTEN
277 { "udp-l", xioaddrs_udp_listen },
278 { "udp-listen", xioaddrs_udp_listen },
279 #endif
280 #if (WITH_IP4 || WITH_IP6) && WITH_UDP
281 { "udp-recv", xioaddrs_udp_recv },
282 { "udp-recvfrom", xioaddrs_udp_recvfrom },
283 { "udp-send", xioaddrs_udp_sendto },
284 { "udp-sendto", xioaddrs_udp_sendto },
285 #endif
286 #if WITH_IP4 && WITH_UDP
287 { "udp4", xioaddrs_udp4_connect },
288 { "udp4-connect", xioaddrs_udp4_connect },
289 { "udp4-datagram", xioaddrs_udp4_datagram },
290 { "udp4-dgram", xioaddrs_udp4_datagram },
291 #endif
292 #if WITH_IP4 && WITH_UDP && WITH_LISTEN
293 { "udp4-l", xioaddrs_udp4_listen },
294 { "udp4-listen", xioaddrs_udp4_listen },
295 #endif
296 #if WITH_IP4 && WITH_UDP
297 { "udp4-recv", xioaddrs_udp4_recv },
298 { "udp4-recvfrom", xioaddrs_udp4_recvfrom },
299 { "udp4-send", xioaddrs_udp4_sendto },
300 { "udp4-sendto", xioaddrs_udp4_sendto },
301 #endif
302 #if WITH_IP6 && WITH_UDP
303 { "udp6", xioaddrs_udp6_connect },
304 { "udp6-connect", xioaddrs_udp6_connect },
305 { "udp6-datagram", xioaddrs_udp6_datagram },
306 { "udp6-dgram", xioaddrs_udp6_datagram },
307 #endif
308 #if WITH_IP6 && WITH_UDP && WITH_LISTEN
309 { "udp6-l", xioaddrs_udp6_listen },
310 { "udp6-listen", xioaddrs_udp6_listen },
311 #endif
312 #if WITH_IP6 && WITH_UDP
313 { "udp6-recv", xioaddrs_udp6_recv },
314 { "udp6-recvfrom", xioaddrs_udp6_recvfrom },
315 { "udp6-send", xioaddrs_udp6_sendto },
316 { "udp6-sendto", xioaddrs_udp6_sendto },
317 #endif
318 #if WITH_UNIX
319 { "unix", xioaddrs_unix_client },
320 { "unix-client", xioaddrs_unix_client },
321 { "unix-connect", xioaddrs_unix_connect },
322 #endif
323 #if WITH_UNIX && WITH_LISTEN
324 { "unix-l", xioaddrs_unix_listen },
325 { "unix-listen", xioaddrs_unix_listen },
326 #endif
327 #if WITH_UNIX
328 { "unix-recv", xioaddrs_unix_recv },
329 { "unix-recvfrom", xioaddrs_unix_recvfrom },
330 { "unix-send", xioaddrs_unix_sendto },
331 { "unix-sendto", xioaddrs_unix_sendto },
332 #endif
333 #else /* !0 */
334 # if WITH_INTEGRATE
335 # include "xiointegrate.c"
336 # else
337 # include "xioaddrtab.c"
338 # endif
339 #endif /* !0 */
340 { NULL } /* end marker */
341 } ;
342  
343  
344 /* prepares a xiofile_t record for dual address type:
345 sets the tag and allocates memory for the substreams.
346 returns 0 on success, or <0 if an error occurred.
347 */
348 int xioopen_makedual(xiofile_t *file) {
349 file->tag = XIO_TAG_DUAL;
350 file->common.flags = XIO_RDWR;
351 if ((file->dual.stream[0] = (xiosingle_t *)xioallocfd()) == NULL)
352 return -1;
353 file->dual.stream[0]->flags = XIO_RDONLY;
354 if ((file->dual.stream[1] = (xiosingle_t *)xioallocfd()) == NULL)
355 return -1;
356 file->dual.stream[1]->flags = XIO_WRONLY;
357 return 0;
358 }
359  
360 /* returns NULL if an error occurred */
361 xiofile_t *xioallocfd(void) {
362 xiofile_t *fd;
363  
364 if ((fd = Calloc(1, sizeof(xiofile_t))) == NULL) {
365 return NULL;
366 }
367 /* some default values; 0's and NULL's need not be applied (calloc'ed) */
368 fd->common.tag = XIO_TAG_INVALID;
369 /* fd->common.addr = NULL; */
370 fd->common.flags = XIO_RDWR;
371  
372 #if WITH_RETRY
373 /* fd->stream.retry = 0; */
374 /* fd->stream.forever = false; */
375 fd->stream.intervall.tv_sec = 1;
376 /* fd->stream.intervall.tv_nsec = 0; */
377 #endif /* WITH_RETRY */
378 /* fd->common.ignoreeof = false; */
379 /* fd->common.eof = 0; */
380  
381 fd->stream.rfd = -1;
382 fd->stream.wfd = -1;
383 fd->stream.dtype = XIODATA_STREAM;
384 #if _WITH_SOCKET
385 /* fd->stream.salen = 0; */
386 #endif /* _WITH_SOCKET */
387 /* fd->stream.howtoshut = XIOSHUT_UNSPEC;*/
388 /* fd->stream.howtoclose = XIOCLOSE_UNSPEC;*/
389 /* fd->stream.name = NULL; */
390 fd->stream.escape = -1;
391 /* fd->stream.para.exec.pid = 0; */
392 fd->stream.lineterm = LINETERM_RAW;
393  
394 /*!! support n socks */
395 if (!sock[0]) {
396 sock[0] = fd;
397 } else {
398 sock[1] = fd;
399 }
400 return fd;
401 }
402  
403 void xiofreefd(xiofile_t *xfd) {
404 if (xfd->stream.opts != NULL) {
405 dropopts(xfd->stream.opts, PH_ALL);
406 }
407 free(xfd);
408 }
409  
410  
411 /* handle one chain of addresses
412 rw is one of XIO_RDWR, XIO_RDONLY, or XIO_WRONLY
413 when finished with this and the following sub addresses we return an xfd
414 that can be used by the _socat() loop
415 */
416 xiofile_t *socat_open(const char *addrs0, int rw, int flags) {
417 const char *addrs;
418 xiosingle_t *sfdA; /* what we just parse(d) */
419 xiosingle_t *sfdB; /* what we just parse(d) - second part of dual */
420 int newpipesep = 1; /* dual address: 1%0 instead of 0!!1 */
421 int reverseA, reverseB=0;
422 bool currentisendpoint = false;
423 int mayleftA, mayrightA, mayleftB, mayrightB;
424 int isleftA, isrightA, isleftB, isrightB;
425 int srchleftA, srchrightA, srchleftB=0, srchrightB=0;
426 xiofile_t *xfd0; /* what we return */
427 xiofile_t *xfd1; /* left hand of engine */
428 xiofile_t *xfd2; /* returned by sub address */
429 int rw0, rw1, rw2; /* the data directions for respective xfd
430 directions are sepcified as seen by transfer
431 engine */
432 xiofd_t left, right;
433 struct threadarg_struct *thread_arg;
434 /*0 pthread_t thread = 0;*/
435 /*pthread_attr_t attr;*/
436 int _errno = 0;
437  
438 Info3("opening address \"%s\", rw=%d, flags=0x%x", addrs0, rw, flags);
439  
440 /* loop over retries, contains nearly the complete function */
441 while (true) {
442  
443 addrs = addrs0;
444 skipsp(&addrs);
445 rw0 = rw;
446  
447 /* here we do not know much: will the next sub address be inter or
448 endpoint, single or dual, reverse? */
449  
450 /* check the logical direction of the current subaddress */
451 reverseA = !(strncmp(addrs, xioparams->reversechar,
452 strlen(xioparams->reversechar)));
453 if (reverseA) {
454 addrs += strlen(xioparams->reversechar); /* consume "reverse" */
455 skipsp(&addrs);
456 }
457  
458 if ((sfdA = xioparse_single(&addrs)) == NULL) {
459 Error1("syntax error in \"%s\"", addrs);
460 return NULL;
461 }
462 skipsp(&addrs);
463  
464 /* is it a dual sub address? */
465 if (!strncmp(addrs, xioparams->pipesep, strlen(xioparams->pipesep))) {
466 /* yes, found dual-address operator */
467 if (rw != XIO_RDWR) {
468 Error("dual address cannot handle single direction data stream");
469 }
470 skipsp(&addrs);
471 addrs += strlen(xioparams->pipesep); /* consume "%" */
472 /* check the logical direction of the current subaddress */
473 skipsp(&addrs);
474 reverseB = !(strncmp(addrs, xioparams->reversechar,
475 strlen(xioparams->reversechar)));
476 if (reverseB) {
477 addrs += strlen(xioparams->reversechar); /* consume "reverse" */
478 skipsp(&addrs);
479 }
480  
481 if ((sfdB = xioparse_single(&addrs)) == NULL) {
482 Error1("syntax error in \"%s\"", addrs);
483 return NULL;
484 }
485 skipsp(&addrs);
486 } else {
487 sfdB = NULL;
488 }
489  
490 /* is it the final sub address? */
491 if (*addrs == '\0') {
492 currentisendpoint = true;
493 } else if (!strncmp(addrs, xioparams->chainsep,
494 strlen(xioparams->chainsep))) {
495 addrs += strlen(xioparams->chainsep);
496 skipsp(&addrs);
497 currentisendpoint = false;
498 } else {
499 Error2("syntax error on \"%s\": expected eol or \"%s\"",
500 addrs, xioparams->chainsep);
501 xiofreefd((xiofile_t *)sfdA);
502 if (sfdB != NULL) xiofreefd((xiofile_t *)sfdB);
503 return NULL;
504 }
505  
506 /* now we know the context of the current sub address:
507 currentisendpoint...it is an endpoint, not an inter address
508 sfdB.......if not null, we have a dual type address
509 reverseA...sfdA is reverse
510 reverseB...if dual address then sfdB is reverse
511 rw0......the data direction of xfd0 */
512 /* note: with dual inter, sfdB is implicitely reverse */
513  
514 /* calculate context parameters that are easier to handle */
515 if (sfdB == NULL) {
516 srchleftA = mayleftA = (1 << rw0);
517 srchrightA = mayrightA = (currentisendpoint ? 0 : XIOBIT_ALL);
518 if (reverseA) {
519 srchrightA = srchleftA;
520 /*srchrightA = XIOBIT_REVERSE(srchleftA); no, see what right means*/
521 srchleftA = XIOBIT_ALL;
522 }
523 } else { /* A is only part of dual */
524 srchleftA = mayleftA = XIOBIT_WRONLY;
525 srchrightA = mayrightA = (currentisendpoint ? 0 : XIOBIT_RDONLY);
526 if (reverseA) {
527 srchleftA = XIOBIT_RDONLY;
528 srchrightA = XIOBIT_WRONLY;
529 }
530 srchleftB = mayleftB = (currentisendpoint ? XIOBIT_RDONLY : XIOBIT_WRONLY);
531 srchrightB = mayrightB = (currentisendpoint ? 0 : XIOBIT_RDONLY);
532 if (reverseB) {
533 srchleftB = XIOBIT_RDONLY;
534 srchrightB = XIOBIT_WRONLY;
535 }
536 }
537  
538 if ((true /*0 || ((rw0+1) & (XIO_WRONLY+1))*/) || currentisendpoint) {
539 if (xioopen_unoverload(sfdA, srchleftA, &isleftA, srchrightA, &isrightA)
540 < 0) {
541 Error1("address \"%s\" can not be used in this context",
542 sfdA->addrdescs[0]->inter_desc.defname);
543 }
544 } else {
545 if (xioopen_unoverload(sfdA, srchrightA, &isrightA, srchleftA, &isleftA)
546 < 0) {
547 Error1("address \"%s\" can not be used in this context",
548 sfdA->addrdescs[0]->inter_desc.defname);
549 }
550 }
551 if (reverseA) {
552 int tmp;
553 tmp = isleftA; isrightA = isleftA; isleftA = tmp;
554 }
555  
556 if (sfdB != NULL) {
557 if (xioopen_unoverload(sfdB, srchleftB, &isleftB, srchrightB, &isrightB)
558 < 0) {
559 Error1("address \"%s\" can not be used in this context",
560 sfdB->addrdescs[0]->inter_desc.defname);
561 }
562 if (reverseB) { isleftB = XIOBIT_REVERSE(srchrightB); }
563 if (!currentisendpoint && ((isrightA+1) & (isleftB+1))) {
564 /* conflict in directions on right side (xfd1) */
565 Error("conflict in data directions");/*!!*/
566 }
567 rw1 = ((isrightA+1) | (isleftB+1)) - 1;
568 } else {
569 rw1 = isrightA;
570 }
571 rw2 = (rw1==XIO_RDWR) ? XIO_RDWR : (rw1==XIO_RDONLY) ? XIO_WRONLY :
572 XIO_RDONLY;
573  
574 /* now we know exactly what to do with the current sub address */
575  
576 /* we need the values for retry, forever, and intervall */
577 applyopts_offset(sfdA, sfdA->opts);
578 if (sfdB != NULL) {
579 applyopts_offset(sfdB, sfdB->opts);
580 }
581  
582 /* if we found the endpoint address we are almost finished here */
583  
584 if (currentisendpoint) {
585 if (sfdB != NULL) {
586 if ((xfd0 = xioallocfd()) == NULL) {
587 xiofreefd((xiofile_t *)sfdA); xiofreefd((xiofile_t *)sfdB);
588 return NULL;
589 }
590 xioopen_makedual(xfd0);
591 xfd0->dual.stream[0] = sfdB;
592 xfd0->dual.stream[1] = sfdA;
593 } else {
594 xfd0 = (xiofile_t *)sfdA;
595 }
596 /* open it and be ready in this thread */
597 if (xioopen_endpoint_dual(xfd0, rw0|flags) < 0) {
598 xiofreefd(xfd0);
599 return NULL;
600 }
601 return xfd0;
602 }
603  
604 /* the current addr is not the final sub address */
605  
606 /* recursively open the following addresses of chain */
607 /* loop over retries if appropriate */
608 do {
609 xfd2 = socat_open(addrs, rw2, flags);
610 if (xfd2 != NULL) {
611 break; /* succeeded */
612 }
613 if (sfdA->retry == 0 && !sfdA->forever) {
614 xiofreefd((xiofile_t *)sfdA);
615 if (sfdB != NULL) xiofreefd((xiofile_t *)sfdB);
616 /*! close()? */
617 return NULL;
618 }
619 Nanosleep(&sfdA->intervall, NULL);
620 if (sfdA->retry) --sfdA->retry;
621 } while (true);
622  
623 /* only xfd2 is valid here, contains a handle for the rest of the chain
624 */
625 /* yupp, and the single addresses sfdA and ev.sfdB are valid too, but
626 not yet opened */
627  
628 /* what are xfd0, xfd1, and xfd2?
629 consider chain: addr1|addr2
630 with no reverse address, this will run like:
631 _socat(<upstream>,addr1) --- _socat(-, addr2)
632 _socat(???, xfd0) --- _socat(xfd1,xfd2)
633 xfd0 will be opened in this routine
634 xfd1 will be assembled now, just using FDs
635 xfd2 comes from recursive open call
636 */
637 /* but, with reverse, it looks so:
638 consider chain: ^addr1|addr2
639 _socat(<upstream>,-) --- _socat(addr1,addr2)
640 _socat(??? ,xfd0) --- _socat(xfd1, xfd2)
641 xfd0 will be assembled now, just using FDs
642 xfd1 was just initialized in this routine
643 xfd2 comes from recursive open call
644 */
645 /* even worse, with mixed forward/reverse dual address:
646 consider chain: addr1a%^addr1b|addr2
647 _socat(<upstream, addr1a%nop) --- _socat(nop%addr1b, addr2)
648 _socat(???, xfd0) --- _socat(xfd1, xfd2)
649 */
650  
651 /* prepare FD based communication of current addr with its right neighbor
652 (xfd0-xfd1) */
653 {
654 switch (xioopts.pipetype) {
655 case XIOCOMM_SOCKETPAIR:
656 case XIOCOMM_SOCKETPAIRS:
657 if (xiocommpair(xioopts.pipetype,
658 (rw2+1)&(XIO_WRONLY+1), (rw1+1)&(XIO_WRONLY+1),
659 sfdB!=0, &left, &right,
660 PF_UNIX, SOCK_STREAM, 0) != 0) {
661 return NULL;
662 }
663 break;
664 case XIOCOMM_PTY:
665 case XIOCOMM_PTYS:
666 if (xiocommpair(xioopts.pipetype,
667 (rw2+1)&(XIO_WRONLY+1), (rw1+1)&(XIO_WRONLY+1),
668 sfdB!=0, &left, &right,
669 1 /* useptmx */) != 0) {
670 return NULL;
671 }
672 break;
673 default:
674 if (xiocommpair(xioopts.pipetype,
675 (rw2+1)&(XIO_WRONLY+1), (rw1+1)&(XIO_WRONLY+1),
676 sfdB!=0, &left, &right) != 0) {
677 return NULL;
678 }
679 break;
680 }
681 }
682  
683 /* now assemble xfd0 and xfd1 */
684  
685 if (sfdB != NULL && reverseA == reverseB) {
686 /* dual address, differing orientation (B is impl.reverse) */
687 /* dual implies (rw0==rw1==XIO_RDWR) */
688 if (!reverseA) {
689 /* A is not reverse, but B */
690 # define MAXADDR 45
691 char addr[MAXADDR];
692  
693 xfd0 = xioallocfd();
694 xioopen_makedual(xfd0);
695 xfd0->dual.stream[1] = sfdA;
696 snprintf(addr, MAXADDR, "FD:%u", /*0 righttoleft[0]*/left.rfd);
697 if ((xfd0->dual.stream[0] =
698 (xiosingle_t *)socat_open(addr, XIO_WRONLY, 0))
699 == NULL) {
700 xiofreefd(xfd0); xiofreefd(xfd2); return NULL;
701 }
702 /* address type FD keeps the FDs open per default, but ... */
703  
704 xfd1 = xioallocfd();
705 xioopen_makedual(xfd1);
706 xfd1->dual.stream[1] = sfdB;
707 snprintf(addr, MAXADDR, "FD:%u", /*0 lefttoright[0]*/right.rfd);
708 if ((xfd1->dual.stream[0] =
709 (xiosingle_t *)socat_open(addr, XIO_RDONLY, 0))
710 == NULL) {
711 xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2);
712 return NULL;
713 }
714 } else {
715 /* A is reverse, but B is not */
716 char addr[MAXADDR];
717  
718 xfd0 = xioallocfd();
719 xioopen_makedual(xfd0);
720 xfd0->dual.stream[0] = sfdB;
721 snprintf(addr, MAXADDR, "FD:%u", /*0 lefttoright[1]*/left.wfd);
722 if ((xfd0->dual.stream[1] =
723 (xiosingle_t *)socat_open(addr, XIO_RDONLY, 0))
724 == NULL) {
725 xiofreefd(xfd0); xiofreefd(xfd2); return NULL;
726 }
727  
728 xfd1 = xioallocfd();
729 xioopen_makedual(xfd1);
730 xfd1->dual.stream[0] = sfdA;
731 snprintf(addr, MAXADDR, "FD:%u", /*0 righttoleft[1]*/right.wfd);
732 if ((xfd1->dual.stream[1] =
733 (xiosingle_t *)socat_open(addr, XIO_RDONLY, 0))
734 == NULL) {
735 xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2);
736 return NULL;
737 }
738 }
739 xfd0->dual.stream[0]->rfd = left.rfd;
740 xfd0->dual.stream[1]->wfd = left.wfd;
741 xfd1->dual.stream[0]->rfd = right.rfd;
742 xfd1->dual.stream[1]->wfd = right.wfd;
743  
744 } else {
745 /* either dual with equal directions, or non-dual */
746 xiofile_t *tfd; /* temp xfd */
747 char addr[MAXADDR];
748 if (sfdB != NULL) {
749 /* dual, none or both are reverse */
750 tfd = xioallocfd();
751 xioopen_makedual(tfd);
752 tfd->dual.stream[1] = sfdA;
753 tfd->dual.stream[0] = sfdB;
754 } else {
755 /* non-dual */
756 tfd = (xiofile_t *)sfdA;
757 }
758  
759 /* now take care of orientation */
760 if (!reverseA) {
761 /* forward */
762 xfd0 = tfd;
763 if (rw1 == XIO_RDWR) {
764 snprintf(addr, MAXADDR, "FD:%u:%u", /*0 righttoleft[1]*/right.wfd, /*0 lefttoright[0]*/right.rfd);
765 } else if (rw1 == XIO_RDONLY) {
766 snprintf(addr, MAXADDR, "FD:%u", /*0 lefttoright[0]*/right.rfd);
767 } else {
768 snprintf(addr, MAXADDR, "FD:%u", /*0 righttoleft[1]*/right.wfd);
769 }
770 if ((xfd1 = socat_open(addr, rw1, 0)) == NULL) {
771 xiofreefd(xfd0); xiofreefd(xfd2);
772 return NULL;
773 }
774 } else {
775 /* reverse */
776 xfd1 = tfd;
777 if (rw0 == XIO_RDWR) {
778 snprintf(addr, MAXADDR, "FD:%u:%u", /*0 lefttoright[1]*/left.wfd, /*0 righttoleft[0]*/left.rfd);
779 } else if (rw0 == XIO_RDONLY) {
780 snprintf(addr, MAXADDR, "FD:%u", /*0 righttoleft[0]*/left.rfd);
781 } else {
782 snprintf(addr, MAXADDR, "FD:%u", /*0 lefttoright[1]*/left.wfd);
783 }
784 if ((xfd0 = socat_open(addr, rw0/*0 XIO_RDWR*/, 0)) == NULL) {
785 xiofreefd(xfd1); xiofreefd(xfd2);
786 return NULL;
787 }
788 /* address type FD keeps the FDs open per default, but ... */
789 }
790 if (xfd0->tag == XIO_TAG_DUAL) {
791 xfd0->dual.stream[0]->rfd = /*0 righttoleft[0]*/left.rfd;
792 xfd0->dual.stream[1]->wfd = /*0 lefttoright[1]*/left.wfd;
793 } else {
794 xfd0->stream.rfd = /*0 righttoleft[0]*/left.rfd;
795 xfd0->stream.wfd = /*0 lefttoright[1]*/left.wfd;
796 }
797 if (xfd1->tag == XIO_TAG_DUAL) {
798 xfd1->dual.stream[0]->rfd = /*0 righttoleft[0]*/left.rfd;
799 xfd1->dual.stream[1]->rfd = /*0 lefttoright[1]*/left.wfd;
800 } else {
801 xfd1->stream.rfd = /*0 lefttoright[0]*/right.rfd;
802 xfd1->stream.wfd = /*0 righttoleft[1]*/right.wfd;
803 }
804 }
805  
806 /* address type FD keeps the FDs open per default, but ... */
807 if (xfd0->tag == XIO_TAG_DUAL) {
808 xfd0->dual.stream[0]->howtoshut = left.howtoshut;
809 xfd0->dual.stream[0]->howtoclose = left.howtoclose;
810 xfd0->dual.stream[0]->dtype = left.dtype;
811 xfd0->dual.stream[1]->howtoshut = right.howtoshut;
812 xfd0->dual.stream[1]->howtoclose = right.howtoclose;
813 xfd0->dual.stream[1]->dtype = right.dtype;
814 } else {
815 xfd0->stream.howtoshut = left.howtoshut;
816 xfd0->stream.howtoclose = left.howtoclose;
817 xfd0->stream.dtype = left.dtype;
818 }
819 if (xfd1->tag == XIO_TAG_DUAL) {
820 xfd1->dual.stream[0]->howtoshut = left.howtoshut;
821 xfd1->dual.stream[0]->howtoclose = left.howtoclose;
822 xfd1->dual.stream[0]->dtype = left.dtype;
823 xfd1->dual.stream[1]->howtoshut = right.howtoshut;
824 xfd1->dual.stream[1]->howtoclose = right.howtoclose;
825 xfd1->dual.stream[1]->dtype = right.dtype;
826 } else {
827 xfd1->stream.howtoshut = right.howtoshut;
828 xfd1->stream.howtoclose = right.howtoclose;
829 xfd1->stream.dtype = right.dtype;
830 }
831  
832 /* here xfd2 is valid and ready for transfer;
833 and xfd0 and xfd1 are valid and ready for opening */
834  
835 /* create a new thread that do the xioopen() of xfd1 and xfd2, and then
836 drive the transfer engine between them */
837 if ((thread_arg = Malloc(sizeof(struct threadarg_struct))) == NULL) {
838 /*! free something */
839 xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2);
840 return NULL;
841 }
842 thread_arg->rw = (reverseA ? rw1 : rw0);
843 thread_arg->xfd1 = xfd1;
844 thread_arg->xfd2 = xfd2;
845 Notice5("starting thread: dir=%d, reverseA=%d, reverseB=%d, xfd1->tag=%d, xfd2->tag=%d",
846 rw0, reverseA, reverseB, xfd1->tag, xfd2->tag);
847 if (xfd1->tag==XIO_TAG_DUAL) {
848 Notice4("xfd1: [%s, wfd=%d] %% [%s, rfd=%d]",
849 xfd1->dual.stream[1]->addrdesc->common_desc.defname,
850 xfd1->dual.stream[1]->wfd,
851 xfd1->dual.stream[0]->addrdesc->common_desc.defname,
852 xfd1->dual.stream[0]->rfd);
853 } else {
854 Notice3("xfd1: %s, wfd=%d, rfd=%d",
855 xfd1->stream.addrdesc->common_desc.defname,
856 xfd1->stream.wfd, xfd1->stream.rfd);
857 }
858 if (xfd2->tag==XIO_TAG_DUAL) {
859 Notice4("xfd2: [%s, wfd=%d] %% [%s, rfd=%d]",
860 xfd2->dual.stream[1]->addrdesc->common_desc.defname,
861 xfd2->dual.stream[1]->wfd,
862 xfd2->dual.stream[0]->addrdesc->common_desc.defname,
863 xfd2->dual.stream[0]->rfd);
864 } else {
865 Notice3("xfd2: %s, wfd=%d, rfd=%d",
866 xfd2->stream.addrdesc->common_desc.defname,
867 xfd2->stream.wfd, xfd2->stream.rfd);
868 }
869 Info5("pthread_create(%p, NULL, %s, {%d,%p,%p})",
870 &xfd0->stream.subthread,
871 (reverseA||(sfdB!=NULL)&&!reverseB)?"xioopenleftthenengine":"xioengine",
872 thread_arg->rw, thread_arg->xfd1, thread_arg->xfd2);
873 if ((_errno =
874 Pthread_create(&xfd0->stream.subthread, NULL,
875 (reverseA||(sfdB!=NULL)&&!reverseB)?xioopenleftthenengine:xioengine,
876 thread_arg))
877 != 0) {
878 Error3("pthread_create(%p, {}, xioengine, %p): %s",
879 &xfd0->stream.subthread, thread_arg,
880 strerror(_errno));
881 xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2);
882 free(thread_arg); return NULL;
883 }
884 Info1("started thread "F_thread, xfd0->stream.subthread);
885 xfd1 = NULL;
886 xfd2 = NULL;
887  
888 /* open protocol part */
889 if (xioopen_inter_dual(xfd0, rw|flags)
890 < 0) {
891 /*! close sub chain */
892 if (xfd0->stream.retry == 0 && !xfd0->stream.forever) {
893 xiofreefd(xfd0); /*! close()? */ return NULL;
894 }
895 Nanosleep(&xfd0->stream.intervall, NULL);
896 if (xfd0->stream.retry) --xfd0->stream.retry;
897 continue;
898 }
899 break;
900 }
901 /*!!!?*/
902 #if 0
903 xfd0->stream.howtoshut = XIOSHUT_CLOSE;
904 #endif
905 return xfd0;
906 }
907  
908 void *xioopenleftthenengine(void *thread_void) {
909 struct threadarg_struct *thread_arg = thread_void;
910 int rw = thread_arg->rw;
911 xiofile_t *xfd1 = thread_arg->xfd1;
912 xiofile_t *xfd2 = thread_arg->xfd2;
913  
914 /*! design a function with better interface */
915 if (xioopen_inter_dual(xfd1, rw|XIO_MAYCONVERT|XIO_MAYCHILD) < 0) {
916 xioclose(xfd2);
917 xiofreefd(xfd1);
918 xiofreefd(xfd2);
919 return NULL;
920 }
921 xioengine(thread_void);
922 return NULL;
923 }
924  
925  
926 xiofile_t *xioparse_dual(const char **addr) {
927 xiofile_t *xfd;
928 xiosingle_t *sfd1;
929 int reverse;
930  
931 /* check the logical direction of the current subaddress */
932 reverse = !(strncmp(*addr, xioparams->reversechar,
933 strlen(xioparams->reversechar)));
934 if (reverse) {
935 /* skip "reverse" token */
936 *addr += strlen(xioparams->reversechar);
937 }
938  
939 /* we parse a single address */
940 if ((sfd1 = xioparse_single(addr)) == NULL) {
941 return NULL;
942 }
943 sfd1->reverse = reverse;
944  
945 /* and now we see if we reached a dual-address separator */
946 if (strncmp(*addr, xioopts.pipesep, strlen(xioopts.pipesep))) {
947 /* no, finish */
948 return (xiofile_t *)sfd1;
949 }
950  
951 /* we found the dual-address operator, so we parse the second single address
952 */
953 *addr += strlen(xioparams->pipesep);
954  
955 if ((xfd = xioallocfd()) == NULL) {
956 xiofreefd((xiofile_t *)sfd1);
957 return NULL;
958 }
959 xfd->tag = XIO_TAG_DUAL;
960 xfd->dual.stream[0] = sfd1;
961 if ((xfd->dual.stream[1] = xioparse_single(addr)) == NULL) {
962 xiofreefd(xfd); /*! and maybe have free some if its contents */
963 return NULL;
964 }
965  
966 return xfd;
967 }
968  
969 int xioopen_inter_dual(xiofile_t *xfd, int xioflags) {
970  
971 if (xfd->tag == XIO_TAG_DUAL) {
972 /* a really dual address */
973 if ((xioflags&XIO_ACCMODE) != XIO_RDWR) {
974 Warn("unidirectional open of dual address");
975 }
976  
977 /* a "usual" bidirectional stream specification, one address */
978 if (((xioflags&XIO_ACCMODE)+1) & (XIO_RDONLY+1)) {
979 if (xioopen_inter_single((xiofile_t *)xfd->dual.stream[0], XIO_RDONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC))
980 < 0) {
981 return -1;
982 }
983 }
984 /*! should come before xioopensingle? */
985 if (((xioflags&XIO_ACCMODE)+1) & (XIO_WRONLY+1)) {
986 if (xioopen_inter_single((xiofile_t *)xfd->dual.stream[1], XIO_WRONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC))
987 < 0) {
988 xioclose((xiofile_t *)xfd->dual.stream[0]);
989 return -1;
990 }
991 }
992 return 0;
993 }
994  
995 return xioopen_inter_single(xfd, xioflags);
996 }
997  
998 int xioopen_endpoint_dual(xiofile_t *xfd, int xioflags) {
999  
1000 if (xfd->tag == XIO_TAG_DUAL) {
1001 /* a really dual address */
1002 if ((xioflags&XIO_ACCMODE) != XIO_RDWR) {
1003 Warn("unidirectional open of dual address");
1004 }
1005  
1006 /* a "usual" bidirectional stream specification, one address */
1007 if (((xioflags&XIO_ACCMODE)+1) & (XIO_WRONLY+1)) {
1008 if (xioopen_endpoint_single((xiofile_t *)xfd->dual.stream[1], XIO_WRONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC))
1009 < 0) {
1010 return -1;
1011 }
1012 }
1013 /*! should come before xioopensingle? */
1014 if (((xioflags&XIO_ACCMODE)+1) & (XIO_RDONLY+1)) {
1015 if (xioopen_endpoint_single((xiofile_t *)xfd->dual.stream[0], XIO_RDONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC))
1016 < 0) {
1017 xioclose((xiofile_t *)xfd->dual.stream[1]);
1018 return -1;
1019 }
1020 }
1021 return 0;
1022 }
1023  
1024 return xioopen_endpoint_single(xfd, xioflags);
1025 }
1026  
1027  
1028 /* parses the parameters and options of a single (sub)address.
1029 returns 0 on success or -1 if an error occurred. */
1030 static xiosingle_t *
1031 xioparse_single(const char **addr /* input string; afterwards points to
1032 first char not belonging to this
1033 sub address */
1034 ) {
1035 char addr0[20];
1036 xiofile_t *xfd;
1037 xiosingle_t *sfd;
1038 struct xioaddrname *ae;
1039 /*int maxparams;*/ /* max number of parameters */
1040 const char *ends[4+1];
1041 const char *hquotes[] = {
1042 "'",
1043 NULL
1044 } ;
1045 const char *squotes[] = {
1046 "\"",
1047 NULL
1048 } ;
1049 const char *nests[] = {
1050 "'", "'",
1051 "(", ")",
1052 "[", "]",
1053 "{", "}",
1054 NULL
1055 } ;
1056 char token[512], *tokp;
1057 size_t len;
1058 int i;
1059  
1060 /* init */
1061 i = 0;
1062 ends[i++] = xioopts.chainsep; /* default: "|" */
1063 ends[i++] = xioopts.pipesep; /* default: "%" */
1064 ends[i++] = ","/*xioopts.comma*/; /* default: "," */
1065 ends[i++] = ":"/*xioopts.colon*/; /* default: ":" */
1066 ends[i++] = NULL;
1067  
1068 if ((xfd = xioallocfd()) == NULL) {
1069 return NULL;
1070 }
1071 sfd = &xfd->stream;
1072 sfd->argc = 0;
1073  
1074 /* for error messages */
1075 addr0[0] = '\0'; strncat(addr0, *addr, sizeof(addr0)-1);
1076  
1077 len = sizeof(token); tokp = token;
1078 if (nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests,
1079 true, true, true, false) < 0) {
1080 Error2("keyword too long, in address \"%s%s\"", token, *addr);
1081 }
1082 *tokp = '\0'; /*! len? */
1083 ae = (struct xioaddrname *)
1084 keyw((struct wordent *)&address_names, token,
1085 sizeof(address_names)/sizeof(struct xioaddrname)-1);
1086 if (ae != NULL) {
1087 /* found keyword */
1088 sfd->addrdescs = ae->desc;
1089 if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) {
1090 Error1("strdup(\"%s\"): out of memory", token);
1091 }
1092 } else {
1093 if (false) { /* for canonical reasons */
1094 ;
1095 #if WITH_FDNUM
1096 } else if (isdigit(token[0]&0xff) && token[1] == '\0') {
1097 Info1("interpreting address \"%s\" as file descriptor", token);
1098 sfd->addrdescs = xioaddrs_fdnum;
1099 if ((sfd->argv[sfd->argc++] = strdup("FD")) == NULL) {
1100 Error("strdup(\"FD\"): out of memory");
1101 }
1102 if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) {
1103 Error1("strdup(\"%s\"): out of memory", token);
1104 }
1105 /*! check argc overflow */
1106 #endif /* WITH_FDNUM */
1107 #if WITH_GOPEN
1108 } else if (strchr(token, '/')) {
1109 Info1("interpreting address \"%s\" as file name", token);
1110 sfd->addrdescs = xioaddrs_gopen;
1111 if ((sfd->argv[sfd->argc++] = strdup("GOPEN")) == NULL) {
1112 Error("strdup(\"GOPEN\"): out of memory");
1113 }
1114 if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) {
1115 Error1("strdup(\"%s\"): out of memory", token);
1116 }
1117 /*! check argc overflow */
1118 #endif /* WITH_GOPEN */
1119 } else {
1120 Error1("unknown device/address \"%s\"", token);
1121 xiofreefd(xfd);
1122 return NULL;
1123 }
1124 }
1125  
1126 while (!strncmp(*addr, xioopts.paramsep, strlen(xioopts.paramsep))) {
1127 if (sfd->argc >= MAXARGV) {
1128 Error1("address \"%s\": succeeds max number of parameters",
1129 sfd->argv[0]);
1130 }
1131 *addr += strlen(xioopts.paramsep);
1132 len = sizeof(token); tokp = token;
1133 if (nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests,
1134 true, true, true, false) != 0) {
1135 Error2("syntax error in address \"%s%s\"", token, *addr);
1136 }
1137 *tokp = '\0';
1138 if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) {
1139 Error1("strdup(\"%s\"): out of memory", token);
1140 }
1141 }
1142  
1143 if (parseopts(addr, &sfd->opts) < 0) {
1144 xiofreefd(xfd);
1145 return NULL;
1146 }
1147  
1148 return sfd;
1149 }
1150  
1151 /* during parsing the sub address, we did not know if it is used as inter
1152 address or endpoint; therefore we could not select the appropriate address
1153 descriptor. Here we already know the context and thus select the address
1154 descriptor and check the option groups.
1155 returns 0 on success or -1 if an error occurred */
1156 static int
1157 xioopen_unoverload(xiosingle_t *sfd,
1158 int mayleft, /* what may be on left side: or'd
1159 XIOBIT_RDWR, XIOBIT_RDONLY,
1160 XIOBIT_WRONLY */
1161 int *isleft, /* what the selected address desc
1162 provides on left side: XIO_RDWR,
1163 XIO_RDONLY, or XIO_WRONLY */
1164 int mayright, /* what may be on right side: or'd
1165 XIOBIT_RDWR, XIOBIT_RDONLY,
1166 XIOBIT_WRONLY */
1167 int *isright) /* what the selected address desc
1168 provides on right side: XIO_RDWR,
1169 XIO_RDONLY, or XIO_WRONLY */
1170 {
1171 const union xioaddr_desc **addrdescs;
1172 int tag;
1173 int i;
1174  
1175 addrdescs = sfd->addrdescs;
1176 tag = (mayright ? XIOADDR_INTER : XIOADDR_ENDPOINT);
1177  
1178 /* look for a matching entry in the list of address descriptions */
1179 Debug5("searching record for \"%s\" with tag=%d, numparams=%d, leftdir %d, rightdir %d",
1180 addrdescs[0]->common_desc.defname,
1181 tag, sfd->argc-1, mayleft, mayright);
1182 while ((*addrdescs) != NULL) {
1183 if ((*addrdescs)->tag == tag &&
1184 addrdescs[0]->common_desc.numparams == sfd->argc-1 &&
1185 (addrdescs[0]->common_desc.leftdirs & mayleft) != 0 &&
1186 (mayright ? (addrdescs[0]->inter_desc.rightdirs & mayright) : 1)) {
1187 break;
1188 }
1189 ++addrdescs;
1190 }
1191  
1192 if (addrdescs[0] == NULL) {
1193 if (tag == XIOADDR_ENDPOINT) {
1194 Error3("address \"%s...\" in endpoint context, leftdirs=%d, with %d parameter(s) is not available",
1195 sfd->argv[0], mayleft, sfd->argc-1);
1196 } else {
1197 Error4("address \"%s...\" in intermediate context, leftdirs=%d, rightdirs=%d, with %d parameter(s) is not available",
1198 sfd->argv[0], mayleft, mayright, sfd->argc-1);
1199 }
1200 xiofreefd((xiofile_t *)sfd); return -1;
1201 }
1202  
1203 i = (addrdescs[0]->common_desc.leftdirs & mayleft);
1204 *isleft = 0;
1205 while (i>>=1) {
1206 ++*isleft;
1207 }
1208 if (true /*0 mayright*/) {
1209 i = (addrdescs[0]->inter_desc.rightdirs & mayright);
1210 *isright = 0;
1211 while (i>>=1) {
1212 ++*isright;
1213 }
1214 }
1215 sfd->tag = (*isleft + 1);
1216 sfd->addrdesc = addrdescs[0];
1217 if (addrdescs[0]->common_desc.howtoshut != XIOSHUT_UNSPEC)
1218 sfd->howtoshut = addrdescs[0]->common_desc.howtoshut;
1219 if (addrdescs[0]->common_desc.howtoclose != XIOCLOSE_UNSPEC)
1220 sfd->howtoclose = addrdescs[0]->common_desc.howtoclose;
1221  
1222 if (tag == XIOADDR_ENDPOINT) {
1223 Debug1("selected record with leftdirs %d",
1224 addrdescs[0]->common_desc.leftdirs);
1225 } else {
1226 Debug2("selected record with leftdirs %d, rightdirs %d",
1227 addrdescs[0]->common_desc.leftdirs,
1228 addrdescs[0]->inter_desc.rightdirs);
1229 }
1230 return 0;
1231 }
1232  
1233  
1234 static int
1235 xioopen_inter_single(xiofile_t *xfd, int xioflags) {
1236 const struct xioaddr_inter_desc *addrdesc;
1237 int result;
1238  
1239 addrdesc = &xfd->stream.addrdesc->inter_desc;
1240  
1241 if ((xioflags&XIO_ACCMODE) == XIO_RDONLY) {
1242 xfd->tag = XIO_TAG_RDONLY;
1243 } else if ((xioflags&XIO_ACCMODE) == XIO_WRONLY) {
1244 xfd->tag = XIO_TAG_WRONLY;
1245 } else if ((xioflags&XIO_ACCMODE) == XIO_RDWR) {
1246 xfd->tag = XIO_TAG_RDWR;
1247 } else {
1248 Error1("invalid mode for address \"%s\"", xfd->stream.argv[0]);
1249 }
1250 xfd->stream.flags &= (~XIO_ACCMODE);
1251 xfd->stream.flags |= (xioflags & XIO_ACCMODE);
1252 result = (*addrdesc->func)(xfd->stream.argc, xfd->stream.argv,
1253 xfd->stream.opts, xioflags, xfd,
1254 addrdesc->groups, addrdesc->arg1,
1255 addrdesc->arg2, addrdesc->arg3);
1256 return result;
1257 }
1258  
1259 static int
1260 xioopen_endpoint_single(xiofile_t *xfd, int xioflags) {
1261 const struct xioaddr_endpoint_desc *addrdesc;
1262 int result;
1263  
1264 addrdesc = &xfd->stream.addrdesc->endpoint_desc;
1265 if ((xioflags&XIO_ACCMODE) == XIO_RDONLY) {
1266 xfd->tag = XIO_TAG_RDONLY;
1267 } else if ((xioflags&XIO_ACCMODE) == XIO_WRONLY) {
1268 xfd->tag = XIO_TAG_WRONLY;
1269 } else if ((xioflags&XIO_ACCMODE) == XIO_RDWR) {
1270 xfd->tag = XIO_TAG_RDWR;
1271 } else {
1272 Error1("invalid mode for address \"%s\"", xfd->stream.argv[0]);
1273 }
1274 xfd->stream.flags &= (~XIO_ACCMODE);
1275 xfd->stream.flags |= (xioflags & XIO_ACCMODE);
1276 result = (*addrdesc->func)(xfd->stream.argc, xfd->stream.argv,
1277 xfd->stream.opts, xioflags, xfd,
1278 addrdesc->groups, addrdesc->arg1,
1279 addrdesc->arg2, addrdesc->arg3);
1280 return result;
1281 }