nexmon – Rev 1

Subversion Repositories:
Rev:
/* source: xio.h */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */

#ifndef __xio_h_included
#define __xio_h_included 1

#if 1 /*!*/
#include "mytypes.h"
#include "sysutils.h"
#endif

#define XIO_MAXSOCK 2

/* Linux 2.2.10 */
#define HAVE_STRUCT_LINGER 1

#define LINETERM_RAW 0
#define LINETERM_CR 1
#define LINETERM_CRNL 2

union xioaddr_desc;
struct opt;

/* the flags argument of xioopen */
#define XIO_RDONLY  O_RDONLY /* asserted to be 0 */
#define XIO_WRONLY  O_WRONLY /* asserted to be 1 */
#define XIO_RDWR    O_RDWR   /* asserted to be 2 */
#define XIO_ACCMODE O_ACCMODE   /* must be 3 */
/* 3 is undefined */
#define XIO_MAYFORK     4 /* address is allowed to fork the program (fork),
                             especially with listen and connect addresses */
#define XIO_MAYCHILD    8 /* address is allowed to fork off a child that 
                             exec's another program or calls system() */
#define XIO_MAYEXEC    16 /* address is allowed to exec a prog (exec+nofork) */
#define XIO_MAYCONVERT 32 /* address is allowed to perform modifications on the
                             stream data, e.g. SSL, READLINE; CRLF */
#define XIO_MAYCHAIN   64 /* address is allowed to consist of a chain of
                             subaddresses that are handled by socat
                             subprocesses */
#define XIO_EMBEDDED 256        /* address is nonterminal */
#define XIO_MAYALL INT_MAX      /* all features enabled */

/* the status flags of xiofile_t */
#define XIO_DOESFORK    XIO_MAYFORK
#define XIO_DOESCHILD   XIO_MAYCHILD
#define XIO_DOESEXEC    XIO_MAYEXEC
#define XIO_DOESCONVERT XIO_MAYCONVERT
#define XIO_DOESCHAIN   XIO_MAYCHAIN

/* sometimes we use a set of allowed direction(s), a bit pattern */
#define XIOBIT_RDONLY (1<<XIO_RDONLY)
#define XIOBIT_WRONLY (1<<XIO_WRONLY)
#define XIOBIT_RDWR   (1<<XIO_RDWR)
#define XIOBIT_ALL    (XIOBIT_RDONLY|XIOBIT_WRONLY|XIOBIT_RDWR)
#define XIOBIT_ALLRD  (XIOBIT_RDONLY|XIOBIT_RDWR)
#define XIOBIT_ALLWR  (XIOBIT_WRONLY|XIOBIT_RDWR)
#define XIOBIT_ONE    (XIOBIT_RDONLY|XIOBIT_WRONLY)
/* reverse the direction pattern */
#define XIOBIT_REVERSE(x) (((x)&XIOBIT_RDWR)|(((x)&XIOBIT_RDONLY)?XIOBIT_WRONLY:0)|(((x)&XIOBIT_WRONLY)?XIOBIT_RDONLY:0))

#define XIOWITHRD(rw) ((rw+1)&(XIO_RDONLY+1))
#define XIOWITHWR(rw) ((rw+1)&(XIO_WRONLY+1))

/* methods for reading and writing, and for related checks */
#define XIODATA_READMASK        0xf000  /* mask for basic r/w method */
#define XIOREAD_STREAM          0x1000  /* read() (default) */
#define XIOREAD_RECV            0x2000  /* recvfrom() */
#define XIOREAD_PTY             0x4000  /* handle EIO */
#define XIOREAD_READLINE        0x5000  /* ... */
#define XIOREAD_OPENSSL         0x6000  /* SSL_read() */
#define XIOREAD_TEST            0x7000  /* xioread_test() */
#define XIODATA_WRITEMASK       0x0f00  /* mask for basic r/w method */
#define XIOWRITE_STREAM         0x0100  /* write() (default) */
#define XIOWRITE_SENDTO         0x0200  /* sendto() */
#define XIOWRITE_PIPE           0x0300  /* write() to alternate (pipe) Fd */
#define XIOWRITE_2PIPE          0x0400  /* write() to alternate (2pipe) Fd */
#define XIOWRITE_READLINE       0x0500  /* check for prompt */
#define XIOWRITE_OPENSSL        0x0600  /* SSL_write() */
#define XIOWRITE_TEST           0x0700  /* xiowrite_test() */
#define XIOWRITE_TESTREV        0x0800  /* xiowrite_testrev() */
/* modifiers to XIODATA_READ_RECV */
#define XIOREAD_RECV_CHECKPORT  0x0001  /* recv, check peer port */
#define XIOREAD_RECV_CHECKADDR  0x0002  /* recv, check peer address */
#define XIOREAD_RECV_CHECKRANGE 0x0004  /* recv, check if peer addr in range */
#define XIOREAD_RECV_ONESHOT    0x0008  /* give EOF after first packet */
#define XIOREAD_RECV_SKIPIP     0x0010  /* recv, skip IPv4 header */
#define XIOREAD_RECV_FROM       0x0020  /* remember peer for replying */

