diff --git a/include/libhttp.h b/include/libhttp.h index fee8fba8..cb7562a7 100644 --- a/include/libhttp.h +++ b/include/libhttp.h @@ -310,7 +310,6 @@ struct httplib_callbacks { Return: web server context, or NULL on error. */ -LIBHTTP_API struct httplib_context *httplib_start(const struct httplib_callbacks *callbacks, void *user_data, const char **configuration_options); /* httplib_request_handler @@ -985,6 +984,7 @@ LIBHTTP_API int httplib_remove( const char *path ); LIBHTTP_API void httplib_send_file( struct httplib_connection *conn, const char *path, const char *mime_type, const char *additional_headers ); LIBHTTP_API void httplib_set_alloc_callback_func( httplib_alloc_callback_func log_func ); LIBHTTP_API void httplib_set_user_connection_data( struct httplib_connection *conn, void *data ); +LIBHTTP_API struct httplib_context * httplib_start(const struct httplib_callbacks *callbacks, void *user_data, const char **configuration_options, char *ebuf, size_t ebuf_len ); LIBHTTP_API void httplib_stop( struct httplib_context *ctx ); LIBHTTP_API int httplib_strcasecmp( const char *s1, const char *s2 ); LIBHTTP_API const char * httplib_strcasestr( const char *big_str, const char *small_str ); diff --git a/src/httplib_cry.c b/src/httplib_cry.c index b1708877..c5382ff4 100644 --- a/src/httplib_cry.c +++ b/src/httplib_cry.c @@ -48,7 +48,7 @@ void httplib_cry( const struct httplib_context *ctx, const struct httplib_connec va_end( ap ); buf[sizeof(buf)-1] = 0; - if ( conn == NULL || ctx == NULL ) return; + if ( ctx == NULL ) return; /* * Do not lock when getting the callback value, here and below. @@ -56,7 +56,7 @@ void httplib_cry( const struct httplib_context *ctx, const struct httplib_connec * same way string option can. */ - if ( ctx->callbacks.log_message == NULL || ctx->callbacks.log_message( conn, buf ) == 0 ) { + if ( conn == NULL || ctx->callbacks.log_message == NULL || ctx->callbacks.log_message( conn, buf ) == 0 ) { if ( ctx->cfg[ERROR_LOG_FILE] != NULL ) { @@ -70,10 +70,10 @@ void httplib_cry( const struct httplib_context *ctx, const struct httplib_connec flockfile( fi.fp ); timestamp = time( NULL ); - XX_httplib_sockaddr_to_string( src_addr, sizeof(src_addr), &conn->client.rsa ); + if ( conn != NULL ) XX_httplib_sockaddr_to_string( src_addr, sizeof(src_addr), &conn->client.rsa ); fprintf( fi.fp, "[%010lu] [error] [client %s] ", (unsigned long)timestamp, src_addr ); - if ( conn->request_info.request_method != NULL ) { + if ( conn != NULL && conn->request_info.request_method != NULL ) { fprintf( fi.fp, "%s %s: ", conn->request_info.request_method, conn->request_info.request_uri ); } diff --git a/src/httplib_set_ports_option.c b/src/httplib_set_ports_option.c index 6836399f..79c53561 100644 --- a/src/httplib_set_ports_option.c +++ b/src/httplib_set_ports_option.c @@ -70,7 +70,7 @@ int XX_httplib_set_ports_option( struct httplib_context *ctx ) { ports_total++; - if ( ! parse_port_string( & vec, & so, & ip_version ) ) { + if ( ! parse_port_string( &vec, &so, &ip_version ) ) { httplib_cry( ctx, NULL, "%.*s: invalid port spec (entry %i). Expecting list of: %s", diff --git a/src/httplib_start.c b/src/httplib_start.c index 7bdb1171..4e392a9d 100644 --- a/src/httplib_start.c +++ b/src/httplib_start.c @@ -31,17 +31,17 @@ #include "httplib_string.h" #include "httplib_utils.h" -static struct httplib_context * cleanup( struct httplib_context *ctx, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3); +static struct httplib_context * cleanup( struct httplib_context *ctx, char *ebuf, size_t ebuf_len, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(4, 5); /* - * struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks, void *user_data, const char **options ); + * struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks, void *user_data, const char **options, char *ebuf, size_t ebuf_len ); * * The function httplib_start() functions as the main entry point for the LibHTTP * server. The function starts all threads and when finished returns the * context to the running server for future reference. */ -struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks, void *user_data, const char **options ) { +struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks, void *user_data, const char **options, char *ebuf, size_t ebuf_len ) { struct httplib_context *ctx; const char *name; @@ -53,13 +53,19 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks void (*exit_callback)(const struct httplib_context *ctx) = NULL; struct httplib_workerTLS tls; + if ( ebuf != NULL && ebuf_len > 0 ) ebuf[0] = '\0'; + #if defined(_WIN32) WSADATA data; WSAStartup(MAKEWORD(2, 2), &data); #endif /* _WIN32 */ ctx = httplib_calloc( 1, sizeof(*ctx) ); - if ( ctx == NULL ) return NULL; + if ( ctx == NULL ) { + + if ( ebuf != NULL && ebuf_len > 0 ) snprintf( ebuf, ebuf_len, "No memory for CTX structure" ); + return NULL; + } /* * Random number generator will initialize at the first call @@ -87,6 +93,8 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks httplib_cry( ctx, NULL, "Cannot initialize thread local storage" ); httplib_free( ctx ); + if ( ebuf != NULL && ebuf_len > 0 ) snprintf( ebuf, ebuf_len, "Cannot create pthread key" ); + return NULL; } } @@ -104,12 +112,12 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks #endif httplib_pthread_setspecific( XX_httplib_sTlsKey, & tls ); - if ( httplib_pthread_mutex_init( & ctx->thread_mutex, &XX_httplib_pthread_mutex_attr ) ) return cleanup( ctx, "Cannot initialize thread mutex" ); + if ( httplib_pthread_mutex_init( & ctx->thread_mutex, &XX_httplib_pthread_mutex_attr ) ) return cleanup( ctx, ebuf, ebuf_len, "Cannot initialize thread mutex" ); #if !defined(ALTERNATIVE_QUEUE) - if ( httplib_pthread_cond_init( & ctx->sq_empty, NULL ) ) return cleanup( ctx, "Cannot initialize empty queue condition" ); - if ( httplib_pthread_cond_init( & ctx->sq_full, NULL ) ) return cleanup( ctx, "Cannot initialize full queue condition" ); + if ( httplib_pthread_cond_init( & ctx->sq_empty, NULL ) ) return cleanup( ctx, ebuf, ebuf_len, "Cannot initialize empty queue condition" ); + if ( httplib_pthread_cond_init( & ctx->sq_full, NULL ) ) return cleanup( ctx, ebuf, ebuf_len, "Cannot initialize full queue condition" ); #endif - if ( httplib_pthread_mutex_init( & ctx->nonce_mutex, & XX_httplib_pthread_mutex_attr ) ) return cleanup( ctx, "Cannot initialize nonce mutex" ); + if ( httplib_pthread_mutex_init( & ctx->nonce_mutex, & XX_httplib_pthread_mutex_attr ) ) return cleanup( ctx, ebuf, ebuf_len, "Cannot initialize nonce mutex" ); if ( callbacks != NULL ) { @@ -124,8 +132,8 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks while ( options && (name = *options++) != NULL ) { idx = XX_httplib_get_option_index( name ); - if ( idx == -1 ) return cleanup( ctx, "Invalid option: %s", name ); - if ( (value = *options++) == NULL ) return cleanup( ctx , "%s: option value cannot be NULL", name ); + if ( idx == -1 ) return cleanup( ctx, ebuf, ebuf_len, "Invalid option: %s", name ); + if ( (value = *options++) == NULL ) return cleanup( ctx, ebuf, ebuf_len, "%s: option value cannot be NULL", name ); if ( ctx->cfg[idx] != NULL ) { @@ -153,13 +161,13 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks * be initialized before listening ports. UID must be set last. */ - if ( ! XX_httplib_set_gpass_option( ctx ) ) return cleanup( ctx, "Error setting gpass option" ); + if ( ! XX_httplib_set_gpass_option( ctx ) ) return cleanup( ctx, ebuf, ebuf_len, "Error setting gpass option" ); #if !defined(NO_SSL) - if ( ! XX_httplib_set_ssl_option( ctx ) ) return cleanup( ctx, "Error setting SSL option" ); + if ( ! XX_httplib_set_ssl_option( ctx ) ) return cleanup( ctx, ebuf, ebuf_len, "Error setting SSL option" ); #endif - if ( ! XX_httplib_set_ports_option( ctx ) ) return cleanup( ctx, "Error setting ports option" ); - if ( ! XX_httplib_set_uid_option( ctx ) ) return cleanup( ctx, "Error setting UID option" ); - if ( ! XX_httplib_set_acl_option( ctx ) ) return cleanup( ctx, "Error setting ACL option" ); + if ( ! XX_httplib_set_ports_option( ctx ) ) return cleanup( ctx, ebuf, ebuf_len, "Error setting ports option" ); + if ( ! XX_httplib_set_uid_option( ctx ) ) return cleanup( ctx, ebuf, ebuf_len, "Error setting UID option" ); + if ( ! XX_httplib_set_acl_option( ctx ) ) return cleanup( ctx, ebuf, ebuf_len, "Error setting ACL option" ); #if !defined(_WIN32) @@ -172,36 +180,36 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks #endif /* !_WIN32 */ - if ( ctx->cfg[NUM_THREADS] == NULL ) return cleanup( ctx, "No worker thread number specified" ); + if ( ctx->cfg[NUM_THREADS] == NULL ) return cleanup( ctx, ebuf, ebuf_len, "No worker thread number specified" ); workerthreadcount = atoi( ctx->cfg[NUM_THREADS] ); - if ( workerthreadcount > MAX_WORKER_THREADS ) return cleanup( ctx, "Too many worker threads" ); + if ( workerthreadcount > MAX_WORKER_THREADS ) return cleanup( ctx, ebuf, ebuf_len, "Too many worker threads" ); if ( workerthreadcount > 0 ) { ctx->cfg_worker_threads = (unsigned int)(workerthreadcount); ctx->workerthreadids = httplib_calloc( ctx->cfg_worker_threads, sizeof(pthread_t) ); - if ( ctx->workerthreadids == NULL ) return cleanup( ctx, "Not enough memory for worker thread ID array" ); + if ( ctx->workerthreadids == NULL ) return cleanup( ctx, ebuf, ebuf_len, "Not enough memory for worker thread ID array" ); #if defined(ALTERNATIVE_QUEUE) ctx->client_wait_events = httplib_calloc( sizeof(ctx->client_wait_events[0]), ctx->cfg_worker_threads ); - if ( ctx->client_wait_events == NULL ) return cleanup( ctx, "Not enough memory for worker event array" ); + if ( ctx->client_wait_events == NULL ) return cleanup( ctx, ebuf, ebuf_len, "Not enough memory for worker event array" ); ctx->client_socks = httplib_calloc( sizeof(ctx->client_socks[0]), ctx->cfg_worker_threads ); - if ( ctx->client_socks == NULL ) return cleanup( ctx, "Not enough memory for worker socket array" ); + if ( ctx->client_socks == NULL ) return cleanup( ctx, ebuf, ebuf_len, "Not enough memory for worker socket array" ); for (i=0; icfg_worker_threads; i++) { ctx->client_wait_events[i] = event_create(); - if ( ctx->client_wait_events[i] == 0 ) return cleanup( ctx, "Error creating worker event %u", i ); + if ( ctx->client_wait_events[i] == 0 ) return cleanup( ctx, ebuf, ebuf_len, "Error creating worker event %u", i ); } #endif } #if defined(USE_TIMERS) - if ( timers_init( ctx ) != 0 ) return cleanup( ctx, "Error creating timers" ); + if ( timers_init( ctx ) != 0 ) return cleanup( ctx, ebuf, ebuf_len, "Error creating timers" ); #endif /* @@ -244,7 +252,7 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks if ( i > 0 ) httplib_cry( ctx, NULL, "Cannot start worker thread %i: error %ld", i + 1, (long)ERRNO ); - else return cleanup( ctx, "Cannot create threads: error %ld", (long)ERRNO ); + else return cleanup( ctx, ebuf, ebuf_len, "Cannot create threads: error %ld", (long)ERRNO ); break; } @@ -259,14 +267,14 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks /* - * static struct httplib_context *cleanup( struct httplib_context *ctx, const char *fmt, ... ); + * static struct httplib_context *cleanup( struct httplib_context *ctx, char *ebuf, size_t ebuf_len, const char *fmt, ... ); * * The function cleanup() is called to do some cleanup work when an error * occured initializing a context. The function returns NULL which is then * further returned to the calling party. */ -static struct httplib_context *cleanup( struct httplib_context *ctx, const char *fmt, ... ) { +static struct httplib_context *cleanup( struct httplib_context *ctx, char *ebuf, size_t ebuf_len, const char *fmt, ... ) { va_list ap; char buf[MG_BUF_LEN]; @@ -276,7 +284,9 @@ static struct httplib_context *cleanup( struct httplib_context *ctx, const char va_end( ap ); buf[sizeof(buf)-1] = 0; - httplib_cry(ctx, NULL, "%s", buf ); + if ( ebuf != NULL && ebuf_len > 0 ) snprintf( ebuf, ebuf_len, "%s", buf ); + + httplib_cry( ctx, NULL, "%s", buf ); if ( ctx != NULL ) XX_httplib_free_context( ctx ); httplib_pthread_setspecific( XX_httplib_sTlsKey, NULL ); diff --git a/src/main.c b/src/main.c index 21533009..b6c02adf 100644 --- a/src/main.c +++ b/src/main.c @@ -869,7 +869,7 @@ static void start_libhttp(int argc, char *argv[]) { /* Start LibHTTP */ memset(&callbacks, 0, sizeof(callbacks)); callbacks.log_message = &log_message; - g_ctx = httplib_start(&callbacks, &g_user_data, (const char **)options); + g_ctx = httplib_start(&callbacks, &g_user_data, (const char **)options, NULL, 0 ); /* httplib_start copies all options to an internal buffer. * The options data field here is not required anymore. */