socket: New option accept-count.
authorMark Wooding <mdw@distorted.org.uk>
Wed, 2 Apr 2008 08:12:02 +0000 (09:12 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Wed, 2 Apr 2008 08:12:02 +0000 (09:12 +0100)
Simply: how many times we call accept in the loop.  This doesn't have as
much affect as I'd hoped, but maybe there's some big performance sink
somewhere.

Suggested by Robin Bryce (thanks).

fw.1.in
socket.c

diff --git a/fw.1.in b/fw.1.in
index 5dc51f7..1b7d4d5 100644 (file)
--- a/fw.1.in
+++ b/fw.1.in
@@ -952,6 +952,24 @@ is given, is
 Socket sources support options; socket targets do not.  The source
 options provided are:
 .OS "Socket options"
 Socket sources support options; socket targets do not.  The source
 options provided are:
 .OS "Socket options"
+.BR socket. [ accept | accept-count ]
+.RB [ = ]
+.IR number | \c
+.B unlimited
+.OD
+Controls the number of connections that
+.B fw
+accepts at a time on a particular socket.  This parameter affects how
+.B fw
+prioritizes between keeping up with connection turnover and processing
+existing connections.  The default is 1, which strongly favours existing
+connections.  The special value
+.B unlimited
+(or
+.BR infinite )
+removes any limit, and therefore favours connection turnover.
+.OE
+.OS "Socket options"
 .B socket.conn
 .RB [ = ]
 .IR number | \c
 .B socket.conn
 .RB [ = ]
 .IR number | \c
index 53ac666..328e8f3 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -34,9 +34,10 @@ typedef struct ssource_opts {
   unsigned opt;
   unsigned conn;
   unsigned listen;
   unsigned opt;
   unsigned conn;
   unsigned listen;
+  unsigned naccept;
 } ssource_opts;
 
 } ssource_opts;
 
-static ssource_opts ssgo = { 256, 0, 5 };
+static ssource_opts ssgo = { 256, 0, 5, 1 };
 
 #define SOCKOPT_LIMIT 0u
 #define SOCKOPT_NOLIMIT 1u
 
 #define SOCKOPT_LIMIT 0u
 #define SOCKOPT_NOLIMIT 1u
@@ -290,6 +291,26 @@ static int ssource_option(source *s, scanner *sc)
     CONF_ACCEPT;
   }
 
     CONF_ACCEPT;
   }
 
+  if (strcmp(sc->d.buf, "accept") == 0 ||
+      strcmp(sc->d.buf, "accept-count") == 0) {
+    token(sc);
+    if (sc->t == '=')
+      token(sc);
+    if (sc->t != CTOK_WORD)
+      error(sc, "parse error, expected `unlimited' or number");
+    else if (isdigit((unsigned char)sc->d.buf[0])) {
+      sso->naccept = atoi(sc->d.buf);
+      if (sso->naccept == 0)
+       error(sc, "argument of `accept-count' must be positive");
+    } else {
+      sso->naccept = 0;
+      conf_enum(sc, "unlimited,infinite",
+               ENUM_ABBREV, "`accept-count' option");
+    }
+    token(sc);
+    CONF_ACCEPT;
+  }
+
   if (strcmp(sc->d.buf, "logging") == 0 ||
       strcmp(sc->d.buf, "log") == 0) {
     addr_opts *ao = ss ? ss->ao : &gsao;
   if (strcmp(sc->d.buf, "logging") == 0 ||
       strcmp(sc->d.buf, "log") == 0) {
     addr_opts *ao = ss ? ss->ao : &gsao;
@@ -335,10 +356,9 @@ static source *ssource_read(scanner *sc)
   ss->a = getaddr(sc, ADDR_SRC);
   if (ss->a->ops->initsrcopts)
     ss->ao = ss->a->ops->initsrcopts();
   ss->a = getaddr(sc, ADDR_SRC);
   if (ss->a->ops->initsrcopts)
     ss->ao = ss->a->ops->initsrcopts();
-  else {
+  else
     ss->ao = CREATE(addr_opts);
     ss->ao = CREATE(addr_opts);
-    *ss->ao = gsao;
-  }
+  *ss->ao = gsao;
   ss->o = ssgo;
   return (&ss->s);
 }
   ss->o = ssgo;
   return (&ss->s);
 }