/* combinations */
#define XIODATA_MASK            (XIODATA_READMASK|XIODATA_WRITEMASK)
#define XIODATA_STREAM          (XIOREAD_STREAM|XIOWRITE_STREAM)
#define XIODATA_RECVFROM        (XIOREAD_RECV|XIOWRITE_SENDTO|XIOREAD_RECV_CHECKPORT|XIOREAD_RECV_CHECKADDR|XIOREAD_RECV_FROM)
#define XIODATA_RECVFROM_SKIPIP (XIODATA_RECVFROM|XIOREAD_RECV_SKIPIP)
#define XIODATA_RECVFROM_ONE    (XIODATA_RECVFROM|XIOREAD_RECV_ONESHOT)
#define XIODATA_RECVFROM_SKIPIP_ONE     (XIODATA_RECVFROM_SKIPIP|XIOREAD_RECV_ONESHOT)
#define XIODATA_RECV            (XIOREAD_RECV|XIOWRITE_SENDTO|XIOREAD_RECV_CHECKRANGE)
#define XIODATA_RECV_SKIPIP     (XIODATA_RECV|XIOREAD_RECV_SKIPIP)
#define XIODATA_PIPE            (XIOREAD_STREAM|XIOWRITE_PIPE)
#define XIODATA_2PIPE           (XIOREAD_STREAM|XIOWRITE_2PIPE)
#define XIODATA_PTY             (XIOREAD_PTY|XIOWRITE_STREAM)
#define XIODATA_READLINE        (XIOREAD_READLINE|XIOWRITE_STREAM)
#define XIODATA_OPENSSL         (XIOREAD_OPENSSL|XIOWRITE_OPENSSL)
#define XIODATA_TEST            (XIOREAD_TEST|XIOWRITE_TEST)
#define XIODATA_TESTUNI         XIOWRITE_TEST
#define XIODATA_TESTREV         XIOWRITE_TESTREV

/* XIOSHUT_* define the actions on shutdown of the address */
/*  */
#define XIOSHUTRD_MASK          0x00f0
#define XIOSHUTWR_MASK          0x000f
#define XIOSHUTSPEC_MASK        0xff00  /* specific action */
#define XIOSHUTRD_UNSPEC        0x0000
#define XIOSHUTWR_UNSPEC        0x0000
#define XIOSHUTRD_NONE          0x0010  /* no action - e.g. stdin */
#define XIOSHUTWR_NONE          0x0001  /* no action - e.g. stdout */
#define XIOSHUTRD_CLOSE         0x0020  /* close() */
#define XIOSHUTWR_CLOSE         0x0002  /* close() */
#define XIOSHUTRD_DOWN          0x0030  /* shutdown(, SHUT_RD) */
#define XIOSHUTWR_DOWN          0x0003  /* shutdown(, SHUT_WR) */
#define XIOSHUTRD_SIGHUP        0x0040  /* kill sub process */
#define XIOSHUTWR_SIGHUP        0x0004  /* flush sub process with SIGHPUP */
#define XIOSHUTRD_SIGTERM       0x0050  /* kill sub process with SIGTERM */
#define XIOSHUTWR_SIGTERM       0x0005  /* kill sub process with SIGTERM */
#define XIOSHUTWR_SIGKILL       0x0006  /* kill sub process with SIGKILL */
#define XIOSHUTWR_NULL          0x0007  /* send empty packet (dgram socket) */
#define XIOSHUT_UNSPEC          (XIOSHUTRD_UNSPEC|XIOSHUTWR_UNSPEC)
#define XIOSHUT_NONE            (XIOSHUTRD_NONE|XIOSHUTWR_NONE)
#define XIOSHUT_CLOSE           (XIOSHUTRD_CLOSE|XIOSHUTWR_CLOSE)
#define XIOSHUT_DOWN            (XIOSHUTRD_DOWN|XIOSHUTWR_DOWN)
#define XIOSHUT_KILL            (XIOSHUTRD_KILL|XIOSHUTWR_KILL)
#define XIOSHUT_NULL            (XIOSHUTRD_DOWN|XIOSHUTWR_NULL)
#define XIOSHUT_PTYEOF          0x0100  /* change pty to icanon and write VEOF */
#define XIOSHUT_OPENSSL         0x0101  /* specific action on openssl */
/*!!!*/

