From bd542135ce221aadf3af40017f2fac4f9c6d15c9 Mon Sep 17 00:00:00 2001 From: Stefan Becker Date: Wed, 17 Apr 2013 20:58:17 +0300 Subject: [PATCH] http: implement stack shutdown flag Don't accept new HTTP connections/requests during HTTP stack shutdown. This shouldn't happen and indicates that some HTTP response callback isn't correctly checking for an aborted request. This prevents SIPE from crashing. --- src/core/sipe-http-request.c | 14 +++++++ src/core/sipe-http-transport.c | 90 +++++++++++++++++++++++++----------------- src/core/sipe-http-transport.h | 9 +++++ 3 files changed, 77 insertions(+), 36 deletions(-) diff --git a/src/core/sipe-http-request.c b/src/core/sipe-http-request.c index fceba973..0df05927 100644 --- a/src/core/sipe-http-request.c +++ b/src/core/sipe-http-request.c @@ -403,6 +403,20 @@ struct sipe_http_request *sipe_http_request_new(struct sipe_core_private *sipe_p struct sipe_http_request *req; if (!parsed_uri) return(NULL); + if (sipe_http_shutting_down(sipe_private)) { + SIPE_DEBUG_ERROR("sipe_http_request_new: new HTTP request during shutdown: THIS SHOULD NOT HAPPEN! Debugging information:\n" + "Host: %s\n" + "Port: %d\n" + "Path: %s\n" + "Headers: %s\n" + "Body: %s\n", + parsed_uri->host, + parsed_uri->port, + parsed_uri->path, + headers ? headers : "", + body ? body : ""); + return(NULL); + } req = g_new0(struct sipe_http_request, 1); req->flags = 0; diff --git a/src/core/sipe-http-transport.c b/src/core/sipe-http-transport.c index 7ccaa71b..b4f47e6b 100644 --- a/src/core/sipe-http-transport.c +++ b/src/core/sipe-http-transport.c @@ -67,6 +67,7 @@ struct sipe_http { GHashTable *connections; GQueue *timeouts; time_t next_timeout; /* in seconds from epoch, 0 if timer isn't running */ + gboolean shutting_down; }; static gint timeout_compare(gconstpointer a, @@ -190,12 +191,24 @@ static void sipe_http_transport_update_timeout_queue(struct sipe_http_connection } } +gboolean sipe_http_shutting_down(struct sipe_core_private *sipe_private) +{ + struct sipe_http *http = sipe_private->http; + /* We need to return FALSE in case HTTP stack isn't initialized yet */ + if (!http) + return(FALSE); + return(http->shutting_down); +} + void sipe_http_free(struct sipe_core_private *sipe_private) { struct sipe_http *http = sipe_private->http; if (!http) return; + /* HTTP stack is shutting down: reject all new requests */ + http->shutting_down = TRUE; + sipe_schedule_cancel(sipe_private, SIPE_HTTP_TIMEOUT_ACTION); g_hash_table_destroy(http->connections); g_queue_free(http->timeouts); @@ -418,7 +431,7 @@ struct sipe_http_connection_public *sipe_http_transport_new(struct sipe_core_pri const guint32 port) { struct sipe_http *http; - struct sipe_http_connection *conn; + struct sipe_http_connection *conn = NULL; /* host name matching should be case insensitive */ gchar *host = g_ascii_strdown(host_in, -1); gchar *host_port = g_strdup_printf("%s:%" G_GUINT32_FORMAT, host, port); @@ -426,49 +439,54 @@ struct sipe_http_connection_public *sipe_http_transport_new(struct sipe_core_pri sipe_http_init(sipe_private); http = sipe_private->http; - conn = g_hash_table_lookup(http->connections, host_port); + if (http->shutting_down) { + SIPE_DEBUG_ERROR("sipe_http_transport_new: new connection requested during shutdown: THIS SHOULD NOT HAPPEN! Debugging information:\n" + "Host/Port: %s", host_port); + } else { + conn = g_hash_table_lookup(http->connections, host_port); - if (conn) { - /* re-establishing connection */ - if (!conn->connection) { - SIPE_DEBUG_INFO("sipe_http_transport_new: re-establishing %s", host_port); + if (conn) { + /* re-establishing connection */ + if (!conn->connection) { + SIPE_DEBUG_INFO("sipe_http_transport_new: re-establishing %s", host_port); - /* will be re-inserted after connect */ - sipe_http_transport_update_timeout_queue(conn, TRUE); - } + /* will be re-inserted after connect */ + sipe_http_transport_update_timeout_queue(conn, TRUE); + } - } else { - /* new connection */ - SIPE_DEBUG_INFO("sipe_http_transport_new: new %s", host_port); + } else { + /* new connection */ + SIPE_DEBUG_INFO("sipe_http_transport_new: new %s", host_port); - conn = g_new0(struct sipe_http_connection, 1); + conn = g_new0(struct sipe_http_connection, 1); - conn->public.sipe_private = sipe_private; - conn->public.host = g_strdup(host); - conn->public.port = port; + conn->public.sipe_private = sipe_private; + conn->public.host = g_strdup(host); + conn->public.port = port; - conn->host_port = host_port; + conn->host_port = host_port; - g_hash_table_insert(http->connections, - host_port, - conn); - host_port = NULL; /* conn_private takes ownership of the key */ - } + g_hash_table_insert(http->connections, + host_port, + conn); + host_port = NULL; /* conn_private takes ownership of the key */ + } - if (!conn->connection) { - sipe_connect_setup setup = { - SIPE_TRANSPORT_TLS, /* TBD: we only support TLS for now */ - host, - port, - conn, - sipe_http_transport_connected, - sipe_http_transport_input, - sipe_http_transport_error - }; - - conn->public.connected = FALSE; - conn->connection = sipe_backend_transport_connect(SIPE_CORE_PUBLIC, - &setup); + if (!conn->connection) { + sipe_connect_setup setup = { + SIPE_TRANSPORT_TLS, /* TBD: we only support TLS for now */ + host, + port, + conn, + sipe_http_transport_connected, + sipe_http_transport_input, + sipe_http_transport_error + }; + + conn->public.connected = FALSE; + conn->connection = sipe_backend_transport_connect(SIPE_CORE_PUBLIC, + &setup); + } } g_free(host_port); diff --git a/src/core/sipe-http-transport.h b/src/core/sipe-http-transport.h index 2832a728..fd0bfcf8 100644 --- a/src/core/sipe-http-transport.h +++ b/src/core/sipe-http-transport.h @@ -48,6 +48,15 @@ struct sipe_http_connection_public { }; /** + * Check if we're shutting down the HTTP stack + * + * @param sipe_private SIPE core private data + * + * @return return @c TRUE if HTTP stack is shutting down + */ +gboolean sipe_http_shutting_down(struct sipe_core_private *sipe_private); + +/** * Initiate HTTP connection * * If a connection to this host/port already exists it will be reused. -- 2.11.4.GIT