/*----- Licensing notice --------------------------------------------------*
*
- * This file is part of the `fw' port forwarder.
+ * This file is part of the `fwd' port forwarder.
*
- * `fw' is free software; you can redistribute it and/or modify
+ * `fwd' is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * `fw' is distributed in the hope that it will be useful,
+ * `fwd' is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with `fw'; if not, write to the Free Software Foundation,
+ * along with `fwd'; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-/*----- Header files ------------------------------------------------------*/
-
-#include "config.h"
-
-#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>
-#include <netdb.h>
-
-#include <mLib/alloc.h>
-#include <mLib/conn.h>
-#include <mLib/dstr.h>
-#include <mLib/fdflags.h>
-#include <mLib/sel.h>
-#include <mLib/sub.h>
-
-#include "addr.h"
-#include "conf.h"
-#include "endpt.h"
-#include "fw.h"
-#include "scan.h"
-#include "socket.h"
-#include "target.h"
-
-#include "inet.h"
-#include "un.h"
+#include "fwd.h"
/*----- Data structures ---------------------------------------------------*/
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
e->e.in = e->e.out = r;
e->e.f &= ~EPF_PENDING;
if (e->e.other)
- endpt_join(&e->e, e->e.other);
+ endpt_join(&e->e, e->e.other, 0);
}
}
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;
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);
}
ssept *e;
endpt *ee;
reffd *r;
+ int acceptp = 1;
+ unsigned i = 0;
- /* --- Make the file descriptor --- */
-
- {
- 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);
- }
+ while (acceptp) {
- /* --- 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->s.desc);
+ }
}
/* --- @ss_listen@ --- *