diff options
-rw-r--r-- | RELNOTES | 2 | ||||
-rw-r--r-- | client/dhclient.c | 15 | ||||
-rw-r--r-- | common/dispatch.c | 30 | ||||
-rw-r--r-- | dhcpctl/omshell.c | 4 | ||||
-rw-r--r-- | includes/omapip/isclib.h | 1 | ||||
-rw-r--r-- | omapip/isclib.c | 21 | ||||
-rw-r--r-- | relay/dhcrelay.c | 5 | ||||
-rw-r--r-- | server/dhcpd.c | 34 |
8 files changed, 84 insertions, 28 deletions
@@ -151,7 +151,7 @@ work on other platforms. Please report any problems and suggested fixes to [ISC-Bugs #34784] - Added support for gentle shutdown after signal is received. - [ISC-BUGS #32692] + [ISC-Bugs #32692] [ISC-Bugs 34945] - Enhance the DHCPv6 server logging to include the addresses that are assigned to the clients. diff --git a/client/dhclient.c b/client/dhclient.c index f131e393..97b86a6f 100644 --- a/client/dhclient.c +++ b/client/dhclient.c @@ -708,6 +708,7 @@ main(int argc, char **argv) { /* Start dispatching packets and timeouts... */ dispatch(); + /* In fact dispatch() never returns. */ return 0; } @@ -3944,6 +3945,20 @@ isc_result_t dhcp_set_control_state (control_object_state_t oldstate, struct client_state *client; struct timeval tv; + if (newstate == server_shutdown) { + /* Re-entry */ + if (shutdown_signal == SIGUSR1) + return ISC_R_SUCCESS; + /* Log shutdown on signal. */ + if ((shutdown_signal == SIGINT) || + (shutdown_signal == SIGTERM)) { + log_info("Received signal %d, initiating shutdown.", + shutdown_signal); + } + /* Mark it was called. */ + shutdown_signal = SIGUSR1; + } + /* Do the right thing for each interface. */ for (ip = interfaces; ip; ip = ip -> next) { for (client = ip -> client; client; client = client -> next) { diff --git a/common/dispatch.c b/common/dispatch.c index 976d37e2..c75a003b 100644 --- a/common/dispatch.c +++ b/common/dispatch.c @@ -110,17 +110,29 @@ dispatch(void) { isc_result_t status; - status = isc_app_ctxrun(dhcp_gbl_ctx.actx); + do { + status = isc_app_ctxrun(dhcp_gbl_ctx.actx); - /* - * isc_app_ctxrun can be stopped by receiving a signal. It will - * return ISC_R_SUCCESS in that case. That is a normal behavior. - */ + /* + * isc_app_ctxrun can be stopped by receiving a + * signal. It will return ISC_R_RELOAD in that + * case. That is a normal behavior. + */ - if (status != ISC_R_SUCCESS) { - log_fatal ("Dispatch routine failed: %s -- exiting", - isc_result_totext (status)); - } + if (status == ISC_R_RELOAD) { + /* + * dhcp_set_control_state() will do the job. + * Note its first argument is ignored. + */ + status = dhcp_set_control_state(server_shutdown, + server_shutdown); + if (status == ISC_R_SUCCESS) + status = ISC_R_RELOAD; + } + } while (status == ISC_R_RELOAD); + + log_fatal ("Dispatch routine failed: %s -- exiting", + isc_result_totext (status)); } void diff --git a/dhcpctl/omshell.c b/dhcpctl/omshell.c index 22506eec..07411b82 100644 --- a/dhcpctl/omshell.c +++ b/dhcpctl/omshell.c @@ -738,5 +738,7 @@ main(int argc, char **argv) { isc_result_t dhcp_set_control_state (control_object_state_t oldstate, control_object_state_t newstate) { - return ISC_R_SUCCESS; + if (newstate != server_shutdown) + return ISC_R_SUCCESS; + exit (0); } diff --git a/includes/omapip/isclib.h b/includes/omapip/isclib.h index 7fd30fea..fc45ef3d 100644 --- a/includes/omapip/isclib.h +++ b/includes/omapip/isclib.h @@ -120,5 +120,6 @@ isc_result_t dhcp_context_create(void); void isclib_cleanup(void); void dhcp_signal_handler(int signal); +extern int shutdown_signal; #endif /* ISCLIB_H */ diff --git a/omapip/isclib.c b/omapip/isclib.c index 5dcb12c0..afab262c 100644 --- a/omapip/isclib.c +++ b/omapip/isclib.c @@ -31,6 +31,7 @@ #include <signal.h> dhcp_context_t dhcp_gbl_ctx; +int shutdown_signal = 0; void isclib_cleanup(void) @@ -225,13 +226,17 @@ isclib_make_dst_key(char *inname, */ void dhcp_signal_handler(int signal) { isc_appctx_t *ctx = dhcp_gbl_ctx.actx; - if (ctx && ctx->methods && ctx->methods->ctxshutdown) { - /* - * Let's not use standard log facilities here. They may not be - * signal safe, e.g. we could get the signal in the middle of - * another log call - */ - printf("Received signal %d, initiating shutdown.\n", signal); - ctx->methods->ctxshutdown(ctx); + int prev = shutdown_signal; + + if (prev != 0) { + /* Already in shutdown. */ + return; + } + /* Possible race but does it matter? */ + shutdown_signal = signal; + + /* Use reload (aka suspend) for easier dispatch() reenter. */ + if (ctx && ctx->methods && ctx->methods->ctxsuspend) { + (void) isc_app_ctxsuspend(ctx); } } diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c index a218dece..b2d7bd90 100644 --- a/relay/dhcrelay.c +++ b/relay/dhcrelay.c @@ -585,6 +585,7 @@ main(int argc, char **argv) { /* Start dispatching packets and timeouts... */ dispatch(); + /* In fact dispatch() never returns. */ return (0); } @@ -1686,5 +1687,7 @@ parse_allow_deny(struct option_cache **oc, struct parse *p, int i) { isc_result_t dhcp_set_control_state(control_object_state_t oldstate, control_object_state_t newstate) { - return ISC_R_SUCCESS; + if (newstate != server_shutdown) + return ISC_R_SUCCESS; + exit(0); } diff --git a/server/dhcpd.c b/server/dhcpd.c index 457b3cc0..bfd84e00 100644 --- a/server/dhcpd.c +++ b/server/dhcpd.c @@ -790,13 +790,10 @@ main(int argc, char **argv) { /* * Receive packets and dispatch them... - * dispatch() will return only when we are shutting down. + * dispatch() will never return. */ dispatch (); - log_info("Shutting down."); - dhcp_set_control_state(server_shutdown/*ignored*/, server_shutdown); - /* Let's return status code */ return 0; } @@ -1358,11 +1355,32 @@ static isc_result_t dhcp_io_shutdown_countdown (void *vlp) isc_result_t dhcp_set_control_state (control_object_state_t oldstate, control_object_state_t newstate) { - if (newstate == server_shutdown) { - shutdown_time = cur_time; - shutdown_state = shutdown_listeners; + struct timeval tv; + + if (newstate != server_shutdown) + return DHCP_R_INVALIDARG; + /* Re-entry. */ + if (shutdown_signal == SIGUSR1) + return ISC_R_SUCCESS; + shutdown_time = cur_time; + shutdown_state = shutdown_listeners; + /* Called by user. */ + if (shutdown_signal == 0) { + shutdown_signal = SIGUSR1; dhcp_io_shutdown_countdown (0); return ISC_R_SUCCESS; } - return DHCP_R_INVALIDARG; + /* Called on signal. */ + log_info("Received signal %d, initiating shutdown.", shutdown_signal); + shutdown_signal = SIGUSR1; + + /* + * Prompt the shutdown event onto the timer queue + * and return to the dispatch loop. + */ + tv.tv_sec = cur_tv.tv_sec; + tv.tv_usec = cur_tv.tv_usec + 1; + add_timeout(&tv, + (void (*)(void *))dhcp_io_shutdown_countdown, 0, 0, 0); + return ISC_R_SUCCESS; } |