/* -*-c-*-
*
- * $Id: socket.c,v 1.1 1999/07/26 23:33:32 mdw Exp $
+ * $Id: socket.c,v 1.4 1999/12/22 15:44:25 mdw Exp $
*
* Socket source and target definitions
*
/*----- Revision history --------------------------------------------------*
*
* $Log: socket.c,v $
+ * 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.
+ *
* Revision 1.1 1999/07/26 23:33:32 mdw
* New sources and targets.
*
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.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 --- */
{
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();
/* --- 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 -------------------------------------------------*/
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;
}
* endpoint.
*/
+static void ssource_destroy(source */*s*/);
+
static void ss_accept(int fd, unsigned mode, void *p)
{
ssource *ss = 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);
}
* 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 --- */
/* --- 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)