about summary refs log tree commit diff
path: root/src/conn-tools/s6-ioconnect.c
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2015-01-15 20:14:44 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2015-01-15 20:14:44 +0000
commit87c5b2118efcee65eeda3f743d081ea9c2b866d9 (patch)
tree31ca07d6134adf44bc3d58f4fcf4ea8be9cb7dbb /src/conn-tools/s6-ioconnect.c
parentcd2500fcc704287c4994a3253b593593c867913e (diff)
downloads6-87c5b2118efcee65eeda3f743d081ea9c2b866d9.tar.gz
s6-87c5b2118efcee65eeda3f743d081ea9c2b866d9.tar.xz
s6-87c5b2118efcee65eeda3f743d081ea9c2b866d9.zip
Move Unix domain utilities and access control utilites,
as well as the accessrules library, from s6-networking to here
Diffstat (limited to 'src/conn-tools/s6-ioconnect.c')
-rw-r--r--src/conn-tools/s6-ioconnect.c187
1 files changed, 187 insertions, 0 deletions
diff --git a/src/conn-tools/s6-ioconnect.c b/src/conn-tools/s6-ioconnect.c
new file mode 100644
index 0000000..a0217bb
--- /dev/null
+++ b/src/conn-tools/s6-ioconnect.c
@@ -0,0 +1,187 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <signal.h>
+#include <skalibs/uint.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/error.h>
+#include <skalibs/iobuffer.h>
+#include <skalibs/sig.h>
+#include <skalibs/selfpipe.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/tai.h>
+#include <skalibs/iopause.h>
+#include <skalibs/djbunix.h>
+
+#define USAGE "s6-ioconnect [ -t timeout ] [ -r fdr ] [ -w fdw ] [ -0 ] [ -1 ] [ -6 ] [ -7 ]"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+
+typedef struct ioblah_s ioblah_t, *ioblah_t_ref ;
+struct ioblah_s
+{
+  unsigned int fd ;
+  unsigned int xindex ;
+  unsigned int flagsocket : 1 ;
+  unsigned int flagopen : 1 ;
+} ;
+
+static ioblah_t a[2][2] = { { { 0, 4, 0, 1 }, { 7, 4, 0, 1 } }, { { 6, 4, 0, 1 }, { 1, 4, 0, 1 } } } ;
+static iobuffer b[2] ;
+static iopause_fd x[5] = { { -1, IOPAUSE_READ, 0 } } ;
+
+static void closeit (unsigned int i, unsigned int j)
+{
+  if (a[i][j].flagsocket)
+  {
+    if ((shutdown(a[i][j].fd, j) < 0) && (errno != ENOTSOCK) && (errno != ENOTCONN))
+      strerr_warnwu4sys("shutdown ", i ? "incoming" : "outgoing", " socket for ", j ? "writing" : "reading") ;
+  }
+  fd_close(a[i][j].fd) ;
+  a[i][j].flagopen = 0 ;
+  a[i][j].xindex = 5 ;
+}
+
+static inline void finishit (unsigned int i)
+{
+  closeit(i, 1) ;
+  iobuffer_finish(&b[i]) ;
+}
+
+static void handle_signals (void)
+{
+  for (;;)
+  {
+    char c = selfpipe_read() ;
+    switch (c)
+    {
+      case -1 : strerr_diefu1sys(111, "selfpipe_read") ;
+      case 0 : return ;
+      case SIGTERM :
+      {
+        if (a[0][0].xindex < 5) x[a[0][0].xindex].revents |= IOPAUSE_EXCEPT ;
+        if (a[1][0].xindex < 5) x[a[1][0].xindex].revents |= IOPAUSE_EXCEPT ;
+        break ;
+      }
+      default :
+        strerr_dief1x(101, "internal error: inconsistent signal state. Please submit a bug-report.") ;
+    }
+  }
+}
+
+int main (int argc, char const *const *argv)
+{
+  tain_t tto ;
+  register unsigned int i, j ;
+  PROG = "s6-ioconnect" ;
+  {
+    subgetopt_t l = SUBGETOPT_ZERO ;
+    unsigned int t = 0 ;
+    for (;;)
+    {
+      register int opt = subgetopt_r(argc, argv, "0167t:r:w:", &l) ;
+      if (opt < 0) break ;
+      switch (opt)
+      {
+        case '0' : a[0][0].flagsocket = 1 ; break ;
+        case '1' : a[1][1].flagsocket = 1 ; break ;
+        case '6' : a[1][0].flagsocket = 1 ; break ;
+        case '7' : a[0][1].flagsocket = 1 ; break ;
+        case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ;
+        case 'r' : if (!uint0_scan(l.arg, &a[1][0].fd)) dieusage() ; break ;
+        case 'w' : if (!uint0_scan(l.arg, &a[0][1].fd)) dieusage() ; break ;
+        default : dieusage() ;
+      }
+    }
+    if (t) tain_from_millisecs(&tto, t) ; else tto = tain_infinite_relative ;
+    argc -= l.ind ; argv += l.ind ;
+  }
+  if ((a[0][1].fd < 3) || (a[1][0].fd < 3)) dieusage() ;
+  for (i = 0 ; i < 2 ; i++)
+  {
+    for (j = 0 ; j < 2 ; j++)
+      if (ndelay_on(a[i][j].fd) == -1) strerr_diefu1sys(111, "ndelay_on") ;
+    if (!iobuffer_init(&b[i], a[i][0].fd, a[i][1].fd) < 0) strerr_diefu1sys(111, "iobuffer_init") ;
+  }
+  if (sig_ignore(SIGPIPE) == -1) strerr_diefu1sys(111, "sig_ignore") ;
+  tain_now_g() ;
+  x[0].fd = selfpipe_init() ;
+  if (x[0].fd < 0) strerr_diefu1sys(111, "selfpipe_init") ;
+  if (selfpipe_trap(SIGTERM) < 0)
+    strerr_diefu1sys(111, "trap SIGTERM") ;
+
+  for (;;)
+  {
+    tain_t deadline ;
+    unsigned int xlen = 1 ;
+    int r ;
+
+    tain_add_g(&deadline, iobuffer_isempty(&b[0]) && iobuffer_isempty(&b[1]) ? &tto : &tain_infinite_relative) ;
+    for (i = 0 ; i < 2 ; i++)
+    {
+      a[i][0].xindex = 5 ;
+      if (a[i][0].flagopen && iobuffer_isreadable(&b[i]))
+      {
+        x[xlen].fd = a[i][0].fd ;
+        x[xlen].events = IOPAUSE_READ ;
+        a[i][0].xindex = xlen++ ;
+      }
+      a[i][1].xindex = 5 ;
+      if (a[i][1].flagopen)
+      {
+        x[xlen].fd = a[i][1].fd ;
+        x[xlen].events = IOPAUSE_EXCEPT | (iobuffer_isempty(&b[i]) ? 0 : IOPAUSE_WRITE) ;
+        a[i][1].xindex = xlen++ ;
+      }
+    }
+    if (xlen <= 1) break ;
+
+    r = iopause_g(x, xlen, &deadline) ;
+    if (r < 0) strerr_diefu1sys(111, "iopause") ;
+    else if (!r) return 1 ;
+
+    if (x[0].revents & IOPAUSE_READ) handle_signals() ;
+
+    for (i = 0 ; i < 2 ; i++) if (a[i][1].xindex < 5)
+    {
+      if (x[a[i][1].xindex].revents & IOPAUSE_WRITE)
+      {
+        if (!iobuffer_flush(&b[i]))
+        {
+          if (!error_isagain(errno)) x[a[i][1].xindex].revents |= IOPAUSE_EXCEPT ;
+        }
+        else if (!a[i][0].flagopen) finishit(i) ;
+      }
+      if (x[a[i][1].xindex].revents & IOPAUSE_EXCEPT)
+      {
+        if (!iobuffer_isempty(&b[i]))
+        {
+          iobuffer_flush(&b[i]) ; /* sets errno */
+          strerr_warnwu3sys("write ", i ? "incoming" : "outgoing", " data") ;
+        }
+        closeit(i, 0) ; finishit(i) ;
+      }
+    }
+
+    for (i = 0 ; i < 2 ; i++) if (a[i][0].xindex < 5)
+    {
+      if (x[a[i][0].xindex].revents & IOPAUSE_READ)
+      {
+        if (sanitize_read(iobuffer_fill(&b[i])) < 0)
+        {
+          if (errno != EPIPE) strerr_warnwu3sys("read ", i ? "incoming" : "outgoing", " data") ;
+          x[a[i][0].xindex].revents |= IOPAUSE_EXCEPT ;
+        }
+      }
+      if (x[a[i][0].xindex].revents & IOPAUSE_EXCEPT)
+      {
+        closeit(i, 0) ;
+        if (iobuffer_isempty(&b[i])) finishit(i) ;
+      }
+    }
+  }
+  return 0 ;
+}