diff options
author | Guillaume Nault <g.nault@alphalink.fr> | 2018-10-22 12:00:02 +0200 |
---|---|---|
committer | Dmitry Kozlov <xeb@mail.ru> | 2018-11-03 09:04:40 +0300 |
commit | 142c943721615020bca80de4c69e6bbf574529aa (patch) | |
tree | 1139c878427b17a6a841b22ab2706837909fa92d | |
parent | c709a12656b64f33cd553b7d01842381d8fdce7a (diff) | |
download | accel-ppp-142c943721615020bca80de4c69e6bbf574529aa.tar.gz accel-ppp-142c943721615020bca80de4c69e6bbf574529aa.zip |
pppd_compat: fix handling of fork() failures
When accel-ppp is under stress (for example because of massive
disconnections) it may enter a state where no session could be
created or destroyed anymore.
This happens when at least one of the pppd_compat fork() fail. In this
case, the error code path doesn't unlock the sigchld handler, which
prevents it from running the completion callbacks of running scripts.
If the "fork-limit" option is used, failure to call the completion
callback will prevent other scripts from running. This will block
setting up and tearing down sessions, as those will wait indefinitely
for their pppd_compat scripts to run.
Therefore, we have to unlock the sigchld handler when fork() fails.
We also need to call fork_queue_wakeup(), because the previous
check_fork_limit() call already took one reference in the fork limit.
Finally, ev_ses_pre_up() is a bit special because it has to tear the
session down if the ip-pre-up script failed. Therefore it also has to
call ap_session_terminate() upon fork() failures.
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
-rw-r--r-- | accel-pppd/extra/pppd_compat.c | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/accel-pppd/extra/pppd_compat.c b/accel-pppd/extra/pppd_compat.c index 7c23eca0..6761e5bd 100644 --- a/accel-pppd/extra/pppd_compat.c +++ b/accel-pppd/extra/pppd_compat.c @@ -275,8 +275,12 @@ static void ev_ses_pre_up(struct ap_session *ses) log_emerg("pppd_compat: exec '%s': %s\n", conf_ip_pre_up, strerror(errno)); _exit(EXIT_FAILURE); - } else + } else { + sigchld_unlock(); + fork_queue_wakeup(); log_error("pppd_compat: fork: %s\n", strerror(errno)); + ap_session_terminate(ses, TERM_NAS_ERROR, 0); + } } static void ev_ses_started(struct ap_session *ses) @@ -325,8 +329,11 @@ static void ev_ses_started(struct ap_session *ses) log_emerg("pppd_compat: exec '%s': %s\n", conf_ip_up, strerror(errno)); _exit(EXIT_FAILURE); - } else + } else { + sigchld_unlock(); + fork_queue_wakeup(); log_error("pppd_compat: fork: %s\n", strerror(errno)); + } } static void ev_ses_finished(struct ap_session *ses) @@ -385,8 +392,11 @@ static void ev_ses_finished(struct ap_session *ses) log_emerg("pppd_compat: exec '%s': %s\n", conf_ip_down, strerror(errno)); _exit(EXIT_FAILURE); - } else + } else { + sigchld_unlock(); + fork_queue_wakeup(); log_error("pppd_compat: fork: %s\n", strerror(errno)); + } } if (pd->ip_up_hnd.pid) { @@ -474,8 +484,11 @@ static void ev_radius_coa(struct ev_radius_t *ev) log_emerg("pppd_compat: exec '%s': %s\n", conf_ip_change, strerror(errno)); _exit(EXIT_FAILURE); - } else + } else { + sigchld_unlock(); + fork_queue_wakeup(); log_error("pppd_compat: fork: %s\n", strerror(errno)); + } } } |