#define XIOCLOSE_UNSPEC         0x0000  /* after init, when no end-close... option */
#define XIOCLOSE_NONE           0x0001  /* no action */
#define XIOCLOSE_CLOSE          0x0002  /* close() */
#define XIOCLOSE_SIGTERM        0x0003  /* send SIGTERM to sub process */
#define XIOCLOSE_SIGKILL        0x0004  /* send SIGKILL to sub process */
#define XIOCLOSE_CLOSE_SIGTERM  0x0005  /* close fd, then send SIGTERM */
#define XIOCLOSE_CLOSE_SIGKILL  0x0006  /* close fd, then send SIGKILL */
#define XIOCLOSE_SLEEP_SIGTERM  0x0007  /* short sleep, then SIGTERM */
#define XIOCLOSE_OPENSSL        0x0101
#define XIOCLOSE_READLINE       0x0102

/* these are the values allowed for the "enum xiotag  tag" flag of the "struct
   single" and "union bipipe" (xiofile_t) structures. */
enum xiotag {
   XIO_TAG_INVALID,     /* the record is not in use */
   XIO_TAG_RDONLY,      /* this is a single read-only stream */
   XIO_TAG_WRONLY,      /* this is a single write-only stream */
   XIO_TAG_RDWR,        /* this is a single read-write stream */
   XIO_TAG_DUAL         /* this is a dual stream, consisting of two single
                           streams */
} ;

/* inter address communication types */
enum xiocomm {
   XIOCOMM_SOCKETPAIRS, /* two unix (local) socket pairs */
   XIOCOMM_PIPES,       /* two unnamed pipes (fifos) */
   XIOCOMM_SOCKETPAIR,  /* one unix (local) socket pairs */
   XIOCOMM_PTYS,        /* two pseudo terminals, each from master to slave */
   XIOCOMM_PTY,         /* one pseudo terminal, master on left side */
   XIOCOMM_TCP,         /* one TCP socket pair */
   XIOCOMM_TCP4,        /* one TCP/IPv4 socket pair */
   XIOCOMM_TCP4_LISTEN, /* right side listens for TCP/IPv4, left connects */
} ;

union bipipe;


#define XIOADDR_ENDPOINT 0      /* endpoint address */
#define XIOADDR_INTER 1 /* inter address */
#define XIOADDR_SYS XIOADDR_ENDPOINT
#define XIOADDR_PROT XIOADDR_INTER

/* one side of an "extended socketpair" */
typedef struct fddesc {
   int rfd;             /* used for reading */  
   int wfd;             /* used for writing */  
   bool single;         /* rfd and wfd refer to the same "file" */
   int dtype;           /* specifies methods for reading and writing */
   int howtoshut;       /* specifies method for shutting down wfd */
   int howtoclose;      /* specifies method for closing rfd and wfd */
} xiofd_t;

struct xioaddr_inter_desc {
   int tag;             /* 0: endpoint addr; 1: inter addr */
   const char *defname; /* main (canonical) name of address */
   int numparams;       /* number of required parameters */
   int leftdirs;        /* set of data directions supported on left side:
                           e.g. XIOBIT_RDONLY|XIOBIT_WRONLY|XIOBIT_RDWR */
   unsigned groups;
   int howtoshut;
   int howtoclose;
   int (*func)(int argc, const char *argv[], struct opt *opts, int rw, union bipipe *fd, unsigned groups,
               int arg1, int arg2, int arg3);
   int arg1;
   int arg2;
   int arg3;
   int rightdirs;
#if WITH_HELP
   const char *syntax;
#endif
} ;

