1
0
Fork 0
mirror of https://repo.or.cz/socat.git synced 2025-07-26 04:02:56 +00:00

new option max-children that limits the number of concurrent child processes

This commit is contained in:
Gerhard Rieger 2011-11-26 14:24:09 +01:00
parent 6cefd1941e
commit 02f3b29ab6
10 changed files with 99 additions and 2 deletions

View file

@ -19,6 +19,7 @@
/***** LISTEN options *****/
const struct optdesc opt_backlog = { "backlog", NULL, OPT_BACKLOG, GROUP_LISTEN, PH_LISTEN, TYPE_INT, OFUNC_SPEC };
const struct optdesc opt_fork = { "fork", NULL, OPT_FORK, GROUP_CHILD, PH_PASTACCEPT, TYPE_BOOL, OFUNC_SPEC };
const struct optdesc opt_max_children = { "max-children", NULL, OPT_MAX_CHILDREN, GROUP_CHILD, PH_PASTACCEPT, TYPE_INT, OFUNC_SPEC };
/**/
#if (WITH_UDP || WITH_TCP)
const struct optdesc opt_range = { "range", NULL, OPT_RANGE, GROUP_RANGE, PH_ACCEPT, TYPE_STRING, OFUNC_SPEC };
@ -114,6 +115,7 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
int backlog = 5; /* why? 1 seems to cause problems under some load */
char *rangename;
bool dofork = false;
int maxchildren = 0;
char infobuff[256];
char lisname[256];
union sockaddr_union _peername;
@ -134,6 +136,13 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
xfd->flags |= XIO_DOESFORK;
}
retropt_int(opts, OPT_MAX_CHILDREN, &maxchildren);
if (! dofork && maxchildren) {
Error("option max-children not allowed without option fork");
return STAT_NORETRY;
}
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
if (dofork) {
@ -278,12 +287,25 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
if (dofork) {
pid_t pid; /* mostly int; only used with fork */
sigset_t mask_sigchld;
/* we must prevent that the current packet triggers another fork;
therefore we wait for a signal from the recent child: USR1
indicates that is has consumed the last packet; CHLD means it has
terminated */
/* block SIGCHLD and SIGUSR1 until parent is ready to react */
sigemptyset(&mask_sigchld);
sigaddset(&mask_sigchld, SIGCHLD);
Sigprocmask(SIG_BLOCK, &mask_sigchld, NULL);
if ((pid = xio_fork(false, level==E_ERROR?level:E_WARN)) < 0) {
Close(xfd->fd);
Sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL);
return STAT_RETRYLATER;
}
if (pid == 0) { /* child */
pid_t cpid = Getpid();
Sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL);
Info1("just born: client process "F_pid, cpid);
xiosetenvulong("PID", cpid, 1);
@ -308,6 +330,15 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
if (Close(ps) < 0) {
Info2("close(%d): %s", ps, strerror(errno));
}
/* now we are ready to handle signals */
Sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL);
while (maxchildren) {
if (num_child < maxchildren) break;
Notice("maxchildren are active, waiting");
while (!Sleep(UINT_MAX)) ; /* any signal lets us continue */
}
Info("still listening");
} else {
if (Close(xfd->fd) < 0) {