From 64c6a21468179964f2f2dc536f981752009791fc Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Wed, 2 Apr 2008 09:12:02 +0100 Subject: [PATCH] socket: New option accept-count. 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 | 18 +++++++++ socket.c | 135 +++++++++++++++++++++++++++++++++++++++------------------------ 2 files changed, 102 insertions(+), 51 deletions(-) diff --git a/fw.1.in b/fw.1.in index 5dc51f7..1b7d4d5 100644 --- 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" +.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 diff --git a/socket.c b/socket.c index 53ac666..328e8f3 100644 --- a/socket.c +++ b/socket.c @@ -34,9 +34,10 @@ typedef struct ssource_opts { unsigned opt; unsigned conn; unsigned listen; + unsigned naccept; } 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 @@ -290,6 +291,26 @@ static int ssource_option(source *s, scanner *sc) 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; @@ -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(); - else { + else ss->ao = CREATE(addr_opts); - *ss->ao = gsao; - } + *ss->ao = gsao; 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; + 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); - } - 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@ --- * -- 2.11.0