struct xioaddr_endpoint_desc {
   int tag;             /* XIOADDR_ENDPOINT, XIOADDR_INTER */
   const char *defname; /* main (canonical) name of address */
   int numparams;       /* number of required parameters */
   int leftdirs;        /* XIOBIT_* */
   unsigned groups;
   int howtoshut;
   int howtoclose;
   int (*func)(int argc, const char *argv[], struct opt *opts, int rw, union bipipe *fd, unsigned groups,
               int arg1, int arg2, int arg3);
   int arg1;
   int arg2;
   int arg3;
#if WITH_HELP
   const char *syntax;
#endif
} ;


struct xioaddr_common_desc {
   int tag;             /* 0: endpoint addr; 1: inter addr */
   const char *defname; /* main (canonical) name of address */
   int numparams;       /* number of required parameters */
   int leftdirs;
   unsigned groups;
   int howtoshut;
   int howtoclose;
} ;


union xioaddr_desc {
   int tag;             /* 0: endpoint addr; 1: inter addr */
   struct xioaddr_common_desc common_desc;
   struct xioaddr_inter_desc inter_desc;
   struct xioaddr_endpoint_desc endpoint_desc;
} ;

union xioaddr_descp {
   struct xioaddr_common_desc *
common_desc;
   int *tag;            /* 0: endpoint addr; 1: inter addr */
   struct xioaddr_inter_desc *inter_desc;
   struct xioaddr_endpoint_desc *endpoint_desc;
} ;


/*!!! this to xio-sockd4.h */
struct socks4head {
   uint8_t  version;
   uint8_t  action;
   uint16_t port;
   uint32_t dest;
} ;

/* global XIO options/parameters */
typedef struct {
   bool strictopts;
   const char *pipesep;
   const char *paramsep;
   const char *optionsep;
   char ip4portsep;
   char ip6portsep;     /* do not change, might be hardcoded somewhere! */
   const char *syslogfac;       /* syslog facility (only with mixed mode) */
   char default_ip;     /* default prot.fam for IP based listen ('4' or '6') */
   char preferred_ip;   /* preferred prot.fam. for name resolution ('0' for
                           unspecified, '4', or '6') */
   char *reversechar;
   char *chainsep;
   size_t bufsiz;
   bool verbose;
   bool verbhex;
   bool debug;
   char logopt;         /* y..syslog; s..stderr; f..file; m..mixed */
   struct timeval total_timeout;/* when nothing happens, die after seconds */
   struct timeval pollintv;     /* with ignoreeof, reread after seconds */
   struct timeval closwait;     /* after close of x, die after seconds */
   bool lefttoright;    /* first addr ro, second addr wo */
   bool righttoleft;    /* first addr wo, second addr ro */
   int pipetype;        /* communication (pipe) type; 0: 2 unidirectional
                           socketpairs; 1: 2 pipes; 2: 1 socketpair */
} xioopts_t;

/* pack the description of a lock file */
typedef struct {
   const char     *lockfile;    /* name of lockfile; NULL if no locking */
   bool            waitlock;    /* dont't exit when already locked */
   struct timespec intervall;   /* polling intervall */
} xiolock_t;

#define MAXARGV 8

