mirror of
https://github.com/moparisthebest/socat
synced 2024-11-15 21:45:05 -05:00
1282 lines
39 KiB
C
1282 lines
39 KiB
C
/* source: xioopen.c */
|
|
/* Copyright Gerhard Rieger 2001-2009 */
|
|
/* Published under the GNU General Public License V.2, see file COPYING */
|
|
|
|
/* this is the source file of the extended open function */
|
|
|
|
#include "xiosysincludes.h"
|
|
|
|
#include "xioopen.h"
|
|
#include "xiomodes.h"
|
|
#include "nestlex.h"
|
|
|
|
#include "xiosigchld.h"
|
|
|
|
void *xioopenleftthenengine(void *thread_void);
|
|
static xiosingle_t *xioparse_single(const char **addr);
|
|
|
|
static int
|
|
xioopen_inter_single(xiofile_t *xfd, int xioflags);
|
|
static int
|
|
xioopen_endpoint_single(xiofile_t *xfd, int xioflags);
|
|
static int
|
|
xioopen_unoverload(xiosingle_t *sfd,
|
|
int mayleft, /* what may be on left side: or'd
|
|
XIOBIT_RDWR, XIOBIT_RDONLY,
|
|
XIOBIT_WRONLY */
|
|
int *isleft, /* what the selected address desc
|
|
provides on left side: XIO_RDWR,
|
|
XIO_RDONLY, or XIO_WRONLY */
|
|
int mayright, /* what may be on right side: or'd
|
|
XIOBIT_RDWR, XIOBIT_RDONLY,
|
|
XIOBIT_WRONLY */
|
|
int *isright); /* what the selected address desc
|
|
provides on right side: XIO_RDWR,
|
|
XIO_RDONLY, or XIO_WRONLY */
|
|
|
|
|
|
const struct xioaddrname address_names[] = {
|
|
#if 1
|
|
#if WITH_STDIO
|
|
{ "-", xioaddrs_stdio },
|
|
#endif
|
|
#if defined(WITH_UNIX) && defined(WITH_ABSTRACT_UNIXSOCKET)
|
|
{ "abstract", xioaddrs_abstract_client },
|
|
{ "abstract-client", xioaddrs_abstract_client },
|
|
{ "abstract-connect", xioaddrs_abstract_connect },
|
|
#if WITH_LISTEN
|
|
{ "abstract-listen", xioaddrs_abstract_listen },
|
|
#endif
|
|
{ "abstract-recv", xioaddrs_abstract_recv },
|
|
{ "abstract-recvfrom", xioaddrs_abstract_recvfrom },
|
|
{ "abstract-sendto", xioaddrs_abstract_sendto },
|
|
#endif /* defined(WITH_UNIX) && defined(WITH_ABSTRACT_UNIXSOCKET) */
|
|
#if WITH_CREAT
|
|
{ "creat", xioaddrs_creat },
|
|
{ "create", xioaddrs_creat },
|
|
#endif
|
|
#if WITH_GENERICSOCKET
|
|
{ "datagram", xioaddrs_socket_datagram },
|
|
{ "dgram", xioaddrs_socket_datagram },
|
|
#endif
|
|
#if WITH_PIPE
|
|
{ "echo", xioaddrs_pipe },
|
|
#endif
|
|
#if WITH_EXEC
|
|
{ "exec", xioaddrs_exec },
|
|
{ "exec1", xioaddrs_exec1 },
|
|
{ "exec2", xioaddrs_exec },
|
|
#endif
|
|
#if WITH_FDNUM
|
|
{ "fd", xioaddrs_fdnum },
|
|
#endif
|
|
#if WITH_PIPE
|
|
{ "fifo", xioaddrs_pipe },
|
|
#endif
|
|
#if WITH_FILE
|
|
{ "file", xioaddrs_open },
|
|
#endif
|
|
#if WITH_GOPEN
|
|
{ "gopen", xioaddrs_gopen },
|
|
#endif
|
|
#if WITH_INTERFACE
|
|
{ "if", xioaddrs_interface },
|
|
#endif
|
|
#if (WITH_IP4 || WITH_IP6) && WITH_TCP
|
|
{ "inet", xioaddrs_tcp_connect },
|
|
#endif
|
|
#if (WITH_IP4 || WITH_IP6) && WITH_TCP && WITH_LISTEN
|
|
{ "inet-l", xioaddrs_tcp_listen },
|
|
{ "inet-listen", xioaddrs_tcp_listen },
|
|
#endif
|
|
#if WITH_IP4 && WITH_TCP
|
|
{ "inet4", xioaddrs_tcp4_connect },
|
|
#endif
|
|
#if WITH_IP4 && WITH_TCP && WITH_LISTEN
|
|
{ "inet4-l", xioaddrs_tcp4_listen },
|
|
{ "inet4-listen", xioaddrs_tcp4_listen },
|
|
#endif
|
|
#if WITH_IP6 && WITH_TCP
|
|
{ "inet6", xioaddrs_tcp6_connect },
|
|
#endif
|
|
#if WITH_IP6 && WITH_TCP && WITH_LISTEN
|
|
{ "inet6-l", xioaddrs_tcp6_listen },
|
|
{ "inet6-listen", xioaddrs_tcp6_listen },
|
|
#endif
|
|
#if WITH_INTERFACE
|
|
{ "interface", xioaddrs_interface },
|
|
#endif
|
|
#if WITH_RAWIP
|
|
#if (WITH_IP4 || WITH_IP6)
|
|
{ "ip", xioaddrs_rawip_sendto },
|
|
{ "ip-datagram", xioaddrs_rawip_datagram },
|
|
{ "ip-dgram", xioaddrs_rawip_datagram },
|
|
{ "ip-recv", xioaddrs_rawip_recv },
|
|
{ "ip-recvfrom", xioaddrs_rawip_recvfrom },
|
|
{ "ip-send", xioaddrs_rawip_sendto },
|
|
{ "ip-sendto", xioaddrs_rawip_sendto },
|
|
#endif
|
|
#if WITH_IP4
|
|
{ "ip4", xioaddrs_rawip4_sendto },
|
|
{ "ip4-datagram", xioaddrs_rawip4_datagram },
|
|
{ "ip4-dgram", xioaddrs_rawip4_datagram },
|
|
{ "ip4-recv", xioaddrs_rawip4_recv },
|
|
{ "ip4-recvfrom", xioaddrs_rawip4_recvfrom },
|
|
{ "ip4-send", xioaddrs_rawip4_sendto },
|
|
{ "ip4-sendto", xioaddrs_rawip4_sendto },
|
|
#endif
|
|
#if WITH_IP6
|
|
{ "ip6", xioaddrs_rawip6_sendto },
|
|
{ "ip6-datagram", xioaddrs_rawip6_datagram },
|
|
{ "ip6-dgram", xioaddrs_rawip6_datagram },
|
|
{ "ip6-recv", xioaddrs_rawip6_recv },
|
|
{ "ip6-recvfrom", xioaddrs_rawip6_recvfrom },
|
|
{ "ip6-send", xioaddrs_rawip6_sendto },
|
|
{ "ip6-sendto", xioaddrs_rawip6_sendto },
|
|
#endif
|
|
#endif /* WITH_RAWIP */
|
|
#if WITH_UNIX
|
|
{ "local", xioaddrs_unix_connect },
|
|
#endif
|
|
#if WITH_NOP
|
|
{ "nop", xioaddrs_nop },
|
|
#endif
|
|
#if WITH_FILE
|
|
{ "open", xioaddrs_open },
|
|
#endif
|
|
#if WITH_OPENSSL
|
|
{ "openssl", xioaddrs_openssl_connect },
|
|
{ "openssl-client", xioaddrs_openssl_connect },
|
|
{ "openssl-connect", xioaddrs_openssl_connect },
|
|
#if WITH_LISTEN
|
|
{ "openssl-listen", xioaddrs_openssl_listen },
|
|
{ "openssl-server", xioaddrs_openssl_listen },
|
|
#endif
|
|
#endif
|
|
#if WITH_PIPE
|
|
{ "pipe", xioaddrs_pipe },
|
|
#endif
|
|
#if WITH_PROXY
|
|
{ "proxy", xioaddrs_proxy_connect },
|
|
{ "proxy-connect", xioaddrs_proxy_connect },
|
|
#endif
|
|
#if WITH_PTY
|
|
{ "pty", xioaddrs_pty },
|
|
#endif
|
|
#if WITH_READLINE
|
|
{ "readline", xioaddrs_readline },
|
|
#endif
|
|
#if (WITH_IP4 || WITH_IP6) && WITH_SCTP
|
|
{ "sctp", xioaddrs_sctp_connect },
|
|
{ "sctp-connect", xioaddrs_sctp_connect },
|
|
#if WITH_LISTEN
|
|
{ "sctp-l", xioaddrs_sctp_listen },
|
|
{ "sctp-listen", xioaddrs_sctp_listen },
|
|
#endif
|
|
#if WITH_IP4
|
|
{ "sctp4", xioaddrs_sctp4_connect },
|
|
{ "sctp4-connect", xioaddrs_sctp4_connect },
|
|
#if WITH_LISTEN
|
|
{ "sctp4-l", xioaddrs_sctp4_listen },
|
|
{ "sctp4-listen", xioaddrs_sctp4_listen },
|
|
#endif
|
|
#endif /* WITH_IP4 */
|
|
#if WITH_IP6
|
|
{ "sctp6", xioaddrs_sctp6_connect },
|
|
{ "sctp6-connect", xioaddrs_sctp6_connect },
|
|
#if WITH_LISTEN
|
|
{ "sctp6-l", xioaddrs_sctp6_listen },
|
|
{ "sctp6-listen", xioaddrs_sctp6_listen },
|
|
#endif
|
|
#endif /* WITH_IP6 */
|
|
#endif /* (WITH_IP4 || WITH_IP6) && WITH_SCTP */
|
|
#if WITH_GENERICSOCKET
|
|
{ "sendto", xioaddrs_socket_sendto },
|
|
#endif
|
|
#if WITH_GENERICSOCKET
|
|
{ "socket-connect", xioaddrs_socket_connect },
|
|
{ "socket-datagram", xioaddrs_socket_datagram },
|
|
#if WITH_LISTEN
|
|
{ "socket-listen", xioaddrs_socket_listen },
|
|
#endif /* WITH_LISTEN */
|
|
{ "socket-recv", xioaddrs_socket_recv },
|
|
{ "socket-recvfrom", xioaddrs_socket_recvfrom },
|
|
{ "socket-sendto", xioaddrs_socket_sendto },
|
|
#endif
|
|
#if WITH_SOCKS4
|
|
{ "socks", xioaddrs_socks4_connect },
|
|
{ "socks-client", xioaddrs_socks4_connect },
|
|
{ "socks4", xioaddrs_socks4_connect },
|
|
{ "socks4-client", xioaddrs_socks4_connect },
|
|
#endif
|
|
#if WITH_SOCKS4A
|
|
{ "socks4a", xioaddrs_socks4a_connect },
|
|
{ "socks4a-client", xioaddrs_socks4a_connect },
|
|
#endif
|
|
#if WITH_SOCKS5
|
|
{ "socks5", xioaddrs_socks5_client },
|
|
{ "socks5-client", xioaddrs_socks5_client },
|
|
#endif
|
|
#if WITH_OPENSSL
|
|
{ "ssl", xioaddrs_openssl_connect },
|
|
#if WITH_LISTEN
|
|
{ "ssl-l", xioaddrs_openssl_listen },
|
|
{ "ssl-s", xioaddrs_openssl_listen },
|
|
#endif
|
|
#endif
|
|
#if WITH_STDIO
|
|
{ "stderr", xioaddrs_stderr },
|
|
{ "stdin", xioaddrs_stdin },
|
|
{ "stdio", xioaddrs_stdio },
|
|
{ "stdout", xioaddrs_stdout },
|
|
#endif
|
|
#if WITH_SYSTEM
|
|
{ "system", xioaddrs_system },
|
|
{ "system1", xioaddrs_system1 },
|
|
{ "system2", xioaddrs_system },
|
|
#endif
|
|
#if (WITH_IP4 || WITH_IP6) && WITH_TCP
|
|
{ "tcp", xioaddrs_tcp_connect },
|
|
{ "tcp-connect", xioaddrs_tcp_connect },
|
|
#endif
|
|
#if (WITH_IP4 || WITH_IP6) && WITH_TCP && WITH_LISTEN
|
|
{ "tcp-l", xioaddrs_tcp_listen },
|
|
{ "tcp-listen", xioaddrs_tcp_listen },
|
|
#endif
|
|
#if WITH_IP4 && WITH_TCP
|
|
{ "tcp4", xioaddrs_tcp4_connect },
|
|
{ "tcp4-connect", xioaddrs_tcp4_connect },
|
|
#endif
|
|
#if WITH_IP4 && WITH_TCP && WITH_LISTEN
|
|
{ "tcp4-l", xioaddrs_tcp4_listen },
|
|
{ "tcp4-listen", xioaddrs_tcp4_listen },
|
|
#endif
|
|
#if WITH_IP6 && WITH_TCP
|
|
{ "tcp6", xioaddrs_tcp6_connect },
|
|
{ "tcp6-connect", xioaddrs_tcp6_connect },
|
|
#endif
|
|
#if WITH_IP6 && WITH_TCP && WITH_LISTEN
|
|
{ "tcp6-l", xioaddrs_tcp6_listen },
|
|
{ "tcp6-listen", xioaddrs_tcp6_listen },
|
|
#endif
|
|
#if WITH_TEST
|
|
{ "test", xioaddrs_test },
|
|
{ "testrev", xioaddrs_testrev },
|
|
{ "testuni", xioaddrs_testuni },
|
|
#endif
|
|
#if WITH_TUN
|
|
{ "tun", xioaddrs_tun },
|
|
#endif
|
|
#if (WITH_IP4 || WITH_IP6) && WITH_UDP
|
|
{ "udp", xioaddrs_udp_connect },
|
|
{ "udp-connect", xioaddrs_udp_connect },
|
|
{ "udp-datagram", xioaddrs_udp_datagram },
|
|
{ "udp-dgram", xioaddrs_udp_datagram },
|
|
#endif
|
|
#if (WITH_IP4 || WITH_IP6) && WITH_UDP && WITH_LISTEN
|
|
{ "udp-l", xioaddrs_udp_listen },
|
|
{ "udp-listen", xioaddrs_udp_listen },
|
|
#endif
|
|
#if (WITH_IP4 || WITH_IP6) && WITH_UDP
|
|
{ "udp-recv", xioaddrs_udp_recv },
|
|
{ "udp-recvfrom", xioaddrs_udp_recvfrom },
|
|
{ "udp-send", xioaddrs_udp_sendto },
|
|
{ "udp-sendto", xioaddrs_udp_sendto },
|
|
#endif
|
|
#if WITH_IP4 && WITH_UDP
|
|
{ "udp4", xioaddrs_udp4_connect },
|
|
{ "udp4-connect", xioaddrs_udp4_connect },
|
|
{ "udp4-datagram", xioaddrs_udp4_datagram },
|
|
{ "udp4-dgram", xioaddrs_udp4_datagram },
|
|
#endif
|
|
#if WITH_IP4 && WITH_UDP && WITH_LISTEN
|
|
{ "udp4-l", xioaddrs_udp4_listen },
|
|
{ "udp4-listen", xioaddrs_udp4_listen },
|
|
#endif
|
|
#if WITH_IP4 && WITH_UDP
|
|
{ "udp4-recv", xioaddrs_udp4_recv },
|
|
{ "udp4-recvfrom", xioaddrs_udp4_recvfrom },
|
|
{ "udp4-send", xioaddrs_udp4_sendto },
|
|
{ "udp4-sendto", xioaddrs_udp4_sendto },
|
|
#endif
|
|
#if WITH_IP6 && WITH_UDP
|
|
{ "udp6", xioaddrs_udp6_connect },
|
|
{ "udp6-connect", xioaddrs_udp6_connect },
|
|
{ "udp6-datagram", xioaddrs_udp6_datagram },
|
|
{ "udp6-dgram", xioaddrs_udp6_datagram },
|
|
#endif
|
|
#if WITH_IP6 && WITH_UDP && WITH_LISTEN
|
|
{ "udp6-l", xioaddrs_udp6_listen },
|
|
{ "udp6-listen", xioaddrs_udp6_listen },
|
|
#endif
|
|
#if WITH_IP6 && WITH_UDP
|
|
{ "udp6-recv", xioaddrs_udp6_recv },
|
|
{ "udp6-recvfrom", xioaddrs_udp6_recvfrom },
|
|
{ "udp6-send", xioaddrs_udp6_sendto },
|
|
{ "udp6-sendto", xioaddrs_udp6_sendto },
|
|
#endif
|
|
#if WITH_UNIX
|
|
{ "unix", xioaddrs_unix_client },
|
|
{ "unix-client", xioaddrs_unix_client },
|
|
{ "unix-connect", xioaddrs_unix_connect },
|
|
#endif
|
|
#if WITH_UNIX && WITH_LISTEN
|
|
{ "unix-l", xioaddrs_unix_listen },
|
|
{ "unix-listen", xioaddrs_unix_listen },
|
|
#endif
|
|
#if WITH_UNIX
|
|
{ "unix-recv", xioaddrs_unix_recv },
|
|
{ "unix-recvfrom", xioaddrs_unix_recvfrom },
|
|
{ "unix-send", xioaddrs_unix_sendto },
|
|
{ "unix-sendto", xioaddrs_unix_sendto },
|
|
#endif
|
|
#else /* !0 */
|
|
# if WITH_INTEGRATE
|
|
# include "xiointegrate.c"
|
|
# else
|
|
# include "xioaddrtab.c"
|
|
# endif
|
|
#endif /* !0 */
|
|
{ NULL } /* end marker */
|
|
} ;
|
|
|
|
|
|
/* prepares a xiofile_t record for dual address type:
|
|
sets the tag and allocates memory for the substreams.
|
|
returns 0 on success, or <0 if an error occurred.
|
|
*/
|
|
int xioopen_makedual(xiofile_t *file) {
|
|
file->tag = XIO_TAG_DUAL;
|
|
file->common.flags = XIO_RDWR;
|
|
if ((file->dual.stream[0] = (xiosingle_t *)xioallocfd()) == NULL)
|
|
return -1;
|
|
file->dual.stream[0]->flags = XIO_RDONLY;
|
|
if ((file->dual.stream[1] = (xiosingle_t *)xioallocfd()) == NULL)
|
|
return -1;
|
|
file->dual.stream[1]->flags = XIO_WRONLY;
|
|
return 0;
|
|
}
|
|
|
|
/* returns NULL if an error occurred */
|
|
xiofile_t *xioallocfd(void) {
|
|
xiofile_t *fd;
|
|
|
|
if ((fd = Calloc(1, sizeof(xiofile_t))) == NULL) {
|
|
return NULL;
|
|
}
|
|
/* some default values; 0's and NULL's need not be applied (calloc'ed) */
|
|
fd->common.tag = XIO_TAG_INVALID;
|
|
/* fd->common.addr = NULL; */
|
|
fd->common.flags = XIO_RDWR;
|
|
|
|
#if WITH_RETRY
|
|
/* fd->stream.retry = 0; */
|
|
/* fd->stream.forever = false; */
|
|
fd->stream.intervall.tv_sec = 1;
|
|
/* fd->stream.intervall.tv_nsec = 0; */
|
|
#endif /* WITH_RETRY */
|
|
/* fd->common.ignoreeof = false; */
|
|
/* fd->common.eof = 0; */
|
|
|
|
fd->stream.rfd = -1;
|
|
fd->stream.wfd = -1;
|
|
fd->stream.dtype = XIODATA_STREAM;
|
|
#if _WITH_SOCKET
|
|
/* fd->stream.salen = 0; */
|
|
#endif /* _WITH_SOCKET */
|
|
/* fd->stream.howtoshut = XIOSHUT_UNSPEC;*/
|
|
/* fd->stream.howtoclose = XIOCLOSE_UNSPEC;*/
|
|
/* fd->stream.name = NULL; */
|
|
fd->stream.escape = -1;
|
|
/* fd->stream.para.exec.pid = 0; */
|
|
fd->stream.lineterm = LINETERM_RAW;
|
|
|
|
/*!! support n socks */
|
|
if (!sock[0]) {
|
|
sock[0] = fd;
|
|
} else {
|
|
sock[1] = fd;
|
|
}
|
|
return fd;
|
|
}
|
|
|
|
void xiofreefd(xiofile_t *xfd) {
|
|
if (xfd->stream.opts != NULL) {
|
|
dropopts(xfd->stream.opts, PH_ALL);
|
|
}
|
|
free(xfd);
|
|
}
|
|
|
|
|
|
/* handle one chain of addresses
|
|
rw is one of XIO_RDWR, XIO_RDONLY, or XIO_WRONLY
|
|
when finished with this and the following sub addresses we return an xfd
|
|
that can be used by the _socat() loop
|
|
*/
|
|
xiofile_t *socat_open(const char *addrs0, int rw, int flags) {
|
|
const char *addrs;
|
|
xiosingle_t *sfdA; /* what we just parse(d) */
|
|
xiosingle_t *sfdB; /* what we just parse(d) - second part of dual */
|
|
int newpipesep = 1; /* dual address: 1%0 instead of 0!!1 */
|
|
int reverseA, reverseB=0;
|
|
bool currentisendpoint = false;
|
|
int mayleftA, mayrightA, mayleftB, mayrightB;
|
|
int isleftA, isrightA, isleftB, isrightB;
|
|
int srchleftA, srchrightA, srchleftB=0, srchrightB=0;
|
|
xiofile_t *xfd0; /* what we return */
|
|
xiofile_t *xfd1; /* left hand of engine */
|
|
xiofile_t *xfd2; /* returned by sub address */
|
|
int rw0, rw1, rw2; /* the data directions for respective xfd
|
|
directions are sepcified as seen by transfer
|
|
engine */
|
|
xiofd_t left, right;
|
|
struct threadarg_struct *thread_arg;
|
|
/*0 pthread_t thread = 0;*/
|
|
/*pthread_attr_t attr;*/
|
|
int _errno = 0;
|
|
|
|
Info3("opening address \"%s\", rw=%d, flags=0x%x", addrs0, rw, flags);
|
|
|
|
/* loop over retries, contains nearly the complete function */
|
|
while (true) {
|
|
|
|
addrs = addrs0;
|
|
skipsp(&addrs);
|
|
rw0 = rw;
|
|
|
|
/* here we do not know much: will the next sub address be inter or
|
|
endpoint, single or dual, reverse? */
|
|
|
|
/* check the logical direction of the current subaddress */
|
|
reverseA = !(strncmp(addrs, xioparams->reversechar,
|
|
strlen(xioparams->reversechar)));
|
|
if (reverseA) {
|
|
addrs += strlen(xioparams->reversechar); /* consume "reverse" */
|
|
skipsp(&addrs);
|
|
}
|
|
|
|
if ((sfdA = xioparse_single(&addrs)) == NULL) {
|
|
Error1("syntax error in \"%s\"", addrs);
|
|
return NULL;
|
|
}
|
|
skipsp(&addrs);
|
|
|
|
/* is it a dual sub address? */
|
|
if (!strncmp(addrs, xioparams->pipesep, strlen(xioparams->pipesep))) {
|
|
/* yes, found dual-address operator */
|
|
if (rw != XIO_RDWR) {
|
|
Error("dual address cannot handle single direction data stream");
|
|
}
|
|
skipsp(&addrs);
|
|
addrs += strlen(xioparams->pipesep); /* consume "%" */
|
|
/* check the logical direction of the current subaddress */
|
|
skipsp(&addrs);
|
|
reverseB = !(strncmp(addrs, xioparams->reversechar,
|
|
strlen(xioparams->reversechar)));
|
|
if (reverseB) {
|
|
addrs += strlen(xioparams->reversechar); /* consume "reverse" */
|
|
skipsp(&addrs);
|
|
}
|
|
|
|
if ((sfdB = xioparse_single(&addrs)) == NULL) {
|
|
Error1("syntax error in \"%s\"", addrs);
|
|
return NULL;
|
|
}
|
|
skipsp(&addrs);
|
|
} else {
|
|
sfdB = NULL;
|
|
}
|
|
|
|
/* is it the final sub address? */
|
|
if (*addrs == '\0') {
|
|
currentisendpoint = true;
|
|
} else if (!strncmp(addrs, xioparams->chainsep,
|
|
strlen(xioparams->chainsep))) {
|
|
addrs += strlen(xioparams->chainsep);
|
|
skipsp(&addrs);
|
|
currentisendpoint = false;
|
|
} else {
|
|
Error2("syntax error on \"%s\": expected eol or \"%s\"",
|
|
addrs, xioparams->chainsep);
|
|
xiofreefd((xiofile_t *)sfdA);
|
|
if (sfdB != NULL) xiofreefd((xiofile_t *)sfdB);
|
|
return NULL;
|
|
}
|
|
|
|
/* now we know the context of the current sub address:
|
|
currentisendpoint...it is an endpoint, not an inter address
|
|
sfdB.......if not null, we have a dual type address
|
|
reverseA...sfdA is reverse
|
|
reverseB...if dual address then sfdB is reverse
|
|
rw0......the data direction of xfd0 */
|
|
/* note: with dual inter, sfdB is implicitely reverse */
|
|
|
|
/* calculate context parameters that are easier to handle */
|
|
if (sfdB == NULL) {
|
|
srchleftA = mayleftA = (1 << rw0);
|
|
srchrightA = mayrightA = (currentisendpoint ? 0 : XIOBIT_ALL);
|
|
if (reverseA) {
|
|
srchrightA = srchleftA;
|
|
/*srchrightA = XIOBIT_REVERSE(srchleftA); no, see what right means*/
|
|
srchleftA = XIOBIT_ALL;
|
|
}
|
|
} else { /* A is only part of dual */
|
|
srchleftA = mayleftA = XIOBIT_WRONLY;
|
|
srchrightA = mayrightA = (currentisendpoint ? 0 : XIOBIT_RDONLY);
|
|
if (reverseA) {
|
|
srchleftA = XIOBIT_RDONLY;
|
|
srchrightA = XIOBIT_WRONLY;
|
|
}
|
|
srchleftB = mayleftB = (currentisendpoint ? XIOBIT_RDONLY : XIOBIT_WRONLY);
|
|
srchrightB = mayrightB = (currentisendpoint ? 0 : XIOBIT_RDONLY);
|
|
if (reverseB) {
|
|
srchleftB = XIOBIT_RDONLY;
|
|
srchrightB = XIOBIT_WRONLY;
|
|
}
|
|
}
|
|
|
|
if ((true /*0 || ((rw0+1) & (XIO_WRONLY+1))*/) || currentisendpoint) {
|
|
if (xioopen_unoverload(sfdA, srchleftA, &isleftA, srchrightA, &isrightA)
|
|
< 0) {
|
|
Error1("address \"%s\" can not be used in this context",
|
|
sfdA->addrdescs[0]->inter_desc.defname);
|
|
}
|
|
} else {
|
|
if (xioopen_unoverload(sfdA, srchrightA, &isrightA, srchleftA, &isleftA)
|
|
< 0) {
|
|
Error1("address \"%s\" can not be used in this context",
|
|
sfdA->addrdescs[0]->inter_desc.defname);
|
|
}
|
|
}
|
|
if (reverseA) {
|
|
int tmp;
|
|
tmp = isleftA; isrightA = isleftA; isleftA = tmp;
|
|
}
|
|
|
|
if (sfdB != NULL) {
|
|
if (xioopen_unoverload(sfdB, srchleftB, &isleftB, srchrightB, &isrightB)
|
|
< 0) {
|
|
Error1("address \"%s\" can not be used in this context",
|
|
sfdB->addrdescs[0]->inter_desc.defname);
|
|
}
|
|
if (reverseB) { isleftB = XIOBIT_REVERSE(srchrightB); }
|
|
if (!currentisendpoint && ((isrightA+1) & (isleftB+1))) {
|
|
/* conflict in directions on right side (xfd1) */
|
|
Error("conflict in data directions");/*!!*/
|
|
}
|
|
rw1 = ((isrightA+1) | (isleftB+1)) - 1;
|
|
} else {
|
|
rw1 = isrightA;
|
|
}
|
|
rw2 = (rw1==XIO_RDWR) ? XIO_RDWR : (rw1==XIO_RDONLY) ? XIO_WRONLY :
|
|
XIO_RDONLY;
|
|
|
|
/* now we know exactly what to do with the current sub address */
|
|
|
|
/* we need the values for retry, forever, and intervall */
|
|
applyopts_offset(sfdA, sfdA->opts);
|
|
if (sfdB != NULL) {
|
|
applyopts_offset(sfdB, sfdB->opts);
|
|
}
|
|
|
|
/* if we found the endpoint address we are almost finished here */
|
|
|
|
if (currentisendpoint) {
|
|
if (sfdB != NULL) {
|
|
if ((xfd0 = xioallocfd()) == NULL) {
|
|
xiofreefd((xiofile_t *)sfdA); xiofreefd((xiofile_t *)sfdB);
|
|
return NULL;
|
|
}
|
|
xioopen_makedual(xfd0);
|
|
xfd0->dual.stream[0] = sfdB;
|
|
xfd0->dual.stream[1] = sfdA;
|
|
} else {
|
|
xfd0 = (xiofile_t *)sfdA;
|
|
}
|
|
/* open it and be ready in this thread */
|
|
if (xioopen_endpoint_dual(xfd0, rw0|flags) < 0) {
|
|
xiofreefd(xfd0);
|
|
return NULL;
|
|
}
|
|
return xfd0;
|
|
}
|
|
|
|
/* the current addr is not the final sub address */
|
|
|
|
/* recursively open the following addresses of chain */
|
|
/* loop over retries if appropriate */
|
|
do {
|
|
xfd2 = socat_open(addrs, rw2, flags);
|
|
if (xfd2 != NULL) {
|
|
break; /* succeeded */
|
|
}
|
|
if (sfdA->retry == 0 && !sfdA->forever) {
|
|
xiofreefd((xiofile_t *)sfdA);
|
|
if (sfdB != NULL) xiofreefd((xiofile_t *)sfdB);
|
|
/*! close()? */
|
|
return NULL;
|
|
}
|
|
Nanosleep(&sfdA->intervall, NULL);
|
|
if (sfdA->retry) --sfdA->retry;
|
|
} while (true);
|
|
|
|
/* only xfd2 is valid here, contains a handle for the rest of the chain
|
|
*/
|
|
/* yupp, and the single addresses sfdA and ev.sfdB are valid too, but
|
|
not yet opened */
|
|
|
|
/* what are xfd0, xfd1, and xfd2?
|
|
consider chain: addr1|addr2
|
|
with no reverse address, this will run like:
|
|
_socat(<upstream>,addr1) --- _socat(-, addr2)
|
|
_socat(???, xfd0) --- _socat(xfd1,xfd2)
|
|
xfd0 will be opened in this routine
|
|
xfd1 will be assembled now, just using FDs
|
|
xfd2 comes from recursive open call
|
|
*/
|
|
/* but, with reverse, it looks so:
|
|
consider chain: ^addr1|addr2
|
|
_socat(<upstream>,-) --- _socat(addr1,addr2)
|
|
_socat(??? ,xfd0) --- _socat(xfd1, xfd2)
|
|
xfd0 will be assembled now, just using FDs
|
|
xfd1 was just initialized in this routine
|
|
xfd2 comes from recursive open call
|
|
*/
|
|
/* even worse, with mixed forward/reverse dual address:
|
|
consider chain: addr1a%^addr1b|addr2
|
|
_socat(<upstream, addr1a%nop) --- _socat(nop%addr1b, addr2)
|
|
_socat(???, xfd0) --- _socat(xfd1, xfd2)
|
|
*/
|
|
|
|
/* prepare FD based communication of current addr with its right neighbor
|
|
(xfd0-xfd1) */
|
|
{
|
|
switch (xioopts.pipetype) {
|
|
case XIOCOMM_SOCKETPAIR:
|
|
case XIOCOMM_SOCKETPAIRS:
|
|
if (xiocommpair(xioopts.pipetype,
|
|
(rw0+1)&(XIO_WRONLY+1), (rw0+1)&(XIO_RDONLY+1),
|
|
sfdB!=0, &left, &right,
|
|
PF_UNIX, SOCK_STREAM, 0) != 0) {
|
|
return NULL;
|
|
}
|
|
break;
|
|
case XIOCOMM_PTY:
|
|
case XIOCOMM_PTYS:
|
|
if (xiocommpair(xioopts.pipetype,
|
|
(rw0+1)&(XIO_WRONLY+1), (rw0+1)&(XIO_RDONLY+1),
|
|
sfdB!=0, &left, &right,
|
|
1 /* useptmx */) != 0) {
|
|
return NULL;
|
|
}
|
|
break;
|
|
default:
|
|
if (xiocommpair(xioopts.pipetype,
|
|
(rw0+1)&(XIO_WRONLY+1), (rw0+1)&(XIO_RDONLY+1),
|
|
sfdB!=0, &left, &right) != 0) {
|
|
return NULL;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* now assemble xfd0 and xfd1 */
|
|
|
|
if (sfdB != NULL && reverseA == reverseB) {
|
|
/* dual address, differing orientation (B is impl.reverse) */
|
|
/* dual implies (rw0==rw1==XIO_RDWR) */
|
|
if (!reverseA) {
|
|
/* A is not reverse, but B */
|
|
char addr[15];
|
|
|
|
xfd0 = xioallocfd();
|
|
xioopen_makedual(xfd0);
|
|
xfd0->dual.stream[1] = sfdA;
|
|
sprintf(addr, "FD:%u", /*0 righttoleft[0]*/left.rfd);
|
|
if ((xfd0->dual.stream[0] =
|
|
(xiosingle_t *)socat_open(addr, XIO_WRONLY, 0))
|
|
== NULL) {
|
|
xiofreefd(xfd0); xiofreefd(xfd2); return NULL;
|
|
}
|
|
/* address type FD keeps the FDs open per default, but ... */
|
|
|
|
xfd1 = xioallocfd();
|
|
xioopen_makedual(xfd1);
|
|
xfd1->dual.stream[1] = sfdB;
|
|
sprintf(addr, "FD:%u", /*0 lefttoright[0]*/right.rfd);
|
|
if ((xfd1->dual.stream[0] =
|
|
(xiosingle_t *)socat_open(addr, XIO_RDONLY, 0))
|
|
== NULL) {
|
|
xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2);
|
|
return NULL;
|
|
}
|
|
} else {
|
|
/* A is reverse, but B is not */
|
|
char addr[15];
|
|
|
|
xfd0 = xioallocfd();
|
|
xioopen_makedual(xfd0);
|
|
xfd0->dual.stream[0] = sfdB;
|
|
sprintf(addr, "FD:%u", /*0 lefttoright[1]*/left.wfd);
|
|
if ((xfd0->dual.stream[1] =
|
|
(xiosingle_t *)socat_open(addr, XIO_RDONLY, 0))
|
|
== NULL) {
|
|
xiofreefd(xfd0); xiofreefd(xfd2); return NULL;
|
|
}
|
|
|
|
xfd1 = xioallocfd();
|
|
xioopen_makedual(xfd1);
|
|
xfd1->dual.stream[0] = sfdA;
|
|
sprintf(addr, "FD:%u", /*0 righttoleft[1]*/right.wfd);
|
|
if ((xfd1->dual.stream[1] =
|
|
(xiosingle_t *)socat_open(addr, XIO_RDONLY, 0))
|
|
== NULL) {
|
|
xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2);
|
|
return NULL;
|
|
}
|
|
}
|
|
xfd0->dual.stream[0]->rfd = left.rfd;
|
|
xfd0->dual.stream[1]->wfd = left.wfd;
|
|
xfd1->dual.stream[0]->rfd = right.rfd;
|
|
xfd1->dual.stream[1]->wfd = right.wfd;
|
|
|
|
} else {
|
|
/* either dual with equal directions, or non-dual */
|
|
xiofile_t *tfd; /* temp xfd */
|
|
char addr[15];
|
|
if (sfdB != NULL) {
|
|
/* dual, none or both are reverse */
|
|
tfd = xioallocfd();
|
|
xioopen_makedual(tfd);
|
|
tfd->dual.stream[1] = sfdA;
|
|
tfd->dual.stream[0] = sfdB;
|
|
} else {
|
|
/* non-dual */
|
|
tfd = (xiofile_t *)sfdA;
|
|
}
|
|
|
|
/* now take care of orientation */
|
|
if (!reverseA) {
|
|
/* forward */
|
|
xfd0 = tfd;
|
|
if (rw1 == XIO_RDWR) {
|
|
sprintf(addr, "FD:%u:%u", /*0 righttoleft[1]*/right.wfd, /*0 lefttoright[0]*/right.rfd);
|
|
} else if (rw1 == XIO_RDONLY) {
|
|
sprintf(addr, "FD:%u", /*0 lefttoright[0]*/right.rfd);
|
|
} else {
|
|
sprintf(addr, "FD:%u", /*0 righttoleft[1]*/right.wfd);
|
|
}
|
|
if ((xfd1 = socat_open(addr, rw1, 0)) == NULL) {
|
|
xiofreefd(xfd0); xiofreefd(xfd2);
|
|
return NULL;
|
|
}
|
|
} else {
|
|
/* reverse */
|
|
xfd1 = tfd;
|
|
if (rw0 == XIO_RDWR) {
|
|
sprintf(addr, "FD:%u:%u", /*0 lefttoright[1]*/left.wfd, /*0 righttoleft[0]*/left.rfd);
|
|
} else if (rw0 == XIO_RDONLY) {
|
|
sprintf(addr, "FD:%u", /*0 righttoleft[0]*/left.rfd);
|
|
} else {
|
|
sprintf(addr, "FD:%u", /*0 lefttoright[1]*/left.wfd);
|
|
}
|
|
if ((xfd0 = socat_open(addr, rw0/*0 XIO_RDWR*/, 0)) == NULL) {
|
|
xiofreefd(xfd1); xiofreefd(xfd2);
|
|
return NULL;
|
|
}
|
|
/* address type FD keeps the FDs open per default, but ... */
|
|
}
|
|
if (xfd0->tag == XIO_TAG_DUAL) {
|
|
xfd0->dual.stream[0]->rfd = /*0 righttoleft[0]*/left.rfd;
|
|
xfd0->dual.stream[1]->wfd = /*0 lefttoright[1]*/left.wfd;
|
|
} else {
|
|
xfd0->stream.rfd = /*0 righttoleft[0]*/left.rfd;
|
|
xfd0->stream.wfd = /*0 lefttoright[1]*/left.wfd;
|
|
}
|
|
if (xfd1->tag == XIO_TAG_DUAL) {
|
|
xfd1->dual.stream[0]->rfd = /*0 righttoleft[0]*/left.rfd;
|
|
xfd1->dual.stream[1]->rfd = /*0 lefttoright[1]*/left.wfd;
|
|
} else {
|
|
xfd1->stream.rfd = /*0 lefttoright[0]*/right.rfd;
|
|
xfd1->stream.wfd = /*0 righttoleft[1]*/right.wfd;
|
|
}
|
|
}
|
|
|
|
/* address type FD keeps the FDs open per default, but ... */
|
|
if (xfd0->tag == XIO_TAG_DUAL) {
|
|
xfd0->dual.stream[0]->howtoshut = left.howtoshut;
|
|
xfd0->dual.stream[0]->howtoclose = left.howtoclose;
|
|
xfd0->dual.stream[0]->dtype = left.dtype;
|
|
xfd0->dual.stream[1]->howtoshut = right.howtoshut;
|
|
xfd0->dual.stream[1]->howtoclose = right.howtoclose;
|
|
xfd0->dual.stream[1]->dtype = right.dtype;
|
|
} else {
|
|
xfd0->stream.howtoshut = left.howtoshut;
|
|
xfd0->stream.howtoclose = left.howtoclose;
|
|
xfd0->stream.dtype = left.dtype;
|
|
}
|
|
if (xfd1->tag == XIO_TAG_DUAL) {
|
|
xfd1->dual.stream[0]->howtoshut = left.howtoshut;
|
|
xfd1->dual.stream[0]->howtoclose = left.howtoclose;
|
|
xfd1->dual.stream[0]->dtype = left.dtype;
|
|
xfd1->dual.stream[1]->howtoshut = right.howtoshut;
|
|
xfd1->dual.stream[1]->howtoclose = right.howtoclose;
|
|
xfd1->dual.stream[1]->dtype = right.dtype;
|
|
} else {
|
|
xfd1->stream.howtoshut = right.howtoshut;
|
|
xfd1->stream.howtoclose = right.howtoclose;
|
|
xfd1->stream.dtype = right.dtype;
|
|
}
|
|
|
|
/* here xfd2 is valid and ready for transfer;
|
|
and xfd0 and xfd1 are valid and ready for opening */
|
|
|
|
/* create a new thread that do the xioopen() of xfd1 and xfd2, and then
|
|
drive the transfer engine between them */
|
|
if ((thread_arg = Malloc(sizeof(struct threadarg_struct))) == NULL) {
|
|
/*! free something */
|
|
xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2);
|
|
return NULL;
|
|
}
|
|
thread_arg->rw = (reverseA ? rw1 : rw0);
|
|
thread_arg->xfd1 = xfd1;
|
|
thread_arg->xfd2 = xfd2;
|
|
Notice5("starting thread: dir=%d, reverseA=%d, reverseB=%d, xfd1->tag=%d, xfd2->tag=%d",
|
|
rw0, reverseA, reverseB, xfd1->tag, xfd2->tag);
|
|
if (xfd1->tag==XIO_TAG_DUAL) {
|
|
Notice4("xfd1: [%s, wfd=%d] %% [%s, rfd=%d]",
|
|
xfd1->dual.stream[1]->addrdesc->common_desc.defname,
|
|
xfd1->dual.stream[1]->wfd,
|
|
xfd1->dual.stream[0]->addrdesc->common_desc.defname,
|
|
xfd1->dual.stream[0]->rfd);
|
|
} else {
|
|
Notice3("xfd1: %s, wfd=%d, rfd=%d",
|
|
xfd1->stream.addrdesc->common_desc.defname,
|
|
xfd1->stream.wfd, xfd1->stream.rfd);
|
|
}
|
|
if (xfd2->tag==XIO_TAG_DUAL) {
|
|
Notice4("xfd2: [%s, wfd=%d] %% [%s, rfd=%d]",
|
|
xfd2->dual.stream[1]->addrdesc->common_desc.defname,
|
|
xfd2->dual.stream[1]->wfd,
|
|
xfd2->dual.stream[0]->addrdesc->common_desc.defname,
|
|
xfd2->dual.stream[0]->rfd);
|
|
} else {
|
|
Notice3("xfd2: %s, wfd=%d, rfd=%d",
|
|
xfd2->stream.addrdesc->common_desc.defname,
|
|
xfd2->stream.wfd, xfd2->stream.rfd);
|
|
}
|
|
Info5("pthread_create(%p, NULL, %s, {%d,%p,%p})",
|
|
&xfd0->stream.subthread,
|
|
(reverseA||(sfdB!=NULL)&&!reverseB)?"xioopenleftthenengine":"xioengine",
|
|
thread_arg->rw, thread_arg->xfd1, thread_arg->xfd2);
|
|
if ((_errno =
|
|
Pthread_create(&xfd0->stream.subthread, NULL,
|
|
(reverseA||(sfdB!=NULL)&&!reverseB)?xioopenleftthenengine:xioengine,
|
|
thread_arg))
|
|
!= 0) {
|
|
Error3("pthread_create(%p, {}, xioengine, %p): %s",
|
|
&xfd0->stream.subthread, thread_arg,
|
|
strerror(_errno));
|
|
xiofreefd(xfd0); xiofreefd(xfd1); xiofreefd(xfd2);
|
|
free(thread_arg); return NULL;
|
|
}
|
|
Info1("started thread "F_thread, xfd0->stream.subthread);
|
|
xfd1 = NULL;
|
|
xfd2 = NULL;
|
|
|
|
/* open protocol part */
|
|
if (xioopen_inter_dual(xfd0, rw|flags)
|
|
< 0) {
|
|
/*! close sub chain */
|
|
if (xfd0->stream.retry == 0 && !xfd0->stream.forever) {
|
|
xiofreefd(xfd0); /*! close()? */ return NULL;
|
|
}
|
|
Nanosleep(&xfd0->stream.intervall, NULL);
|
|
if (xfd0->stream.retry) --xfd0->stream.retry;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
/*!!!?*/
|
|
#if 0
|
|
xfd0->stream.howtoshut = XIOSHUT_CLOSE;
|
|
#endif
|
|
return xfd0;
|
|
}
|
|
|
|
void *xioopenleftthenengine(void *thread_void) {
|
|
struct threadarg_struct *thread_arg = thread_void;
|
|
int rw = thread_arg->rw;
|
|
xiofile_t *xfd1 = thread_arg->xfd1;
|
|
xiofile_t *xfd2 = thread_arg->xfd2;
|
|
|
|
/*! design a function with better interface */
|
|
if (xioopen_inter_dual(xfd1, rw|XIO_MAYCONVERT|XIO_MAYCHILD) < 0) {
|
|
xioclose(xfd2);
|
|
xiofreefd(xfd1);
|
|
xiofreefd(xfd2);
|
|
return NULL;
|
|
}
|
|
xioengine(thread_void);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
xiofile_t *xioparse_dual(const char **addr) {
|
|
xiofile_t *xfd;
|
|
xiosingle_t *sfd1;
|
|
int reverse;
|
|
|
|
/* check the logical direction of the current subaddress */
|
|
reverse = !(strncmp(*addr, xioparams->reversechar,
|
|
strlen(xioparams->reversechar)));
|
|
if (reverse) {
|
|
/* skip "reverse" token */
|
|
*addr += strlen(xioparams->reversechar);
|
|
}
|
|
|
|
/* we parse a single address */
|
|
if ((sfd1 = xioparse_single(addr)) == NULL) {
|
|
return NULL;
|
|
}
|
|
sfd1->reverse = reverse;
|
|
|
|
/* and now we see if we reached a dual-address separator */
|
|
if (strncmp(*addr, xioopts.pipesep, strlen(xioopts.pipesep))) {
|
|
/* no, finish */
|
|
return (xiofile_t *)sfd1;
|
|
}
|
|
|
|
/* we found the dual-address operator, so we parse the second single address
|
|
*/
|
|
*addr += strlen(xioparams->pipesep);
|
|
|
|
if ((xfd = xioallocfd()) == NULL) {
|
|
xiofreefd((xiofile_t *)sfd1);
|
|
return NULL;
|
|
}
|
|
xfd->tag = XIO_TAG_DUAL;
|
|
xfd->dual.stream[0] = sfd1;
|
|
if ((xfd->dual.stream[1] = xioparse_single(addr)) == NULL) {
|
|
xiofreefd(xfd); /*! and maybe have free some if its contents */
|
|
return NULL;
|
|
}
|
|
|
|
return xfd;
|
|
}
|
|
|
|
int xioopen_inter_dual(xiofile_t *xfd, int xioflags) {
|
|
|
|
if (xfd->tag == XIO_TAG_DUAL) {
|
|
/* a really dual address */
|
|
if ((xioflags&XIO_ACCMODE) != XIO_RDWR) {
|
|
Warn("unidirectional open of dual address");
|
|
}
|
|
|
|
/* a "usual" bidirectional stream specification, one address */
|
|
if (((xioflags&XIO_ACCMODE)+1) & (XIO_RDONLY+1)) {
|
|
if (xioopen_inter_single((xiofile_t *)xfd->dual.stream[0], XIO_RDONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC))
|
|
< 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
/*! should come before xioopensingle? */
|
|
if (((xioflags&XIO_ACCMODE)+1) & (XIO_WRONLY+1)) {
|
|
if (xioopen_inter_single((xiofile_t *)xfd->dual.stream[1], XIO_WRONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC))
|
|
< 0) {
|
|
xioclose((xiofile_t *)xfd->dual.stream[0]);
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return xioopen_inter_single(xfd, xioflags);
|
|
}
|
|
|
|
int xioopen_endpoint_dual(xiofile_t *xfd, int xioflags) {
|
|
|
|
if (xfd->tag == XIO_TAG_DUAL) {
|
|
/* a really dual address */
|
|
if ((xioflags&XIO_ACCMODE) != XIO_RDWR) {
|
|
Warn("unidirectional open of dual address");
|
|
}
|
|
|
|
/* a "usual" bidirectional stream specification, one address */
|
|
if (((xioflags&XIO_ACCMODE)+1) & (XIO_WRONLY+1)) {
|
|
if (xioopen_endpoint_single((xiofile_t *)xfd->dual.stream[1], XIO_WRONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC))
|
|
< 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
/*! should come before xioopensingle? */
|
|
if (((xioflags&XIO_ACCMODE)+1) & (XIO_RDONLY+1)) {
|
|
if (xioopen_endpoint_single((xiofile_t *)xfd->dual.stream[0], XIO_RDONLY|(xioflags&~XIO_ACCMODE&~XIO_MAYEXEC))
|
|
< 0) {
|
|
xioclose((xiofile_t *)xfd->dual.stream[1]);
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return xioopen_endpoint_single(xfd, xioflags);
|
|
}
|
|
|
|
|
|
/* parses the parameters and options of a single (sub)address.
|
|
returns 0 on success or -1 if an error occurred. */
|
|
static xiosingle_t *
|
|
xioparse_single(const char **addr /* input string; afterwards points to
|
|
first char not belonging to this
|
|
sub address */
|
|
) {
|
|
char addr0[20];
|
|
xiofile_t *xfd;
|
|
xiosingle_t *sfd;
|
|
struct xioaddrname *ae;
|
|
/*int maxparams;*/ /* max number of parameters */
|
|
const char *ends[4+1];
|
|
const char *hquotes[] = {
|
|
"'",
|
|
NULL
|
|
} ;
|
|
const char *squotes[] = {
|
|
"\"",
|
|
NULL
|
|
} ;
|
|
const char *nests[] = {
|
|
"'", "'",
|
|
"(", ")",
|
|
"[", "]",
|
|
"{", "}",
|
|
NULL
|
|
} ;
|
|
char token[512], *tokp;
|
|
size_t len;
|
|
int i;
|
|
|
|
/* init */
|
|
i = 0;
|
|
ends[i++] = xioopts.chainsep; /* default: "|" */
|
|
ends[i++] = xioopts.pipesep; /* default: "%" */
|
|
ends[i++] = ","/*xioopts.comma*/; /* default: "," */
|
|
ends[i++] = ":"/*xioopts.colon*/; /* default: ":" */
|
|
ends[i++] = NULL;
|
|
|
|
if ((xfd = xioallocfd()) == NULL) {
|
|
return NULL;
|
|
}
|
|
sfd = &xfd->stream;
|
|
sfd->argc = 0;
|
|
|
|
/* for error messages */
|
|
strncpy(addr0, *addr, sizeof(addr0)-1);
|
|
addr0[sizeof(addr0)-1] = '\0';
|
|
|
|
len = sizeof(token); tokp = token;
|
|
if (nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests,
|
|
true, true, true, false) < 0) {
|
|
Error2("keyword too long, in address \"%s%s\"", token, *addr);
|
|
}
|
|
*tokp = '\0'; /*! len? */
|
|
ae = (struct xioaddrname *)
|
|
keyw((struct wordent *)&address_names, token,
|
|
sizeof(address_names)/sizeof(struct xioaddrname)-1);
|
|
if (ae != NULL) {
|
|
/* found keyword */
|
|
sfd->addrdescs = ae->desc;
|
|
if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) {
|
|
Error1("strdup(\"%s\"): out of memory", token);
|
|
}
|
|
} else {
|
|
if (false) { /* for canonical reasons */
|
|
;
|
|
#if WITH_FDNUM
|
|
} else if (isdigit(token[0]&0xff) && token[1] == '\0') {
|
|
Info1("interpreting address \"%s\" as file descriptor", token);
|
|
sfd->addrdescs = xioaddrs_fdnum;
|
|
if ((sfd->argv[sfd->argc++] = strdup("FD")) == NULL) {
|
|
Error("strdup(\"FD\"): out of memory");
|
|
}
|
|
if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) {
|
|
Error1("strdup(\"%s\"): out of memory", token);
|
|
}
|
|
/*! check argc overflow */
|
|
#endif /* WITH_FDNUM */
|
|
#if WITH_GOPEN
|
|
} else if (strchr(token, '/')) {
|
|
Info1("interpreting address \"%s\" as file name", token);
|
|
sfd->addrdescs = xioaddrs_gopen;
|
|
if ((sfd->argv[sfd->argc++] = strdup("GOPEN")) == NULL) {
|
|
Error("strdup(\"GOPEN\"): out of memory");
|
|
}
|
|
if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) {
|
|
Error1("strdup(\"%s\"): out of memory", token);
|
|
}
|
|
/*! check argc overflow */
|
|
#endif /* WITH_GOPEN */
|
|
} else {
|
|
Error1("unknown device/address \"%s\"", token);
|
|
xiofreefd(xfd);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
while (!strncmp(*addr, xioopts.paramsep, strlen(xioopts.paramsep))) {
|
|
if (sfd->argc >= MAXARGV) {
|
|
Error1("address \"%s\": succeeds max number of parameters",
|
|
sfd->argv[0]);
|
|
}
|
|
*addr += strlen(xioopts.paramsep);
|
|
len = sizeof(token); tokp = token;
|
|
if (nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests,
|
|
true, true, true, false) != 0) {
|
|
Error2("syntax error in address \"%s%s\"", token, *addr);
|
|
}
|
|
*tokp = '\0';
|
|
if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) {
|
|
Error1("strdup(\"%s\"): out of memory", token);
|
|
}
|
|
}
|
|
|
|
if (parseopts(addr, &sfd->opts) < 0) {
|
|
xiofreefd(xfd);
|
|
return NULL;
|
|
}
|
|
|
|
return sfd;
|
|
}
|
|
|
|
/* during parsing the sub address, we did not know if it is used as inter
|
|
address or endpoint; therefore we could not select the appropriate address
|
|
descriptor. Here we already know the context and thus select the address
|
|
descriptor and check the option groups.
|
|
returns 0 on success or -1 if an error occurred */
|
|
static int
|
|
xioopen_unoverload(xiosingle_t *sfd,
|
|
int mayleft, /* what may be on left side: or'd
|
|
XIOBIT_RDWR, XIOBIT_RDONLY,
|
|
XIOBIT_WRONLY */
|
|
int *isleft, /* what the selected address desc
|
|
provides on left side: XIO_RDWR,
|
|
XIO_RDONLY, or XIO_WRONLY */
|
|
int mayright, /* what may be on right side: or'd
|
|
XIOBIT_RDWR, XIOBIT_RDONLY,
|
|
XIOBIT_WRONLY */
|
|
int *isright) /* what the selected address desc
|
|
provides on right side: XIO_RDWR,
|
|
XIO_RDONLY, or XIO_WRONLY */
|
|
{
|
|
const union xioaddr_desc **addrdescs;
|
|
int tag;
|
|
int i;
|
|
|
|
addrdescs = sfd->addrdescs;
|
|
tag = (mayright ? XIOADDR_INTER : XIOADDR_ENDPOINT);
|
|
|
|
/* look for a matching entry in the list of address descriptions */
|
|
Debug5("searching record for \"%s\" with tag=%d, numparams=%d, leftdir %d, rightdir %d",
|
|
addrdescs[0]->common_desc.defname,
|
|
tag, sfd->argc-1, mayleft, mayright);
|
|
while ((*addrdescs) != NULL) {
|
|
if ((*addrdescs)->tag == tag &&
|
|
addrdescs[0]->common_desc.numparams == sfd->argc-1 &&
|
|
(addrdescs[0]->common_desc.leftdirs & mayleft) != 0 &&
|
|
(mayright ? (addrdescs[0]->inter_desc.rightdirs & mayright) : 1)) {
|
|
break;
|
|
}
|
|
++addrdescs;
|
|
}
|
|
|
|
if (addrdescs[0] == NULL) {
|
|
if (tag == XIOADDR_ENDPOINT) {
|
|
Error3("address \"%s...\" in endpoint context, leftdirs=%d, with %d parameter(s) is not available",
|
|
sfd->argv[0], mayleft, sfd->argc-1);
|
|
} else {
|
|
Error4("address \"%s...\" in intermediate context, leftdirs=%d, rightdirs=%d, with %d parameter(s) is not available",
|
|
sfd->argv[0], mayleft, mayright, sfd->argc-1);
|
|
}
|
|
xiofreefd((xiofile_t *)sfd); return -1;
|
|
}
|
|
|
|
i = (addrdescs[0]->common_desc.leftdirs & mayleft);
|
|
*isleft = 0;
|
|
while (i>>=1) {
|
|
++*isleft;
|
|
}
|
|
if (true /*0 mayright*/) {
|
|
i = (addrdescs[0]->inter_desc.rightdirs & mayright);
|
|
*isright = 0;
|
|
while (i>>=1) {
|
|
++*isright;
|
|
}
|
|
}
|
|
sfd->tag = (*isleft + 1);
|
|
sfd->addrdesc = addrdescs[0];
|
|
if (addrdescs[0]->common_desc.howtoshut != XIOSHUT_UNSPEC)
|
|
sfd->howtoshut = addrdescs[0]->common_desc.howtoshut;
|
|
if (addrdescs[0]->common_desc.howtoclose != XIOCLOSE_UNSPEC)
|
|
sfd->howtoclose = addrdescs[0]->common_desc.howtoclose;
|
|
|
|
if (tag == XIOADDR_ENDPOINT) {
|
|
Debug1("selected record with leftdirs %d",
|
|
addrdescs[0]->common_desc.leftdirs);
|
|
} else {
|
|
Debug2("selected record with leftdirs %d, rightdirs %d",
|
|
addrdescs[0]->common_desc.leftdirs,
|
|
addrdescs[0]->inter_desc.rightdirs);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int
|
|
xioopen_inter_single(xiofile_t *xfd, int xioflags) {
|
|
const struct xioaddr_inter_desc *addrdesc;
|
|
int result;
|
|
|
|
addrdesc = &xfd->stream.addrdesc->inter_desc;
|
|
|
|
if ((xioflags&XIO_ACCMODE) == XIO_RDONLY) {
|
|
xfd->tag = XIO_TAG_RDONLY;
|
|
} else if ((xioflags&XIO_ACCMODE) == XIO_WRONLY) {
|
|
xfd->tag = XIO_TAG_WRONLY;
|
|
} else if ((xioflags&XIO_ACCMODE) == XIO_RDWR) {
|
|
xfd->tag = XIO_TAG_RDWR;
|
|
} else {
|
|
Error1("invalid mode for address \"%s\"", xfd->stream.argv[0]);
|
|
}
|
|
xfd->stream.flags &= (~XIO_ACCMODE);
|
|
xfd->stream.flags |= (xioflags & XIO_ACCMODE);
|
|
result = (*addrdesc->func)(xfd->stream.argc, xfd->stream.argv,
|
|
xfd->stream.opts, xioflags, xfd,
|
|
addrdesc->groups, addrdesc->arg1,
|
|
addrdesc->arg2, addrdesc->arg3);
|
|
return result;
|
|
}
|
|
|
|
static int
|
|
xioopen_endpoint_single(xiofile_t *xfd, int xioflags) {
|
|
const struct xioaddr_endpoint_desc *addrdesc;
|
|
int result;
|
|
|
|
addrdesc = &xfd->stream.addrdesc->endpoint_desc;
|
|
if ((xioflags&XIO_ACCMODE) == XIO_RDONLY) {
|
|
xfd->tag = XIO_TAG_RDONLY;
|
|
} else if ((xioflags&XIO_ACCMODE) == XIO_WRONLY) {
|
|
xfd->tag = XIO_TAG_WRONLY;
|
|
} else if ((xioflags&XIO_ACCMODE) == XIO_RDWR) {
|
|
xfd->tag = XIO_TAG_RDWR;
|
|
} else {
|
|
Error1("invalid mode for address \"%s\"", xfd->stream.argv[0]);
|
|
}
|
|
xfd->stream.flags &= (~XIO_ACCMODE);
|
|
xfd->stream.flags |= (xioflags & XIO_ACCMODE);
|
|
result = (*addrdesc->func)(xfd->stream.argc, xfd->stream.argv,
|
|
xfd->stream.opts, xioflags, xfd,
|
|
addrdesc->groups, addrdesc->arg1,
|
|
addrdesc->arg2, addrdesc->arg3);
|
|
return result;
|
|
}
|