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
{
ssept *ee = (ssept *)e;
- if (ee->s->o.opt == SOCKOPT_LIMIT) {
+ if ((ee->s->s.f&SF_ACTIVE) && ee->s->o.opt == SOCKOPT_LIMIT) {
ee->s->o.conn++;
if (ee->s->o.conn == 1)
ss_listen(ee->s);
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;
(void)(conf_prefix(sc, "socket") || conf_prefix(sc, "sk"));
ss = CREATE(ssource);
ss->s.ops = &ssource_ops;
+ ss->s.ref = 1;
+ ss->s.f = 0;
ss->s.desc = 0;
ss->t = 0;
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 --- */
+ 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 the file descriptor --- */
- /* --- Make an endpoint --- */
-
- 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;
- }
+ source_dec(&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@ --- *
close(fd);
fail_0:
ss->o.conn = 0;
- ssource_destroy(&ss->s);
+ source_dec(&ss->s);
}
/* --- @attach@ --- */
int fd;
int opt = 1;
- ss->t = t;
+ ss->t = t; target_inc(t);
/* --- Initialize the description string --- */
fw_inc();
}
-/* --- @destroy@ --- */
+/* --- @shutdown@ --- */
-static void ssource_destroy(source *s)
+static void ssource_shutdown(source *s)
{
ssource *ss = (ssource *)s;
ss->a->ops->freesrcopts(ss->ao);
else
DESTROY(ss->ao);
- xfree(ss->s.desc);
ss->a->ops->destroy(ss->a);
- ss->t->ops->destroy(ss->t);
source_remove(&ss->s);
+ target_dec(ss->t);
+ fw_dec();
+}
+
+/* --- @destroy@ --- */
+
+static void ssource_destroy(source *s)
+{
+ ssource *ss = (ssource *)s;
+
+ xfree(ss->s.desc);
DESTROY(ss);
fw_dec();
}
source_ops ssource_ops = {
"socket",
- ssource_option, ssource_read, ssource_attach, ssource_destroy
+ ssource_option, ssource_read, ssource_attach, ssource_shutdown, ssource_destroy
};
/*----- Target definition -------------------------------------------------*/
(void)(conf_prefix(sc, "socket") || conf_prefix(sc, "sk"));
st = CREATE(starget);
st->t.ops = &starget_ops;
+ st->t.ref = 1;
st->a = getaddr(sc, ADDR_DEST);
if (st->a->ops->inittargopts)
st->ao = st->a->ops->inittargopts();