/* a non-dual file descriptor */ 
typedef struct single {
   enum xiotag tag;     /* see  enum xiotag  */
   const union xioaddr_desc *addrdesc;
   int    flags;
   /* until here, keep consistent with bipipe.common !!! */
#if WITH_RETRY
   unsigned int retry;  /* retry opening this many times */
   bool forever;        /* retry opening forever */
   struct timespec intervall;   /* wait so long between retries */
#endif /* WITH_RETRY */
   bool   ignoreeof;    /* option ignoreeof; do not pass eof condition to app*/
   int    eof;          /* 1..exec'd child has died, but no explicit eof
                           occurred 
                           2..fd0 has reached EOF (definitely; never with
                           ignoreeof! */
   size_t wsize;        /* write always this size; 0..all available */
   size_t readbytes;    /* read only so many bytes; 0...unlimited */
   size_t actbytes;     /* so many bytes still to be read (when readbytes!=0)*/
   xiolock_t lock;      /* parameters of lockfile */
   bool      havelock;  /* we are happy owner of the above lock */
   /* until here, keep consistent with bipipe.dual ! */
   int reverse;         /* valid during parse and overload, before open:
                           will this (inter) address be integrated forward or
                           reverse? */
   const union xioaddr_desc **addrdescs;
                        /* valid after parse, before overload:
                           the list of possible address descriptors derived
                           from addr keyword, one of which will be selected by
                           context and num of parameters */
   int    closing;      /* 0..write channel is up, 1..just shutdown write ch.,
                           2..counting down closing timeout, 3..no more write
                           possible */
   bool      cool_write;        /* downlevel EPIPE, ECONNRESET to notice */
   int argc;            /* number of fields in argv */
   const char *argv[MAXARGV];   /* address keyword, required args */
   struct opt *opts;    /* the options of this address */
   int    lineterm;     /* 0..dont touch; 1..CR; 2..CRNL on extern data */
   int    rfd;  /* was fd1 */
   int    wfd;  /* was fd2 */
   pid_t  subaddrpid;   /* pid of subaddress (process handling next addr in
                           chain) */
   int    subaddrstat;  /* state of subaddress process
                           0...no sub address process
                           1...running
                           -1...ended (aborted?) */
   int    subaddrexit;  /* if subaddstat==-1: exit code of sub process */
   bool   opt_unlink_close;     /* option unlink_close */
   char  *unlink_close; /* name of a symlink or unix socket to be removed */
   int dtype;
   int howtoshut;       /* method for shutting down xfds */
   int howtoclose;      /* method for closing xfds */
#if _WITH_SOCKET
   union sockaddr_union peersa;
   socklen_t salen;
#endif /* _WITH_SOCKET */
#if WITH_TERMIOS
   bool ttyvalid;               /* the following struct is valid */
   struct termios savetty;      /* save orig tty settings for later restore */
#endif /* WITH_TERMIOS */
   /*0 const char *name;*/              /* only with END_UNLINK */
   struct {                     /* this was for exec only, now for embedded */
      pid_t pid;                /* child PID, with EXEC: */
      int (*sigchild)(struct single *); /* callback after sigchild */
   } child;
   pid_t ppid;                  /* parent pid, only if we send it signals */
   int escape;                  /* escape character; -1 for no escape */
   bool actescape;              /* escape character found in input data */
   pthread_t subthread;         /* thread handling next inter-addr in chain */
   union {
#if 0
      struct {
         int fdout;             /* use fd for output */
      } bipipe;
#endif
#if _WITH_SOCKET
      struct {
         struct timeval connect_timeout; /* how long to hang in connect() */
         union sockaddr_union la;       /* local socket address */
         bool null_eof;         /* with dgram: empty packet means EOF */
         bool dorange;
         struct xiorange range; /* restrictions for peer address */
#if _WITH_IP4 || _WITH_IP6
         struct {
            unsigned int res_opts[2];   /* bits to be set in _res.options are
                                       at [0], bits to be cleared are at [1] */
            bool   dosourceport;
            uint16_t sourceport;        /* host byte order */
            bool     lowport;
#if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
            bool   dolibwrap;
            char    *libwrapname;
            char    *tcpwrap_etc;
            char    *hosts_allow_table;
            char    *hosts_deny_table;
#endif
         } ip;
#endif /* _WITH_IP4 || _WITH_IP6 */
#if WITH_UNIX
         struct {
            bool     tight;
         } un;
#endif /* WITH_UNIX */
      } socket;
#endif /* _WITH_SOCKET */
      struct {
         pid_t pid;             /* child PID, with EXEC: */
         int fdout;             /* use fd for output if two pipes */
      } exec;
#if WITH_READLINE
      struct {
         char *history_file;
         char *prompt;          /* static prompt, passed to readline() */
         size_t dynbytes;       /* length of buffer for dynamic prompt */
         char *dynprompt;       /* the dynamic prompt */
         char *dynend;          /* current end of dynamic prompt */
#if HAVE_REGEX_H
         bool    hasnoecho;     /* following regex is set */
         regex_t noecho;        /* if it matches the prompt, input is silent */
#endif
      } readline;
#endif /* WITH_READLINE */
#if WITH_SOCKS4_SERVER
      struct {
         int state;             /* state of socks4 protocol negotiation */
         /* we cannot rely on all request data arriving at once */
         struct socks4head head;
         char *userid;
         char *hostname;        /* socks4a only */
         /* the following structs are an experiment for future synchronization
            mechanisms */
         struct {
            size_t canrecv;
            size_t wantwrite;
            void *inbuff;
            size_t inbuflen;    /* length of buffer */
            size_t bytes;       /* current bytes in buffer */
         } proto;
         struct {
            size_t canrecv;
            size_t wantwrite;
         } peer_proto;
         struct {
            size_t canrecv;
            size_t wantwrite;
            int _errno;
         } data;
         struct {
            size_t canrecv;
            size_t wantwrite;
         } peer_data;
      } socks4d;
#endif /* WITH_SOCKS4_SERVER */
#if WITH_OPENSSL
      struct {
         struct timeval connect_timeout; /* how long to hang in connect() */
         SSL *ssl;
         SSL_CTX* ctx;
      } openssl;
#endif /* WITH_OPENSSL */
#if WITH_TUN
      struct {
         short iff_opts[2];     /* ifr flags, using OFUNC_OFFSET_MASKS */
      } tun;
#endif /* WITH_TUN */
#if _WITH_GZIP
      struct {
         gzFile in;     /* for reading (uncompressing from stream to API) */
         gzFile out;    /* for writing (compressing from API to stream) */
         int level;
      } gzip;
#endif /* _WITH_GZIP */
   } para;
} xiosingle_t;

