Remove listener even if connection option isn't SOCKOPT_LIMITED.
[fwd] / socket.c
index 6df5c4d..afa3dc0 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: socket.c,v 1.2 1999/07/27 18:30:53 mdw Exp $
+ * $Id: socket.c,v 1.5 2000/03/23 23:20:42 mdw Exp $
  *
  * Socket source and target definitions
  *
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: socket.c,v $
+ * Revision 1.5  2000/03/23 23:20:42  mdw
+ * Remove listener even if connection option isn't SOCKOPT_LIMITED.
+ *
+ * Revision 1.4  1999/12/22 15:44:25  mdw
+ * Fix log message.
+ *
+ * Revision 1.3  1999/10/22 22:48:36  mdw
+ * New connection options: unlimited concurrent connections, and one-shot
+ * listening sockets.
+ *
  * Revision 1.2  1999/07/27 18:30:53  mdw
  * Various minor portability fixes.
  *
@@ -43,6 +53,7 @@
 
 #include <ctype.h>
 #include <errno.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 /* --- Socket source options --- */
 
 typedef struct ssource_opts {
+  unsigned opt;
   unsigned conn;
 } ssource_opts;
 
-static ssource_opts ssgo = { 256 };
+static ssource_opts ssgo = { 256, 0 };
+
+#define SOCKOPT_LIMIT 0u
+#define SOCKOPT_NOLIMIT 1u
+#define SOCKOPT_ONESHOT 2u
 
 /* --- Socket source --- */
 
@@ -213,11 +229,11 @@ static void ssept_close(endpt *e)
 {
   ssept *ee = (ssept *)e;
 
-  if (!ee->s->o.conn) {
-    ee->s->o.conn++;
-    ss_listen(ee->s);
-  } else
+  if (ee->s->o.opt == SOCKOPT_LIMIT) {
     ee->s->o.conn++;
+    if (ee->s->o.conn == 1)
+      ss_listen(ee->s);
+  }
   REFFD_DEC(ee->e.in);
   REFFD_DEC(ee->e.out);
   fw_dec();
@@ -293,11 +309,11 @@ static void stept_go(int fd, void *p)
 /* --- Socket endpoint definition --- */
 
 static endpt_ops ssept_ops = {
-  0, sept_wclose, ssept_close
+  0, 0, sept_wclose, ssept_close
 };
 
 static endpt_ops stept_ops = {
-  0, sept_wclose, stept_close
+  0, 0, sept_wclose, stept_close
 };
 
 /*----- Source definition -------------------------------------------------*/
@@ -322,12 +338,20 @@ static int ssource_option(source *s, scanner *sc)
     token(sc);
     if (sc->t == '=')
       token(sc);
-    if (sc->t != CTOK_WORD || !isdigit((unsigned char)sc->d.buf[0]))
-      error(sc, "parse error, argument of `conn' must be a number");
-    sso->conn = atoi(sc->d.buf);
-    if (sso->conn == 0)
-      error(sc, "argument of `conn' must be positive");
-    token(sc);
+    if (sc->t != CTOK_WORD)
+      error(sc, "parse error, expected `unlimited', `one-shot' or number");
+    if (isdigit((unsigned char)sc->d.buf[0])) {
+      sso->conn = atoi(sc->d.buf);
+      if (sso->conn == 0)
+       error(sc, "argument of `conn' must be positive");
+      sso->opt = SOCKOPT_LIMIT;
+      token(sc);
+    } else {
+      sso->conn = 0;
+      sso->opt = 1 + (1 & conf_enum(sc,
+                                   "unlimited,one-shot,infinite",
+                                   ENUM_ABBREV, "`conn' option"));
+    }
     CONF_ACCEPT;
   }
 
@@ -395,6 +419,8 @@ static source *ssource_read(scanner *sc)
  *             endpoint.
  */
 
+static void ssource_destroy(source */*s*/);
+
 static void ss_accept(int fd, unsigned mode, void *p)
 {
   ssource *ss = p;
@@ -431,21 +457,35 @@ static void ss_accept(int fd, unsigned mode, void *p)
     DESTROY(e);
     return;
   }
+  fw_inc();
 
   /* --- Remove the listening socket if necessary --- */
 
-  ss->o.conn--;
-  if (!ss->o.conn) {
-    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);
+  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);
+      }
+      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;
   }
 
   /* --- Let everything else happen --- */
 
-  fw_inc();
   endpt_join(&e->e, ee);
 }
 
@@ -461,14 +501,13 @@ static void ss_accept(int fd, unsigned mode, void *p)
  *             behaviour.
  */
 
-static void ssource_destroy(source */*s*/);
-
 static void ss_listen(ssource *ss)
 {
   gen_addr *ga = (gen_addr *)ss->a;
   int fd;
 
-  fw_log(-1, "[%s] reattaching listener", ss->s.desc);
+  if (!(ss->ao->f & ADDRF_NOLOG))
+    fw_log(-1, "[%s] reattaching listener", ss->s.desc);
 
   /* --- Make the socket --- */
 
@@ -489,7 +528,7 @@ static void ss_listen(ssource *ss)
   /* --- Bind it to the right port --- */
 
   if (bind(fd, &ga->sa, ga->a.sz)) {
-    fw_log(-1, "[%s] couldn't bind to %s: %s", ss->s.desc, strerror(errno));
+    fw_log(-1, "[%s] couldn't bind socket: %s", ss->s.desc, strerror(errno));
     goto fail_1;
   }
   if (ga->a.ops->bound)
@@ -587,7 +626,7 @@ static void ssource_destroy(source *s)
 {
   ssource *ss = (ssource *)s;
 
-  if (ss->o.conn) {
+  if (ss->o.conn || ss->o.opt != SOCKOPT_LIMIT) {
     sel_rmfile(&ss->r);
     close(ss->r.fd);
     if (ss->a->ops->unbind)