summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Nault <g.nault@alphalink.fr>2018-10-22 12:00:02 +0200
committerDmitry Kozlov <xeb@mail.ru>2018-11-03 09:04:40 +0300
commit142c943721615020bca80de4c69e6bbf574529aa (patch)
tree1139c878427b17a6a841b22ab2706837909fa92d
parentc709a12656b64f33cd553b7d01842381d8fdce7a (diff)
downloadaccel-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.c21
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));
+ }
}
}