/* rw: 0..read, 1..write, 2..r/w */
/* when implementing a new address type take care of following topics:
   . be aware that xioopen_single is used for O_RDONLY, O_WRONLY, and O_RDWR data
   . which options are allowed (option groups)
   . implement application of all these options
   . set FD_CLOEXEC on new file descriptors BEFORE the cloexec option might be
     applied
   .
*/

typedef union bipipe {
   enum xiotag    tag;
   struct {
      enum xiotag tag;
      const union xioaddr_desc *addrdesc;
      int         flags;
   } common;
   struct single  stream;
   struct {
      enum xiotag tag;
      const union xioaddr_desc *addrdesc;
      int         flags;        /* compatible to fcntl(.., F_GETFL, ..) */
#if WITH_RETRY
      unsigned retry;   /* retry opening this many times */
      bool forever;     /* retry opening forever */
      struct timespec intervall;        /* wait so long between retries */
#endif /* WITH_RETRY */
      bool        ignoreeof;
      int         eof;          /* fd0 has reached EOF */
      size_t      wsize;        /* write always this size; 0..all available */
      size_t readbytes; /* read only so many bytes; 0...unlimited */
      size_t actbytes;  /* so many bytes still to be read */
      xiolock_t lock;   /* parameters of lockfile */
      bool      havelock;       /* we are happy owner of the above lock */
      /* until here, keep consistent with struct single ! */
      xiosingle_t *stream[2];   /* input stream, output stream */
   } dual;
} xiofile_t;


#define XIO_WRITABLE(s) (((s)->common.flags+1)&2)
#define XIO_READABLE(s) (((s)->common.flags+1)&1)
#define XIO_RDSTREAM(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[0]:&(s)->stream)
#define XIO_WRSTREAM(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[1]:&(s)->stream)
#define XIO_GETRDFD(s) (((s)->tag==XIO_TAG_DUAL)?(s)->dual.stream[0]->rfd:(s)->stream.rfd)
#define _XIO_GETWRFD(s) ((s)->wfd)
#define XIO_GETWRFD(s) (((s)->tag==XIO_TAG_DUAL)?_XIO_GETWRFD((s)->dual.stream[1]):_XIO_GETWRFD(&(s)->stream))
#define XIO_EOF(s) (XIO_RDSTREAM(s)->eof && !XIO_RDSTREAM(s)->ignoreeof)

typedef unsigned long flags_t;

union integral {
   int            u_bool;
   uint8_t        u_byte;
   gid_t          u_gidt;
   int            u_int;
   long           u_long;
#if HAVE_TYPE_LONGLONG
   long long      u_longlong;
#endif
   double         u_double;
   mode_t         u_modet;
   short          u_short;
   size_t         u_sizet;
   char          *u_string;
   uid_t          u_uidt;
   unsigned int   u_uint;
   unsigned long  u_ulong;
   unsigned short u_ushort;
   uint16_t       u_2bytes;
   void          *u_ptr;
   flags_t        u_flag;
   struct {
      uint8_t    *b_data;
      size_t      b_len;
   }              u_bin;
   struct timeval u_timeval;
#if HAVE_STRUCT_LINGER
   struct linger  u_linger;
#endif /* HAVE_STRUCT_LINGER */
#if HAVE_STRUCT_TIMESPEC        
   struct timespec u_timespec;
#endif /* HAVE_STRUCT_TIMESPEC */
#if HAVE_STRUCT_IP_MREQ || HAVE_STRUCT_IP_MREQN
   struct {
      char *multiaddr;
      char *param2;     /* address, interface */
#if HAVE_STRUCT_IP_MREQN
      char ifindex[IF_NAMESIZE+1];
#endif
   } u_ip_mreq;
#endif
#if WITH_IP4
   struct in_addr  u_ip4addr;
#endif
} ;

