diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-11-24 18:34:29 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-11-24 18:34:29 +0200 |
commit | a7779d56bb758157e122a420a56f2d7b4475e554 (patch) | |
tree | 98241b97aa36b7713b2a76677b387cf214a1dbb7 | |
parent | e6772c4d68849cfdb4547a59bc51cb6dd0acd2c6 (diff) | |
download | pies-a7779d56bb758157e122a420a56f2d7b4475e554.tar.gz pies-a7779d56bb758157e122a420a56f2d7b4475e554.tar.bz2 |
Implement inetd connection rate.
* src/pies.h (struct component): New member "max_rate".
(default_max_rate): New extern.
* src/progman.c (check_rate): New function.
(check_spawn_rate, check_connection_rate): New functions.
(prog_open_socket): New function.
(prog_start): Rewrite using the above functions.
(_prog_accept): Check connection rate.
(progman_start): Special handling for inetd listeners.
(progman_wake_sleeping): Likewise.
* src/pies.c (default_max_rate): New global.
(component_keywords): New keyword max-rate.
(options): New option "rate".
(parse_opt): Handle the new option.
* src/inetd.c (inetd_conf_file): Set max_rate, instead of
max_instances.
-rw-r--r-- | src/inetd.c | 6 | ||||
-rw-r--r-- | src/pies.c | 24 | ||||
-rw-r--r-- | src/pies.h | 6 | ||||
-rw-r--r-- | src/progman.c | 178 |
4 files changed, 156 insertions, 58 deletions
diff --git a/src/inetd.c b/src/inetd.c index ac40a5a..270425d 100644 --- a/src/inetd.c +++ b/src/inetd.c @@ -60,7 +60,7 @@ inetd_conf_file (const char *file) struct component *comp; int socket_type; struct pies_url *url; - size_t max_instances = 0; + size_t max_rate = 0; int flags = 0; char *str; char *user = NULL; @@ -161,7 +161,7 @@ inetd_conf_file (const char *file) logmsg (LOG_WARNING, "%s:%lu: invalid number (near %s)", file, line_no, p); else - max_instances = n; + max_rate = n; } if (strcmp (ws.ws_wordv[IFLD_WAIT], "wait") == 0) @@ -199,7 +199,7 @@ inetd_conf_file (const char *file) comp->mode = pies_comp_inetd; comp->socket_type = socket_type; comp->socket_url = url; - comp->max_instances = max_instances; + comp->max_rate = max_rate; comp->flags = flags; comp->privs.user = xstrdup (user); /* FIXME: memory leak */ if (group) @@ -34,6 +34,7 @@ char *ctlfile = LOCALSTATEDIR "/pies.ctl"; char *statfile = LOCALSTATEDIR "/pies.stat"; mode_t pies_umask = 0; unsigned long shutdown_timeout = 5; +size_t default_max_rate; pies_acl_t pies_acl; limits_record_t pies_limits; int force_option; @@ -900,6 +901,12 @@ struct grecs_keyword component_keywords[] = { grecs_type_size, NULL, offsetof (struct component, max_instances), NULL }, + {"max-rate", + NULL, + N_("Maximum number of times an inetd component can be invoked in one minute."), + grecs_type_size, NULL, + offsetof (struct component, max_rate), + NULL }, {"socket", N_("url: string"), N_("Listen on the given url."), @@ -1389,7 +1396,8 @@ enum OPT_DUMP_DEPMAP, OPT_FORCE, OPT_CONFIG_HELP, - OPT_SOURCE_INFO + OPT_SOURCE_INFO, + OPT_RATE }; #define OPT_RESTART 'R' @@ -1415,6 +1423,9 @@ static struct argp_option options[] = { N_("use FILE instead of the default configuration"), GRP + 1}, {"config-help", OPT_CONFIG_HELP, NULL, 0, N_("show configuration file summary"), GRP + 1}, + {"rate", OPT_RATE, N_("NUMBER"), 0, + N_("set default maximum rate for inetd-style components"), + GRP + 1}, #undef GRP #define GRP 5 @@ -1455,6 +1466,8 @@ static struct argp_option options[] = { static error_t parse_opt (int key, char *arg, struct argp_state *state) { + char *p; + switch (key) { case 'c': @@ -1513,6 +1526,15 @@ parse_opt (int key, char *arg, struct argp_state *state) debug_level = strtoul (arg, NULL, 0); break; + case OPT_RATE: + default_max_rate = strtoul (arg, &p, 10); + if (*p) + { + logmsg (LOG_ERR, _("not a number: %s"), arg); + exit (EX_USAGE); + } + break; + case OPT_SOURCE_INFO: source_info_option = 1; break; @@ -153,7 +153,10 @@ struct component gl_list_t prereq; /* Prerequisites */ gl_list_t depend; /* Dependency targets */ int flags; /* CF_ bitmask */ - size_t max_instances; /* Maximum number of running instances */ + size_t max_instances; /* Maximum number of simultaneously running + instances (inetd) */ + size_t max_rate; /* Maximum number of invocations per minute + (inetd) */ int socket_type; /* Socket type */ char *rmfile; /* Try to remove this file before starting */ struct pies_privs privs; /* UID/GIDS+groups to run under */ @@ -184,6 +187,7 @@ extern char *mailer_program; extern char *mailer_command_line; extern int mailer_argc; extern char **mailer_argv; +extern size_t default_max_rate; void register_prog (struct component *comp); size_t progman_running_count (void); diff --git a/src/progman.c b/src/progman.c index 227b438..f0cc4c9 100644 --- a/src/progman.c +++ b/src/progman.c @@ -610,11 +610,92 @@ env_setup (char **env) return new_env; } +static int +check_rate (struct prog *prog, unsigned testtime, size_t max_count) +{ + time_t now; + + time (&now); + + if (prog->v.p.timestamp + testtime > now) + prog->v.p.failcount++; + else + { + prog->v.p.failcount = 0; + prog->v.p.timestamp = now; + } + + if (prog->v.p.failcount > max_count) + { + prog->v.p.timestamp = now; + prog->v.p.status = status_sleeping; + recompute_alarm = 1; + return 1; + } + + return 0; +} + +static int +check_spawn_rate (struct prog *prog) +{ + if (check_rate (prog, TESTTIME, MAXSPAWN)) + { + logmsg (LOG_NOTICE, + ngettext ("%s is respawning too fast, disabled for %d minute", + "%s is respawning too fast, disabled for %d minutes", + SLEEPTIME / 60), + prog->tag, SLEEPTIME / 60); + return 1; + } + return 0; +} + +static int +check_connection_rate (struct prog *prog) +{ + size_t max_rate = prog->v.p.comp->max_rate + ? prog->v.p.comp->max_rate : default_max_rate; + if (max_rate && check_rate (prog, 60, max_rate)) + { + logmsg (LOG_NOTICE, + ngettext ("%s is starting too often, disabled for %d minute", + "%s is starting too often, disabled for %d minutes", + SLEEPTIME / 60), + prog->tag, SLEEPTIME / 60); + return 1; + } + return 0; +} + + +static int +prog_open_socket (struct prog *prog) +{ + prog->v.p.socket = create_socket (prog->v.p.comp->socket_url, + prog->v.p.comp->socket_type, + prog->v.p.comp->privs.user, + prog->v.p.comp->umask); + if (prog->v.p.socket == -1) + { + prog->v.p.status = status_disabled; + return 1; + } + if (listen (prog->v.p.socket, 8)) + { + logmsg (LOG_ERR, "listen: %s", strerror (errno)); + close (prog->v.p.socket); + prog->v.p.socket = -1; + prog->v.p.status = status_disabled; + return 1; + } + return 0; +} + static void prog_start (struct prog *prog) { pid_t pid; - time_t now; int redir[2]; fd_set fdset; @@ -629,35 +710,16 @@ prog_start (struct prog *prog) if (prog_start_prerequisites (prog)) return; - time (&now); - - if (prog->v.p.timestamp + TESTTIME > now) - prog->v.p.failcount++; - else - { - prog->v.p.failcount = 0; - prog->v.p.timestamp = now; - } - - if (prog->v.p.failcount > MAXSPAWN) - { - logmsg (LOG_NOTICE, ngettext ( - "%s is respawning too fast, disabled for %d minute", - "%s is respawning too fast, disabled for %d minutes", - SLEEPTIME / 60), - prog->tag, SLEEPTIME / 60); - prog->v.p.timestamp = now; - prog->v.p.status = status_sleeping; - recompute_alarm = 1; - return; - } - switch (prog->v.p.comp->mode) { case pies_comp_exec: + if (check_spawn_rate (prog)) + return; break; case pies_comp_pass_fd: + if (check_spawn_rate (prog)) + return; debug (1, (_("unlinking %s"), prog->v.p.comp->pass_fd_socket)); if (unlink (prog->v.p.comp->pass_fd_socket) && errno != ENOENT) { @@ -666,26 +728,15 @@ prog_start (struct prog *prog) strerror (errno)); return; } - /* fall through */ + if (prog_open_socket (prog)) + return; + break; case pies_comp_accept: - prog->v.p.socket = create_socket (prog->v.p.comp->socket_url, - prog->v.p.comp->socket_type, - prog->v.p.comp->privs.user, - prog->v.p.comp->umask); - if (prog->v.p.socket == -1) - { - prog->v.p.status = status_disabled; - return; - } - if (listen (prog->v.p.socket, 8)) - { - logmsg (LOG_ERR, "listen: %s", strerror (errno)); - close (prog->v.p.socket); - prog->v.p.socket = -1; - prog->v.p.status = status_disabled; - return; - } + if (check_spawn_rate (prog)) + return; + if (prog_open_socket (prog)) + return; break; case pies_comp_inetd: @@ -897,6 +948,13 @@ _prog_accept (struct prog *p) close (fd); return 1; } + + if (check_connection_rate (p)) + { + disable_socket (p->v.p.socket); + close (fd); + return 1; + } pinst = register_prog0 (p->v.p.comp, -1); pinst->v.p.socket = fd; @@ -1192,10 +1250,17 @@ progman_start () recompute_alarm = 0; debug (1, ("starting components")); for (prog = proghead; prog; prog = prog->next) - if (IS_COMPONENT (prog) - && ((prog->v.p.status == status_enabled && prog->pid == 0) - || prog->v.p.status == status_sleeping)) - prog_start (prog); + if (IS_COMPONENT (prog)) + { + if (prog->v.p.comp->mode == pies_comp_inetd) + { + prog->v.p.status = status_listener; + enable_socket (prog->v.p.socket); + } + else if ((prog->v.p.status == status_enabled && prog->pid == 0) + || prog->v.p.status == status_sleeping) + prog_start (prog); + } } static void @@ -1230,10 +1295,18 @@ progman_wake_sleeping (int onalrm) case status_sleeping: if (now - prog->v.p.timestamp >= SLEEPTIME) { - prog->v.p.status = status_enabled; - prog->v.p.failcount = 0; - prog->v.p.timestamp = 0; - prog_start (prog); + if (prog->v.p.comp->mode == pies_comp_inetd) + { + prog->v.p.status = status_listener; + enable_socket (prog->v.p.socket); + } + else + { + prog->v.p.status = status_enabled; + prog->v.p.failcount = 0; + prog->v.p.timestamp = 0; + prog_start (prog); + } } /* If there is no alarm pending, recompute next alarm. This allows to cope with eventual clock inaccuracies. */ @@ -1882,9 +1955,8 @@ progman_stop_component (const char *name) default: logmsg (LOG_INFO, - _("stopping component `%s': " - "component not started"), - name); + _("stopping component `%s': component not started"), + name); } } } |