commit 7512349b3bb7ec147195cf25864f637e1a99c569
parent e77fce2749a06b448e496140e8ad7e51891972de
Author: Christian Grothoff <christian@grothoff.org>
Date: Fri, 9 Feb 2018 06:09:02 +0100
allow passing pf instead of just v6 flag to listen socket creation
Diffstat:
32 files changed, 5730 insertions(+), 15 deletions(-)
diff --git a/m4/ac_define_dir.m4 b/m4/ac_define_dir.m4
@@ -0,0 +1,35 @@
+dnl @synopsis AC_DEFINE_DIR(VARNAME, DIR [, DESCRIPTION])
+dnl
+dnl This macro _AC_DEFINEs VARNAME to the expansion of the DIR
+dnl variable, taking care of fixing up ${prefix} and such.
+dnl
+dnl VARNAME is offered as both a C preprocessor symbol, and an output
+dnl variable.
+dnl
+dnl Note that the 3 argument form is only supported with autoconf 2.13
+dnl and later (i.e. only where _AC_DEFINE supports 3 arguments).
+dnl
+dnl Examples:
+dnl
+dnl AC_DEFINE_DIR(DATADIR, datadir)
+dnl AC_DEFINE_DIR(PROG_PATH, bindir, [Location of installed binaries])
+dnl
+dnl @category Misc
+dnl @author Stepan Kasal <kasal@ucw.cz>
+dnl @author Andreas Schwab <schwab@suse.de>
+dnl @author Guido Draheim <guidod@gmx.de>
+dnl @author Alexandre Oliva
+dnl @version 2005-01-17
+dnl @license AllPermissive
+
+AC_DEFUN([AC_DEFINE_DIR], [
+ prefix_NONE=
+ exec_prefix_NONE=
+ test "x$prefix" = xNONE && prefix_NONE=yes && prefix=$ac_default_prefix
+ test "x$exec_prefix" = xNONE && exec_prefix_NONE=yes && exec_prefix=$prefix
+ eval ac_define_dir="\"[$]$2\""
+ AC_SUBST($1, "$ac_define_dir")
+ AC_DEFINE_UNQUOTED($1, "$ac_define_dir", [$3])
+ test "$prefix_NONE" && prefix=NONE
+ test "$exec_prefix_NONE" && exec_prefix=NONE
+])
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
@@ -0,0 +1,167 @@
+# This Makefile.am is in the public domain
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/include \
+ -I$(top_srcdir)/src/lib
+
+AM_CFLAGS = $(HIDDEN_VISIBILITY_CFLAGS)
+
+lib_LTLIBRARIES = \
+ libmicrohttpd.la
+
+noinst_DATA =
+MOSTLYCLEANFILES =
+
+if W32_SHARED_LIB_EXP
+W32_MHD_LIB_LDFLAGS = -Wl,--output-def,$(lt_cv_objdir)/libmicrohttpd.def -XCClinker -static-libgcc
+noinst_DATA += $(lt_cv_objdir)/libmicrohttpd.lib $(lt_cv_objdir)/libmicrohttpd.def $(lt_cv_objdir)/libmicrohttpd.exp
+MOSTLYCLEANFILES += $(lt_cv_objdir)/libmicrohttpd.lib $(lt_cv_objdir)/libmicrohttpd.def $(lt_cv_objdir)/libmicrohttpd.exp
+
+$(lt_cv_objdir)/libmicrohttpd.def: libmicrohttpd.la
+
+$(lt_cv_objdir)/libmicrohttpd.exp: $(lt_cv_objdir)/libmicrohttpd.lib
+
+$(lt_cv_objdir)/libmicrohttpd.lib: $(lt_cv_objdir)/libmicrohttpd.def libmicrohttpd.la $(libmicrohttpd_la_OBJECTS)
+if USE_MS_LIB_TOOL
+ @echo Creating $@ and libmicrohttpd.exp by $(MS_LIB_TOOL)... && \
+ dll_name=`$(EGREP) -o dlname=\'.+\' libmicrohttpd.la` && \
+ dll_name=$${dll_name#*\'} && dll_name=$${dll_name%\'} && test -n "$$dll_name" && \
+ echo Creating $$dll_name by $(MS_LIB_TOOL).. && cd "$(lt_cv_objdir)" && \
+ $(MS_LIB_TOOL) -def:libmicrohttpd.def -name:$$dll_name -out:libmicrohttpd.lib $(libmicrohttpd_la_OBJECTS:.lo=.o) && cd ..
+else
+ @echo Creating $@ and libmicrohttpd.exp by $(DLLTOOL)... && \
+ dll_name=`$(EGREP) -o dlname=\'.+\' libmicrohttpd.la` && \
+ dll_name=$${dll_name#*\'} && dll_name=$${dll_name%\'} && test -n "$$dll_name" && \
+ echo Creating $$dll_name by $(DLLTOOL).. && cd "$(lt_cv_objdir)" && \
+ $(DLLTOOL) -d ./libmicrohttpd.def -D $$dll_name -l libmicrohttpd.lib $(libmicrohttpd_la_OBJECTS:.lo=.o) -e ./libmicrohttpd.exp && cd .. &&\
+ echo Created libmicrohttpd.exp and libmicrohttpd.lib.
+endif
+else
+ W32_MHD_LIB_LDFLAGS =
+endif
+
+if W32_STATIC_LIB
+noinst_DATA += $(lt_cv_objdir)/libmicrohttpd-static.lib
+MOSTLYCLEANFILES += $(lt_cv_objdir)/libmicrohttpd-static.lib
+
+$(lt_cv_objdir)/libmicrohttpd-static.lib: libmicrohttpd.la $(libmicrohttpd_la_OBJECTS)
+if USE_MS_LIB_TOOL
+ $(MS_LIB_TOOL) -out:$@ $(libmicrohttpd_la_OBJECTS:.lo=.o)
+else
+ cp $(lt_cv_objdir)/libmicrohttpd.a $@
+endif
+endif
+
+
+libmicrohttpd_la_SOURCES = \
+ action_continue.c \
+ action_from_response.c \
+ action_parse_post.c \
+ action_process_upload.c \
+ action_suspend.c \
+ connection_info.c \
+ connection_options.c \
+ daemon_create.c \
+ daemon_destroy.c \
+ daemon_info.c \
+ daemon_options.c \
+ daemon_start.c \
+ daemon_quiesce.c \
+ init.c init.h \
+ internal.c internal.h \
+ memorypool.c memorypool.h \
+ mhd_assert.h \
+ mhd_byteorder.h \
+ mhd_compat.c mhd_compat.h \
+ mhd_itc.c mhd_itc.h mhd_itc_types.h \
+ mhd_limits.h \
+ mhd_locks.h \
+ mhd_mono_clock.c mhd_mono_clock.h \
+ mhd_str.c mhd_str.h \
+ mhd_sockets.c mhd_sockets.h \
+ mhd_threads.c mhd_threads.h \
+ response.c \
+ response_for_upgrade.c \
+ response_from_buffer.c \
+ response_from_callback.c \
+ response_from_fd.c \
+ response_options.c \
+ reason_phrase.c \
+ request.c \
+ request_info.c \
+ request_resume.c \
+ sysfdsetsize.c sysfdsetsize.h \
+ panic.c \
+ version.c
+
+
+
+libmicrohttpd_la_CPPFLAGS = \
+ $(AM_CPPFLAGS) $(MHD_LIB_CPPFLAGS) \
+ -DBUILDING_MHD_LIB=1
+libmicrohttpd_la_CFLAGS = \
+ $(AM_CFLAGS) $(MHD_LIB_CFLAGS)
+libmicrohttpd_la_LDFLAGS = \
+ $(MHD_LIB_LDFLAGS) \
+ $(W32_MHD_LIB_LDFLAGS) \
+ -version-info @LIB_VERSION_CURRENT@:@LIB_VERSION_REVISION@:@LIB_VERSION_AGE@
+libmicrohttpd_la_LIBADD = \
+ $(MHD_LIBDEPS)
+
+if HAVE_W32
+MHD_DLL_RES_SRC = microhttpd_dll_res.rc
+MHD_DLL_RES_LO = libmicrohttpd_la-$(MHD_DLL_RES_SRC:.rc=.lo)
+
+EXTRA_libmicrohttpd_la_DEPENDENCIES = $(MHD_DLL_RES_LO)
+libmicrohttpd_la_LIBADD += $(MHD_DLL_RES_LO)
+
+# General rule is not required, but keep it just in case
+.rc.lo:
+ $(LIBTOOL) $(AM_V_lt) --tag=RC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(RC) $(RCFLAGS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $< -o $@
+
+# To add dll resource only to .dll file and exclude it form static
+# lib, a little trick was used. Allow libtool to create file.lo,
+# file.o and .libs/file.lo, .libs/file.o files, then overwrite file.o
+# by empty object generated from empty c-file. Later libtool will
+# use .libs/file.o for shared lib and empty file.o for static lib.
+# This implementation is based on trick found in liblzma.
+# Note: windres does not understand '-isystem' flag, so all
+# possible '-isystem' flags are replaced by simple '-I' flags.
+$(MHD_DLL_RES_LO): $(MHD_DLL_RES_SRC)
+ RC_CPP_FLAGS=" $(DEFAULT_INCLUDES) $(INCLUDES) $(libmicrohttpd_la_CPPFLAGS) $(CPPFLAGS) " && \
+ $(LIBTOOL) $(AM_V_lt) --tag=RC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(RC) $(RCFLAGS) $(DEFS) $${RC_CPP_FLAGS// -isystem / -I } $< -o $@ && \
+ echo > $@-empty.c && $(CC) $(AM_CFLAGS) $(CFLAGS) -c $@-empty.c -o $(@:.lo=.o) && rm -f $@-empty.c
+endif
+
+if USE_COVERAGE
+ AM_CFLAGS += --coverage
+endif
+
+if !MHD_HAVE_TSEARCH
+libmicrohttpd_la_SOURCES += \
+ tsearch.c tsearch.h
+endif
+
+# TBD!
+if HAVE_POSTPROCESSOR
+libmicrohttpd_la_SOURCES += \
+ postprocessor.c
+endif
+
+# TBD!
+if ENABLE_DAUTH
+libmicrohttpd_la_SOURCES += \
+ digestauth.c \
+ md5.c md5.h
+endif
+
+# TBD!
+if ENABLE_BAUTH
+libmicrohttpd_la_SOURCES += \
+ basicauth.c \
+ base64.c base64.h
+endif
+
+
+
+
+
diff --git a/src/lib/base64.c b/src/lib/base64.c
@@ -0,0 +1,59 @@
+/*
+ * This code implements the BASE64 algorithm.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * @file base64.c
+ * @brief This code implements the BASE64 algorithm
+ * @author Matthieu Speder
+ */
+#include "base64.h"
+
+static const char base64_digits[] =
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ 0, 0, 0, -1, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+
+char *
+BASE64Decode(const char* src)
+{
+ size_t in_len = strlen (src);
+ char* dest;
+ char* result;
+
+ if (in_len % 4)
+ {
+ /* Wrong base64 string length */
+ return NULL;
+ }
+ result = dest = malloc(in_len / 4 * 3 + 1);
+ if (NULL == result)
+ return NULL; /* out of memory */
+ while (*src) {
+ char a = base64_digits[(unsigned char)*(src++)];
+ char b = base64_digits[(unsigned char)*(src++)];
+ char c = base64_digits[(unsigned char)*(src++)];
+ char d = base64_digits[(unsigned char)*(src++)];
+ *(dest++) = (a << 2) | ((b & 0x30) >> 4);
+ if (c == (char)-1)
+ break;
+ *(dest++) = ((b & 0x0f) << 4) | ((c & 0x3c) >> 2);
+ if (d == (char)-1)
+ break;
+ *(dest++) = ((c & 0x03) << 6) | d;
+ }
+ *dest = 0;
+ return result;
+}
+
+
+/* end of base64.c */
diff --git a/src/lib/base64.h b/src/lib/base64.h
@@ -0,0 +1,17 @@
+/*
+ * This code implements the BASE64 algorithm.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * @file base64.c
+ * @brief This code implements the BASE64 algorithm
+ * @author Matthieu Speder
+ */
+#ifndef BASE64_H
+#define BASE64_H
+
+#include "platform.h"
+
+char *
+BASE64Decode(const char* src);
+
+#endif /* !BASE64_H */
diff --git a/src/lib/internal.c b/src/lib/internal.c
@@ -0,0 +1,281 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007 Daniel Pittman and Christian Grothoff
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+/**
+ * @file microhttpd/internal.c
+ * @brief internal shared structures
+ * @author Daniel Pittman
+ * @author Christian Grothoff
+ */
+
+#include "internal.h"
+#include "mhd_str.h"
+
+#ifdef HAVE_MESSAGES
+#if DEBUG_STATES
+/**
+ * State to string dictionary.
+ */
+const char *
+MHD_state_to_string (enum MHD_CONNECTION_STATE state)
+{
+ switch (state)
+ {
+ case MHD_CONNECTION_INIT:
+ return "connection init";
+ case MHD_CONNECTION_URL_RECEIVED:
+ return "connection url received";
+ case MHD_CONNECTION_HEADER_PART_RECEIVED:
+ return "header partially received";
+ case MHD_CONNECTION_HEADERS_RECEIVED:
+ return "headers received";
+ case MHD_CONNECTION_HEADERS_PROCESSED:
+ return "headers processed";
+ case MHD_CONNECTION_CONTINUE_SENDING:
+ return "continue sending";
+ case MHD_CONNECTION_CONTINUE_SENT:
+ return "continue sent";
+ case MHD_CONNECTION_BODY_RECEIVED:
+ return "body received";
+ case MHD_CONNECTION_FOOTER_PART_RECEIVED:
+ return "footer partially received";
+ case MHD_CONNECTION_FOOTERS_RECEIVED:
+ return "footers received";
+ case MHD_CONNECTION_HEADERS_SENDING:
+ return "headers sending";
+ case MHD_CONNECTION_HEADERS_SENT:
+ return "headers sent";
+ case MHD_CONNECTION_NORMAL_BODY_READY:
+ return "normal body ready";
+ case MHD_CONNECTION_NORMAL_BODY_UNREADY:
+ return "normal body unready";
+ case MHD_CONNECTION_CHUNKED_BODY_READY:
+ return "chunked body ready";
+ case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
+ return "chunked body unready";
+ case MHD_CONNECTION_BODY_SENT:
+ return "body sent";
+ case MHD_CONNECTION_FOOTERS_SENDING:
+ return "footers sending";
+ case MHD_CONNECTION_FOOTERS_SENT:
+ return "footers sent";
+ case MHD_CONNECTION_CLOSED:
+ return "closed";
+ default:
+ return "unrecognized connection state";
+ }
+}
+#endif
+#endif
+
+
+#ifdef HAVE_MESSAGES
+/**
+ * fprintf-like helper function for logging debug
+ * messages.
+ */
+void
+MHD_DLOG (const struct MHD_Daemon *daemon,
+ const char *format,
+ ...)
+{
+ va_list va;
+
+ if (0 == (daemon->options & MHD_USE_ERROR_LOG))
+ return;
+ va_start (va, format);
+ daemon->custom_error_log (daemon->custom_error_log_cls,
+ format,
+ va);
+ va_end (va);
+}
+#endif
+
+
+/**
+ * Convert all occurrences of '+' to ' '.
+ *
+ * @param arg string that is modified (in place), must be 0-terminated
+ */
+void
+MHD_unescape_plus (char *arg)
+{
+ char *p;
+
+ for (p=strchr (arg, '+'); NULL != p; p = strchr (p + 1, '+'))
+ *p = ' ';
+}
+
+
+/**
+ * Process escape sequences ('%HH') Updates val in place; the
+ * result should be UTF-8 encoded and cannot be larger than the input.
+ * The result must also still be 0-terminated.
+ *
+ * @param val value to unescape (modified in the process)
+ * @return length of the resulting val (strlen(val) maybe
+ * shorter afterwards due to elimination of escape sequences)
+ */
+size_t
+MHD_http_unescape (char *val)
+{
+ char *rpos = val;
+ char *wpos = val;
+
+ while ('\0' != *rpos)
+ {
+ uint32_t num;
+ switch (*rpos)
+ {
+ case '%':
+ if (2 == MHD_strx_to_uint32_n_ (rpos + 1,
+ 2,
+ &num))
+ {
+ *wpos = (char)((unsigned char) num);
+ wpos++;
+ rpos += 3;
+ break;
+ }
+ /* TODO: add bad sequence handling */
+ /* intentional fall through! */
+ default:
+ *wpos = *rpos;
+ wpos++;
+ rpos++;
+ }
+ }
+ *wpos = '\0'; /* add 0-terminator */
+ return wpos - val; /* = strlen(val) */
+}
+
+
+/**
+ * Parse and unescape the arguments given by the client
+ * as part of the HTTP request URI.
+ *
+ * @param kind header kind to pass to @a cb
+ * @param connection connection to add headers to
+ * @param[in,out] args argument URI string (after "?" in URI),
+ * clobbered in the process!
+ * @param cb function to call on each key-value pair found
+ * @param[out] num_headers set to the number of headers found
+ * @return #MHD_NO on failure (@a cb returned #MHD_NO),
+ * #MHD_YES for success (parsing succeeded, @a cb always
+ * returned #MHD_YES)
+ */
+int
+MHD_parse_arguments_ (struct MHD_Connection *connection,
+ enum MHD_ValueKind kind,
+ char *args,
+ MHD_ArgumentIterator_ cb,
+ unsigned int *num_headers)
+{
+ struct MHD_Daemon *daemon = connection->daemon;
+ char *equals;
+ char *amper;
+
+ *num_headers = 0;
+ while ( (NULL != args) &&
+ ('\0' != args[0]) )
+ {
+ equals = strchr (args, '=');
+ amper = strchr (args, '&');
+ if (NULL == amper)
+ {
+ /* last argument */
+ if (NULL == equals)
+ {
+ /* last argument, without '=' */
+ MHD_unescape_plus (args);
+ daemon->unescape_callback (daemon->unescape_callback_cls,
+ connection,
+ args);
+ if (MHD_YES != cb (connection,
+ args,
+ NULL,
+ kind))
+ return MHD_NO;
+ (*num_headers)++;
+ break;
+ }
+ /* got 'foo=bar' */
+ equals[0] = '\0';
+ equals++;
+ MHD_unescape_plus (args);
+ daemon->unescape_callback (daemon->unescape_callback_cls,
+ connection,
+ args);
+ MHD_unescape_plus (equals);
+ daemon->unescape_callback (daemon->unescape_callback_cls,
+ connection,
+ equals);
+ if (MHD_YES != cb (connection,
+ args,
+ equals,
+ kind))
+ return MHD_NO;
+ (*num_headers)++;
+ break;
+ }
+ /* amper is non-NULL here */
+ amper[0] = '\0';
+ amper++;
+ if ( (NULL == equals) ||
+ (equals >= amper) )
+ {
+ /* got 'foo&bar' or 'foo&bar=val', add key 'foo' with NULL for value */
+ MHD_unescape_plus (args);
+ daemon->unescape_callback (daemon->unescape_callback_cls,
+ connection,
+ args);
+ if (MHD_YES != cb (connection,
+ args,
+ NULL,
+ kind))
+ return MHD_NO;
+ /* continue with 'bar' */
+ (*num_headers)++;
+ args = amper;
+ continue;
+ }
+ /* equals and amper are non-NULL here, and equals < amper,
+ so we got regular 'foo=value&bar...'-kind of argument */
+ equals[0] = '\0';
+ equals++;
+ MHD_unescape_plus (args);
+ daemon->unescape_callback (daemon->unescape_callback_cls,
+ connection,
+ args);
+ MHD_unescape_plus (equals);
+ daemon->unescape_callback (daemon->unescape_callback_cls,
+ connection,
+ equals);
+ if (MHD_YES != cb (connection,
+ args,
+ equals,
+ kind))
+ return MHD_NO;
+ (*num_headers)++;
+ args = amper;
+ }
+ return MHD_YES;
+}
+
+/* end of internal.c */
diff --git a/src/lib/md5.c b/src/lib/md5.c
@@ -0,0 +1,264 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+/* Based on OpenBSD modifications */
+
+#include "md5.h"
+#include "mhd_byteorder.h"
+
+#define PUT_64BIT_LE(cp, value) do { \
+ (cp)[7] = (uint8_t)((value) >> 56); \
+ (cp)[6] = (uint8_t)((value) >> 48); \
+ (cp)[5] = (uint8_t)((value) >> 40); \
+ (cp)[4] = (uint8_t)((value) >> 32); \
+ (cp)[3] = (uint8_t)((value) >> 24); \
+ (cp)[2] = (uint8_t)((value) >> 16); \
+ (cp)[1] = (uint8_t)((value) >> 8); \
+ (cp)[0] = (uint8_t)((value)); } while (0)
+
+#define PUT_32BIT_LE(cp, value) do { \
+ (cp)[3] = (uint8_t)((value) >> 24); \
+ (cp)[2] = (uint8_t)((value) >> 16); \
+ (cp)[1] = (uint8_t)((value) >> 8); \
+ (cp)[0] = (uint8_t)((value)); } while (0)
+
+static uint8_t PADDING[MD5_BLOCK_SIZE] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(struct MD5Context *ctx)
+{
+ if (!ctx)
+ return;
+
+ ctx->count = 0;
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xefcdab89;
+ ctx->state[2] = 0x98badcfe;
+ ctx->state[3] = 0x10325476;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(struct MD5Context *ctx, const unsigned char *input, size_t len)
+{
+ size_t have, need;
+
+ if (!ctx || !input)
+ return;
+
+ /* Check how many bytes we already have and how many more we need. */
+ have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_SIZE - 1));
+ need = MD5_BLOCK_SIZE - have;
+
+ /* Update bitcount */
+ ctx->count += (uint64_t)len << 3;
+
+ if (len >= need)
+ {
+ if (have != 0)
+ {
+ memcpy(ctx->buffer + have, input, need);
+ MD5Transform(ctx->state, ctx->buffer);
+ input += need;
+ len -= need;
+ have = 0;
+ }
+
+ /* Process data in MD5_BLOCK_SIZE-byte chunks. */
+ while (len >= MD5_BLOCK_SIZE)
+ {
+ MD5Transform(ctx->state, input);
+ input += MD5_BLOCK_SIZE;
+ len -= MD5_BLOCK_SIZE;
+ }
+ }
+
+ /* Handle any remaining bytes of data. */
+ if (len != 0)
+ memcpy(ctx->buffer + have, input, len);
+}
+
+/*
+ * Pad pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Pad(struct MD5Context *ctx)
+{
+ uint8_t count[8];
+ size_t padlen;
+
+ if (!ctx)
+ return;
+
+ /* Convert count to 8 bytes in little endian order. */
+ PUT_64BIT_LE(count, ctx->count);
+
+ /* Pad out to 56 mod 64. */
+ padlen = MD5_BLOCK_SIZE -
+ ((ctx->count >> 3) & (MD5_BLOCK_SIZE - 1));
+ if (padlen < 1 + 8)
+ padlen += MD5_BLOCK_SIZE;
+ MD5Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */
+ MD5Update(ctx, count, 8);
+}
+
+/*
+ * Final wrapup--call MD5Pad, fill in digest and zero out ctx.
+ */
+void
+MD5Final(unsigned char digest[MD5_DIGEST_SIZE], struct MD5Context *ctx)
+{
+ int i;
+
+ if (!ctx || !digest)
+ return;
+
+ MD5Pad(ctx);
+ for (i = 0; i < 4; i++)
+ PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
+
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_SIZE])
+{
+ uint32_t a, b, c, d, in[MD5_BLOCK_SIZE / 4];
+
+#if _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
+ memcpy(in, block, sizeof(in));
+#else
+ for (a = 0; a < MD5_BLOCK_SIZE / 4; a++)
+ {
+ in[a] = (uint32_t)(
+ (uint32_t)(block[a * 4 + 0]) |
+ (uint32_t)(block[a * 4 + 1]) << 8 |
+ (uint32_t)(block[a * 4 + 2]) << 16 |
+ (uint32_t)(block[a * 4 + 3]) << 24);
+ }
+#endif
+
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+}
+
+/* end of md5.c */
diff --git a/src/lib/md5.h b/src/lib/md5.h
@@ -0,0 +1,64 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#ifndef MHD_MD5_H
+#define MHD_MD5_H
+
+#include "platform.h"
+
+#define MD5_BLOCK_SIZE 64
+#define MD5_DIGEST_SIZE 16
+#define MD5_DIGEST_STRING_LENGTH (MD5_DIGEST_SIZE * 2 + 1)
+
+struct MD5Context
+{
+ uint32_t state[4]; /* state */
+ uint64_t count; /* number of bits, mod 2^64 */
+ uint8_t buffer[MD5_BLOCK_SIZE]; /* input buffer */
+};
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx);
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, const unsigned char *input, size_t len);
+
+/*
+ * Pad pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Pad(struct MD5Context *ctx);
+
+/*
+ * Final wrapup--call MD5Pad, fill in digest and zero out ctx.
+ */
+void MD5Final(unsigned char digest[MD5_DIGEST_SIZE], struct MD5Context *ctx);
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_SIZE]);
+
+#endif /* !MHD_MD5_H */
diff --git a/src/lib/memorypool.c b/src/lib/memorypool.c
@@ -0,0 +1,340 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007, 2009, 2010 Daniel Pittman and Christian Grothoff
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+/**
+ * @file memorypool.c
+ * @brief memory pool
+ * @author Christian Grothoff
+ */
+#include "memorypool.h"
+
+/* define MAP_ANONYMOUS for Mac OS X */
+#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void*)-1)
+#endif
+
+/**
+ * Align to 2x word size (as GNU libc does).
+ */
+#define ALIGN_SIZE (2 * sizeof(void*))
+
+/**
+ * Round up 'n' to a multiple of ALIGN_SIZE.
+ */
+#define ROUND_TO_ALIGN(n) ((n+(ALIGN_SIZE-1)) & (~(ALIGN_SIZE-1)))
+
+
+/**
+ * Handle for a memory pool. Pools are not reentrant and must not be
+ * used by multiple threads.
+ */
+struct MemoryPool
+{
+
+ /**
+ * Pointer to the pool's memory
+ */
+ char *memory;
+
+ /**
+ * Size of the pool.
+ */
+ size_t size;
+
+ /**
+ * Offset of the first unallocated byte.
+ */
+ size_t pos;
+
+ /**
+ * Offset of the last unallocated byte.
+ */
+ size_t end;
+
+ /**
+ * #MHD_NO if pool was malloc'ed, #MHD_YES if mmapped (VirtualAlloc'ed for W32).
+ */
+ int is_mmap;
+};
+
+
+/**
+ * Free the memory given by @a ptr. Calls "free(ptr)". This function
+ * should be used to free the username returned by
+ * #MHD_digest_auth_get_username().
+ * @note Since v0.9.56
+ *
+ * @param ptr pointer to free.
+ */
+_MHD_EXTERN void
+MHD_free (void *ptr)
+{
+ free (ptr);
+}
+
+
+/**
+ * Create a memory pool.
+ *
+ * @param max maximum size of the pool
+ * @return NULL on error
+ */
+struct MemoryPool *
+MHD_pool_create (size_t max)
+{
+ struct MemoryPool *pool;
+
+ pool = malloc (sizeof (struct MemoryPool));
+ if (NULL == pool)
+ return NULL;
+#if defined(MAP_ANONYMOUS) || defined(_WIN32)
+ if (max <= 32 * 1024)
+ pool->memory = MAP_FAILED;
+ else
+#if defined(MAP_ANONYMOUS) && !defined(_WIN32)
+ pool->memory = mmap (NULL,
+ max,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS,
+ -1,
+ 0);
+#elif defined(_WIN32)
+ pool->memory = VirtualAlloc (NULL,
+ max,
+ MEM_COMMIT | MEM_RESERVE,
+ PAGE_READWRITE);
+#endif
+#else
+ pool->memory = MAP_FAILED;
+#endif
+ if ( (MAP_FAILED == pool->memory) ||
+ (NULL == pool->memory))
+ {
+ pool->memory = malloc (max);
+ if (NULL == pool->memory)
+ {
+ free (pool);
+ return NULL;
+ }
+ pool->is_mmap = MHD_NO;
+ }
+ else
+ {
+ pool->is_mmap = MHD_YES;
+ }
+ pool->pos = 0;
+ pool->end = max;
+ pool->size = max;
+ return pool;
+}
+
+
+/**
+ * Destroy a memory pool.
+ *
+ * @param pool memory pool to destroy
+ */
+void
+MHD_pool_destroy (struct MemoryPool *pool)
+{
+ if (NULL == pool)
+ return;
+ if (MHD_NO == pool->is_mmap)
+ free (pool->memory);
+ else
+#if defined(MAP_ANONYMOUS) && !defined(_WIN32)
+ munmap (pool->memory,
+ pool->size);
+#elif defined(_WIN32)
+ VirtualFree (pool->memory,
+ 0,
+ MEM_RELEASE);
+#else
+ abort ();
+#endif
+ free (pool);
+}
+
+
+/**
+ * Check how much memory is left in the @a pool
+ *
+ * @param pool pool to check
+ * @return number of bytes still available in @a pool
+ */
+size_t
+MHD_pool_get_free (struct MemoryPool *pool)
+{
+ return (pool->end - pool->pos);
+}
+
+
+/**
+ * Allocate size bytes from the pool.
+ *
+ * @param pool memory pool to use for the operation
+ * @param size number of bytes to allocate
+ * @param from_end allocate from end of pool (set to #MHD_YES);
+ * use this for small, persistent allocations that
+ * will never be reallocated
+ * @return NULL if the pool cannot support size more
+ * bytes
+ */
+void *
+MHD_pool_allocate (struct MemoryPool *pool,
+ size_t size,
+ int from_end)
+{
+ void *ret;
+ size_t asize;
+
+ asize = ROUND_TO_ALIGN (size);
+ if ( (0 == asize) && (0 != size) )
+ return NULL; /* size too close to SIZE_MAX */
+ if ( (pool->pos + asize > pool->end) ||
+ (pool->pos + asize < pool->pos))
+ return NULL;
+ if (from_end == MHD_YES)
+ {
+ ret = &pool->memory[pool->end - asize];
+ pool->end -= asize;
+ }
+ else
+ {
+ ret = &pool->memory[pool->pos];
+ pool->pos += asize;
+ }
+ return ret;
+}
+
+
+/**
+ * Reallocate a block of memory obtained from the pool.
+ * This is particularly efficient when growing or
+ * shrinking the block that was last (re)allocated.
+ * If the given block is not the most recently
+ * (re)allocated block, the memory of the previous
+ * allocation may be leaked until the pool is
+ * destroyed (and copying the data maybe required).
+ *
+ * @param pool memory pool to use for the operation
+ * @param old the existing block
+ * @param old_size the size of the existing block
+ * @param new_size the new size of the block
+ * @return new address of the block, or
+ * NULL if the pool cannot support @a new_size
+ * bytes (old continues to be valid for @a old_size)
+ */
+void *
+MHD_pool_reallocate (struct MemoryPool *pool,
+ void *old,
+ size_t old_size,
+ size_t new_size)
+{
+ void *ret;
+ size_t asize;
+
+ asize = ROUND_TO_ALIGN (new_size);
+ if ( (0 == asize) &&
+ (0 != new_size) )
+ return NULL; /* new_size too close to SIZE_MAX */
+ if ( (pool->end < old_size) ||
+ (pool->end < asize) )
+ return NULL; /* unsatisfiable or bogus request */
+
+ if ( (pool->pos >= old_size) &&
+ (&pool->memory[pool->pos - old_size] == old) )
+ {
+ /* was the previous allocation - optimize! */
+ if (pool->pos + asize - old_size <= pool->end)
+ {
+ /* fits */
+ pool->pos += asize - old_size;
+ if (asize < old_size) /* shrinking - zero again! */
+ memset (&pool->memory[pool->pos],
+ 0,
+ old_size - asize);
+ return old;
+ }
+ /* does not fit */
+ return NULL;
+ }
+ if (asize <= old_size)
+ return old; /* cannot shrink, no need to move */
+ if ((pool->pos + asize >= pool->pos) &&
+ (pool->pos + asize <= pool->end))
+ {
+ /* fits */
+ ret = &pool->memory[pool->pos];
+ if (0 != old_size)
+ memmove (ret,
+ old,
+ old_size);
+ pool->pos += asize;
+ return ret;
+ }
+ /* does not fit */
+ return NULL;
+}
+
+
+/**
+ * Clear all entries from the memory pool except
+ * for @a keep of the given @a size. The pointer
+ * returned should be a buffer of @a new_size where
+ * the first @a copy_bytes are from @a keep.
+ *
+ * @param pool memory pool to use for the operation
+ * @param keep pointer to the entry to keep (maybe NULL)
+ * @param copy_bytes how many bytes need to be kept at this address
+ * @param new_size how many bytes should the allocation we return have?
+ * (should be larger or equal to @a copy_bytes)
+ * @return addr new address of @a keep (if it had to change)
+ */
+void *
+MHD_pool_reset (struct MemoryPool *pool,
+ void *keep,
+ size_t copy_bytes,
+ size_t new_size)
+{
+ if ( (NULL != keep) &&
+ (keep != pool->memory) )
+ {
+ if (0 != copy_bytes)
+ memmove (pool->memory,
+ keep,
+ copy_bytes);
+ keep = pool->memory;
+ }
+ pool->end = pool->size;
+ /* technically not needed, but safer to zero out */
+ if (pool->size > copy_bytes)
+ memset (&pool->memory[copy_bytes],
+ 0,
+ pool->size - copy_bytes);
+ if (NULL != keep)
+ pool->pos = ROUND_TO_ALIGN (new_size);
+ return keep;
+}
+
+
+/* end of memorypool.c */
diff --git a/src/lib/memorypool.h b/src/lib/memorypool.h
@@ -0,0 +1,130 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007, 2009 Daniel Pittman and Christian Grothoff
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+/**
+ * @file memorypool.h
+ * @brief memory pool; mostly used for efficient (de)allocation
+ * for each connection and bounding memory use for each
+ * request
+ * @author Christian Grothoff
+ */
+
+#ifndef MEMORYPOOL_H
+#define MEMORYPOOL_H
+
+#include "internal.h"
+
+/**
+ * Opaque handle for a memory pool.
+ * Pools are not reentrant and must not be used
+ * by multiple threads.
+ */
+struct MemoryPool;
+
+
+/**
+ * Create a memory pool.
+ *
+ * @param max maximum size of the pool
+ * @return NULL on error
+ */
+struct MemoryPool *
+MHD_pool_create (size_t max);
+
+
+/**
+ * Destroy a memory pool.
+ *
+ * @param pool memory pool to destroy
+ */
+void
+MHD_pool_destroy (struct MemoryPool *pool);
+
+
+/**
+ * Allocate size bytes from the pool.
+ *
+ * @param pool memory pool to use for the operation
+ * @param size number of bytes to allocate
+ * @param from_end allocate from end of pool (set to #MHD_YES);
+ * use this for small, persistent allocations that
+ * will never be reallocated
+ * @return NULL if the pool cannot support size more
+ * bytes
+ */
+void *
+MHD_pool_allocate (struct MemoryPool *pool,
+ size_t size,
+ int from_end);
+
+
+/**
+ * Reallocate a block of memory obtained from the pool.
+ * This is particularly efficient when growing or
+ * shrinking the block that was last (re)allocated.
+ * If the given block is not the most recently
+ * (re)allocated block, the memory of the previous
+ * allocation may be leaked until the pool is
+ * destroyed (and copying the data maybe required).
+ *
+ * @param pool memory pool to use for the operation
+ * @param old the existing block
+ * @param old_size the size of the existing block
+ * @param new_size the new size of the block
+ * @return new address of the block, or
+ * NULL if the pool cannot support new_size
+ * bytes (old continues to be valid for old_size)
+ */
+void *
+MHD_pool_reallocate (struct MemoryPool *pool,
+ void *old,
+ size_t old_size,
+ size_t new_size);
+
+
+/**
+ * Check how much memory is left in the @a pool
+ *
+ * @param pool pool to check
+ * @return number of bytes still available in @a pool
+ */
+size_t
+MHD_pool_get_free (struct MemoryPool *pool);
+
+
+/**
+ * Clear all entries from the memory pool except
+ * for @a keep of the given @a copy_bytes. The pointer
+ * returned should be a buffer of @a new_size where
+ * the first @a copy_bytes are from @a keep.
+ *
+ * @param pool memory pool to use for the operation
+ * @param keep pointer to the entry to keep (maybe NULL)
+ * @param copy_bytes how many bytes need to be kept at this address
+ * @param new_size how many bytes should the allocation we return have?
+ * (should be larger or equal to @a copy_bytes)
+ * @return addr new address of @a keep (if it had to change)
+ */
+void *
+MHD_pool_reset (struct MemoryPool *pool,
+ void *keep,
+ size_t copy_bytes,
+ size_t new_size);
+
+#endif
diff --git a/src/lib/mhd_assert.h b/src/lib/mhd_assert.h
@@ -0,0 +1,49 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2017 Karlson2k (Evgeny Grin)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library.
+ If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file microhttpd/mhd_assert.h
+ * @brief macros for mhd_assert()
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_ASSERT_H
+#define MHD_ASSERT_H 1
+
+#include "mhd_options.h"
+#ifdef NDEBUG
+# define mhd_assert(ignore) ((void)0)
+#else /* _DEBUG */
+# ifdef HAVE_ASSERT
+# include <assert.h>
+# define mhd_assert(CHK) assert(CHK)
+# else /* ! HAVE_ASSERT */
+# include <stdio.h>
+# include <stdlib.h>
+# define mhd_assert(CHK) \
+ do { \
+ if (!(CHK)) { \
+ fprintf(stderr, "%s:%u Assertion failed: %s\nProgram aborted.\n", \
+ __FILE__, (unsigned)__LINE__, #CHK); \
+ fflush(stderr); abort(); } \
+ } while(0)
+# endif /* ! HAVE_ASSERT */
+#endif /* _DEBUG */
+
+#endif /* ! MHD_ASSERT_H */
diff --git a/src/lib/mhd_byteorder.h b/src/lib/mhd_byteorder.h
@@ -0,0 +1,160 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2015 Karlson2k (Evgeny Grin)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library.
+ If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file microhttpd/mhd_byteorder.h
+ * @brief macro definitions for host byte order
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_BYTEORDER_H
+#define MHD_BYTEORDER_H
+
+#include "platform.h"
+
+#if HAVE_ENDIAN_H
+#include <endian.h>
+#endif
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#if HAVE_MACHINE_ENDIAN_H
+#include <machine/endian.h>
+#endif
+
+#if HAVE_SYS_ENDIAN_H
+#include <sys/endian.h>
+#endif
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#if HAVE_SYS_BYTEORDER_H
+#include <sys/byteorder.h>
+#endif
+
+#if HAVE_SYS_MACHINE_H
+#include <sys/machine.h>
+#endif
+
+#if HAVE_MACHINE_PARAM_H
+#include <machine/param.h>
+#endif
+
+#if HAVE_SYS_ISA_DEFS_H
+#include <sys/isa_defs.h>
+#endif
+
+#define _MHD_BIG_ENDIAN 1234
+#define _MHD_LITTLE_ENDIAN 4321
+#define _MHD_PDP_ENDIAN 2143
+
+#if defined(__BYTE_ORDER__)
+#if defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define _MHD_BYTE_ORDER _MHD_BIG_ENDIAN
+#elif defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
+#elif defined(__ORDER_PDP_ENDIAN__) && __BYTE_ORDER__ == __ORDER_PDP_ENDIAN__
+#define _MHD_BYTE_ORDER _MHD_PDP_ENDIAN
+#endif /* __BYTE_ORDER__ == __ORDER_PDP_ENDIAN__ */
+#elif defined(__BYTE_ORDER)
+#if defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN
+#define _MHD_BYTE_ORDER _MHD_BIG_ENDIAN
+#elif defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN
+#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
+#elif defined(__PDP_ENDIAN) && __BYTE_ORDER == __PDP_ENDIAN
+#define _MHD_BYTE_ORDER _MHD_PDP_ENDIAN
+#endif /* __BYTE_ORDER == __PDP_ENDIAN */
+#elif defined (BYTE_ORDER)
+#if defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
+#define _MHD_BYTE_ORDER _MHD_BIG_ENDIAN
+#elif defined(LITTLE_ENDIAN) && BYTE_ORDER == LITTLE_ENDIAN
+#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
+#elif defined(PDP_ENDIAN) && BYTE_ORDER == PDP_ENDIAN
+#define _MHD_BYTE_ORDER _MHD_PDP_ENDIAN
+#endif /* __BYTE_ORDER == _PDP_ENDIAN */
+#elif defined (_BYTE_ORDER)
+#if defined(_BIG_ENDIAN) && _BYTE_ORDER == _BIG_ENDIAN
+#define _MHD_BYTE_ORDER _MHD_BIG_ENDIAN
+#elif defined(_LITTLE_ENDIAN) && _BYTE_ORDER == _LITTLE_ENDIAN
+#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
+#elif defined(_PDP_ENDIAN) && _BYTE_ORDER == _PDP_ENDIAN
+#define _MHD_BYTE_ORDER _MHD_PDP_ENDIAN
+#endif /* _BYTE_ORDER == _PDP_ENDIAN */
+#endif /* _BYTE_ORDER */
+
+#ifndef _MHD_BYTE_ORDER
+/* Byte order specification didn't detected in system headers */
+/* Try some guessing */
+
+#if (defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)) || \
+ (defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN))
+/* Seems that we are on big endian platform */
+#define _MHD_BYTE_ORDER _MHD_BIG_ENDIAN
+#elif (defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) || \
+ (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN))
+/* Seems that we are on little endian platform */
+#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
+#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || \
+ defined(_M_X64) || defined(_M_AMD64) || defined(i386) || defined(__i386) || \
+ defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || \
+ defined(_M_IX86) || defined(_X86_) || defined (__THW_INTEL__)
+/* x86 family is little endian */
+#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
+#elif defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \
+ defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__)
+/* Looks like we are on ARM/MIPS in big endian mode */
+#define _MHD_BYTE_ORDER _MHD_BIG_ENDIAN
+#elif defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \
+ defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__)
+/* Looks like we are on ARM/MIPS in little endian mode */
+#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
+#elif defined(__m68k__) || defined(M68000) || defined(__hppa__) || defined(__hppa) || \
+ defined(__HPPA__) || defined(__370__) || defined(__THW_370__) || \
+ defined(__s390__) || defined(__s390x__) || defined(__SYSC_ZARCH__)
+/* Looks like we are on big endian platform */
+#define _MHD_BYTE_ORDER _MHD_BIG_ENDIAN
+#elif defined(__ia64__) || defined(_IA64) || defined(__IA64__) || defined(__ia64) || \
+ defined(_M_IA64) || defined(__itanium__) || defined(__bfin__) || \
+ defined(__BFIN__) || defined(bfin) || defined(BFIN)
+/* Looks like we are on little endian platform */
+#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
+#elif defined(_WIN32)
+/* W32 is always little endian on all platforms */
+#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
+#elif defined(WORDS_BIGENDIAN)
+/* Use byte order detected by configure */
+#define _MHD_BYTE_ORDER _MHD_BIG_ENDIAN
+#endif /* _WIN32 */
+
+#endif /* !_MHD_BYTE_ORDER */
+
+#ifdef _MHD_BYTE_ORDER
+/* Some safety checks */
+#if defined(WORDS_BIGENDIAN) && _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN
+#error Configure detected big endian byte order but headers specify different byte order
+#elif !defined(WORDS_BIGENDIAN) && _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
+#error Configure did not detect big endian byte order but headers specify big endian byte order
+#endif /* !WORDS_BIGENDIAN && _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN */
+#endif /* _MHD_BYTE_ORDER */
+
+#endif /* !MHD_BYTEORDER_H */
diff --git a/src/lib/mhd_compat.c b/src/lib/mhd_compat.c
@@ -0,0 +1,114 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2014-2016 Karlson2k (Evgeny Grin)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+/**
+ * @file microhttpd/mhd_compat.c
+ * @brief Implementation of platform missing functions.
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#include "mhd_compat.h"
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <stdint.h>
+#include <time.h>
+#ifndef HAVE_SNPRINTF
+#include <stdio.h>
+#include <stdarg.h>
+#endif /* HAVE_SNPRINTF */
+#endif /* _WIN32 && !__CYGWIN__ */
+
+#ifndef HAVE_CALLOC
+#include <string.h> /* for memset() */
+#endif /* ! HAVE_CALLOC */
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+
+#ifndef HAVE_SNPRINTF
+/* Emulate snprintf function on W32 */
+int
+W32_snprintf (char *__restrict s,
+ size_t n,
+ const char *__restrict format,
+ ...)
+{
+ int ret;
+ va_list args;
+
+ if ( (0 != n) &&
+ (NULL != s) )
+ {
+ va_start (args,
+ format);
+ ret = _vsnprintf (s,
+ n,
+ format,
+ args);
+ va_end (args);
+ if ((int)n == ret)
+ s[n - 1] = 0;
+ if (ret >= 0)
+ return ret;
+ }
+ va_start(args,
+ format);
+ ret = _vscprintf (format,
+ args);
+ va_end(args);
+ if ( (0 <= ret) &&
+ (0 != n) &&
+ (NULL == s) )
+ return -1;
+
+ return ret;
+}
+
+#endif /* HAVE_SNPRINTF */
+#endif /* _WIN32 && !__CYGWIN__ */
+
+#ifndef HAVE_CALLOC
+
+#ifdef __has_builtin
+# if __has_builtin(__builtin_mul_overflow)
+# define MHD_HAVE_NUL_OVERFLOW 1
+# endif
+#elif __GNUC__+0 >= 5
+# define MHD_HAVE_NUL_OVERFLOW 1
+#endif /* __GNUC__ >= 5 */
+
+
+void *MHD_calloc_(size_t nelem, size_t elsize)
+{
+ size_t alloc_size;
+ void *ptr;
+#ifdef MHD_HAVE_NUL_OVERFLOW
+ if (__builtin_mul_overflow(nelem, elsize, &alloc_size) || 0 == alloc_size)
+ return NULL;
+#else /* ! MHD_HAVE_NUL_OVERFLOW */
+ alloc_size = nelem * elsize;
+ if (0 == alloc_size || elsize != alloc_size / nelem)
+ return NULL;
+#endif /* ! MHD_HAVE_NUL_OVERFLOW */
+ ptr = malloc (alloc_size);
+ if (NULL == ptr)
+ return NULL;
+ memset(ptr, 0, alloc_size);
+ return ptr;
+}
+#endif /* ! HAVE_CALLOC */
diff --git a/src/lib/mhd_compat.h b/src/lib/mhd_compat.h
@@ -0,0 +1,87 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2014-2016 Karlson2k (Evgeny Grin)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+/**
+ * @file microhttpd/mhd_compat.h
+ * @brief Header for platform missing functions.
+ * @author Karlson2k (Evgeny Grin)
+ *
+ * Provides compatibility for platforms with some missing
+ * functionality.
+ * Any functions can be implemented as macro on some platforms
+ * unless explicitly marked otherwise.
+ * Any function argument can be skipped in macro, so avoid
+ * variable modification in function parameters.
+ */
+
+#ifndef MHD_COMPAT_H
+#define MHD_COMPAT_H 1
+
+#include "mhd_options.h"
+#include <stdlib.h>
+#ifdef HAVE_STRING_H /* for strerror() */
+#include <string.h>
+#endif /* HAVE_STRING_H */
+
+ /* MHD_strerror_ is strerror */
+#define MHD_strerror_(errnum) strerror((errnum))
+
+/* Platform-independent snprintf name */
+#if defined(HAVE_SNPRINTF)
+#define MHD_snprintf_ snprintf
+#else /* ! HAVE_SNPRINTF */
+#if defined(_WIN32) && ! defined(__CYGWIN__)
+/* Emulate snprintf function on W32 */
+int W32_snprintf(char *__restrict s, size_t n, const char *__restrict format, ...);
+#define MHD_snprintf_ W32_snprintf
+#else /* ! _WIN32 || __CYGWIN__ */
+#error Your platform does not support snprintf() and MHD does not know how to emulate it on your platform.
+#endif /* ! _WIN32 || __CYGWIN__ */
+#endif /* ! HAVE_SNPRINTF */
+
+#ifdef HAVE_RANDOM
+/**
+ * Generate pseudo random number at least 30-bit wide.
+ * @return pseudo random number at least 30-bit wide.
+ */
+#define MHD_random_() random()
+#else /* HAVE_RANDOM */
+#ifdef HAVE_RAND
+/**
+ * Generate pseudo random number at least 30-bit wide.
+ * @return pseudo random number at least 30-bit wide.
+ */
+#define MHD_random_() ( (((long)rand()) << 15) + (long)rand() )
+#endif /* HAVE_RAND */
+#endif /* HAVE_RANDOM */
+
+#ifdef HAVE_CALLOC
+/**
+ * MHD_calloc_ is platform-independent calloc()
+ */
+#define MHD_calloc_(n,s) calloc((n),(s))
+#else /* ! HAVE_CALLOC */
+/**
+ * MHD_calloc_ is platform-independent calloc()
+ */
+void *MHD_calloc_(size_t nelem, size_t elsize);
+#endif /* ! HAVE_CALLOC */
+
+#endif /* MHD_COMPAT_H */
diff --git a/src/lib/mhd_itc.c b/src/lib/mhd_itc.c
@@ -0,0 +1,70 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2016 Karlson2k (Evgeny Grin)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+/**
+ * @file microhttpd/mhd_itc.c
+ * @brief Implementation of inter-thread communication functions
+ * @author Karlson2k (Evgeny Grin)
+ * @author Christian Grothoff
+ */
+
+#include "mhd_itc.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <fcntl.h>
+#include "internal.h"
+
+
+#if defined(_MHD_ITC_PIPE)
+#if !defined(_WIN32) || defined(__CYGWIN__)
+
+#ifndef HAVE_PIPE2_FUNC
+/**
+ * Change itc FD options to be non-blocking.
+ *
+ * @param itc the inter-thread communication primitive to manipulate
+ * @return non-zero if succeeded, zero otherwise
+ */
+int
+MHD_itc_nonblocking_ (struct MHD_itc_ itc)
+{
+ unsigned int i;
+
+ for (i=0;i<2;i++)
+ {
+ int flags;
+
+ flags = fcntl (itc.fd[i],
+ F_GETFL);
+ if (-1 == flags)
+ return 0;
+
+ if ( ((flags | O_NONBLOCK) != flags) &&
+ (0 != fcntl (itc.fd[i],
+ F_SETFL,
+ flags | O_NONBLOCK)) )
+ return 0;
+ }
+ return !0;
+}
+#endif /* ! HAVE_PIPE2_FUNC */
+#endif /* !_WIN32 || __CYGWIN__ */
+#endif /* _MHD_ITC_EVENTFD || _MHD_ITC_PIPE */
diff --git a/src/lib/mhd_itc.h b/src/lib/mhd_itc.h
@@ -0,0 +1,361 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2016 Karlson2k (Evgeny Grin)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+/**
+ * @file microhttpd/mhd_itc.h
+ * @brief Header for platform-independent inter-thread communication
+ * @author Karlson2k (Evgeny Grin)
+ * @author Christian Grothoff
+ *
+ * Provides basic abstraction for inter-thread communication.
+ * Any functions can be implemented as macro on some platforms
+ * unless explicitly marked otherwise.
+ * Any function argument can be skipped in macro, so avoid
+ * variable modification in function parameters.
+ */
+#ifndef MHD_ITC_H
+#define MHD_ITC_H 1
+#include "mhd_itc_types.h"
+
+#include <fcntl.h>
+
+#ifndef MHD_PANIC
+# include <stdio.h>
+# include <stdlib.h>
+/* Simple implementation of MHD_PANIC, to be used outside lib */
+# define MHD_PANIC(msg) do { fprintf (stderr, \
+ "Abnormal termination at %d line in file %s: %s\n", \
+ (int)__LINE__, __FILE__, msg); abort();} while(0)
+#endif /* ! MHD_PANIC */
+
+#if defined(_MHD_ITC_EVENTFD)
+
+/* **************** Optimized GNU/Linux ITC implementation by eventfd ********** */
+#include <sys/eventfd.h>
+#include <stdint.h> /* for uint64_t */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* for read(), write(), errno */
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_STRING_H
+#include <string.h> /* for strerror() */
+#endif
+
+
+/**
+ * Initialise ITC by generating eventFD
+ * @param itc the itc to initialise
+ * @return non-zero if succeeded, zero otherwise
+ */
+#define MHD_itc_init_(itc) (-1 != ((itc).fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK)))
+
+/**
+ * Get description string of last errno for itc operations.
+ */
+#define MHD_itc_last_strerror_() strerror(errno)
+
+/**
+ * Internal static const helper for MHD_itc_activate_()
+ */
+static const uint64_t _MHD_itc_wr_data = 1;
+
+/**
+ * Activate signal on @a itc
+ * @param itc the itc to use
+ * @param str ignored
+ * @return non-zero if succeeded, zero otherwise
+ */
+#define MHD_itc_activate_(itc, str) \
+ ((write((itc).fd, (const void*)&_MHD_itc_wr_data, 8) > 0) || (EAGAIN == errno))
+
+/**
+ * Return read FD of @a itc which can be used for poll(), select() etc.
+ * @param itc the itc to get FD
+ * @return FD of read side
+ */
+#define MHD_itc_r_fd_(itc) ((itc).fd)
+
+/**
+ * Return write FD of @a itc
+ * @param itc the itc to get FD
+ * @return FD of write side
+ */
+#define MHD_itc_w_fd_(itc) ((itc).fd)
+
+/**
+ * Clear signaled state on @a itc
+ * @param itc the itc to clear
+ */
+#define MHD_itc_clear_(itc) \
+ do { uint64_t __b; int __r; \
+ __r = read((itc).fd, &__b, sizeof(__b)); \
+ (void)__r; } while(0)
+
+/**
+ * Destroy previously initialised ITC
+ * @param itc the itc to destroy
+ * @return non-zero if succeeded, zero otherwise
+ */
+#define MHD_itc_destroy_(itc) ((0 != close ((itc).fd)) || (EBADF != errno))
+
+/**
+ * Check whether ITC has valid value.
+ *
+ * Macro check whether @a itc value is valid (allowed),
+ * macro does not check whether @a itc was really initialised.
+ * @param itc the itc to check
+ * @return boolean true if @a itc has valid value,
+ * boolean false otherwise.
+ */
+#define MHD_ITC_IS_VALID_(itc) (-1 != ((itc).fd))
+
+/**
+ * Set @a itc to invalid value.
+ * @param itc the itc to set
+ */
+#define MHD_itc_set_invalid_(itc) ((itc).fd = -1)
+
+
+#elif defined(_MHD_ITC_PIPE)
+
+/* **************** Standard UNIX ITC implementation by pipe ********** */
+
+#if defined(HAVE_PIPE2_FUNC) && defined(HAVE_FCNTL_H)
+# include <fcntl.h> /* for O_CLOEXEC, O_NONBLOCK */
+#endif /* HAVE_PIPE2_FUNC && HAVE_FCNTL_H */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* for read(), write(), errno */
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_STRING_H
+#include <string.h> /* for strerror() */
+#endif
+
+
+/**
+ * Initialise ITC by generating pipe
+ * @param itc the itc to initialise
+ * @return non-zero if succeeded, zero otherwise
+ */
+#ifdef HAVE_PIPE2_FUNC
+# define MHD_itc_init_(itc) (!pipe2((itc).fd, O_CLOEXEC | O_NONBLOCK))
+#else /* ! HAVE_PIPE2_FUNC */
+# define MHD_itc_init_(itc) \
+ ( (!pipe((itc).fd)) ? \
+ (MHD_itc_nonblocking_((itc)) ? \
+ (!0) : \
+ (MHD_itc_destroy_((itc)), 0) ) \
+ : (0) )
+#endif /* ! HAVE_PIPE2_FUNC */
+
+/**
+ * Get description string of last errno for itc operations.
+ */
+#define MHD_itc_last_strerror_() strerror(errno)
+
+/**
+ * Activate signal on @a itc
+ * @param itc the itc to use
+ * @param str one-symbol string, useful only for strace debug
+ * @return non-zero if succeeded, zero otherwise
+ */
+#define MHD_itc_activate_(itc, str) \
+ ((write((itc).fd[1], (const void*)(str), 1) > 0) || (EAGAIN == errno))
+
+
+/**
+ * Return read FD of @a itc which can be used for poll(), select() etc.
+ * @param itc the itc to get FD
+ * @return FD of read side
+ */
+#define MHD_itc_r_fd_(itc) ((itc).fd[0])
+
+/**
+ * Return write FD of @a itc
+ * @param itc the itc to get FD
+ * @return FD of write side
+ */
+#define MHD_itc_w_fd_(itc) ((itc).fd[1])
+
+/**
+ * Clear signaled state on @a itc
+ * @param itc the itc to clear
+ */
+#define MHD_itc_clear_(itc) do \
+ { long __b; \
+ while(0 < read((itc).fd[0], &__b, sizeof(__b))) \
+ {} } while(0)
+
+/**
+ * Destroy previously initialised ITC
+ * @param itc the itc to destroy
+ * @return non-zero if succeeded, zero otherwise
+ */
+#define MHD_itc_destroy_(itc) \
+ ( (0 == close ((itc).fd[0])) ? \
+ (0 == close ((itc).fd[1])) : \
+ ((close ((itc).fd[1])), 0) )
+
+/**
+ * Check whether ITC has valid value.
+ *
+ * Macro check whether @a itc value is valid (allowed),
+ * macro does not check whether @a itc was really initialised.
+ * @param itc the itc to check
+ * @return boolean true if @a itc has valid value,
+ * boolean false otherwise.
+ */
+#define MHD_ITC_IS_VALID_(itc) (-1 != (itc).fd[0])
+
+/**
+ * Set @a itc to invalid value.
+ * @param itc the itc to set
+ */
+#define MHD_itc_set_invalid_(itc) ((itc).fd[0] = (itc).fd[1] = -1)
+
+#ifndef HAVE_PIPE2_FUNC
+ /**
+ * Change itc FD options to be non-blocking.
+ *
+ * @param fd the FD to manipulate
+ * @return non-zero if succeeded, zero otherwise
+ */
+ int
+ MHD_itc_nonblocking_ (struct MHD_itc_ itc);
+#endif /* ! HAVE_PIPE2_FUNC */
+
+
+#elif defined(_MHD_ITC_SOCKETPAIR)
+
+/* **************** ITC implementation by socket pair ********** */
+
+#include "mhd_sockets.h"
+
+
+/**
+ * Initialise ITC by generating socketpair
+ * @param itc the itc to initialise
+ * @return non-zero if succeeded, zero otherwise
+ */
+#ifdef MHD_socket_pair_nblk_
+# define MHD_itc_init_(itc) MHD_socket_pair_nblk_((itc).sk)
+#else /* ! MHD_socket_pair_nblk_ */
+# define MHD_itc_init_(itc) \
+ (MHD_socket_pair_((itc).sk) ? \
+ (MHD_itc_nonblocking_((itc)) ? \
+ (!0) : \
+ (MHD_itc_destroy_((itc)), 0) ) \
+ : (0))
+#endif /* ! MHD_socket_pair_nblk_ */
+
+/**
+ * Get description string of last error for itc operations.
+ */
+#define MHD_itc_last_strerror_() MHD_socket_last_strerr_()
+
+/**
+ * Activate signal on @a itc
+ * @param itc the itc to use
+ * @param str one-symbol string, useful only for strace debug
+ * @return non-zero if succeeded, zero otherwise
+ */
+#define MHD_itc_activate_(itc, str) \
+ ((MHD_send_((itc).sk[1], (str), 1) > 0) || \
+ (MHD_SCKT_ERR_IS_EAGAIN_(MHD_socket_get_error_())))
+
+/**
+ * Return read FD of @a itc which can be used for poll(), select() etc.
+ * @param itc the itc to get FD
+ * @return FD of read side
+ */
+#define MHD_itc_r_fd_(itc) ((itc).sk[0])
+
+/**
+ * Return write FD of @a itc
+ * @param itc the itc to get FD
+ * @return FD of write side
+ */
+#define MHD_itc_w_fd_(itc) ((itc).sk[1])
+
+/**
+ * Clear signaled state on @a itc
+ * @param itc the itc to clear
+ */
+#define MHD_itc_clear_(itc) do \
+ { long __b; \
+ while(0 < recv((itc).sk[0], \
+ (char*)&__b, \
+ sizeof(__b), 0)) \
+ {} } while(0)
+
+/**
+ * Destroy previously initialised ITC
+ * @param itc the itc to destroy
+ * @return non-zero if succeeded, zero otherwise
+ */
+#define MHD_itc_destroy_(itc) \
+ ( MHD_socket_close_((itc).sk[0]) ? \
+ MHD_socket_close_((itc).sk[1]) : \
+ ((void)MHD_socket_close_((itc).sk[1]), 0) )
+
+
+/**
+ * Check whether ITC has valid value.
+ *
+ * Macro check whether @a itc value is valid (allowed),
+ * macro does not check whether @a itc was really initialised.
+ * @param itc the itc to check
+ * @return boolean true if @a itc has valid value,
+ * boolean false otherwise.
+ */
+#define MHD_ITC_IS_VALID_(itc) (MHD_INVALID_SOCKET != (itc).sk[0])
+
+/**
+ * Set @a itc to invalid value.
+ * @param itc the itc to set
+ */
+#define MHD_itc_set_invalid_(itc) ((itc).sk[0] = (itc).sk[1] = MHD_INVALID_SOCKET)
+
+#ifndef MHD_socket_pair_nblk_
+# define MHD_itc_nonblocking_(pip) (MHD_socket_nonblocking_((pip).sk[0]) && MHD_socket_nonblocking_((pip).sk[1]))
+#endif /* ! MHD_socket_pair_nblk_ */
+
+#endif /* _MHD_ITC_SOCKETPAIR */
+
+/**
+ * Destroy previously initialised ITC and abort execution
+ * if error is detected.
+ * @param itc the itc to destroy
+ */
+#define MHD_itc_destroy_chk_(itc) do { \
+ if (!MHD_itc_destroy_(itc)) \
+ MHD_PANIC(_("Failed to destroy ITC.\n")); \
+ } while(0)
+
+/**
+ * Check whether ITC has invalid value.
+ *
+ * Macro check whether @a itc value is invalid,
+ * macro does not check whether @a itc was destroyed.
+ * @param itc the itc to check
+ * @return boolean true if @a itc has invalid value,
+ * boolean false otherwise.
+ */
+#define MHD_ITC_IS_INVALID_(itc) (! MHD_ITC_IS_VALID_(itc))
+
+#endif /* MHD_ITC_H */
diff --git a/src/lib/mhd_itc_types.h b/src/lib/mhd_itc_types.h
@@ -0,0 +1,77 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2016 Karlson2k (Evgeny Grin), Christian Grothoff
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+/**
+ * @file microhttpd/mhd_itc_types.h
+ * @brief Types for platform-independent inter-thread communication
+ * @author Karlson2k (Evgeny Grin)
+ * @author Christian Grothoff
+ *
+ * Provides basic types for inter-thread communication.
+ * Designed to be included by other headers.
+ */
+#ifndef MHD_ITC_TYPES_H
+#define MHD_ITC_TYPES_H 1
+#include "mhd_options.h"
+
+/* Force socketpair on native W32 */
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(_MHD_ITC_SOCKETPAIR)
+#error _MHD_ITC_SOCKETPAIR is not defined on naitive W32 platform
+#endif /* _WIN32 && !__CYGWIN__ && !_MHD_ITC_SOCKETPAIR */
+
+#if defined(_MHD_ITC_EVENTFD)
+/* **************** Optimized GNU/Linux ITC implementation by eventfd ********** */
+
+/**
+ * Data type for a MHD ITC.
+ */
+struct MHD_itc_
+{
+ int fd;
+};
+
+#elif defined(_MHD_ITC_PIPE)
+/* **************** Standard UNIX ITC implementation by pipe ********** */
+
+/**
+ * Data type for a MHD ITC.
+ */
+struct MHD_itc_
+{
+ int fd[2];
+};
+
+
+#elif defined(_MHD_ITC_SOCKETPAIR)
+/* **************** ITC implementation by socket pair ********** */
+
+#include "mhd_sockets.h"
+
+/**
+ * Data type for a MHD ITC.
+ */
+struct MHD_itc_
+{
+ MHD_socket sk[2];
+};
+
+#endif /* _MHD_ITC_SOCKETPAIR */
+
+#endif /* ! MHD_ITC_TYPES_H */
diff --git a/src/lib/mhd_limits.h b/src/lib/mhd_limits.h
@@ -0,0 +1,146 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2015 Karlson2k (Evgeny Grin)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+/**
+ * @file microhttpd/mhd_limits.h
+ * @brief limits values definitions
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_LIMITS_H
+#define MHD_LIMITS_H
+
+#include "platform.h"
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif /* HAVE_LIMITS_H */
+
+#define MHD_UNSIGNED_TYPE_MAX_(type) ((type)-1)
+/* Assume 8 bits per byte, no padding bits. */
+#define MHD_SIGNED_TYPE_MAX_(type) \
+ ( (type)((( ((type)1) << (sizeof(type)*8 - 2)) - 1)*2 + 1) )
+#define MHD_TYPE_IS_SIGNED_(type) (((type)0)>((type)-1))
+
+#ifndef UINT_MAX
+#ifdef __UINT_MAX__
+#define UINT_MAX __UINT_MAX__
+#else /* ! __UINT_MAX__ */
+#define UINT_MAX MHD_UNSIGNED_TYPE_MAX_(unsigned int)
+#endif /* ! __UINT_MAX__ */
+#endif /* !UINT_MAX */
+
+#ifndef LONG_MAX
+#ifdef __LONG_MAX__
+#define LONG_MAX __LONG_MAX__
+#else /* ! __LONG_MAX__ */
+#define LONG_MAX MHD_SIGNED_TYPE_MAX(long)
+#endif /* ! __LONG_MAX__ */
+#endif /* !OFF_T_MAX */
+
+#ifndef ULLONG_MAX
+#define ULLONG_MAX MHD_UNSIGNED_TYPE_MAX_(MHD_UNSIGNED_LONG_LONG)
+#endif /* !ULLONG_MAX */
+
+#ifndef INT32_MAX
+#ifdef __INT32_MAX__
+#define INT32_MAX __INT32_MAX__
+#else /* ! __INT32_MAX__ */
+#define INT32_MAX ((int32_t)0x7FFFFFFF)
+#endif /* ! __INT32_MAX__ */
+#endif /* !INT32_MAX */
+
+#ifndef UINT32_MAX
+#ifdef __UINT32_MAX__
+#define UINT32_MAX __UINT32_MAX__
+#else /* ! __UINT32_MAX__ */
+#define UINT32_MAX ((int32_t)0xFFFFFFFF)
+#endif /* ! __UINT32_MAX__ */
+#endif /* !UINT32_MAX */
+
+#ifndef UINT64_MAX
+#ifdef __UINT64_MAX__
+#define UINT64_MAX __UINT64_MAX__
+#else /* ! __UINT64_MAX__ */
+#define UINT64_MAX ((uint64_t)0xFFFFFFFFFFFFFFFF)
+#endif /* ! __UINT64_MAX__ */
+#endif /* !UINT64_MAX */
+
+#ifndef INT64_MAX
+#ifdef __INT64_MAX__
+#define INT64_MAX __INT64_MAX__
+#else /* ! __INT64_MAX__ */
+#define INT64_MAX ((int64_t)0x7FFFFFFFFFFFFFFF)
+#endif /* ! __UINT64_MAX__ */
+#endif /* !INT64_MAX */
+
+#ifndef SIZE_MAX
+#ifdef __SIZE_MAX__
+#define SIZE_MAX __SIZE_MAX__
+#elif defined(UINTPTR_MAX)
+#define SIZE_MAX UINTPTR_MAX
+#else /* ! __SIZE_MAX__ */
+#define SIZE_MAX MHD_UNSIGNED_TYPE_MAX_(size_t)
+#endif /* ! __SIZE_MAX__ */
+#endif /* !SIZE_MAX */
+
+#ifndef SSIZE_MAX
+#ifdef __SSIZE_MAX__
+#define SSIZE_MAX __SSIZE_MAX__
+#elif defined(PTRDIFF_MAX)
+#define SSIZE_MAX PTRDIFF_MAX
+#elif defined(INTPTR_MAX)
+#define SSIZE_MAX INTPTR_MAX
+#else
+#define SSIZE_MAN MHD_SIGNED_TYPE_MAX_(ssize_t)
+#endif
+#endif /* ! SSIZE_MAX */
+
+#ifndef OFF_T_MAX
+#ifdef OFF_MAX
+#define OFF_T_MAX OFF_MAX
+#elif defined(OFFT_MAX)
+#define OFF_T_MAX OFFT_MAX
+#elif defined(__APPLE__) && defined(__MACH__)
+#define OFF_T_MAX INT64_MAX
+#else
+#define OFF_T_MAX MHD_SIGNED_TYPE_MAX_(off_t)
+#endif
+#endif /* !OFF_T_MAX */
+
+#if defined(_LARGEFILE64_SOURCE) && !defined(OFF64_T_MAX)
+#define OFF64_T_MAX MHD_SIGNED_TYPE_MAX_(uint64_t)
+#endif /* _LARGEFILE64_SOURCE && !OFF64_T_MAX */
+
+#ifndef TIME_T_MAX
+#define TIME_T_MAX ((time_t) \
+ ( MHD_TYPE_IS_SIGNED_(time_t) ? \
+ MHD_SIGNED_TYPE_MAX_(time_t) : \
+ MHD_UNSIGNED_TYPE_MAX_(time_t)))
+#endif /* !TIME_T_MAX */
+
+#ifndef TIMEVAL_TV_SEC_MAX
+#ifndef _WIN32
+#define TIMEVAL_TV_SEC_MAX TIME_T_MAX
+#else /* _WIN32 */
+#define TIMEVAL_TV_SEC_MAX LONG_MAX
+#endif /* _WIN32 */
+#endif /* !TIMEVAL_TV_SEC_MAX */
+
+#endif /* MHD_LIMITS_H */
diff --git a/src/lib/mhd_locks.h b/src/lib/mhd_locks.h
@@ -0,0 +1,183 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2016 Karlson2k (Evgeny Grin)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+/**
+ * @file microhttpd/mhd_locks.h
+ * @brief Header for platform-independent locks abstraction
+ * @author Karlson2k (Evgeny Grin)
+ * @author Christian Grothoff
+ *
+ * Provides basic abstraction for locks/mutex.
+ * Any functions can be implemented as macro on some platforms
+ * unless explicitly marked otherwise.
+ * Any function argument can be skipped in macro, so avoid
+ * variable modification in function parameters.
+ *
+ * @warning Unlike pthread functions, most of functions return
+ * nonzero on success.
+ */
+
+#ifndef MHD_LOCKS_H
+#define MHD_LOCKS_H 1
+
+#include "mhd_options.h"
+
+#if defined(MHD_USE_W32_THREADS)
+# define MHD_W32_MUTEX_ 1
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif /* !WIN32_LEAN_AND_MEAN */
+# include <windows.h>
+#elif defined(HAVE_PTHREAD_H) && defined(MHD_USE_POSIX_THREADS)
+# define MHD_PTHREAD_MUTEX_ 1
+# undef HAVE_CONFIG_H
+# include <pthread.h>
+# define HAVE_CONFIG_H 1
+#else
+# error No base mutex API is available.
+#endif
+
+#ifndef MHD_PANIC
+# include <stdio.h>
+# include <stdlib.h>
+/* Simple implementation of MHD_PANIC, to be used outside lib */
+# define MHD_PANIC(msg) do { fprintf (stderr, \
+ "Abnormal termination at %d line in file %s: %s\n", \
+ (int)__LINE__, __FILE__, msg); abort();} while(0)
+#endif /* ! MHD_PANIC */
+
+#if defined(MHD_PTHREAD_MUTEX_)
+ typedef pthread_mutex_t MHD_mutex_;
+#elif defined(MHD_W32_MUTEX_)
+ typedef CRITICAL_SECTION MHD_mutex_;
+#endif
+
+#if defined(MHD_PTHREAD_MUTEX_)
+/**
+ * Initialise new mutex.
+ * @param pmutex pointer to the mutex
+ * @return nonzero on success, zero otherwise
+ */
+#define MHD_mutex_init_(pmutex) (!(pthread_mutex_init((pmutex), NULL)))
+#elif defined(MHD_W32_MUTEX_)
+/**
+ * Initialise new mutex.
+ * @param pmutex pointer to mutex
+ * @return nonzero on success, zero otherwise
+ */
+#define MHD_mutex_init_(pmutex) (InitializeCriticalSectionAndSpinCount((pmutex),16))
+#endif
+
+#if defined(MHD_PTHREAD_MUTEX_)
+# if defined(PTHREAD_MUTEX_INITIALIZER)
+/**
+ * Define static mutex and statically initialise it.
+ */
+# define MHD_MUTEX_STATIC_DEFN_INIT_(m) static MHD_mutex_ m = PTHREAD_MUTEX_INITIALIZER
+# endif /* PTHREAD_MUTEX_INITIALIZER */
+#endif
+
+#if defined(MHD_PTHREAD_MUTEX_)
+/**
+ * Destroy previously initialised mutex.
+ * @param pmutex pointer to mutex
+ * @return nonzero on success, zero otherwise
+ */
+#define MHD_mutex_destroy_(pmutex) (!(pthread_mutex_destroy((pmutex))))
+#elif defined(MHD_W32_MUTEX_)
+/**
+ * Destroy previously initialised mutex.
+ * @param pmutex pointer to mutex
+ * @return Always nonzero
+ */
+#define MHD_mutex_destroy_(pmutex) (DeleteCriticalSection((pmutex)), !0)
+#endif
+
+/**
+ * Destroy previously initialised mutex and abort execution
+ * if error is detected.
+ * @param pmutex pointer to mutex
+ */
+#define MHD_mutex_destroy_chk_(pmutex) do { \
+ if (!MHD_mutex_destroy_(pmutex)) \
+ MHD_PANIC(_("Failed to destroy mutex.\n")); \
+ } while(0)
+
+
+#if defined(MHD_PTHREAD_MUTEX_)
+/**
+ * Acquire lock on previously initialised mutex.
+ * If mutex was already locked by other thread, function
+ * blocks until mutex becomes available.
+ * @param pmutex pointer to mutex
+ * @return nonzero on success, zero otherwise
+ */
+#define MHD_mutex_lock_(pmutex) (!(pthread_mutex_lock((pmutex))))
+#elif defined(MHD_W32_MUTEX_)
+/**
+ * Acquire lock on previously initialised mutex.
+ * If mutex was already locked by other thread, function
+ * blocks until mutex becomes available.
+ * @param pmutex pointer to mutex
+ * @return Always nonzero
+ */
+#define MHD_mutex_lock_(pmutex) (EnterCriticalSection((pmutex)), !0)
+#endif
+
+/**
+ * Acquire lock on previously initialised mutex.
+ * If mutex was already locked by other thread, function
+ * blocks until mutex becomes available.
+ * If error is detected, execution will be aborted.
+ * @param pmutex pointer to mutex
+ */
+#define MHD_mutex_lock_chk_(pmutex) do { \
+ if (!MHD_mutex_lock_(pmutex)) \
+ MHD_PANIC(_("Failed to lock mutex.\n")); \
+ } while(0)
+
+#if defined(MHD_PTHREAD_MUTEX_)
+/**
+ * Unlock previously initialised and locked mutex.
+ * @param pmutex pointer to mutex
+ * @return nonzero on success, zero otherwise
+ */
+#define MHD_mutex_unlock_(pmutex) (!(pthread_mutex_unlock((pmutex))))
+#elif defined(MHD_W32_MUTEX_)
+/**
+ * Unlock previously initialised and locked mutex.
+ * @param pmutex pointer to mutex
+ * @return Always nonzero
+ */
+#define MHD_mutex_unlock_(pmutex) (LeaveCriticalSection((pmutex)), !0)
+#endif
+
+/**
+ * Unlock previously initialised and locked mutex.
+ * If error is detected, execution will be aborted.
+ * @param pmutex pointer to mutex
+ */
+#define MHD_mutex_unlock_chk_(pmutex) do { \
+ if (!MHD_mutex_unlock_(pmutex)) \
+ MHD_PANIC(_("Failed to unlock mutex.\n")); \
+ } while(0)
+
+
+#endif /* ! MHD_LOCKS_H */
diff --git a/src/lib/mhd_mono_clock.c b/src/lib/mhd_mono_clock.c
@@ -0,0 +1,377 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2015 Karlson2k (Evgeny Grin)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+/**
+ * @file microhttpd/mhd_mono_clock.h
+ * @brief internal monotonic clock functions implementations
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#include "mhd_mono_clock.h"
+
+#if defined(_WIN32) && ! defined(__CYGWIN__) && defined(HAVE_CLOCK_GETTIME)
+/* Prefer native clock source over wrappers */
+#undef HAVE_CLOCK_GETTIME
+#endif /* _WIN32 && ! __CYGWIN__ && HAVE_CLOCK_GETTIME */
+
+#ifdef HAVE_CLOCK_GETTIME
+#include <time.h>
+#endif /* HAVE_CLOCK_GETTIME */
+
+#ifdef HAVE_GETHRTIME
+#ifdef HAVE_SYS_TIME_H
+/* Solaris defines gethrtime() in sys/time.h */
+#include <sys/time.h>
+#endif /* HAVE_SYS_TIME_H */
+#ifdef HAVE_TIME_H
+/* HP-UX defines gethrtime() in time.h */
+#include <time.h>
+#endif /* HAVE_TIME_H */
+#endif /* HAVE_GETHRTIME */
+
+#ifdef HAVE_CLOCK_GET_TIME
+#include <mach/mach.h>
+/* for host_get_clock_service(), mach_host_self(), mach_task_self() */
+#include <mach/clock.h>
+/* for clock_get_time() */
+
+#define _MHD_INVALID_CLOCK_SERV ((clock_serv_t) -2)
+
+static clock_serv_t mono_clock_service = _MHD_INVALID_CLOCK_SERV;
+#endif /* HAVE_CLOCK_GET_TIME */
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+/* Do not include unneeded parts of W32 headers. */
+#define WIN32_LEAN_AND_MEAN 1
+#endif /* !WIN32_LEAN_AND_MEAN */
+#include <windows.h>
+#include <stdint.h>
+#endif /* _WIN32 */
+
+#ifdef HAVE_CLOCK_GETTIME
+#ifdef CLOCK_REALTIME
+#define _MHD_UNWANTED_CLOCK CLOCK_REALTIME
+#else /* !CLOCK_REALTIME */
+#define _MHD_UNWANTED_CLOCK ((clockid_t) -2)
+#endif /* !CLOCK_REALTIME */
+
+static clockid_t mono_clock_id = _MHD_UNWANTED_CLOCK;
+#endif /* HAVE_CLOCK_GETTIME */
+
+/* sync clocks; reduce chance of value wrap */
+#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_GET_TIME) || defined(HAVE_GETHRTIME)
+static time_t mono_clock_start;
+#endif /* HAVE_CLOCK_GETTIME || HAVE_CLOCK_GET_TIME || HAVE_GETHRTIME */
+static time_t sys_clock_start;
+#ifdef HAVE_GETHRTIME
+static hrtime_t hrtime_start;
+#endif /* HAVE_GETHRTIME */
+#ifdef _WIN32
+#if _WIN32_WINNT >= 0x0600
+static uint64_t tick_start;
+#else /* _WIN32_WINNT < 0x0600 */
+static int64_t perf_freq;
+static int64_t perf_start;
+#endif /* _WIN32_WINNT < 0x0600 */
+#endif /* _WIN32 */
+
+
+
+/**
+ * Type of monotonic clock source
+ */
+enum _MHD_mono_clock_source
+{
+ /**
+ * No monotonic clock
+ */
+ _MHD_CLOCK_NO_SOURCE = 0,
+
+ /**
+ * clock_gettime() with specific clock
+ */
+ _MHD_CLOCK_GETTIME,
+
+ /**
+ * clock_get_time() with specific clock service
+ */
+ _MHD_CLOCK_GET_TIME,
+
+ /**
+ * gethrtime() / 1000000000
+ */
+ _MHD_CLOCK_GETHRTIME,
+
+ /**
+ * GetTickCount64() / 1000
+ */
+ _MHD_CLOCK_GETTICKCOUNT64,
+
+ /**
+ * QueryPerformanceCounter() / QueryPerformanceFrequency()
+ */
+ _MHD_CLOCK_PERFCOUNTER
+};
+
+
+/**
+ * Initialise monotonic seconds counter.
+ */
+void
+MHD_monotonic_sec_counter_init (void)
+{
+#ifdef HAVE_CLOCK_GET_TIME
+ mach_timespec_t cur_time;
+#endif /* HAVE_CLOCK_GET_TIME */
+ enum _MHD_mono_clock_source mono_clock_source = _MHD_CLOCK_NO_SOURCE;
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec ts;
+
+ mono_clock_id = _MHD_UNWANTED_CLOCK;
+#endif /* HAVE_CLOCK_GETTIME */
+#ifdef HAVE_CLOCK_GET_TIME
+ mono_clock_service = _MHD_INVALID_CLOCK_SERV;
+#endif /* HAVE_CLOCK_GET_TIME */
+
+ /* just a little syntactic trick to get the
+ various following ifdef's to work out nicely */
+ if (0)
+ {
+ }
+ else
+#ifdef HAVE_CLOCK_GETTIME
+#ifdef CLOCK_MONOTONIC_COARSE
+ /* Linux-specific fast value-getting clock */
+ /* Can be affected by frequency adjustment and don't count time in suspend, */
+ /* but preferred since it's fast */
+ if (0 == clock_gettime (CLOCK_MONOTONIC_COARSE,
+ &ts))
+ {
+ mono_clock_id = CLOCK_MONOTONIC_COARSE;
+ mono_clock_start = ts.tv_sec;
+ mono_clock_source = _MHD_CLOCK_GETTIME;
+ }
+ else
+#endif /* CLOCK_MONOTONIC_COARSE */
+#ifdef CLOCK_MONOTONIC_FAST
+ /* FreeBSD/DragonFly fast value-getting clock */
+ /* Can be affected by frequency adjustment, but preferred since it's fast */
+ if (0 == clock_gettime (CLOCK_MONOTONIC_FAST,
+ &ts))
+ {
+ mono_clock_id = CLOCK_MONOTONIC_FAST;
+ mono_clock_start = ts.tv_sec;
+ mono_clock_source = _MHD_CLOCK_GETTIME;
+ }
+ else
+#endif /* CLOCK_MONOTONIC_COARSE */
+#ifdef CLOCK_MONOTONIC_RAW
+ /* Linux-specific clock */
+ /* Not affected by frequency adjustment, but don't count time in suspend */
+ if (0 == clock_gettime (CLOCK_MONOTONIC_RAW,
+ &ts))
+ {
+ mono_clock_id = CLOCK_MONOTONIC_RAW;
+ mono_clock_start = ts.tv_sec;
+ mono_clock_source = _MHD_CLOCK_GETTIME;
+ }
+ else
+#endif /* CLOCK_MONOTONIC_RAW */
+#ifdef CLOCK_BOOTTIME
+ /* Linux-specific clock */
+ /* Count time in suspend so it's real monotonic on Linux, */
+ /* but can be slower value-getting than other clocks */
+ if (0 == clock_gettime (CLOCK_BOOTTIME,
+ &ts))
+ {
+ mono_clock_id = CLOCK_BOOTTIME;
+ mono_clock_start = ts.tv_sec;
+ mono_clock_source = _MHD_CLOCK_GETTIME;
+ }
+ else
+#endif /* CLOCK_BOOTTIME */
+#ifdef CLOCK_MONOTONIC
+ /* Monotonic clock */
+ /* Widely supported, may be affected by frequency adjustment */
+ /* On Linux it's not truly monotonic as it doesn't count time in suspend */
+ if (0 == clock_gettime (CLOCK_MONOTONIC,
+ &ts))
+ {
+ mono_clock_id = CLOCK_MONOTONIC;
+ mono_clock_start = ts.tv_sec;
+ mono_clock_source = _MHD_CLOCK_GETTIME;
+ }
+ else
+#endif /* CLOCK_BOOTTIME */
+#endif /* HAVE_CLOCK_GETTIME */
+#ifdef HAVE_CLOCK_GET_TIME
+ /* Darwin-specific monotonic clock */
+ /* Should be monotonic as clock_set_time function always unconditionally */
+ /* failed on latest kernels */
+ if ( (KERN_SUCCESS == host_get_clock_service (mach_host_self(),
+ SYSTEM_CLOCK,
+ &mono_clock_service)) &&
+ (KERN_SUCCESS == clock_get_time (mono_clock_service,
+ &cur_time)) )
+ {
+ mono_clock_start = cur_time.tv_sec;
+ mono_clock_source = _MHD_CLOCK_GET_TIME;
+ }
+ else
+#endif /* HAVE_CLOCK_GET_TIME */
+#ifdef _WIN32
+#if _WIN32_WINNT >= 0x0600
+ /* W32 Vista or later specific monotonic clock */
+ /* Available since Vista, ~15ms accuracy */
+ if (1)
+ {
+ tick_start = GetTickCount64 ();
+ mono_clock_source = _MHD_CLOCK_GETTICKCOUNT64;
+ }
+ else
+#else /* _WIN32_WINNT < 0x0600 */
+ /* W32 specific monotonic clock */
+ /* Available on Windows 2000 and later */
+ if (1)
+ {
+ LARGE_INTEGER freq;
+ LARGE_INTEGER perf_counter;
+
+ QueryPerformanceFrequency (&freq); /* never fail on XP and later */
+ QueryPerformanceCounter (&perf_counter); /* never fail on XP and later */
+ perf_freq = freq.QuadPart;
+ perf_start = perf_counter.QuadPart;
+ mono_clock_source = _MHD_CLOCK_PERFCOUNTER;
+ }
+ else
+#endif /* _WIN32_WINNT < 0x0600 */
+#endif /* _WIN32 */
+#ifdef HAVE_CLOCK_GETTIME
+#ifdef CLOCK_HIGHRES
+ /* Solaris-specific monotonic high-resolution clock */
+ /* Not preferred due to be potentially resource-hungry */
+ if (0 == clock_gettime (CLOCK_HIGHRES,
+ &ts))
+ {
+ mono_clock_id = CLOCK_HIGHRES;
+ mono_clock_start = ts.tv_sec;
+ mono_clock_source = _MHD_CLOCK_GETTIME;
+ }
+ else
+#endif /* CLOCK_HIGHRES */
+#endif /* HAVE_CLOCK_GETTIME */
+#ifdef HAVE_GETHRTIME
+ /* HP-UX and Solaris monotonic clock */
+ /* Not preferred due to be potentially resource-hungry */
+ if (1)
+ {
+ hrtime_start = gethrtime ();
+ mono_clock_source = _MHD_CLOCK_GETHRTIME;
+ }
+ else
+#endif /* HAVE_GETHRTIME */
+ {
+ /* no suitable clock source was found */
+ mono_clock_source = _MHD_CLOCK_NO_SOURCE;
+ }
+
+#ifdef HAVE_CLOCK_GET_TIME
+ if ( (_MHD_CLOCK_GET_TIME != mono_clock_source) &&
+ (_MHD_INVALID_CLOCK_SERV != mono_clock_service) )
+ {
+ /* clock service was initialised but clock_get_time failed */
+ mach_port_deallocate (mach_task_self(),
+ mono_clock_service);
+ mono_clock_service = _MHD_INVALID_CLOCK_SERV;
+ }
+#else
+ (void) mono_clock_source; /* avoid compiler warning */
+#endif /* HAVE_CLOCK_GET_TIME */
+
+ sys_clock_start = time (NULL);
+}
+
+
+/**
+ * Deinitialise monotonic seconds counter by freeing any allocated resources
+ */
+void
+MHD_monotonic_sec_counter_finish (void)
+{
+#ifdef HAVE_CLOCK_GET_TIME
+ if (_MHD_INVALID_CLOCK_SERV != mono_clock_service)
+ {
+ mach_port_deallocate (mach_task_self(),
+ mono_clock_service);
+ mono_clock_service = _MHD_INVALID_CLOCK_SERV;
+ }
+#endif /* HAVE_CLOCK_GET_TIME */
+}
+
+
+/**
+ * Monotonic seconds counter, useful for timeout calculation.
+ * Tries to be not affected by manually setting the system real time
+ * clock or adjustments by NTP synchronization.
+ *
+ * @return number of seconds from some fixed moment
+ */
+time_t
+MHD_monotonic_sec_counter (void)
+{
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec ts;
+
+ if ( (_MHD_UNWANTED_CLOCK != mono_clock_id) &&
+ (0 == clock_gettime (mono_clock_id ,
+ &ts)) )
+ return ts.tv_sec - mono_clock_start;
+#endif /* HAVE_CLOCK_GETTIME */
+#ifdef HAVE_CLOCK_GET_TIME
+ if (_MHD_INVALID_CLOCK_SERV != mono_clock_service)
+ {
+ mach_timespec_t cur_time;
+
+ if (KERN_SUCCESS == clock_get_time(mono_clock_service,
+ &cur_time))
+ return cur_time.tv_sec - mono_clock_start;
+ }
+#endif /* HAVE_CLOCK_GET_TIME */
+#if defined(_WIN32)
+#if _WIN32_WINNT >= 0x0600
+ if (1)
+ return (time_t)(((uint64_t)(GetTickCount64() - tick_start)) / 1000);
+#else /* _WIN32_WINNT < 0x0600 */
+ if (0 != perf_freq)
+ {
+ LARGE_INTEGER perf_counter;
+
+ QueryPerformanceCounter (&perf_counter); /* never fail on XP and later */
+ return (time_t)(((uint64_t)(perf_counter.QuadPart - perf_start)) / perf_freq);
+ }
+#endif /* _WIN32_WINNT < 0x0600 */
+#endif /* _WIN32 */
+#ifdef HAVE_GETHRTIME
+ if (1)
+ return (time_t)(((uint64_t) (gethrtime () - hrtime_start)) / 1000000000);
+#endif /* HAVE_GETHRTIME */
+
+ return time (NULL) - sys_clock_start;
+}
diff --git a/src/lib/mhd_mono_clock.h b/src/lib/mhd_mono_clock.h
@@ -0,0 +1,60 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2015 Karlson2k (Evgeny Grin)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+/**
+ * @file microhttpd/mhd_mono_clock.h
+ * @brief internal monotonic clock functions declarations
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_MONO_CLOCK_H
+#define MHD_MONO_CLOCK_H 1
+#include "mhd_options.h"
+
+#if defined(HAVE_TIME_H)
+#include <time.h>
+#elif defined(HAVE_SYS_TYPES_H)
+#include <sys/types.h>
+#endif
+
+/**
+ * Initialise monotonic seconds counter.
+ */
+void
+MHD_monotonic_sec_counter_init(void);
+
+
+/**
+ * Deinitialise monotonic seconds counter by freeing any allocated resources
+ */
+void
+MHD_monotonic_sec_counter_finish(void);
+
+
+/**
+ * Monotonic seconds counter, useful for timeout calculation.
+ * Tries to be not affected by manually setting the system real time
+ * clock or adjustments by NTP synchronization.
+ *
+ * @return number of seconds from some fixed moment
+ */
+time_t
+MHD_monotonic_sec_counter(void);
+
+#endif /* MHD_MONO_CLOCK_H */
diff --git a/src/microhttpd/mhd_sockets.c b/src/lib/mhd_sockets.c
diff --git a/src/lib/mhd_sockets.h b/src/lib/mhd_sockets.h
@@ -0,0 +1,760 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2014-2016 Karlson2k (Evgeny Grin)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+/**
+ * @file microhttpd/mhd_sockets.c
+ * @brief Header for platform-independent sockets abstraction
+ * @author Karlson2k (Evgeny Grin)
+ *
+ * Provides basic abstraction for sockets.
+ * Any functions can be implemented as macro on some platforms
+ * unless explicitly marked otherwise.
+ * Any function argument can be skipped in macro, so avoid
+ * variable modification in function parameters.
+ */
+
+#ifndef MHD_SOCKETS_H
+#define MHD_SOCKETS_H 1
+#include "mhd_options.h"
+
+#include <errno.h>
+
+#if !defined(MHD_POSIX_SOCKETS) && !defined(MHD_WINSOCK_SOCKETS)
+# if !defined(_WIN32) || defined(__CYGWIN__)
+# define MHD_POSIX_SOCKETS 1
+# else /* defined(_WIN32) && !defined(__CYGWIN__) */
+# define MHD_WINSOCK_SOCKETS 1
+# endif /* defined(_WIN32) && !defined(__CYGWIN__) */
+#endif /* !MHD_POSIX_SOCKETS && !MHD_WINSOCK_SOCKETS */
+
+/*
+ * MHD require headers that define socket type, socket basic functions
+ * (socket(), accept(), listen(), bind(), send(), recv(), select()), socket
+ * parameters like SOCK_CLOEXEC, SOCK_NONBLOCK, additional socket functions
+ * (poll(), epoll(), accept4()), struct timeval and other types, required
+ * for socket function.
+ */
+#if defined(MHD_POSIX_SOCKETS)
+# ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h> /* required on old platforms */
+# endif
+# ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+# endif
+# if defined(__VXWORKS__) || defined(__vxworks) || defined(OS_VXWORKS)
+# ifdef HAVE_SOCKLIB_H
+# include <sockLib.h>
+# endif /* HAVE_SOCKLIB_H */
+# ifdef HAVE_INETLIB_H
+# include <inetLib.h>
+# endif /* HAVE_INETLIB_H */
+# include <strings.h> /* required for FD_SET (bzero() function) */
+# endif /* __VXWORKS__ || __vxworks || OS_VXWORKS */
+# ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+# endif /* HAVE_NETINET_IN_H */
+# ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+# endif
+# ifdef HAVE_NET_IF_H
+# include <net/if.h>
+# endif
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# endif
+# ifdef HAVE_TIME_H
+# include <time.h>
+# endif
+# ifdef HAVE_NETDB_H
+# include <netdb.h>
+# endif
+# ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+# endif
+# ifdef EPOLL_SUPPORT
+# include <sys/epoll.h>
+# endif
+# ifdef HAVE_NETINET_TCP_H
+ /* for TCP_FASTOPEN and TCP_CORK */
+# include <netinet/tcp.h>
+# endif
+# ifdef HAVE_STRING_H
+# include <string.h> /* for strerror() */
+# endif
+#elif defined(MHD_WINSOCK_SOCKETS)
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif /* !WIN32_LEAN_AND_MEAN */
+# include <winsock2.h>
+# include <ws2tcpip.h>
+#endif /* MHD_WINSOCK_SOCKETS */
+
+#if defined(HAVE_POLL_H) && defined(HAVE_POLL)
+# include <poll.h>
+#endif
+
+#include <stddef.h>
+#if defined(_MSC_FULL_VER) && !defined (_SSIZE_T_DEFINED)
+# include <stdint.h>
+# define _SSIZE_T_DEFINED
+ typedef intptr_t ssize_t;
+#endif /* !_SSIZE_T_DEFINED */
+
+#include "mhd_limits.h"
+
+#ifdef _MHD_FD_SETSIZE_IS_DEFAULT
+# define _MHD_SYS_DEFAULT_FD_SETSIZE FD_SETSIZE
+#else /* ! _MHD_FD_SETSIZE_IS_DEFAULT */
+# include "sysfdsetsize.h"
+# define _MHD_SYS_DEFAULT_FD_SETSIZE get_system_fdsetsize_value()
+#endif /* ! _MHD_FD_SETSIZE_IS_DEFAULT */
+
+#ifndef MHD_PANIC
+# include <stdio.h>
+# include <stdlib.h>
+/* Simple implementation of MHD_PANIC, to be used outside lib */
+# define MHD_PANIC(msg) do { fprintf (stderr, \
+ "Abnormal termination at %d line in file %s: %s\n", \
+ (int)__LINE__, __FILE__, msg); abort();} while(0)
+#endif /* ! MHD_PANIC */
+
+#ifndef MHD_SOCKET_DEFINED
+/**
+ * MHD_socket is type for socket FDs
+ */
+# if defined(MHD_POSIX_SOCKETS)
+ typedef int MHD_socket;
+# define MHD_INVALID_SOCKET (-1)
+# elif defined(MHD_WINSOCK_SOCKETS)
+ typedef SOCKET MHD_socket;
+# define MHD_INVALID_SOCKET (INVALID_SOCKET)
+# endif /* MHD_WINSOCK_SOCKETS */
+
+# define MHD_SOCKET_DEFINED 1
+#endif /* ! MHD_SOCKET_DEFINED */
+
+#ifdef SOCK_CLOEXEC
+# define MAYBE_SOCK_CLOEXEC SOCK_CLOEXEC
+#else /* ! SOCK_CLOEXEC */
+# define MAYBE_SOCK_CLOEXEC 0
+#endif /* ! SOCK_CLOEXEC */
+
+#ifdef HAVE_SOCK_NONBLOCK
+# define MAYBE_SOCK_NONBLOCK SOCK_NONBLOCK
+#else /* ! HAVE_SOCK_NONBLOCK */
+# define MAYBE_SOCK_NONBLOCK 0
+#endif /* ! HAVE_SOCK_NONBLOCK */
+
+#ifdef MSG_NOSIGNAL
+# define MAYBE_MSG_NOSIGNAL MSG_NOSIGNAL
+#else /* ! MSG_NOSIGNAL */
+# define MAYBE_MSG_NOSIGNAL 0
+#endif /* ! MSG_NOSIGNAL */
+
+#if !defined(SHUT_WR) && defined(SD_SEND)
+# define SHUT_WR SD_SEND
+#endif
+#if !defined(SHUT_RD) && defined(SD_RECEIVE)
+# define SHUT_RD SD_RECEIVE
+#endif
+#if !defined(SHUT_RDWR) && defined(SD_BOTH)
+# define SHUT_RDWR SD_BOTH
+#endif
+
+#if HAVE_ACCEPT4+0 != 0 && (defined(HAVE_SOCK_NONBLOCK) || defined(SOCK_CLOEXEC))
+# define USE_ACCEPT4 1
+#endif
+
+#if defined(HAVE_EPOLL_CREATE1) && defined(EPOLL_CLOEXEC)
+# define USE_EPOLL_CREATE1 1
+#endif /* HAVE_EPOLL_CREATE1 && EPOLL_CLOEXEC */
+
+#ifdef TCP_FASTOPEN
+/**
+ * Default TCP fastopen queue size.
+ */
+#define MHD_TCP_FASTOPEN_QUEUE_SIZE_DEFAULT 10
+#endif
+
+
+/**
+ * MHD_SCKT_OPT_BOOL_ is type for bool parameters for setsockopt()/getsockopt()
+ */
+#ifdef MHD_POSIX_SOCKETS
+ typedef int MHD_SCKT_OPT_BOOL_;
+#else /* MHD_WINSOCK_SOCKETS */
+ typedef BOOL MHD_SCKT_OPT_BOOL_;
+#endif /* MHD_WINSOCK_SOCKETS */
+
+/**
+ * MHD_SCKT_SEND_SIZE_ is type used to specify size for send and recv
+ * functions
+ */
+#if !defined(MHD_WINSOCK_SOCKETS)
+ typedef size_t MHD_SCKT_SEND_SIZE_;
+#else
+ typedef int MHD_SCKT_SEND_SIZE_;
+#endif
+
+/**
+ * MHD_SCKT_SEND_MAX_SIZE_ is maximum send()/recv() size value.
+ */
+#if !defined(MHD_WINSOCK_SOCKETS)
+# define MHD_SCKT_SEND_MAX_SIZE_ SSIZE_MAX
+#else
+# define MHD_SCKT_SEND_MAX_SIZE_ INT_MAX
+#endif
+
+/**
+ * MHD_socket_close_(fd) close any FDs (non-W32) / close only socket
+ * FDs (W32). Note that on HP-UNIX, this function may leak the FD if
+ * errno is set to EINTR. Do not use HP-UNIX.
+ *
+ * @param fd descriptor to close
+ * @return boolean true on success (error codes like EINTR and EIO are
+ * counted as success, only EBADF counts as an error!),
+ * boolean false otherwise.
+ */
+#if !defined(MHD_WINSOCK_SOCKETS)
+# define MHD_socket_close_(fd) ((0 == close((fd))) || (EBADF != errno))
+#else
+# define MHD_socket_close_(fd) (0 == closesocket((fd)))
+#endif
+
+/**
+ * MHD_socket_close_chk_(fd) close socket and abort execution
+ * if error is detected.
+ * @param fd socket to close
+ */
+#define MHD_socket_close_chk_(fd) do { \
+ if (!MHD_socket_close_(fd)) \
+ MHD_PANIC(_("Close socket failed.\n")); \
+ } while(0)
+
+
+/**
+ * MHD_send_ is wrapper for system's send()
+ * @param s the socket to use
+ * @param b the buffer with data to send
+ * @param l the length of data in @a b
+ * @return ssize_t type value
+ */
+#define MHD_send_(s,b,l) \
+ ((ssize_t)send((s),(const void*)(b),((MHD_SCKT_SEND_SIZE_)l), MAYBE_MSG_NOSIGNAL))
+
+
+/**
+ * MHD_recv_ is wrapper for system's recv()
+ * @param s the socket to use
+ * @param b the buffer for data to receive
+ * @param l the length of @a b
+ * @return ssize_t type value
+ */
+#define MHD_recv_(s,b,l) \
+ ((ssize_t)recv((s),(void*)(b),((MHD_SCKT_SEND_SIZE_)l), 0))
+
+
+/**
+ * Check whether FD can be added to fd_set with specified FD_SETSIZE.
+ * @param fd the fd to check
+ * @param pset the pointer to fd_set to check or NULL to check
+ * whether FD can be used with fd_sets.
+ * @param setsize the value of FD_SETSIZE.
+ * @return boolean true if FD can be added to fd_set,
+ * boolean false otherwise.
+ */
+#if defined(MHD_POSIX_SOCKETS)
+# define MHD_SCKT_FD_FITS_FDSET_SETSIZE_(fd,pset,setsize) ((fd) < ((MHD_socket)setsize))
+#elif defined(MHD_WINSOCK_SOCKETS)
+# define MHD_SCKT_FD_FITS_FDSET_SETSIZE_(fd,pset,setsize) ( ((void*)(pset)==(void*)0) || \
+ (((fd_set*)(pset))->fd_count < ((unsigned)setsize)) || \
+ (FD_ISSET((fd),(pset))) )
+#endif
+
+/**
+ * Check whether FD can be added to fd_set with current FD_SETSIZE.
+ * @param fd the fd to check
+ * @param pset the pointer to fd_set to check or NULL to check
+ * whether FD can be used with fd_sets.
+ * @return boolean true if FD can be added to fd_set,
+ * boolean false otherwise.
+ */
+#define MHD_SCKT_FD_FITS_FDSET_(fd,pset) MHD_SCKT_FD_FITS_FDSET_SETSIZE_((fd),(pset),FD_SETSIZE)
+
+/**
+ * Add FD to fd_set with specified FD_SETSIZE.
+ * @param fd the fd to add
+ * @param pset the valid pointer to fd_set.
+ * @param setsize the value of FD_SETSIZE.
+ * @note To work on W32 with value of FD_SETSIZE different from currently defined value,
+ * system definition of FD_SET() is not used.
+ */
+#if defined(MHD_POSIX_SOCKETS)
+# define MHD_SCKT_ADD_FD_TO_FDSET_SETSIZE_(fd,pset,setsize) FD_SET((fd),(pset))
+#elif defined(MHD_WINSOCK_SOCKETS)
+# define MHD_SCKT_ADD_FD_TO_FDSET_SETSIZE_(fd,pset,setsize) \
+ do { \
+ u_int _i_ = 0; \
+ fd_set* const _s_ = (fd_set*)(pset); \
+ while((_i_ < _s_->fd_count) && ((fd) != _s_->fd_array[_i_])) {++_i_;} \
+ if ((_i_ == _s_->fd_count)) {_s_->fd_array[_s_->fd_count++] = (fd);} \
+ } while(0)
+#endif
+
+ /* MHD_SYS_select_ is wrapper macro for system select() function */
+#if !defined(MHD_WINSOCK_SOCKETS)
+# define MHD_SYS_select_(n,r,w,e,t) select((n),(r),(w),(e),(t))
+#else
+# define MHD_SYS_select_(n,r,w,e,t) \
+( ( (((void*)(r) == (void*)0) || ((fd_set*)(r))->fd_count == 0) && \
+ (((void*)(w) == (void*)0) || ((fd_set*)(w))->fd_count == 0) && \
+ (((void*)(e) == (void*)0) || ((fd_set*)(e))->fd_count == 0) ) ? \
+ ( ((void*)(t) == (void*)0) ? 0 : \
+ (Sleep(((struct timeval*)(t))->tv_sec * 1000 + \
+ ((struct timeval*)(t))->tv_usec / 1000), 0) ) : \
+ (select((int)0,(r),(w),(e),(t))) )
+#endif
+
+#if defined(HAVE_POLL)
+/* MHD_sys_poll_ is wrapper macro for system poll() function */
+# if !defined(MHD_WINSOCK_SOCKETS)
+# define MHD_sys_poll_ poll
+# else /* MHD_WINSOCK_SOCKETS */
+# define MHD_sys_poll_ WSAPoll
+# endif /* MHD_WINSOCK_SOCKETS */
+
+# ifdef POLLPRI
+# define MHD_POLLPRI_OR_ZERO POLLPRI
+# else /* ! POLLPRI */
+# define MHD_POLLPRI_OR_ZERO 0
+# endif /* ! POLLPRI */
+# ifdef POLLRDBAND
+# define MHD_POLLRDBAND_OR_ZERO POLLRDBAND
+# else /* ! POLLRDBAND */
+# define MHD_POLLRDBAND_OR_ZERO 0
+# endif /* ! POLLRDBAND */
+# ifdef POLLNVAL
+# define MHD_POLLNVAL_OR_ZERO POLLNVAL
+# else /* ! POLLNVAL */
+# define MHD_POLLNVAL_OR_ZERO 0
+# endif /* ! POLLNVAL */
+
+/* MHD_POLL_EVENTS_ERR_DISC is 'events' mask for errors and disconnect.
+ * Note: Out-of-band data is treated as error. */
+# if defined(_WIN32) && ! defined(__CYGWIN__)
+# define MHD_POLL_EVENTS_ERR_DISC POLLRDBAND
+# elif defined(__linux__)
+# define MHD_POLL_EVENTS_ERR_DISC POLLPRI
+# else /* ! __linux__ */
+# define MHD_POLL_EVENTS_ERR_DISC (MHD_POLLPRI_OR_ZERO | MHD_POLLRDBAND_OR_ZERO)
+# endif /* ! __linux__ */
+/* MHD_POLL_REVENTS_ERR_DISC is 'revents' mask for errors and disconnect.
+ * Note: Out-of-band data is treated as error. */
+# define MHD_POLL_REVENTS_ERR_DISC \
+ (MHD_POLLPRI_OR_ZERO | MHD_POLLRDBAND_OR_ZERO | MHD_POLLNVAL_OR_ZERO | POLLERR | POLLHUP)
+/* MHD_POLL_REVENTS_ERRROR is 'revents' mask for errors.
+ * Note: Out-of-band data is treated as error. */
+# define MHD_POLL_REVENTS_ERRROR \
+ (MHD_POLLPRI_OR_ZERO | MHD_POLLRDBAND_OR_ZERO | MHD_POLLNVAL_OR_ZERO | POLLERR)
+#endif /* HAVE_POLL */
+
+#define MHD_SCKT_MISSING_ERR_CODE_ 31450
+
+#if defined(MHD_POSIX_SOCKETS)
+# if defined(EAGAIN)
+# define MHD_SCKT_EAGAIN_ EAGAIN
+# elif defined(EWOULDBLOCK)
+# define MHD_SCKT_EAGAIN_ EWOULDBLOCK
+# else /* !EAGAIN && !EWOULDBLOCK */
+# define MHD_SCKT_EAGAIN_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* !EAGAIN && !EWOULDBLOCK */
+# if defined(EWOULDBLOCK)
+# define MHD_SCKT_EWOULDBLOCK_ EWOULDBLOCK
+# elif defined(EAGAIN)
+# define MHD_SCKT_EWOULDBLOCK_ EAGAIN
+# else /* !EWOULDBLOCK && !EAGAIN */
+# define MHD_SCKT_EWOULDBLOCK_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* !EWOULDBLOCK && !EAGAIN */
+# ifdef EINTR
+# define MHD_SCKT_EINTR_ EINTR
+# else /* ! EINTR */
+# define MHD_SCKT_EINTR_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* ! EINTR */
+# ifdef ECONNRESET
+# define MHD_SCKT_ECONNRESET_ ECONNRESET
+# else /* ! ECONNRESET */
+# define MHD_SCKT_ECONNRESET_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* ! ECONNRESET */
+# ifdef ECONNABORTED
+# define MHD_SCKT_ECONNABORTED_ ECONNABORTED
+# else /* ! ECONNABORTED */
+# define MHD_SCKT_ECONNABORTED_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* ! ECONNABORTED */
+# ifdef ENOTCONN
+# define MHD_SCKT_ENOTCONN_ ENOTCONN
+# else /* ! ENOTCONN */
+# define MHD_SCKT_ENOTCONN_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* ! ENOTCONN */
+# ifdef EMFILE
+# define MHD_SCKT_EMFILE_ EMFILE
+# else /* ! EMFILE */
+# define MHD_SCKT_EMFILE_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* ! EMFILE */
+# ifdef ENFILE
+# define MHD_SCKT_ENFILE_ ENFILE
+# else /* ! ENFILE */
+# define MHD_SCKT_ENFILE_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* ! ENFILE */
+# ifdef ENOMEM
+# define MHD_SCKT_ENOMEM_ ENOMEM
+# else /* ! ENOMEM */
+# define MHD_SCKT_ENOMEM_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* ! ENOMEM */
+# ifdef ENOBUFS
+# define MHD_SCKT_ENOBUFS_ ENOBUFS
+# else /* ! ENOBUFS */
+# define MHD_SCKT_ENOBUFS_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* ! ENOBUFS */
+# ifdef EBADF
+# define MHD_SCKT_EBADF_ EBADF
+# else /* ! EBADF */
+# define MHD_SCKT_EBADF_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* ! EBADF */
+# ifdef ENOTSOCK
+# define MHD_SCKT_ENOTSOCK_ ENOTSOCK
+# else /* ! ENOTSOCK */
+# define MHD_SCKT_ENOTSOCK_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* ! ENOTSOCK */
+# ifdef EINVAL
+# define MHD_SCKT_EINVAL_ EINVAL
+# else /* ! EINVAL */
+# define MHD_SCKT_EINVAL_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* ! EINVAL */
+# ifdef EFAULT
+# define MHD_SCKT_EFAUL_ EFAULT
+# else /* ! EFAULT */
+# define MHD_SCKT_EFAUL_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* ! EFAULT */
+# ifdef ENOSYS
+# define MHD_SCKT_ENOSYS_ ENOSYS
+# else /* ! ENOSYS */
+# define MHD_SCKT_ENOSYS_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* ! ENOSYS */
+# ifdef ENOTSUP
+# define MHD_SCKT_ENOTSUP_ ENOTSUP
+# else /* ! ENOTSUP */
+# define MHD_SCKT_ENOTSUP_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* ! ENOTSUP */
+# ifdef EOPNOTSUPP
+# define MHD_SCKT_EOPNOTSUPP_ EOPNOTSUPP
+# else /* ! EOPNOTSUPP */
+# define MHD_SCKT_EOPNOTSUPP_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* ! EOPNOTSUPP */
+# ifdef EACCES
+# define MHD_SCKT_EACCESS_ EACCES
+# else /* ! EACCES */
+# define MHD_SCKT_EACCESS_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* ! EACCES */
+# ifdef ENETDOWN
+# define MHD_SCKT_ENETDOWN_ ENETDOWN
+# else /* ! ENETDOWN */
+# define MHD_SCKT_ENETDOWN_ MHD_SCKT_MISSING_ERR_CODE_
+# endif /* ! ENETDOWN */
+#elif defined(MHD_WINSOCK_SOCKETS)
+# define MHD_SCKT_EAGAIN_ WSAEWOULDBLOCK
+# define MHD_SCKT_EWOULDBLOCK_ WSAEWOULDBLOCK
+# define MHD_SCKT_EINTR_ WSAEINTR
+# define MHD_SCKT_ECONNRESET_ WSAECONNRESET
+# define MHD_SCKT_ECONNABORTED_ WSAECONNABORTED
+# define MHD_SCKT_ENOTCONN_ WSAENOTCONN
+# define MHD_SCKT_EMFILE_ WSAEMFILE
+# define MHD_SCKT_ENFILE_ MHD_SCKT_MISSING_ERR_CODE_
+# define MHD_SCKT_ENOMEM_ MHD_SCKT_MISSING_ERR_CODE_
+# define MHD_SCKT_ENOBUFS_ WSAENOBUFS
+# define MHD_SCKT_EBADF_ WSAEBADF
+# define MHD_SCKT_ENOTSOCK_ WSAENOTSOCK
+# define MHD_SCKT_EINVAL_ WSAEINVAL
+# define MHD_SCKT_EFAUL_ WSAEFAULT
+# define MHD_SCKT_ENOSYS_ MHD_SCKT_MISSING_ERR_CODE_
+# define MHD_SCKT_ENOTSUP_ MHD_SCKT_MISSING_ERR_CODE_
+# define MHD_SCKT_EOPNOTSUPP_ WSAEOPNOTSUPP
+# define MHD_SCKT_EACCESS_ WSAEACCES
+# define MHD_SCKT_ENETDOWN_ WSAENETDOWN
+#endif
+
+/**
+ * MHD_socket_error_ return system native error code for last socket error.
+ * @return system error code for last socket error.
+ */
+#if defined(MHD_POSIX_SOCKETS)
+# define MHD_socket_get_error_() (errno)
+#elif defined(MHD_WINSOCK_SOCKETS)
+# define MHD_socket_get_error_() WSAGetLastError()
+#endif
+
+#ifdef MHD_WINSOCK_SOCKETS
+ /* POSIX-W32 sockets compatibility functions */
+
+/**
+ * Return pointer to string description of specified WinSock error
+ * @param err the WinSock error code.
+ * @return pointer to string description of specified WinSock error.
+ */
+ const char* MHD_W32_strerror_winsock_(int err);
+#endif /* MHD_WINSOCK_SOCKETS */
+
+/* MHD_socket_last_strerr_ is description string of specified socket error code */
+#if defined(MHD_POSIX_SOCKETS)
+# define MHD_socket_strerr_(err) strerror((err))
+#elif defined(MHD_WINSOCK_SOCKETS)
+# define MHD_socket_strerr_(err) MHD_W32_strerror_winsock_((err))
+#endif
+
+/* MHD_socket_last_strerr_ is description string of last errno (non-W32) /
+ * description string of last socket error (W32) */
+#define MHD_socket_last_strerr_() MHD_socket_strerr_(MHD_socket_get_error_())
+
+/**
+ * MHD_socket_fset_error_() set socket system native error code.
+ */
+#if defined(MHD_POSIX_SOCKETS)
+# define MHD_socket_fset_error_(err) (errno = (err))
+#elif defined(MHD_WINSOCK_SOCKETS)
+# define MHD_socket_fset_error_(err) (WSASetLastError((err)))
+#endif
+
+/**
+ * MHD_socket_try_set_error_() set socket system native error code if
+ * specified code is defined on system.
+ * @return non-zero if specified @a err code is defined on system
+ * and error was set;
+ * zero if specified @a err code is not defined on system
+ * and error was not set.
+ */
+#define MHD_socket_try_set_error_(err) ( (MHD_SCKT_MISSING_ERR_CODE_ != (err)) ? \
+ (MHD_socket_fset_error_((err)), !0) : 0 )
+
+/**
+ * MHD_socket_set_error_() set socket system native error code to
+ * specified code or replacement code if specified code is not
+ * defined on system.
+ */
+#if defined(MHD_POSIX_SOCKETS)
+# if defined(ENOSYS)
+# define MHD_socket_set_error_(err) ( (MHD_SCKT_MISSING_ERR_CODE_ == (err)) ? \
+ (errno = ENOSYS) : (errno = (err)) )
+# elif defined(EOPNOTSUPP)
+# define MHD_socket_set_error_(err) ( (MHD_SCKT_MISSING_ERR_CODE_ == (err)) ? \
+ (errno = EOPNOTSUPP) : (errno = (err)) )
+# elif defined (EFAULT)
+# define MHD_socket_set_error_(err) ( (MHD_SCKT_MISSING_ERR_CODE_ == (err)) ? \
+ (errno = EFAULT) : (errno = (err)) )
+# elif defined (EINVAL)
+# define MHD_socket_set_error_(err) ( (MHD_SCKT_MISSING_ERR_CODE_ == (err)) ? \
+ (errno = EINVAL) : (errno = (err)) )
+# else /* !EOPNOTSUPP && !EFAULT && !EINVAL */
+# warning No suitable replacement for missing socket error code is found. Edit this file and add replacement code which is defined on system.
+# define MHD_socket_set_error_(err) (errno = (err))
+# endif /* !EOPNOTSUPP && !EFAULT && !EINVAL*/
+#elif defined(MHD_WINSOCK_SOCKETS)
+# define MHD_socket_set_error_(err) ( (MHD_SCKT_MISSING_ERR_CODE_ == (err)) ? \
+ (WSASetLastError((WSAEOPNOTSUPP))) : \
+ (WSASetLastError((err))) )
+#endif
+
+/**
+ * Check whether given socket error is equal to specified system
+ * native MHD_SCKT_E*_ code.
+ * If platform don't have specific error code, result is
+ * always boolean false.
+ * @return boolean true if @a code is real error code and
+ * @a err equals to MHD_SCKT_E*_ @a code;
+ * boolean false otherwise
+ */
+#define MHD_SCKT_ERR_IS_(err,code) ( (MHD_SCKT_MISSING_ERR_CODE_ != (code)) && \
+ ((code) == (err)) )
+
+/**
+ * Check whether last socket error is equal to specified system
+ * native MHD_SCKT_E*_ code.
+ * If platform don't have specific error code, result is
+ * always boolean false.
+ * @return boolean true if @a code is real error code and
+ * last socket error equals to MHD_SCKT_E*_ @a code;
+ * boolean false otherwise
+ */
+#define MHD_SCKT_LAST_ERR_IS_(code) MHD_SCKT_ERR_IS_(MHD_socket_get_error_() ,(code))
+
+/* Specific error code checks */
+
+/**
+ * Check whether given socket error is equal to system's
+ * socket error codes for EINTR.
+ * @return boolean true if @a err is equal to sockets' EINTR code;
+ * boolean false otherwise.
+ */
+#define MHD_SCKT_ERR_IS_EINTR_(err) MHD_SCKT_ERR_IS_((err),MHD_SCKT_EINTR_)
+
+/**
+ * Check whether given socket error is equal to system's
+ * socket error codes for EAGAIN or EWOULDBLOCK.
+ * @return boolean true if @a err is equal to sockets' EAGAIN or EWOULDBLOCK codes;
+ * boolean false otherwise.
+ */
+#if MHD_SCKT_EAGAIN_ == MHD_SCKT_EWOULDBLOCK_
+# define MHD_SCKT_ERR_IS_EAGAIN_(err) MHD_SCKT_ERR_IS_((err),MHD_SCKT_EAGAIN_)
+#else /* MHD_SCKT_EAGAIN_ != MHD_SCKT_EWOULDBLOCK_ */
+# define MHD_SCKT_ERR_IS_EAGAIN_(err) ( MHD_SCKT_ERR_IS_((err),MHD_SCKT_EAGAIN_) || \
+ MHD_SCKT_ERR_IS_((err),MHD_SCKT_EWOULDBLOCK_) )
+#endif /* MHD_SCKT_EAGAIN_ != MHD_SCKT_EWOULDBLOCK_ */
+
+/**
+ * Check whether given socket error is any kind of "low resource" error.
+ * @return boolean true if @a err is any kind of "low resource" error,
+ * boolean false otherwise.
+ */
+#define MHD_SCKT_ERR_IS_LOW_RESOURCES_(err) ( MHD_SCKT_ERR_IS_((err),MHD_SCKT_EMFILE_) || \
+ MHD_SCKT_ERR_IS_((err),MHD_SCKT_ENFILE_) || \
+ MHD_SCKT_ERR_IS_((err),MHD_SCKT_ENOMEM_) || \
+ MHD_SCKT_ERR_IS_((err),MHD_SCKT_ENOBUFS_) )
+
+/**
+ * Check whether is given socket error is type of "incoming connection
+ * was disconnected before 'accept()' is called".
+ * @return boolean true is @a err match described socket error code,
+ * boolean false otherwise.
+ */
+#if defined(MHD_POSIX_SOCKETS)
+# define MHD_SCKT_ERR_IS_DISCNN_BEFORE_ACCEPT_(err) MHD_SCKT_ERR_IS_((err),MHD_SCKT_ECONNABORTED_)
+#elif defined(MHD_WINSOCK_SOCKETS)
+# define MHD_SCKT_ERR_IS_DISCNN_BEFORE_ACCEPT_(err) MHD_SCKT_ERR_IS_((err),MHD_SCKT_ECONNRESET_)
+#endif
+
+/**
+ * Check whether is given socket error is type of "connection was terminated
+ * by remote side".
+ * @return boolean true is @a err match described socket error code,
+ * boolean false otherwise.
+ */
+#define MHD_SCKT_ERR_IS_REMOTE_DISCNN_(err) ( MHD_SCKT_ERR_IS_((err),MHD_SCKT_ECONNRESET_) || \
+ MHD_SCKT_ERR_IS_((err),MHD_SCKT_ECONNABORTED_))
+
+/* Specific error code set */
+
+/**
+ * Set socket's error code to ENOMEM or equivalent if ENOMEM is not
+ * available on platform.
+ */
+#if MHD_SCKT_MISSING_ERR_CODE_ != MHD_SCKT_ENOMEM_
+# define MHD_socket_set_error_to_ENOMEM() MHD_socket_set_error_(MHD_SCKT_ENOMEM_)
+#elif MHD_SCKT_MISSING_ERR_CODE_ != MHD_SCKT_ENOBUFS_
+# define MHD_socket_set_error_to_ENOMEM() MHD_socket_set_error_(MHD_SCKT_ENOBUFS_)
+#else
+# warning No suitable replacement for ENOMEM error codes is found. Edit this file and add replacement code which is defined on system.
+# define MHD_socket_set_error_to_ENOMEM() MHD_socket_set_error_(MHD_SCKT_ENOMEM_)
+#endif
+
+/* Socket functions */
+
+#if defined(AF_LOCAL)
+# define MHD_SCKT_LOCAL AF_LOCAL
+#elif defined(AF_UNIX)
+# define MHD_SCKT_LOCAL AF_UNIX
+#endif /* AF_UNIX */
+
+#if defined(MHD_POSIX_SOCKETS) && defined(MHD_SCKT_LOCAL)
+# define MHD_socket_pair_(fdarr) (!socketpair(MHD_SCKT_LOCAL, SOCK_STREAM, 0, (fdarr)))
+# if defined(HAVE_SOCK_NONBLOCK)
+# define MHD_socket_pair_nblk_(fdarr) (!socketpair(MHD_SCKT_LOCAL, SOCK_STREAM | SOCK_NONBLOCK, 0, (fdarr)))
+# endif /* HAVE_SOCK_NONBLOCK*/
+#elif defined(MHD_WINSOCK_SOCKETS)
+ /**
+ * Create pair of mutually connected TCP/IP sockets on loopback address
+ * @param sockets_pair array to receive resulted sockets
+ * @param non_blk if set to non-zero value, sockets created in non-blocking mode
+ * otherwise sockets will be in blocking mode
+ * @return non-zero if succeeded, zero otherwise
+ */
+ int MHD_W32_socket_pair_(SOCKET sockets_pair[2], int non_blk);
+
+# define MHD_socket_pair_(fdarr) MHD_W32_socket_pair_((fdarr), 0)
+# define MHD_socket_pair_nblk_(fdarr) MHD_W32_socket_pair_((fdarr), 1)
+#endif
+
+/**
+ * Add @a fd to the @a set. If @a fd is
+ * greater than @a max_fd, set @a max_fd to @a fd.
+ *
+ * @param fd file descriptor to add to the @a set
+ * @param set set to modify
+ * @param max_fd maximum value to potentially update
+ * @param fd_setsize value of FD_SETSIZE
+ * @return non-zero if succeeded, zero otherwise
+ */
+int
+MHD_add_to_fd_set_ (MHD_socket fd,
+ fd_set *set,
+ MHD_socket *max_fd,
+ unsigned int fd_setsize);
+
+
+/**
+ * Change socket options to be non-blocking.
+ *
+ * @param sock socket to manipulate
+ * @return non-zero if succeeded, zero otherwise
+ */
+int
+MHD_socket_nonblocking_ (MHD_socket sock);
+
+
+/**
+ * Change socket options to be non-inheritable.
+ *
+ * @param sock socket to manipulate
+ * @return non-zero if succeeded, zero otherwise
+ * @warning Does not set socket error on W32.
+ */
+int
+MHD_socket_noninheritable_ (MHD_socket sock);
+
+
+#if defined(SOL_SOCKET) && defined(SO_NOSIGPIPE)
+ static const int _MHD_socket_int_one = 1;
+/**
+ * Change socket options to no signal on remote disconnect.
+ *
+ * @param sock socket to manipulate
+ * @return non-zero if succeeded, zero otherwise
+ */
+# define MHD_socket_nosignal_(sock) \
+ (!setsockopt((sock),SOL_SOCKET,SO_NOSIGPIPE,&_MHD_socket_int_one,sizeof(_MHD_socket_int_one)))
+#endif /* SOL_SOCKET && SO_NOSIGPIPE */
+
+/**
+ * Create a listen socket, with noninheritable flag if possible.
+ *
+ * @param use_ipv6 if set to non-zero IPv6 is used
+ * @return created socket or MHD_INVALID_SOCKET in case of errors
+ */
+MHD_socket
+MHD_socket_create_listen_ (bool use_ipv6);
+
+#endif /* ! MHD_SOCKETS_H */
diff --git a/src/lib/mhd_str.c b/src/lib/mhd_str.c
@@ -0,0 +1,758 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2015, 2016 Karlson2k (Evgeny Grin)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+/**
+ * @file microhttpd/mhd_str.c
+ * @brief Functions implementations for string manipulating
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#include "mhd_str.h"
+
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif
+
+#include "mhd_limits.h"
+
+#ifdef MHD_FAVOR_SMALL_CODE
+#ifdef _MHD_static_inline
+#undef _MHD_static_inline
+#endif /* _MHD_static_inline */
+/* Do not force inlining and do not use macro functions, use normal static
+ functions instead.
+ This may give more flexibility for size optimizations. */
+#define _MHD_static_inline static
+#ifndef INLINE_FUNC
+#define INLINE_FUNC 1
+#endif /* !INLINE_FUNC */
+#endif /* MHD_FAVOR_SMALL_CODE */
+
+/*
+ * Block of functions/macros that use US-ASCII charset as required by HTTP
+ * standards. Not affected by current locale settings.
+ */
+
+#ifdef INLINE_FUNC
+
+#if 0 /* Disable unused functions. */
+/**
+ * Check whether character is lower case letter in US-ASCII
+ *
+ * @param c character to check
+ * @return non-zero if character is lower case letter, zero otherwise
+ */
+_MHD_static_inline bool
+isasciilower (char c)
+{
+ return (c >= 'a') && (c <= 'z');
+}
+#endif /* Disable unused functions. */
+
+
+/**
+ * Check whether character is upper case letter in US-ASCII
+ *
+ * @param c character to check
+ * @return non-zero if character is upper case letter, zero otherwise
+ */
+_MHD_static_inline bool
+isasciiupper (char c)
+{
+ return (c >= 'A') && (c <= 'Z');
+}
+
+
+#if 0 /* Disable unused functions. */
+/**
+ * Check whether character is letter in US-ASCII
+ *
+ * @param c character to check
+ * @return non-zero if character is letter in US-ASCII, zero otherwise
+ */
+_MHD_static_inline bool
+isasciialpha (char c)
+{
+ return isasciilower (c) || isasciiupper (c);
+}
+#endif /* Disable unused functions. */
+
+
+/**
+ * Check whether character is decimal digit in US-ASCII
+ *
+ * @param c character to check
+ * @return non-zero if character is decimal digit, zero otherwise
+ */
+_MHD_static_inline bool
+isasciidigit (char c)
+{
+ return (c >= '0') && (c <= '9');
+}
+
+#if 0 /* Disable unused functions. */
+/**
+ * Check whether character is hexadecimal digit in US-ASCII
+ *
+ * @param c character to check
+ * @return non-zero if character is decimal digit, zero otherwise
+ */
+_MHD_static_inline bool
+isasciixdigit (char c)
+{
+ return isasciidigit (c) ||
+ ( (c >= 'A') && (c <= 'F') ) ||
+ ( (c >= 'a') && (c <= 'f') );
+}
+
+
+/**
+ * Check whether character is decimal digit or letter in US-ASCII
+ *
+ * @param c character to check
+ * @return non-zero if character is decimal digit or letter, zero otherwise
+ */
+_MHD_static_inline bool
+isasciialnum (char c)
+{
+ return isasciialpha (c) || isasciidigit (c);
+}
+#endif /* Disable unused functions. */
+
+
+/**
+ * Convert US-ASCII character to lower case.
+ * If character is upper case letter in US-ASCII than it's converted to lower
+ * case analog. If character is NOT upper case letter than it's returned
+ * unmodified.
+ *
+ * @param c character to convert
+ * @return converted to lower case character
+ */
+_MHD_static_inline char
+toasciilower (char c)
+{
+ return isasciiupper (c) ? (c - 'A' + 'a') : c;
+}
+
+
+#if 0 /* Disable unused functions. */
+/**
+ * Convert US-ASCII character to upper case.
+ * If character is lower case letter in US-ASCII than it's converted to upper
+ * case analog. If character is NOT lower case letter than it's returned
+ * unmodified.
+ *
+ * @param c character to convert
+ * @return converted to upper case character
+ */
+_MHD_static_inline char
+toasciiupper (char c)
+{
+ return isasciilower (c) ? (c - 'a' + 'A') : c;
+}
+#endif /* Disable unused functions. */
+
+
+#if defined(MHD_FAVOR_SMALL_CODE) /* Used only in MHD_str_to_uvalue_n_() */
+/**
+ * Convert US-ASCII decimal digit to its value.
+ *
+ * @param c character to convert
+ * @return value of decimal digit or -1 if @ c is not decimal digit
+ */
+_MHD_static_inline int
+todigitvalue (char c)
+{
+ if (isasciidigit (c))
+ return (unsigned char)(c - '0');
+
+ return -1;
+}
+#endif /* MHD_FAVOR_SMALL_CODE */
+
+
+/**
+ * Convert US-ASCII hexadecimal digit to its value.
+ *
+ * @param c character to convert
+ * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
+ */
+_MHD_static_inline int
+toxdigitvalue (char c)
+{
+ if (isasciidigit (c))
+ return (unsigned char)(c - '0');
+ if ( (c >= 'A') && (c <= 'F') )
+ return (unsigned char)(c - 'A' + 10);
+ if ( (c >= 'a') && (c <= 'f') )
+ return (unsigned char)(c - 'a' + 10);
+
+ return -1;
+}
+#else /* !INLINE_FUNC */
+
+
+/**
+ * Checks whether character is lower case letter in US-ASCII
+ *
+ * @param c character to check
+ * @return boolean true if character is lower case letter,
+ * boolean false otherwise
+ */
+#define isasciilower(c) (((char)(c)) >= 'a' && ((char)(c)) <= 'z')
+
+
+/**
+ * Checks whether character is upper case letter in US-ASCII
+ *
+ * @param c character to check
+ * @return boolean true if character is upper case letter,
+ * boolean false otherwise
+ */
+#define isasciiupper(c) (((char)(c)) >= 'A' && ((char)(c)) <= 'Z')
+
+
+/**
+ * Checks whether character is letter in US-ASCII
+ *
+ * @param c character to check
+ * @return boolean true if character is letter, boolean false
+ * otherwise
+ */
+#define isasciialpha(c) (isasciilower(c) || isasciiupper(c))
+
+
+/**
+ * Check whether character is decimal digit in US-ASCII
+ *
+ * @param c character to check
+ * @return boolean true if character is decimal digit, boolean false
+ * otherwise
+ */
+#define isasciidigit(c) (((char)(c)) >= '0' && ((char)(c)) <= '9')
+
+
+/**
+ * Check whether character is hexadecimal digit in US-ASCII
+ *
+ * @param c character to check
+ * @return boolean true if character is hexadecimal digit,
+ * boolean false otherwise
+ */
+#define isasciixdigit(c) (isasciidigit((c)) || \
+ (((char)(c)) >= 'A' && ((char)(c)) <= 'F') || \
+ (((char)(c)) >= 'a' && ((char)(c)) <= 'f') )
+
+
+/**
+ * Check whether character is decimal digit or letter in US-ASCII
+ *
+ * @param c character to check
+ * @return boolean true if character is decimal digit or letter,
+ * boolean false otherwise
+ */
+#define isasciialnum(c) (isasciialpha(c) || isasciidigit(c))
+
+
+/**
+ * Convert US-ASCII character to lower case.
+ * If character is upper case letter in US-ASCII than it's converted to lower
+ * case analog. If character is NOT upper case letter than it's returned
+ * unmodified.
+ *
+ * @param c character to convert
+ * @return converted to lower case character
+ */
+#define toasciilower(c) ((isasciiupper(c)) ? (((char)(c)) - 'A' + 'a') : ((char)(c)))
+
+
+/**
+ * Convert US-ASCII character to upper case.
+ * If character is lower case letter in US-ASCII than it's converted to upper
+ * case analog. If character is NOT lower case letter than it's returned
+ * unmodified.
+ *
+ * @param c character to convert
+ * @return converted to upper case character
+ */
+#define toasciiupper(c) ((isasciilower(c)) ? (((char)(c)) - 'a' + 'A') : ((char)(c)))
+
+
+/**
+ * Convert US-ASCII decimal digit to its value.
+ *
+ * @param c character to convert
+ * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
+ */
+#define todigitvalue(c) (isasciidigit(c) ? (int)(((char)(c)) - '0') : (int)(-1))
+
+
+/**
+ * Convert US-ASCII hexadecimal digit to its value.
+ * @param c character to convert
+ * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
+ */
+#define toxdigitvalue(c) ( isasciidigit(c) ? (int)(((char)(c)) - '0') : \
+ ( (((char)(c)) >= 'A' && ((char)(c)) <= 'F') ? \
+ (int)(((unsigned char)(c)) - 'A' + 10) : \
+ ( (((char)(c)) >= 'a' && ((char)(c)) <= 'f') ? \
+ (int)(((unsigned char)(c)) - 'a' + 10) : (int)(-1) )))
+#endif /* !INLINE_FUNC */
+
+
+#ifndef MHD_FAVOR_SMALL_CODE
+/**
+ * Check two string for equality, ignoring case of US-ASCII letters.
+ *
+ * @param str1 first string to compare
+ * @param str2 second string to compare
+ * @return non-zero if two strings are equal, zero otherwise.
+ */
+int
+MHD_str_equal_caseless_ (const char * str1,
+ const char * str2)
+{
+ while (0 != (*str1))
+ {
+ const char c1 = *str1;
+ const char c2 = *str2;
+ if ( (c1 != c2) &&
+ (toasciilower (c1) != toasciilower (c2)) )
+ return 0;
+ str1++;
+ str2++;
+ }
+ return 0 == (*str2);
+}
+#endif /* ! MHD_FAVOR_SMALL_CODE */
+
+
+/**
+ * Check two string for equality, ignoring case of US-ASCII letters and
+ * checking not more than @a maxlen characters.
+ * Compares up to first terminating null character, but not more than
+ * first @a maxlen characters.
+ *
+ * @param str1 first string to compare
+ * @param str2 second string to compare
+ * @param maxlen maximum number of characters to compare
+ * @return non-zero if two strings are equal, zero otherwise.
+ */
+int
+MHD_str_equal_caseless_n_ (const char * const str1,
+ const char * const str2,
+ size_t maxlen)
+{
+ size_t i;
+
+ for (i = 0; i < maxlen; ++i)
+ {
+ const char c1 = str1[i];
+ const char c2 = str2[i];
+ if (0 == c2)
+ return 0 == c1;
+ if ( (c1 != c2) &&
+ (toasciilower (c1) != toasciilower (c2)) )
+ return 0;
+ }
+ return !0;
+}
+
+
+/**
+ * Check whether @a str has case-insensitive @a token.
+ * Token could be surrounded by spaces and tabs and delimited by comma.
+ * Match succeed if substring between start, end (of string) or comma
+ * contains only case-insensitive token and optional spaces and tabs.
+ * @warning token must not contain null-charters except optional
+ * terminating null-character.
+ * @param str the string to check
+ * @param token the token to find
+ * @param token_len length of token, not including optional terminating
+ * null-character.
+ * @return non-zero if two strings are equal, zero otherwise.
+ */
+bool
+MHD_str_has_token_caseless_ (const char * str,
+ const char * const token,
+ size_t token_len)
+{
+ if (0 == token_len)
+ return false;
+
+ while (0 != *str)
+ {
+ size_t i;
+ /* Skip all whitespaces and empty tokens. */
+ while (' ' == *str || '\t' == *str || ',' == *str) str++;
+
+ /* Check for token match. */
+ i = 0;
+ while (1)
+ {
+ const char sc = *(str++);
+ const char tc = token[i++];
+
+ if (0 == sc)
+ return false;
+ if ( (sc != tc) &&
+ (toasciilower (sc) != toasciilower (tc)) )
+ break;
+ if (i >= token_len)
+ {
+ /* Check whether substring match token fully or
+ * has additional unmatched chars at tail. */
+ while (' ' == *str || '\t' == *str) str++;
+ /* End of (sub)string? */
+ if (0 == *str || ',' == *str)
+ return true;
+ /* Unmatched chars at end of substring. */
+ break;
+ }
+ }
+ /* Find next substring. */
+ while (0 != *str && ',' != *str) str++;
+ }
+ return false;
+}
+
+#ifndef MHD_FAVOR_SMALL_CODE
+/* Use individual function for each case */
+
+/**
+ * Convert decimal US-ASCII digits in string to number in uint64_t.
+ * Conversion stopped at first non-digit character.
+ *
+ * @param str string to convert
+ * @param[out] out_val pointer to uint64_t to store result of conversion
+ * @return non-zero number of characters processed on succeed,
+ * zero if no digit is found, resulting value is larger
+ * then possible to store in uint64_t or @a out_val is NULL
+ */
+size_t
+MHD_str_to_uint64_ (const char *str,
+ uint64_t *out_val)
+{
+ const char * const start = str;
+ uint64_t res;
+
+ if (!str || !out_val || !isasciidigit(str[0]))
+ return 0;
+
+ res = 0;
+ do
+ {
+ const int digit = (unsigned char)(*str) - '0';
+ if ( (res > (UINT64_MAX / 10)) ||
+ ( (res == (UINT64_MAX / 10)) &&
+ ((uint64_t)digit > (UINT64_MAX % 10)) ) )
+ return 0;
+
+ res *= 10;
+ res += digit;
+ str++;
+ } while (isasciidigit (*str));
+
+ *out_val = res;
+ return str - start;
+}
+
+
+/**
+ * Convert not more then @a maxlen decimal US-ASCII digits in string to
+ * number in uint64_t.
+ * Conversion stopped at first non-digit character or after @a maxlen
+ * digits.
+ *
+ * @param str string to convert
+ * @param maxlen maximum number of characters to process
+ * @param[out] out_val pointer to uint64_t to store result of conversion
+ * @return non-zero number of characters processed on succeed,
+ * zero if no digit is found, resulting value is larger
+ * then possible to store in uint64_t or @a out_val is NULL
+ */
+size_t
+MHD_str_to_uint64_n_ (const char * str,
+ size_t maxlen,
+ uint64_t *out_val)
+{
+ uint64_t res;
+ size_t i;
+
+ if (!str || !maxlen || !out_val || !isasciidigit (str[0]))
+ return 0;
+
+ res = 0;
+ i = 0;
+ do
+ {
+ const int digit = (unsigned char)str[i] - '0';
+
+ if ( (res > (UINT64_MAX / 10)) ||
+ ( (res == (UINT64_MAX / 10)) &&
+ ((uint64_t)digit > (UINT64_MAX % 10)) ) )
+ return 0;
+
+ res *= 10;
+ res += digit;
+ i++;
+ } while ( (i < maxlen) &&
+ isasciidigit (str[i]) );
+
+ *out_val= res;
+ return i;
+}
+
+
+/**
+ * Convert hexadecimal US-ASCII digits in string to number in uint32_t.
+ * Conversion stopped at first non-digit character.
+ *
+ * @param str string to convert
+ * @param[out] out_val pointer to uint32_t to store result of conversion
+ * @return non-zero number of characters processed on succeed,
+ * zero if no digit is found, resulting value is larger
+ * then possible to store in uint32_t or @a out_val is NULL
+ */
+size_t
+MHD_strx_to_uint32_ (const char * str,
+ uint32_t *out_val)
+{
+ const char * const start = str;
+ uint32_t res;
+ int digit;
+
+ if (!str || !out_val)
+ return 0;
+
+ res = 0;
+ digit = toxdigitvalue (*str);
+ while (digit >= 0)
+ {
+ if ( (res < (UINT32_MAX / 16)) ||
+ (res == (UINT32_MAX / 16) && (uint32_t)digit <= (UINT32_MAX % 16)) )
+ {
+ res *= 16;
+ res += digit;
+ }
+ else
+ return 0;
+ str++;
+ digit = toxdigitvalue (*str);
+ }
+
+ if (str - start > 0)
+ *out_val = res;
+ return str - start;
+}
+
+
+/**
+ * Convert not more then @a maxlen hexadecimal US-ASCII digits in string
+ * to number in uint32_t.
+ * Conversion stopped at first non-digit character or after @a maxlen
+ * digits.
+ *
+ * @param str string to convert
+ * @param maxlen maximum number of characters to process
+ * @param[out] out_val pointer to uint32_t to store result of conversion
+ * @return non-zero number of characters processed on succeed,
+ * zero if no digit is found, resulting value is larger
+ * then possible to store in uint32_t or @a out_val is NULL
+ */
+size_t
+MHD_strx_to_uint32_n_ (const char *str,
+ size_t maxlen,
+ uint32_t *out_val)
+{
+ size_t i;
+ uint32_t res;
+ int digit;
+ if (!str || !out_val)
+ return 0;
+
+ res = 0;
+ i = 0;
+ while (i < maxlen && (digit = toxdigitvalue (str[i])) >= 0)
+ {
+ if ( (res > (UINT32_MAX / 16)) ||
+ (res == (UINT32_MAX / 16) && (uint32_t)digit > (UINT32_MAX % 16)) )
+ return 0;
+
+ res *= 16;
+ res += digit;
+ i++;
+ }
+
+ if (i)
+ *out_val = res;
+ return i;
+}
+
+
+/**
+ * Convert hexadecimal US-ASCII digits in string to number in uint64_t.
+ * Conversion stopped at first non-digit character.
+ *
+ * @param str string to convert
+ * @param[out] out_val pointer to uint64_t to store result of conversion
+ * @return non-zero number of characters processed on succeed,
+ * zero if no digit is found, resulting value is larger
+ * then possible to store in uint64_t or @a out_val is NULL
+ */
+size_t
+MHD_strx_to_uint64_ (const char *str,
+ uint64_t *out_val)
+{
+ const char * const start = str;
+ uint64_t res;
+ int digit;
+ if (!str || !out_val)
+ return 0;
+
+ res = 0;
+ digit = toxdigitvalue (*str);
+ while (digit >= 0)
+ {
+ if ( (res < (UINT64_MAX / 16)) ||
+ (res == (UINT64_MAX / 16) && (uint64_t)digit <= (UINT64_MAX % 16)) )
+ {
+ res *= 16;
+ res += digit;
+ }
+ else
+ return 0;
+ str++;
+ digit = toxdigitvalue (*str);
+ }
+
+ if (str - start > 0)
+ *out_val = res;
+ return str - start;
+}
+
+
+/**
+ * Convert not more then @a maxlen hexadecimal US-ASCII digits in string
+ * to number in uint64_t.
+ * Conversion stopped at first non-digit character or after @a maxlen
+ * digits.
+ *
+ * @param str string to convert
+ * @param maxlen maximum number of characters to process
+ * @param[out] out_val pointer to uint64_t to store result of conversion
+ * @return non-zero number of characters processed on succeed,
+ * zero if no digit is found, resulting value is larger
+ * then possible to store in uint64_t or @a out_val is NULL
+ */
+size_t
+MHD_strx_to_uint64_n_ (const char * str,
+ size_t maxlen,
+ uint64_t *out_val)
+{
+ size_t i;
+ uint64_t res;
+ int digit;
+ if (!str || !out_val)
+ return 0;
+
+ res = 0;
+ i = 0;
+ while (i < maxlen && (digit = toxdigitvalue (str[i])) >= 0)
+ {
+ if ( (res > (UINT64_MAX / 16)) ||
+ (res == (UINT64_MAX / 16) && (uint64_t)digit > (UINT64_MAX % 16)) )
+ return 0;
+
+ res *= 16;
+ res += digit;
+ i++;
+ }
+
+ if (i)
+ *out_val = res;
+ return i;
+}
+
+#else /* MHD_FAVOR_SMALL_CODE */
+
+/**
+ * Generic function for converting not more then @a maxlen
+ * hexadecimal or decimal US-ASCII digits in string to number.
+ * Conversion stopped at first non-digit character or after @a maxlen
+ * digits.
+ * To be used only within macro.
+ *
+ * @param str the string to convert
+ * @param maxlen the maximum number of characters to process
+ * @param out_val the pointer to variable to store result of conversion
+ * @param val_size the size of variable pointed by @a out_val, in bytes, 4 or 8
+ * @param max_val the maximum decoded number
+ * @param base the numeric base, 10 or 16
+ * @return non-zero number of characters processed on succeed,
+ * zero if no digit is found, resulting value is larger
+ * then @max_val, @val_size is not 16/32 or @a out_val is NULL
+ */
+size_t
+MHD_str_to_uvalue_n_ (const char *str,
+ size_t maxlen,
+ void * out_val,
+ size_t val_size,
+ uint64_t max_val,
+ int base)
+{
+ size_t i;
+ uint64_t res;
+ int digit;
+ const uint64_t max_v_div_b = max_val / base;
+ const uint64_t max_v_mod_b = max_val % base;
+ /* 'digit->value' must be function, not macro */
+ int (*const dfunc)(char) = (base == 16) ?
+ toxdigitvalue : todigitvalue;
+
+ if ( !str || !out_val ||
+ (base != 16 && base != 10) )
+ return 0;
+
+ res = 0;
+ i = 0;
+ while (maxlen > i && 0 <= (digit = dfunc (str[i])))
+ {
+ if ( ((max_v_div_b) < res) ||
+ ((max_v_div_b) == res && (max_v_mod_b) < (uint64_t)digit) )
+ return 0;
+
+ res *= base;
+ res += digit;
+ i++;
+ }
+
+ if (i)
+ {
+ if (8 == val_size)
+ *(uint64_t*)out_val = res;
+ else if (4 == val_size)
+ *(uint32_t*)out_val = (uint32_t)res;
+ else
+ return 0;
+ }
+ return i;
+}
+#endif /* MHD_FAVOR_SMALL_CODE */
diff --git a/src/lib/mhd_str.h b/src/lib/mhd_str.h
@@ -0,0 +1,266 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2015, 2016 Karlson2k (Evgeny Grin)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+/**
+ * @file microhttpd/mhd_str.h
+ * @brief Header for string manipulating helpers
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_STR_H
+#define MHD_STR_H 1
+
+#include "mhd_options.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif /* HAVE_STDBOOL_H */
+
+#ifdef MHD_FAVOR_SMALL_CODE
+#include "mhd_limits.h"
+#endif /* MHD_FAVOR_SMALL_CODE */
+
+#ifndef MHD_STATICSTR_LEN_
+/**
+ * Determine length of static string / macro strings at compile time.
+ */
+#define MHD_STATICSTR_LEN_(macro) (sizeof(macro)/sizeof(char) - 1)
+#endif /* ! MHD_STATICSTR_LEN_ */
+
+/*
+ * Block of functions/macros that use US-ASCII charset as required by HTTP
+ * standards. Not affected by current locale settings.
+ */
+
+#ifndef MHD_FAVOR_SMALL_CODE
+/**
+ * Check two string for equality, ignoring case of US-ASCII letters.
+ * @param str1 first string to compare
+ * @param str2 second string to compare
+ * @return non-zero if two strings are equal, zero otherwise.
+ */
+int
+MHD_str_equal_caseless_ (const char * str1,
+ const char * str2);
+#else /* MHD_FAVOR_SMALL_CODE */
+/* Reuse MHD_str_equal_caseless_n_() to reduce size */
+#define MHD_str_equal_caseless_(s1,s2) MHD_str_equal_caseless_n_((s1),(s2), SIZE_MAX)
+#endif /* MHD_FAVOR_SMALL_CODE */
+
+
+/**
+ * Check two string for equality, ignoring case of US-ASCII letters and
+ * checking not more than @a maxlen characters.
+ * Compares up to first terminating null character, but not more than
+ * first @a maxlen characters.
+ * @param str1 first string to compare
+ * @param str2 second string to compare
+ * @param maxlen maximum number of characters to compare
+ * @return non-zero if two strings are equal, zero otherwise.
+ */
+int
+MHD_str_equal_caseless_n_ (const char * const str1,
+ const char * const str2,
+ size_t maxlen);
+
+
+/**
+ * Check whether @a str has case-insensitive @a token.
+ * Token could be surrounded by spaces and tabs and delimited by comma.
+ * Match succeed if substring between start, end of string or comma
+ * contains only case-insensitive token and optional spaces and tabs.
+ * @warning token must not contain null-charters except optional
+ * terminating null-character.
+ * @param str the string to check
+ * @param token the token to find
+ * @param token_len length of token, not including optional terminating
+ * null-character.
+ * @return non-zero if two strings are equal, zero otherwise.
+ */
+bool
+MHD_str_has_token_caseless_ (const char * str,
+ const char * const token,
+ size_t token_len);
+
+/**
+ * Check whether @a str has case-insensitive static @a tkn.
+ * Token could be surrounded by spaces and tabs and delimited by comma.
+ * Match succeed if substring between start, end of string or comma
+ * contains only case-insensitive token and optional spaces and tabs.
+ * @warning tkn must be static string
+ * @param str the string to check
+ * @param tkn the static string of token to find
+ * @return non-zero if two strings are equal, zero otherwise.
+ */
+#define MHD_str_has_s_token_caseless_(str,tkn) \
+ MHD_str_has_token_caseless_((str),(tkn),MHD_STATICSTR_LEN_(tkn))
+
+#ifndef MHD_FAVOR_SMALL_CODE
+/* Use individual function for each case to improve speed */
+
+/**
+ * Convert decimal US-ASCII digits in string to number in uint64_t.
+ * Conversion stopped at first non-digit character.
+ * @param str string to convert
+ * @param out_val pointer to uint64_t to store result of conversion
+ * @return non-zero number of characters processed on succeed,
+ * zero if no digit is found, resulting value is larger
+ * then possible to store in uint64_t or @a out_val is NULL
+ */
+size_t
+MHD_str_to_uint64_ (const char * str,
+ uint64_t * out_val);
+
+/**
+ * Convert not more then @a maxlen decimal US-ASCII digits in string to
+ * number in uint64_t.
+ * Conversion stopped at first non-digit character or after @a maxlen
+ * digits.
+ * @param str string to convert
+ * @param maxlen maximum number of characters to process
+ * @param out_val pointer to uint64_t to store result of conversion
+ * @return non-zero number of characters processed on succeed,
+ * zero if no digit is found, resulting value is larger
+ * then possible to store in uint64_t or @a out_val is NULL
+ */
+size_t
+MHD_str_to_uint64_n_ (const char * str,
+ size_t maxlen,
+ uint64_t * out_val);
+
+
+/**
+ * Convert hexadecimal US-ASCII digits in string to number in uint32_t.
+ * Conversion stopped at first non-digit character.
+ * @param str string to convert
+ * @param out_val pointer to uint32_t to store result of conversion
+ * @return non-zero number of characters processed on succeed,
+ * zero if no digit is found, resulting value is larger
+ * then possible to store in uint32_t or @a out_val is NULL
+ */
+size_t
+MHD_strx_to_uint32_ (const char * str,
+ uint32_t * out_val);
+
+
+/**
+ * Convert not more then @a maxlen hexadecimal US-ASCII digits in string
+ * to number in uint32_t.
+ * Conversion stopped at first non-digit character or after @a maxlen
+ * digits.
+ * @param str string to convert
+ * @param maxlen maximum number of characters to process
+ * @param out_val pointer to uint32_t to store result of conversion
+ * @return non-zero number of characters processed on succeed,
+ * zero if no digit is found, resulting value is larger
+ * then possible to store in uint32_t or @a out_val is NULL
+ */
+size_t
+MHD_strx_to_uint32_n_ (const char * str,
+ size_t maxlen,
+ uint32_t * out_val);
+
+
+/**
+ * Convert hexadecimal US-ASCII digits in string to number in uint64_t.
+ * Conversion stopped at first non-digit character.
+ * @param str string to convert
+ * @param out_val pointer to uint64_t to store result of conversion
+ * @return non-zero number of characters processed on succeed,
+ * zero if no digit is found, resulting value is larger
+ * then possible to store in uint64_t or @a out_val is NULL
+ */
+size_t
+MHD_strx_to_uint64_ (const char * str,
+ uint64_t * out_val);
+
+
+/**
+ * Convert not more then @a maxlen hexadecimal US-ASCII digits in string
+ * to number in uint64_t.
+ * Conversion stopped at first non-digit character or after @a maxlen
+ * digits.
+ * @param str string to convert
+ * @param maxlen maximum number of characters to process
+ * @param out_val pointer to uint64_t to store result of conversion
+ * @return non-zero number of characters processed on succeed,
+ * zero if no digit is found, resulting value is larger
+ * then possible to store in uint64_t or @a out_val is NULL
+ */
+size_t
+MHD_strx_to_uint64_n_ (const char * str,
+ size_t maxlen,
+ uint64_t * out_val);
+
+#else /* MHD_FAVOR_SMALL_CODE */
+/* Use one universal function and macros to reduce size */
+
+/**
+ * Generic function for converting not more then @a maxlen
+ * hexadecimal or decimal US-ASCII digits in string to number.
+ * Conversion stopped at first non-digit character or after @a maxlen
+ * digits.
+ * To be used only within macro.
+ * @param str the string to convert
+ * @param maxlen the maximum number of characters to process
+ * @param out_val the pointer to uint64_t to store result of conversion
+ * @param val_size the size of variable pointed by @a out_val
+ * @param max_val the maximum decoded number
+ * @param base the numeric base, 10 or 16
+ * @return non-zero number of characters processed on succeed,
+ * zero if no digit is found, resulting value is larger
+ * then @ max_val or @a out_val is NULL
+ */
+size_t
+MHD_str_to_uvalue_n_ (const char * str,
+ size_t maxlen,
+ void * out_val,
+ size_t val_size,
+ uint64_t max_val,
+ int base);
+
+#define MHD_str_to_uint64_(s,ov) MHD_str_to_uvalue_n_((s),SIZE_MAX,(ov),\
+ sizeof(uint64_t),UINT64_MAX,10)
+
+#define MHD_str_to_uint64_n_(s,ml,ov) MHD_str_to_uvalue_n_((s),(ml),(ov),\
+ sizeof(uint64_t),UINT64_MAX,10)
+
+#define MHD_strx_to_sizet_(s,ov) MHD_str_to_uvalue_n_((s),SIZE_MAX,(ov),\
+ sizeof(size_t),SIZE_MAX,16)
+
+#define MHD_strx_to_sizet_n_(s,ml,ov) MHD_str_to_uvalue_n_((s),(ml),(ov),\
+ sizeof(size_t),SIZE_MAX,16)
+
+#define MHD_strx_to_uint32_(s,ov) MHD_str_to_uvalue_n_((s),SIZE_MAX,(ov),\
+ sizeof(uint32_t),UINT32_MAX,16)
+
+#define MHD_strx_to_uint32_n_(s,ml,ov) MHD_str_to_uvalue_n_((s),(ml),(ov),\
+ sizeof(uint32_t),UINT32_MAX,16)
+
+#define MHD_strx_to_uint64_(s,ov) MHD_str_to_uvalue_n_((s),SIZE_MAX,(ov),\
+ sizeof(uint64_t),UINT64_MAX,16)
+
+#define MHD_strx_to_uint64_n_(s,ml,ov) MHD_str_to_uvalue_n_((s),(ml),(ov),\
+ sizeof(uint64_t),UINT64_MAX,16)
+
+#endif /* MHD_FAVOR_SMALL_CODE */
+
+#endif /* MHD_STR_H */
diff --git a/src/lib/mhd_threads.c b/src/lib/mhd_threads.c
@@ -0,0 +1,363 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2016 Karlson2k (Evgeny Grin)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+/**
+ * @file microhttpd/mhd_threads.c
+ * @brief Implementation for thread functions
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#include "mhd_threads.h"
+#ifdef MHD_USE_W32_THREADS
+#include "mhd_limits.h"
+#include <process.h>
+#endif
+#ifdef MHD_USE_THREAD_NAME_
+#include <stdlib.h>
+#ifdef HAVE_PTHREAD_NP_H
+#include <pthread_np.h>
+#endif /* HAVE_PTHREAD_NP_H */
+#endif /* MHD_USE_THREAD_NAME_ */
+#include <errno.h>
+
+
+#ifndef MHD_USE_THREAD_NAME_
+
+#define MHD_set_thread_name_(t, n) (void)
+#define MHD_set_cur_thread_name_(n) (void)
+
+#else /* MHD_USE_THREAD_NAME_ */
+
+#if defined(MHD_USE_POSIX_THREADS)
+#if defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD) || defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
+# define MHD_USE_THREAD_ATTR_SETNAME 1
+#endif /* HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD || HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI */
+
+#if defined(HAVE_PTHREAD_SETNAME_NP_GNU) || defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD) \
+ || defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
+
+/**
+ * Set thread name
+ *
+ * @param thread_id ID of thread
+ * @param thread_name name to set
+ * @return non-zero on success, zero otherwise
+ */
+static int
+MHD_set_thread_name_(const MHD_thread_ID_ thread_id,
+ const char *thread_name)
+{
+ if (NULL == thread_name)
+ return 0;
+
+#if defined(HAVE_PTHREAD_SETNAME_NP_GNU)
+ return !pthread_setname_np (thread_id, thread_name);
+#elif defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD)
+ /* FreeBSD and OpenBSD use different name and void return type */
+ pthread_set_name_np (thread_id, thread_name);
+ return !0;
+#elif defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
+ /* NetBSD use 3 arguments: second argument is string in printf-like format,
+ * third argument is single argument for printf;
+ * OSF1 use 3 arguments too, but last one always must be zero (NULL).
+ * MHD doesn't use '%' in thread names, so both form are used in same way.
+ */
+ return !pthread_setname_np (thread_id, thread_name, 0);
+#endif /* HAVE_PTHREAD_SETNAME_NP_NETBSD */
+}
+
+
+#ifndef __QNXNTO__
+/**
+ * Set current thread name
+ * @param n name to set
+ * @return non-zero on success, zero otherwise
+ */
+#define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(pthread_self(),(n))
+#else /* __QNXNTO__ */
+/* Special case for QNX Neutrino - using zero for thread ID sets name faster. */
+#define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(0,(n))
+#endif /* __QNXNTO__ */
+#elif defined(HAVE_PTHREAD_SETNAME_NP_DARWIN)
+
+/**
+ * Set current thread name
+ * @param n name to set
+ * @return non-zero on success, zero otherwise
+ */
+#define MHD_set_cur_thread_name_(n) (!(pthread_setname_np((n))))
+#endif /* HAVE_PTHREAD_SETNAME_NP_DARWIN */
+
+#elif defined(MHD_USE_W32_THREADS)
+#ifndef _MSC_FULL_VER
+/* Thread name available only for VC-compiler */
+#else /* _MSC_FULL_VER */
+/**
+ * Set thread name
+ *
+ * @param thread_id ID of thread, -1 for current thread
+ * @param thread_name name to set
+ * @return non-zero on success, zero otherwise
+ */
+static int
+MHD_set_thread_name_(const MHD_thread_ID_ thread_id,
+ const char *thread_name)
+{
+ static const DWORD VC_SETNAME_EXC = 0x406D1388;
+#pragma pack(push,8)
+ struct thread_info_struct
+ {
+ DWORD type; /* Must be 0x1000. */
+ LPCSTR name; /* Pointer to name (in user address space). */
+ DWORD ID; /* Thread ID (-1 = caller thread). */
+ DWORD flags; /* Reserved for future use, must be zero. */
+ } thread_info;
+#pragma pack(pop)
+
+ if (NULL == thread_name)
+ return 0;
+
+ thread_info.type = 0x1000;
+ thread_info.name = thread_name;
+ thread_info.ID = thread_id;
+ thread_info.flags = 0;
+
+ __try
+ { /* This exception is intercepted by debugger */
+ RaiseException (VC_SETNAME_EXC,
+ 0,
+ sizeof (thread_info) / sizeof(ULONG_PTR),
+ (ULONG_PTR *) &thread_info);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {}
+
+ return !0;
+}
+
+
+/**
+ * Set current thread name
+ * @param n name to set
+ * @return non-zero on success, zero otherwise
+ */
+#define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(-1,(n))
+#endif /* _MSC_FULL_VER */
+#endif /* MHD_USE_W32_THREADS */
+
+#endif /* MHD_USE_THREAD_NAME_ */
+
+
+/**
+ * Create a thread and set the attributes according to our options.
+ *
+ * @param thread handle to initialize
+ * @param stack_size size of stack for new thread, 0 for default
+ * @param start_routine main function of thread
+ * @param arg argument for start_routine
+ * @return non-zero on success; zero otherwise (with errno set)
+ */
+int
+MHD_create_thread_ (MHD_thread_handle_ID_ *thread,
+ size_t stack_size,
+ MHD_THREAD_START_ROUTINE_ start_routine,
+ void *arg)
+{
+#if defined(MHD_USE_POSIX_THREADS)
+ int res;
+
+ if (0 != stack_size)
+ {
+ pthread_attr_t attr;
+ res = pthread_attr_init (&attr);
+ if (0 == res)
+ {
+ res = pthread_attr_setstacksize (&attr,
+ stack_size);
+ if (0 == res)
+ res = pthread_create (&(thread->handle),
+ &attr,
+ start_routine,
+ arg);
+ pthread_attr_destroy (&attr);
+ }
+ }
+ else
+ res = pthread_create (&(thread->handle),
+ NULL,
+ start_routine,
+ arg);
+
+ if (0 != res)
+ errno = res;
+
+ return !res;
+#elif defined(MHD_USE_W32_THREADS)
+#if SIZE_MAX != UINT_MAX
+ if (stack_size > UINT_MAX)
+ {
+ errno = EINVAL;
+ return 0;
+ }
+#endif /* SIZE_MAX != UINT_MAX */
+
+ thread->handle = (MHD_thread_handle_)
+ _beginthreadex (NULL,
+ (unsigned int) stack_size,
+ start_routine,
+ arg,
+ 0,
+ NULL);
+
+ if ((MHD_thread_handle_)-1 == thread->handle)
+ return 0;
+
+ return !0;
+#endif
+}
+
+#ifdef MHD_USE_THREAD_NAME_
+
+#ifndef MHD_USE_THREAD_ATTR_SETNAME
+struct MHD_named_helper_param_
+{
+ /**
+ * Real thread start routine
+ */
+ MHD_THREAD_START_ROUTINE_ start_routine;
+
+ /**
+ * Argument for thread start routine
+ */
+ void *arg;
+
+ /**
+ * Name for thread
+ */
+ const char *name;
+};
+
+
+static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
+named_thread_starter (void *data)
+{
+ struct MHD_named_helper_param_ * const param =
+ (struct MHD_named_helper_param_ *) data;
+ void * arg;
+ MHD_THREAD_START_ROUTINE_ thr_func;
+
+ if (NULL == data)
+ return (MHD_THRD_RTRN_TYPE_)0;
+
+ MHD_set_cur_thread_name_ (param->name);
+
+ arg = param->arg;
+ thr_func = param->start_routine;
+ free(data);
+
+ return thr_func(arg);
+}
+#endif /* ! MHD_USE_THREAD_ATTR_SETNAME */
+
+
+/**
+ * Create a named thread and set the attributes according to our options.
+ *
+ * @param thread handle to initialize
+ * @param thread_name name for new thread
+ * @param stack_size size of stack for new thread, 0 for default
+ * @param start_routine main function of thread
+ * @param arg argument for start_routine
+ * @return non-zero on success; zero otherwise (with errno set)
+ */
+int
+MHD_create_named_thread_ (MHD_thread_handle_ID_ *thread,
+ const char* thread_name,
+ size_t stack_size,
+ MHD_THREAD_START_ROUTINE_ start_routine,
+ void *arg)
+{
+#if defined(MHD_USE_THREAD_ATTR_SETNAME)
+ int res;
+ pthread_attr_t attr;
+
+ res = pthread_attr_init (&attr);
+ if (0 == res)
+ {
+#if defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD)
+ /* NetBSD use 3 arguments: second argument is string in printf-like format,
+ * third argument is single argument for printf;
+ * OSF1 use 3 arguments too, but last one always must be zero (NULL).
+ * MHD doesn't use '%' in thread names, so both form are used in same way.
+ */
+ res = pthread_attr_setname_np (&attr, thread_name, 0);
+#elif defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
+ res = pthread_attr_setname_np (&attr, thread_name);
+#else
+#error No pthread_attr_setname_np() function.
+#endif
+ if (res == 0 && 0 != stack_size)
+ res = pthread_attr_setstacksize (&attr,
+ stack_size);
+ if (0 == res)
+ res = pthread_create (&(thread->handle),
+ &attr,
+ start_routine,
+ arg);
+ pthread_attr_destroy (&attr);
+ }
+ if (0 != res)
+ errno = res;
+
+ return !res;
+#else /* ! MHD_USE_THREAD_ATTR_SETNAME */
+ struct MHD_named_helper_param_ *param;
+
+ if (NULL == thread_name)
+ {
+ errno = EINVAL;
+ return 0;
+ }
+
+ param = malloc (sizeof (struct MHD_named_helper_param_));
+ if (NULL == param)
+ return 0;
+
+ param->start_routine = start_routine;
+ param->arg = arg;
+ param->name = thread_name;
+
+ /* Set thread name in thread itself to avoid problems with
+ * threads which terminated before name is set in other thread.
+ */
+ if (! MHD_create_thread_(thread,
+ stack_size,
+ &named_thread_starter,
+ (void*)param))
+ {
+ free (param);
+ return 0;
+ }
+
+ return !0;
+#endif /* ! MHD_USE_THREAD_ATTR_SETNAME */
+}
+
+#endif /* MHD_USE_THREAD_NAME_ */
diff --git a/src/lib/mhd_threads.h b/src/lib/mhd_threads.h
@@ -0,0 +1,229 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2016 Karlson2k (Evgeny Grin)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+/**
+ * @file microhttpd/mhd_threads.h
+ * @brief Header for platform-independent threads abstraction
+ * @author Karlson2k (Evgeny Grin)
+ *
+ * Provides basic abstraction for threads.
+ * Any functions can be implemented as macro on some platforms
+ * unless explicitly marked otherwise.
+ * Any function argument can be skipped in macro, so avoid
+ * variable modification in function parameters.
+ *
+ * @warning Unlike pthread functions, most of functions return
+ * nonzero on success.
+ */
+
+#ifndef MHD_THREADS_H
+#define MHD_THREADS_H 1
+
+#include "mhd_options.h"
+#ifdef HAVE_STDDEF_H
+# include <stddef.h> /* for size_t */
+#else /* ! HAVE_STDDEF_H */
+# include <stdlib.h> /* for size_t */
+#endif /* ! HAVE_STDDEF_H */
+
+#if defined(MHD_USE_POSIX_THREADS)
+# undef HAVE_CONFIG_H
+# include <pthread.h>
+# define HAVE_CONFIG_H 1
+#elif defined(MHD_USE_W32_THREADS)
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif /* !WIN32_LEAN_AND_MEAN */
+# include <windows.h>
+#else
+# error No threading API is available.
+#endif
+
+#ifndef MHD_NO_THREAD_NAMES
+# if defined(MHD_USE_POSIX_THREADS)
+# if defined(HAVE_PTHREAD_SETNAME_NP_GNU) || defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD) || \
+ defined(HAVE_PTHREAD_SETNAME_NP_DARWIN) || defined(HAVE_PTHREAD_SETNAME_NP_NETBSD) || \
+ defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD) || defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
+# define MHD_USE_THREAD_NAME_
+# endif /* HAVE_PTHREAD_SETNAME_NP */
+# elif defined(MHD_USE_W32_THREADS)
+# ifdef _MSC_FULL_VER
+ /* Thread names only available with VC compiler */
+# define MHD_USE_THREAD_NAME_
+# endif /* _MSC_FULL_VER */
+# endif
+#endif
+
+#if defined(MHD_USE_POSIX_THREADS)
+ typedef pthread_t MHD_thread_handle_;
+#elif defined(MHD_USE_W32_THREADS)
+ typedef HANDLE MHD_thread_handle_;
+#endif
+
+#if defined(MHD_USE_POSIX_THREADS)
+# define MHD_THRD_RTRN_TYPE_ void*
+# define MHD_THRD_CALL_SPEC_
+#elif defined(MHD_USE_W32_THREADS)
+# define MHD_THRD_RTRN_TYPE_ unsigned
+# define MHD_THRD_CALL_SPEC_ __stdcall
+#endif
+
+#if defined(MHD_USE_POSIX_THREADS)
+ typedef pthread_t MHD_thread_ID_;
+#elif defined(MHD_USE_W32_THREADS)
+ typedef DWORD MHD_thread_ID_;
+#endif
+
+/* Depending on implementation, pthread_create() MAY set thread ID into
+ * provided pointer and after it start thread OR start thread and after
+ * if set thread ID. In latter case, to avoid data races, additional
+ * pthread_self() call is required in thread routine. Is some platform
+ * is known for setting thread ID BEFORE starting thread macro
+ * MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD could be defined
+ * to save some resources. */
+#if defined(MHD_USE_POSIX_THREADS)
+# ifdef MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD
+ union _MHD_thread_handle_ID_
+ {
+ MHD_thread_handle_ handle; /**< To be used in other threads */
+ MHD_thread_ID_ ID; /**< To be used in thread itself */
+ };
+ typedef union _MHD_thread_handle_ID_ MHD_thread_handle_ID_;
+# else /* ! MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD */
+ struct _MHD_thread_handle_ID_
+ {
+ MHD_thread_handle_ handle; /**< To be used in other threads */
+ MHD_thread_ID_ ID; /**< To be used in thread itself */
+ };
+ typedef struct _MHD_thread_handle_ID_ MHD_thread_handle_ID_;
+# endif /* ! MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD */
+#elif defined(MHD_USE_W32_THREADS)
+ struct _MHD_thread_handle_ID_
+ {
+ MHD_thread_handle_ handle; /**< To be used in other threads */
+ MHD_thread_ID_ ID; /**< To be used in thread itself */
+ };
+ typedef struct _MHD_thread_handle_ID_ MHD_thread_handle_ID_;
+#endif
+
+#if defined(MHD_USE_POSIX_THREADS)
+/**
+ * Wait until specified thread is ended and free thread handle on success.
+ * @param thread handle to watch
+ * @return nonzero on success, zero otherwise
+ */
+#define MHD_join_thread_(thread) (!pthread_join((thread), NULL))
+#elif defined(MHD_USE_W32_THREADS)
+/**
+ * Wait until specified thread is ended and free thread handle on success.
+ * @param thread handle to watch
+ * @return nonzero on success, zero otherwise
+ */
+#define MHD_join_thread_(thread) (WAIT_OBJECT_0 == WaitForSingleObject((thread), INFINITE) ? (CloseHandle((thread)), !0) : 0)
+#endif
+
+#if defined(MHD_USE_POSIX_THREADS)
+/**
+ * Check whether provided thread ID match current thread.
+ * @param ID thread ID to match
+ * @return nonzero on match, zero otherwise
+ */
+#define MHD_thread_ID_match_current_(ID) (pthread_equal((ID), pthread_self()))
+#elif defined(MHD_USE_W32_THREADS)
+/**
+ * Check whether provided thread ID match current thread.
+ * @param ID thread ID to match
+ * @return nonzero on match, zero otherwise
+ */
+#define MHD_thread_ID_match_current_(ID) (GetCurrentThreadId() == (ID))
+#endif
+
+#if defined(MHD_USE_POSIX_THREADS)
+# ifdef MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD
+/**
+ * Initialise thread ID.
+ * @param thread_handle_ID_ptr pointer to thread handle-ID
+ */
+#define MHD_thread_init_(thread_handle_ID_ptr) (void)0
+# else /* ! MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD */
+/**
+ * Initialise thread ID.
+ * @param thread_handle_ID_ptr pointer to thread handle-ID
+ */
+#define MHD_thread_init_(thread_handle_ID_ptr) ((thread_handle_ID_ptr)->ID=pthread_self())
+# endif /* ! MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD */
+#elif defined(MHD_USE_W32_THREADS)
+/**
+ * Initialise thread ID.
+ * @param thread_handle_ID_ptr pointer to thread handle-ID
+ */
+#define MHD_thread_init_(thread_handle_ID_ptr) ((thread_handle_ID_ptr)->ID=GetCurrentThreadId())
+#endif
+
+/**
+ * Signature of main function for a thread.
+ *
+ * @param cls closure argument for the function
+ * @return termination code from the thread
+ */
+typedef MHD_THRD_RTRN_TYPE_
+(MHD_THRD_CALL_SPEC_ *MHD_THREAD_START_ROUTINE_)(void *cls);
+
+
+/**
+ * Create a thread and set the attributes according to our options.
+ *
+ * If thread is created, thread handle must be freed by MHD_join_thread_().
+ *
+ * @param thread handle to initialize
+ * @param stack_size size of stack for new thread, 0 for default
+ * @param start_routine main function of thread
+ * @param arg argument for start_routine
+ * @return non-zero on success; zero otherwise
+ */
+int
+MHD_create_thread_ (MHD_thread_handle_ID_ *thread,
+ size_t stack_size,
+ MHD_THREAD_START_ROUTINE_ start_routine,
+ void *arg);
+
+#ifndef MHD_USE_THREAD_NAME_
+#define MHD_create_named_thread_(t,n,s,r,a) MHD_create_thread_((t),(s),(r),(a))
+#else /* MHD_USE_THREAD_NAME_ */
+/**
+ * Create a named thread and set the attributes according to our options.
+ *
+ * @param thread handle to initialize
+ * @param thread_name name for new thread
+ * @param stack_size size of stack for new thread, 0 for default
+ * @param start_routine main function of thread
+ * @param arg argument for start_routine
+ * @return non-zero on success; zero otherwise
+ */
+int
+MHD_create_named_thread_ (MHD_thread_handle_ID_ *thread,
+ const char* thread_name,
+ size_t stack_size,
+ MHD_THREAD_START_ROUTINE_ start_routine,
+ void *arg);
+
+#endif /* MHD_USE_THREAD_NAME_ */
+
+#endif /* ! MHD_THREADS_H */
diff --git a/src/lib/sysfdsetsize.c b/src/lib/sysfdsetsize.c
@@ -0,0 +1,80 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2015 Karlson2k (Evgeny Grin)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+/**
+ * @file microhttpd/sysfdsetsize.c
+ * @brief Helper for obtaining FD_SETSIZE system default value
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+
+#include "MHD_config.h"
+
+#ifdef FD_SETSIZE
+/* FD_SETSIZE was defined before system headers. */
+/* To get system value of FD_SETSIZE, undefine FD_SETSIZE
+ here. */
+#undef FD_SETSIZE
+#endif /* FD_SETSIZE */
+
+#include <stdlib.h>
+#if defined(__VXWORKS__) || defined(__vxworks) || defined(OS_VXWORKS)
+#include <sockLib.h>
+#endif /* OS_VXWORKS */
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif /* HAVE_SYS_SELECT_H */
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif /* HAVE_SYS_TIME_H */
+#if HAVE_TIME_H
+#include <time.h>
+#endif /* HAVE_TIME_H */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif /* HAVE_SYS_SOCKET_H */
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif /* !WIN32_LEAN_AND_MEAN */
+#include <winsock2.h>
+#endif /* _WIN32 && !__CYGWIN__ */
+
+#ifndef FD_SETSIZE
+#error FD_SETSIZE must be defined in system headers
+#endif /* !FD_SETSIZE */
+
+#include "sysfdsetsize.h"
+
+/**
+ * Get system default value of FD_SETSIZE
+ * @return system default value of FD_SETSIZE
+ */
+int
+get_system_fdsetsize_value (void)
+{
+ return FD_SETSIZE;
+}
diff --git a/src/lib/sysfdsetsize.h b/src/lib/sysfdsetsize.h
@@ -0,0 +1,36 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2015 Karlson2k (Evgeny Grin)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+/**
+ * @file microhttpd/sysfdsetsize.h
+ * @brief Helper for obtaining FD_SETSIZE system default value
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef SYSFDSETSIZE_H
+#define SYSFDSETSIZE_H 1
+
+/**
+ * Get system default value of FD_SETSIZE
+ * @return system default value of FD_SETSIZE
+ */
+int
+get_system_fdsetsize_value (void);
+
+#endif /* !SYSFDSETSIZE_H */
diff --git a/src/lib/tsearch.c b/src/lib/tsearch.c
@@ -0,0 +1,143 @@
+/*
+ * Tree search generalized from Knuth (6.2.2) Algorithm T just like
+ * the AT&T man page says.
+ *
+ * The node_t structure is for internal use only, lint doesn't grok it.
+ *
+ * Written by reading the System V Interface Definition, not the code.
+ *
+ * Totally public domain.
+ */
+
+#include "tsearch.h"
+#include <stdlib.h>
+
+
+typedef struct node
+{
+ const void *key;
+ struct node *llink;
+ struct node *rlink;
+} node_t;
+
+
+/* $NetBSD: tsearch.c,v 1.5 2005/11/29 03:12:00 christos Exp $ */
+/* find or insert datum into search tree */
+void *
+tsearch (const void *vkey, /* key to be located */
+ void **vrootp, /* address of tree root */
+ int (*compar)(const void *, const void *))
+{
+ node_t *q;
+ node_t **rootp = (node_t **)vrootp;
+
+ if (NULL == rootp)
+ return NULL;
+
+ while (*rootp != NULL)
+ { /* Knuth's T1: */
+ int r;
+
+ if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
+ return *rootp; /* we found it! */
+
+ rootp = (r < 0) ?
+ &(*rootp)->llink : /* T3: follow left branch */
+ &(*rootp)->rlink; /* T4: follow right branch */
+ }
+
+ q = malloc (sizeof(node_t)); /* T5: key not found */
+ if (q)
+ { /* make new node */
+ *rootp = q; /* link new node to old */
+ q->key = vkey; /* initialize new node */
+ q->llink = q->rlink = NULL;
+ }
+ return q;
+}
+
+
+/* $NetBSD: tfind.c,v 1.5 2005/03/23 08:16:53 kleink Exp $ */
+/* find a node, or return NULL */
+void *
+tfind (const void *vkey, /* key to be found */
+ void * const *vrootp, /* address of the tree root */
+ int (*compar)(const void *, const void *))
+{
+ node_t * const *rootp = (node_t * const*)vrootp;
+
+ if (NULL == rootp)
+ return NULL;
+
+ while (*rootp != NULL)
+ { /* T1: */
+ int r;
+
+ if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
+ return *rootp; /* key found */
+ rootp = (r < 0) ?
+ &(*rootp)->llink : /* T3: follow left branch */
+ &(*rootp)->rlink; /* T4: follow right branch */
+ }
+ return NULL;
+}
+
+
+/* $NetBSD: tdelete.c,v 1.2 1999/09/16 11:45:37 lukem Exp $ */
+/*
+ * delete node with given key
+ *
+ * vkey: key to be deleted
+ * vrootp: address of the root of the tree
+ * compar: function to carry out node comparisons
+ */
+void *
+tdelete (const void * __restrict vkey,
+ void ** __restrict vrootp,
+ int (*compar)(const void *, const void *))
+{
+ node_t **rootp = (node_t **)vrootp;
+ node_t *p;
+ node_t *q;
+ node_t *r;
+ int cmp;
+
+ if (rootp == NULL || (p = *rootp) == NULL)
+ return NULL;
+
+ while ((cmp = (*compar)(vkey, (*rootp)->key)) != 0)
+ {
+ p = *rootp;
+ rootp = (cmp < 0) ?
+ &(*rootp)->llink : /* follow llink branch */
+ &(*rootp)->rlink; /* follow rlink branch */
+ if (*rootp == NULL)
+ return NULL; /* key not found */
+ }
+ r = (*rootp)->rlink; /* D1: */
+ if ((q = (*rootp)->llink) == NULL) /* Left NULL? */
+ {
+ q = r;
+ }
+ else if (r != NULL)
+ { /* Right link is NULL? */
+ if (r->llink == NULL)
+ { /* D2: Find successor */
+ r->llink = q;
+ q = r;
+ }
+ else
+ { /* D3: Find NULL link */
+ for (q = r->llink; q->llink != NULL; q = r->llink)
+ r = q;
+ r->llink = q->rlink;
+ q->llink = (*rootp)->llink;
+ q->rlink = (*rootp)->rlink;
+ }
+ }
+ free(*rootp); /* D4: Free node */
+ *rootp = q; /* link parent to new node */
+ return p;
+}
+
+/* end of tsearch.c */
diff --git a/src/lib/tsearch.h b/src/lib/tsearch.h
@@ -0,0 +1,38 @@
+/*-
+ * Written by J.T. Conklin <jtc@netbsd.org>
+ * Public domain.
+ *
+ * $NetBSD: search.h,v 1.12 1999/02/22 10:34:28 christos Exp $
+ * $FreeBSD: release/9.0.0/include/search.h 105250 2002-10-16 14:29:23Z robert $
+ */
+
+#ifndef _TSEARCH_H_
+#define _TSEARCH_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus */
+
+
+void *
+tdelete (const void * __restrict,
+ void ** __restrict,
+ int (*)(const void *, const void *));
+
+
+void *
+tfind (const void *,
+ void * const *,
+ int (*)(const void *, const void *));
+
+
+void *
+tsearch (const void *,
+ void **,
+ int (*)(const void *, const void *));
+
+#if defined(__cplusplus)
+};
+#endif /* __cplusplus */
+
+#endif /* !_TSEARCH_H_ */
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
@@ -5526,7 +5526,17 @@ MHD_start_daemon_va (unsigned int flags,
(0 == (*pflags & MHD_USE_NO_LISTEN_SOCKET)) )
{
/* try to open listen socket */
- listen_fd = MHD_socket_create_listen_(*pflags & MHD_USE_IPv6);
+ int domain;
+
+#ifdef HAVE_INET6
+ domain = (*pflags & MHD_USE_IPv6) ? PF_INET6 : PF_INET;
+#else /* ! HAVE_INET6 */
+ if (*pflags & MHD_USE_IPv6)
+ goto free_and_fail;
+ domain = PF_INET;
+#endif /* ! HAVE_INET6 */
+
+ listen_fd = MHD_socket_create_listen_(domain);
if (MHD_INVALID_SOCKET == listen_fd)
{
#ifdef HAVE_MESSAGES
diff --git a/src/microhttpd/mhd_sockets.c b/src/microhttpd/mhd_sockets.c
@@ -464,31 +464,22 @@ MHD_socket_noninheritable_ (MHD_socket sock)
/**
* Create a listen socket, with noninheritable flag if possible.
*
- * @param use_ipv6 if set to non-zero IPv6 is used
+ * @param pf protocol family to use
* @return created socket or MHD_INVALID_SOCKET in case of errors
*/
MHD_socket
-MHD_socket_create_listen_ (bool use_ipv6)
+MHD_socket_create_listen_ (int pf)
{
- int domain;
MHD_socket fd;
int cloexec_set;
-#ifdef HAVE_INET6
- domain = (use_ipv6) ? PF_INET6 : PF_INET;
-#else /* ! HAVE_INET6 */
- if (use_ipv6)
- return MHD_INVALID_SOCKET;
- domain = PF_INET;
-#endif /* ! HAVE_INET6 */
-
#if defined(MHD_POSIX_SOCKETS) && defined(SOCK_CLOEXEC)
- fd = socket (domain,
+ fd = socket (pf,
SOCK_STREAM | SOCK_CLOEXEC,
0);
cloexec_set = !0;
#elif defined(MHD_WINSOCK_SOCKETS) && defined (WSA_FLAG_NO_HANDLE_INHERIT)
- fd = WSASocketW (domain,
+ fd = WSASocketW (pf,
SOCK_STREAM,
0,
NULL,
@@ -500,7 +491,7 @@ MHD_socket_create_listen_ (bool use_ipv6)
#endif /* !SOCK_CLOEXEC */
if (MHD_INVALID_SOCKET == fd)
{
- fd = socket (domain,
+ fd = socket (pf,
SOCK_STREAM,
0);
cloexec_set = 0;