From 40ffc74331d00cc3e443e30e112cd21b26bd595f Mon Sep 17 00:00:00 2001 From: Lammert Bies Date: Tue, 27 Dec 2016 11:32:30 +0100 Subject: [PATCH] More functional error logging --- include/libhttp.h | 131 ++++++++++++++++++++------------------------ src/httplib_cry.c | 81 +++++++++++++++++---------- src/httplib_main.h | 4 -- src/httplib_start.c | 116 +++++++++++++++++++++++---------------- src/main.c | 19 ++++--- 5 files changed, 189 insertions(+), 162 deletions(-) diff --git a/include/libhttp.h b/include/libhttp.h index cb7562a7..7ac9ec1d 100644 --- a/include/libhttp.h +++ b/include/libhttp.h @@ -27,6 +27,10 @@ #define LIBHTTP_VERSION "1.9" +#ifndef UNUSED_PARAMETER +#define UNUSED_PARAMETER(x) (void)(x) +#endif /* UNUSED_PARAMETER */ + #ifndef LIBHTTP_API #if defined(_WIN32) #if defined(LIBHTTP_DLL_EXPORTS) @@ -209,10 +213,7 @@ struct httplib_callbacks { /* Called when LibHTTP has finished processing request. */ void (*end_request)(const struct httplib_connection *, int reply_status_code); - - /* Called when LibHTTP is about to log a message. If callback returns - non-zero, LibHTTP does not log anything. */ - int (*log_message)(const struct httplib_connection *, const char *message); + int (*log_message)( const struct httplib_context *ctx, const struct httplib_connection * conn, const char *message ); /* Called when LibHTTP is about to log access. If callback returns non-zero, LibHTTP does not log anything. */ @@ -468,10 +469,6 @@ struct httplib_server_ports { int port; /* port number */ bool has_ssl; /* https port: 0 = no, 1 = yes */ bool has_redirect; /* redirect all requests: 0 = no, 1 = yes */ - int _reserved1; - int _reserved2; - int _reserved3; - int _reserved4; }; @@ -815,7 +812,6 @@ typedef LIBHTTP_THREAD_TYPE (LIBHTTP_THREAD_CALLING_CONV *httplib_thread_func_t) LIBHTTP_API int httplib_start_thread(httplib_thread_func_t f, void *p); -LIBHTTP_API const char * httplib_get_builtin_mime_type( const char *file_name ); /* Get text representation of HTTP status code. */ @@ -905,8 +901,7 @@ struct httplib_client_options { }; -LIBHTTP_API struct httplib_connection * -httplib_connect_client_secure(const struct httplib_client_options *client_options, char *error_buffer, size_t error_buffer_size); +LIBHTTP_API struct httplib_connection *httplib_connect_client_secure(const struct httplib_client_options *client_options, char *error_buffer, size_t error_buffer_size); enum { TIMEOUT_INFINITE = -1 }; @@ -926,73 +921,63 @@ enum { TIMEOUT_INFINITE = -1 }; LIBHTTP_API int httplib_get_response(struct httplib_connection *conn, char *ebuf, size_t ebuf_len, int timeout); -/* Check which features where set when LibHTTP has been compiled. - Parameters: - feature: specifies which feature should be checked - 2 support HTTPS (NO_SSL not set) - 4 support CGI (NO_CGI not set) - The result is undefined for all other feature values. - - Return: - If feature is available > 0 - If feature is not available = 0 -*/ -LIBHTTP_API unsigned httplib_check_feature(unsigned feature); typedef void (*httplib_alloc_callback_func)( const char *file, unsigned line, const char *action, int64_t current_bytes, int64_t total_blocks, int64_t total_bytes ); -#define httplib_calloc(a, b) XX_httplib_calloc_ex(a, b, __FILE__, __LINE__) -#define httplib_free(a) XX_httplib_free_ex(a, __FILE__, __LINE__) -#define httplib_malloc(a) XX_httplib_malloc_ex(a, __FILE__, __LINE__) -#define httplib_realloc(a, b) XX_httplib_realloc_ex(a, b, __FILE__, __LINE__) +#define httplib_calloc(a, b) XX_httplib_calloc_ex(a, b, __FILE__, __LINE__) +#define httplib_free(a) XX_httplib_free_ex(a, __FILE__, __LINE__) +#define httplib_malloc(a) XX_httplib_malloc_ex(a, __FILE__, __LINE__) +#define httplib_realloc(a, b) XX_httplib_realloc_ex(a, b, __FILE__, __LINE__) -LIBHTTP_API void * XX_httplib_calloc_ex( size_t count, size_t size, const char *file, unsigned line ); -LIBHTTP_API void XX_httplib_free_ex( void *memory, const char *file, unsigned line ); -LIBHTTP_API void * XX_httplib_malloc_ex( size_t size, const char *file, unsigned line ); -LIBHTTP_API void * XX_httplib_realloc_ex( void *memory, size_t newsize, const char *file, unsigned line ); +LIBHTTP_API void * XX_httplib_calloc_ex( size_t count, size_t size, const char *file, unsigned line ); +LIBHTTP_API void XX_httplib_free_ex( void *memory, const char *file, unsigned line ); +LIBHTTP_API void * XX_httplib_malloc_ex( size_t size, const char *file, unsigned line ); +LIBHTTP_API void * XX_httplib_realloc_ex( void *memory, size_t newsize, const char *file, unsigned line ); -LIBHTTP_API int httplib_atomic_dec( volatile int *addr ); -LIBHTTP_API int httplib_atomic_inc( volatile int *addr ); -LIBHTTP_API int httplib_base64_encode( const unsigned char *src, int src_len, char *dst, int dst_len ); -LIBHTTP_API int httplib_closedir( DIR *dir ); -LIBHTTP_API void httplib_cry( const struct httplib_context *ctx, const struct httplib_connection *conn, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(3, 4); -LIBHTTP_API uint64_t httplib_get_random( void ); -LIBHTTP_API void * httplib_get_user_connection_data( const struct httplib_connection *conn ); -LIBHTTP_API int httplib_kill( pid_t pid, int sig_num ); -LIBHTTP_API int httplib_mkdir( const char *path, int mode ); -LIBHTTP_API DIR * httplib_opendir( const char *name ); -LIBHTTP_API int httplib_poll( struct pollfd *pfd, unsigned int nfds, int timeout ); -LIBHTTP_API int httplib_pthread_cond_broadcast( pthread_cond_t *cv ); -LIBHTTP_API int httplib_pthread_cond_destroy( pthread_cond_t *cv ); -LIBHTTP_API int httplib_pthread_cond_init( pthread_cond_t *cv, const pthread_condattr_t *attr ); -LIBHTTP_API int httplib_pthread_cond_signal( pthread_cond_t *cv ); -LIBHTTP_API int httplib_pthread_cond_timedwait( pthread_cond_t *cv, pthread_mutex_t *mutex, const struct timespec *abstime ); -LIBHTTP_API int httplib_pthread_cond_wait( pthread_cond_t *cv, pthread_mutex_t *mutex ); -LIBHTTP_API void * httplib_pthread_getspecific( pthread_key_t key ); -LIBHTTP_API int httplib_pthread_join( pthread_t thread, void **value_ptr ); -LIBHTTP_API int httplib_pthread_key_create( pthread_key_t *key, void (*destructor)(void *) ); -LIBHTTP_API int httplib_pthread_key_delete( pthread_key_t key ); -LIBHTTP_API int httplib_pthread_mutex_destroy( pthread_mutex_t *mutex ); -LIBHTTP_API int httplib_pthread_mutex_init( pthread_mutex_t *mutex, const pthread_mutexattr_t *attr ); -LIBHTTP_API int httplib_pthread_mutex_lock( pthread_mutex_t *mutex ); -LIBHTTP_API int httplib_pthread_mutex_trylock( pthread_mutex_t *mutex ); -LIBHTTP_API int httplib_pthread_mutex_unlock( pthread_mutex_t *mutex ); -LIBHTTP_API pthread_t httplib_pthread_self( void ); -LIBHTTP_API int httplib_pthread_setspecific( pthread_key_t key, void *value ); -LIBHTTP_API struct dirent * httplib_readdir( DIR *dir ); -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 ); -LIBHTTP_API char * httplib_strdup( const char *str ); -LIBHTTP_API void httplib_strlcpy( char *dst, const char *src, size_t len ); -LIBHTTP_API int httplib_strncasecmp( const char *s1, const char *s2, size_t len ); -LIBHTTP_API char * httplib_strndup( const char *str, size_t len ); -LIBHTTP_API const char * httplib_version( void ); +LIBHTTP_API int httplib_atomic_dec( volatile int *addr ); +LIBHTTP_API int httplib_atomic_inc( volatile int *addr ); +LIBHTTP_API int httplib_base64_encode( const unsigned char *src, int src_len, char *dst, int dst_len ); +LIBHTTP_API unsigned httplib_check_feature( unsigned feature ); +LIBHTTP_API int httplib_closedir( DIR *dir ); +LIBHTTP_API void httplib_cry( const struct httplib_context *ctx, const struct httplib_connection *conn, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(3, 4); +LIBHTTP_API const char * httplib_get_builtin_mime_type( const char *file_name ); +LIBHTTP_API uint64_t httplib_get_random( void ); +LIBHTTP_API void * httplib_get_user_connection_data( const struct httplib_connection *conn ); +LIBHTTP_API int httplib_kill( pid_t pid, int sig_num ); +LIBHTTP_API int httplib_mkdir( const char *path, int mode ); +LIBHTTP_API DIR * httplib_opendir( const char *name ); +LIBHTTP_API int httplib_poll( struct pollfd *pfd, unsigned int nfds, int timeout ); +LIBHTTP_API int httplib_pthread_cond_broadcast( pthread_cond_t *cv ); +LIBHTTP_API int httplib_pthread_cond_destroy( pthread_cond_t *cv ); +LIBHTTP_API int httplib_pthread_cond_init( pthread_cond_t *cv, const pthread_condattr_t *attr ); +LIBHTTP_API int httplib_pthread_cond_signal( pthread_cond_t *cv ); +LIBHTTP_API int httplib_pthread_cond_timedwait( pthread_cond_t *cv, pthread_mutex_t *mutex, const struct timespec *abstime ); +LIBHTTP_API int httplib_pthread_cond_wait( pthread_cond_t *cv, pthread_mutex_t *mutex ); +LIBHTTP_API void * httplib_pthread_getspecific( pthread_key_t key ); +LIBHTTP_API int httplib_pthread_join( pthread_t thread, void **value_ptr ); +LIBHTTP_API int httplib_pthread_key_create( pthread_key_t *key, void (*destructor)(void *) ); +LIBHTTP_API int httplib_pthread_key_delete( pthread_key_t key ); +LIBHTTP_API int httplib_pthread_mutex_destroy( pthread_mutex_t *mutex ); +LIBHTTP_API int httplib_pthread_mutex_init( pthread_mutex_t *mutex, const pthread_mutexattr_t *attr ); +LIBHTTP_API int httplib_pthread_mutex_lock( pthread_mutex_t *mutex ); +LIBHTTP_API int httplib_pthread_mutex_trylock( pthread_mutex_t *mutex ); +LIBHTTP_API int httplib_pthread_mutex_unlock( pthread_mutex_t *mutex ); +LIBHTTP_API pthread_t httplib_pthread_self( void ); +LIBHTTP_API int httplib_pthread_setspecific( pthread_key_t key, void *value ); +LIBHTTP_API struct dirent * httplib_readdir( DIR *dir ); +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 ); +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 ); +LIBHTTP_API char * httplib_strdup( const char *str ); +LIBHTTP_API void httplib_strlcpy( char *dst, const char *src, size_t len ); +LIBHTTP_API int httplib_strncasecmp( const char *s1, const char *s2, size_t len ); +LIBHTTP_API char * httplib_strndup( const char *str, size_t len ); +LIBHTTP_API const char * httplib_version( void ); #ifdef __cplusplus } diff --git a/src/httplib_cry.c b/src/httplib_cry.c index c5382ff4..8f45cea7 100644 --- a/src/httplib_cry.c +++ b/src/httplib_cry.c @@ -20,9 +20,6 @@ * 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. - * - * ============ - * Release: 2.0 */ #include "httplib_main.h" @@ -32,7 +29,8 @@ * void httplib_cry( const struct httplib_context *ctx, const struct httplib_connection *conn, const char *fmt, ... ); * * The function httplib_cry() prints a formatted error message to the opened - * error log stream. + * error log stream. It first tries to use a user supplied error handler. If + * that doesn't work, the alternative is to write to an error log file. */ void httplib_cry( const struct httplib_context *ctx, const struct httplib_connection *conn, const char *fmt, ... ) { @@ -43,47 +41,70 @@ void httplib_cry( const struct httplib_context *ctx, const struct httplib_connec struct file fi; time_t timestamp; + /* + * Check if we have a context. Without a context there is no callback + * and also other important information like the path to the error file + * is missing. No need to continue if that information cannot be + * retrieved. + */ + + if ( ctx == NULL ) return; + + /* + * Gather all the information from the parameters of this function and + * create a NULL terminated string buffer with the error message. + */ + va_start( ap, fmt ); vsnprintf_impl( buf, sizeof(buf), fmt, ap ); va_end( ap ); buf[sizeof(buf)-1] = 0; - if ( ctx == NULL ) return; - /* - * Do not lock when getting the callback value, here and below. - * I suppose this is fine, since function cannot disappear in the - * same way string option can. + * Let's first try to use the user's custom error handler callback. If + * that succeeds, there is no need for us to do our own error + * processing. */ - if ( conn == NULL || ctx->callbacks.log_message == NULL || ctx->callbacks.log_message( conn, buf ) == 0 ) { + if ( ctx->callbacks.log_message != NULL && ctx->callbacks.log_message( ctx, conn, buf ) != 0 ) return; - if ( ctx->cfg[ERROR_LOG_FILE] != NULL ) { + /* + * We now try to open the error log file. If this succeeds the error is + * appended to the file. On failure there is no way to log the message + * without disrupting the user's flow of control so we just return and + * logging anything. This is IMHO better than printing to stderr which + * may not even be available on all platforms (Windows etc). + */ - if ( XX_httplib_fopen( conn, ctx->cfg[ERROR_LOG_FILE], "a+", &fi ) == 0 ) fi.fp = NULL; - } - - else fi.fp = NULL; + if ( ctx->cfg[ERROR_LOG_FILE] == NULL ) return; + if ( ! XX_httplib_fopen( conn, ctx->cfg[ERROR_LOG_FILE], "a+", &fi ) ) return; - if ( fi.fp != NULL ) { + /* + * We now have an open FILE stream pointer in fi.fp and can dump the + * message in that file. Note though, that some information might not + * be available for logging if the message has no connection, so some + * information is skipped if the 'conn' parameter is NULL. + * + * Just to be sure that no other process is writing to the same file, + * we use locking around this operation. + */ - flockfile( fi.fp ); - timestamp = time( NULL ); + flockfile( fi.fp ); + timestamp = time( NULL ); - 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 != 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 != NULL && 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 ); - } - - fprintf( fi.fp, "%s", buf ); - fputc( '\n', fi.fp ); - fflush( fi.fp ); - funlockfile( fi.fp ); - XX_httplib_fclose( &fi ); - } + fprintf( fi.fp, "%s %s: ", conn->request_info.request_method, conn->request_info.request_uri ); } + fprintf( fi.fp, "%s", buf ); + fputc( '\n', fi.fp ); + fflush( fi.fp ); + + funlockfile( fi.fp ); + XX_httplib_fclose( &fi ); + } /* httplib_cry */ diff --git a/src/httplib_main.h b/src/httplib_main.h index 492a1528..6eb60649 100644 --- a/src/httplib_main.h +++ b/src/httplib_main.h @@ -24,10 +24,6 @@ -#ifndef UNUSED_PARAMETER -#define UNUSED_PARAMETER(x) (void)(x) -#endif /* UNUSED_PARAMETER */ - #if defined(_WIN32) #if !defined(_CRT_SECURE_NO_WARNINGS) diff --git a/src/httplib_start.c b/src/httplib_start.c index 4e392a9d..cb0f5ab8 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, char *ebuf, size_t ebuf_len, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(4, 5); +static struct httplib_context * cleanup( struct httplib_context *ctx, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3); /* - * 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 *httplib_start( const struct httplib_callbacks *callbacks, void *user_data, const char **options ); * * 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, char *ebuf, size_t ebuf_len ) { +struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks, void *user_data, const char **options ) { struct httplib_context *ctx; const char *name; @@ -50,21 +50,50 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks int idx; int workerthreadcount; unsigned int i; - void (*exit_callback)(const struct httplib_context *ctx) = NULL; + void (*exit_callback)(const struct httplib_context *ctx); struct httplib_workerTLS tls; - if ( ebuf != NULL && ebuf_len > 0 ) ebuf[0] = '\0'; - #if defined(_WIN32) + + /* + * Yes, this is Windows and nothing works out of the box. We first have + * to initialize socket communications by telling Windows which socket + * version we want to use. 2.2 in this case. + */ + WSADATA data; - WSAStartup(MAKEWORD(2, 2), &data); + WSAStartup( MAKEWORD(2, 2), &data ); + #endif /* _WIN32 */ - ctx = httplib_calloc( 1, sizeof(*ctx) ); - if ( ctx == NULL ) { - - if ( ebuf != NULL && ebuf_len > 0 ) snprintf( ebuf, ebuf_len, "No memory for CTX structure" ); - return NULL; + /* + * No memory for the ctx structure is the only error which we + * don't log through httplib_cry() for the simple reason that we do not + * have enough configured yet to make that function working. Having an + * OOM in this state of the process though should be noticed by the + * calling process in other parts of their execution anyway. + */ + + exit_callback = NULL; + ctx = httplib_calloc( 1, sizeof(*ctx) ); + + if ( ctx == NULL ) return NULL; + + /* + * Setup callback functions very early. This is necessary to make the + * log_message() callback function available in case an error occurs. + * + * We first set the exit_context() callback to NULL becasue no proper + * context is available yet and we do not want to mess up things if the + * function exits and that callback is given a half-decent structure to + * work on and without a call to init_context() before. + */ + + if ( callbacks != NULL ) { + + ctx->callbacks = *callbacks; + exit_callback = callbacks->exit_context; + ctx->callbacks.exit_context = NULL; } /* @@ -93,15 +122,16 @@ 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; } } else { - /* TODO (low): istead of sleeping, check if XX_httplib_sTlsKey is already - * initialized. */ + /* + * TODO (low): istead of sleeping, check if XX_httplib_sTlsKey is already + * initialized. + */ + httplib_sleep( 1 ); } @@ -112,19 +142,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, ebuf, ebuf_len, "Cannot initialize thread mutex" ); + if ( httplib_pthread_mutex_init( & ctx->thread_mutex, &XX_httplib_pthread_mutex_attr ) ) return cleanup( ctx, "Cannot initialize thread mutex" ); #if !defined(ALTERNATIVE_QUEUE) - 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" ); + 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" ); #endif - 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 ) { - - ctx->callbacks = *callbacks; - exit_callback = callbacks->exit_context; - ctx->callbacks.exit_context = 0; - } + if ( httplib_pthread_mutex_init( & ctx->nonce_mutex, & XX_httplib_pthread_mutex_attr ) ) return cleanup( ctx, "Cannot initialize nonce mutex" ); ctx->user_data = user_data; ctx->handlers = NULL; @@ -132,8 +155,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, 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 ( idx == -1 ) return cleanup( ctx, "Invalid option: %s", name ); + if ( (value = *options++) == NULL ) return cleanup( ctx, "%s: option value cannot be NULL", name ); if ( ctx->cfg[idx] != NULL ) { @@ -161,13 +184,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, ebuf, ebuf_len, "Error setting gpass option" ); + if ( ! XX_httplib_set_gpass_option( ctx ) ) return cleanup( ctx, "Error setting gpass option" ); #if !defined(NO_SSL) - if ( ! XX_httplib_set_ssl_option( ctx ) ) return cleanup( ctx, ebuf, ebuf_len, "Error setting SSL option" ); + if ( ! XX_httplib_set_ssl_option( ctx ) ) return cleanup( ctx, "Error setting SSL option" ); #endif - 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 ( ! 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 !defined(_WIN32) @@ -180,40 +203,43 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks #endif /* !_WIN32 */ - if ( ctx->cfg[NUM_THREADS] == NULL ) return cleanup( ctx, ebuf, ebuf_len, "No worker thread number specified" ); + if ( ctx->cfg[NUM_THREADS] == NULL ) return cleanup( ctx, "No worker thread number specified" ); workerthreadcount = atoi( ctx->cfg[NUM_THREADS] ); - if ( workerthreadcount > MAX_WORKER_THREADS ) return cleanup( ctx, ebuf, ebuf_len, "Too many worker threads" ); + if ( workerthreadcount > MAX_WORKER_THREADS ) return cleanup( ctx, "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, ebuf, ebuf_len, "Not enough memory for worker thread ID array" ); + if ( ctx->workerthreadids == NULL ) return cleanup( ctx, "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, ebuf, ebuf_len, "Not enough memory for worker event array" ); + if ( ctx->client_wait_events == NULL ) return cleanup( ctx, "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, ebuf, ebuf_len, "Not enough memory for worker socket array" ); + if ( ctx->client_socks == NULL ) return cleanup( ctx, "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, ebuf, ebuf_len, "Error creating worker event %u", i ); + if ( ctx->client_wait_events[i] == 0 ) return cleanup( ctx, "Error creating worker event %u", i ); } #endif } #if defined(USE_TIMERS) - if ( timers_init( ctx ) != 0 ) return cleanup( ctx, ebuf, ebuf_len, "Error creating timers" ); + if ( timers_init( ctx ) != 0 ) return cleanup( ctx, "Error creating timers" ); #endif /* * Context has been created - init user libraries + * + * Context has been properly setup. It is now safe to use exit_context + * in case the system needs a shutdown. */ if ( ctx->callbacks.init_context != NULL ) ctx->callbacks.init_context( ctx ); @@ -252,7 +278,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, ebuf, ebuf_len, "Cannot create threads: error %ld", (long)ERRNO ); + else return cleanup( ctx, "Cannot create threads: error %ld", (long)ERRNO ); break; } @@ -267,14 +293,14 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks /* - * static struct httplib_context *cleanup( struct httplib_context *ctx, char *ebuf, size_t ebuf_len, const char *fmt, ... ); + * static struct httplib_context *cleanup( struct httplib_context *ctx, 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, char *ebuf, size_t ebuf_len, const char *fmt, ... ) { +static struct httplib_context *cleanup( struct httplib_context *ctx, const char *fmt, ... ) { va_list ap; char buf[MG_BUF_LEN]; @@ -284,8 +310,6 @@ static struct httplib_context *cleanup( struct httplib_context *ctx, char *ebuf, va_end( ap ); buf[sizeof(buf)-1] = 0; - 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 ); diff --git a/src/main.c b/src/main.c index b6c02adf..4090a175 100644 --- a/src/main.c +++ b/src/main.c @@ -606,19 +606,20 @@ static void init_server_name(int argc, const char *argv[]) { } -static int log_message(const struct httplib_connection *conn, const char *message) { +static int log_message( const struct httplib_context *ctx, const struct httplib_connection *conn, const char *message ) { - const struct httplib_context *ctx = httplib_get_context(conn); - struct tuser_data *ud = (struct tuser_data *)httplib_get_user_data(ctx); + struct tuser_data *ud; - fprintf(stderr, "%s\n", message); + UNUSED_PARAMETER(conn); - if (ud->first_message == NULL) { - ud->first_message = sdup(message); - } + fprintf( stderr, "%s\n", message ); + + ud = httplib_get_user_data( ctx ); + if ( ud != NULL && ud->first_message == NULL ) ud->first_message = sdup( message ); return 0; -} + +} /* log_message */ static int is_path_absolute(const char *path) { @@ -869,7 +870,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, NULL, 0 ); + g_ctx = httplib_start(&callbacks, &g_user_data, (const char **)options ); /* httplib_start copies all options to an internal buffer. * The options data field here is not required anymore. */