From: Stephan Bosch Date: Sat, 16 Apr 2016 01:54:00 +0000 (+0200) Subject: lib-http: server: Implemented means to gracefully shut down the server. X-Git-Tag: 2.3.0.rc1~3885 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e1a4ea6ad3e799ef8df7395e765c0ae9218e6c5d;p=thirdparty%2Fdovecot%2Fcore.git lib-http: server: Implemented means to gracefully shut down the server. While shutting down, it will not accept new requests and connections are closed once they become idle. --- diff --git a/src/lib-http/http-server-connection.c b/src/lib-http/http-server-connection.c index 94713e6805..6e166817e3 100644 --- a/src/lib-http/http-server-connection.c +++ b/src/lib-http/http-server-connection.c @@ -151,6 +151,16 @@ http_server_connection_timeout_reset(struct http_server_connection *conn) timeout_reset(conn->to_idle); } +bool http_server_connection_shut_down(struct http_server_connection *conn) +{ + if (conn->request_queue_head == NULL || + conn->request_queue_head->state == HTTP_SERVER_REQUEST_STATE_NEW) { + http_server_connection_close(&conn, "Server shutting down"); + return TRUE; + } + return FALSE; +} + static void http_server_connection_ready(struct http_server_connection *conn) { struct stat st; @@ -403,17 +413,24 @@ static bool http_server_connection_pipeline_is_full(struct http_server_connection *conn) { return (conn->request_queue_count >= - conn->server->set.max_pipelined_requests); + conn->server->set.max_pipelined_requests || + conn->server->shutting_down); } static void http_server_connection_pipeline_handle_full( struct http_server_connection *conn) { - http_server_connection_debug(conn, - "Pipeline full (%u requests pending; %u maximum)", - conn->request_queue_count, - conn->server->set.max_pipelined_requests); + if (conn->server->shutting_down) { + http_server_connection_debug(conn, + "Pipeline full (%u requests pending; server shutting down)", + conn->request_queue_count); + } else { + http_server_connection_debug(conn, + "Pipeline full (%u requests pending; %u maximum)", + conn->request_queue_count, + conn->server->set.max_pipelined_requests); + } http_server_connection_input_halt(conn); } @@ -517,6 +534,12 @@ static void http_server_connection_input(struct connection *_conn) bool cont; int ret; + if (conn->server->shutting_down) { + if (!http_server_connection_shut_down(conn)) + http_server_connection_pipeline_handle_full(conn); + return; + } + i_assert(!conn->in_req_callback); i_assert(!conn->input_broken && conn->incoming_payload == NULL); i_assert(!conn->close_indicated); @@ -881,7 +904,8 @@ static int http_server_connection_send_responses( /* accept more requests if possible */ if (conn->incoming_payload == NULL && - conn->request_queue_count < conn->server->set.max_pipelined_requests) { + conn->request_queue_count < conn->server->set.max_pipelined_requests && + !conn->server->shutting_down) { http_server_connection_input_resume(conn); return 1; } @@ -947,6 +971,10 @@ int http_server_connection_output(struct http_server_connection *conn) } } + if (conn->server->shutting_down && + http_server_connection_shut_down(conn)) + return 1; + if (!http_server_connection_pipeline_is_full(conn)) { http_server_connection_input_resume(conn); if (pipeline_was_full && conn->conn.io != NULL) @@ -997,6 +1025,8 @@ http_server_connection_create(struct http_server *server, in_port_t port; const char *name; + i_assert(!server->shutting_down); + conn = i_new(struct http_server_connection, 1); conn->refcount = 1; conn->id = id++; diff --git a/src/lib-http/http-server-private.h b/src/lib-http/http-server-private.h index 73788bef68..b0a512898b 100644 --- a/src/lib-http/http-server-private.h +++ b/src/lib-http/http-server-private.h @@ -139,6 +139,8 @@ struct http_server { struct ssl_iostream_context *ssl_ctx; struct connection_list *conn_list; + + unsigned int shutting_down:1; /* shutting down server */ }; static inline const char * @@ -211,6 +213,8 @@ http_server_request_version_equals(struct http_server_request *req, struct connection_list *http_server_connection_list_init(void); +bool http_server_connection_shut_down(struct http_server_connection *conn); + void http_server_connection_switch_ioloop(struct http_server_connection *conn); void http_server_connection_write_failed(struct http_server_connection *conn, diff --git a/src/lib-http/http-server.c b/src/lib-http/http-server.c index 7f9f28df4f..f036d3326f 100644 --- a/src/lib-http/http-server.c +++ b/src/lib-http/http-server.c @@ -69,3 +69,19 @@ void http_server_switch_ioloop(struct http_server *server) http_server_connection_switch_ioloop(conn); } } + +void http_server_shut_down(struct http_server *server) +{ + struct connection *_conn, *_next; + + server->shutting_down = TRUE; + + for (_conn = server->conn_list->connections; + _conn != NULL; _conn = _next) { + struct http_server_connection *conn = + (struct http_server_connection *)_conn; + + _next = _conn->next; + (void)http_server_connection_shut_down(conn); + } +} diff --git a/src/lib-http/http-server.h b/src/lib-http/http-server.h index b90a396731..53ec3ac521 100644 --- a/src/lib-http/http-server.h +++ b/src/lib-http/http-server.h @@ -68,6 +68,9 @@ typedef void (*http_server_tunnel_callback_t)(void *context, struct http_server *http_server_init(const struct http_server_settings *set); void http_server_deinit(struct http_server **_server); +/* shut down the server; accept no new requests and drop connections once + they become idle */ +void http_server_shut_down(struct http_server *server); struct http_server_connection * http_server_connection_create(struct http_server *server,