@@ -363,66 +383,79 @@ static void ss_accept(int fd, unsigned mode, void *p)
   ssept *e;
   endpt *ee;
   reffd *r;
   ssept *e;
   endpt *ee;
   reffd *r;
+  int acceptp = 1;
+  unsigned i = 0;
 
 
-  /* --- Make the file descriptor --- */
+  while (acceptp) {
 
 
-  {
-    int opt = 1;
-    if ((r = ss->a->ops->accept(fd, ss->ao, ss->s.desc)) == 0)
-      return;
-    setsockopt(r->fd, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
-    fdflags(r->fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
-  }
-
-  /* --- Make an endpoint --- */
+    /* --- Make the file descriptor --- */
 
 
-  e = CREATE(ssept);
-  e->e.ops = &ssept_ops;
-  e->e.other = 0;
-  e->e.f = EPF_FILE;
-  e->e.t = 0;
-  e->e.in = e->e.out = r;
-  e->s = ss;
-  REFFD_INC(r);
+    {
+      int opt = 1;
+      if ((r = ss->a->ops->accept(fd, ss->ao, ss->s.desc)) == 0)
+       return;
+      setsockopt(r->fd, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
+      fdflags(r->fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
+    }
 
 
-  /* --- Obtain the target endpoint and let rip --- */
+    /* --- Make an endpoint --- */
 
 
-  if ((ee = ss->t->ops->create(ss->t, ss->s.desc)) == 0) {
-    REFFD_DEC(r);
-    REFFD_DEC(r);
-    DESTROY(e);
-    return;
-  }
-  fw_inc();
+    e = CREATE(ssept);
+    e->e.ops = &ssept_ops;
+    e->e.other = 0;
+    e->e.f = EPF_FILE;
+    e->e.t = 0;
+    e->e.in = e->e.out = r;
+    e->s = ss;
+    REFFD_INC(r);
 
 
-  /* --- Remove the listening socket if necessary --- */
+    /* --- Obtain the target endpoint and let rip --- */
 
 
-  switch (ss->o.opt) {
-    case SOCKOPT_LIMIT:
-      ss->o.conn--;
-      if (!ss->o.conn) {
-       if (!(ss->ao->f & ADDRF_NOLOG))
-         fw_log(-1, "[%s] maximum connections reached", ss->s.desc);
+    if ((ee = ss->t->ops->create(ss->t, ss->s.desc)) == 0) {
+      REFFD_DEC(r);
+      REFFD_DEC(r);
+      DESTROY(e);
+      return;
+    }
+    fw_inc();
+
+    /* --- Note that we've done one --- */
+
+    i++;
+    if (i >= ss->o.naccept)
+      acceptp = 0;
+
+    /* --- Remove the listening socket if necessary --- */
+
+    switch (ss->o.opt) {
+      case SOCKOPT_LIMIT:
+       ss->o.conn--;
+       if (!ss->o.conn) {
+         if (!(ss->ao->f & ADDRF_NOLOG))
+           fw_log(-1, "[%s] maximum connections reached", ss->s.desc);
+         sel_rmfile(&ss->r);
+         close(ss->r.fd);
+         if (ss->a->ops->unbind)
+           ss->a->ops->unbind(ss->a);
+         acceptp = 0;
+       }
+       break;
+      case SOCKOPT_NOLIMIT:
+       break;
+      case SOCKOPT_ONESHOT:
        sel_rmfile(&ss->r);
        close(ss->r.fd);
        if (ss->a->ops->unbind)
          ss->a->ops->unbind(ss->a);
        sel_rmfile(&ss->r);
        close(ss->r.fd);
        if (ss->a->ops->unbind)
          ss->a->ops->unbind(ss->a);
-      }
-      break;
-    case SOCKOPT_NOLIMIT:
-      break;
-    case SOCKOPT_ONESHOT:
-      sel_rmfile(&ss->r);
-      close(ss->r.fd);
-      if (ss->a->ops->unbind)
-       ss->a->ops->unbind(ss->a);
-      ssource_destroy(&ss->s);
-      break;
-  }
+       ssource_destroy(&ss->s);
+       acceptp = 0;
+       break;
+    }
 
 
-  /* --- Let everything else happen --- */
+    /* --- Let everything else happen --- */
 
 
-  endpt_join(&e->e, ee);
+    endpt_join(&e->e, ee);
+  }
 }
 
 /* --- @ss_listen@ --- *
 }
 
 /* --- @ss_listen@ --- *