|  | @@ -803,135 +803,6 @@ stat(const char *name, struct stat *st)
 | 
	
		
			
				|  |  |  #endif /* defined(_WIN32_WCE) */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#if defined(__GNUC__)
 | 
	
		
			
				|  |  | -/* Show no warning in case system functions are not used. */
 | 
	
		
			
				|  |  | -#pragma GCC diagnostic push
 | 
	
		
			
				|  |  | -#pragma GCC diagnostic ignored "-Wunused-function"
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -#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
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -static unsigned long
 | 
	
		
			
				|  |  | -mg_current_thread_id(void)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -#ifdef _WIN32
 | 
	
		
			
				|  |  | -	return GetCurrentThreadId();
 | 
	
		
			
				|  |  | -#else
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#ifdef __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;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#ifdef __clang__
 | 
	
		
			
				|  |  | -#pragma clang diagnostic pop
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#if defined(__GNUC__)
 | 
	
		
			
				|  |  | -/* Show no warning in case system functions are not used. */
 | 
	
		
			
				|  |  | -#pragma GCC diagnostic pop
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -#if defined(__clang__)
 | 
	
		
			
				|  |  | -/* Show no warning in case system functions are not used. */
 | 
	
		
			
				|  |  | -#pragma clang diagnostic pop
 | 
	
		
			
				|  |  | -#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);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static void
 | 
	
		
			
				|  |  | -DEBUG_TRACE_FUNC(const char *func, unsigned line, const char *fmt, ...)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -	va_list args;
 | 
	
		
			
				|  |  | -	struct timespec tsnow;
 | 
	
		
			
				|  |  | -	uint64_t nsnow;
 | 
	
		
			
				|  |  | -	static uint64_t nslast;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	/* 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) * 1000000000) + (uint64_t)tsnow.tv_nsec;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	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;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#define DEBUG_TRACE(fmt, ...)                                                  \
 | 
	
		
			
				|  |  | -	DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#else
 | 
	
		
			
				|  |  | -#define DEBUG_TRACE(fmt, ...)                                                  \
 | 
	
		
			
				|  |  | -	do {                                                                       \
 | 
	
		
			
				|  |  | -	} while (0)
 | 
	
		
			
				|  |  | -#endif /* DEBUG */
 | 
	
		
			
				|  |  | -#endif /* DEBUG_TRACE */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #if defined(MEMORY_DEBUGGING)
 | 
	
		
			
				|  |  |  static unsigned long mg_memory_debug_blockCount = 0;
 | 
	
	
		
			
				|  | @@ -1153,6 +1024,142 @@ static void mg_snprintf(const struct mg_connection *conn,
 | 
	
		
			
				|  |  |  #define vsnprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_vsnprintf
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static pthread_key_t sTlsKey; /* Thread local storage index */
 | 
	
		
			
				|  |  | +static int sTlsInit = 0;
 | 
	
		
			
				|  |  | +static int thread_idx_max = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#if defined(__GNUC__)
 | 
	
		
			
				|  |  | +/* Show no warning in case system functions are not used. */
 | 
	
		
			
				|  |  | +#pragma GCC diagnostic push
 | 
	
		
			
				|  |  | +#pragma GCC diagnostic ignored "-Wunused-function"
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +#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
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static unsigned long
 | 
	
		
			
				|  |  | +mg_current_thread_id(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +#ifdef _WIN32
 | 
	
		
			
				|  |  | +	return GetCurrentThreadId();
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#ifdef __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;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#ifdef __clang__
 | 
	
		
			
				|  |  | +#pragma clang diagnostic pop
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#if defined(__GNUC__)
 | 
	
		
			
				|  |  | +/* Show no warning in case system functions are not used. */
 | 
	
		
			
				|  |  | +#pragma GCC diagnostic pop
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +#if defined(__clang__)
 | 
	
		
			
				|  |  | +/* Show no warning in case system functions are not used. */
 | 
	
		
			
				|  |  | +#pragma clang diagnostic pop
 | 
	
		
			
				|  |  | +#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);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void
 | 
	
		
			
				|  |  | +DEBUG_TRACE_FUNC(const char *func, unsigned line, const char *fmt, ...)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	va_list args;
 | 
	
		
			
				|  |  | +	struct timespec tsnow;
 | 
	
		
			
				|  |  | +	uint64_t nsnow;
 | 
	
		
			
				|  |  | +	static uint64_t nslast;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* 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) * 1000000000) + (uint64_t)tsnow.tv_nsec;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	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;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define DEBUG_TRACE(fmt, ...)                                                  \
 | 
	
		
			
				|  |  | +	DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +#define DEBUG_TRACE(fmt, ...)                                                  \
 | 
	
		
			
				|  |  | +	do {                                                                       \
 | 
	
		
			
				|  |  | +	} while (0)
 | 
	
		
			
				|  |  | +#endif /* DEBUG */
 | 
	
		
			
				|  |  | +#endif /* DEBUG_TRACE */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #define MD5_STATIC static
 | 
	
		
			
				|  |  |  #include "md5.inl"
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1763,11 +1770,6 @@ struct mg_connection {
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static pthread_key_t sTlsKey; /* Thread local storage index */
 | 
	
		
			
				|  |  | -static int sTlsInit = 0;
 | 
	
		
			
				|  |  | -static int thread_idx_max = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  struct mg_workerTLS {
 | 
	
		
			
				|  |  |  	int is_master;
 | 
	
		
			
				|  |  |  	unsigned long thread_idx;
 |