http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/examples/celix-examples/civetweb/civetweb/civetweb.c ---------------------------------------------------------------------- diff --git a/examples/celix-examples/civetweb/civetweb/civetweb.c b/examples/celix-examples/civetweb/civetweb/civetweb.c new file mode 100644 index 0000000..259663a --- /dev/null +++ b/examples/celix-examples/civetweb/civetweb/civetweb.c @@ -0,0 +1,19792 @@ +/* Copyright (c) 2013-2018 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. + */ + +#if defined(__GNUC__) || defined(__MINGW32__) +/* Disable unused macros warnings - not all defines are required + * for all systems and all compilers. */ +#pragma GCC diagnostic ignored "-Wunused-macros" +/* A padding warning is just plain useless */ +#pragma GCC diagnostic ignored "-Wpadded" +#endif + +#if defined(__clang__) /* GCC does not (yet) support this pragma */ +/* We must set some flags for the headers we include. These flags + * are reserved ids according to C99, so we need to disable a + * warning for that. */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wreserved-id-macro" +#endif + +#if defined(_WIN32) +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005 */ +#endif +#if !defined(_WIN32_WINNT) /* defined for tdm-gcc so we can use getnameinfo */ +#define _WIN32_WINNT 0x0501 +#endif +#else +#if !defined(_GNU_SOURCE) +#define _GNU_SOURCE /* for setgroups(), pthread_setname_np() */ +#endif +#if defined(__linux__) && !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE 600 /* For flockfile() on Linux */ +#endif +#if !defined(_LARGEFILE_SOURCE) +#define _LARGEFILE_SOURCE /* For fseeko(), ftello() */ +#endif +#if !defined(_FILE_OFFSET_BITS) +#define _FILE_OFFSET_BITS 64 /* Use 64-bit file offsets by default */ +#endif +#if !defined(__STDC_FORMAT_MACROS) +#define __STDC_FORMAT_MACROS /* <inttypes.h> wants this for C++ */ +#endif +#if !defined(__STDC_LIMIT_MACROS) +#define __STDC_LIMIT_MACROS /* C++ wants that for INT64_MAX */ +#endif +#if !defined(_DARWIN_UNLIMITED_SELECT) +#define _DARWIN_UNLIMITED_SELECT +#endif +#if defined(__sun) +#define __EXTENSIONS__ /* to expose flockfile and friends in stdio.h */ +#define __inline inline /* not recognized on older compiler versions */ +#endif +#endif + +#if defined(__clang__) +/* Enable reserved-id-macro warning again. */ +#pragma GCC diagnostic pop +#endif + + +#if defined(USE_LUA) +#define USE_TIMERS +#endif + +#if defined(_MSC_VER) +/* 'type cast' : conversion from 'int' to 'HANDLE' of greater size */ +#pragma warning(disable : 4306) +/* conditional expression is constant: introduced by FD_SET(..) */ +#pragma warning(disable : 4127) +/* non-constant aggregate initializer: issued due to missing C99 support */ +#pragma warning(disable : 4204) +/* padding added after data member */ +#pragma warning(disable : 4820) +/* not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +#pragma warning(disable : 4668) +/* no function prototype given: converting '()' to '(void)' */ +#pragma warning(disable : 4255) +/* function has been selected for automatic inline expansion */ +#pragma warning(disable : 4711) +#endif + + +/* This code uses static_assert to check some conditions. + * Unfortunately some compilers still do not support it, so we have a + * replacement function here. */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201100L +#define mg_static_assert _Static_assert +#elif defined(__cplusplus) && __cplusplus >= 201103L +#define mg_static_assert static_assert +#else +char static_assert_replacement[1]; +#define mg_static_assert(cond, txt) \ + extern char static_assert_replacement[(cond) ? 1 : -1] +#endif + +mg_static_assert(sizeof(int) == 4 || sizeof(int) == 8, +"int data type size check"); +mg_static_assert(sizeof(void *) == 4 || sizeof(void *) == 8, +"pointer data type size check"); +mg_static_assert(sizeof(void *) >= sizeof(int), "data type size check"); + + +/* Alternative queue is well tested and should be the new default */ +#if defined(NO_ALTERNATIVE_QUEUE) +#if defined(ALTERNATIVE_QUEUE) +#error "Define ALTERNATIVE_QUEUE or NO_ALTERNATIVE_QUEUE or none, but not both" +#endif +#else +#define ALTERNATIVE_QUEUE +#endif + + +/* DTL -- including winsock2.h works better if lean and mean */ +#if !defined(WIN32_LEAN_AND_MEAN) +#define WIN32_LEAN_AND_MEAN +#endif + +#if defined(__SYMBIAN32__) +/* According to https://en.wikipedia.org/wiki/Symbian#History, + * Symbian is no longer maintained since 2014-01-01. + * Recent versions of CivetWeb are no longer tested for Symbian. + * It makes no sense, to support an abandoned operating system. + */ +#error "Symbian is no longer maintained. CivetWeb no longer supports Symbian." +#define NO_SSL /* SSL is not supported */ +#define NO_CGI /* CGI is not supported */ +#define PATH_MAX FILENAME_MAX +#endif /* __SYMBIAN32__ */ + + +#if !defined(CIVETWEB_HEADER_INCLUDED) +/* Include the header file here, so the CivetWeb interface is defined for the + * entire implementation, including the following forward definitions. */ +#include "civetweb.h" +#endif + +#if !defined(DEBUG_TRACE) +#if defined(DEBUG) +static void DEBUG_TRACE_FUNC(const char *func, +unsigned line, +PRINTF_FORMAT_STRING(const char *fmt), +...) PRINTF_ARGS(3, 4); + +#define DEBUG_TRACE(fmt, ...) \ + DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__) + +#define NEED_DEBUG_TRACE_FUNC + +#else +#define DEBUG_TRACE(fmt, ...) \ + do { \ + } while (0) +#endif /* DEBUG */ +#endif /* DEBUG_TRACE */ + + +#if !defined(DEBUG_ASSERT) +#if defined(DEBUG) +#define DEBUG_ASSERT(cond) \ + do { \ + if (!(cond)) { \ + DEBUG_TRACE("ASSERTION FAILED: %s", #cond); \ + exit(2); /* Exit with error */ \ + } \ + } while (0) +#else +#define DEBUG_ASSERT(cond) +#endif /* DEBUG */ +#endif + + +#if !defined(IGNORE_UNUSED_RESULT) +#define IGNORE_UNUSED_RESULT(a) ((void)((a) && 1)) +#endif + + +#if defined(__GNUC__) || defined(__MINGW32__) + +/* GCC unused function attribute seems fundamentally broken. + * Several attempts to tell the compiler "THIS FUNCTION MAY BE USED + * OR UNUSED" for individual functions failed. + * Either the compiler creates an "unused-function" warning if a + * function is not marked with __attribute__((unused)). + * On the other hand, if the function is marked with this attribute, + * but is used, the compiler raises a completely idiotic + * "used-but-marked-unused" warning - and + * #pragma GCC diagnostic ignored "-Wused-but-marked-unused" + * raises error: unknown option after "#pragma GCC diagnostic". + * Disable this warning completely, until the GCC guys sober up + * again. + */ + +#pragma GCC diagnostic ignored "-Wunused-function" + +#define FUNCTION_MAY_BE_UNUSED /* __attribute__((unused)) */ + +#else +#define FUNCTION_MAY_BE_UNUSED +#endif + + +/* Some ANSI #includes are not available on Windows CE */ +#if !defined(_WIN32_WCE) +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <signal.h> +#include <fcntl.h> +#endif /* !_WIN32_WCE */ + + +#if defined(__clang__) +/* When using -Weverything, clang does not accept it's own headers + * in a release build configuration. Disable what is too much in + * -Weverything. */ +#pragma clang diagnostic ignored "-Wdisabled-macro-expansion" +#endif + +#if defined(__GNUC__) || defined(__MINGW32__) +/* Who on earth came to the conclusion, using __DATE__ should rise + * an "expansion of date or time macro is not reproducible" + * warning. That's exactly what was intended by using this macro. + * Just disable this nonsense warning. */ + +/* And disabling them does not work either: + * #pragma clang diagnostic ignored "-Wno-error=date-time" + * #pragma clang diagnostic ignored "-Wdate-time" + * So we just have to disable ALL warnings for some lines + * of code. + * This seems to be a known GCC bug, not resolved since 2012: + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53431 + */ +#endif + + +#if defined(__MACH__) /* Apple OSX section */ + +#if defined(__clang__) +#if (__clang_major__ == 3) && ((__clang_minor__ == 7) || (__clang_minor__ == 8)) +/* Avoid warnings for Xcode 7. It seems it does no longer exist in Xcode 8 */ +#pragma clang diagnostic ignored "-Wno-reserved-id-macro" +#pragma clang diagnostic ignored "-Wno-keyword-macro" +#endif +#endif + +#define CLOCK_MONOTONIC (1) +#define CLOCK_REALTIME (2) + +#include <sys/errno.h> +#include <sys/time.h> +#include <mach/clock.h> +#include <mach/mach.h> +#include <mach/mach_time.h> + +/* clock_gettime is not implemented on OSX prior to 10.12 */ +static int +_civet_clock_gettime(int clk_id, struct timespec *t) +{ +memset(t, 0, sizeof(*t)); +if (clk_id == CLOCK_REALTIME) { +struct timeval now; +int rv = gettimeofday(&now, NULL); +if (rv) { +return rv; +} +t->tv_sec = now.tv_sec; +t->tv_nsec = now.tv_usec * 1000; +return 0; + +} else if (clk_id == CLOCK_MONOTONIC) { +static uint64_t clock_start_time = 0; +static mach_timebase_info_data_t timebase_ifo = {0, 0}; + +uint64_t now = mach_absolute_time(); + +if (clock_start_time == 0) { +kern_return_t mach_status = mach_timebase_info(&timebase_ifo); +DEBUG_ASSERT(mach_status == KERN_SUCCESS); + +/* appease "unused variable" warning for release builds */ +(void)mach_status; + +clock_start_time = now; +} + +now = (uint64_t)((double)(now - clock_start_time) +* (double)timebase_ifo.numer +/ (double)timebase_ifo.denom); + +t->tv_sec = now / 1000000000; +t->tv_nsec = now % 1000000000; +return 0; +} +return -1; /* EINVAL - Clock ID is unknown */ +} + +/* if clock_gettime is declared, then __CLOCK_AVAILABILITY will be defined */ +#if defined(__CLOCK_AVAILABILITY) +/* If we compiled with Mac OSX 10.12 or later, then clock_gettime will be + * declared but it may be NULL at runtime. So we need to check before using + * it. */ +static int +_civet_safe_clock_gettime(int clk_id, struct timespec *t) +{ +if (clock_gettime) { +return clock_gettime(clk_id, t); +} +return _civet_clock_gettime(clk_id, t); +} +#define clock_gettime _civet_safe_clock_gettime +#else +#define clock_gettime _civet_clock_gettime +#endif + +#endif + + +#include <time.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> +#include <limits.h> +#include <stddef.h> +#include <stdio.h> +#include <stdint.h> + +/********************************************************************/ +/* CivetWeb configuration defines */ +/********************************************************************/ + +/* Maximum number of threads that can be configured. + * The number of threads actually created depends on the "num_threads" + * configuration parameter, but this is the upper limit. */ +#if !defined(MAX_WORKER_THREADS) +#define MAX_WORKER_THREADS (1024 * 64) /* in threads (count) */ +#endif + +/* Timeout interval for select/poll calls. + * The timeouts depend on "*_timeout_ms" configuration values, but long + * timeouts are split into timouts as small as SOCKET_TIMEOUT_QUANTUM. + * This reduces the time required to stop the server. */ +#if !defined(SOCKET_TIMEOUT_QUANTUM) +#define SOCKET_TIMEOUT_QUANTUM (2000) /* in ms */ +#endif + +/* Do not try to compress files smaller than this limit. */ +#if !defined(MG_FILE_COMPRESSION_SIZE_LIMIT) +#define MG_FILE_COMPRESSION_SIZE_LIMIT (1024) /* in bytes */ +#endif + +#if !defined(PASSWORDS_FILE_NAME) +#define PASSWORDS_FILE_NAME ".htpasswd" +#endif + +/* Initial buffer size for all CGI environment variables. In case there is + * not enough space, another block is allocated. */ +#if !defined(CGI_ENVIRONMENT_SIZE) +#define CGI_ENVIRONMENT_SIZE (4096) /* in bytes */ +#endif + +/* Maximum number of environment variables. */ +#if !defined(MAX_CGI_ENVIR_VARS) +#define MAX_CGI_ENVIR_VARS (256) /* in variables (count) */ +#endif + +/* General purpose buffer size. */ +#if !defined(MG_BUF_LEN) /* in bytes */ +#define MG_BUF_LEN (1024 * 8) +#endif + +/* Size of the accepted socket queue (in case the old queue implementation + * is used). */ +#if !defined(MGSQLEN) +#define MGSQLEN (20) /* count */ +#endif + + +/********************************************************************/ + +/* Helper makros */ +#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) + +/* Standard defines */ +#if !defined(INT64_MAX) +#define INT64_MAX (9223372036854775807) +#endif + +#define SHUTDOWN_RD (0) +#define SHUTDOWN_WR (1) +#define SHUTDOWN_BOTH (2) + +mg_static_assert(MAX_WORKER_THREADS >= 1, +"worker threads must be a positive number"); + +mg_static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8, +"size_t data type size check"); + +#if defined(_WIN32) /* WINDOWS include block */ +#include <winsock2.h> /* DTL add for SO_EXCLUSIVE */ +#include <ws2tcpip.h> +#include <windows.h> + +typedef const char *SOCK_OPT_TYPE; + +#if !defined(PATH_MAX) +#define W_PATH_MAX (MAX_PATH) +/* at most three UTF-8 chars per wchar_t */ +#define PATH_MAX (W_PATH_MAX * 3) +#else +#define W_PATH_MAX ((PATH_MAX + 2) / 3) +#endif + +mg_static_assert(PATH_MAX >= 1, "path length must be a positive number"); + +#if !defined(_IN_PORT_T) +#if !defined(in_port_t) +#define in_port_t u_short +#endif +#endif + +#if !defined(_WIN32_WCE) +#include <process.h> +#include <direct.h> +#include <io.h> +#else /* _WIN32_WCE */ +#define NO_CGI /* WinCE has no pipes */ +#define NO_POPEN /* WinCE has no popen */ + +typedef long off_t; + +#define errno ((int)(GetLastError())) +#define strerror(x) (_ultoa(x, (char *)_alloca(sizeof(x) * 3), 10)) +#endif /* _WIN32_WCE */ + +#define MAKEUQUAD(lo, hi) \ + ((uint64_t)(((uint32_t)(lo)) | ((uint64_t)((uint32_t)(hi))) << 32)) +#define RATE_DIFF (10000000) /* 100 nsecs */ +#define EPOCH_DIFF (MAKEUQUAD(0xd53e8000, 0x019db1de)) +#define SYS2UNIX_TIME(lo, hi) \ + ((time_t)((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF)) + +/* Visual Studio 6 does not know __func__ or __FUNCTION__ + * The rest of MS compilers use __FUNCTION__, not C99 __func__ + * Also use _strtoui64 on modern M$ compilers */ +#if defined(_MSC_VER) +#if (_MSC_VER < 1300) +#define STRX(x) #x +#define STR(x) STRX(x) +#define __func__ __FILE__ ":" STR(__LINE__) +#define strtoull(x, y, z) ((unsigned __int64)_atoi64(x)) +#define strtoll(x, y, z) (_atoi64(x)) +#else +#define __func__ __FUNCTION__ +#define strtoull(x, y, z) (_strtoui64(x, y, z)) +#define strtoll(x, y, z) (_strtoi64(x, y, z)) +#endif +#endif /* _MSC_VER */ + +#define ERRNO ((int)(GetLastError())) +#define NO_SOCKLEN_T + +#if defined(_WIN64) || defined(__MINGW64__) +#if !defined(SSL_LIB) +#define SSL_LIB "ssleay64.dll" +#endif +#if !defined(CRYPTO_LIB) +#define CRYPTO_LIB "libeay64.dll" +#endif +#else +#if !defined(SSL_LIB) +#define SSL_LIB "ssleay32.dll" +#endif +#if !defined(CRYPTO_LIB) +#define CRYPTO_LIB "libeay32.dll" +#endif +#endif + +#define O_NONBLOCK (0) +#if !defined(W_OK) +#define W_OK (2) /* http://msdn.microsoft.com/en-us/library/1w06ktdy.aspx */ +#endif +#if !defined(EWOULDBLOCK) +#define EWOULDBLOCK WSAEWOULDBLOCK +#endif /* !EWOULDBLOCK */ +#define _POSIX_ +#define INT64_FMT "I64d" +#define UINT64_FMT "I64u" + +#define WINCDECL __cdecl +#define vsnprintf_impl _vsnprintf +#define access _access +#define mg_sleep(x) (Sleep(x)) + +#define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY) +#if !defined(popen) +#define popen(x, y) (_popen(x, y)) +#endif +#if !defined(pclose) +#define pclose(x) (_pclose(x)) +#endif +#define close(x) (_close(x)) +#define dlsym(x, y) (GetProcAddress((HINSTANCE)(x), (y))) +#define RTLD_LAZY (0) +#define fseeko(x, y, z) ((_lseeki64(_fileno(x), (y), (z)) == -1) ? -1 : 0) +#define fdopen(x, y) (_fdopen((x), (y))) +#define write(x, y, z) (_write((x), (y), (unsigned)z)) +#define read(x, y, z) (_read((x), (y), (unsigned)z)) +#define flockfile(x) (EnterCriticalSection(&global_log_file_lock)) +#define funlockfile(x) (LeaveCriticalSection(&global_log_file_lock)) +#define sleep(x) (Sleep((x)*1000)) +#define rmdir(x) (_rmdir(x)) +#if defined(_WIN64) || !defined(__MINGW32__) +/* Only MinGW 32 bit is missing this function */ +#define timegm(x) (_mkgmtime(x)) +#else +time_t timegm(struct tm *tm); +#define NEED_TIMEGM +#endif + + +#if !defined(fileno) +#define fileno(x) (_fileno(x)) +#endif /* !fileno MINGW #defines fileno */ + +typedef HANDLE pthread_mutex_t; +typedef DWORD pthread_key_t; +typedef HANDLE pthread_t; +typedef struct { +CRITICAL_SECTION threadIdSec; +struct mg_workerTLS *waiting_thread; /* The chain of threads */ +} pthread_cond_t; + +#if !defined(__clockid_t_defined) +typedef DWORD clockid_t; +#endif +#if !defined(CLOCK_MONOTONIC) +#define CLOCK_MONOTONIC (1) +#endif +#if !defined(CLOCK_REALTIME) +#define CLOCK_REALTIME (2) +#endif +#if !defined(CLOCK_THREAD) +#define CLOCK_THREAD (3) +#endif +#if !defined(CLOCK_PROCESS) +#define CLOCK_PROCESS (4) +#endif + + +#if defined(_MSC_VER) && (_MSC_VER >= 1900) +#define _TIMESPEC_DEFINED +#endif +#if !defined(_TIMESPEC_DEFINED) +struct timespec { +time_t tv_sec; /* seconds */ +long tv_nsec; /* nanoseconds */ +}; +#endif + +#if !defined(WIN_PTHREADS_TIME_H) +#define MUST_IMPLEMENT_CLOCK_GETTIME +#endif + +#if defined(MUST_IMPLEMENT_CLOCK_GETTIME) +#define clock_gettime mg_clock_gettime +static int +clock_gettime(clockid_t clk_id, struct timespec *tp) +{ +FILETIME ft; +ULARGE_INTEGER li, li2; +BOOL ok = FALSE; +double d; +static double perfcnt_per_sec = 0.0; +static BOOL initialized = FALSE; + +if (!initialized) { +QueryPerformanceFrequency((LARGE_INTEGER *)&li); +perfcnt_per_sec = 1.0 / li.QuadPart; +initialized = TRUE; +} + +if (tp) { +memset(tp, 0, sizeof(*tp)); + +if (clk_id == CLOCK_REALTIME) { + +/* BEGIN: CLOCK_REALTIME = wall clock (date and time) */ +GetSystemTimeAsFileTime(&ft); +li.LowPart = ft.dwLowDateTime; +li.HighPart = ft.dwHighDateTime; +li.QuadPart -= 116444736000000000; /* 1.1.1970 in filedate */ +tp->tv_sec = (time_t)(li.QuadPart / 10000000); +tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100; +ok = TRUE; +/* END: CLOCK_REALTIME */ + +} else if (clk_id == CLOCK_MONOTONIC) { + +/* BEGIN: CLOCK_MONOTONIC = stopwatch (time differences) */ +QueryPerformanceCounter((LARGE_INTEGER *)&li); +d = li.QuadPart * perfcnt_per_sec; +tp->tv_sec = (time_t)d; +d -= (double)tp->tv_sec; +tp->tv_nsec = (long)(d * 1.0E9); +ok = TRUE; +/* END: CLOCK_MONOTONIC */ + +} else if (clk_id == CLOCK_THREAD) { + +/* BEGIN: CLOCK_THREAD = CPU usage of thread */ +FILETIME t_create, t_exit, t_kernel, t_user; +if (GetThreadTimes(GetCurrentThread(), +&t_create, +&t_exit, +&t_kernel, +&t_user)) { +li.LowPart = t_user.dwLowDateTime; +li.HighPart = t_user.dwHighDateTime; +li2.LowPart = t_kernel.dwLowDateTime; +li2.HighPart = t_kernel.dwHighDateTime; +li.QuadPart += li2.QuadPart; +tp->tv_sec = (time_t)(li.QuadPart / 10000000); +tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100; +ok = TRUE; +} +/* END: CLOCK_THREAD */ + +} else if (clk_id == CLOCK_PROCESS) { + +/* BEGIN: CLOCK_PROCESS = CPU usage of process */ +FILETIME t_create, t_exit, t_kernel, t_user; +if (GetProcessTimes(GetCurrentProcess(), +&t_create, +&t_exit, +&t_kernel, +&t_user)) { +li.LowPart = t_user.dwLowDateTime; +li.HighPart = t_user.dwHighDateTime; +li2.LowPart = t_kernel.dwLowDateTime; +li2.HighPart = t_kernel.dwHighDateTime; +li.QuadPart += li2.QuadPart; +tp->tv_sec = (time_t)(li.QuadPart / 10000000); +tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100; +ok = TRUE; +} +/* END: CLOCK_PROCESS */ + +} else { + +/* BEGIN: unknown clock */ +/* ok = FALSE; already set by init */ +/* END: unknown clock */ +} +} + +return ok ? 0 : -1; +} +#endif + + +#define pid_t HANDLE /* MINGW typedefs pid_t to int. Using #define here. */ + +static int pthread_mutex_lock(pthread_mutex_t *); +static int pthread_mutex_unlock(pthread_mutex_t *); +static void path_to_unicode(const struct mg_connection *conn, +const char *path, +wchar_t *wbuf, +size_t wbuf_len); + +/* All file operations need to be rewritten to solve #246. */ + +struct mg_file; + +static const char * +mg_fgets(char *buf, size_t size, struct mg_file *filep, char **p); + + +/* POSIX dirent interface */ +struct dirent { +char d_name[PATH_MAX]; +}; + +typedef struct DIR { +HANDLE handle; +WIN32_FIND_DATAW info; +struct dirent result; +} DIR; + +#if defined(_WIN32) +#if !defined(HAVE_POLL) +struct pollfd { +SOCKET fd; +short events; +short revents; +}; +#endif +#endif + +/* Mark required libraries */ +#if defined(_MSC_VER) +#pragma comment(lib, "Ws2_32.lib") +#endif + +#else /* defined(_WIN32) - WINDOWS vs UNIX include block */ + +#include <sys/wait.h> +#include <sys/socket.h> +#include <sys/poll.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/time.h> +#include <sys/utsname.h> +#include <stdint.h> +#include <inttypes.h> +#include <netdb.h> +#include <netinet/tcp.h> +typedef const void *SOCK_OPT_TYPE; + +#if defined(ANDROID) +typedef unsigned short int in_port_t; +#endif + +#include <pwd.h> +#include <unistd.h> +#include <grp.h> +#include <dirent.h> +#define vsnprintf_impl vsnprintf + +#if !defined(NO_SSL_DL) && !defined(NO_SSL) +#include <dlfcn.h> +#endif +#include <pthread.h> +#if defined(__MACH__) +#define SSL_LIB "libssl.dylib" +#define CRYPTO_LIB "libcrypto.dylib" +#else +#if !defined(SSL_LIB) +#define SSL_LIB "libssl.so" +#endif +#if !defined(CRYPTO_LIB) +#define CRYPTO_LIB "libcrypto.so" +#endif +#endif +#if !defined(O_BINARY) +#define O_BINARY (0) +#endif /* O_BINARY */ +#define closesocket(a) (close(a)) +#define mg_mkdir(conn, path, mode) (mkdir(path, mode)) +#define mg_remove(conn, x) (remove(x)) +#define mg_sleep(x) (usleep((x)*1000)) +#define mg_opendir(conn, x) (opendir(x)) +#define mg_closedir(x) (closedir(x)) +#define mg_readdir(x) (readdir(x)) +#define ERRNO (errno) +#define INVALID_SOCKET (-1) +#define INT64_FMT PRId64 +#define UINT64_FMT PRIu64 +typedef int SOCKET; +#define WINCDECL + +#if defined(__hpux) +/* HPUX 11 does not have monotonic, fall back to realtime */ +#if !defined(CLOCK_MONOTONIC) +#define CLOCK_MONOTONIC CLOCK_REALTIME +#endif + +/* HPUX defines socklen_t incorrectly as size_t which is 64bit on + * Itanium. Without defining _XOPEN_SOURCE or _XOPEN_SOURCE_EXTENDED + * the prototypes use int* rather than socklen_t* which matches the + * actual library expectation. When called with the wrong size arg + * accept() returns a zero client inet addr and check_acl() always + * fails. Since socklen_t is widely used below, just force replace + * their typedef with int. - DTL + */ +#define socklen_t int +#endif /* hpux */ + +#endif /* defined(_WIN32) - WINDOWS vs UNIX include block */ + +/* Maximum queue length for pending connections. This value is passed as + * parameter to the "listen" socket call. */ +#if !defined(SOMAXCONN) +/* This symbol may be defined in winsock2.h so this must after that include */ +#define SOMAXCONN (100) /* in pending connections (count) */ +#endif + +/* In case our C library is missing "timegm", provide an implementation */ +#if defined(NEED_TIMEGM) +static inline int +is_leap(int y) +{ +return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0; +} + +static inline int +count_leap(int y) +{ +return (y - 1969) / 4 - (y - 1901) / 100 + (y - 1601) / 400; +} + +time_t +timegm(struct tm *tm) +{ +static const unsigned short ydays[] = { +0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}; +int year = tm->tm_year + 1900; +int mon = tm->tm_mon; +int mday = tm->tm_mday - 1; +int hour = tm->tm_hour; +int min = tm->tm_min; +int sec = tm->tm_sec; + +if (year < 1970 || mon < 0 || mon > 11 || mday < 0 +|| (mday >= ydays[mon + 1] - ydays[mon] ++ (mon == 1 && is_leap(year) ? 1 : 0)) || hour < 0 +|| hour > 23 +|| min < 0 +|| min > 59 +|| sec < 0 +|| sec > 60) +return -1; + +time_t res = year - 1970; +res *= 365; +res += mday; +res += ydays[mon] + (mon > 1 && is_leap(year) ? 1 : 0); +res += count_leap(year); + +res *= 24; +res += hour; +res *= 60; +res += min; +res *= 60; +res += sec; +return res; +} +#endif /* NEED_TIMEGM */ + + +/* va_copy should always be a macro, C99 and C++11 - DTL */ +#if !defined(va_copy) +#define va_copy(x, y) ((x) = (y)) +#endif + + +#if defined(_WIN32) +/* Create substitutes for POSIX functions in Win32. */ + +#if defined(__MINGW32__) +/* Show no warning in case system functions are not used. */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + + +static CRITICAL_SECTION global_log_file_lock; + +FUNCTION_MAY_BE_UNUSED +static DWORD +pthread_self(void) +{ +return GetCurrentThreadId(); +} + + +FUNCTION_MAY_BE_UNUSED +static int +pthread_key_create( +pthread_key_t *key, +void (*_ignored)(void *) /* destructor not supported for Windows */ +) +{ +(void)_ignored; + +if ((key != 0)) { +*key = TlsAlloc(); +return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1; +} +return -2; +} + + +FUNCTION_MAY_BE_UNUSED +static int +pthread_key_delete(pthread_key_t key) +{ +return TlsFree(key) ? 0 : 1; +} + + +FUNCTION_MAY_BE_UNUSED +static int +pthread_setspecific(pthread_key_t key, void *value) +{ +return TlsSetValue(key, value) ? 0 : 1; +} + + +FUNCTION_MAY_BE_UNUSED +static void * +pthread_getspecific(pthread_key_t key) +{ +return TlsGetValue(key); +} + +#if defined(__MINGW32__) +/* Enable unused function warning again */ +#pragma GCC diagnostic pop +#endif + +static struct pthread_mutex_undefined_struct *pthread_mutex_attr = NULL; +#else +static pthread_mutexattr_t pthread_mutex_attr; +#endif /* _WIN32 */ + + +#if defined(_WIN32_WCE) +/* Create substitutes for POSIX functions in Win32. */ + +#if defined(__MINGW32__) +/* Show no warning in case system functions are not used. */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + + +FUNCTION_MAY_BE_UNUSED +static time_t +time(time_t *ptime) +{ +time_t t; +SYSTEMTIME st; +FILETIME ft; + +GetSystemTime(&st); +SystemTimeToFileTime(&st, &ft); +t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime); + +if (ptime != NULL) { +*ptime = t; +} + +return t; +} + + +FUNCTION_MAY_BE_UNUSED +static struct tm * +localtime_s(const time_t *ptime, struct tm *ptm) +{ +int64_t t = ((int64_t)*ptime) * RATE_DIFF + EPOCH_DIFF; +FILETIME ft, lft; +SYSTEMTIME st; +TIME_ZONE_INFORMATION tzinfo; + +if (ptm == NULL) { +return NULL; +} + +*(int64_t *)&ft = t; +FileTimeToLocalFileTime(&ft, &lft); +FileTimeToSystemTime(&lft, &st); +ptm->tm_year = st.wYear - 1900; +ptm->tm_mon = st.wMonth - 1; +ptm->tm_wday = st.wDayOfWeek; +ptm->tm_mday = st.wDay; +ptm->tm_hour = st.wHour; +ptm->tm_min = st.wMinute; +ptm->tm_sec = st.wSecond; +ptm->tm_yday = 0; /* hope nobody uses this */ +ptm->tm_isdst = +(GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT) ? 1 : 0; + +return ptm; +} + + +FUNCTION_MAY_BE_UNUSED +static struct tm * +gmtime_s(const time_t *ptime, struct tm *ptm) +{ +/* FIXME(lsm): fix this. */ +return localtime_s(ptime, ptm); +} + + +static int mg_atomic_inc(volatile int *addr); +static struct tm tm_array[MAX_WORKER_THREADS]; +static int tm_index = 0; + + +FUNCTION_MAY_BE_UNUSED +static struct tm * +localtime(const time_t *ptime) +{ +int i = mg_atomic_inc(&tm_index) % (sizeof(tm_array) / sizeof(tm_array[0])); +return localtime_s(ptime, tm_array + i); +} + + +FUNCTION_MAY_BE_UNUSED +static struct tm * +gmtime(const time_t *ptime) +{ +int i = mg_atomic_inc(&tm_index) % ARRAY_SIZE(tm_array); +return gmtime_s(ptime, tm_array + i); +} + + +FUNCTION_MAY_BE_UNUSED +static size_t +strftime(char *dst, size_t dst_size, const char *fmt, const struct tm *tm) +{ +/* TODO: (void)mg_snprintf(NULL, dst, dst_size, "implement strftime() + * for WinCE"); */ +return 0; +} + +#define _beginthreadex(psec, stack, func, prm, flags, ptid) \ + (uintptr_t) CreateThread(psec, stack, func, prm, flags, ptid) + +#define remove(f) mg_remove(NULL, f) + + +FUNCTION_MAY_BE_UNUSED +static int +rename(const char *a, const char *b) +{ +wchar_t wa[W_PATH_MAX]; +wchar_t wb[W_PATH_MAX]; +path_to_unicode(NULL, a, wa, ARRAY_SIZE(wa)); +path_to_unicode(NULL, b, wb, ARRAY_SIZE(wb)); + +return MoveFileW(wa, wb) ? 0 : -1; +} + + +struct stat { +int64_t st_size; +time_t st_mtime; +}; + + +FUNCTION_MAY_BE_UNUSED +static int +stat(const char *name, struct stat *st) +{ +wchar_t wbuf[W_PATH_MAX]; +WIN32_FILE_ATTRIBUTE_DATA attr; +time_t creation_time, write_time; + +path_to_unicode(NULL, name, wbuf, ARRAY_SIZE(wbuf)); +memset(&attr, 0, sizeof(attr)); + +GetFileAttributesExW(wbuf, GetFileExInfoStandard, &attr); +st->st_size = +(((int64_t)attr.nFileSizeHigh) << 32) + (int64_t)attr.nFileSizeLow; + +write_time = SYS2UNIX_TIME(attr.ftLastWriteTime.dwLowDateTime, +attr.ftLastWriteTime.dwHighDateTime); +creation_time = SYS2UNIX_TIME(attr.ftCreationTime.dwLowDateTime, +attr.ftCreationTime.dwHighDateTime); + +if (creation_time > write_time) { +st->st_mtime = creation_time; +} else { +st->st_mtime = write_time; +} +return 0; +} + +#define access(x, a) 1 /* not required anyway */ + +/* WinCE-TODO: define stat, remove, rename, _rmdir, _lseeki64 */ +/* Values from errno.h in Windows SDK (Visual Studio). */ +#define EEXIST 17 +#define EACCES 13 +#define ENOENT 2 + +#if defined(__MINGW32__) +/* Enable unused function warning again */ +#pragma GCC diagnostic pop +#endif + +#endif /* defined(_WIN32_WCE) */ + + +#if defined(__GNUC__) || defined(__MINGW32__) +/* Show no warning in case system functions are not used. */ +#define GCC_VERSION \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#if GCC_VERSION >= 40500 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#endif /* GCC_VERSION >= 40500 */ +#endif /* defined(__GNUC__) || defined(__MINGW32__) */ +#if defined(__clang__) +/* Show no warning in case system functions are not used. */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + +static pthread_mutex_t global_lock_mutex; + + +#if defined(_WIN32) +/* Forward declaration for Windows */ +FUNCTION_MAY_BE_UNUSED +static int pthread_mutex_lock(pthread_mutex_t *mutex); + +FUNCTION_MAY_BE_UNUSED +static int pthread_mutex_unlock(pthread_mutex_t *mutex); +#endif + + +FUNCTION_MAY_BE_UNUSED +static void +mg_global_lock(void) +{ +(void)pthread_mutex_lock(&global_lock_mutex); +} + + +FUNCTION_MAY_BE_UNUSED +static void +mg_global_unlock(void) +{ +(void)pthread_mutex_unlock(&global_lock_mutex); +} + + +FUNCTION_MAY_BE_UNUSED +static int +mg_atomic_inc(volatile int *addr) +{ +int ret; +#if defined(_WIN32) && !defined(NO_ATOMICS) +/* Depending on the SDK, this function uses either + * (volatile unsigned int *) or (volatile LONG *), + * so whatever you use, the other SDK is likely to raise a warning. */ +ret = InterlockedIncrement((volatile long *)addr); +#elif defined(__GNUC__) \ + && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \ + && !defined(NO_ATOMICS) +ret = __sync_add_and_fetch(addr, 1); +#else +mg_global_lock(); +ret = (++(*addr)); +mg_global_unlock(); +#endif +return ret; +} + + +FUNCTION_MAY_BE_UNUSED +static int +mg_atomic_dec(volatile int *addr) +{ +int ret; +#if defined(_WIN32) && !defined(NO_ATOMICS) +/* Depending on the SDK, this function uses either + * (volatile unsigned int *) or (volatile LONG *), + * so whatever you use, the other SDK is likely to raise a warning. */ +ret = InterlockedDecrement((volatile long *)addr); +#elif defined(__GNUC__) \ + && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \ + && !defined(NO_ATOMICS) +ret = __sync_sub_and_fetch(addr, 1); +#else +mg_global_lock(); +ret = (--(*addr)); +mg_global_unlock(); +#endif +return ret; +} + + +#if defined(USE_SERVER_STATS) +static int64_t +mg_atomic_add(volatile int64_t *addr, int64_t value) +{ +int64_t ret; +#if defined(_WIN64) && !defined(NO_ATOMICS) +ret = InterlockedAdd64(addr, value); +#elif defined(__GNUC__) \ + && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \ + && !defined(NO_ATOMICS) +ret = __sync_add_and_fetch(addr, value); +#else +mg_global_lock(); +*addr += value; +ret = (*addr); +mg_global_unlock(); +#endif +return ret; +} +#endif + + +#if defined(__GNUC__) +/* Show no warning in case system functions are not used. */ +#if GCC_VERSION >= 40500 +#pragma GCC diagnostic pop +#endif /* GCC_VERSION >= 40500 */ +#endif /* defined(__GNUC__) */ +#if defined(__clang__) +/* Show no warning in case system functions are not used. */ +#pragma clang diagnostic pop +#endif + + +#if defined(USE_SERVER_STATS) + +struct mg_memory_stat { +volatile int64_t totalMemUsed; +volatile int64_t maxMemUsed; +volatile int blockCount; +}; + + +static struct mg_memory_stat *get_memory_stat(struct mg_context *ctx); + + +static void * +mg_malloc_ex(size_t size, +struct mg_context *ctx, +const char *file, +unsigned line) +{ +void *data = malloc(size + 2 * sizeof(uintptr_t)); +void *memory = 0; +struct mg_memory_stat *mstat = get_memory_stat(ctx); + +#if defined(MEMORY_DEBUGGING) +char mallocStr[256]; +#else +(void)file; +(void)line; +#endif + +if (data) { +int64_t mmem = mg_atomic_add(&mstat->totalMemUsed, (int64_t)size); +if (mmem > mstat->maxMemUsed) { +/* could use atomic compare exchange, but this + * seems overkill for statistics data */ +mstat->maxMemUsed = mmem; +} + +mg_atomic_inc(&mstat->blockCount); +((uintptr_t *)data)[0] = size; +((uintptr_t *)data)[1] = (uintptr_t)mstat; +memory = (void *)(((char *)data) + 2 * sizeof(uintptr_t)); +} + +#if defined(MEMORY_DEBUGGING) +sprintf(mallocStr, +"MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n", +memory, +(unsigned long)size, +(unsigned long)mstat->totalMemUsed, +(unsigned long)mstat->blockCount, +file, +line); +#if defined(_WIN32) +OutputDebugStringA(mallocStr); +#else +DEBUG_TRACE("%s", mallocStr); +#endif +#endif + +return memory; +} + + +static void * +mg_calloc_ex(size_t count, +size_t size, +struct mg_context *ctx, +const char *file, +unsigned line) +{ +void *data = mg_malloc_ex(size * count, ctx, file, line); + +if (data) { +memset(data, 0, size * count); +} +return data; +} + + +static void +mg_free_ex(void *memory, const char *file, unsigned line) +{ +void *data = (void *)(((char *)memory) - 2 * sizeof(uintptr_t)); + + +#if defined(MEMORY_DEBUGGING) +char mallocStr[256]; +#else +(void)file; +(void)line; +#endif + +if (memory) { +uintptr_t size = ((uintptr_t *)data)[0]; +struct mg_memory_stat *mstat = +(struct mg_memory_stat *)(((uintptr_t *)data)[1]); +mg_atomic_add(&mstat->totalMemUsed, -(int64_t)size); +mg_atomic_dec(&mstat->blockCount); +#if defined(MEMORY_DEBUGGING) +sprintf(mallocStr, +"MEM: %p %5lu free %7lu %4lu --- %s:%u\n", +memory, +(unsigned long)size, +(unsigned long)mstat->totalMemUsed, +(unsigned long)mstat->blockCount, +file, +line); +#if defined(_WIN32) +OutputDebugStringA(mallocStr); +#else +DEBUG_TRACE("%s", mallocStr); +#endif +#endif +free(data); +} +} + + +static void * +mg_realloc_ex(void *memory, +size_t newsize, +struct mg_context *ctx, +const char *file, +unsigned line) +{ +void *data; +void *_realloc; +uintptr_t oldsize; + +#if defined(MEMORY_DEBUGGING) +char mallocStr[256]; +#else +(void)file; +(void)line; +#endif + +if (newsize) { +if (memory) { +/* Reallocate existing block */ +struct mg_memory_stat *mstat; +data = (void *)(((char *)memory) - 2 * sizeof(uintptr_t)); +oldsize = ((uintptr_t *)data)[0]; +mstat = (struct mg_memory_stat *)((uintptr_t *)data)[1]; +_realloc = realloc(data, newsize + 2 * sizeof(uintptr_t)); +if (_realloc) { +data = _realloc; +mg_atomic_add(&mstat->totalMemUsed, -(int64_t)oldsize); +#if defined(MEMORY_DEBUGGING) +sprintf(mallocStr, +"MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n", +memory, +(unsigned long)oldsize, +(unsigned long)mstat->totalMemUsed, +(unsigned long)mstat->blockCount, +file, +line); +#if defined(_WIN32) +OutputDebugStringA(mallocStr); +#else +DEBUG_TRACE("%s", mallocStr); +#endif +#endif +mg_atomic_add(&mstat->totalMemUsed, (int64_t)newsize); +#if defined(MEMORY_DEBUGGING) +sprintf(mallocStr, +"MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n", +memory, +(unsigned long)newsize, +(unsigned long)mstat->totalMemUsed, +(unsigned long)mstat->blockCount, +file, +line); +#if defined(_WIN32) +OutputDebugStringA(mallocStr); +#else +DEBUG_TRACE("%s", mallocStr); +#endif +#endif +*(uintptr_t *)data = newsize; +data = (void *)(((char *)data) + 2 * sizeof(uintptr_t)); +} else { +#if defined(MEMORY_DEBUGGING) +#if defined(_WIN32) +OutputDebugStringA("MEM: realloc failed\n"); +#else +DEBUG_TRACE("%s", "MEM: realloc failed\n"); +#endif +#endif +return _realloc; +} +} else { +/* Allocate new block */ +data = mg_malloc_ex(newsize, ctx, file, line); +} +} else { +/* Free existing block */ +data = 0; +mg_free_ex(memory, file, line); +} + +return data; +} + +#define mg_malloc(a) mg_malloc_ex(a, NULL, __FILE__, __LINE__) +#define mg_calloc(a, b) mg_calloc_ex(a, b, NULL, __FILE__, __LINE__) +#define mg_realloc(a, b) mg_realloc_ex(a, b, NULL, __FILE__, __LINE__) +#define mg_free(a) mg_free_ex(a, __FILE__, __LINE__) + +#define mg_malloc_ctx(a, c) mg_malloc_ex(a, c, __FILE__, __LINE__) +#define mg_calloc_ctx(a, b, c) mg_calloc_ex(a, b, c, __FILE__, __LINE__) +#define mg_realloc_ctx(a, b, c) mg_realloc_ex(a, b, c, __FILE__, __LINE__) + +#else /* USE_SERVER_STATS */ + +static __inline void * +mg_malloc(size_t a) +{ +return malloc(a); +} + +static __inline void * +mg_calloc(size_t a, size_t b) +{ +return calloc(a, b); +} + +static __inline void * +mg_realloc(void *a, size_t b) +{ +return realloc(a, b); +} + +static __inline void +mg_free(void *a) +{ +free(a); +} + +#define mg_malloc_ctx(a, c) mg_malloc(a) +#define mg_calloc_ctx(a, b, c) mg_calloc(a, b) +#define mg_realloc_ctx(a, b, c) mg_realloc(a, b) +#define mg_free_ctx(a, c) mg_free(a) + +#endif /* USE_SERVER_STATS */ + + +static void mg_vsnprintf(const struct mg_connection *conn, +int *truncated, +char *buf, +size_t buflen, +const char *fmt, +va_list ap); + +static void mg_snprintf(const struct mg_connection *conn, +int *truncated, +char *buf, +size_t buflen, +PRINTF_FORMAT_STRING(const char *fmt), +...) PRINTF_ARGS(5, 6); + +/* This following lines are just meant as a reminder to use the mg-functions + * for memory management */ +#if defined(malloc) +#undef malloc +#endif +#if defined(calloc) +#undef calloc +#endif +#if defined(realloc) +#undef realloc +#endif +#if defined(free) +#undef free +#endif +#if defined(snprintf) +#undef snprintf +#endif +#if defined(vsnprintf) +#undef vsnprintf +#endif +#define malloc DO_NOT_USE_THIS_FUNCTION__USE_mg_malloc +#define calloc DO_NOT_USE_THIS_FUNCTION__USE_mg_calloc +#define realloc DO_NOT_USE_THIS_FUNCTION__USE_mg_realloc +#define free DO_NOT_USE_THIS_FUNCTION__USE_mg_free +#define snprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_snprintf +#if defined(_WIN32) +/* vsnprintf must not be used in any system, + * but this define only works well for Windows. */ +#define vsnprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_vsnprintf +#endif + + +/* mg_init_library counter */ +static int mg_init_library_called = 0; + +#if !defined(NO_SSL) +static int mg_ssl_initialized = 0; +#endif + +static pthread_key_t sTlsKey; /* Thread local storage index */ +static int thread_idx_max = 0; + +#if defined(MG_LEGACY_INTERFACE) +#define MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE +#endif + +struct mg_workerTLS { +int is_master; +unsigned long thread_idx; +#if defined(_WIN32) +HANDLE pthread_cond_helper_mutex; +struct mg_workerTLS *next_waiting_thread; +#endif +#if defined(MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE) +char txtbuf[4]; +#endif +}; + + +#if defined(__GNUC__) || defined(__MINGW32__) +/* Show no warning in case system functions are not used. */ +#if GCC_VERSION >= 40500 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#endif /* GCC_VERSION >= 40500 */ +#endif /* defined(__GNUC__) || defined(__MINGW32__) */ +#if defined(__clang__) +/* Show no warning in case system functions are not used. */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + + +/* Get a unique thread ID as unsigned long, independent from the data type + * of thread IDs defined by the operating system API. + * If two calls to mg_current_thread_id return the same value, they calls + * are done from the same thread. If they return different values, they are + * done from different threads. (Provided this function is used in the same + * process context and threads are not repeatedly created and deleted, but + * CivetWeb does not do that). + * This function must match the signature required for SSL id callbacks: + * CRYPTO_set_id_callback + */ +FUNCTION_MAY_BE_UNUSED +static unsigned long +mg_current_thread_id(void) +{ +#if defined(_WIN32) +return GetCurrentThreadId(); +#else + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +/* For every compiler, either "sizeof(pthread_t) > sizeof(unsigned long)" + * or not, so one of the two conditions will be unreachable by construction. + * Unfortunately the C standard does not define a way to check this at + * compile time, since the #if preprocessor conditions can not use the sizeof + * operator as an argument. */ +#endif + +if (sizeof(pthread_t) > sizeof(unsigned long)) { +/* This is the problematic case for CRYPTO_set_id_callback: + * The OS pthread_t can not be cast to unsigned long. */ +struct mg_workerTLS *tls = +(struct mg_workerTLS *)pthread_getspecific(sTlsKey); +if (tls == NULL) { +/* SSL called from an unknown thread: Create some thread index. + */ +tls = (struct mg_workerTLS *)mg_malloc(sizeof(struct mg_workerTLS)); +tls->is_master = -2; /* -2 means "3rd party thread" */ +tls->thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max); +pthread_setspecific(sTlsKey, tls); +} +return tls->thread_idx; +} else { +/* pthread_t may be any data type, so a simple cast to unsigned long + * can rise a warning/error, depending on the platform. + * Here memcpy is used as an anything-to-anything cast. */ +unsigned long ret = 0; +pthread_t t = pthread_self(); +memcpy(&ret, &t, sizeof(pthread_t)); +return ret; +} + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + +#endif +} + + +FUNCTION_MAY_BE_UNUSED +static uint64_t +mg_get_current_time_ns(void) +{ +struct timespec tsnow; +clock_gettime(CLOCK_REALTIME, &tsnow); +return (((uint64_t)tsnow.tv_sec) * 1000000000) + (uint64_t)tsnow.tv_nsec; +} + + +#if defined(__GNUC__) +/* Show no warning in case system functions are not used. */ +#if GCC_VERSION >= 40500 +#pragma GCC diagnostic pop +#endif /* GCC_VERSION >= 40500 */ +#endif /* defined(__GNUC__) */ +#if defined(__clang__) +/* Show no warning in case system functions are not used. */ +#pragma clang diagnostic pop +#endif + + +#if defined(NEED_DEBUG_TRACE_FUNC) +static void +DEBUG_TRACE_FUNC(const char *func, unsigned line, const char *fmt, ...) +{ +va_list args; +uint64_t nsnow; +static uint64_t nslast; +struct timespec tsnow; + +/* Get some operating system independent thread id */ +unsigned long thread_id = mg_current_thread_id(); + +clock_gettime(CLOCK_REALTIME, &tsnow); +nsnow = ((uint64_t)tsnow.tv_sec) * ((uint64_t)1000000000) ++ ((uint64_t)tsnow.tv_nsec); + +if (!nslast) { +nslast = nsnow; +} + +flockfile(stdout); +printf("*** %lu.%09lu %12" INT64_FMT " %lu %s:%u: ", +(unsigned long)tsnow.tv_sec, +(unsigned long)tsnow.tv_nsec, +nsnow - nslast, +thread_id, +func, +line); +va_start(args, fmt); +vprintf(fmt, args); +va_end(args); +putchar('\n'); +fflush(stdout); +funlockfile(stdout); +nslast = nsnow; +} +#endif /* NEED_DEBUG_TRACE_FUNC */ + + +#define MD5_STATIC static +#include "md5.inl" + +/* Darwin prior to 7.0 and Win32 do not have socklen_t */ +#if defined(NO_SOCKLEN_T) +typedef int socklen_t; +#endif /* NO_SOCKLEN_T */ + +#define IP_ADDR_STR_LEN (50) /* IPv6 hex string is 46 chars */ + +#if !defined(MSG_NOSIGNAL) +#define MSG_NOSIGNAL (0) +#endif + + +#if defined(NO_SSL) +typedef struct SSL SSL; /* dummy for SSL argument to push/pull */ +typedef struct SSL_CTX SSL_CTX; +#else +#if defined(NO_SSL_DL) +#include <openssl/ssl.h> +#include <openssl/err.h> +#include <openssl/crypto.h> +#include <openssl/x509.h> +#include <openssl/pem.h> +#include <openssl/engine.h> +#include <openssl/conf.h> +#include <openssl/dh.h> +#include <openssl/bn.h> +#include <openssl/opensslv.h> + +#if defined(WOLFSSL_VERSION) +/* Additional defines for WolfSSL, see + * https://github.com/civetweb/civetweb/issues/583 */ +#include "wolfssl_extras.inl" +#endif + +#else + +/* SSL loaded dynamically from DLL. + * I put the prototypes here to be independent from OpenSSL source + * installation. */ + +typedef struct ssl_st SSL; +typedef struct ssl_method_st SSL_METHOD; +typedef struct ssl_ctx_st SSL_CTX; +typedef struct x509_store_ctx_st X509_STORE_CTX; +typedef struct x509_name X509_NAME; +typedef struct asn1_integer ASN1_INTEGER; +typedef struct bignum BIGNUM; +typedef struct ossl_init_settings_st OPENSSL_INIT_SETTINGS; +typedef struct evp_md EVP_MD; +typedef struct x509 X509; + + +#define SSL_CTRL_OPTIONS (32) +#define SSL_CTRL_CLEAR_OPTIONS (77) +#define SSL_CTRL_SET_ECDH_AUTO (94) + +#define OPENSSL_INIT_NO_LOAD_SSL_STRINGS 0x00100000L +#define OPENSSL_INIT_LOAD_SSL_STRINGS 0x00200000L +#define OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L + +#define SSL_VERIFY_NONE (0) +#define SSL_VERIFY_PEER (1) +#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT (2) +#define SSL_VERIFY_CLIENT_ONCE (4) +#define SSL_OP_ALL ((long)(0x80000BFFUL)) +#define SSL_OP_NO_SSLv2 (0x01000000L) +#define SSL_OP_NO_SSLv3 (0x02000000L) +#define SSL_OP_NO_TLSv1 (0x04000000L) +#define SSL_OP_NO_TLSv1_2 (0x08000000L) +#define SSL_OP_NO_TLSv1_1 (0x10000000L) +#define SSL_OP_SINGLE_DH_USE (0x00100000L) +#define SSL_OP_CIPHER_SERVER_PREFERENCE (0x00400000L) +#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (0x00010000L) +#define SSL_OP_NO_COMPRESSION (0x00020000L) + +#define SSL_CB_HANDSHAKE_START (0x10) +#define SSL_CB_HANDSHAKE_DONE (0x20) + +#define SSL_ERROR_NONE (0) +#define SSL_ERROR_SSL (1) +#define SSL_ERROR_WANT_READ (2) +#define SSL_ERROR_WANT_WRITE (3) +#define SSL_ERROR_WANT_X509_LOOKUP (4) +#define SSL_ERROR_SYSCALL (5) /* see errno */ +#define SSL_ERROR_ZERO_RETURN (6) +#define SSL_ERROR_WANT_CONNECT (7) +#define SSL_ERROR_WANT_ACCEPT (8) + +#define TLSEXT_TYPE_server_name (0) +#define TLSEXT_NAMETYPE_host_name (0) +#define SSL_TLSEXT_ERR_OK (0) +#define SSL_TLSEXT_ERR_ALERT_WARNING (1) +#define SSL_TLSEXT_ERR_ALERT_FATAL (2) +#define SSL_TLSEXT_ERR_NOACK (3) + +struct ssl_func { +const char *name; /* SSL function name */ +void (*ptr)(void); /* Function pointer */ +}; + + +#if defined(OPENSSL_API_1_1) + +#define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr) +#define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr) +#define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr) +#define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr) +#define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr) +#define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr) +#define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr) +#define SSL_new (*(SSL * (*)(SSL_CTX *))ssl_sw[7].ptr) +#define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *))ssl_sw[8].ptr) +#define TLS_server_method (*(SSL_METHOD * (*)(void))ssl_sw[9].ptr) +#define OPENSSL_init_ssl \ + (*(int (*)(uint64_t opts, \ + const OPENSSL_INIT_SETTINGS *settings))ssl_sw[10].ptr) +#define SSL_CTX_use_PrivateKey_file \ + (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr) +#define SSL_CTX_use_certificate_file \ + (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr) +#define SSL_CTX_set_default_passwd_cb \ + (*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr) +#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr) +#define SSL_CTX_use_certificate_chain_file \ + (*(int (*)(SSL_CTX *, const char *))ssl_sw[15].ptr) +#define TLS_client_method (*(SSL_METHOD * (*)(void))ssl_sw[16].ptr) +#define SSL_pending (*(int (*)(SSL *))ssl_sw[17].ptr) +#define SSL_CTX_set_verify \ + (*(void (*)(SSL_CTX *, \ + int, \ + int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[18].ptr) +#define SSL_shutdown (*(int (*)(SSL *))ssl_sw[19].ptr) +#define SSL_CTX_load_verify_locations \ + (*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[20].ptr) +#define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[21].ptr) +#define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[22].ptr) +#define SSL_get_peer_certificate (*(X509 * (*)(SSL *))ssl_sw[23].ptr) +#define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[24].ptr) +#define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *))ssl_sw[25].ptr) +#define SSL_CIPHER_get_name \ + (*(const char *(*)(const SSL_CIPHER *))ssl_sw[26].ptr) +#define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[27].ptr) +#define SSL_CTX_set_session_id_context \ + (*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[28].ptr) +#define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[29].ptr) +#define SSL_CTX_set_cipher_list \ + (*(int (*)(SSL_CTX *, const char *))ssl_sw[30].ptr) +#define SSL_CTX_set_options \ + (*(unsigned long (*)(SSL_CTX *, unsigned long))ssl_sw[31].ptr) +#define SSL_CTX_set_info_callback \ + (*(void (*)(SSL_CTX * ctx, \ + void (*callback)(SSL * s, int, int)))ssl_sw[32].ptr) +#define SSL_get_ex_data (*(char *(*)(SSL *, int))ssl_sw[33].ptr) +#define SSL_set_ex_data (*(void (*)(SSL *, int, char *))ssl_sw[34].ptr) +#define SSL_CTX_callback_ctrl \ + (*(long (*)(SSL_CTX *, int, void (*)(void)))ssl_sw[35].ptr) +#define SSL_get_servername \ + (*(const char *(*)(const SSL *, int type))ssl_sw[36].ptr) +#define SSL_set_SSL_CTX (*(SSL_CTX * (*)(SSL *, SSL_CTX *))ssl_sw[37].ptr) + +#define SSL_CTX_clear_options(ctx, op) \ + SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL) +#define SSL_CTX_set_ecdh_auto(ctx, onoff) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL) + +#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53 +#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54 +#define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \ + SSL_CTX_callback_ctrl(ctx, \ + SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, \ + (void (*)(void))cb) +#define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, (void *)arg) + +#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore) +#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter) + +#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg)) +#define SSL_get_app_data(s) (SSL_get_ex_data(s, 0)) + +#define ERR_get_error (*(unsigned long (*)(void))crypto_sw[0].ptr) +#define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[1].ptr) +#define ERR_remove_state (*(void (*)(unsigned long))crypto_sw[2].ptr) +#define CONF_modules_unload (*(void (*)(int))crypto_sw[3].ptr) +#define X509_free (*(void (*)(X509 *))crypto_sw[4].ptr) +#define X509_get_subject_name (*(X509_NAME * (*)(X509 *))crypto_sw[5].ptr) +#define X509_get_issuer_name (*(X509_NAME * (*)(X509 *))crypto_sw[6].ptr) +#define X509_NAME_oneline \ + (*(char *(*)(X509_NAME *, char *, int))crypto_sw[7].ptr) +#define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *))crypto_sw[8].ptr) +#define EVP_get_digestbyname \ + (*(const EVP_MD *(*)(const char *))crypto_sw[9].ptr) +#define EVP_Digest \ + (*(int (*)( \ + const void *, size_t, void *, unsigned int *, const EVP_MD *, void *)) \ + crypto_sw[10].ptr) +#define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[11].ptr) +#define BN_bn2hex (*(char *(*)(const BIGNUM *a))crypto_sw[12].ptr) +#define ASN1_INTEGER_to_BN \ + (*(BIGNUM * (*)(const ASN1_INTEGER *ai, BIGNUM *bn))crypto_sw[13].ptr) +#define BN_free (*(void (*)(const BIGNUM *a))crypto_sw[14].ptr) +#define CRYPTO_free (*(void (*)(void *addr))crypto_sw[15].ptr) + +#define OPENSSL_free(a) CRYPTO_free(a) + + +/* init_ssl_ctx() function updates this array. + * It loads SSL library dynamically and changes NULLs to the actual addresses + * of respective functions. The macros above (like SSL_connect()) are really + * just calling these functions indirectly via the pointer. */ +static struct ssl_func ssl_sw[] = {{"SSL_free", NULL}, +{"SSL_accept", NULL}, +{"SSL_connect", NULL}, +{"SSL_read", NULL}, +{"SSL_write", NULL}, +{"SSL_get_error", NULL}, +{"SSL_set_fd", NULL}, +{"SSL_new", NULL}, +{"SSL_CTX_new", NULL}, +{"TLS_server_method", NULL}, +{"OPENSSL_init_ssl", NULL}, +{"SSL_CTX_use_PrivateKey_file", NULL}, +{"SSL_CTX_use_certificate_file", NULL}, +{"SSL_CTX_set_default_passwd_cb", NULL}, +{"SSL_CTX_free", NULL}, +{"SSL_CTX_use_certificate_chain_file", NULL}, +{"TLS_client_method", NULL}, +{"SSL_pending", NULL}, +{"SSL_CTX_set_verify", NULL}, +{"SSL_shutdown", NULL}, +{"SSL_CTX_load_verify_locations", NULL}, +{"SSL_CTX_set_default_verify_paths", NULL}, +{"SSL_CTX_set_verify_depth", NULL}, +{"SSL_get_peer_certificate", NULL}, +{"SSL_get_version", NULL}, +{"SSL_get_current_cipher", NULL}, +{"SSL_CIPHER_get_name", NULL}, +{"SSL_CTX_check_private_key", NULL}, +{"SSL_CTX_set_session_id_context", NULL}, +{"SSL_CTX_ctrl", NULL}, +{"SSL_CTX_set_cipher_list", NULL}, +{"SSL_CTX_set_options", NULL}, +{"SSL_CTX_set_info_callback", NULL}, +{"SSL_get_ex_data", NULL}, +{"SSL_set_ex_data", NULL}, +{"SSL_CTX_callback_ctrl", NULL}, +{"SSL_get_servername", NULL}, +{"SSL_set_SSL_CTX", NULL}, +{NULL, NULL}}; + + +/* Similar array as ssl_sw. These functions could be located in different + * lib. */ +static struct ssl_func crypto_sw[] = {{"ERR_get_error", NULL}, +{"ERR_error_string", NULL}, +{"ERR_remove_state", NULL}, +{"CONF_modules_unload", NULL}, +{"X509_free", NULL}, +{"X509_get_subject_name", NULL}, +{"X509_get_issuer_name", NULL}, +{"X509_NAME_oneline", NULL}, +{"X509_get_serialNumber", NULL}, +{"EVP_get_digestbyname", NULL}, +{"EVP_Digest", NULL}, +{"i2d_X509", NULL}, +{"BN_bn2hex", NULL}, +{"ASN1_INTEGER_to_BN", NULL}, +{"BN_free", NULL}, +{"CRYPTO_free", NULL}, +{NULL, NULL}}; +#else + +#define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr) +#define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr) +#define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr) +#define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr) +#define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr) +#define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr) +#define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr) +#define SSL_new (*(SSL * (*)(SSL_CTX *))ssl_sw[7].ptr) +#define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *))ssl_sw[8].ptr) +#define SSLv23_server_method (*(SSL_METHOD * (*)(void))ssl_sw[9].ptr) +#define SSL_library_init (*(int (*)(void))ssl_sw[10].ptr) +#define SSL_CTX_use_PrivateKey_file \ + (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr) +#define SSL_CTX_use_certificate_file \ + (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr) +#define SSL_CTX_set_default_passwd_cb \ + (*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr) +#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr) +#define SSL_load_error_strings (*(void (*)(void))ssl_sw[15].ptr) +#define SSL_CTX_use_certificate_chain_file \ + (*(int (*)(SSL_CTX *, const char *))ssl_sw[16].ptr) +#define SSLv23_client_method (*(SSL_METHOD * (*)(void))ssl_sw[17].ptr) +#define SSL_pending (*(int (*)(SSL *))ssl_sw[18].ptr) +#define SSL_CTX_set_verify \ + (*(void (*)(SSL_CTX *, \ + int, \ + int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[19].ptr) +#define SSL_shutdown (*(int (*)(SSL *))ssl_sw[20].ptr) +#define SSL_CTX_load_verify_locations \ + (*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[21].ptr) +#define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[22].ptr) +#define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[23].ptr) +#define SSL_get_peer_certificate (*(X509 * (*)(SSL *))ssl_sw[24].ptr) +#define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[25].ptr) +#define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *))ssl_sw[26].ptr) +#define SSL_CIPHER_get_name \ + (*(const char *(*)(const SSL_CIPHER *))ssl_sw[27].ptr) +#define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[28].ptr) +#define SSL_CTX_set_session_id_context \ + (*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[29].ptr) +#define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[30].ptr) +#define SSL_CTX_set_cipher_list \ + (*(int (*)(SSL_CTX *, const char *))ssl_sw[31].ptr) +#define SSL_CTX_set_info_callback \ + (*(void (*)(SSL_CTX *, void (*callback)(SSL * s, int, int)))ssl_sw[32].ptr) +#define SSL_get_ex_data (*(char *(*)(SSL *, int))ssl_sw[33].ptr) +#define SSL_set_ex_data (*(void (*)(SSL *, int, char *))ssl_sw[34].ptr) +#define SSL_CTX_callback_ctrl \ + (*(long (*)(SSL_CTX *, int, void (*)(void)))ssl_sw[35].ptr) +#define SSL_get_servername \ + (*(const char *(*)(const SSL *, int type))ssl_sw[36].ptr) +#define SSL_set_SSL_CTX (*(SSL_CTX * (*)(SSL *, SSL_CTX *))ssl_sw[37].ptr) + +#define SSL_CTX_set_options(ctx, op) \ + SSL_CTX_ctrl((ctx), SSL_CTRL_OPTIONS, (op), NULL) +#define SSL_CTX_clear_options(ctx, op) \ + SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL) +#define SSL_CTX_set_ecdh_auto(ctx, onoff) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL) + +#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53 +#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54 +#define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \ + SSL_CTX_callback_ctrl(ctx, \ + SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, \ + (void (*)(void))cb) +#define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, (void *)arg) + +#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore) +#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter) + +#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg)) +#define SSL_get_app_data(s) (SSL_get_ex_data(s, 0)) + +#define CRYPTO_num_locks (*(int (*)(void))crypto_sw[0].ptr) +#define CRYPTO_set_locking_callback \ + (*(void (*)(void (*)(int, int, const char *, int)))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) +#define X509_NAME_oneline \ + (*(char *(*)(X509_NAME *, char *, int))crypto_sw[14].ptr) +#define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *))crypto_sw[15].ptr) +#define i2c_ASN1_INTEGER \ + (*(int (*)(ASN1_INTEGER *, unsigned char **))crypto_sw[16].ptr) +#define EVP_get_digestbyname \ + (*(const EVP_MD *(*)(const char *))crypto_sw[17].ptr) +#define EVP_Digest \ + (*(int (*)( \ + const void *, size_t, void *, unsigned int *, const EVP_MD *, void *)) \ + crypto_sw[18].ptr) +#define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[19].ptr) +#define BN_bn2hex (*(char *(*)(const BIGNUM *a))crypto_sw[20].ptr) +#define ASN1_INTEGER_to_BN \ + (*(BIGNUM * (*)(const ASN1_INTEGER *ai, BIGNUM *bn))crypto_sw[21].ptr) +#define BN_free (*(void (*)(const BIGNUM *a))crypto_sw[22].ptr) +#define CRYPTO_free (*(void (*)(void *addr))crypto_sw[23].ptr) + +#define OPENSSL_free(a) CRYPTO_free(a) + +/* init_ssl_ctx() function updates this array. + * It loads SSL library dynamically and changes NULLs to the actual addresses + * of respective functions. The macros above (like SSL_connect()) are really + * just calling these functions indirectly via the pointer. */ +static struct ssl_func ssl_sw[] = {{"SSL_free", NULL}, +{"SSL_accept", NULL}, +{"SSL_connect", NULL}, +{"SSL_read", NULL}, +{"SSL_write", NULL}, +{"SSL_get_error", NULL}, +{"SSL_set_fd", NULL}, +{"SSL_new", NULL}, +{"SSL_CTX_new", NULL}, +{"SSLv23_server_method", NULL}, +{"SSL_library_init", NULL}, +{"SSL_CTX_use_PrivateKey_file", NULL}, +{"SSL_CTX_use_certificate_file", NULL}, +{"SSL_CTX_set_default_passwd_cb", NULL}, +{"SSL_CTX_free", NULL}, +{"SSL_load_error_strings", NULL}, +{"SSL_CTX_use_certificate_chain_file", NULL}, +{"SSLv23_client_method", NULL}, +{"SSL_pending", NULL}, +{"SSL_CTX_set_verify", NULL}, +{"SSL_shutdown", NULL}, +{"SSL_CTX_load_verify_locations", NULL}, +{"SSL_CTX_set_default_verify_paths", NULL}, +{"SSL_CTX_set_verify_depth", NULL}, +{"SSL_get_peer_certificate", NULL}, +{"SSL_get_version", NULL}, +{"SSL_get_current_cipher", NULL}, +{"SSL_CIPHER_get_name", NULL}, +{"SSL_CTX_check_private_key", NULL}, +{"SSL_CTX_set_session_id_context", NULL}, +{"SSL_CTX_ctrl", NULL}, +{"SSL_CTX_set_cipher_list", NULL}, +{"SSL_CTX_set_info_callback", NULL}, +{"SSL_get_ex_data", NULL}, +{"SSL_set_ex_data", NULL}, +{"SSL_CTX_callback_ctrl", NULL}, +{"SSL_get_servername", NULL}, +{"SSL_set_SSL_CTX", NULL}, +{NULL, NULL}}; + + +/* Similar array as ssl_sw. These functions could be located in different + * lib. */ +static struct ssl_func crypto_sw[] = {{"CRYPTO_num_locks", NULL}, +{"CRYPTO_set_locking_callback", NULL}, +{"CRYPTO_set_id_callback", NULL}, +{"ERR_get_error", NULL}, +{"ERR_error_string", NULL}, +{"ERR_remove_state", NULL}, +{"ERR_free_strings", NULL}, +{"ENGINE_cleanup", NULL}, +{"CONF_modules_unload", NULL}, +{"CRYPTO_cleanup_all_ex_data", NULL}, +{"EVP_cleanup", NULL}, +{"X509_free", NULL}, +{"X509_get_subject_name", NULL}, +{"X509_get_issuer_name", NULL}, +{"X509_NAME_oneline", NULL}, +{"X509_get_serialNumber", NULL}, +{"i2c_ASN1_INTEGER", NULL}, +{"EVP_get_digestbyname", NULL}, +{"EVP_Digest", NULL}, +{"i2d_X509", NULL}, +{"BN_bn2hex", NULL}, +{"ASN1_INTEGER_to_BN", NULL}, +{"BN_free", NULL}, +{"CRYPTO_free", NULL}, +{NULL, NULL}}; +#endif /* OPENSSL_API_1_1 */ +#endif /* NO_SSL_DL */ +#endif /* NO_SSL */ + + +#if !defined(NO_CACHING) +static const char *month_names[] = {"Jan", +"Feb", +"Mar", +"Apr", +"May", +"Jun", +"Jul", +"Aug", +"Sep", +"Oct", +"Nov", +"Dec"}; +#endif /* !NO_CACHING */ + +/* Unified socket address. For IPv6 support, add IPv6 address structure in + * the + * union u. */ +union usa { +struct sockaddr sa; +struct sockaddr_in sin; +#if defined(USE_IPV6) +struct sockaddr_in6 sin6; +#endif +}; + +/* Describes a string (chunk of memory). */ +struct vec { +const char *ptr; +size_t len; +}; + +struct mg_file_stat { +/* File properties filled by mg_stat: */ +uint64_t size; +time_t last_modified; +int is_directory; /* Set to 1 if mg_stat is called for a directory */ +int is_gzipped; /* Set to 1 if the content is gzipped, in which + * case we need a "Content-Eencoding: gzip" header */ +int location; /* 0 = nowhere, 1 = on disk, 2 = in memory */ +}; + +struct mg_file_in_memory { +char *p; +uint32_t pos; +char mode; +}; + +struct mg_file_access { +/* File properties filled by mg_fopen: */ +FILE *fp; +#if defined(MG_USE_OPEN_FILE) +/* TODO (low): Remove obsolete "file in memory" implementation. + * In an "early 2017" discussion at Google groups + * https://groups.google.com/forum/#!topic/civetweb/h9HT4CmeYqI + * we decided to get rid of this feature (after some fade-out + * phase). */ +const char *membuf; +#endif +}; + +struct mg_file { +struct mg_file_stat stat; +struct mg_file_access access; +}; + +#if defined(MG_USE_OPEN_FILE) + +#define STRUCT_FILE_INITIALIZER \ + { \ + { \ + (uint64_t)0, (time_t)0, 0, 0, 0 \ + } \ + , \ + { \ + (FILE *) NULL, (const char *)NULL \ + } \ + } + +#else + +#define STRUCT_FILE_INITIALIZER \ + { \ + { \ + (uint64_t)0, (time_t)0, 0, 0, 0 \ + } \ + , \ + { \ + (FILE *) NULL \ + } \ + } + +#endif + + +/* Describes listening socket, or socket which was accept()-ed by the master + * thread and queued for future handling by the worker thread. */ +struct socket { +SOCKET sock; /* Listening socket */ +union usa lsa; /* Local socket address */ +union usa rsa; /* Remote socket address */ +unsigned char is_ssl; /* Is port SSL-ed */ +unsigned char ssl_redir; /* Is port supposed to redirect everything to SSL + * port */ +unsigned char in_use; /* Is valid */ +}; + + +/* Enum const for all options must be in sync with + * static struct mg_option config_options[] + * This is tested in the unit test (test/private.c) + * "Private Config Options" + */ +enum { +/* Once for each server */ +LISTENING_PORTS, +NUM_THREADS, +RUN_AS_USER, +CONFIG_TCP_NODELAY, /* Prepended CONFIG_ to avoid conflict with the + * socket option typedef TCP_NODELAY. */ +MAX_REQUEST_SIZE, +LINGER_TIMEOUT, +#if defined(__linux__) +ALLOW_SENDFILE_CALL, +#endif +#if defined(_WIN32) +CASE_SENSITIVE_FILES, +#endif +THROTTLE, +ACCESS_LOG_FILE, +ERROR_LOG_FILE, +ENABLE_KEEP_ALIVE, +REQUEST_TIMEOUT, +KEEP_ALIVE_TIMEOUT, +#if defined(USE_WEBSOCKET) +WEBSOCKET_TIMEOUT, +ENABLE_WEBSOCKET_PING_PONG, +#endif +DECODE_URL, +#if defined(USE_LUA) +LUA_BACKGROUND_SCRIPT, +LUA_BACKGROUND_SCRIPT_PARAMS, +#endif +#if defined(USE_TIMERS) +CGI_TIMEOUT, +#endif + +/* Once for each domain */ +DOCUMENT_ROOT, +CGI_EXTENSIONS, +CGI_ENVIRONMENT, +PUT_DELETE_PASSWORDS_FILE, +CGI_INTERPRETER, +PROTECT_URI, +AUTHENTICATION_DOMAIN, +ENABLE_AUTH_DOMAIN_CHECK, +SSI_EXTENSIONS, +ENABLE_DIRECTORY_LISTING, +GLOBAL_PASSWORDS_FILE, +INDEX_FILES, +ACCESS_CONTROL_LIST, +EXTRA_MIME_TYPES, +SSL_CERTIFICATE, +SSL_CERTIFICATE_CHAIN, +URL_REWRITE_PATTERN, +HIDE_FILES, +SSL_DO_VERIFY_PEER, +SSL_CA_PATH, +SSL_CA_FILE, +SSL_VERIFY_DEPTH, +SSL_DEFAULT_VERIFY_PATHS, +SSL_CIPHER_LIST, +SSL_PROTOCOL_VERSION, +SSL_SHORT_TRUST, + +#if defined(USE_LUA) +LUA_PRELOAD_FILE, +LUA_SCRIPT_EXTENSIONS, +LUA_SERVER_PAGE_EXTENSIONS, +#if defined(MG_EXPERIMENTAL_INTERFACES) +LUA_DEBUG_PARAMS, +#endif +#endif +#if defined(USE_DUKTAPE) +DUKTAPE_SCRIPT_EXTENSIONS, +#endif + +#if defined(USE_WEBSOCKET) +WEBSOCKET_ROOT, +#endif +#if defined(USE_LUA) && defined(USE_WEBSOCKET) +LUA_WEBSOCKET_EXTENSIONS, +#endif + +ACCESS_CONTROL_ALLOW_ORIGIN, +ACCESS_CONTROL_ALLOW_METHODS, +ACCESS_CONTROL_ALLOW_HEADERS, +ERROR_PAGES, +#if !defined(NO_CACHING) +STATIC_FILE_MAX_AGE, +#endif +#if !defined(NO_SSL) +STRICT_HTTPS_MAX_AGE, +#endif +ADDITIONAL_HEADER, +ALLOW_INDEX_SCRIPT_SUB_RES, + +NUM_OPTIONS +}; + + +/* Config option name, config types, default value. + * Must be in the same order as the enum const above. + */ +static const struct mg_option config_options[] = { + +/* Once for each server */ +{"listening_ports", MG_CONFIG_TYPE_STRING_LIST, "8080"}, +{"num_threads", MG_CONFIG_TYPE_NUMBER, "50"}, +{"run_as_user", MG_CONFIG_TYPE_STRING, NULL}, +{"tcp_nodelay", MG_CONFIG_TYPE_NUMBER, "0"}, +{"max_request_size", MG_CONFIG_TYPE_NUMBER, "16384"}, +{"linger_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL}, +#if defined(__linux__) +{"allow_sendfile_call", MG_CONFIG_TYPE_BOOLEAN, "yes"}, +#endif +#if defined(_WIN32) +{"case_sensitive", MG_CONFIG_TYPE_BOOLEAN, "no"}, +#endif +{"throttle", MG_CONFIG_TYPE_STRING_LIST, NULL}, +{"access_log_file", MG_CONFIG_TYPE_FILE, NULL}, +{"error_log_file", MG_CONFIG_TYPE_FILE, NULL}, +{"enable_keep_alive", MG_CONFIG_TYPE_BOOLEAN, "no"}, +{"request_timeout_ms", MG_CONFIG_TYPE_NUMBER, "30000"}, +{"keep_alive_timeout_ms", MG_CONFIG_TYPE_NUMBER, "500"}, +#if defined(USE_WEBSOCKET) +{"websocket_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL}, +{"enable_websocket_ping_pong", MG_CONFIG_TYPE_BOOLEAN, "no"}, +#endif +{"decode_url", MG_CONFIG_TYPE_BOOLEAN, "yes"}, +#if defined(USE_LUA) +{"lua_background_script", MG_CONFIG_TYPE_FILE, NULL}, +{"lua_background_script_params", MG_CONFIG_TYPE_STRING_LIST, NULL}, +#endif +#if defined(USE_TIMERS) +{"cgi_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL}, +#endif + +/* Once for each domain */ +{"document_root", MG_CONFIG_TYPE_DIRECTORY, NULL}, +{"cgi_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.cgi$|**.pl$|**.php$"}, +{"cgi_environment", MG_CONFIG_TYPE_STRING_LIST, NULL}, +{"put_delete_auth_file", MG_CONFIG_TYPE_FILE, NULL}, +{"cgi_interpreter", MG_CONFIG_TYPE_FILE, NULL}, +{"protect_uri", MG_CONFIG_TYPE_STRING_LIST, NULL}, +{"authentication_domain", MG_CONFIG_TYPE_STRING, "mydomain.com"}, +{"enable_auth_domain_check", MG_CONFIG_TYPE_BOOLEAN, "yes"}, +{"ssi_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.shtml$|**.shtm$"}, +{"enable_directory_listing", MG_CONFIG_TYPE_BOOLEAN, "yes"}, +{"global_auth_file", MG_CONFIG_TYPE_FILE, NULL}, +{"index_files", +MG_CONFIG_TYPE_STRING_LIST, +#if defined(USE_LUA) +"index.xhtml,index.html,index.htm," +"index.lp,index.lsp,index.lua,index.cgi," +"index.shtml,index.php"}, +#else +"index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"}, +#endif +{"access_control_list", MG_CONFIG_TYPE_STRING_LIST, NULL}, +{"extra_mime_types", MG_CONFIG_TYPE_STRING_LIST, NULL}, +{"ssl_certificate", MG_CONFIG_TYPE_FILE, NULL}, +{"ssl_certificate_chain", MG_CONFIG_TYPE_FILE, NULL}, +{"url_rewrite_patterns", MG_CONFIG_TYPE_STRING_LIST, NULL}, +{"hide_files_patterns", MG_CONFIG_TYPE_EXT_PATTERN, NULL}, + +{"ssl_verify_peer", MG_CONFIG_TYPE_YES_NO_OPTIONAL, "no"}, + +{"ssl_ca_path", MG_CONFIG_TYPE_DIRECTORY, NULL}, +{"ssl_ca_file", MG_CONFIG_TYPE_FILE, NULL}, +{"ssl_verify_depth", MG_CONFIG_TYPE_NUMBER, "9"}, +{"ssl_default_verify_paths", MG_CONFIG_TYPE_BOOLEAN, "yes"}, +{"ssl_cipher_list", MG_CONFIG_TYPE_STRING, NULL}, +{"ssl_protocol_version", MG_CONFIG_TYPE_NUMBER, "0"}, +{"ssl_short_trust", MG_CONFIG_TYPE_BOOLEAN, "no"}, + +#if defined(USE_LUA) +{"lua_preload_file", MG_CONFIG_TYPE_FILE, NULL}, +{"lua_script_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.lua$"}, +{"lua_server_page_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.lp$|**.lsp$"}, +#if defined(MG_EXPERIMENTAL_INTERFACES) +{"lua_debug", MG_CONFIG_TYPE_STRING, NULL}, +#endif +#endif +#if defined(USE_DUKTAPE) +/* The support for duktape is still in alpha version state. + * The name of this config option might change. */ +{"duktape_script_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.ssjs$"}, +#endif + +#if defined(USE_WEBSOCKET) +{"websocket_root", MG_CONFIG_TYPE_DIRECTORY, NULL}, +#endif +#if defined(USE_LUA) && defined(USE_WEBSOCKET) +{"lua_websocket_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.lua$"}, +#endif +{"access_control_allow_origin", MG_CONFIG_TYPE_STRING, "*"}, +{"access_control_allow_methods", MG_CONFIG_TYPE_STRING, "*"}, +{"access_control_allow_headers", MG_CONFIG_TYPE_STRING, "*"}, +{"error_pages", MG_CONFIG_TYPE_DIRECTORY, NULL}, +#if !defined(NO_CACHING) +{"static_file_max_age", MG_CONFIG_TYPE_NUMBER, "3600"}, +#endif +#if !defined(NO_SSL) +{"strict_transport_security_max_age", MG_CONFIG_TYPE_NUMBER, NULL}, +#endif +{"additional_header", MG_CONFIG_TYPE_STRING_MULTILINE, NULL}, +{"allow_index_script_resource", MG_CONFIG_TYPE_BOOLEAN, "no"}, + +{NULL, MG_CONFIG_TYPE_UNKNOWN, NULL}}; + + +/* Check if the config_options and the corresponding enum have compatible + * sizes. */ +mg_static_assert((sizeof(config_options) / sizeof(config_options[0])) +== (NUM_OPTIONS + 1), +"config_options and enum not sync"); + + +enum { REQUEST_HANDLER, WEBSOCKET_HANDLER, AUTH_HANDLER }; + + +struct mg_handler_info { +/* Name/Pattern of the URI. */ +char *uri; +size_t uri_len; + +/* handler type */ +int handler_type; + +/* Handler for http/https or authorization requests. */ +mg_request_handler handler; +unsigned int refcount; +pthread_mutex_t refcount_mutex; /* Protects refcount */ +pthread_cond_t +refcount_cond; /* Signaled when handler refcount is decremented */ + +/* Handler for ws/wss (websocket) requests. */ +mg_websocket_connect_handler connect_handler; +mg_websocket_ready_handler ready_handler; +mg_websocket_data_handler data_handler; +mg_websocket_close_handler close_handler; + +/* accepted subprotocols for ws/wss requests. */ +struct mg_websocket_subprotocols *subprotocols; + +/* Handler for authorization requests */ +mg_authorization_handler auth_handler; + +/* User supplied argument for the handler function. */ +void *cbdata; + +/* next handler in a linked list */ +struct mg_handler_info *next; +}; + + +enum { +CONTEXT_INVALID, +CONTEXT_SERVER, +CONTEXT_HTTP_CLIENT, +CONTEXT_WS_CLIENT +}; + + +struct mg_domain_context { +SSL_CTX *ssl_ctx; /* SSL context */ +char *config[NUM_OPTIONS]; /* Civetweb configuration parameters */ +struct mg_handler_info *handlers; /* linked list of uri handlers */ + +/* Server nonce */ +uint64_t auth_nonce_mask; /* Mask for all nonce values */ +unsigned long nonce_count; /* Used nonces, used for authentication */ + +#if defined(USE_LUA) && defined(USE_WEBSOCKET) +/* linked list of shared lua websockets */ +struct mg_shared_lua_websocket_list *shared_lua_websockets; +#endif + +/* Linked list of domains */ +struct mg_domain_context *next; +}; + + +struct mg_context { + +/* Part 1 - Physical context: + * This holds threads, ports, timeouts, ... + * set for the entire server, independent from the + * addressed hostname. + */ + +/* Connection related */ +int context_type; /* See CONTEXT_* above */ + +struct socket *listening_sockets; +struct pollfd *listening_socket_fds; +unsigned int num_listening_sockets; + +struct mg_connection *worker_connections; /* The connection struct, pre- + * allocated for each worker */ + +#if defined(USE_SERVER_STATS) +int active_connections; +int max_connections; +int64_t total_connections; +int64_t total_requests; +int64_t total_data_read; +int64_t total_data_written; +#endif + +/* Thread related */ +volatile int stop_flag; /* Should we stop event loop */ +pthread_mutex_t thread_mutex; /* Protects (max|num)_threads */ + +pthread_t masterthreadid; /* The master thread ID */ +unsigned int +cfg_worker_threads; /* The number of configured worker threads. */ +pthread_t *worker_threadids; /* The worker thread IDs */ + +/* Connection to thread dispatching */ +#if defined(ALTERNATIVE_QUEUE) +struct socket *client_socks; +void **client_wait_events; +#else +struct socket queue[MGSQLEN]; /* Accepted sockets */ +volatile int sq_head; /* Head of the socket queue */ +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 */ +#endif + +/* Memory related */ +unsigned int max_request_size; /* The max request size */ + +#if defined(USE_SERVER_STATS) +struct mg_memory_stat ctx_memory; +#endif + +/* Operating system related */ +char *systemName; /* What operating system is running */ +time_t start_time; /* Server start time, used for authentication + * and for diagnstics. */ + +#if defined(USE_TIMERS) +struct ttimers *timers; +#endif + +/* Lua specific: Background operations and shared websockets */ +#if defined(USE_LUA) +void *lua_background_state; +#endif + +/* Server nonce */ +pthread_mutex_t nonce_mutex; /* Protects nonce_count */ + +/* Server callbacks */ +struct mg_callbacks callbacks; /* User-defined callback function */ +void *user_data; /* User-defined data */ + +/* Part 2 - Logical domain: + * This holds hostname, TLS certificate, document root, ... + * set for a domain hosted at the server. + * There may be multiple domains hosted at one physical server. + * The default domain "dd" is the first element of a list of + * domains. + */ +struct mg_domain_context dd; /* default domain */ +}; + + +#if defined(USE_SERVER_STATS) +static struct mg_memory_stat mg_common_memory = {0, 0, 0}; + +static struct mg_memory_stat * +get_memory_stat(struct mg_context *ctx) +{ +if (ctx) { +return &(ctx->ctx_memory); +} +return &mg_common_memory; +} +#endif + +enum { +CONNECTION_TYPE_INVALID, +CONNECTION_TYPE_REQUEST, +CONNECTION_TYPE_RESPONSE +}; + +struct mg_connection { +int connection_type; /* see CONNECTION_TYPE_* above */ + +struct mg_request_info request_info; +struct mg_response_info response_info; + +struct mg_context *phys_ctx; +struct mg_domain_context *dom_ctx; + +#if defined(USE_SERVER_STATS) +int conn_state; /* 0 = undef, numerical value may change in different + * versions. For the current definition, see + * mg_get_connection_info_impl */ +#endif + +const char *host; /* Host (HTTP/1.1 header or SNI) */ +SSL *ssl; /* SSL descriptor */ +SSL_CTX *client_ssl_ctx; /* SSL context for client connections */ +struct socket client; /* Connected client */ +time_t conn_birth_time; /* Time (wall clock) when connection was + * established */ +struct timespec req_time; /* Time (since system start) when the request + * was received */ +int64_t num_bytes_sent; /* Total bytes sent to client */ +int64_t content_len; /* Content-Length header value */ +int64_t consumed_content; /* How many bytes of content have been read */ +int is_chunked; /* Transfer-Encoding is chunked: + * 0 = not chunked, + * 1 = chunked, do data read yet, + * 2 = chunked, some data read, + * 3 = chunked, all data read + */ +size_t chunk_remainder; /* Unread data from the last chunk */ +char *buf; /* Buffer for received data */ +char *path_info; /* PATH_INFO part of the URL */ + +int must_close; /* 1 if connection must be closed */ +int accept_gzip; /* 1 if gzip encoding is accepted */ +int in_error_handler; /* 1 if in handler for user defined error + * pages */ +#if defined(USE_WEBSOCKET) +int in_websocket_handling; /* 1 if in read_websocket */ +#endif +int handled_requests; /* Number of requests handled by this connection + */ +int buf_size; /* Buffer size */ +int request_len; /* Size of the request + headers in a buffer */ +int data_len; /* Total size of data in a buffer */ +int status_code; /* HTTP reply status code, e.g. 200 */ +int throttle; /* Throttling, bytes/sec. <= 0 means no + * throttle */ + +time_t last_throttle_time; /* Last time throttled data was sent */ +int64_t last_throttle_bytes; /* Bytes sent this second */ +pthread_mutex_t mutex; /* Used by mg_(un)lock_connection to ensure + * atomic transmissions for websockets */ +#if defined(USE_LUA) && defined(USE_WEBSOCKET) +void *lua_websocket_state; /* Lua_State for a websocket connection */ +#endif + +int thread_index; /* Thread index within ctx */ +}; + + +/* Directory entry */ +struct de { +struct mg_connection *conn; +char *file_name; +struct mg_file_stat file; +}; + + +#if defined(USE_WEBSOCKET) +static int is_websocket_protocol(const struct mg_connection *conn); +#else +#define is_websocket_protocol(conn) (0) +#endif + + +#define mg_cry_internal(conn, fmt, ...) \ + mg_cry_internal_wrap(conn, __func__, __LINE__, fmt, __VA_ARGS__) + +static void mg_cry_internal_wrap(const struct mg_connection *conn, +const char *func, +unsigned line, +const char *fmt, +...) PRINTF_ARGS(4, 5); + + +#if !defined(NO_THREAD_NAME) +#if defined(_WIN32) && defined(_MSC_VER) +/* Set the thread name for debugging purposes in Visual Studio + * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx + */ +#pragma pack(push, 8) +typedef struct tagTHREADNAME_INFO { +DWORD dwType; /* Must be 0x1000. */ +LPCSTR szName; /* Pointer to name (in user addr space). */ +DWORD dwThreadID; /* Thread ID (-1=caller thread). */ +DWORD dwFlags; /* Reserved for future use, must be zero. */ +} THREADNAME_INFO; +#pragma pack(pop) + +#elif defined(__linux__) + +#include <sys/prctl.h> +#include <sys/sendfile.h> +#if defined(ALTERNATIVE_QUEUE) +#include <sys/eventfd.h> +#endif /* ALTERNATIVE_QUEUE */ + + +#if defined(ALTERNATIVE_QUEUE) + +static void * +event_create(void) +{ +int evhdl = eventfd(0, EFD_CLOEXEC); +int *ret; + +if (evhdl == -1) { +/* Linux uses -1 on error, Windows NULL. */ +/* However, Linux does not return 0 on success either. */ +return 0; +} + +ret = (int *)mg_malloc(sizeof(int)); +if (ret) { +*ret = evhdl; +} else { +(void)close(evhdl); +} + +return (void *)ret; +} + + +static int +event_wait(void *eventhdl) +{ +uint64_t u; +int evhdl, s; + +if (!eventhdl) { +/* error */ +return 0; +} +evhdl = *(int *)eventhdl; + +s = (int)read(evhdl, &u, sizeof(u)); +if (s != sizeof(u)) { +/* error */ +return 0; +} +(void)u; /* the value is not required */ +return 1; +} + + +static int +event_signal(void *eventhdl) +{ +uint64_t u = 1; +int evhdl, s; + +if (!eventhdl) { +/* error */ +return 0; +} +evhdl = *(int *)eventhdl; + +s = (int)write(evhdl, &u, sizeof(u)); +if (s != sizeof(u)) { +/* error */ +return 0; +} +return 1; +} + + +static void +event_destroy(void *eventhdl) +{ +int evhdl; + +if (!eventhdl) { +/* error */ +return; +} +evhdl = *(int *)eventhdl; + +close(evhdl); +mg_free(eventhdl); +} + + +#endif + +#endif + + +#if !defined(__linux__) && !defined(_WIN32) && defined(ALTERNATIVE_QUEUE) + +struct posix_event { +pthread_mutex_t mutex; +pthread_cond_t cond; +}; + + +static void * +event_create(void) +{ +struct posix_event *ret = mg_malloc(sizeof(struct posix_event)); +if (ret == 0) { +/* out of memory */ +return 0; +} +if (0 != pthread_mutex_init(&(ret->mutex), NULL)) { +/* pthread mutex not available */ +mg_free(ret); +return 0; +} +if (0 != pthread_cond_init(&(ret->cond), NULL)) { +/* pthread cond not available */ +pthread_mutex_destroy(&(ret->mutex)); +mg_free(ret); +return 0; +} +return (void *)ret; +} + + +static int +event_wait(void *eventhdl) +{ +struct posix_event *ev = (struct posix_event *)eventhdl; +pthread_mutex_lock(&(ev->mutex)); +pthread_cond_wait(&(ev->cond), &(ev->mutex)); +pthread_mutex_unlock(&(ev->mutex)); +return 1; +} + + +static int +event_signal(void *eventhdl) +{ +struct posix_event *ev = (struct posix_event *)eventhdl; +pthread_mutex_lock(&(ev->mutex)); +pthread_cond_signal(&(ev->cond)); +pthread_mutex_unlock(&(ev->mutex)); +return 1; +} + + +static void +event_destroy(void *eventhdl) +{ +struct posix_event *ev = (struct posix_event *)eventhdl; +pthread_cond_destroy(&(ev->cond)); +pthread_mutex_destroy(&(ev->mutex)); +mg_free(ev); +} +#endif + + +static void +mg_set_thread_name(const char *name) +{ +char threadName[16 + 1]; /* 16 = Max. thread length in Linux/OSX/.. */ + +mg_snprintf( +NULL, NULL, threadName, sizeof(threadName), "civetweb-%s", name); + +#if defined(_WIN32) +#if defined(_MSC_VER) +/* Windows and Visual Studio Compiler */ +__try +{ +THREADNAME_INFO info; +info.dwType = 0x1000; +info.szName = threadName; +info.dwThreadID = ~0U; +info.dwFlags = 0; + +RaiseException(0x406D1388, +0, +sizeof(info) / sizeof(ULONG_PTR), +(ULONG_PTR *)&info); +} +__except(EXCEPTION_EXECUTE_HANDLER) +{ +} +#elif defined(__MINGW32__) +/* No option known to set thread name for MinGW */ +#endif +#elif defined(_GNU_SOURCE) && defined(__GLIBC__) \ + && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12))) +/* pthread_setname_np first appeared in glibc in version 2.12*/ +(void)pthread_setname_np(pthread_self(), threadName); +#elif defined(__linux__) +/* on linux we can use the old prctl function */ +(void)prctl(PR_SET_NAME, threadName, 0, 0, 0); +#endif +} +#else /* !defined(NO_THREAD_NAME) */ +void +mg_set_thread_name(const char *threadName) +{ +} +#endif + + +#if defined(MG_LEGACY_INTERFACE) +const char ** +mg_get_valid_option_names(void) +{ +/* This function is deprecated. Use mg_get_valid_options instead. */ +static const char * +
<TRUNCATED>
