diff --git a/src/civetweb.c b/src/civetweb.c index b3346a34..5fd643ff 100644 --- a/src/civetweb.c +++ b/src/civetweb.c @@ -164,7 +164,7 @@ typedef HANDLE pthread_mutex_t; typedef struct { HANDLE signal, broadcast; } pthread_cond_t; -typedef DWORD pthread_t; +typedef HANDLE pthread_t; #define pid_t HANDLE // MINGW typedefs pid_t to int. Using #define here. static int pthread_mutex_lock(pthread_mutex_t *); @@ -267,7 +267,7 @@ typedef int SOCKET; #ifdef _WIN32 static CRITICAL_SECTION global_log_file_lock; -static pthread_t pthread_self(void) +static DWORD pthread_self(void) { return GetCurrentThreadId(); } @@ -507,6 +507,8 @@ struct mg_request_handler_info { struct mg_context { volatile int stop_flag; // Should we stop event loop + void *ssllib_dll_handle; // Store the ssl library handle. + void *cryptolib_dll_handle; // Store the crypto library handle. SSL_CTX *ssl_ctx; // SSL context char *config[NUM_OPTIONS]; // Civetweb configuration parameters struct mg_callbacks callbacks; // User-defined callback function @@ -524,6 +526,9 @@ struct mg_context { volatile int sq_tail; // Tail of the socket queue pthread_cond_t sq_full; // Signaled when socket is produced pthread_cond_t sq_empty; // Signaled when socket is consumed + pthread_t masterthreadid; // The master thread ID. + int workerthreadcount; // The amount of worker threads. + pthread_t *workerthreadids;// The worker thread IDs. // linked list of uri handlers struct mg_request_handler_info *request_handlers; @@ -655,7 +660,7 @@ void mg_cry(struct mg_connection *conn, const char *fmt, ...) time_t timestamp; va_start(ap, fmt); - (void) vsnprintf(buf, sizeof(buf), fmt, ap); + IGNORE_UNUSED_RESULT(vsnprintf(buf, sizeof(buf), fmt, ap)); va_end(ap); // Do not lock when getting the callback value, here and below. @@ -663,7 +668,7 @@ void mg_cry(struct mg_connection *conn, const char *fmt, ...) // same way string option can. if (conn->ctx->callbacks.log_message == NULL || conn->ctx->callbacks.log_message(conn, buf) == 0) { - fp = conn->ctx == NULL || conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL : + fp = conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL : fopen(conn->ctx->config[ERROR_LOG_FILE], "a+"); if (fp != NULL) { @@ -1341,8 +1346,9 @@ static int poll(struct pollfd *pfd, int n, int milliseconds) } #endif // HAVE_POLL -static void set_close_on_exec(SOCKET sock) +static void set_close_on_exec(SOCKET sock, struct mg_connection *conn) { + (void) conn; /* Unused. */ (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0); } @@ -1351,6 +1357,50 @@ int mg_start_thread(mg_thread_func_t f, void *p) return (long)_beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0; } +/* Start a thread storing the thread context. */ + +static int mg_start_thread_with_id(unsigned (__stdcall *f)(void *), void *p, + pthread_t *threadidptr) +{ + uintptr_t uip; + HANDLE threadhandle; + int result; + + uip = _beginthreadex(NULL, 0, (unsigned (__stdcall *)(void *)) f, p, 0, + NULL); + threadhandle = (HANDLE) uip; + if (threadidptr != NULL) { + *threadidptr = threadhandle; + } + result = (threadhandle == NULL) ? -1 : 0; + + return result; +} + +/* Wait for a thread to finish. */ + +static int mg_join_thread(pthread_t threadid) +{ + int result; + DWORD dwevent; + + result = -1; + dwevent = WaitForSingleObject(threadid, INFINITE); + if (dwevent == WAIT_FAILED) { + int err; + + err = GetLastError(); + DEBUG_TRACE(("WaitForSingleObject() failed, error %d", err)); + } else { + if (dwevent == WAIT_OBJECT_0) { + CloseHandle(threadid); + result = 0; + } + } + + return result; +} + static HANDLE dlopen(const char *dll_name, int flags) { wchar_t wbuf[PATH_MAX]; @@ -1359,6 +1409,19 @@ static HANDLE dlopen(const char *dll_name, int flags) return LoadLibraryW(wbuf); } +static int dlclose(void *handle) +{ + int result; + + if (FreeLibrary(handle) != 0) { + result = 0; + } else { + result = -1; + } + + return result; +} + #if !defined(NO_CGI) #define SIGKILL 0 static int kill(pid_t pid, int sig_num) @@ -1473,9 +1536,12 @@ static int mg_stat(struct mg_connection *conn, const char *path, return filep->membuf != NULL || filep->modification_time != (time_t) 0; } -static void set_close_on_exec(int fd) +static void set_close_on_exec(int fd, struct mg_connection *conn) { - fcntl(fd, F_SETFD, FD_CLOEXEC); + if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { + mg_cry(conn, "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s", + __func__, strerror(ERRNO)); + } } int mg_start_thread(mg_thread_func_t func, void *param) @@ -1487,10 +1553,10 @@ int mg_start_thread(mg_thread_func_t func, void *param) (void) pthread_attr_init(&attr); (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); -#if USE_STACK_SIZE > 1 +#if defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 // Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384 (void) pthread_attr_setstacksize(&attr, USE_STACK_SIZE); -#endif +#endif /* defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 */ result = pthread_create(&thread_id, &attr, func, param); pthread_attr_destroy(&attr); @@ -1498,6 +1564,40 @@ int mg_start_thread(mg_thread_func_t func, void *param) return result; } +/* Start a thread storing the thread context. */ + +static int mg_start_thread_with_id(mg_thread_func_t func, void *param, + pthread_t *threadidptr) +{ + pthread_t thread_id; + pthread_attr_t attr; + int result; + + (void) pthread_attr_init(&attr); + +#if defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 + // Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384 + (void) pthread_attr_setstacksize(&attr, USE_STACK_SIZE); +#endif /* defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 */ + + result = pthread_create(&thread_id, &attr, func, param); + pthread_attr_destroy(&attr); + if (threadidptr != NULL) { + *threadidptr = thread_id; + } + return result; +} + +/* Wait for a thread to finish. */ + +static int mg_join_thread(pthread_t threadid) +{ + int result; + + result = pthread_join(threadid, NULL); + return result; +} + #ifndef NO_CGI static pid_t spawn_process(struct mg_connection *conn, const char *prog, char *envblk, char *envp[], int fdin, @@ -1732,6 +1832,7 @@ static int alloc_vprintf2(char **buf, const char *fmt, va_list ap) if (!*buf) break; va_copy(ap_copy, ap); len = vsnprintf(*buf, size, fmt, ap_copy); + va_end(ap_copy); } return len; @@ -1752,24 +1853,29 @@ static int alloc_vprintf(char **buf, size_t size, const char *fmt, va_list ap) // On second pass, actually print the message. va_copy(ap_copy, ap); len = vsnprintf(NULL, 0, fmt, ap_copy); + va_end(ap_copy); if (len < 0) { // C runtime is not standard compliant, vsnprintf() returned -1. // Switch to alternative code path that uses incremental allocations. va_copy(ap_copy, ap); len = alloc_vprintf2(buf, fmt, ap); + va_end(ap_copy); } else if (len > (int) size && (size = len + 1) > 0 && (*buf = (char *) malloc(size)) == NULL) { len = -1; // Allocation failed, mark failure } else { va_copy(ap_copy, ap); - vsnprintf(*buf, size, fmt, ap_copy); + IGNORE_UNUSED_RESULT(vsnprintf(*buf, size, fmt, ap_copy)); + va_end(ap_copy); } return len; } +int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap); + int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap) { char mem[MG_BUF_LEN], *buf = mem; @@ -1788,8 +1894,13 @@ int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap) int mg_printf(struct mg_connection *conn, const char *fmt, ...) { va_list ap; + int result; + va_start(ap, fmt); - return mg_vprintf(conn, fmt, ap); + result = mg_vprintf(conn, fmt, ap); + va_end(ap); + + return result; } int mg_url_decode(const char *src, int src_len, char *dst, @@ -2046,7 +2157,8 @@ static time_t parse_date_string(const char *datetime) leap_days = num_leap_years(year) - num_leap_years(1970); year -= 1970; days = year * 365 + days_before_month[month] + (day - 1) + leap_days; - result = days * 24 * 3600 + hour * 3600 + minute * 60 + second; + result = (time_t) days * 24 * 3600 + (time_t) hour * 3600 + + minute * 60 + second; } return result; @@ -2258,7 +2370,9 @@ static void open_auth_file(struct mg_connection *conn, const char *path, } else if (mg_stat(conn, path, &file) && file.is_directory) { mg_snprintf(conn, name, sizeof(name), "%s%c%s", path, '/', PASSWORDS_FILE_NAME); - mg_fopen(conn, name, "r", filep); + if (!mg_fopen(conn, name, "r", filep)) { + mg_cry(conn, "fopen(%s): %s", name, strerror(ERRNO)); + } } else { // Try to find .htpasswd in requested directory. for (p = path, e = p + strlen(p) - 1; e > p; e--) @@ -2266,7 +2380,9 @@ static void open_auth_file(struct mg_connection *conn, const char *path, break; mg_snprintf(conn, name, sizeof(name), "%.*s%c%s", (int) (e - p), p, '/', PASSWORDS_FILE_NAME); - mg_fopen(conn, name, "r", filep); + if (!mg_fopen(conn, name, "r", filep)) { + mg_cry(conn, "fopen(%s): %s", name, strerror(ERRNO)); + } } } @@ -2510,16 +2626,16 @@ int mg_modify_passwords_file(const char *fname, const char *domain, fclose(fp2); // Put the temp file in place of real file - remove(fname); + IGNORE_UNUSED_RESULT(remove(fname)); IGNORE_UNUSED_RESULT(rename(tmp, fname)); return 1; } -static SOCKET conn2(const char *host, int port, int use_ssl, - char *ebuf, size_t ebuf_len) +static SOCKET conn2(struct mg_context *ctx, const char *host, int port, + int use_ssl, char *ebuf, size_t ebuf_len) { - struct sockaddr_in sin; + struct sockaddr_in sain; struct hostent *he; SOCKET sock = INVALID_SOCKET; @@ -2533,11 +2649,12 @@ static SOCKET conn2(const char *host, int port, int use_ssl, } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { snprintf(ebuf, ebuf_len, "socket(): %s", strerror(ERRNO)); } else { - set_close_on_exec(sock); - sin.sin_family = AF_INET; - sin.sin_port = htons((uint16_t) port); - sin.sin_addr = * (struct in_addr *) he->h_addr_list[0]; - if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) { + set_close_on_exec(sock, fc(ctx)); + memset(&sain, '\0', sizeof(sain)); + sain.sin_family = AF_INET; + sain.sin_port = htons((uint16_t) port); + sain.sin_addr = * (struct in_addr *) he->h_addr_list[0]; + if (connect(sock, (struct sockaddr *) &sain, sizeof(sain)) != 0) { snprintf(ebuf, ebuf_len, "connect(%s:%d): %s", host, port, strerror(ERRNO)); closesocket(sock); @@ -2575,6 +2692,7 @@ int mg_url_encode(const char *src, char *dst, size_t dst_len) static void print_dir_entry(struct de *de) { char size[64], mod[64], href[PATH_MAX]; + struct tm *tm; if (de->file.is_directory) { mg_snprintf(de->conn, size, sizeof(size), "%s", "[DIRECTORY]"); @@ -2594,8 +2712,13 @@ static void print_dir_entry(struct de *de) "%.1fG", (double) de->file.size / 1073741824); } } - strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", - localtime(&de->file.modification_time)); + tm = localtime(&de->file.modification_time); + if (tm != NULL) { + strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", tm); + } else { + strncpy(mod, "01-Jan-1970 00:00", sizeof(mod)); + mod[sizeof(mod) - 1] = '\0'; + } mg_url_encode(de->file_name, href, sizeof(href)); de->conn->num_bytes_sent += mg_printf(de->conn, "