/* some aliases */
 
#if HAVE_BASIC_OFF_T==3
#  define u_off u_int
#elif HAVE_BASIC_OFF_T==5
#  define u_off u_long
#elif HAVE_BASIC_OFF_T==7
#  define u_off u_longlong
#else
#  error "unexpected size of off_t, please report this as bug"
#endif

#if defined(HAVE_BASIC_OFF64_T) && HAVE_BASIC_OFF64_T
#  if HAVE_BASIC_OFF64_T==5
#     define u_off64 u_long
#  elif HAVE_BASIC_OFF64_T==7
#     define u_off64 u_longlong
#  else
#     error "unexpected size of off64_t, please report this as bug"
#  endif
#endif /* defined(HAVE_BASIC_OFF64_T) && HAVE_BASIC_OFF64_T */


/* this handles option instances, for communication between subroutines */
struct opt {
   const struct optdesc *desc;
   union integral value;
   union integral value2;
   union integral value3;
} ;

/* with threading, the arguments indirectly passed to xioengine() */
struct threadarg_struct {
   int rw;      /* one of XIO_RDONLY, ... */
   xiofile_t *xfd1;
   xiofile_t *xfd2;
} ;

extern const char *PIPESEP;
extern xiofile_t *sock[XIO_MAXSOCK];    /*!!!*/

extern int num_child;

/* return values of xioopensingle */
#define STAT_OK         0
#define STAT_WARNING    1
#define STAT_EXIT       2
#define STAT_NOACTION   3       /* by retropt_* when option not applied */
#define STAT_RETRYNOW   -1      /* only after timeouts useful ? */
#define STAT_RETRYLATER -2      /* address cannot be opened, but user might
                                   change something in the filesystem etc. to
                                   make this process succeed later. */
#define STAT_NORETRY    -3      /* address syntax error, not implemented etc;
                                   not even by external changes correctable */

extern int xioinitialize(int xioflags);
extern int xioinitialize2(void);
extern pid_t xio_fork(bool subchild, int level);
extern int xio_forked_inchild(void);
extern int xiosetopt(char what, const char *arg);
extern int xioinqopt(char what, char *arg, size_t n);
extern xiofile_t *xioopen(const char *args, int xioflags);
extern xiofile_t *xioopenx(const char *addr, int xioflags, int infd, int outfd);
extern int xiosocketpair2(int pf, int socktype, int protocol, int sv[2]);
extern int xiosocketpair3(xiofile_t **xfd1p, xiofile_t **xfd2p, int how, ...);
extern int xiopty(int useptmx, int *ttyfdp, int *ptyfdp);
extern int xiocommpair(int commtype, bool lefttoright, bool righttoleft,
                       int dual, xiofd_t *left, xiofd_t *right, ...);

extern int xioopensingle(char *addr, xiosingle_t *fd, int xioflags);
extern int xioopenhelp(FILE *of, int level);

/* must be outside function for use by childdied handler */
extern xiofile_t *xioallocfd(void);
extern void xiofreefd(xiofile_t *xfd);

extern int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *));
extern int xiosetchilddied(void);
extern int xio_opt_signal(pid_t pid, int signum);

extern void *xioengine(void *thread_arg);
extern int _socat(xiofile_t *xfd1, xiofile_t *xfd2);
extern ssize_t xioread(xiofile_t *sock1, void *buff, size_t bufsiz);
extern ssize_t xiopending(xiofile_t *sock1);
extern ssize_t xiowrite(xiofile_t *sock1, const void *buff, size_t bufsiz);
extern int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
                unsigned char **buff, size_t bufsiz, bool righttoleft);
extern int xioshutdown(xiofile_t *sock, int how);

extern int xioclose(xiofile_t *sock);
extern void xioexit(void);

extern int (*xiohook_newchild)(void);   /* xio calls this function from a new child process */
extern int socat_sigchild(struct single *file);


extern xioopts_t xioopts, *xioparams;


#endif /* !defined(__xio_h_included) */