diff --git a/Makefile b/Makefile index 38e37394..11521096 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,7 @@ BUILD_DIRS = $(BUILD_DIR) $(BUILD_DIR)/src $(BUILD_DIR)/resources LIB_SOURCES = src/libhttp.c \ src/httplib_accept_new_connection.c \ src/httplib_check_feature.c \ + src/httplib_close_connection.c \ src/httplib_connect_client.c \ src/httplib_connect_websocket_client.c \ src/httplib_consume_socket.c \ diff --git a/src/httplib_close_connection.c b/src/httplib_close_connection.c new file mode 100644 index 00000000..70091da8 --- /dev/null +++ b/src/httplib_close_connection.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2016 Lammert Bies + * Copyright (c) 2013-2016 the Civetweb developers + * Copyright (c) 2004-2013 Sergey Lyubka + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + + +#include "libhttp-private.h" + + + +/* + * void XX_httplib_close_connection( struct mg_connection *conn ); + * + * The function XX_httplib_close_connection() is the internal function which + * does the heavy lifting to close a connection. + */ + +void XX_httplib_close_connection( struct mg_connection *conn ) { + + if ( conn == NULL || conn->ctx == NULL ) return; + + /* call the connection_close callback if assigned */ + if ((conn->ctx->callbacks.connection_close != NULL) && (conn->ctx->context_type == 1)) { + conn->ctx->callbacks.connection_close(conn); + } + + mg_lock_connection( conn ); + + conn->must_close = 1; + +#ifndef NO_SSL + if (conn->ssl != NULL) { + /* Run SSL_shutdown twice to ensure completly close SSL connection + */ + SSL_shutdown(conn->ssl); + SSL_free(conn->ssl); + /* Avoid CRYPTO_cleanup_all_ex_data(); See discussion: + * https://wiki.openssl.org/index.php/Talk:Library_Initialization */ + ERR_remove_state(0); + conn->ssl = NULL; + } +#endif + if ( conn->client.sock != INVALID_SOCKET ) { + + XX_httplib_close_socket_gracefully( conn ); + conn->client.sock = INVALID_SOCKET; + } + + mg_unlock_connection( conn ); + +} /* XX_httplib_close_connection */ + + + +/* + * void mg_close_connection( struct mg_connection *conn ); + * + * The function mg_close_connection() closes the connection passed as a + * parameter to this function. The function does not return a success or + * failure value. + */ + +void mg_close_connection( struct mg_connection *conn ) { + + struct mg_context *client_ctx = NULL; + unsigned int i; + + if ( conn == NULL ) return; + + if ( conn->ctx->context_type == 2 ) { + + client_ctx = conn->ctx; + /* client context: loops must end */ + conn->ctx->stop_flag = 1; + } + +#ifndef NO_SSL + if (conn->client_ssl_ctx != NULL) SSL_CTX_free((SSL_CTX *)conn->client_ssl_ctx); +#endif + XX_httplib_close_connection(conn); + if (client_ctx != NULL) { + /* join worker thread and free context */ + for (i = 0; i < client_ctx->cfg_worker_threads; i++) { + if (client_ctx->workerthreadids[i] != 0) XX_httplib_join_thread(client_ctx->workerthreadids[i]); + } + + XX_httplib_free(client_ctx->workerthreadids); + XX_httplib_free(client_ctx); + pthread_mutex_destroy(&conn->mutex); + XX_httplib_free(conn); + } + +} /* mg_close_connection */ diff --git a/src/libhttp-private.h b/src/libhttp-private.h index 11e7dfdf..8b850e1b 100644 --- a/src/libhttp-private.h +++ b/src/libhttp-private.h @@ -614,36 +614,36 @@ struct ssl_func { #define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter) -#define CRYPTO_num_locks (*(int (*)(void))crypto_sw[0].ptr) +#define CRYPTO_num_locks (*(int (*)(void))XX_httplib_crypto_sw[0].ptr) #define CRYPTO_set_locking_callback \ - (*(void (*)(void (*)(int, int, const char *, int)))crypto_sw[1].ptr) + (*(void (*)(void (*)(int, int, const char *, int)))XX_httplib_crypto_sw[1].ptr) #define CRYPTO_set_id_callback \ - (*(void (*)(unsigned long (*)(void)))crypto_sw[2].ptr) -#define ERR_get_error (*(unsigned long (*)(void))crypto_sw[3].ptr) -#define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[4].ptr) -#define ERR_remove_state (*(void (*)(unsigned long))crypto_sw[5].ptr) -#define ERR_free_strings (*(void (*)(void))crypto_sw[6].ptr) -#define ENGINE_cleanup (*(void (*)(void))crypto_sw[7].ptr) -#define CONF_modules_unload (*(void (*)(int))crypto_sw[8].ptr) -#define CRYPTO_cleanup_all_ex_data (*(void (*)(void))crypto_sw[9].ptr) -#define EVP_cleanup (*(void (*)(void))crypto_sw[10].ptr) -#define X509_free (*(void (*)(X509 *))crypto_sw[11].ptr) -#define X509_get_subject_name (*(X509_NAME * (*)(X509 *))crypto_sw[12].ptr) -#define X509_get_issuer_name (*(X509_NAME * (*)(X509 *))crypto_sw[13].ptr) + (*(void (*)(unsigned long (*)(void)))XX_httplib_crypto_sw[2].ptr) +#define ERR_get_error (*(unsigned long (*)(void))XX_httplib_crypto_sw[3].ptr) +#define ERR_error_string (*(char *(*)(unsigned long, char *))XX_httplib_crypto_sw[4].ptr) +#define ERR_remove_state (*(void (*)(unsigned long))XX_httplib_crypto_sw[5].ptr) +#define ERR_free_strings (*(void (*)(void))XX_httplib_crypto_sw[6].ptr) +#define ENGINE_cleanup (*(void (*)(void))XX_httplib_crypto_sw[7].ptr) +#define CONF_modules_unload (*(void (*)(int))XX_httplib_crypto_sw[8].ptr) +#define CRYPTO_cleanup_all_ex_data (*(void (*)(void))XX_httplib_crypto_sw[9].ptr) +#define EVP_cleanup (*(void (*)(void))XX_httplib_crypto_sw[10].ptr) +#define X509_free (*(void (*)(X509 *))XX_httplib_crypto_sw[11].ptr) +#define X509_get_subject_name (*(X509_NAME * (*)(X509 *))XX_httplib_crypto_sw[12].ptr) +#define X509_get_issuer_name (*(X509_NAME * (*)(X509 *))XX_httplib_crypto_sw[13].ptr) #define X509_NAME_oneline \ - (*(char *(*)(X509_NAME *, char *, int))crypto_sw[14].ptr) -#define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *))crypto_sw[15].ptr) + (*(char *(*)(X509_NAME *, char *, int))XX_httplib_crypto_sw[14].ptr) +#define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *))XX_httplib_crypto_sw[15].ptr) #define i2c_ASN1_INTEGER \ - (*(int (*)(ASN1_INTEGER *, unsigned char **))crypto_sw[16].ptr) + (*(int (*)(ASN1_INTEGER *, unsigned char **))XX_httplib_crypto_sw[16].ptr) #define EVP_get_digestbyname \ - (*(const EVP_MD *(*)(const char *))crypto_sw[17].ptr) + (*(const EVP_MD *(*)(const char *))XX_httplib_crypto_sw[17].ptr) #define ASN1_digest \ (*(int (*)(int (*)(), \ const EVP_MD *, \ char *, \ unsigned char *, \ - unsigned int *))crypto_sw[18].ptr) -#define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[19].ptr) + unsigned int *))XX_httplib_crypto_sw[18].ptr) +#define i2d_X509 (*(int (*)(X509 *, unsigned char **))XX_httplib_crypto_sw[19].ptr) #endif /* NO_SSL_DL */ #endif /* NO_SSL */ @@ -819,6 +819,7 @@ int XX_httplib_atomic_inc( volatile int *addr ); int XX_httplib_check_acl( struct mg_context *ctx, uint32_t remote_ip ); void XX_httplib_close_all_listening_sockets( struct mg_context *ctx ); void XX_httplib_close_connection( struct mg_connection *conn ); +void XX_httplib_close_socket_gracefully( struct mg_connection *conn ); int XX_httplib_connect_socket( struct mg_context *ctx, const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len, SOCKET *sock, union usa *sa ); int XX_httplib_consume_socket( struct mg_context *ctx, struct socket *sp, int thread_index ); void XX_httplib_set_close_on_exec( SOCKET sock, struct mg_connection *conn ); @@ -894,6 +895,7 @@ void * XX_httplib_malloc( size_t a ); extern const struct uriprot_tp XX_httplib_abs_uri_protocols[]; extern struct mg_option XX_httplib_config_options[]; +extern struct ssl_func XX_httplib_crypto_sw[]; extern struct ssl_func XX_httplib_ssl_sw[]; extern int XX_httplib_sTlsInit; extern pthread_key_t XX_httplib_sTlsKey; diff --git a/src/libhttp.c b/src/libhttp.c index 86318294..6cef1f10 100644 --- a/src/libhttp.c +++ b/src/libhttp.c @@ -517,7 +517,7 @@ struct ssl_func XX_httplib_ssl_sw[] = {{"SSL_free", NULL}, /* Similar array as XX_httplib_ssl_sw. These functions could be located in different * lib. */ -static struct ssl_func crypto_sw[] = {{"CRYPTO_num_locks", NULL}, +struct ssl_func XX_httplib_crypto_sw[] = {{"CRYPTO_num_locks", NULL}, {"CRYPTO_set_locking_callback", NULL}, {"CRYPTO_set_id_callback", NULL}, {"ERR_get_error", NULL}, @@ -8716,7 +8716,7 @@ static int initialize_ssl(struct mg_context *ctx) { #if !defined(NO_SSL_DL) if (!cryptolib_dll_handle) { - cryptolib_dll_handle = load_dll(ctx, CRYPTO_LIB, crypto_sw); + cryptolib_dll_handle = load_dll(ctx, CRYPTO_LIB, XX_httplib_crypto_sw); if (!cryptolib_dll_handle) return 0; } #endif /* NO_SSL_DL */ @@ -9052,7 +9052,7 @@ int XX_httplib_set_tcp_nodelay( SOCKET sock, int nodelay_on ) { } /* XX_httplib_set_tcp_nodelay */ -static void close_socket_gracefully(struct mg_connection *conn) { +void XX_httplib_close_socket_gracefully( struct mg_connection *conn ) { #if defined(_WIN32) char buf[MG_BUF_LEN]; @@ -9103,76 +9103,5 @@ static void close_socket_gracefully(struct mg_connection *conn) { /* Now we know that our FIN is ACK-ed, safe to close */ closesocket(conn->client.sock); conn->client.sock = INVALID_SOCKET; -} - -void XX_httplib_close_connection( struct mg_connection *conn ) { - - if (!conn || !conn->ctx) return; - - /* call the connection_close callback if assigned */ - if ((conn->ctx->callbacks.connection_close != NULL) - && (conn->ctx->context_type == 1)) { - conn->ctx->callbacks.connection_close(conn); - } - - mg_lock_connection(conn); - - conn->must_close = 1; - -#ifndef NO_SSL - if (conn->ssl != NULL) { - /* Run SSL_shutdown twice to ensure completly close SSL connection - */ - SSL_shutdown(conn->ssl); - SSL_free(conn->ssl); - /* Avoid CRYPTO_cleanup_all_ex_data(); See discussion: - * https://wiki.openssl.org/index.php/Talk:Library_Initialization */ - ERR_remove_state(0); - conn->ssl = NULL; - } -#endif - if (conn->client.sock != INVALID_SOCKET) { - close_socket_gracefully(conn); - conn->client.sock = INVALID_SOCKET; - } - - mg_unlock_connection(conn); - -} /* XX_httplib_close_connection */ - - -void mg_close_connection(struct mg_connection *conn) { - - struct mg_context *client_ctx = NULL; - unsigned int i; - - if (conn == NULL) { - return; - } - - if (conn->ctx->context_type == 2) { - client_ctx = conn->ctx; - /* client context: loops must end */ - conn->ctx->stop_flag = 1; - } - -#ifndef NO_SSL - if (conn->client_ssl_ctx != NULL) { - SSL_CTX_free((SSL_CTX *)conn->client_ssl_ctx); - } -#endif - XX_httplib_close_connection(conn); - if (client_ctx != NULL) { - /* join worker thread and free context */ - for (i = 0; i < client_ctx->cfg_worker_threads; i++) { - if (client_ctx->workerthreadids[i] != 0) { - XX_httplib_join_thread(client_ctx->workerthreadids[i]); - } - } - XX_httplib_free(client_ctx->workerthreadids); - XX_httplib_free(client_ctx); - pthread_mutex_destroy(&conn->mutex); - XX_httplib_free(conn); - } -} +} /* XX_httplib_close_socket_gracefully */