aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-02-09 06:09:02 +0100
committerChristian Grothoff <christian@grothoff.org>2018-02-09 06:09:02 +0100
commit7512349b3bb7ec147195cf25864f637e1a99c569 (patch)
tree6870c0438764b096bd380f90aa54d54629b6cf3a
parente77fce2749a06b448e496140e8ad7e51891972de (diff)
downloadlibmicrohttpd-7512349b3bb7ec147195cf25864f637e1a99c569.tar.gz
libmicrohttpd-7512349b3bb7ec147195cf25864f637e1a99c569.zip
allow passing pf instead of just v6 flag to listen socket creation
-rw-r--r--m4/ac_define_dir.m435
-rw-r--r--src/lib/Makefile.am167
-rw-r--r--src/lib/base64.c59
-rw-r--r--src/lib/base64.h17
-rw-r--r--src/lib/internal.c281
-rw-r--r--src/lib/md5.c264
-rw-r--r--src/lib/md5.h64
-rw-r--r--src/lib/memorypool.c340
-rw-r--r--src/lib/memorypool.h130
-rw-r--r--src/lib/mhd_assert.h49
-rw-r--r--src/lib/mhd_byteorder.h160
-rw-r--r--src/lib/mhd_compat.c114
-rw-r--r--src/lib/mhd_compat.h87
-rw-r--r--src/lib/mhd_itc.c70
-rw-r--r--src/lib/mhd_itc.h361
-rw-r--r--src/lib/mhd_itc_types.h77
-rw-r--r--src/lib/mhd_limits.h146
-rw-r--r--src/lib/mhd_locks.h183
-rw-r--r--src/lib/mhd_mono_clock.c377
-rw-r--r--src/lib/mhd_mono_clock.h60
-rw-r--r--src/lib/mhd_sockets.c523
-rw-r--r--src/lib/mhd_sockets.h760
-rw-r--r--src/lib/mhd_str.c758
-rw-r--r--src/lib/mhd_str.h266
-rw-r--r--src/lib/mhd_threads.c363
-rw-r--r--src/lib/mhd_threads.h229
-rw-r--r--src/lib/sysfdsetsize.c80
-rw-r--r--src/lib/sysfdsetsize.h36
-rw-r--r--src/lib/tsearch.c143
-rw-r--r--src/lib/tsearch.h38
-rw-r--r--src/microhttpd/daemon.c12
-rw-r--r--src/microhttpd/mhd_sockets.c19
32 files changed, 6253 insertions, 15 deletions
diff --git a/m4/ac_define_dir.m4 b/m4/ac_define_dir.m4
new file mode 100644
index 00000000..f7e028fc
--- /dev/null
+++ b/m4/ac_define_dir.m4
@@ -0,0 +1,35 @@
1dnl @synopsis AC_DEFINE_DIR(VARNAME, DIR [, DESCRIPTION])
2dnl
3dnl This macro _AC_DEFINEs VARNAME to the expansion of the DIR
4dnl variable, taking care of fixing up ${prefix} and such.
5dnl
6dnl VARNAME is offered as both a C preprocessor symbol, and an output
7dnl variable.
8dnl
9dnl Note that the 3 argument form is only supported with autoconf 2.13
10dnl and later (i.e. only where _AC_DEFINE supports 3 arguments).
11dnl
12dnl Examples:
13dnl
14dnl AC_DEFINE_DIR(DATADIR, datadir)
15dnl AC_DEFINE_DIR(PROG_PATH, bindir, [Location of installed binaries])
16dnl
17dnl @category Misc
18dnl @author Stepan Kasal <kasal@ucw.cz>
19dnl @author Andreas Schwab <schwab@suse.de>
20dnl @author Guido Draheim <guidod@gmx.de>
21dnl @author Alexandre Oliva
22dnl @version 2005-01-17
23dnl @license AllPermissive
24
25AC_DEFUN([AC_DEFINE_DIR], [
26 prefix_NONE=
27 exec_prefix_NONE=
28 test "x$prefix" = xNONE && prefix_NONE=yes && prefix=$ac_default_prefix
29 test "x$exec_prefix" = xNONE && exec_prefix_NONE=yes && exec_prefix=$prefix
30 eval ac_define_dir="\"[$]$2\""
31 AC_SUBST($1, "$ac_define_dir")
32 AC_DEFINE_UNQUOTED($1, "$ac_define_dir", [$3])
33 test "$prefix_NONE" && prefix=NONE
34 test "$exec_prefix_NONE" && exec_prefix=NONE
35])
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
new file mode 100644
index 00000000..bba6b620
--- /dev/null
+++ b/src/lib/Makefile.am
@@ -0,0 +1,167 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = \
3 -I$(top_srcdir)/src/include \
4 -I$(top_srcdir)/src/lib
5
6AM_CFLAGS = $(HIDDEN_VISIBILITY_CFLAGS)
7
8lib_LTLIBRARIES = \
9 libmicrohttpd.la
10
11noinst_DATA =
12MOSTLYCLEANFILES =
13
14if W32_SHARED_LIB_EXP
15W32_MHD_LIB_LDFLAGS = -Wl,--output-def,$(lt_cv_objdir)/libmicrohttpd.def -XCClinker -static-libgcc
16noinst_DATA += $(lt_cv_objdir)/libmicrohttpd.lib $(lt_cv_objdir)/libmicrohttpd.def $(lt_cv_objdir)/libmicrohttpd.exp
17MOSTLYCLEANFILES += $(lt_cv_objdir)/libmicrohttpd.lib $(lt_cv_objdir)/libmicrohttpd.def $(lt_cv_objdir)/libmicrohttpd.exp
18
19$(lt_cv_objdir)/libmicrohttpd.def: libmicrohttpd.la
20
21$(lt_cv_objdir)/libmicrohttpd.exp: $(lt_cv_objdir)/libmicrohttpd.lib
22
23$(lt_cv_objdir)/libmicrohttpd.lib: $(lt_cv_objdir)/libmicrohttpd.def libmicrohttpd.la $(libmicrohttpd_la_OBJECTS)
24if USE_MS_LIB_TOOL
25 @echo Creating $@ and libmicrohttpd.exp by $(MS_LIB_TOOL)... && \
26 dll_name=`$(EGREP) -o dlname=\'.+\' libmicrohttpd.la` && \
27 dll_name=$${dll_name#*\'} && dll_name=$${dll_name%\'} && test -n "$$dll_name" && \
28 echo Creating $$dll_name by $(MS_LIB_TOOL).. && cd "$(lt_cv_objdir)" && \
29 $(MS_LIB_TOOL) -def:libmicrohttpd.def -name:$$dll_name -out:libmicrohttpd.lib $(libmicrohttpd_la_OBJECTS:.lo=.o) && cd ..
30else
31 @echo Creating $@ and libmicrohttpd.exp by $(DLLTOOL)... && \
32 dll_name=`$(EGREP) -o dlname=\'.+\' libmicrohttpd.la` && \
33 dll_name=$${dll_name#*\'} && dll_name=$${dll_name%\'} && test -n "$$dll_name" && \
34 echo Creating $$dll_name by $(DLLTOOL).. && cd "$(lt_cv_objdir)" && \
35 $(DLLTOOL) -d ./libmicrohttpd.def -D $$dll_name -l libmicrohttpd.lib $(libmicrohttpd_la_OBJECTS:.lo=.o) -e ./libmicrohttpd.exp && cd .. &&\
36 echo Created libmicrohttpd.exp and libmicrohttpd.lib.
37endif
38else
39 W32_MHD_LIB_LDFLAGS =
40endif
41
42if W32_STATIC_LIB
43noinst_DATA += $(lt_cv_objdir)/libmicrohttpd-static.lib
44MOSTLYCLEANFILES += $(lt_cv_objdir)/libmicrohttpd-static.lib
45
46$(lt_cv_objdir)/libmicrohttpd-static.lib: libmicrohttpd.la $(libmicrohttpd_la_OBJECTS)
47if USE_MS_LIB_TOOL
48 $(MS_LIB_TOOL) -out:$@ $(libmicrohttpd_la_OBJECTS:.lo=.o)
49else
50 cp $(lt_cv_objdir)/libmicrohttpd.a $@
51endif
52endif
53
54
55libmicrohttpd_la_SOURCES = \
56 action_continue.c \
57 action_from_response.c \
58 action_parse_post.c \
59 action_process_upload.c \
60 action_suspend.c \
61 connection_info.c \
62 connection_options.c \
63 daemon_create.c \
64 daemon_destroy.c \
65 daemon_info.c \
66 daemon_options.c \
67 daemon_start.c \
68 daemon_quiesce.c \
69 init.c init.h \
70 internal.c internal.h \
71 memorypool.c memorypool.h \
72 mhd_assert.h \
73 mhd_byteorder.h \
74 mhd_compat.c mhd_compat.h \
75 mhd_itc.c mhd_itc.h mhd_itc_types.h \
76 mhd_limits.h \
77 mhd_locks.h \
78 mhd_mono_clock.c mhd_mono_clock.h \
79 mhd_str.c mhd_str.h \
80 mhd_sockets.c mhd_sockets.h \
81 mhd_threads.c mhd_threads.h \
82 response.c \
83 response_for_upgrade.c \
84 response_from_buffer.c \
85 response_from_callback.c \
86 response_from_fd.c \
87 response_options.c \
88 reason_phrase.c \
89 request.c \
90 request_info.c \
91 request_resume.c \
92 sysfdsetsize.c sysfdsetsize.h \
93 panic.c \
94 version.c
95
96
97
98libmicrohttpd_la_CPPFLAGS = \
99 $(AM_CPPFLAGS) $(MHD_LIB_CPPFLAGS) \
100 -DBUILDING_MHD_LIB=1
101libmicrohttpd_la_CFLAGS = \
102 $(AM_CFLAGS) $(MHD_LIB_CFLAGS)
103libmicrohttpd_la_LDFLAGS = \
104 $(MHD_LIB_LDFLAGS) \
105 $(W32_MHD_LIB_LDFLAGS) \
106 -version-info @LIB_VERSION_CURRENT@:@LIB_VERSION_REVISION@:@LIB_VERSION_AGE@
107libmicrohttpd_la_LIBADD = \
108 $(MHD_LIBDEPS)
109
110if HAVE_W32
111MHD_DLL_RES_SRC = microhttpd_dll_res.rc
112MHD_DLL_RES_LO = libmicrohttpd_la-$(MHD_DLL_RES_SRC:.rc=.lo)
113
114EXTRA_libmicrohttpd_la_DEPENDENCIES = $(MHD_DLL_RES_LO)
115libmicrohttpd_la_LIBADD += $(MHD_DLL_RES_LO)
116
117# General rule is not required, but keep it just in case
118.rc.lo:
119 $(LIBTOOL) $(AM_V_lt) --tag=RC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(RC) $(RCFLAGS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $< -o $@
120
121# To add dll resource only to .dll file and exclude it form static
122# lib, a little trick was used. Allow libtool to create file.lo,
123# file.o and .libs/file.lo, .libs/file.o files, then overwrite file.o
124# by empty object generated from empty c-file. Later libtool will
125# use .libs/file.o for shared lib and empty file.o for static lib.
126# This implementation is based on trick found in liblzma.
127# Note: windres does not understand '-isystem' flag, so all
128# possible '-isystem' flags are replaced by simple '-I' flags.
129$(MHD_DLL_RES_LO): $(MHD_DLL_RES_SRC)
130 RC_CPP_FLAGS=" $(DEFAULT_INCLUDES) $(INCLUDES) $(libmicrohttpd_la_CPPFLAGS) $(CPPFLAGS) " && \
131 $(LIBTOOL) $(AM_V_lt) --tag=RC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(RC) $(RCFLAGS) $(DEFS) $${RC_CPP_FLAGS// -isystem / -I } $< -o $@ && \
132 echo > $@-empty.c && $(CC) $(AM_CFLAGS) $(CFLAGS) -c $@-empty.c -o $(@:.lo=.o) && rm -f $@-empty.c
133endif
134
135if USE_COVERAGE
136 AM_CFLAGS += --coverage
137endif
138
139if !MHD_HAVE_TSEARCH
140libmicrohttpd_la_SOURCES += \
141 tsearch.c tsearch.h
142endif
143
144# TBD!
145if HAVE_POSTPROCESSOR
146libmicrohttpd_la_SOURCES += \
147 postprocessor.c
148endif
149
150# TBD!
151if ENABLE_DAUTH
152libmicrohttpd_la_SOURCES += \
153 digestauth.c \
154 md5.c md5.h
155endif
156
157# TBD!
158if ENABLE_BAUTH
159libmicrohttpd_la_SOURCES += \
160 basicauth.c \
161 base64.c base64.h
162endif
163
164
165
166
167
diff --git a/src/lib/base64.c b/src/lib/base64.c
new file mode 100644
index 00000000..3dc7a142
--- /dev/null
+++ b/src/lib/base64.c
@@ -0,0 +1,59 @@
1/*
2 * This code implements the BASE64 algorithm.
3 * This code is in the public domain; do with it what you wish.
4 *
5 * @file base64.c
6 * @brief This code implements the BASE64 algorithm
7 * @author Matthieu Speder
8 */
9#include "base64.h"
10
11static const char base64_digits[] =
12 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
13 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
14 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
15 0, 0, 0, -1, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
16 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26,
17 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
18 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
19 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
20 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
21 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
22 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
23 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
24
25
26char *
27BASE64Decode(const char* src)
28{
29 size_t in_len = strlen (src);
30 char* dest;
31 char* result;
32
33 if (in_len % 4)
34 {
35 /* Wrong base64 string length */
36 return NULL;
37 }
38 result = dest = malloc(in_len / 4 * 3 + 1);
39 if (NULL == result)
40 return NULL; /* out of memory */
41 while (*src) {
42 char a = base64_digits[(unsigned char)*(src++)];
43 char b = base64_digits[(unsigned char)*(src++)];
44 char c = base64_digits[(unsigned char)*(src++)];
45 char d = base64_digits[(unsigned char)*(src++)];
46 *(dest++) = (a << 2) | ((b & 0x30) >> 4);
47 if (c == (char)-1)
48 break;
49 *(dest++) = ((b & 0x0f) << 4) | ((c & 0x3c) >> 2);
50 if (d == (char)-1)
51 break;
52 *(dest++) = ((c & 0x03) << 6) | d;
53 }
54 *dest = 0;
55 return result;
56}
57
58
59/* end of base64.c */
diff --git a/src/lib/base64.h b/src/lib/base64.h
new file mode 100644
index 00000000..ba96ca0c
--- /dev/null
+++ b/src/lib/base64.h
@@ -0,0 +1,17 @@
1/*
2 * This code implements the BASE64 algorithm.
3 * This code is in the public domain; do with it what you wish.
4 *
5 * @file base64.c
6 * @brief This code implements the BASE64 algorithm
7 * @author Matthieu Speder
8 */
9#ifndef BASE64_H
10#define BASE64_H
11
12#include "platform.h"
13
14char *
15BASE64Decode(const char* src);
16
17#endif /* !BASE64_H */
diff --git a/src/lib/internal.c b/src/lib/internal.c
new file mode 100644
index 00000000..d2532c54
--- /dev/null
+++ b/src/lib/internal.c
@@ -0,0 +1,281 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file microhttpd/internal.c
22 * @brief internal shared structures
23 * @author Daniel Pittman
24 * @author Christian Grothoff
25 */
26
27#include "internal.h"
28#include "mhd_str.h"
29
30#ifdef HAVE_MESSAGES
31#if DEBUG_STATES
32/**
33 * State to string dictionary.
34 */
35const char *
36MHD_state_to_string (enum MHD_CONNECTION_STATE state)
37{
38 switch (state)
39 {
40 case MHD_CONNECTION_INIT:
41 return "connection init";
42 case MHD_CONNECTION_URL_RECEIVED:
43 return "connection url received";
44 case MHD_CONNECTION_HEADER_PART_RECEIVED:
45 return "header partially received";
46 case MHD_CONNECTION_HEADERS_RECEIVED:
47 return "headers received";
48 case MHD_CONNECTION_HEADERS_PROCESSED:
49 return "headers processed";
50 case MHD_CONNECTION_CONTINUE_SENDING:
51 return "continue sending";
52 case MHD_CONNECTION_CONTINUE_SENT:
53 return "continue sent";
54 case MHD_CONNECTION_BODY_RECEIVED:
55 return "body received";
56 case MHD_CONNECTION_FOOTER_PART_RECEIVED:
57 return "footer partially received";
58 case MHD_CONNECTION_FOOTERS_RECEIVED:
59 return "footers received";
60 case MHD_CONNECTION_HEADERS_SENDING:
61 return "headers sending";
62 case MHD_CONNECTION_HEADERS_SENT:
63 return "headers sent";
64 case MHD_CONNECTION_NORMAL_BODY_READY:
65 return "normal body ready";
66 case MHD_CONNECTION_NORMAL_BODY_UNREADY:
67 return "normal body unready";
68 case MHD_CONNECTION_CHUNKED_BODY_READY:
69 return "chunked body ready";
70 case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
71 return "chunked body unready";
72 case MHD_CONNECTION_BODY_SENT:
73 return "body sent";
74 case MHD_CONNECTION_FOOTERS_SENDING:
75 return "footers sending";
76 case MHD_CONNECTION_FOOTERS_SENT:
77 return "footers sent";
78 case MHD_CONNECTION_CLOSED:
79 return "closed";
80 default:
81 return "unrecognized connection state";
82 }
83}
84#endif
85#endif
86
87
88#ifdef HAVE_MESSAGES
89/**
90 * fprintf-like helper function for logging debug
91 * messages.
92 */
93void
94MHD_DLOG (const struct MHD_Daemon *daemon,
95 const char *format,
96 ...)
97{
98 va_list va;
99
100 if (0 == (daemon->options & MHD_USE_ERROR_LOG))
101 return;
102 va_start (va, format);
103 daemon->custom_error_log (daemon->custom_error_log_cls,
104 format,
105 va);
106 va_end (va);
107}
108#endif
109
110
111/**
112 * Convert all occurrences of '+' to ' '.
113 *
114 * @param arg string that is modified (in place), must be 0-terminated
115 */
116void
117MHD_unescape_plus (char *arg)
118{
119 char *p;
120
121 for (p=strchr (arg, '+'); NULL != p; p = strchr (p + 1, '+'))
122 *p = ' ';
123}
124
125
126/**
127 * Process escape sequences ('%HH') Updates val in place; the
128 * result should be UTF-8 encoded and cannot be larger than the input.
129 * The result must also still be 0-terminated.
130 *
131 * @param val value to unescape (modified in the process)
132 * @return length of the resulting val (strlen(val) maybe
133 * shorter afterwards due to elimination of escape sequences)
134 */
135size_t
136MHD_http_unescape (char *val)
137{
138 char *rpos = val;
139 char *wpos = val;
140
141 while ('\0' != *rpos)
142 {
143 uint32_t num;
144 switch (*rpos)
145 {
146 case '%':
147 if (2 == MHD_strx_to_uint32_n_ (rpos + 1,
148 2,
149 &num))
150 {
151 *wpos = (char)((unsigned char) num);
152 wpos++;
153 rpos += 3;
154 break;
155 }
156 /* TODO: add bad sequence handling */
157 /* intentional fall through! */
158 default:
159 *wpos = *rpos;
160 wpos++;
161 rpos++;
162 }
163 }
164 *wpos = '\0'; /* add 0-terminator */
165 return wpos - val; /* = strlen(val) */
166}
167
168
169/**
170 * Parse and unescape the arguments given by the client
171 * as part of the HTTP request URI.
172 *
173 * @param kind header kind to pass to @a cb
174 * @param connection connection to add headers to
175 * @param[in,out] args argument URI string (after "?" in URI),
176 * clobbered in the process!
177 * @param cb function to call on each key-value pair found
178 * @param[out] num_headers set to the number of headers found
179 * @return #MHD_NO on failure (@a cb returned #MHD_NO),
180 * #MHD_YES for success (parsing succeeded, @a cb always
181 * returned #MHD_YES)
182 */
183int
184MHD_parse_arguments_ (struct MHD_Connection *connection,
185 enum MHD_ValueKind kind,
186 char *args,
187 MHD_ArgumentIterator_ cb,
188 unsigned int *num_headers)
189{
190 struct MHD_Daemon *daemon = connection->daemon;
191 char *equals;
192 char *amper;
193
194 *num_headers = 0;
195 while ( (NULL != args) &&
196 ('\0' != args[0]) )
197 {
198 equals = strchr (args, '=');
199 amper = strchr (args, '&');
200 if (NULL == amper)
201 {
202 /* last argument */
203 if (NULL == equals)
204 {
205 /* last argument, without '=' */
206 MHD_unescape_plus (args);
207 daemon->unescape_callback (daemon->unescape_callback_cls,
208 connection,
209 args);
210 if (MHD_YES != cb (connection,
211 args,
212 NULL,
213 kind))
214 return MHD_NO;
215 (*num_headers)++;
216 break;
217 }
218 /* got 'foo=bar' */
219 equals[0] = '\0';
220 equals++;
221 MHD_unescape_plus (args);
222 daemon->unescape_callback (daemon->unescape_callback_cls,
223 connection,
224 args);
225 MHD_unescape_plus (equals);
226 daemon->unescape_callback (daemon->unescape_callback_cls,
227 connection,
228 equals);
229 if (MHD_YES != cb (connection,
230 args,
231 equals,
232 kind))
233 return MHD_NO;
234 (*num_headers)++;
235 break;
236 }
237 /* amper is non-NULL here */
238 amper[0] = '\0';
239 amper++;
240 if ( (NULL == equals) ||
241 (equals >= amper) )
242 {
243 /* got 'foo&bar' or 'foo&bar=val', add key 'foo' with NULL for value */
244 MHD_unescape_plus (args);
245 daemon->unescape_callback (daemon->unescape_callback_cls,
246 connection,
247 args);
248 if (MHD_YES != cb (connection,
249 args,
250 NULL,
251 kind))
252 return MHD_NO;
253 /* continue with 'bar' */
254 (*num_headers)++;
255 args = amper;
256 continue;
257 }
258 /* equals and amper are non-NULL here, and equals < amper,
259 so we got regular 'foo=value&bar...'-kind of argument */
260 equals[0] = '\0';
261 equals++;
262 MHD_unescape_plus (args);
263 daemon->unescape_callback (daemon->unescape_callback_cls,
264 connection,
265 args);
266 MHD_unescape_plus (equals);
267 daemon->unescape_callback (daemon->unescape_callback_cls,
268 connection,
269 equals);
270 if (MHD_YES != cb (connection,
271 args,
272 equals,
273 kind))
274 return MHD_NO;
275 (*num_headers)++;
276 args = amper;
277 }
278 return MHD_YES;
279}
280
281/* end of internal.c */
diff --git a/src/lib/md5.c b/src/lib/md5.c
new file mode 100644
index 00000000..d92a42ee
--- /dev/null
+++ b/src/lib/md5.c
@@ -0,0 +1,264 @@
1/*
2 * This code implements the MD5 message-digest algorithm.
3 * The algorithm is due to Ron Rivest. This code was
4 * written by Colin Plumb in 1993, no copyright is claimed.
5 * This code is in the public domain; do with it what you wish.
6 *
7 * Equivalent code is available from RSA Data Security, Inc.
8 * This code has been tested against that, and is equivalent,
9 * except that you don't need to include two pages of legalese
10 * with every copy.
11 *
12 * To compute the message digest of a chunk of bytes, declare an
13 * MD5Context structure, pass it to MD5Init, call MD5Update as
14 * needed on buffers full of bytes, and then call MD5Final, which
15 * will fill a supplied 16-byte array with the digest.
16 */
17
18/* Based on OpenBSD modifications */
19
20#include "md5.h"
21#include "mhd_byteorder.h"
22
23#define PUT_64BIT_LE(cp, value) do { \
24 (cp)[7] = (uint8_t)((value) >> 56); \
25 (cp)[6] = (uint8_t)((value) >> 48); \
26 (cp)[5] = (uint8_t)((value) >> 40); \
27 (cp)[4] = (uint8_t)((value) >> 32); \
28 (cp)[3] = (uint8_t)((value) >> 24); \
29 (cp)[2] = (uint8_t)((value) >> 16); \
30 (cp)[1] = (uint8_t)((value) >> 8); \
31 (cp)[0] = (uint8_t)((value)); } while (0)
32
33#define PUT_32BIT_LE(cp, value) do { \
34 (cp)[3] = (uint8_t)((value) >> 24); \
35 (cp)[2] = (uint8_t)((value) >> 16); \
36 (cp)[1] = (uint8_t)((value) >> 8); \
37 (cp)[0] = (uint8_t)((value)); } while (0)
38
39static uint8_t PADDING[MD5_BLOCK_SIZE] = {
40 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
41 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
42 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
43};
44
45/*
46 * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
47 * initialization constants.
48 */
49void
50MD5Init(struct MD5Context *ctx)
51{
52 if (!ctx)
53 return;
54
55 ctx->count = 0;
56 ctx->state[0] = 0x67452301;
57 ctx->state[1] = 0xefcdab89;
58 ctx->state[2] = 0x98badcfe;
59 ctx->state[3] = 0x10325476;
60}
61
62/*
63 * Update context to reflect the concatenation of another buffer full
64 * of bytes.
65 */
66void
67MD5Update(struct MD5Context *ctx, const unsigned char *input, size_t len)
68{
69 size_t have, need;
70
71 if (!ctx || !input)
72 return;
73
74 /* Check how many bytes we already have and how many more we need. */
75 have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_SIZE - 1));
76 need = MD5_BLOCK_SIZE - have;
77
78 /* Update bitcount */
79 ctx->count += (uint64_t)len << 3;
80
81 if (len >= need)
82 {
83 if (have != 0)
84 {
85 memcpy(ctx->buffer + have, input, need);
86 MD5Transform(ctx->state, ctx->buffer);
87 input += need;
88 len -= need;
89 have = 0;
90 }
91
92 /* Process data in MD5_BLOCK_SIZE-byte chunks. */
93 while (len >= MD5_BLOCK_SIZE)
94 {
95 MD5Transform(ctx->state, input);
96 input += MD5_BLOCK_SIZE;
97 len -= MD5_BLOCK_SIZE;
98 }
99 }
100
101 /* Handle any remaining bytes of data. */
102 if (len != 0)
103 memcpy(ctx->buffer + have, input, len);
104}
105
106/*
107 * Pad pad to 64-byte boundary with the bit pattern
108 * 1 0* (64-bit count of bits processed, MSB-first)
109 */
110void
111MD5Pad(struct MD5Context *ctx)
112{
113 uint8_t count[8];
114 size_t padlen;
115
116 if (!ctx)
117 return;
118
119 /* Convert count to 8 bytes in little endian order. */
120 PUT_64BIT_LE(count, ctx->count);
121
122 /* Pad out to 56 mod 64. */
123 padlen = MD5_BLOCK_SIZE -
124 ((ctx->count >> 3) & (MD5_BLOCK_SIZE - 1));
125 if (padlen < 1 + 8)
126 padlen += MD5_BLOCK_SIZE;
127 MD5Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */
128 MD5Update(ctx, count, 8);
129}
130
131/*
132 * Final wrapup--call MD5Pad, fill in digest and zero out ctx.
133 */
134void
135MD5Final(unsigned char digest[MD5_DIGEST_SIZE], struct MD5Context *ctx)
136{
137 int i;
138
139 if (!ctx || !digest)
140 return;
141
142 MD5Pad(ctx);
143 for (i = 0; i < 4; i++)
144 PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
145
146 memset(ctx, 0, sizeof(*ctx));
147}
148
149
150/* The four core functions - F1 is optimized somewhat */
151
152/* #define F1(x, y, z) (x & y | ~x & z) */
153#define F1(x, y, z) (z ^ (x & (y ^ z)))
154#define F2(x, y, z) F1(z, x, y)
155#define F3(x, y, z) (x ^ y ^ z)
156#define F4(x, y, z) (y ^ (x | ~z))
157
158/* This is the central step in the MD5 algorithm. */
159#define MD5STEP(f, w, x, y, z, data, s) \
160 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
161
162/*
163 * The core of the MD5 algorithm, this alters an existing MD5 hash to
164 * reflect the addition of 16 longwords of new data. MD5Update blocks
165 * the data and converts bytes into longwords for this routine.
166 */
167void
168MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_SIZE])
169{
170 uint32_t a, b, c, d, in[MD5_BLOCK_SIZE / 4];
171
172#if _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
173 memcpy(in, block, sizeof(in));
174#else
175 for (a = 0; a < MD5_BLOCK_SIZE / 4; a++)
176 {
177 in[a] = (uint32_t)(
178 (uint32_t)(block[a * 4 + 0]) |
179 (uint32_t)(block[a * 4 + 1]) << 8 |
180 (uint32_t)(block[a * 4 + 2]) << 16 |
181 (uint32_t)(block[a * 4 + 3]) << 24);
182 }
183#endif
184
185 a = state[0];
186 b = state[1];
187 c = state[2];
188 d = state[3];
189
190 MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
191 MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
192 MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
193 MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
194 MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
195 MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
196 MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
197 MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
198 MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
199 MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
200 MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
201 MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
202 MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
203 MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
204 MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
205 MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
206
207 MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
208 MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
209 MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
210 MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
211 MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
212 MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
213 MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
214 MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
215 MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
216 MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
217 MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
218 MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
219 MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
220 MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
221 MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
222 MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
223
224 MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
225 MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
226 MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
227 MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
228 MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
229 MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
230 MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
231 MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
232 MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
233 MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
234 MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
235 MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
236 MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
237 MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
238 MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
239 MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
240
241 MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
242 MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
243 MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
244 MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
245 MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
246 MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
247 MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
248 MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
249 MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
250 MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
251 MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
252 MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
253 MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
254 MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
255 MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
256 MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
257
258 state[0] += a;
259 state[1] += b;
260 state[2] += c;
261 state[3] += d;
262}
263
264/* end of md5.c */
diff --git a/src/lib/md5.h b/src/lib/md5.h
new file mode 100644
index 00000000..ad1151e9
--- /dev/null
+++ b/src/lib/md5.h
@@ -0,0 +1,64 @@
1/*
2 * This code implements the MD5 message-digest algorithm.
3 * The algorithm is due to Ron Rivest. This code was
4 * written by Colin Plumb in 1993, no copyright is claimed.
5 * This code is in the public domain; do with it what you wish.
6 *
7 * Equivalent code is available from RSA Data Security, Inc.
8 * This code has been tested against that, and is equivalent,
9 * except that you don't need to include two pages of legalese
10 * with every copy.
11 *
12 * To compute the message digest of a chunk of bytes, declare an
13 * MD5Context structure, pass it to MD5Init, call MD5Update as
14 * needed on buffers full of bytes, and then call MD5Final, which
15 * will fill a supplied 16-byte array with the digest.
16 */
17
18#ifndef MHD_MD5_H
19#define MHD_MD5_H
20
21#include "platform.h"
22
23#define MD5_BLOCK_SIZE 64
24#define MD5_DIGEST_SIZE 16
25#define MD5_DIGEST_STRING_LENGTH (MD5_DIGEST_SIZE * 2 + 1)
26
27struct MD5Context
28{
29 uint32_t state[4]; /* state */
30 uint64_t count; /* number of bits, mod 2^64 */
31 uint8_t buffer[MD5_BLOCK_SIZE]; /* input buffer */
32};
33
34/*
35 * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
36 * initialization constants.
37 */
38void MD5Init(struct MD5Context *ctx);
39
40/*
41 * Update context to reflect the concatenation of another buffer full
42 * of bytes.
43 */
44void MD5Update(struct MD5Context *ctx, const unsigned char *input, size_t len);
45
46/*
47 * Pad pad to 64-byte boundary with the bit pattern
48 * 1 0* (64-bit count of bits processed, MSB-first)
49 */
50void MD5Pad(struct MD5Context *ctx);
51
52/*
53 * Final wrapup--call MD5Pad, fill in digest and zero out ctx.
54 */
55void MD5Final(unsigned char digest[MD5_DIGEST_SIZE], struct MD5Context *ctx);
56
57/*
58 * The core of the MD5 algorithm, this alters an existing MD5 hash to
59 * reflect the addition of 16 longwords of new data. MD5Update blocks
60 * the data and converts bytes into longwords for this routine.
61 */
62void MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_SIZE]);
63
64#endif /* !MHD_MD5_H */
diff --git a/src/lib/memorypool.c b/src/lib/memorypool.c
new file mode 100644
index 00000000..bda45e1e
--- /dev/null
+++ b/src/lib/memorypool.c
@@ -0,0 +1,340 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007, 2009, 2010 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file memorypool.c
22 * @brief memory pool
23 * @author Christian Grothoff
24 */
25#include "memorypool.h"
26
27/* define MAP_ANONYMOUS for Mac OS X */
28#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
29#define MAP_ANONYMOUS MAP_ANON
30#endif
31#ifndef MAP_FAILED
32#define MAP_FAILED ((void*)-1)
33#endif
34
35/**
36 * Align to 2x word size (as GNU libc does).
37 */
38#define ALIGN_SIZE (2 * sizeof(void*))
39
40/**
41 * Round up 'n' to a multiple of ALIGN_SIZE.
42 */
43#define ROUND_TO_ALIGN(n) ((n+(ALIGN_SIZE-1)) & (~(ALIGN_SIZE-1)))
44
45
46/**
47 * Handle for a memory pool. Pools are not reentrant and must not be
48 * used by multiple threads.
49 */
50struct MemoryPool
51{
52
53 /**
54 * Pointer to the pool's memory
55 */
56 char *memory;
57
58 /**
59 * Size of the pool.
60 */
61 size_t size;
62
63 /**
64 * Offset of the first unallocated byte.
65 */
66 size_t pos;
67
68 /**
69 * Offset of the last unallocated byte.
70 */
71 size_t end;
72
73 /**
74 * #MHD_NO if pool was malloc'ed, #MHD_YES if mmapped (VirtualAlloc'ed for W32).
75 */
76 int is_mmap;
77};
78
79
80/**
81 * Free the memory given by @a ptr. Calls "free(ptr)". This function
82 * should be used to free the username returned by
83 * #MHD_digest_auth_get_username().
84 * @note Since v0.9.56
85 *
86 * @param ptr pointer to free.
87 */
88_MHD_EXTERN void
89MHD_free (void *ptr)
90{
91 free (ptr);
92}
93
94
95/**
96 * Create a memory pool.
97 *
98 * @param max maximum size of the pool
99 * @return NULL on error
100 */
101struct MemoryPool *
102MHD_pool_create (size_t max)
103{
104 struct MemoryPool *pool;
105
106 pool = malloc (sizeof (struct MemoryPool));
107 if (NULL == pool)
108 return NULL;
109#if defined(MAP_ANONYMOUS) || defined(_WIN32)
110 if (max <= 32 * 1024)
111 pool->memory = MAP_FAILED;
112 else
113#if defined(MAP_ANONYMOUS) && !defined(_WIN32)
114 pool->memory = mmap (NULL,
115 max,
116 PROT_READ | PROT_WRITE,
117 MAP_PRIVATE | MAP_ANONYMOUS,
118 -1,
119 0);
120#elif defined(_WIN32)
121 pool->memory = VirtualAlloc (NULL,
122 max,
123 MEM_COMMIT | MEM_RESERVE,
124 PAGE_READWRITE);
125#endif
126#else
127 pool->memory = MAP_FAILED;
128#endif
129 if ( (MAP_FAILED == pool->memory) ||
130 (NULL == pool->memory))
131 {
132 pool->memory = malloc (max);
133 if (NULL == pool->memory)
134 {
135 free (pool);
136 return NULL;
137 }
138 pool->is_mmap = MHD_NO;
139 }
140 else
141 {
142 pool->is_mmap = MHD_YES;
143 }
144 pool->pos = 0;
145 pool->end = max;
146 pool->size = max;
147 return pool;
148}
149
150
151/**
152 * Destroy a memory pool.
153 *
154 * @param pool memory pool to destroy
155 */
156void
157MHD_pool_destroy (struct MemoryPool *pool)
158{
159 if (NULL == pool)
160 return;
161 if (MHD_NO == pool->is_mmap)
162 free (pool->memory);
163 else
164#if defined(MAP_ANONYMOUS) && !defined(_WIN32)
165 munmap (pool->memory,
166 pool->size);
167#elif defined(_WIN32)
168 VirtualFree (pool->memory,
169 0,
170 MEM_RELEASE);
171#else
172 abort ();
173#endif
174 free (pool);
175}
176
177
178/**
179 * Check how much memory is left in the @a pool
180 *
181 * @param pool pool to check
182 * @return number of bytes still available in @a pool
183 */
184size_t
185MHD_pool_get_free (struct MemoryPool *pool)
186{
187 return (pool->end - pool->pos);
188}
189
190
191/**
192 * Allocate size bytes from the pool.
193 *
194 * @param pool memory pool to use for the operation
195 * @param size number of bytes to allocate
196 * @param from_end allocate from end of pool (set to #MHD_YES);
197 * use this for small, persistent allocations that
198 * will never be reallocated
199 * @return NULL if the pool cannot support size more
200 * bytes
201 */
202void *
203MHD_pool_allocate (struct MemoryPool *pool,
204 size_t size,
205 int from_end)
206{
207 void *ret;
208 size_t asize;
209
210 asize = ROUND_TO_ALIGN (size);
211 if ( (0 == asize) && (0 != size) )
212 return NULL; /* size too close to SIZE_MAX */
213 if ( (pool->pos + asize > pool->end) ||
214 (pool->pos + asize < pool->pos))
215 return NULL;
216 if (from_end == MHD_YES)
217 {
218 ret = &pool->memory[pool->end - asize];
219 pool->end -= asize;
220 }
221 else
222 {
223 ret = &pool->memory[pool->pos];
224 pool->pos += asize;
225 }
226 return ret;
227}
228
229
230/**
231 * Reallocate a block of memory obtained from the pool.
232 * This is particularly efficient when growing or
233 * shrinking the block that was last (re)allocated.
234 * If the given block is not the most recently
235 * (re)allocated block, the memory of the previous
236 * allocation may be leaked until the pool is
237 * destroyed (and copying the data maybe required).
238 *
239 * @param pool memory pool to use for the operation
240 * @param old the existing block
241 * @param old_size the size of the existing block
242 * @param new_size the new size of the block
243 * @return new address of the block, or
244 * NULL if the pool cannot support @a new_size
245 * bytes (old continues to be valid for @a old_size)
246 */
247void *
248MHD_pool_reallocate (struct MemoryPool *pool,
249 void *old,
250 size_t old_size,
251 size_t new_size)
252{
253 void *ret;
254 size_t asize;
255
256 asize = ROUND_TO_ALIGN (new_size);
257 if ( (0 == asize) &&
258 (0 != new_size) )
259 return NULL; /* new_size too close to SIZE_MAX */
260 if ( (pool->end < old_size) ||
261 (pool->end < asize) )
262 return NULL; /* unsatisfiable or bogus request */
263
264 if ( (pool->pos >= old_size) &&
265 (&pool->memory[pool->pos - old_size] == old) )
266 {
267 /* was the previous allocation - optimize! */
268 if (pool->pos + asize - old_size <= pool->end)
269 {
270 /* fits */
271 pool->pos += asize - old_size;
272 if (asize < old_size) /* shrinking - zero again! */
273 memset (&pool->memory[pool->pos],
274 0,
275 old_size - asize);
276 return old;
277 }
278 /* does not fit */
279 return NULL;
280 }
281 if (asize <= old_size)
282 return old; /* cannot shrink, no need to move */
283 if ((pool->pos + asize >= pool->pos) &&
284 (pool->pos + asize <= pool->end))
285 {
286 /* fits */
287 ret = &pool->memory[pool->pos];
288 if (0 != old_size)
289 memmove (ret,
290 old,
291 old_size);
292 pool->pos += asize;
293 return ret;
294 }
295 /* does not fit */
296 return NULL;
297}
298
299
300/**
301 * Clear all entries from the memory pool except
302 * for @a keep of the given @a size. The pointer
303 * returned should be a buffer of @a new_size where
304 * the first @a copy_bytes are from @a keep.
305 *
306 * @param pool memory pool to use for the operation
307 * @param keep pointer to the entry to keep (maybe NULL)
308 * @param copy_bytes how many bytes need to be kept at this address
309 * @param new_size how many bytes should the allocation we return have?
310 * (should be larger or equal to @a copy_bytes)
311 * @return addr new address of @a keep (if it had to change)
312 */
313void *
314MHD_pool_reset (struct MemoryPool *pool,
315 void *keep,
316 size_t copy_bytes,
317 size_t new_size)
318{
319 if ( (NULL != keep) &&
320 (keep != pool->memory) )
321 {
322 if (0 != copy_bytes)
323 memmove (pool->memory,
324 keep,
325 copy_bytes);
326 keep = pool->memory;
327 }
328 pool->end = pool->size;
329 /* technically not needed, but safer to zero out */
330 if (pool->size > copy_bytes)
331 memset (&pool->memory[copy_bytes],
332 0,
333 pool->size - copy_bytes);
334 if (NULL != keep)
335 pool->pos = ROUND_TO_ALIGN (new_size);
336 return keep;
337}
338
339
340/* end of memorypool.c */
diff --git a/src/lib/memorypool.h b/src/lib/memorypool.h
new file mode 100644
index 00000000..36136af8
--- /dev/null
+++ b/src/lib/memorypool.h
@@ -0,0 +1,130 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007, 2009 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file memorypool.h
22 * @brief memory pool; mostly used for efficient (de)allocation
23 * for each connection and bounding memory use for each
24 * request
25 * @author Christian Grothoff
26 */
27
28#ifndef MEMORYPOOL_H
29#define MEMORYPOOL_H
30
31#include "internal.h"
32
33/**
34 * Opaque handle for a memory pool.
35 * Pools are not reentrant and must not be used
36 * by multiple threads.
37 */
38struct MemoryPool;
39
40
41/**
42 * Create a memory pool.
43 *
44 * @param max maximum size of the pool
45 * @return NULL on error
46 */
47struct MemoryPool *
48MHD_pool_create (size_t max);
49
50
51/**
52 * Destroy a memory pool.
53 *
54 * @param pool memory pool to destroy
55 */
56void
57MHD_pool_destroy (struct MemoryPool *pool);
58
59
60/**
61 * Allocate size bytes from the pool.
62 *
63 * @param pool memory pool to use for the operation
64 * @param size number of bytes to allocate
65 * @param from_end allocate from end of pool (set to #MHD_YES);
66 * use this for small, persistent allocations that
67 * will never be reallocated
68 * @return NULL if the pool cannot support size more
69 * bytes
70 */
71void *
72MHD_pool_allocate (struct MemoryPool *pool,
73 size_t size,
74 int from_end);
75
76
77/**
78 * Reallocate a block of memory obtained from the pool.
79 * This is particularly efficient when growing or
80 * shrinking the block that was last (re)allocated.
81 * If the given block is not the most recently
82 * (re)allocated block, the memory of the previous
83 * allocation may be leaked until the pool is
84 * destroyed (and copying the data maybe required).
85 *
86 * @param pool memory pool to use for the operation
87 * @param old the existing block
88 * @param old_size the size of the existing block
89 * @param new_size the new size of the block
90 * @return new address of the block, or
91 * NULL if the pool cannot support new_size
92 * bytes (old continues to be valid for old_size)
93 */
94void *
95MHD_pool_reallocate (struct MemoryPool *pool,
96 void *old,
97 size_t old_size,
98 size_t new_size);
99
100
101/**
102 * Check how much memory is left in the @a pool
103 *
104 * @param pool pool to check
105 * @return number of bytes still available in @a pool
106 */
107size_t
108MHD_pool_get_free (struct MemoryPool *pool);
109
110
111/**
112 * Clear all entries from the memory pool except
113 * for @a keep of the given @a copy_bytes. The pointer
114 * returned should be a buffer of @a new_size where
115 * the first @a copy_bytes are from @a keep.
116 *
117 * @param pool memory pool to use for the operation
118 * @param keep pointer to the entry to keep (maybe NULL)
119 * @param copy_bytes how many bytes need to be kept at this address
120 * @param new_size how many bytes should the allocation we return have?
121 * (should be larger or equal to @a copy_bytes)
122 * @return addr new address of @a keep (if it had to change)
123 */
124void *
125MHD_pool_reset (struct MemoryPool *pool,
126 void *keep,
127 size_t copy_bytes,
128 size_t new_size);
129
130#endif
diff --git a/src/lib/mhd_assert.h b/src/lib/mhd_assert.h
new file mode 100644
index 00000000..c720ce5c
--- /dev/null
+++ b/src/lib/mhd_assert.h
@@ -0,0 +1,49 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2017 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library.
17 If not, see <http://www.gnu.org/licenses/>.
18*/
19
20/**
21 * @file microhttpd/mhd_assert.h
22 * @brief macros for mhd_assert()
23 * @author Karlson2k (Evgeny Grin)
24 */
25
26#ifndef MHD_ASSERT_H
27#define MHD_ASSERT_H 1
28
29#include "mhd_options.h"
30#ifdef NDEBUG
31# define mhd_assert(ignore) ((void)0)
32#else /* _DEBUG */
33# ifdef HAVE_ASSERT
34# include <assert.h>
35# define mhd_assert(CHK) assert(CHK)
36# else /* ! HAVE_ASSERT */
37# include <stdio.h>
38# include <stdlib.h>
39# define mhd_assert(CHK) \
40 do { \
41 if (!(CHK)) { \
42 fprintf(stderr, "%s:%u Assertion failed: %s\nProgram aborted.\n", \
43 __FILE__, (unsigned)__LINE__, #CHK); \
44 fflush(stderr); abort(); } \
45 } while(0)
46# endif /* ! HAVE_ASSERT */
47#endif /* _DEBUG */
48
49#endif /* ! MHD_ASSERT_H */
diff --git a/src/lib/mhd_byteorder.h b/src/lib/mhd_byteorder.h
new file mode 100644
index 00000000..66689804
--- /dev/null
+++ b/src/lib/mhd_byteorder.h
@@ -0,0 +1,160 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2015 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library.
17 If not, see <http://www.gnu.org/licenses/>.
18*/
19
20/**
21 * @file microhttpd/mhd_byteorder.h
22 * @brief macro definitions for host byte order
23 * @author Karlson2k (Evgeny Grin)
24 */
25
26#ifndef MHD_BYTEORDER_H
27#define MHD_BYTEORDER_H
28
29#include "platform.h"
30
31#if HAVE_ENDIAN_H
32#include <endian.h>
33#endif
34
35#if HAVE_SYS_PARAM_H
36#include <sys/param.h>
37#endif
38
39#if HAVE_MACHINE_ENDIAN_H
40#include <machine/endian.h>
41#endif
42
43#if HAVE_SYS_ENDIAN_H
44#include <sys/endian.h>
45#endif
46
47#if HAVE_SYS_TYPES_H
48#include <sys/types.h>
49#endif
50
51#if HAVE_SYS_BYTEORDER_H
52#include <sys/byteorder.h>
53#endif
54
55#if HAVE_SYS_MACHINE_H
56#include <sys/machine.h>
57#endif
58
59#if HAVE_MACHINE_PARAM_H
60#include <machine/param.h>
61#endif
62
63#if HAVE_SYS_ISA_DEFS_H
64#include <sys/isa_defs.h>
65#endif
66
67#define _MHD_BIG_ENDIAN 1234
68#define _MHD_LITTLE_ENDIAN 4321
69#define _MHD_PDP_ENDIAN 2143
70
71#if defined(__BYTE_ORDER__)
72#if defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
73#define _MHD_BYTE_ORDER _MHD_BIG_ENDIAN
74#elif defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
75#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
76#elif defined(__ORDER_PDP_ENDIAN__) && __BYTE_ORDER__ == __ORDER_PDP_ENDIAN__
77#define _MHD_BYTE_ORDER _MHD_PDP_ENDIAN
78#endif /* __BYTE_ORDER__ == __ORDER_PDP_ENDIAN__ */
79#elif defined(__BYTE_ORDER)
80#if defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN
81#define _MHD_BYTE_ORDER _MHD_BIG_ENDIAN
82#elif defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN
83#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
84#elif defined(__PDP_ENDIAN) && __BYTE_ORDER == __PDP_ENDIAN
85#define _MHD_BYTE_ORDER _MHD_PDP_ENDIAN
86#endif /* __BYTE_ORDER == __PDP_ENDIAN */
87#elif defined (BYTE_ORDER)
88#if defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
89#define _MHD_BYTE_ORDER _MHD_BIG_ENDIAN
90#elif defined(LITTLE_ENDIAN) && BYTE_ORDER == LITTLE_ENDIAN
91#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
92#elif defined(PDP_ENDIAN) && BYTE_ORDER == PDP_ENDIAN
93#define _MHD_BYTE_ORDER _MHD_PDP_ENDIAN
94#endif /* __BYTE_ORDER == _PDP_ENDIAN */
95#elif defined (_BYTE_ORDER)
96#if defined(_BIG_ENDIAN) && _BYTE_ORDER == _BIG_ENDIAN
97#define _MHD_BYTE_ORDER _MHD_BIG_ENDIAN
98#elif defined(_LITTLE_ENDIAN) && _BYTE_ORDER == _LITTLE_ENDIAN
99#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
100#elif defined(_PDP_ENDIAN) && _BYTE_ORDER == _PDP_ENDIAN
101#define _MHD_BYTE_ORDER _MHD_PDP_ENDIAN
102#endif /* _BYTE_ORDER == _PDP_ENDIAN */
103#endif /* _BYTE_ORDER */
104
105#ifndef _MHD_BYTE_ORDER
106/* Byte order specification didn't detected in system headers */
107/* Try some guessing */
108
109#if (defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)) || \
110 (defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN))
111/* Seems that we are on big endian platform */
112#define _MHD_BYTE_ORDER _MHD_BIG_ENDIAN
113#elif (defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) || \
114 (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN))
115/* Seems that we are on little endian platform */
116#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
117#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || \
118 defined(_M_X64) || defined(_M_AMD64) || defined(i386) || defined(__i386) || \
119 defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || \
120 defined(_M_IX86) || defined(_X86_) || defined (__THW_INTEL__)
121/* x86 family is little endian */
122#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
123#elif defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \
124 defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__)
125/* Looks like we are on ARM/MIPS in big endian mode */
126#define _MHD_BYTE_ORDER _MHD_BIG_ENDIAN
127#elif defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \
128 defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__)
129/* Looks like we are on ARM/MIPS in little endian mode */
130#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
131#elif defined(__m68k__) || defined(M68000) || defined(__hppa__) || defined(__hppa) || \
132 defined(__HPPA__) || defined(__370__) || defined(__THW_370__) || \
133 defined(__s390__) || defined(__s390x__) || defined(__SYSC_ZARCH__)
134/* Looks like we are on big endian platform */
135#define _MHD_BYTE_ORDER _MHD_BIG_ENDIAN
136#elif defined(__ia64__) || defined(_IA64) || defined(__IA64__) || defined(__ia64) || \
137 defined(_M_IA64) || defined(__itanium__) || defined(__bfin__) || \
138 defined(__BFIN__) || defined(bfin) || defined(BFIN)
139/* Looks like we are on little endian platform */
140#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
141#elif defined(_WIN32)
142/* W32 is always little endian on all platforms */
143#define _MHD_BYTE_ORDER _MHD_LITTLE_ENDIAN
144#elif defined(WORDS_BIGENDIAN)
145/* Use byte order detected by configure */
146#define _MHD_BYTE_ORDER _MHD_BIG_ENDIAN
147#endif /* _WIN32 */
148
149#endif /* !_MHD_BYTE_ORDER */
150
151#ifdef _MHD_BYTE_ORDER
152/* Some safety checks */
153#if defined(WORDS_BIGENDIAN) && _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN
154#error Configure detected big endian byte order but headers specify different byte order
155#elif !defined(WORDS_BIGENDIAN) && _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
156#error Configure did not detect big endian byte order but headers specify big endian byte order
157#endif /* !WORDS_BIGENDIAN && _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN */
158#endif /* _MHD_BYTE_ORDER */
159
160#endif /* !MHD_BYTEORDER_H */
diff --git a/src/lib/mhd_compat.c b/src/lib/mhd_compat.c
new file mode 100644
index 00000000..3abdc367
--- /dev/null
+++ b/src/lib/mhd_compat.c
@@ -0,0 +1,114 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2014-2016 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file microhttpd/mhd_compat.c
23 * @brief Implementation of platform missing functions.
24 * @author Karlson2k (Evgeny Grin)
25 */
26
27#include "mhd_compat.h"
28#if defined(_WIN32) && !defined(__CYGWIN__)
29#include <stdint.h>
30#include <time.h>
31#ifndef HAVE_SNPRINTF
32#include <stdio.h>
33#include <stdarg.h>
34#endif /* HAVE_SNPRINTF */
35#endif /* _WIN32 && !__CYGWIN__ */
36
37#ifndef HAVE_CALLOC
38#include <string.h> /* for memset() */
39#endif /* ! HAVE_CALLOC */
40
41#if defined(_WIN32) && !defined(__CYGWIN__)
42
43#ifndef HAVE_SNPRINTF
44/* Emulate snprintf function on W32 */
45int
46W32_snprintf (char *__restrict s,
47 size_t n,
48 const char *__restrict format,
49 ...)
50{
51 int ret;
52 va_list args;
53
54 if ( (0 != n) &&
55 (NULL != s) )
56 {
57 va_start (args,
58 format);
59 ret = _vsnprintf (s,
60 n,
61 format,
62 args);
63 va_end (args);
64 if ((int)n == ret)
65 s[n - 1] = 0;
66 if (ret >= 0)
67 return ret;
68 }
69 va_start(args,
70 format);
71 ret = _vscprintf (format,
72 args);
73 va_end(args);
74 if ( (0 <= ret) &&
75 (0 != n) &&
76 (NULL == s) )
77 return -1;
78
79 return ret;
80}
81
82#endif /* HAVE_SNPRINTF */
83#endif /* _WIN32 && !__CYGWIN__ */
84
85#ifndef HAVE_CALLOC
86
87#ifdef __has_builtin
88# if __has_builtin(__builtin_mul_overflow)
89# define MHD_HAVE_NUL_OVERFLOW 1
90# endif
91#elif __GNUC__+0 >= 5
92# define MHD_HAVE_NUL_OVERFLOW 1
93#endif /* __GNUC__ >= 5 */
94
95
96void *MHD_calloc_(size_t nelem, size_t elsize)
97{
98 size_t alloc_size;
99 void *ptr;
100#ifdef MHD_HAVE_NUL_OVERFLOW
101 if (__builtin_mul_overflow(nelem, elsize, &alloc_size) || 0 == alloc_size)
102 return NULL;
103#else /* ! MHD_HAVE_NUL_OVERFLOW */
104 alloc_size = nelem * elsize;
105 if (0 == alloc_size || elsize != alloc_size / nelem)
106 return NULL;
107#endif /* ! MHD_HAVE_NUL_OVERFLOW */
108 ptr = malloc (alloc_size);
109 if (NULL == ptr)
110 return NULL;
111 memset(ptr, 0, alloc_size);
112 return ptr;
113}
114#endif /* ! HAVE_CALLOC */
diff --git a/src/lib/mhd_compat.h b/src/lib/mhd_compat.h
new file mode 100644
index 00000000..b4e2c66c
--- /dev/null
+++ b/src/lib/mhd_compat.h
@@ -0,0 +1,87 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2014-2016 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file microhttpd/mhd_compat.h
23 * @brief Header for platform missing functions.
24 * @author Karlson2k (Evgeny Grin)
25 *
26 * Provides compatibility for platforms with some missing
27 * functionality.
28 * Any functions can be implemented as macro on some platforms
29 * unless explicitly marked otherwise.
30 * Any function argument can be skipped in macro, so avoid
31 * variable modification in function parameters.
32 */
33
34#ifndef MHD_COMPAT_H
35#define MHD_COMPAT_H 1
36
37#include "mhd_options.h"
38#include <stdlib.h>
39#ifdef HAVE_STRING_H /* for strerror() */
40#include <string.h>
41#endif /* HAVE_STRING_H */
42
43 /* MHD_strerror_ is strerror */
44#define MHD_strerror_(errnum) strerror((errnum))
45
46/* Platform-independent snprintf name */
47#if defined(HAVE_SNPRINTF)
48#define MHD_snprintf_ snprintf
49#else /* ! HAVE_SNPRINTF */
50#if defined(_WIN32) && ! defined(__CYGWIN__)
51/* Emulate snprintf function on W32 */
52int W32_snprintf(char *__restrict s, size_t n, const char *__restrict format, ...);
53#define MHD_snprintf_ W32_snprintf
54#else /* ! _WIN32 || __CYGWIN__ */
55#error Your platform does not support snprintf() and MHD does not know how to emulate it on your platform.
56#endif /* ! _WIN32 || __CYGWIN__ */
57#endif /* ! HAVE_SNPRINTF */
58
59#ifdef HAVE_RANDOM
60/**
61 * Generate pseudo random number at least 30-bit wide.
62 * @return pseudo random number at least 30-bit wide.
63 */
64#define MHD_random_() random()
65#else /* HAVE_RANDOM */
66#ifdef HAVE_RAND
67/**
68 * Generate pseudo random number at least 30-bit wide.
69 * @return pseudo random number at least 30-bit wide.
70 */
71#define MHD_random_() ( (((long)rand()) << 15) + (long)rand() )
72#endif /* HAVE_RAND */
73#endif /* HAVE_RANDOM */
74
75#ifdef HAVE_CALLOC
76/**
77 * MHD_calloc_ is platform-independent calloc()
78 */
79#define MHD_calloc_(n,s) calloc((n),(s))
80#else /* ! HAVE_CALLOC */
81/**
82 * MHD_calloc_ is platform-independent calloc()
83 */
84void *MHD_calloc_(size_t nelem, size_t elsize);
85#endif /* ! HAVE_CALLOC */
86
87#endif /* MHD_COMPAT_H */
diff --git a/src/lib/mhd_itc.c b/src/lib/mhd_itc.c
new file mode 100644
index 00000000..8aeee576
--- /dev/null
+++ b/src/lib/mhd_itc.c
@@ -0,0 +1,70 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2016 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file microhttpd/mhd_itc.c
23 * @brief Implementation of inter-thread communication functions
24 * @author Karlson2k (Evgeny Grin)
25 * @author Christian Grothoff
26 */
27
28#include "mhd_itc.h"
29#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif /* HAVE_UNISTD_H */
32#include <fcntl.h>
33#include "internal.h"
34
35
36#if defined(_MHD_ITC_PIPE)
37#if !defined(_WIN32) || defined(__CYGWIN__)
38
39#ifndef HAVE_PIPE2_FUNC
40/**
41 * Change itc FD options to be non-blocking.
42 *
43 * @param itc the inter-thread communication primitive to manipulate
44 * @return non-zero if succeeded, zero otherwise
45 */
46int
47MHD_itc_nonblocking_ (struct MHD_itc_ itc)
48{
49 unsigned int i;
50
51 for (i=0;i<2;i++)
52 {
53 int flags;
54
55 flags = fcntl (itc.fd[i],
56 F_GETFL);
57 if (-1 == flags)
58 return 0;
59
60 if ( ((flags | O_NONBLOCK) != flags) &&
61 (0 != fcntl (itc.fd[i],
62 F_SETFL,
63 flags | O_NONBLOCK)) )
64 return 0;
65 }
66 return !0;
67}
68#endif /* ! HAVE_PIPE2_FUNC */
69#endif /* !_WIN32 || __CYGWIN__ */
70#endif /* _MHD_ITC_EVENTFD || _MHD_ITC_PIPE */
diff --git a/src/lib/mhd_itc.h b/src/lib/mhd_itc.h
new file mode 100644
index 00000000..7bfccf30
--- /dev/null
+++ b/src/lib/mhd_itc.h
@@ -0,0 +1,361 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2016 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file microhttpd/mhd_itc.h
23 * @brief Header for platform-independent inter-thread communication
24 * @author Karlson2k (Evgeny Grin)
25 * @author Christian Grothoff
26 *
27 * Provides basic abstraction for inter-thread communication.
28 * Any functions can be implemented as macro on some platforms
29 * unless explicitly marked otherwise.
30 * Any function argument can be skipped in macro, so avoid
31 * variable modification in function parameters.
32 */
33#ifndef MHD_ITC_H
34#define MHD_ITC_H 1
35#include "mhd_itc_types.h"
36
37#include <fcntl.h>
38
39#ifndef MHD_PANIC
40# include <stdio.h>
41# include <stdlib.h>
42/* Simple implementation of MHD_PANIC, to be used outside lib */
43# define MHD_PANIC(msg) do { fprintf (stderr, \
44 "Abnormal termination at %d line in file %s: %s\n", \
45 (int)__LINE__, __FILE__, msg); abort();} while(0)
46#endif /* ! MHD_PANIC */
47
48#if defined(_MHD_ITC_EVENTFD)
49
50/* **************** Optimized GNU/Linux ITC implementation by eventfd ********** */
51#include <sys/eventfd.h>
52#include <stdint.h> /* for uint64_t */
53#ifdef HAVE_UNISTD_H
54#include <unistd.h> /* for read(), write(), errno */
55#endif /* HAVE_UNISTD_H */
56#ifdef HAVE_STRING_H
57#include <string.h> /* for strerror() */
58#endif
59
60
61/**
62 * Initialise ITC by generating eventFD
63 * @param itc the itc to initialise
64 * @return non-zero if succeeded, zero otherwise
65 */
66#define MHD_itc_init_(itc) (-1 != ((itc).fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK)))
67
68/**
69 * Get description string of last errno for itc operations.
70 */
71#define MHD_itc_last_strerror_() strerror(errno)
72
73/**
74 * Internal static const helper for MHD_itc_activate_()
75 */
76static const uint64_t _MHD_itc_wr_data = 1;
77
78/**
79 * Activate signal on @a itc
80 * @param itc the itc to use
81 * @param str ignored
82 * @return non-zero if succeeded, zero otherwise
83 */
84#define MHD_itc_activate_(itc, str) \
85 ((write((itc).fd, (const void*)&_MHD_itc_wr_data, 8) > 0) || (EAGAIN == errno))
86
87/**
88 * Return read FD of @a itc which can be used for poll(), select() etc.
89 * @param itc the itc to get FD
90 * @return FD of read side
91 */
92#define MHD_itc_r_fd_(itc) ((itc).fd)
93
94/**
95 * Return write FD of @a itc
96 * @param itc the itc to get FD
97 * @return FD of write side
98 */
99#define MHD_itc_w_fd_(itc) ((itc).fd)
100
101/**
102 * Clear signaled state on @a itc
103 * @param itc the itc to clear
104 */
105#define MHD_itc_clear_(itc) \
106 do { uint64_t __b; int __r; \
107 __r = read((itc).fd, &__b, sizeof(__b)); \
108 (void)__r; } while(0)
109
110/**
111 * Destroy previously initialised ITC
112 * @param itc the itc to destroy
113 * @return non-zero if succeeded, zero otherwise
114 */
115#define MHD_itc_destroy_(itc) ((0 != close ((itc).fd)) || (EBADF != errno))
116
117/**
118 * Check whether ITC has valid value.
119 *
120 * Macro check whether @a itc value is valid (allowed),
121 * macro does not check whether @a itc was really initialised.
122 * @param itc the itc to check
123 * @return boolean true if @a itc has valid value,
124 * boolean false otherwise.
125 */
126#define MHD_ITC_IS_VALID_(itc) (-1 != ((itc).fd))
127
128/**
129 * Set @a itc to invalid value.
130 * @param itc the itc to set
131 */
132#define MHD_itc_set_invalid_(itc) ((itc).fd = -1)
133
134
135#elif defined(_MHD_ITC_PIPE)
136
137/* **************** Standard UNIX ITC implementation by pipe ********** */
138
139#if defined(HAVE_PIPE2_FUNC) && defined(HAVE_FCNTL_H)
140# include <fcntl.h> /* for O_CLOEXEC, O_NONBLOCK */
141#endif /* HAVE_PIPE2_FUNC && HAVE_FCNTL_H */
142#ifdef HAVE_UNISTD_H
143#include <unistd.h> /* for read(), write(), errno */
144#endif /* HAVE_UNISTD_H */
145#ifdef HAVE_STRING_H
146#include <string.h> /* for strerror() */
147#endif
148
149
150/**
151 * Initialise ITC by generating pipe
152 * @param itc the itc to initialise
153 * @return non-zero if succeeded, zero otherwise
154 */
155#ifdef HAVE_PIPE2_FUNC
156# define MHD_itc_init_(itc) (!pipe2((itc).fd, O_CLOEXEC | O_NONBLOCK))
157#else /* ! HAVE_PIPE2_FUNC */
158# define MHD_itc_init_(itc) \
159 ( (!pipe((itc).fd)) ? \
160 (MHD_itc_nonblocking_((itc)) ? \
161 (!0) : \
162 (MHD_itc_destroy_((itc)), 0) ) \
163 : (0) )
164#endif /* ! HAVE_PIPE2_FUNC */
165
166/**
167 * Get description string of last errno for itc operations.
168 */
169#define MHD_itc_last_strerror_() strerror(errno)
170
171/**
172 * Activate signal on @a itc
173 * @param itc the itc to use
174 * @param str one-symbol string, useful only for strace debug
175 * @return non-zero if succeeded, zero otherwise
176 */
177#define MHD_itc_activate_(itc, str) \
178 ((write((itc).fd[1], (const void*)(str), 1) > 0) || (EAGAIN == errno))
179
180
181/**
182 * Return read FD of @a itc which can be used for poll(), select() etc.
183 * @param itc the itc to get FD
184 * @return FD of read side
185 */
186#define MHD_itc_r_fd_(itc) ((itc).fd[0])
187
188/**
189 * Return write FD of @a itc
190 * @param itc the itc to get FD
191 * @return FD of write side
192 */
193#define MHD_itc_w_fd_(itc) ((itc).fd[1])
194
195/**
196 * Clear signaled state on @a itc
197 * @param itc the itc to clear
198 */
199#define MHD_itc_clear_(itc) do \
200 { long __b; \
201 while(0 < read((itc).fd[0], &__b, sizeof(__b))) \
202 {} } while(0)
203
204/**
205 * Destroy previously initialised ITC
206 * @param itc the itc to destroy
207 * @return non-zero if succeeded, zero otherwise
208 */
209#define MHD_itc_destroy_(itc) \
210 ( (0 == close ((itc).fd[0])) ? \
211 (0 == close ((itc).fd[1])) : \
212 ((close ((itc).fd[1])), 0) )
213
214/**
215 * Check whether ITC has valid value.
216 *
217 * Macro check whether @a itc value is valid (allowed),
218 * macro does not check whether @a itc was really initialised.
219 * @param itc the itc to check
220 * @return boolean true if @a itc has valid value,
221 * boolean false otherwise.
222 */
223#define MHD_ITC_IS_VALID_(itc) (-1 != (itc).fd[0])
224
225/**
226 * Set @a itc to invalid value.
227 * @param itc the itc to set
228 */
229#define MHD_itc_set_invalid_(itc) ((itc).fd[0] = (itc).fd[1] = -1)
230
231#ifndef HAVE_PIPE2_FUNC
232 /**
233 * Change itc FD options to be non-blocking.
234 *
235 * @param fd the FD to manipulate
236 * @return non-zero if succeeded, zero otherwise
237 */
238 int
239 MHD_itc_nonblocking_ (struct MHD_itc_ itc);
240#endif /* ! HAVE_PIPE2_FUNC */
241
242
243#elif defined(_MHD_ITC_SOCKETPAIR)
244
245/* **************** ITC implementation by socket pair ********** */
246
247#include "mhd_sockets.h"
248
249
250/**
251 * Initialise ITC by generating socketpair
252 * @param itc the itc to initialise
253 * @return non-zero if succeeded, zero otherwise
254 */
255#ifdef MHD_socket_pair_nblk_
256# define MHD_itc_init_(itc) MHD_socket_pair_nblk_((itc).sk)
257#else /* ! MHD_socket_pair_nblk_ */
258# define MHD_itc_init_(itc) \
259 (MHD_socket_pair_((itc).sk) ? \
260 (MHD_itc_nonblocking_((itc)) ? \
261 (!0) : \
262 (MHD_itc_destroy_((itc)), 0) ) \
263 : (0))
264#endif /* ! MHD_socket_pair_nblk_ */
265
266/**
267 * Get description string of last error for itc operations.
268 */
269#define MHD_itc_last_strerror_() MHD_socket_last_strerr_()
270
271/**
272 * Activate signal on @a itc
273 * @param itc the itc to use
274 * @param str one-symbol string, useful only for strace debug
275 * @return non-zero if succeeded, zero otherwise
276 */
277#define MHD_itc_activate_(itc, str) \
278 ((MHD_send_((itc).sk[1], (str), 1) > 0) || \
279 (MHD_SCKT_ERR_IS_EAGAIN_(MHD_socket_get_error_())))
280
281/**
282 * Return read FD of @a itc which can be used for poll(), select() etc.
283 * @param itc the itc to get FD
284 * @return FD of read side
285 */
286#define MHD_itc_r_fd_(itc) ((itc).sk[0])
287
288/**
289 * Return write FD of @a itc
290 * @param itc the itc to get FD
291 * @return FD of write side
292 */
293#define MHD_itc_w_fd_(itc) ((itc).sk[1])
294
295/**
296 * Clear signaled state on @a itc
297 * @param itc the itc to clear
298 */
299#define MHD_itc_clear_(itc) do \
300 { long __b; \
301 while(0 < recv((itc).sk[0], \
302 (char*)&__b, \
303 sizeof(__b), 0)) \
304 {} } while(0)
305
306/**
307 * Destroy previously initialised ITC
308 * @param itc the itc to destroy
309 * @return non-zero if succeeded, zero otherwise
310 */
311#define MHD_itc_destroy_(itc) \
312 ( MHD_socket_close_((itc).sk[0]) ? \
313 MHD_socket_close_((itc).sk[1]) : \
314 ((void)MHD_socket_close_((itc).sk[1]), 0) )
315
316
317/**
318 * Check whether ITC has valid value.
319 *
320 * Macro check whether @a itc value is valid (allowed),
321 * macro does not check whether @a itc was really initialised.
322 * @param itc the itc to check
323 * @return boolean true if @a itc has valid value,
324 * boolean false otherwise.
325 */
326#define MHD_ITC_IS_VALID_(itc) (MHD_INVALID_SOCKET != (itc).sk[0])
327
328/**
329 * Set @a itc to invalid value.
330 * @param itc the itc to set
331 */
332#define MHD_itc_set_invalid_(itc) ((itc).sk[0] = (itc).sk[1] = MHD_INVALID_SOCKET)
333
334#ifndef MHD_socket_pair_nblk_
335# define MHD_itc_nonblocking_(pip) (MHD_socket_nonblocking_((pip).sk[0]) && MHD_socket_nonblocking_((pip).sk[1]))
336#endif /* ! MHD_socket_pair_nblk_ */
337
338#endif /* _MHD_ITC_SOCKETPAIR */
339
340/**
341 * Destroy previously initialised ITC and abort execution
342 * if error is detected.
343 * @param itc the itc to destroy
344 */
345#define MHD_itc_destroy_chk_(itc) do { \
346 if (!MHD_itc_destroy_(itc)) \
347 MHD_PANIC(_("Failed to destroy ITC.\n")); \
348 } while(0)
349
350/**
351 * Check whether ITC has invalid value.
352 *
353 * Macro check whether @a itc value is invalid,
354 * macro does not check whether @a itc was destroyed.
355 * @param itc the itc to check
356 * @return boolean true if @a itc has invalid value,
357 * boolean false otherwise.
358 */
359#define MHD_ITC_IS_INVALID_(itc) (! MHD_ITC_IS_VALID_(itc))
360
361#endif /* MHD_ITC_H */
diff --git a/src/lib/mhd_itc_types.h b/src/lib/mhd_itc_types.h
new file mode 100644
index 00000000..04966d36
--- /dev/null
+++ b/src/lib/mhd_itc_types.h
@@ -0,0 +1,77 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2016 Karlson2k (Evgeny Grin), Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file microhttpd/mhd_itc_types.h
23 * @brief Types for platform-independent inter-thread communication
24 * @author Karlson2k (Evgeny Grin)
25 * @author Christian Grothoff
26 *
27 * Provides basic types for inter-thread communication.
28 * Designed to be included by other headers.
29 */
30#ifndef MHD_ITC_TYPES_H
31#define MHD_ITC_TYPES_H 1
32#include "mhd_options.h"
33
34/* Force socketpair on native W32 */
35#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(_MHD_ITC_SOCKETPAIR)
36#error _MHD_ITC_SOCKETPAIR is not defined on naitive W32 platform
37#endif /* _WIN32 && !__CYGWIN__ && !_MHD_ITC_SOCKETPAIR */
38
39#if defined(_MHD_ITC_EVENTFD)
40/* **************** Optimized GNU/Linux ITC implementation by eventfd ********** */
41
42/**
43 * Data type for a MHD ITC.
44 */
45struct MHD_itc_
46{
47 int fd;
48};
49
50#elif defined(_MHD_ITC_PIPE)
51/* **************** Standard UNIX ITC implementation by pipe ********** */
52
53/**
54 * Data type for a MHD ITC.
55 */
56struct MHD_itc_
57{
58 int fd[2];
59};
60
61
62#elif defined(_MHD_ITC_SOCKETPAIR)
63/* **************** ITC implementation by socket pair ********** */
64
65#include "mhd_sockets.h"
66
67/**
68 * Data type for a MHD ITC.
69 */
70struct MHD_itc_
71{
72 MHD_socket sk[2];
73};
74
75#endif /* _MHD_ITC_SOCKETPAIR */
76
77#endif /* ! MHD_ITC_TYPES_H */
diff --git a/src/lib/mhd_limits.h b/src/lib/mhd_limits.h
new file mode 100644
index 00000000..1b0f5d7d
--- /dev/null
+++ b/src/lib/mhd_limits.h
@@ -0,0 +1,146 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2015 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file microhttpd/mhd_limits.h
22 * @brief limits values definitions
23 * @author Karlson2k (Evgeny Grin)
24 */
25
26#ifndef MHD_LIMITS_H
27#define MHD_LIMITS_H
28
29#include "platform.h"
30
31#ifdef HAVE_LIMITS_H
32#include <limits.h>
33#endif /* HAVE_LIMITS_H */
34
35#define MHD_UNSIGNED_TYPE_MAX_(type) ((type)-1)
36/* Assume 8 bits per byte, no padding bits. */
37#define MHD_SIGNED_TYPE_MAX_(type) \
38 ( (type)((( ((type)1) << (sizeof(type)*8 - 2)) - 1)*2 + 1) )
39#define MHD_TYPE_IS_SIGNED_(type) (((type)0)>((type)-1))
40
41#ifndef UINT_MAX
42#ifdef __UINT_MAX__
43#define UINT_MAX __UINT_MAX__
44#else /* ! __UINT_MAX__ */
45#define UINT_MAX MHD_UNSIGNED_TYPE_MAX_(unsigned int)
46#endif /* ! __UINT_MAX__ */
47#endif /* !UINT_MAX */
48
49#ifndef LONG_MAX
50#ifdef __LONG_MAX__
51#define LONG_MAX __LONG_MAX__
52#else /* ! __LONG_MAX__ */
53#define LONG_MAX MHD_SIGNED_TYPE_MAX(long)
54#endif /* ! __LONG_MAX__ */
55#endif /* !OFF_T_MAX */
56
57#ifndef ULLONG_MAX
58#define ULLONG_MAX MHD_UNSIGNED_TYPE_MAX_(MHD_UNSIGNED_LONG_LONG)
59#endif /* !ULLONG_MAX */
60
61#ifndef INT32_MAX
62#ifdef __INT32_MAX__
63#define INT32_MAX __INT32_MAX__
64#else /* ! __INT32_MAX__ */
65#define INT32_MAX ((int32_t)0x7FFFFFFF)
66#endif /* ! __INT32_MAX__ */
67#endif /* !INT32_MAX */
68
69#ifndef UINT32_MAX
70#ifdef __UINT32_MAX__
71#define UINT32_MAX __UINT32_MAX__
72#else /* ! __UINT32_MAX__ */
73#define UINT32_MAX ((int32_t)0xFFFFFFFF)
74#endif /* ! __UINT32_MAX__ */
75#endif /* !UINT32_MAX */
76
77#ifndef UINT64_MAX
78#ifdef __UINT64_MAX__
79#define UINT64_MAX __UINT64_MAX__
80#else /* ! __UINT64_MAX__ */
81#define UINT64_MAX ((uint64_t)0xFFFFFFFFFFFFFFFF)
82#endif /* ! __UINT64_MAX__ */
83#endif /* !UINT64_MAX */
84
85#ifndef INT64_MAX
86#ifdef __INT64_MAX__
87#define INT64_MAX __INT64_MAX__
88#else /* ! __INT64_MAX__ */
89#define INT64_MAX ((int64_t)0x7FFFFFFFFFFFFFFF)
90#endif /* ! __UINT64_MAX__ */
91#endif /* !INT64_MAX */
92
93#ifndef SIZE_MAX
94#ifdef __SIZE_MAX__
95#define SIZE_MAX __SIZE_MAX__
96#elif defined(UINTPTR_MAX)
97#define SIZE_MAX UINTPTR_MAX
98#else /* ! __SIZE_MAX__ */
99#define SIZE_MAX MHD_UNSIGNED_TYPE_MAX_(size_t)
100#endif /* ! __SIZE_MAX__ */
101#endif /* !SIZE_MAX */
102
103#ifndef SSIZE_MAX
104#ifdef __SSIZE_MAX__
105#define SSIZE_MAX __SSIZE_MAX__
106#elif defined(PTRDIFF_MAX)
107#define SSIZE_MAX PTRDIFF_MAX
108#elif defined(INTPTR_MAX)
109#define SSIZE_MAX INTPTR_MAX
110#else
111#define SSIZE_MAN MHD_SIGNED_TYPE_MAX_(ssize_t)
112#endif
113#endif /* ! SSIZE_MAX */
114
115#ifndef OFF_T_MAX
116#ifdef OFF_MAX
117#define OFF_T_MAX OFF_MAX
118#elif defined(OFFT_MAX)
119#define OFF_T_MAX OFFT_MAX
120#elif defined(__APPLE__) && defined(__MACH__)
121#define OFF_T_MAX INT64_MAX
122#else
123#define OFF_T_MAX MHD_SIGNED_TYPE_MAX_(off_t)
124#endif
125#endif /* !OFF_T_MAX */
126
127#if defined(_LARGEFILE64_SOURCE) && !defined(OFF64_T_MAX)
128#define OFF64_T_MAX MHD_SIGNED_TYPE_MAX_(uint64_t)
129#endif /* _LARGEFILE64_SOURCE && !OFF64_T_MAX */
130
131#ifndef TIME_T_MAX
132#define TIME_T_MAX ((time_t) \
133 ( MHD_TYPE_IS_SIGNED_(time_t) ? \
134 MHD_SIGNED_TYPE_MAX_(time_t) : \
135 MHD_UNSIGNED_TYPE_MAX_(time_t)))
136#endif /* !TIME_T_MAX */
137
138#ifndef TIMEVAL_TV_SEC_MAX
139#ifndef _WIN32
140#define TIMEVAL_TV_SEC_MAX TIME_T_MAX
141#else /* _WIN32 */
142#define TIMEVAL_TV_SEC_MAX LONG_MAX
143#endif /* _WIN32 */
144#endif /* !TIMEVAL_TV_SEC_MAX */
145
146#endif /* MHD_LIMITS_H */
diff --git a/src/lib/mhd_locks.h b/src/lib/mhd_locks.h
new file mode 100644
index 00000000..21db56c4
--- /dev/null
+++ b/src/lib/mhd_locks.h
@@ -0,0 +1,183 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2016 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file microhttpd/mhd_locks.h
23 * @brief Header for platform-independent locks abstraction
24 * @author Karlson2k (Evgeny Grin)
25 * @author Christian Grothoff
26 *
27 * Provides basic abstraction for locks/mutex.
28 * Any functions can be implemented as macro on some platforms
29 * unless explicitly marked otherwise.
30 * Any function argument can be skipped in macro, so avoid
31 * variable modification in function parameters.
32 *
33 * @warning Unlike pthread functions, most of functions return
34 * nonzero on success.
35 */
36
37#ifndef MHD_LOCKS_H
38#define MHD_LOCKS_H 1
39
40#include "mhd_options.h"
41
42#if defined(MHD_USE_W32_THREADS)
43# define MHD_W32_MUTEX_ 1
44# ifndef WIN32_LEAN_AND_MEAN
45# define WIN32_LEAN_AND_MEAN 1
46# endif /* !WIN32_LEAN_AND_MEAN */
47# include <windows.h>
48#elif defined(HAVE_PTHREAD_H) && defined(MHD_USE_POSIX_THREADS)
49# define MHD_PTHREAD_MUTEX_ 1
50# undef HAVE_CONFIG_H
51# include <pthread.h>
52# define HAVE_CONFIG_H 1
53#else
54# error No base mutex API is available.
55#endif
56
57#ifndef MHD_PANIC
58# include <stdio.h>
59# include <stdlib.h>
60/* Simple implementation of MHD_PANIC, to be used outside lib */
61# define MHD_PANIC(msg) do { fprintf (stderr, \
62 "Abnormal termination at %d line in file %s: %s\n", \
63 (int)__LINE__, __FILE__, msg); abort();} while(0)
64#endif /* ! MHD_PANIC */
65
66#if defined(MHD_PTHREAD_MUTEX_)
67 typedef pthread_mutex_t MHD_mutex_;
68#elif defined(MHD_W32_MUTEX_)
69 typedef CRITICAL_SECTION MHD_mutex_;
70#endif
71
72#if defined(MHD_PTHREAD_MUTEX_)
73/**
74 * Initialise new mutex.
75 * @param pmutex pointer to the mutex
76 * @return nonzero on success, zero otherwise
77 */
78#define MHD_mutex_init_(pmutex) (!(pthread_mutex_init((pmutex), NULL)))
79#elif defined(MHD_W32_MUTEX_)
80/**
81 * Initialise new mutex.
82 * @param pmutex pointer to mutex
83 * @return nonzero on success, zero otherwise
84 */
85#define MHD_mutex_init_(pmutex) (InitializeCriticalSectionAndSpinCount((pmutex),16))
86#endif
87
88#if defined(MHD_PTHREAD_MUTEX_)
89# if defined(PTHREAD_MUTEX_INITIALIZER)
90/**
91 * Define static mutex and statically initialise it.
92 */
93# define MHD_MUTEX_STATIC_DEFN_INIT_(m) static MHD_mutex_ m = PTHREAD_MUTEX_INITIALIZER
94# endif /* PTHREAD_MUTEX_INITIALIZER */
95#endif
96
97#if defined(MHD_PTHREAD_MUTEX_)
98/**
99 * Destroy previously initialised mutex.
100 * @param pmutex pointer to mutex
101 * @return nonzero on success, zero otherwise
102 */
103#define MHD_mutex_destroy_(pmutex) (!(pthread_mutex_destroy((pmutex))))
104#elif defined(MHD_W32_MUTEX_)
105/**
106 * Destroy previously initialised mutex.
107 * @param pmutex pointer to mutex
108 * @return Always nonzero
109 */
110#define MHD_mutex_destroy_(pmutex) (DeleteCriticalSection((pmutex)), !0)
111#endif
112
113/**
114 * Destroy previously initialised mutex and abort execution
115 * if error is detected.
116 * @param pmutex pointer to mutex
117 */
118#define MHD_mutex_destroy_chk_(pmutex) do { \
119 if (!MHD_mutex_destroy_(pmutex)) \
120 MHD_PANIC(_("Failed to destroy mutex.\n")); \
121 } while(0)
122
123
124#if defined(MHD_PTHREAD_MUTEX_)
125/**
126 * Acquire lock on previously initialised mutex.
127 * If mutex was already locked by other thread, function
128 * blocks until mutex becomes available.
129 * @param pmutex pointer to mutex
130 * @return nonzero on success, zero otherwise
131 */
132#define MHD_mutex_lock_(pmutex) (!(pthread_mutex_lock((pmutex))))
133#elif defined(MHD_W32_MUTEX_)
134/**
135 * Acquire lock on previously initialised mutex.
136 * If mutex was already locked by other thread, function
137 * blocks until mutex becomes available.
138 * @param pmutex pointer to mutex
139 * @return Always nonzero
140 */
141#define MHD_mutex_lock_(pmutex) (EnterCriticalSection((pmutex)), !0)
142#endif
143
144/**
145 * Acquire lock on previously initialised mutex.
146 * If mutex was already locked by other thread, function
147 * blocks until mutex becomes available.
148 * If error is detected, execution will be aborted.
149 * @param pmutex pointer to mutex
150 */
151#define MHD_mutex_lock_chk_(pmutex) do { \
152 if (!MHD_mutex_lock_(pmutex)) \
153 MHD_PANIC(_("Failed to lock mutex.\n")); \
154 } while(0)
155
156#if defined(MHD_PTHREAD_MUTEX_)
157/**
158 * Unlock previously initialised and locked mutex.
159 * @param pmutex pointer to mutex
160 * @return nonzero on success, zero otherwise
161 */
162#define MHD_mutex_unlock_(pmutex) (!(pthread_mutex_unlock((pmutex))))
163#elif defined(MHD_W32_MUTEX_)
164/**
165 * Unlock previously initialised and locked mutex.
166 * @param pmutex pointer to mutex
167 * @return Always nonzero
168 */
169#define MHD_mutex_unlock_(pmutex) (LeaveCriticalSection((pmutex)), !0)
170#endif
171
172/**
173 * Unlock previously initialised and locked mutex.
174 * If error is detected, execution will be aborted.
175 * @param pmutex pointer to mutex
176 */
177#define MHD_mutex_unlock_chk_(pmutex) do { \
178 if (!MHD_mutex_unlock_(pmutex)) \
179 MHD_PANIC(_("Failed to unlock mutex.\n")); \
180 } while(0)
181
182
183#endif /* ! MHD_LOCKS_H */
diff --git a/src/lib/mhd_mono_clock.c b/src/lib/mhd_mono_clock.c
new file mode 100644
index 00000000..97dbfb9f
--- /dev/null
+++ b/src/lib/mhd_mono_clock.c
@@ -0,0 +1,377 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2015 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file microhttpd/mhd_mono_clock.h
22 * @brief internal monotonic clock functions implementations
23 * @author Karlson2k (Evgeny Grin)
24 */
25
26#include "mhd_mono_clock.h"
27
28#if defined(_WIN32) && ! defined(__CYGWIN__) && defined(HAVE_CLOCK_GETTIME)
29/* Prefer native clock source over wrappers */
30#undef HAVE_CLOCK_GETTIME
31#endif /* _WIN32 && ! __CYGWIN__ && HAVE_CLOCK_GETTIME */
32
33#ifdef HAVE_CLOCK_GETTIME
34#include <time.h>
35#endif /* HAVE_CLOCK_GETTIME */
36
37#ifdef HAVE_GETHRTIME
38#ifdef HAVE_SYS_TIME_H
39/* Solaris defines gethrtime() in sys/time.h */
40#include <sys/time.h>
41#endif /* HAVE_SYS_TIME_H */
42#ifdef HAVE_TIME_H
43/* HP-UX defines gethrtime() in time.h */
44#include <time.h>
45#endif /* HAVE_TIME_H */
46#endif /* HAVE_GETHRTIME */
47
48#ifdef HAVE_CLOCK_GET_TIME
49#include <mach/mach.h>
50/* for host_get_clock_service(), mach_host_self(), mach_task_self() */
51#include <mach/clock.h>
52/* for clock_get_time() */
53
54#define _MHD_INVALID_CLOCK_SERV ((clock_serv_t) -2)
55
56static clock_serv_t mono_clock_service = _MHD_INVALID_CLOCK_SERV;
57#endif /* HAVE_CLOCK_GET_TIME */
58
59#ifdef _WIN32
60#ifndef WIN32_LEAN_AND_MEAN
61/* Do not include unneeded parts of W32 headers. */
62#define WIN32_LEAN_AND_MEAN 1
63#endif /* !WIN32_LEAN_AND_MEAN */
64#include <windows.h>
65#include <stdint.h>
66#endif /* _WIN32 */
67
68#ifdef HAVE_CLOCK_GETTIME
69#ifdef CLOCK_REALTIME
70#define _MHD_UNWANTED_CLOCK CLOCK_REALTIME
71#else /* !CLOCK_REALTIME */
72#define _MHD_UNWANTED_CLOCK ((clockid_t) -2)
73#endif /* !CLOCK_REALTIME */
74
75static clockid_t mono_clock_id = _MHD_UNWANTED_CLOCK;
76#endif /* HAVE_CLOCK_GETTIME */
77
78/* sync clocks; reduce chance of value wrap */
79#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_GET_TIME) || defined(HAVE_GETHRTIME)
80static time_t mono_clock_start;
81#endif /* HAVE_CLOCK_GETTIME || HAVE_CLOCK_GET_TIME || HAVE_GETHRTIME */
82static time_t sys_clock_start;
83#ifdef HAVE_GETHRTIME
84static hrtime_t hrtime_start;
85#endif /* HAVE_GETHRTIME */
86#ifdef _WIN32
87#if _WIN32_WINNT >= 0x0600
88static uint64_t tick_start;
89#else /* _WIN32_WINNT < 0x0600 */
90static int64_t perf_freq;
91static int64_t perf_start;
92#endif /* _WIN32_WINNT < 0x0600 */
93#endif /* _WIN32 */
94
95
96
97/**
98 * Type of monotonic clock source
99 */
100enum _MHD_mono_clock_source
101{
102 /**
103 * No monotonic clock
104 */
105 _MHD_CLOCK_NO_SOURCE = 0,
106
107 /**
108 * clock_gettime() with specific clock
109 */
110 _MHD_CLOCK_GETTIME,
111
112 /**
113 * clock_get_time() with specific clock service
114 */
115 _MHD_CLOCK_GET_TIME,
116
117 /**
118 * gethrtime() / 1000000000
119 */
120 _MHD_CLOCK_GETHRTIME,
121
122 /**
123 * GetTickCount64() / 1000
124 */
125 _MHD_CLOCK_GETTICKCOUNT64,
126
127 /**
128 * QueryPerformanceCounter() / QueryPerformanceFrequency()
129 */
130 _MHD_CLOCK_PERFCOUNTER
131};
132
133
134/**
135 * Initialise monotonic seconds counter.
136 */
137void
138MHD_monotonic_sec_counter_init (void)
139{
140#ifdef HAVE_CLOCK_GET_TIME
141 mach_timespec_t cur_time;
142#endif /* HAVE_CLOCK_GET_TIME */
143 enum _MHD_mono_clock_source mono_clock_source = _MHD_CLOCK_NO_SOURCE;
144#ifdef HAVE_CLOCK_GETTIME
145 struct timespec ts;
146
147 mono_clock_id = _MHD_UNWANTED_CLOCK;
148#endif /* HAVE_CLOCK_GETTIME */
149#ifdef HAVE_CLOCK_GET_TIME
150 mono_clock_service = _MHD_INVALID_CLOCK_SERV;
151#endif /* HAVE_CLOCK_GET_TIME */
152
153 /* just a little syntactic trick to get the
154 various following ifdef's to work out nicely */
155 if (0)
156 {
157 }
158 else
159#ifdef HAVE_CLOCK_GETTIME
160#ifdef CLOCK_MONOTONIC_COARSE
161 /* Linux-specific fast value-getting clock */
162 /* Can be affected by frequency adjustment and don't count time in suspend, */
163 /* but preferred since it's fast */
164 if (0 == clock_gettime (CLOCK_MONOTONIC_COARSE,
165 &ts))
166 {
167 mono_clock_id = CLOCK_MONOTONIC_COARSE;
168 mono_clock_start = ts.tv_sec;
169 mono_clock_source = _MHD_CLOCK_GETTIME;
170 }
171 else
172#endif /* CLOCK_MONOTONIC_COARSE */
173#ifdef CLOCK_MONOTONIC_FAST
174 /* FreeBSD/DragonFly fast value-getting clock */
175 /* Can be affected by frequency adjustment, but preferred since it's fast */
176 if (0 == clock_gettime (CLOCK_MONOTONIC_FAST,
177 &ts))
178 {
179 mono_clock_id = CLOCK_MONOTONIC_FAST;
180 mono_clock_start = ts.tv_sec;
181 mono_clock_source = _MHD_CLOCK_GETTIME;
182 }
183 else
184#endif /* CLOCK_MONOTONIC_COARSE */
185#ifdef CLOCK_MONOTONIC_RAW
186 /* Linux-specific clock */
187 /* Not affected by frequency adjustment, but don't count time in suspend */
188 if (0 == clock_gettime (CLOCK_MONOTONIC_RAW,
189 &ts))
190 {
191 mono_clock_id = CLOCK_MONOTONIC_RAW;
192 mono_clock_start = ts.tv_sec;
193 mono_clock_source = _MHD_CLOCK_GETTIME;
194 }
195 else
196#endif /* CLOCK_MONOTONIC_RAW */
197#ifdef CLOCK_BOOTTIME
198 /* Linux-specific clock */
199 /* Count time in suspend so it's real monotonic on Linux, */
200 /* but can be slower value-getting than other clocks */
201 if (0 == clock_gettime (CLOCK_BOOTTIME,
202 &ts))
203 {
204 mono_clock_id = CLOCK_BOOTTIME;
205 mono_clock_start = ts.tv_sec;
206 mono_clock_source = _MHD_CLOCK_GETTIME;
207 }
208 else
209#endif /* CLOCK_BOOTTIME */
210#ifdef CLOCK_MONOTONIC
211 /* Monotonic clock */
212 /* Widely supported, may be affected by frequency adjustment */
213 /* On Linux it's not truly monotonic as it doesn't count time in suspend */
214 if (0 == clock_gettime (CLOCK_MONOTONIC,
215 &ts))
216 {
217 mono_clock_id = CLOCK_MONOTONIC;
218 mono_clock_start = ts.tv_sec;
219 mono_clock_source = _MHD_CLOCK_GETTIME;
220 }
221 else
222#endif /* CLOCK_BOOTTIME */
223#endif /* HAVE_CLOCK_GETTIME */
224#ifdef HAVE_CLOCK_GET_TIME
225 /* Darwin-specific monotonic clock */
226 /* Should be monotonic as clock_set_time function always unconditionally */
227 /* failed on latest kernels */
228 if ( (KERN_SUCCESS == host_get_clock_service (mach_host_self(),
229 SYSTEM_CLOCK,
230 &mono_clock_service)) &&
231 (KERN_SUCCESS == clock_get_time (mono_clock_service,
232 &cur_time)) )
233 {
234 mono_clock_start = cur_time.tv_sec;
235 mono_clock_source = _MHD_CLOCK_GET_TIME;
236 }
237 else
238#endif /* HAVE_CLOCK_GET_TIME */
239#ifdef _WIN32
240#if _WIN32_WINNT >= 0x0600
241 /* W32 Vista or later specific monotonic clock */
242 /* Available since Vista, ~15ms accuracy */
243 if (1)
244 {
245 tick_start = GetTickCount64 ();
246 mono_clock_source = _MHD_CLOCK_GETTICKCOUNT64;
247 }
248 else
249#else /* _WIN32_WINNT < 0x0600 */
250 /* W32 specific monotonic clock */
251 /* Available on Windows 2000 and later */
252 if (1)
253 {
254 LARGE_INTEGER freq;
255 LARGE_INTEGER perf_counter;
256
257 QueryPerformanceFrequency (&freq); /* never fail on XP and later */
258 QueryPerformanceCounter (&perf_counter); /* never fail on XP and later */
259 perf_freq = freq.QuadPart;
260 perf_start = perf_counter.QuadPart;
261 mono_clock_source = _MHD_CLOCK_PERFCOUNTER;
262 }
263 else
264#endif /* _WIN32_WINNT < 0x0600 */
265#endif /* _WIN32 */
266#ifdef HAVE_CLOCK_GETTIME
267#ifdef CLOCK_HIGHRES
268 /* Solaris-specific monotonic high-resolution clock */
269 /* Not preferred due to be potentially resource-hungry */
270 if (0 == clock_gettime (CLOCK_HIGHRES,
271 &ts))
272 {
273 mono_clock_id = CLOCK_HIGHRES;
274 mono_clock_start = ts.tv_sec;
275 mono_clock_source = _MHD_CLOCK_GETTIME;
276 }
277 else
278#endif /* CLOCK_HIGHRES */
279#endif /* HAVE_CLOCK_GETTIME */
280#ifdef HAVE_GETHRTIME
281 /* HP-UX and Solaris monotonic clock */
282 /* Not preferred due to be potentially resource-hungry */
283 if (1)
284 {
285 hrtime_start = gethrtime ();
286 mono_clock_source = _MHD_CLOCK_GETHRTIME;
287 }
288 else
289#endif /* HAVE_GETHRTIME */
290 {
291 /* no suitable clock source was found */
292 mono_clock_source = _MHD_CLOCK_NO_SOURCE;
293 }
294
295#ifdef HAVE_CLOCK_GET_TIME
296 if ( (_MHD_CLOCK_GET_TIME != mono_clock_source) &&
297 (_MHD_INVALID_CLOCK_SERV != mono_clock_service) )
298 {
299 /* clock service was initialised but clock_get_time failed */
300 mach_port_deallocate (mach_task_self(),
301 mono_clock_service);
302 mono_clock_service = _MHD_INVALID_CLOCK_SERV;
303 }
304#else
305 (void) mono_clock_source; /* avoid compiler warning */
306#endif /* HAVE_CLOCK_GET_TIME */
307
308 sys_clock_start = time (NULL);
309}
310
311
312/**
313 * Deinitialise monotonic seconds counter by freeing any allocated resources
314 */
315void
316MHD_monotonic_sec_counter_finish (void)
317{
318#ifdef HAVE_CLOCK_GET_TIME
319 if (_MHD_INVALID_CLOCK_SERV != mono_clock_service)
320 {
321 mach_port_deallocate (mach_task_self(),
322 mono_clock_service);
323 mono_clock_service = _MHD_INVALID_CLOCK_SERV;
324 }
325#endif /* HAVE_CLOCK_GET_TIME */
326}
327
328
329/**
330 * Monotonic seconds counter, useful for timeout calculation.
331 * Tries to be not affected by manually setting the system real time
332 * clock or adjustments by NTP synchronization.
333 *
334 * @return number of seconds from some fixed moment
335 */
336time_t
337MHD_monotonic_sec_counter (void)
338{
339#ifdef HAVE_CLOCK_GETTIME
340 struct timespec ts;
341
342 if ( (_MHD_UNWANTED_CLOCK != mono_clock_id) &&
343 (0 == clock_gettime (mono_clock_id ,
344 &ts)) )
345 return ts.tv_sec - mono_clock_start;
346#endif /* HAVE_CLOCK_GETTIME */
347#ifdef HAVE_CLOCK_GET_TIME
348 if (_MHD_INVALID_CLOCK_SERV != mono_clock_service)
349 {
350 mach_timespec_t cur_time;
351
352 if (KERN_SUCCESS == clock_get_time(mono_clock_service,
353 &cur_time))
354 return cur_time.tv_sec - mono_clock_start;
355 }
356#endif /* HAVE_CLOCK_GET_TIME */
357#if defined(_WIN32)
358#if _WIN32_WINNT >= 0x0600
359 if (1)
360 return (time_t)(((uint64_t)(GetTickCount64() - tick_start)) / 1000);
361#else /* _WIN32_WINNT < 0x0600 */
362 if (0 != perf_freq)
363 {
364 LARGE_INTEGER perf_counter;
365
366 QueryPerformanceCounter (&perf_counter); /* never fail on XP and later */
367 return (time_t)(((uint64_t)(perf_counter.QuadPart - perf_start)) / perf_freq);
368 }
369#endif /* _WIN32_WINNT < 0x0600 */
370#endif /* _WIN32 */
371#ifdef HAVE_GETHRTIME
372 if (1)
373 return (time_t)(((uint64_t) (gethrtime () - hrtime_start)) / 1000000000);
374#endif /* HAVE_GETHRTIME */
375
376 return time (NULL) - sys_clock_start;
377}
diff --git a/src/lib/mhd_mono_clock.h b/src/lib/mhd_mono_clock.h
new file mode 100644
index 00000000..f4722af2
--- /dev/null
+++ b/src/lib/mhd_mono_clock.h
@@ -0,0 +1,60 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2015 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file microhttpd/mhd_mono_clock.h
22 * @brief internal monotonic clock functions declarations
23 * @author Karlson2k (Evgeny Grin)
24 */
25
26#ifndef MHD_MONO_CLOCK_H
27#define MHD_MONO_CLOCK_H 1
28#include "mhd_options.h"
29
30#if defined(HAVE_TIME_H)
31#include <time.h>
32#elif defined(HAVE_SYS_TYPES_H)
33#include <sys/types.h>
34#endif
35
36/**
37 * Initialise monotonic seconds counter.
38 */
39void
40MHD_monotonic_sec_counter_init(void);
41
42
43/**
44 * Deinitialise monotonic seconds counter by freeing any allocated resources
45 */
46void
47MHD_monotonic_sec_counter_finish(void);
48
49
50/**
51 * Monotonic seconds counter, useful for timeout calculation.
52 * Tries to be not affected by manually setting the system real time
53 * clock or adjustments by NTP synchronization.
54 *
55 * @return number of seconds from some fixed moment
56 */
57time_t
58MHD_monotonic_sec_counter(void);
59
60#endif /* MHD_MONO_CLOCK_H */
diff --git a/src/lib/mhd_sockets.c b/src/lib/mhd_sockets.c
new file mode 100644
index 00000000..ddcc1f25
--- /dev/null
+++ b/src/lib/mhd_sockets.c
@@ -0,0 +1,523 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2014-2016 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file microhttpd/mhd_sockets.c
23 * @brief Implementation for sockets functions
24 * @author Karlson2k (Evgeny Grin)
25 */
26
27#include "mhd_sockets.h"
28#ifdef HAVE_UNISTD_H
29#include <unistd.h>
30#endif /* HAVE_UNISTD_H */
31#include <fcntl.h>
32
33#ifdef MHD_WINSOCK_SOCKETS
34
35/**
36 * Return pointer to string description of specified WinSock error
37 * @param err the WinSock error code.
38 * @return pointer to string description of specified WinSock error.
39 */
40const char* MHD_W32_strerror_winsock_(int err)
41{
42 switch (err)
43 {
44 case 0:
45 return "No error";
46 case WSA_INVALID_HANDLE:
47 return "Specified event object handle is invalid";
48 case WSA_NOT_ENOUGH_MEMORY:
49 return "Insufficient memory available";
50 case WSA_INVALID_PARAMETER:
51 return "One or more parameters are invalid";
52 case WSA_OPERATION_ABORTED:
53 return "Overlapped operation aborted";
54 case WSA_IO_INCOMPLETE:
55 return "Overlapped I/O event object not in signaled state";
56 case WSA_IO_PENDING:
57 return "Overlapped operations will complete later";
58 case WSAEINTR:
59 return "Interrupted function call";
60 case WSAEBADF:
61 return "File handle is not valid";
62 case WSAEACCES:
63 return "Permission denied";
64 case WSAEFAULT:
65 return "Bad address";
66 case WSAEINVAL:
67 return "Invalid argument";
68 case WSAEMFILE:
69 return "Too many open files";
70 case WSAEWOULDBLOCK:
71 return "Resource temporarily unavailable";
72 case WSAEINPROGRESS:
73 return "Operation now in progress";
74 case WSAEALREADY:
75 return "Operation already in progress";
76 case WSAENOTSOCK:
77 return "Socket operation on nonsocket";
78 case WSAEDESTADDRREQ:
79 return "Destination address required";
80 case WSAEMSGSIZE:
81 return "Message too long";
82 case WSAEPROTOTYPE:
83 return "Protocol wrong type for socket";
84 case WSAENOPROTOOPT:
85 return "Bad protocol option";
86 case WSAEPROTONOSUPPORT:
87 return "Protocol not supported";
88 case WSAESOCKTNOSUPPORT:
89 return "Socket type not supported";
90 case WSAEOPNOTSUPP:
91 return "Operation not supported";
92 case WSAEPFNOSUPPORT:
93 return "Protocol family not supported";
94 case WSAEAFNOSUPPORT:
95 return "Address family not supported by protocol family";
96 case WSAEADDRINUSE:
97 return "Address already in use";
98 case WSAEADDRNOTAVAIL:
99 return "Cannot assign requested address";
100 case WSAENETDOWN:
101 return "Network is down";
102 case WSAENETUNREACH:
103 return "Network is unreachable";
104 case WSAENETRESET:
105 return "Network dropped connection on reset";
106 case WSAECONNABORTED:
107 return "Software caused connection abort";
108 case WSAECONNRESET:
109 return "Connection reset by peer";
110 case WSAENOBUFS:
111 return "No buffer space available";
112 case WSAEISCONN:
113 return "Socket is already connected";
114 case WSAENOTCONN:
115 return "Socket is not connected";
116 case WSAESHUTDOWN:
117 return "Cannot send after socket shutdown";
118 case WSAETOOMANYREFS:
119 return "Too many references";
120 case WSAETIMEDOUT:
121 return "Connection timed out";
122 case WSAECONNREFUSED:
123 return "Connection refused";
124 case WSAELOOP:
125 return "Cannot translate name";
126 case WSAENAMETOOLONG:
127 return "Name too long";
128 case WSAEHOSTDOWN:
129 return "Host is down";
130 case WSAEHOSTUNREACH:
131 return "No route to host";
132 case WSAENOTEMPTY:
133 return "Directory not empty";
134 case WSAEPROCLIM:
135 return "Too many processes";
136 case WSAEUSERS:
137 return "User quota exceeded";
138 case WSAEDQUOT:
139 return "Disk quota exceeded";
140 case WSAESTALE:
141 return "Stale file handle reference";
142 case WSAEREMOTE:
143 return "Item is remote";
144 case WSASYSNOTREADY:
145 return "Network subsystem is unavailable";
146 case WSAVERNOTSUPPORTED:
147 return "Winsock.dll version out of range";
148 case WSANOTINITIALISED:
149 return "Successful WSAStartup not yet performed";
150 case WSAEDISCON:
151 return "Graceful shutdown in progress";
152 case WSAENOMORE:
153 return "No more results";
154 case WSAECANCELLED:
155 return "Call has been canceled";
156 case WSAEINVALIDPROCTABLE:
157 return "Procedure call table is invalid";
158 case WSAEINVALIDPROVIDER:
159 return "Service provider is invalid";
160 case WSAEPROVIDERFAILEDINIT:
161 return "Service provider failed to initialize";
162 case WSASYSCALLFAILURE:
163 return "System call failure";
164 case WSASERVICE_NOT_FOUND:
165 return "Service not found";
166 case WSATYPE_NOT_FOUND:
167 return "Class type not found";
168 case WSA_E_NO_MORE:
169 return "No more results";
170 case WSA_E_CANCELLED:
171 return "Call was canceled";
172 case WSAEREFUSED:
173 return "Database query was refused";
174 case WSAHOST_NOT_FOUND:
175 return "Host not found";
176 case WSATRY_AGAIN:
177 return "Nonauthoritative host not found";
178 case WSANO_RECOVERY:
179 return "This is a nonrecoverable error";
180 case WSANO_DATA:
181 return "Valid name, no data record of requested type";
182 case WSA_QOS_RECEIVERS:
183 return "QoS receivers";
184 case WSA_QOS_SENDERS:
185 return "QoS senders";
186 case WSA_QOS_NO_SENDERS:
187 return "No QoS senders";
188 case WSA_QOS_NO_RECEIVERS:
189 return "QoS no receivers";
190 case WSA_QOS_REQUEST_CONFIRMED:
191 return "QoS request confirmed";
192 case WSA_QOS_ADMISSION_FAILURE:
193 return "QoS admission error";
194 case WSA_QOS_POLICY_FAILURE:
195 return "QoS policy failure";
196 case WSA_QOS_BAD_STYLE:
197 return "QoS bad style";
198 case WSA_QOS_BAD_OBJECT:
199 return "QoS bad object";
200 case WSA_QOS_TRAFFIC_CTRL_ERROR:
201 return "QoS traffic control error";
202 case WSA_QOS_GENERIC_ERROR:
203 return "QoS generic error";
204 case WSA_QOS_ESERVICETYPE:
205 return "QoS service type error";
206 case WSA_QOS_EFLOWSPEC:
207 return "QoS flowspec error";
208 case WSA_QOS_EPROVSPECBUF:
209 return "Invalid QoS provider buffer";
210 case WSA_QOS_EFILTERSTYLE:
211 return "Invalid QoS filter style";
212 case WSA_QOS_EFILTERTYPE:
213 return "Invalid QoS filter type";
214 case WSA_QOS_EFILTERCOUNT:
215 return "Incorrect QoS filter count";
216 case WSA_QOS_EOBJLENGTH:
217 return "Invalid QoS object length";
218 case WSA_QOS_EFLOWCOUNT:
219 return "Incorrect QoS flow count";
220 case WSA_QOS_EUNKOWNPSOBJ:
221 return "Unrecognized QoS object";
222 case WSA_QOS_EPOLICYOBJ:
223 return "Invalid QoS policy object";
224 case WSA_QOS_EFLOWDESC:
225 return "Invalid QoS flow descriptor";
226 case WSA_QOS_EPSFLOWSPEC:
227 return "Invalid QoS provider-specific flowspec";
228 case WSA_QOS_EPSFILTERSPEC:
229 return "Invalid QoS provider-specific filterspec";
230 case WSA_QOS_ESDMODEOBJ:
231 return "Invalid QoS shape discard mode object";
232 case WSA_QOS_ESHAPERATEOBJ:
233 return "Invalid QoS shaping rate object";
234 case WSA_QOS_RESERVED_PETYPE:
235 return "Reserved policy QoS element type";
236 }
237 return "Unknown winsock error";
238}
239
240
241/**
242 * Create pair of mutually connected TCP/IP sockets on loopback address
243 * @param sockets_pair array to receive resulted sockets
244 * @param non_blk if set to non-zero value, sockets created in non-blocking mode
245 * otherwise sockets will be in blocking mode
246 * @return non-zero if succeeded, zero otherwise
247 */
248int
249MHD_W32_socket_pair_(SOCKET sockets_pair[2], int non_blk)
250{
251 int i;
252
253 if (! sockets_pair)
254 {
255 WSASetLastError (WSAEFAULT);
256 return 0;
257 }
258
259#define PAIRMAXTRYIES 800
260 for (i = 0; i < PAIRMAXTRYIES; i++)
261 {
262 struct sockaddr_in listen_addr;
263 SOCKET listen_s;
264 static const int c_addinlen = sizeof(struct sockaddr_in); /* help compiler to optimize */
265 int addr_len = c_addinlen;
266 unsigned long on_val = 1;
267 unsigned long off_val = 0;
268
269 listen_s = socket (AF_INET,
270 SOCK_STREAM,
271 IPPROTO_TCP);
272 if (INVALID_SOCKET == listen_s)
273 break; /* can't create even single socket */
274
275 listen_addr.sin_family = AF_INET;
276 listen_addr.sin_port = 0; /* same as htons(0) */
277 listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
278 if ( (0 == bind (listen_s,
279 (struct sockaddr*) &listen_addr,
280 c_addinlen) &&
281 (0 == listen (listen_s,
282 1) ) &&
283 (0 == getsockname (listen_s,
284 (struct sockaddr*) &listen_addr,
285 &addr_len))) )
286 {
287 SOCKET client_s = socket(AF_INET,
288 SOCK_STREAM,
289 IPPROTO_TCP);
290 struct sockaddr_in accepted_from_addr;
291 struct sockaddr_in client_addr;
292 SOCKET server_s;
293
294 if (INVALID_SOCKET == client_s)
295 {
296 /* try again */
297 closesocket (listen_s);
298 continue;
299 }
300
301 if ( (0 != ioctlsocket (client_s,
302 FIONBIO,
303 &on_val)) ||
304 ( (0 != connect (client_s,
305 (struct sockaddr*) &listen_addr,
306 c_addinlen)) &&
307 (WSAGetLastError() != WSAEWOULDBLOCK)) )
308 {
309 /* try again */
310 closesocket (listen_s);
311 closesocket (client_s);
312 continue;
313 }
314
315 addr_len = c_addinlen;
316 server_s = accept (listen_s,
317 (struct sockaddr*) &accepted_from_addr,
318 &addr_len);
319 if (INVALID_SOCKET == server_s)
320 {
321 /* try again */
322 closesocket (listen_s);
323 closesocket (client_s);
324 continue;
325 }
326
327 addr_len = c_addinlen;
328 if ( (0 == getsockname (client_s,
329 (struct sockaddr*) &client_addr,
330 &addr_len)) &&
331 (accepted_from_addr.sin_family == client_addr.sin_family) &&
332 (accepted_from_addr.sin_port == client_addr.sin_port) &&
333 (accepted_from_addr.sin_addr.s_addr == client_addr.sin_addr.s_addr) &&
334 ( (0 != non_blk) ?
335 (0 == ioctlsocket(server_s,
336 FIONBIO,
337 &on_val)) :
338 (0 == ioctlsocket(client_s,
339 FIONBIO,
340 &off_val)) ) )
341 {
342 closesocket (listen_s);
343 sockets_pair[0] = server_s;
344 sockets_pair[1] = client_s;
345 return !0;
346 }
347 closesocket (server_s);
348 closesocket (client_s);
349 }
350 closesocket(listen_s);
351 }
352
353 sockets_pair[0] = INVALID_SOCKET;
354 sockets_pair[1] = INVALID_SOCKET;
355 WSASetLastError(WSAECONNREFUSED);
356
357 return 0;
358}
359
360#endif /* MHD_WINSOCK_SOCKETS */
361
362
363/**
364 * Add @a fd to the @a set. If @a fd is
365 * greater than @a max_fd, set @a max_fd to @a fd.
366 *
367 * @param fd file descriptor to add to the @a set
368 * @param set set to modify
369 * @param max_fd maximum value to potentially update
370 * @param fd_setsize value of FD_SETSIZE
371 * @return non-zero if succeeded, zero otherwise
372 */
373int
374MHD_add_to_fd_set_ (MHD_socket fd,
375 fd_set *set,
376 MHD_socket *max_fd,
377 unsigned int fd_setsize)
378{
379 if ( (NULL == set) ||
380 (MHD_INVALID_SOCKET == fd) )
381 return 0;
382 if (! MHD_SCKT_FD_FITS_FDSET_SETSIZE_ (fd,
383 set,
384 fd_setsize))
385 return 0;
386 MHD_SCKT_ADD_FD_TO_FDSET_SETSIZE_(fd,
387 set,
388 fd_setsize);
389 if ( (NULL != max_fd) &&
390 ( (fd > *max_fd) ||
391 (MHD_INVALID_SOCKET == *max_fd) ) )
392 *max_fd = fd;
393 return ! 0;
394}
395
396
397/**
398 * Change socket options to be non-blocking.
399 *
400 * @param sock socket to manipulate
401 * @return non-zero if succeeded, zero otherwise
402 */
403int
404MHD_socket_nonblocking_ (MHD_socket sock)
405{
406#if defined(MHD_POSIX_SOCKETS)
407 int flags;
408
409 flags = fcntl (sock,
410 F_GETFL);
411 if (-1 == flags)
412 return 0;
413
414 if ( ((flags | O_NONBLOCK) != flags) &&
415 (0 != fcntl (sock,
416 F_SETFL,
417 flags | O_NONBLOCK)) )
418 return 0;
419#elif defined(MHD_WINSOCK_SOCKETS)
420 unsigned long flags = 1;
421
422 if (0 != ioctlsocket (sock,
423 FIONBIO,
424 &flags))
425 return 0;
426#endif /* MHD_WINSOCK_SOCKETS */
427 return !0;
428}
429
430
431/**
432 * Change socket options to be non-inheritable.
433 *
434 * @param sock socket to manipulate
435 * @return non-zero if succeeded, zero otherwise
436 * @warning Does not set socket error on W32.
437 */
438int
439MHD_socket_noninheritable_ (MHD_socket sock)
440{
441#if defined(MHD_POSIX_SOCKETS)
442 int flags;
443
444 flags = fcntl (sock,
445 F_GETFD);
446 if (-1 == flags)
447 return 0;
448
449 if ( ((flags | FD_CLOEXEC) != flags) &&
450 (0 != fcntl (sock,
451 F_SETFD,
452 flags | FD_CLOEXEC)) )
453 return 0;
454#elif defined(MHD_WINSOCK_SOCKETS)
455 if (! SetHandleInformation ((HANDLE)sock,
456 HANDLE_FLAG_INHERIT,
457 0))
458 return 0;
459#endif /* MHD_WINSOCK_SOCKETS */
460 return !0;
461}
462
463
464/**
465 * Create a listen socket, with noninheritable flag if possible.
466 *
467 * @param use_ipv6 if set to non-zero IPv6 is used
468 * @return created socket or MHD_INVALID_SOCKET in case of errors
469 */
470MHD_socket
471MHD_socket_create_listen_ (bool use_ipv6)
472{
473 int domain;
474 MHD_socket fd;
475 int cloexec_set;
476
477#ifdef HAVE_INET6
478 domain = (use_ipv6) ? PF_INET6 : PF_INET;
479#else /* ! HAVE_INET6 */
480 if (use_ipv6)
481 return MHD_INVALID_SOCKET;
482 domain = PF_INET;
483#endif /* ! HAVE_INET6 */
484
485#if defined(MHD_POSIX_SOCKETS) && defined(SOCK_CLOEXEC)
486 fd = socket (domain,
487 SOCK_STREAM | SOCK_CLOEXEC,
488 0);
489 cloexec_set = !0;
490#elif defined(MHD_WINSOCK_SOCKETS) && defined (WSA_FLAG_NO_HANDLE_INHERIT)
491 fd = WSASocketW (domain,
492 SOCK_STREAM,
493 0,
494 NULL,
495 0,
496 WSA_FLAG_NO_HANDLE_INHERIT);
497 cloexec_set = !0;
498#else /* !SOCK_CLOEXEC */
499 fd = MHD_INVALID_SOCKET;
500#endif /* !SOCK_CLOEXEC */
501 if (MHD_INVALID_SOCKET == fd)
502 {
503 fd = socket (domain,
504 SOCK_STREAM,
505 0);
506 cloexec_set = 0;
507 }
508 if (MHD_INVALID_SOCKET == fd)
509 return MHD_INVALID_SOCKET;
510#ifdef MHD_socket_nosignal_
511 if(! MHD_socket_nosignal_(fd))
512 {
513 const int err = MHD_socket_get_error_ ();
514 (void) MHD_socket_close_ (fd);
515 MHD_socket_fset_error_ (err);
516 return MHD_INVALID_SOCKET;
517 }
518#endif /* MHD_socket_nosignal_ */
519 if (! cloexec_set)
520 (void) MHD_socket_noninheritable_ (fd);
521
522 return fd;
523}
diff --git a/src/lib/mhd_sockets.h b/src/lib/mhd_sockets.h
new file mode 100644
index 00000000..c999ea35
--- /dev/null
+++ b/src/lib/mhd_sockets.h
@@ -0,0 +1,760 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2014-2016 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file microhttpd/mhd_sockets.c
23 * @brief Header for platform-independent sockets abstraction
24 * @author Karlson2k (Evgeny Grin)
25 *
26 * Provides basic abstraction for sockets.
27 * Any functions can be implemented as macro on some platforms
28 * unless explicitly marked otherwise.
29 * Any function argument can be skipped in macro, so avoid
30 * variable modification in function parameters.
31 */
32
33#ifndef MHD_SOCKETS_H
34#define MHD_SOCKETS_H 1
35#include "mhd_options.h"
36
37#include <errno.h>
38
39#if !defined(MHD_POSIX_SOCKETS) && !defined(MHD_WINSOCK_SOCKETS)
40# if !defined(_WIN32) || defined(__CYGWIN__)
41# define MHD_POSIX_SOCKETS 1
42# else /* defined(_WIN32) && !defined(__CYGWIN__) */
43# define MHD_WINSOCK_SOCKETS 1
44# endif /* defined(_WIN32) && !defined(__CYGWIN__) */
45#endif /* !MHD_POSIX_SOCKETS && !MHD_WINSOCK_SOCKETS */
46
47/*
48 * MHD require headers that define socket type, socket basic functions
49 * (socket(), accept(), listen(), bind(), send(), recv(), select()), socket
50 * parameters like SOCK_CLOEXEC, SOCK_NONBLOCK, additional socket functions
51 * (poll(), epoll(), accept4()), struct timeval and other types, required
52 * for socket function.
53 */
54#if defined(MHD_POSIX_SOCKETS)
55# ifdef HAVE_SYS_TYPES_H
56# include <sys/types.h> /* required on old platforms */
57# endif
58# ifdef HAVE_SYS_SOCKET_H
59# include <sys/socket.h>
60# endif
61# if defined(__VXWORKS__) || defined(__vxworks) || defined(OS_VXWORKS)
62# ifdef HAVE_SOCKLIB_H
63# include <sockLib.h>
64# endif /* HAVE_SOCKLIB_H */
65# ifdef HAVE_INETLIB_H
66# include <inetLib.h>
67# endif /* HAVE_INETLIB_H */
68# include <strings.h> /* required for FD_SET (bzero() function) */
69# endif /* __VXWORKS__ || __vxworks || OS_VXWORKS */
70# ifdef HAVE_NETINET_IN_H
71# include <netinet/in.h>
72# endif /* HAVE_NETINET_IN_H */
73# ifdef HAVE_ARPA_INET_H
74# include <arpa/inet.h>
75# endif
76# ifdef HAVE_NET_IF_H
77# include <net/if.h>
78# endif
79# ifdef HAVE_SYS_TIME_H
80# include <sys/time.h>
81# endif
82# ifdef HAVE_TIME_H
83# include <time.h>
84# endif
85# ifdef HAVE_NETDB_H
86# include <netdb.h>
87# endif
88# ifdef HAVE_SYS_SELECT_H
89# include <sys/select.h>
90# endif
91# ifdef EPOLL_SUPPORT
92# include <sys/epoll.h>
93# endif
94# ifdef HAVE_NETINET_TCP_H
95 /* for TCP_FASTOPEN and TCP_CORK */
96# include <netinet/tcp.h>
97# endif
98# ifdef HAVE_STRING_H
99# include <string.h> /* for strerror() */
100# endif
101#elif defined(MHD_WINSOCK_SOCKETS)
102# ifndef WIN32_LEAN_AND_MEAN
103# define WIN32_LEAN_AND_MEAN 1
104# endif /* !WIN32_LEAN_AND_MEAN */
105# include <winsock2.h>
106# include <ws2tcpip.h>
107#endif /* MHD_WINSOCK_SOCKETS */
108
109#if defined(HAVE_POLL_H) && defined(HAVE_POLL)
110# include <poll.h>
111#endif
112
113#include <stddef.h>
114#if defined(_MSC_FULL_VER) && !defined (_SSIZE_T_DEFINED)
115# include <stdint.h>
116# define _SSIZE_T_DEFINED
117 typedef intptr_t ssize_t;
118#endif /* !_SSIZE_T_DEFINED */
119
120#include "mhd_limits.h"
121
122#ifdef _MHD_FD_SETSIZE_IS_DEFAULT
123# define _MHD_SYS_DEFAULT_FD_SETSIZE FD_SETSIZE
124#else /* ! _MHD_FD_SETSIZE_IS_DEFAULT */
125# include "sysfdsetsize.h"
126# define _MHD_SYS_DEFAULT_FD_SETSIZE get_system_fdsetsize_value()
127#endif /* ! _MHD_FD_SETSIZE_IS_DEFAULT */
128
129#ifndef MHD_PANIC
130# include <stdio.h>
131# include <stdlib.h>
132/* Simple implementation of MHD_PANIC, to be used outside lib */
133# define MHD_PANIC(msg) do { fprintf (stderr, \
134 "Abnormal termination at %d line in file %s: %s\n", \
135 (int)__LINE__, __FILE__, msg); abort();} while(0)
136#endif /* ! MHD_PANIC */
137
138#ifndef MHD_SOCKET_DEFINED
139/**
140 * MHD_socket is type for socket FDs
141 */
142# if defined(MHD_POSIX_SOCKETS)
143 typedef int MHD_socket;
144# define MHD_INVALID_SOCKET (-1)
145# elif defined(MHD_WINSOCK_SOCKETS)
146 typedef SOCKET MHD_socket;
147# define MHD_INVALID_SOCKET (INVALID_SOCKET)
148# endif /* MHD_WINSOCK_SOCKETS */
149
150# define MHD_SOCKET_DEFINED 1
151#endif /* ! MHD_SOCKET_DEFINED */
152
153#ifdef SOCK_CLOEXEC
154# define MAYBE_SOCK_CLOEXEC SOCK_CLOEXEC
155#else /* ! SOCK_CLOEXEC */
156# define MAYBE_SOCK_CLOEXEC 0
157#endif /* ! SOCK_CLOEXEC */
158
159#ifdef HAVE_SOCK_NONBLOCK
160# define MAYBE_SOCK_NONBLOCK SOCK_NONBLOCK
161#else /* ! HAVE_SOCK_NONBLOCK */
162# define MAYBE_SOCK_NONBLOCK 0
163#endif /* ! HAVE_SOCK_NONBLOCK */
164
165#ifdef MSG_NOSIGNAL
166# define MAYBE_MSG_NOSIGNAL MSG_NOSIGNAL
167#else /* ! MSG_NOSIGNAL */
168# define MAYBE_MSG_NOSIGNAL 0
169#endif /* ! MSG_NOSIGNAL */
170
171#if !defined(SHUT_WR) && defined(SD_SEND)
172# define SHUT_WR SD_SEND
173#endif
174#if !defined(SHUT_RD) && defined(SD_RECEIVE)
175# define SHUT_RD SD_RECEIVE
176#endif
177#if !defined(SHUT_RDWR) && defined(SD_BOTH)
178# define SHUT_RDWR SD_BOTH
179#endif
180
181#if HAVE_ACCEPT4+0 != 0 && (defined(HAVE_SOCK_NONBLOCK) || defined(SOCK_CLOEXEC))
182# define USE_ACCEPT4 1
183#endif
184
185#if defined(HAVE_EPOLL_CREATE1) && defined(EPOLL_CLOEXEC)
186# define USE_EPOLL_CREATE1 1
187#endif /* HAVE_EPOLL_CREATE1 && EPOLL_CLOEXEC */
188
189#ifdef TCP_FASTOPEN
190/**
191 * Default TCP fastopen queue size.
192 */
193#define MHD_TCP_FASTOPEN_QUEUE_SIZE_DEFAULT 10
194#endif
195
196
197/**
198 * MHD_SCKT_OPT_BOOL_ is type for bool parameters for setsockopt()/getsockopt()
199 */
200#ifdef MHD_POSIX_SOCKETS
201 typedef int MHD_SCKT_OPT_BOOL_;
202#else /* MHD_WINSOCK_SOCKETS */
203 typedef BOOL MHD_SCKT_OPT_BOOL_;
204#endif /* MHD_WINSOCK_SOCKETS */
205
206/**
207 * MHD_SCKT_SEND_SIZE_ is type used to specify size for send and recv
208 * functions
209 */
210#if !defined(MHD_WINSOCK_SOCKETS)
211 typedef size_t MHD_SCKT_SEND_SIZE_;
212#else
213 typedef int MHD_SCKT_SEND_SIZE_;
214#endif
215
216/**
217 * MHD_SCKT_SEND_MAX_SIZE_ is maximum send()/recv() size value.
218 */
219#if !defined(MHD_WINSOCK_SOCKETS)
220# define MHD_SCKT_SEND_MAX_SIZE_ SSIZE_MAX
221#else
222# define MHD_SCKT_SEND_MAX_SIZE_ INT_MAX
223#endif
224
225/**
226 * MHD_socket_close_(fd) close any FDs (non-W32) / close only socket
227 * FDs (W32). Note that on HP-UNIX, this function may leak the FD if
228 * errno is set to EINTR. Do not use HP-UNIX.
229 *
230 * @param fd descriptor to close
231 * @return boolean true on success (error codes like EINTR and EIO are
232 * counted as success, only EBADF counts as an error!),
233 * boolean false otherwise.
234 */
235#if !defined(MHD_WINSOCK_SOCKETS)
236# define MHD_socket_close_(fd) ((0 == close((fd))) || (EBADF != errno))
237#else
238# define MHD_socket_close_(fd) (0 == closesocket((fd)))
239#endif
240
241/**
242 * MHD_socket_close_chk_(fd) close socket and abort execution
243 * if error is detected.
244 * @param fd socket to close
245 */
246#define MHD_socket_close_chk_(fd) do { \
247 if (!MHD_socket_close_(fd)) \
248 MHD_PANIC(_("Close socket failed.\n")); \
249 } while(0)
250
251
252/**
253 * MHD_send_ is wrapper for system's send()
254 * @param s the socket to use
255 * @param b the buffer with data to send
256 * @param l the length of data in @a b
257 * @return ssize_t type value
258 */
259#define MHD_send_(s,b,l) \
260 ((ssize_t)send((s),(const void*)(b),((MHD_SCKT_SEND_SIZE_)l), MAYBE_MSG_NOSIGNAL))
261
262
263/**
264 * MHD_recv_ is wrapper for system's recv()
265 * @param s the socket to use
266 * @param b the buffer for data to receive
267 * @param l the length of @a b
268 * @return ssize_t type value
269 */
270#define MHD_recv_(s,b,l) \
271 ((ssize_t)recv((s),(void*)(b),((MHD_SCKT_SEND_SIZE_)l), 0))
272
273
274/**
275 * Check whether FD can be added to fd_set with specified FD_SETSIZE.
276 * @param fd the fd to check
277 * @param pset the pointer to fd_set to check or NULL to check
278 * whether FD can be used with fd_sets.
279 * @param setsize the value of FD_SETSIZE.
280 * @return boolean true if FD can be added to fd_set,
281 * boolean false otherwise.
282 */
283#if defined(MHD_POSIX_SOCKETS)
284# define MHD_SCKT_FD_FITS_FDSET_SETSIZE_(fd,pset,setsize) ((fd) < ((MHD_socket)setsize))
285#elif defined(MHD_WINSOCK_SOCKETS)
286# define MHD_SCKT_FD_FITS_FDSET_SETSIZE_(fd,pset,setsize) ( ((void*)(pset)==(void*)0) || \
287 (((fd_set*)(pset))->fd_count < ((unsigned)setsize)) || \
288 (FD_ISSET((fd),(pset))) )
289#endif
290
291/**
292 * Check whether FD can be added to fd_set with current FD_SETSIZE.
293 * @param fd the fd to check
294 * @param pset the pointer to fd_set to check or NULL to check
295 * whether FD can be used with fd_sets.
296 * @return boolean true if FD can be added to fd_set,
297 * boolean false otherwise.
298 */
299#define MHD_SCKT_FD_FITS_FDSET_(fd,pset) MHD_SCKT_FD_FITS_FDSET_SETSIZE_((fd),(pset),FD_SETSIZE)
300
301/**
302 * Add FD to fd_set with specified FD_SETSIZE.
303 * @param fd the fd to add
304 * @param pset the valid pointer to fd_set.
305 * @param setsize the value of FD_SETSIZE.
306 * @note To work on W32 with value of FD_SETSIZE different from currently defined value,
307 * system definition of FD_SET() is not used.
308 */
309#if defined(MHD_POSIX_SOCKETS)
310# define MHD_SCKT_ADD_FD_TO_FDSET_SETSIZE_(fd,pset,setsize) FD_SET((fd),(pset))
311#elif defined(MHD_WINSOCK_SOCKETS)
312# define MHD_SCKT_ADD_FD_TO_FDSET_SETSIZE_(fd,pset,setsize) \
313 do { \
314 u_int _i_ = 0; \
315 fd_set* const _s_ = (fd_set*)(pset); \
316 while((_i_ < _s_->fd_count) && ((fd) != _s_->fd_array[_i_])) {++_i_;} \
317 if ((_i_ == _s_->fd_count)) {_s_->fd_array[_s_->fd_count++] = (fd);} \
318 } while(0)
319#endif
320
321 /* MHD_SYS_select_ is wrapper macro for system select() function */
322#if !defined(MHD_WINSOCK_SOCKETS)
323# define MHD_SYS_select_(n,r,w,e,t) select((n),(r),(w),(e),(t))
324#else
325# define MHD_SYS_select_(n,r,w,e,t) \
326( ( (((void*)(r) == (void*)0) || ((fd_set*)(r))->fd_count == 0) && \
327 (((void*)(w) == (void*)0) || ((fd_set*)(w))->fd_count == 0) && \
328 (((void*)(e) == (void*)0) || ((fd_set*)(e))->fd_count == 0) ) ? \
329 ( ((void*)(t) == (void*)0) ? 0 : \
330 (Sleep(((struct timeval*)(t))->tv_sec * 1000 + \
331 ((struct timeval*)(t))->tv_usec / 1000), 0) ) : \
332 (select((int)0,(r),(w),(e),(t))) )
333#endif
334
335#if defined(HAVE_POLL)
336/* MHD_sys_poll_ is wrapper macro for system poll() function */
337# if !defined(MHD_WINSOCK_SOCKETS)
338# define MHD_sys_poll_ poll
339# else /* MHD_WINSOCK_SOCKETS */
340# define MHD_sys_poll_ WSAPoll
341# endif /* MHD_WINSOCK_SOCKETS */
342
343# ifdef POLLPRI
344# define MHD_POLLPRI_OR_ZERO POLLPRI
345# else /* ! POLLPRI */
346# define MHD_POLLPRI_OR_ZERO 0
347# endif /* ! POLLPRI */
348# ifdef POLLRDBAND
349# define MHD_POLLRDBAND_OR_ZERO POLLRDBAND
350# else /* ! POLLRDBAND */
351# define MHD_POLLRDBAND_OR_ZERO 0
352# endif /* ! POLLRDBAND */
353# ifdef POLLNVAL
354# define MHD_POLLNVAL_OR_ZERO POLLNVAL
355# else /* ! POLLNVAL */
356# define MHD_POLLNVAL_OR_ZERO 0
357# endif /* ! POLLNVAL */
358
359/* MHD_POLL_EVENTS_ERR_DISC is 'events' mask for errors and disconnect.
360 * Note: Out-of-band data is treated as error. */
361# if defined(_WIN32) && ! defined(__CYGWIN__)
362# define MHD_POLL_EVENTS_ERR_DISC POLLRDBAND
363# elif defined(__linux__)
364# define MHD_POLL_EVENTS_ERR_DISC POLLPRI
365# else /* ! __linux__ */
366# define MHD_POLL_EVENTS_ERR_DISC (MHD_POLLPRI_OR_ZERO | MHD_POLLRDBAND_OR_ZERO)
367# endif /* ! __linux__ */
368/* MHD_POLL_REVENTS_ERR_DISC is 'revents' mask for errors and disconnect.
369 * Note: Out-of-band data is treated as error. */
370# define MHD_POLL_REVENTS_ERR_DISC \
371 (MHD_POLLPRI_OR_ZERO | MHD_POLLRDBAND_OR_ZERO | MHD_POLLNVAL_OR_ZERO | POLLERR | POLLHUP)
372/* MHD_POLL_REVENTS_ERRROR is 'revents' mask for errors.
373 * Note: Out-of-band data is treated as error. */
374# define MHD_POLL_REVENTS_ERRROR \
375 (MHD_POLLPRI_OR_ZERO | MHD_POLLRDBAND_OR_ZERO | MHD_POLLNVAL_OR_ZERO | POLLERR)
376#endif /* HAVE_POLL */
377
378#define MHD_SCKT_MISSING_ERR_CODE_ 31450
379
380#if defined(MHD_POSIX_SOCKETS)
381# if defined(EAGAIN)
382# define MHD_SCKT_EAGAIN_ EAGAIN
383# elif defined(EWOULDBLOCK)
384# define MHD_SCKT_EAGAIN_ EWOULDBLOCK
385# else /* !EAGAIN && !EWOULDBLOCK */
386# define MHD_SCKT_EAGAIN_ MHD_SCKT_MISSING_ERR_CODE_
387# endif /* !EAGAIN && !EWOULDBLOCK */
388# if defined(EWOULDBLOCK)
389# define MHD_SCKT_EWOULDBLOCK_ EWOULDBLOCK
390# elif defined(EAGAIN)
391# define MHD_SCKT_EWOULDBLOCK_ EAGAIN
392# else /* !EWOULDBLOCK && !EAGAIN */
393# define MHD_SCKT_EWOULDBLOCK_ MHD_SCKT_MISSING_ERR_CODE_
394# endif /* !EWOULDBLOCK && !EAGAIN */
395# ifdef EINTR
396# define MHD_SCKT_EINTR_ EINTR
397# else /* ! EINTR */
398# define MHD_SCKT_EINTR_ MHD_SCKT_MISSING_ERR_CODE_
399# endif /* ! EINTR */
400# ifdef ECONNRESET
401# define MHD_SCKT_ECONNRESET_ ECONNRESET
402# else /* ! ECONNRESET */
403# define MHD_SCKT_ECONNRESET_ MHD_SCKT_MISSING_ERR_CODE_
404# endif /* ! ECONNRESET */
405# ifdef ECONNABORTED
406# define MHD_SCKT_ECONNABORTED_ ECONNABORTED
407# else /* ! ECONNABORTED */
408# define MHD_SCKT_ECONNABORTED_ MHD_SCKT_MISSING_ERR_CODE_
409# endif /* ! ECONNABORTED */
410# ifdef ENOTCONN
411# define MHD_SCKT_ENOTCONN_ ENOTCONN
412# else /* ! ENOTCONN */
413# define MHD_SCKT_ENOTCONN_ MHD_SCKT_MISSING_ERR_CODE_
414# endif /* ! ENOTCONN */
415# ifdef EMFILE
416# define MHD_SCKT_EMFILE_ EMFILE
417# else /* ! EMFILE */
418# define MHD_SCKT_EMFILE_ MHD_SCKT_MISSING_ERR_CODE_
419# endif /* ! EMFILE */
420# ifdef ENFILE
421# define MHD_SCKT_ENFILE_ ENFILE
422# else /* ! ENFILE */
423# define MHD_SCKT_ENFILE_ MHD_SCKT_MISSING_ERR_CODE_
424# endif /* ! ENFILE */
425# ifdef ENOMEM
426# define MHD_SCKT_ENOMEM_ ENOMEM
427# else /* ! ENOMEM */
428# define MHD_SCKT_ENOMEM_ MHD_SCKT_MISSING_ERR_CODE_
429# endif /* ! ENOMEM */
430# ifdef ENOBUFS
431# define MHD_SCKT_ENOBUFS_ ENOBUFS
432# else /* ! ENOBUFS */
433# define MHD_SCKT_ENOBUFS_ MHD_SCKT_MISSING_ERR_CODE_
434# endif /* ! ENOBUFS */
435# ifdef EBADF
436# define MHD_SCKT_EBADF_ EBADF
437# else /* ! EBADF */
438# define MHD_SCKT_EBADF_ MHD_SCKT_MISSING_ERR_CODE_
439# endif /* ! EBADF */
440# ifdef ENOTSOCK
441# define MHD_SCKT_ENOTSOCK_ ENOTSOCK
442# else /* ! ENOTSOCK */
443# define MHD_SCKT_ENOTSOCK_ MHD_SCKT_MISSING_ERR_CODE_
444# endif /* ! ENOTSOCK */
445# ifdef EINVAL
446# define MHD_SCKT_EINVAL_ EINVAL
447# else /* ! EINVAL */
448# define MHD_SCKT_EINVAL_ MHD_SCKT_MISSING_ERR_CODE_
449# endif /* ! EINVAL */
450# ifdef EFAULT
451# define MHD_SCKT_EFAUL_ EFAULT
452# else /* ! EFAULT */
453# define MHD_SCKT_EFAUL_ MHD_SCKT_MISSING_ERR_CODE_
454# endif /* ! EFAULT */
455# ifdef ENOSYS
456# define MHD_SCKT_ENOSYS_ ENOSYS
457# else /* ! ENOSYS */
458# define MHD_SCKT_ENOSYS_ MHD_SCKT_MISSING_ERR_CODE_
459# endif /* ! ENOSYS */
460# ifdef ENOTSUP
461# define MHD_SCKT_ENOTSUP_ ENOTSUP
462# else /* ! ENOTSUP */
463# define MHD_SCKT_ENOTSUP_ MHD_SCKT_MISSING_ERR_CODE_
464# endif /* ! ENOTSUP */
465# ifdef EOPNOTSUPP
466# define MHD_SCKT_EOPNOTSUPP_ EOPNOTSUPP
467# else /* ! EOPNOTSUPP */
468# define MHD_SCKT_EOPNOTSUPP_ MHD_SCKT_MISSING_ERR_CODE_
469# endif /* ! EOPNOTSUPP */
470# ifdef EACCES
471# define MHD_SCKT_EACCESS_ EACCES
472# else /* ! EACCES */
473# define MHD_SCKT_EACCESS_ MHD_SCKT_MISSING_ERR_CODE_
474# endif /* ! EACCES */
475# ifdef ENETDOWN
476# define MHD_SCKT_ENETDOWN_ ENETDOWN
477# else /* ! ENETDOWN */
478# define MHD_SCKT_ENETDOWN_ MHD_SCKT_MISSING_ERR_CODE_
479# endif /* ! ENETDOWN */
480#elif defined(MHD_WINSOCK_SOCKETS)
481# define MHD_SCKT_EAGAIN_ WSAEWOULDBLOCK
482# define MHD_SCKT_EWOULDBLOCK_ WSAEWOULDBLOCK
483# define MHD_SCKT_EINTR_ WSAEINTR
484# define MHD_SCKT_ECONNRESET_ WSAECONNRESET
485# define MHD_SCKT_ECONNABORTED_ WSAECONNABORTED
486# define MHD_SCKT_ENOTCONN_ WSAENOTCONN
487# define MHD_SCKT_EMFILE_ WSAEMFILE
488# define MHD_SCKT_ENFILE_ MHD_SCKT_MISSING_ERR_CODE_
489# define MHD_SCKT_ENOMEM_ MHD_SCKT_MISSING_ERR_CODE_
490# define MHD_SCKT_ENOBUFS_ WSAENOBUFS
491# define MHD_SCKT_EBADF_ WSAEBADF
492# define MHD_SCKT_ENOTSOCK_ WSAENOTSOCK
493# define MHD_SCKT_EINVAL_ WSAEINVAL
494# define MHD_SCKT_EFAUL_ WSAEFAULT
495# define MHD_SCKT_ENOSYS_ MHD_SCKT_MISSING_ERR_CODE_
496# define MHD_SCKT_ENOTSUP_ MHD_SCKT_MISSING_ERR_CODE_
497# define MHD_SCKT_EOPNOTSUPP_ WSAEOPNOTSUPP
498# define MHD_SCKT_EACCESS_ WSAEACCES
499# define MHD_SCKT_ENETDOWN_ WSAENETDOWN
500#endif
501
502/**
503 * MHD_socket_error_ return system native error code for last socket error.
504 * @return system error code for last socket error.
505 */
506#if defined(MHD_POSIX_SOCKETS)
507# define MHD_socket_get_error_() (errno)
508#elif defined(MHD_WINSOCK_SOCKETS)
509# define MHD_socket_get_error_() WSAGetLastError()
510#endif
511
512#ifdef MHD_WINSOCK_SOCKETS
513 /* POSIX-W32 sockets compatibility functions */
514
515/**
516 * Return pointer to string description of specified WinSock error
517 * @param err the WinSock error code.
518 * @return pointer to string description of specified WinSock error.
519 */
520 const char* MHD_W32_strerror_winsock_(int err);
521#endif /* MHD_WINSOCK_SOCKETS */
522
523/* MHD_socket_last_strerr_ is description string of specified socket error code */
524#if defined(MHD_POSIX_SOCKETS)
525# define MHD_socket_strerr_(err) strerror((err))
526#elif defined(MHD_WINSOCK_SOCKETS)
527# define MHD_socket_strerr_(err) MHD_W32_strerror_winsock_((err))
528#endif
529
530/* MHD_socket_last_strerr_ is description string of last errno (non-W32) /
531 * description string of last socket error (W32) */
532#define MHD_socket_last_strerr_() MHD_socket_strerr_(MHD_socket_get_error_())
533
534/**
535 * MHD_socket_fset_error_() set socket system native error code.
536 */
537#if defined(MHD_POSIX_SOCKETS)
538# define MHD_socket_fset_error_(err) (errno = (err))
539#elif defined(MHD_WINSOCK_SOCKETS)
540# define MHD_socket_fset_error_(err) (WSASetLastError((err)))
541#endif
542
543/**
544 * MHD_socket_try_set_error_() set socket system native error code if
545 * specified code is defined on system.
546 * @return non-zero if specified @a err code is defined on system
547 * and error was set;
548 * zero if specified @a err code is not defined on system
549 * and error was not set.
550 */
551#define MHD_socket_try_set_error_(err) ( (MHD_SCKT_MISSING_ERR_CODE_ != (err)) ? \
552 (MHD_socket_fset_error_((err)), !0) : 0 )
553
554/**
555 * MHD_socket_set_error_() set socket system native error code to
556 * specified code or replacement code if specified code is not
557 * defined on system.
558 */
559#if defined(MHD_POSIX_SOCKETS)
560# if defined(ENOSYS)
561# define MHD_socket_set_error_(err) ( (MHD_SCKT_MISSING_ERR_CODE_ == (err)) ? \
562 (errno = ENOSYS) : (errno = (err)) )
563# elif defined(EOPNOTSUPP)
564# define MHD_socket_set_error_(err) ( (MHD_SCKT_MISSING_ERR_CODE_ == (err)) ? \
565 (errno = EOPNOTSUPP) : (errno = (err)) )
566# elif defined (EFAULT)
567# define MHD_socket_set_error_(err) ( (MHD_SCKT_MISSING_ERR_CODE_ == (err)) ? \
568 (errno = EFAULT) : (errno = (err)) )
569# elif defined (EINVAL)
570# define MHD_socket_set_error_(err) ( (MHD_SCKT_MISSING_ERR_CODE_ == (err)) ? \
571 (errno = EINVAL) : (errno = (err)) )
572# else /* !EOPNOTSUPP && !EFAULT && !EINVAL */
573# warning No suitable replacement for missing socket error code is found. Edit this file and add replacement code which is defined on system.
574# define MHD_socket_set_error_(err) (errno = (err))
575# endif /* !EOPNOTSUPP && !EFAULT && !EINVAL*/
576#elif defined(MHD_WINSOCK_SOCKETS)
577# define MHD_socket_set_error_(err) ( (MHD_SCKT_MISSING_ERR_CODE_ == (err)) ? \
578 (WSASetLastError((WSAEOPNOTSUPP))) : \
579 (WSASetLastError((err))) )
580#endif
581
582/**
583 * Check whether given socket error is equal to specified system
584 * native MHD_SCKT_E*_ code.
585 * If platform don't have specific error code, result is
586 * always boolean false.
587 * @return boolean true if @a code is real error code and
588 * @a err equals to MHD_SCKT_E*_ @a code;
589 * boolean false otherwise
590 */
591#define MHD_SCKT_ERR_IS_(err,code) ( (MHD_SCKT_MISSING_ERR_CODE_ != (code)) && \
592 ((code) == (err)) )
593
594/**
595 * Check whether last socket error is equal to specified system
596 * native MHD_SCKT_E*_ code.
597 * If platform don't have specific error code, result is
598 * always boolean false.
599 * @return boolean true if @a code is real error code and
600 * last socket error equals to MHD_SCKT_E*_ @a code;
601 * boolean false otherwise
602 */
603#define MHD_SCKT_LAST_ERR_IS_(code) MHD_SCKT_ERR_IS_(MHD_socket_get_error_() ,(code))
604
605/* Specific error code checks */
606
607/**
608 * Check whether given socket error is equal to system's
609 * socket error codes for EINTR.
610 * @return boolean true if @a err is equal to sockets' EINTR code;
611 * boolean false otherwise.
612 */
613#define MHD_SCKT_ERR_IS_EINTR_(err) MHD_SCKT_ERR_IS_((err),MHD_SCKT_EINTR_)
614
615/**
616 * Check whether given socket error is equal to system's
617 * socket error codes for EAGAIN or EWOULDBLOCK.
618 * @return boolean true if @a err is equal to sockets' EAGAIN or EWOULDBLOCK codes;
619 * boolean false otherwise.
620 */
621#if MHD_SCKT_EAGAIN_ == MHD_SCKT_EWOULDBLOCK_
622# define MHD_SCKT_ERR_IS_EAGAIN_(err) MHD_SCKT_ERR_IS_((err),MHD_SCKT_EAGAIN_)
623#else /* MHD_SCKT_EAGAIN_ != MHD_SCKT_EWOULDBLOCK_ */
624# define MHD_SCKT_ERR_IS_EAGAIN_(err) ( MHD_SCKT_ERR_IS_((err),MHD_SCKT_EAGAIN_) || \
625 MHD_SCKT_ERR_IS_((err),MHD_SCKT_EWOULDBLOCK_) )
626#endif /* MHD_SCKT_EAGAIN_ != MHD_SCKT_EWOULDBLOCK_ */
627
628/**
629 * Check whether given socket error is any kind of "low resource" error.
630 * @return boolean true if @a err is any kind of "low resource" error,
631 * boolean false otherwise.
632 */
633#define MHD_SCKT_ERR_IS_LOW_RESOURCES_(err) ( MHD_SCKT_ERR_IS_((err),MHD_SCKT_EMFILE_) || \
634 MHD_SCKT_ERR_IS_((err),MHD_SCKT_ENFILE_) || \
635 MHD_SCKT_ERR_IS_((err),MHD_SCKT_ENOMEM_) || \
636 MHD_SCKT_ERR_IS_((err),MHD_SCKT_ENOBUFS_) )
637
638/**
639 * Check whether is given socket error is type of "incoming connection
640 * was disconnected before 'accept()' is called".
641 * @return boolean true is @a err match described socket error code,
642 * boolean false otherwise.
643 */
644#if defined(MHD_POSIX_SOCKETS)
645# define MHD_SCKT_ERR_IS_DISCNN_BEFORE_ACCEPT_(err) MHD_SCKT_ERR_IS_((err),MHD_SCKT_ECONNABORTED_)
646#elif defined(MHD_WINSOCK_SOCKETS)
647# define MHD_SCKT_ERR_IS_DISCNN_BEFORE_ACCEPT_(err) MHD_SCKT_ERR_IS_((err),MHD_SCKT_ECONNRESET_)
648#endif
649
650/**
651 * Check whether is given socket error is type of "connection was terminated
652 * by remote side".
653 * @return boolean true is @a err match described socket error code,
654 * boolean false otherwise.
655 */
656#define MHD_SCKT_ERR_IS_REMOTE_DISCNN_(err) ( MHD_SCKT_ERR_IS_((err),MHD_SCKT_ECONNRESET_) || \
657 MHD_SCKT_ERR_IS_((err),MHD_SCKT_ECONNABORTED_))
658
659/* Specific error code set */
660
661/**
662 * Set socket's error code to ENOMEM or equivalent if ENOMEM is not
663 * available on platform.
664 */
665#if MHD_SCKT_MISSING_ERR_CODE_ != MHD_SCKT_ENOMEM_
666# define MHD_socket_set_error_to_ENOMEM() MHD_socket_set_error_(MHD_SCKT_ENOMEM_)
667#elif MHD_SCKT_MISSING_ERR_CODE_ != MHD_SCKT_ENOBUFS_
668# define MHD_socket_set_error_to_ENOMEM() MHD_socket_set_error_(MHD_SCKT_ENOBUFS_)
669#else
670# warning No suitable replacement for ENOMEM error codes is found. Edit this file and add replacement code which is defined on system.
671# define MHD_socket_set_error_to_ENOMEM() MHD_socket_set_error_(MHD_SCKT_ENOMEM_)
672#endif
673
674/* Socket functions */
675
676#if defined(AF_LOCAL)
677# define MHD_SCKT_LOCAL AF_LOCAL
678#elif defined(AF_UNIX)
679# define MHD_SCKT_LOCAL AF_UNIX
680#endif /* AF_UNIX */
681
682#if defined(MHD_POSIX_SOCKETS) && defined(MHD_SCKT_LOCAL)
683# define MHD_socket_pair_(fdarr) (!socketpair(MHD_SCKT_LOCAL, SOCK_STREAM, 0, (fdarr)))
684# if defined(HAVE_SOCK_NONBLOCK)
685# define MHD_socket_pair_nblk_(fdarr) (!socketpair(MHD_SCKT_LOCAL, SOCK_STREAM | SOCK_NONBLOCK, 0, (fdarr)))
686# endif /* HAVE_SOCK_NONBLOCK*/
687#elif defined(MHD_WINSOCK_SOCKETS)
688 /**
689 * Create pair of mutually connected TCP/IP sockets on loopback address
690 * @param sockets_pair array to receive resulted sockets
691 * @param non_blk if set to non-zero value, sockets created in non-blocking mode
692 * otherwise sockets will be in blocking mode
693 * @return non-zero if succeeded, zero otherwise
694 */
695 int MHD_W32_socket_pair_(SOCKET sockets_pair[2], int non_blk);
696
697# define MHD_socket_pair_(fdarr) MHD_W32_socket_pair_((fdarr), 0)
698# define MHD_socket_pair_nblk_(fdarr) MHD_W32_socket_pair_((fdarr), 1)
699#endif
700
701/**
702 * Add @a fd to the @a set. If @a fd is
703 * greater than @a max_fd, set @a max_fd to @a fd.
704 *
705 * @param fd file descriptor to add to the @a set
706 * @param set set to modify
707 * @param max_fd maximum value to potentially update
708 * @param fd_setsize value of FD_SETSIZE
709 * @return non-zero if succeeded, zero otherwise
710 */
711int
712MHD_add_to_fd_set_ (MHD_socket fd,
713 fd_set *set,
714 MHD_socket *max_fd,
715 unsigned int fd_setsize);
716
717
718/**
719 * Change socket options to be non-blocking.
720 *
721 * @param sock socket to manipulate
722 * @return non-zero if succeeded, zero otherwise
723 */
724int
725MHD_socket_nonblocking_ (MHD_socket sock);
726
727
728/**
729 * Change socket options to be non-inheritable.
730 *
731 * @param sock socket to manipulate
732 * @return non-zero if succeeded, zero otherwise
733 * @warning Does not set socket error on W32.
734 */
735int
736MHD_socket_noninheritable_ (MHD_socket sock);
737
738
739#if defined(SOL_SOCKET) && defined(SO_NOSIGPIPE)
740 static const int _MHD_socket_int_one = 1;
741/**
742 * Change socket options to no signal on remote disconnect.
743 *
744 * @param sock socket to manipulate
745 * @return non-zero if succeeded, zero otherwise
746 */
747# define MHD_socket_nosignal_(sock) \
748 (!setsockopt((sock),SOL_SOCKET,SO_NOSIGPIPE,&_MHD_socket_int_one,sizeof(_MHD_socket_int_one)))
749#endif /* SOL_SOCKET && SO_NOSIGPIPE */
750
751/**
752 * Create a listen socket, with noninheritable flag if possible.
753 *
754 * @param use_ipv6 if set to non-zero IPv6 is used
755 * @return created socket or MHD_INVALID_SOCKET in case of errors
756 */
757MHD_socket
758MHD_socket_create_listen_ (bool use_ipv6);
759
760#endif /* ! MHD_SOCKETS_H */
diff --git a/src/lib/mhd_str.c b/src/lib/mhd_str.c
new file mode 100644
index 00000000..d0b03ead
--- /dev/null
+++ b/src/lib/mhd_str.c
@@ -0,0 +1,758 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2015, 2016 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file microhttpd/mhd_str.c
22 * @brief Functions implementations for string manipulating
23 * @author Karlson2k (Evgeny Grin)
24 */
25
26#include "mhd_str.h"
27
28#ifdef HAVE_STDBOOL_H
29#include <stdbool.h>
30#endif
31
32#include "mhd_limits.h"
33
34#ifdef MHD_FAVOR_SMALL_CODE
35#ifdef _MHD_static_inline
36#undef _MHD_static_inline
37#endif /* _MHD_static_inline */
38/* Do not force inlining and do not use macro functions, use normal static
39 functions instead.
40 This may give more flexibility for size optimizations. */
41#define _MHD_static_inline static
42#ifndef INLINE_FUNC
43#define INLINE_FUNC 1
44#endif /* !INLINE_FUNC */
45#endif /* MHD_FAVOR_SMALL_CODE */
46
47/*
48 * Block of functions/macros that use US-ASCII charset as required by HTTP
49 * standards. Not affected by current locale settings.
50 */
51
52#ifdef INLINE_FUNC
53
54#if 0 /* Disable unused functions. */
55/**
56 * Check whether character is lower case letter in US-ASCII
57 *
58 * @param c character to check
59 * @return non-zero if character is lower case letter, zero otherwise
60 */
61_MHD_static_inline bool
62isasciilower (char c)
63{
64 return (c >= 'a') && (c <= 'z');
65}
66#endif /* Disable unused functions. */
67
68
69/**
70 * Check whether character is upper case letter in US-ASCII
71 *
72 * @param c character to check
73 * @return non-zero if character is upper case letter, zero otherwise
74 */
75_MHD_static_inline bool
76isasciiupper (char c)
77{
78 return (c >= 'A') && (c <= 'Z');
79}
80
81
82#if 0 /* Disable unused functions. */
83/**
84 * Check whether character is letter in US-ASCII
85 *
86 * @param c character to check
87 * @return non-zero if character is letter in US-ASCII, zero otherwise
88 */
89_MHD_static_inline bool
90isasciialpha (char c)
91{
92 return isasciilower (c) || isasciiupper (c);
93}
94#endif /* Disable unused functions. */
95
96
97/**
98 * Check whether character is decimal digit in US-ASCII
99 *
100 * @param c character to check
101 * @return non-zero if character is decimal digit, zero otherwise
102 */
103_MHD_static_inline bool
104isasciidigit (char c)
105{
106 return (c >= '0') && (c <= '9');
107}
108
109#if 0 /* Disable unused functions. */
110/**
111 * Check whether character is hexadecimal digit in US-ASCII
112 *
113 * @param c character to check
114 * @return non-zero if character is decimal digit, zero otherwise
115 */
116_MHD_static_inline bool
117isasciixdigit (char c)
118{
119 return isasciidigit (c) ||
120 ( (c >= 'A') && (c <= 'F') ) ||
121 ( (c >= 'a') && (c <= 'f') );
122}
123
124
125/**
126 * Check whether character is decimal digit or letter in US-ASCII
127 *
128 * @param c character to check
129 * @return non-zero if character is decimal digit or letter, zero otherwise
130 */
131_MHD_static_inline bool
132isasciialnum (char c)
133{
134 return isasciialpha (c) || isasciidigit (c);
135}
136#endif /* Disable unused functions. */
137
138
139/**
140 * Convert US-ASCII character to lower case.
141 * If character is upper case letter in US-ASCII than it's converted to lower
142 * case analog. If character is NOT upper case letter than it's returned
143 * unmodified.
144 *
145 * @param c character to convert
146 * @return converted to lower case character
147 */
148_MHD_static_inline char
149toasciilower (char c)
150{
151 return isasciiupper (c) ? (c - 'A' + 'a') : c;
152}
153
154
155#if 0 /* Disable unused functions. */
156/**
157 * Convert US-ASCII character to upper case.
158 * If character is lower case letter in US-ASCII than it's converted to upper
159 * case analog. If character is NOT lower case letter than it's returned
160 * unmodified.
161 *
162 * @param c character to convert
163 * @return converted to upper case character
164 */
165_MHD_static_inline char
166toasciiupper (char c)
167{
168 return isasciilower (c) ? (c - 'a' + 'A') : c;
169}
170#endif /* Disable unused functions. */
171
172
173#if defined(MHD_FAVOR_SMALL_CODE) /* Used only in MHD_str_to_uvalue_n_() */
174/**
175 * Convert US-ASCII decimal digit to its value.
176 *
177 * @param c character to convert
178 * @return value of decimal digit or -1 if @ c is not decimal digit
179 */
180_MHD_static_inline int
181todigitvalue (char c)
182{
183 if (isasciidigit (c))
184 return (unsigned char)(c - '0');
185
186 return -1;
187}
188#endif /* MHD_FAVOR_SMALL_CODE */
189
190
191/**
192 * Convert US-ASCII hexadecimal digit to its value.
193 *
194 * @param c character to convert
195 * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
196 */
197_MHD_static_inline int
198toxdigitvalue (char c)
199{
200 if (isasciidigit (c))
201 return (unsigned char)(c - '0');
202 if ( (c >= 'A') && (c <= 'F') )
203 return (unsigned char)(c - 'A' + 10);
204 if ( (c >= 'a') && (c <= 'f') )
205 return (unsigned char)(c - 'a' + 10);
206
207 return -1;
208}
209#else /* !INLINE_FUNC */
210
211
212/**
213 * Checks whether character is lower case letter in US-ASCII
214 *
215 * @param c character to check
216 * @return boolean true if character is lower case letter,
217 * boolean false otherwise
218 */
219#define isasciilower(c) (((char)(c)) >= 'a' && ((char)(c)) <= 'z')
220
221
222/**
223 * Checks whether character is upper case letter in US-ASCII
224 *
225 * @param c character to check
226 * @return boolean true if character is upper case letter,
227 * boolean false otherwise
228 */
229#define isasciiupper(c) (((char)(c)) >= 'A' && ((char)(c)) <= 'Z')
230
231
232/**
233 * Checks whether character is letter in US-ASCII
234 *
235 * @param c character to check
236 * @return boolean true if character is letter, boolean false
237 * otherwise
238 */
239#define isasciialpha(c) (isasciilower(c) || isasciiupper(c))
240
241
242/**
243 * Check whether character is decimal digit in US-ASCII
244 *
245 * @param c character to check
246 * @return boolean true if character is decimal digit, boolean false
247 * otherwise
248 */
249#define isasciidigit(c) (((char)(c)) >= '0' && ((char)(c)) <= '9')
250
251
252/**
253 * Check whether character is hexadecimal digit in US-ASCII
254 *
255 * @param c character to check
256 * @return boolean true if character is hexadecimal digit,
257 * boolean false otherwise
258 */
259#define isasciixdigit(c) (isasciidigit((c)) || \
260 (((char)(c)) >= 'A' && ((char)(c)) <= 'F') || \
261 (((char)(c)) >= 'a' && ((char)(c)) <= 'f') )
262
263
264/**
265 * Check whether character is decimal digit or letter in US-ASCII
266 *
267 * @param c character to check
268 * @return boolean true if character is decimal digit or letter,
269 * boolean false otherwise
270 */
271#define isasciialnum(c) (isasciialpha(c) || isasciidigit(c))
272
273
274/**
275 * Convert US-ASCII character to lower case.
276 * If character is upper case letter in US-ASCII than it's converted to lower
277 * case analog. If character is NOT upper case letter than it's returned
278 * unmodified.
279 *
280 * @param c character to convert
281 * @return converted to lower case character
282 */
283#define toasciilower(c) ((isasciiupper(c)) ? (((char)(c)) - 'A' + 'a') : ((char)(c)))
284
285
286/**
287 * Convert US-ASCII character to upper case.
288 * If character is lower case letter in US-ASCII than it's converted to upper
289 * case analog. If character is NOT lower case letter than it's returned
290 * unmodified.
291 *
292 * @param c character to convert
293 * @return converted to upper case character
294 */
295#define toasciiupper(c) ((isasciilower(c)) ? (((char)(c)) - 'a' + 'A') : ((char)(c)))
296
297
298/**
299 * Convert US-ASCII decimal digit to its value.
300 *
301 * @param c character to convert
302 * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
303 */
304#define todigitvalue(c) (isasciidigit(c) ? (int)(((char)(c)) - '0') : (int)(-1))
305
306
307/**
308 * Convert US-ASCII hexadecimal digit to its value.
309 * @param c character to convert
310 * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
311 */
312#define toxdigitvalue(c) ( isasciidigit(c) ? (int)(((char)(c)) - '0') : \
313 ( (((char)(c)) >= 'A' && ((char)(c)) <= 'F') ? \
314 (int)(((unsigned char)(c)) - 'A' + 10) : \
315 ( (((char)(c)) >= 'a' && ((char)(c)) <= 'f') ? \
316 (int)(((unsigned char)(c)) - 'a' + 10) : (int)(-1) )))
317#endif /* !INLINE_FUNC */
318
319
320#ifndef MHD_FAVOR_SMALL_CODE
321/**
322 * Check two string for equality, ignoring case of US-ASCII letters.
323 *
324 * @param str1 first string to compare
325 * @param str2 second string to compare
326 * @return non-zero if two strings are equal, zero otherwise.
327 */
328int
329MHD_str_equal_caseless_ (const char * str1,
330 const char * str2)
331{
332 while (0 != (*str1))
333 {
334 const char c1 = *str1;
335 const char c2 = *str2;
336 if ( (c1 != c2) &&
337 (toasciilower (c1) != toasciilower (c2)) )
338 return 0;
339 str1++;
340 str2++;
341 }
342 return 0 == (*str2);
343}
344#endif /* ! MHD_FAVOR_SMALL_CODE */
345
346
347/**
348 * Check two string for equality, ignoring case of US-ASCII letters and
349 * checking not more than @a maxlen characters.
350 * Compares up to first terminating null character, but not more than
351 * first @a maxlen characters.
352 *
353 * @param str1 first string to compare
354 * @param str2 second string to compare
355 * @param maxlen maximum number of characters to compare
356 * @return non-zero if two strings are equal, zero otherwise.
357 */
358int
359MHD_str_equal_caseless_n_ (const char * const str1,
360 const char * const str2,
361 size_t maxlen)
362{
363 size_t i;
364
365 for (i = 0; i < maxlen; ++i)
366 {
367 const char c1 = str1[i];
368 const char c2 = str2[i];
369 if (0 == c2)
370 return 0 == c1;
371 if ( (c1 != c2) &&
372 (toasciilower (c1) != toasciilower (c2)) )
373 return 0;
374 }
375 return !0;
376}
377
378
379/**
380 * Check whether @a str has case-insensitive @a token.
381 * Token could be surrounded by spaces and tabs and delimited by comma.
382 * Match succeed if substring between start, end (of string) or comma
383 * contains only case-insensitive token and optional spaces and tabs.
384 * @warning token must not contain null-charters except optional
385 * terminating null-character.
386 * @param str the string to check
387 * @param token the token to find
388 * @param token_len length of token, not including optional terminating
389 * null-character.
390 * @return non-zero if two strings are equal, zero otherwise.
391 */
392bool
393MHD_str_has_token_caseless_ (const char * str,
394 const char * const token,
395 size_t token_len)
396{
397 if (0 == token_len)
398 return false;
399
400 while (0 != *str)
401 {
402 size_t i;
403 /* Skip all whitespaces and empty tokens. */
404 while (' ' == *str || '\t' == *str || ',' == *str) str++;
405
406 /* Check for token match. */
407 i = 0;
408 while (1)
409 {
410 const char sc = *(str++);
411 const char tc = token[i++];
412
413 if (0 == sc)
414 return false;
415 if ( (sc != tc) &&
416 (toasciilower (sc) != toasciilower (tc)) )
417 break;
418 if (i >= token_len)
419 {
420 /* Check whether substring match token fully or
421 * has additional unmatched chars at tail. */
422 while (' ' == *str || '\t' == *str) str++;
423 /* End of (sub)string? */
424 if (0 == *str || ',' == *str)
425 return true;
426 /* Unmatched chars at end of substring. */
427 break;
428 }
429 }
430 /* Find next substring. */
431 while (0 != *str && ',' != *str) str++;
432 }
433 return false;
434}
435
436#ifndef MHD_FAVOR_SMALL_CODE
437/* Use individual function for each case */
438
439/**
440 * Convert decimal US-ASCII digits in string to number in uint64_t.
441 * Conversion stopped at first non-digit character.
442 *
443 * @param str string to convert
444 * @param[out] out_val pointer to uint64_t to store result of conversion
445 * @return non-zero number of characters processed on succeed,
446 * zero if no digit is found, resulting value is larger
447 * then possible to store in uint64_t or @a out_val is NULL
448 */
449size_t
450MHD_str_to_uint64_ (const char *str,
451 uint64_t *out_val)
452{
453 const char * const start = str;
454 uint64_t res;
455
456 if (!str || !out_val || !isasciidigit(str[0]))
457 return 0;
458
459 res = 0;
460 do
461 {
462 const int digit = (unsigned char)(*str) - '0';
463 if ( (res > (UINT64_MAX / 10)) ||
464 ( (res == (UINT64_MAX / 10)) &&
465 ((uint64_t)digit > (UINT64_MAX % 10)) ) )
466 return 0;
467
468 res *= 10;
469 res += digit;
470 str++;
471 } while (isasciidigit (*str));
472
473 *out_val = res;
474 return str - start;
475}
476
477
478/**
479 * Convert not more then @a maxlen decimal US-ASCII digits in string to
480 * number in uint64_t.
481 * Conversion stopped at first non-digit character or after @a maxlen
482 * digits.
483 *
484 * @param str string to convert
485 * @param maxlen maximum number of characters to process
486 * @param[out] out_val pointer to uint64_t to store result of conversion
487 * @return non-zero number of characters processed on succeed,
488 * zero if no digit is found, resulting value is larger
489 * then possible to store in uint64_t or @a out_val is NULL
490 */
491size_t
492MHD_str_to_uint64_n_ (const char * str,
493 size_t maxlen,
494 uint64_t *out_val)
495{
496 uint64_t res;
497 size_t i;
498
499 if (!str || !maxlen || !out_val || !isasciidigit (str[0]))
500 return 0;
501
502 res = 0;
503 i = 0;
504 do
505 {
506 const int digit = (unsigned char)str[i] - '0';
507
508 if ( (res > (UINT64_MAX / 10)) ||
509 ( (res == (UINT64_MAX / 10)) &&
510 ((uint64_t)digit > (UINT64_MAX % 10)) ) )
511 return 0;
512
513 res *= 10;
514 res += digit;
515 i++;
516 } while ( (i < maxlen) &&
517 isasciidigit (str[i]) );
518
519 *out_val= res;
520 return i;
521}
522
523
524/**
525 * Convert hexadecimal US-ASCII digits in string to number in uint32_t.
526 * Conversion stopped at first non-digit character.
527 *
528 * @param str string to convert
529 * @param[out] out_val pointer to uint32_t to store result of conversion
530 * @return non-zero number of characters processed on succeed,
531 * zero if no digit is found, resulting value is larger
532 * then possible to store in uint32_t or @a out_val is NULL
533 */
534size_t
535MHD_strx_to_uint32_ (const char * str,
536 uint32_t *out_val)
537{
538 const char * const start = str;
539 uint32_t res;
540 int digit;
541
542 if (!str || !out_val)
543 return 0;
544
545 res = 0;
546 digit = toxdigitvalue (*str);
547 while (digit >= 0)
548 {
549 if ( (res < (UINT32_MAX / 16)) ||
550 (res == (UINT32_MAX / 16) && (uint32_t)digit <= (UINT32_MAX % 16)) )
551 {
552 res *= 16;
553 res += digit;
554 }
555 else
556 return 0;
557 str++;
558 digit = toxdigitvalue (*str);
559 }
560
561 if (str - start > 0)
562 *out_val = res;
563 return str - start;
564}
565
566
567/**
568 * Convert not more then @a maxlen hexadecimal US-ASCII digits in string
569 * to number in uint32_t.
570 * Conversion stopped at first non-digit character or after @a maxlen
571 * digits.
572 *
573 * @param str string to convert
574 * @param maxlen maximum number of characters to process
575 * @param[out] out_val pointer to uint32_t to store result of conversion
576 * @return non-zero number of characters processed on succeed,
577 * zero if no digit is found, resulting value is larger
578 * then possible to store in uint32_t or @a out_val is NULL
579 */
580size_t
581MHD_strx_to_uint32_n_ (const char *str,
582 size_t maxlen,
583 uint32_t *out_val)
584{
585 size_t i;
586 uint32_t res;
587 int digit;
588 if (!str || !out_val)
589 return 0;
590
591 res = 0;
592 i = 0;
593 while (i < maxlen && (digit = toxdigitvalue (str[i])) >= 0)
594 {
595 if ( (res > (UINT32_MAX / 16)) ||
596 (res == (UINT32_MAX / 16) && (uint32_t)digit > (UINT32_MAX % 16)) )
597 return 0;
598
599 res *= 16;
600 res += digit;
601 i++;
602 }
603
604 if (i)
605 *out_val = res;
606 return i;
607}
608
609
610/**
611 * Convert hexadecimal US-ASCII digits in string to number in uint64_t.
612 * Conversion stopped at first non-digit character.
613 *
614 * @param str string to convert
615 * @param[out] out_val pointer to uint64_t to store result of conversion
616 * @return non-zero number of characters processed on succeed,
617 * zero if no digit is found, resulting value is larger
618 * then possible to store in uint64_t or @a out_val is NULL
619 */
620size_t
621MHD_strx_to_uint64_ (const char *str,
622 uint64_t *out_val)
623{
624 const char * const start = str;
625 uint64_t res;
626 int digit;
627 if (!str || !out_val)
628 return 0;
629
630 res = 0;
631 digit = toxdigitvalue (*str);
632 while (digit >= 0)
633 {
634 if ( (res < (UINT64_MAX / 16)) ||
635 (res == (UINT64_MAX / 16) && (uint64_t)digit <= (UINT64_MAX % 16)) )
636 {
637 res *= 16;
638 res += digit;
639 }
640 else
641 return 0;
642 str++;
643 digit = toxdigitvalue (*str);
644 }
645
646 if (str - start > 0)
647 *out_val = res;
648 return str - start;
649}
650
651
652/**
653 * Convert not more then @a maxlen hexadecimal US-ASCII digits in string
654 * to number in uint64_t.
655 * Conversion stopped at first non-digit character or after @a maxlen
656 * digits.
657 *
658 * @param str string to convert
659 * @param maxlen maximum number of characters to process
660 * @param[out] out_val pointer to uint64_t to store result of conversion
661 * @return non-zero number of characters processed on succeed,
662 * zero if no digit is found, resulting value is larger
663 * then possible to store in uint64_t or @a out_val is NULL
664 */
665size_t
666MHD_strx_to_uint64_n_ (const char * str,
667 size_t maxlen,
668 uint64_t *out_val)
669{
670 size_t i;
671 uint64_t res;
672 int digit;
673 if (!str || !out_val)
674 return 0;
675
676 res = 0;
677 i = 0;
678 while (i < maxlen && (digit = toxdigitvalue (str[i])) >= 0)
679 {
680 if ( (res > (UINT64_MAX / 16)) ||
681 (res == (UINT64_MAX / 16) && (uint64_t)digit > (UINT64_MAX % 16)) )
682 return 0;
683
684 res *= 16;
685 res += digit;
686 i++;
687 }
688
689 if (i)
690 *out_val = res;
691 return i;
692}
693
694#else /* MHD_FAVOR_SMALL_CODE */
695
696/**
697 * Generic function for converting not more then @a maxlen
698 * hexadecimal or decimal US-ASCII digits in string to number.
699 * Conversion stopped at first non-digit character or after @a maxlen
700 * digits.
701 * To be used only within macro.
702 *
703 * @param str the string to convert
704 * @param maxlen the maximum number of characters to process
705 * @param out_val the pointer to variable to store result of conversion
706 * @param val_size the size of variable pointed by @a out_val, in bytes, 4 or 8
707 * @param max_val the maximum decoded number
708 * @param base the numeric base, 10 or 16
709 * @return non-zero number of characters processed on succeed,
710 * zero if no digit is found, resulting value is larger
711 * then @max_val, @val_size is not 16/32 or @a out_val is NULL
712 */
713size_t
714MHD_str_to_uvalue_n_ (const char *str,
715 size_t maxlen,
716 void * out_val,
717 size_t val_size,
718 uint64_t max_val,
719 int base)
720{
721 size_t i;
722 uint64_t res;
723 int digit;
724 const uint64_t max_v_div_b = max_val / base;
725 const uint64_t max_v_mod_b = max_val % base;
726 /* 'digit->value' must be function, not macro */
727 int (*const dfunc)(char) = (base == 16) ?
728 toxdigitvalue : todigitvalue;
729
730 if ( !str || !out_val ||
731 (base != 16 && base != 10) )
732 return 0;
733
734 res = 0;
735 i = 0;
736 while (maxlen > i && 0 <= (digit = dfunc (str[i])))
737 {
738 if ( ((max_v_div_b) < res) ||
739 ((max_v_div_b) == res && (max_v_mod_b) < (uint64_t)digit) )
740 return 0;
741
742 res *= base;
743 res += digit;
744 i++;
745 }
746
747 if (i)
748 {
749 if (8 == val_size)
750 *(uint64_t*)out_val = res;
751 else if (4 == val_size)
752 *(uint32_t*)out_val = (uint32_t)res;
753 else
754 return 0;
755 }
756 return i;
757}
758#endif /* MHD_FAVOR_SMALL_CODE */
diff --git a/src/lib/mhd_str.h b/src/lib/mhd_str.h
new file mode 100644
index 00000000..410cc36e
--- /dev/null
+++ b/src/lib/mhd_str.h
@@ -0,0 +1,266 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2015, 2016 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file microhttpd/mhd_str.h
22 * @brief Header for string manipulating helpers
23 * @author Karlson2k (Evgeny Grin)
24 */
25
26#ifndef MHD_STR_H
27#define MHD_STR_H 1
28
29#include "mhd_options.h"
30
31#include <stdint.h>
32#include <stdlib.h>
33#ifdef HAVE_STDBOOL_H
34#include <stdbool.h>
35#endif /* HAVE_STDBOOL_H */
36
37#ifdef MHD_FAVOR_SMALL_CODE
38#include "mhd_limits.h"
39#endif /* MHD_FAVOR_SMALL_CODE */
40
41#ifndef MHD_STATICSTR_LEN_
42/**
43 * Determine length of static string / macro strings at compile time.
44 */
45#define MHD_STATICSTR_LEN_(macro) (sizeof(macro)/sizeof(char) - 1)
46#endif /* ! MHD_STATICSTR_LEN_ */
47
48/*
49 * Block of functions/macros that use US-ASCII charset as required by HTTP
50 * standards. Not affected by current locale settings.
51 */
52
53#ifndef MHD_FAVOR_SMALL_CODE
54/**
55 * Check two string for equality, ignoring case of US-ASCII letters.
56 * @param str1 first string to compare
57 * @param str2 second string to compare
58 * @return non-zero if two strings are equal, zero otherwise.
59 */
60int
61MHD_str_equal_caseless_ (const char * str1,
62 const char * str2);
63#else /* MHD_FAVOR_SMALL_CODE */
64/* Reuse MHD_str_equal_caseless_n_() to reduce size */
65#define MHD_str_equal_caseless_(s1,s2) MHD_str_equal_caseless_n_((s1),(s2), SIZE_MAX)
66#endif /* MHD_FAVOR_SMALL_CODE */
67
68
69/**
70 * Check two string for equality, ignoring case of US-ASCII letters and
71 * checking not more than @a maxlen characters.
72 * Compares up to first terminating null character, but not more than
73 * first @a maxlen characters.
74 * @param str1 first string to compare
75 * @param str2 second string to compare
76 * @param maxlen maximum number of characters to compare
77 * @return non-zero if two strings are equal, zero otherwise.
78 */
79int
80MHD_str_equal_caseless_n_ (const char * const str1,
81 const char * const str2,
82 size_t maxlen);
83
84
85/**
86 * Check whether @a str has case-insensitive @a token.
87 * Token could be surrounded by spaces and tabs and delimited by comma.
88 * Match succeed if substring between start, end of string or comma
89 * contains only case-insensitive token and optional spaces and tabs.
90 * @warning token must not contain null-charters except optional
91 * terminating null-character.
92 * @param str the string to check
93 * @param token the token to find
94 * @param token_len length of token, not including optional terminating
95 * null-character.
96 * @return non-zero if two strings are equal, zero otherwise.
97 */
98bool
99MHD_str_has_token_caseless_ (const char * str,
100 const char * const token,
101 size_t token_len);
102
103/**
104 * Check whether @a str has case-insensitive static @a tkn.
105 * Token could be surrounded by spaces and tabs and delimited by comma.
106 * Match succeed if substring between start, end of string or comma
107 * contains only case-insensitive token and optional spaces and tabs.
108 * @warning tkn must be static string
109 * @param str the string to check
110 * @param tkn the static string of token to find
111 * @return non-zero if two strings are equal, zero otherwise.
112 */
113#define MHD_str_has_s_token_caseless_(str,tkn) \
114 MHD_str_has_token_caseless_((str),(tkn),MHD_STATICSTR_LEN_(tkn))
115
116#ifndef MHD_FAVOR_SMALL_CODE
117/* Use individual function for each case to improve speed */
118
119/**
120 * Convert decimal US-ASCII digits in string to number in uint64_t.
121 * Conversion stopped at first non-digit character.
122 * @param str string to convert
123 * @param out_val pointer to uint64_t to store result of conversion
124 * @return non-zero number of characters processed on succeed,
125 * zero if no digit is found, resulting value is larger
126 * then possible to store in uint64_t or @a out_val is NULL
127 */
128size_t
129MHD_str_to_uint64_ (const char * str,
130 uint64_t * out_val);
131
132/**
133 * Convert not more then @a maxlen decimal US-ASCII digits in string to
134 * number in uint64_t.
135 * Conversion stopped at first non-digit character or after @a maxlen
136 * digits.
137 * @param str string to convert
138 * @param maxlen maximum number of characters to process
139 * @param out_val pointer to uint64_t to store result of conversion
140 * @return non-zero number of characters processed on succeed,
141 * zero if no digit is found, resulting value is larger
142 * then possible to store in uint64_t or @a out_val is NULL
143 */
144size_t
145MHD_str_to_uint64_n_ (const char * str,
146 size_t maxlen,
147 uint64_t * out_val);
148
149
150/**
151 * Convert hexadecimal US-ASCII digits in string to number in uint32_t.
152 * Conversion stopped at first non-digit character.
153 * @param str string to convert
154 * @param out_val pointer to uint32_t to store result of conversion
155 * @return non-zero number of characters processed on succeed,
156 * zero if no digit is found, resulting value is larger
157 * then possible to store in uint32_t or @a out_val is NULL
158 */
159size_t
160MHD_strx_to_uint32_ (const char * str,
161 uint32_t * out_val);
162
163
164/**
165 * Convert not more then @a maxlen hexadecimal US-ASCII digits in string
166 * to number in uint32_t.
167 * Conversion stopped at first non-digit character or after @a maxlen
168 * digits.
169 * @param str string to convert
170 * @param maxlen maximum number of characters to process
171 * @param out_val pointer to uint32_t to store result of conversion
172 * @return non-zero number of characters processed on succeed,
173 * zero if no digit is found, resulting value is larger
174 * then possible to store in uint32_t or @a out_val is NULL
175 */
176size_t
177MHD_strx_to_uint32_n_ (const char * str,
178 size_t maxlen,
179 uint32_t * out_val);
180
181
182/**
183 * Convert hexadecimal US-ASCII digits in string to number in uint64_t.
184 * Conversion stopped at first non-digit character.
185 * @param str string to convert
186 * @param out_val pointer to uint64_t to store result of conversion
187 * @return non-zero number of characters processed on succeed,
188 * zero if no digit is found, resulting value is larger
189 * then possible to store in uint64_t or @a out_val is NULL
190 */
191size_t
192MHD_strx_to_uint64_ (const char * str,
193 uint64_t * out_val);
194
195
196/**
197 * Convert not more then @a maxlen hexadecimal US-ASCII digits in string
198 * to number in uint64_t.
199 * Conversion stopped at first non-digit character or after @a maxlen
200 * digits.
201 * @param str string to convert
202 * @param maxlen maximum number of characters to process
203 * @param out_val pointer to uint64_t to store result of conversion
204 * @return non-zero number of characters processed on succeed,
205 * zero if no digit is found, resulting value is larger
206 * then possible to store in uint64_t or @a out_val is NULL
207 */
208size_t
209MHD_strx_to_uint64_n_ (const char * str,
210 size_t maxlen,
211 uint64_t * out_val);
212
213#else /* MHD_FAVOR_SMALL_CODE */
214/* Use one universal function and macros to reduce size */
215
216/**
217 * Generic function for converting not more then @a maxlen
218 * hexadecimal or decimal US-ASCII digits in string to number.
219 * Conversion stopped at first non-digit character or after @a maxlen
220 * digits.
221 * To be used only within macro.
222 * @param str the string to convert
223 * @param maxlen the maximum number of characters to process
224 * @param out_val the pointer to uint64_t to store result of conversion
225 * @param val_size the size of variable pointed by @a out_val
226 * @param max_val the maximum decoded number
227 * @param base the numeric base, 10 or 16
228 * @return non-zero number of characters processed on succeed,
229 * zero if no digit is found, resulting value is larger
230 * then @ max_val or @a out_val is NULL
231 */
232size_t
233MHD_str_to_uvalue_n_ (const char * str,
234 size_t maxlen,
235 void * out_val,
236 size_t val_size,
237 uint64_t max_val,
238 int base);
239
240#define MHD_str_to_uint64_(s,ov) MHD_str_to_uvalue_n_((s),SIZE_MAX,(ov),\
241 sizeof(uint64_t),UINT64_MAX,10)
242
243#define MHD_str_to_uint64_n_(s,ml,ov) MHD_str_to_uvalue_n_((s),(ml),(ov),\
244 sizeof(uint64_t),UINT64_MAX,10)
245
246#define MHD_strx_to_sizet_(s,ov) MHD_str_to_uvalue_n_((s),SIZE_MAX,(ov),\
247 sizeof(size_t),SIZE_MAX,16)
248
249#define MHD_strx_to_sizet_n_(s,ml,ov) MHD_str_to_uvalue_n_((s),(ml),(ov),\
250 sizeof(size_t),SIZE_MAX,16)
251
252#define MHD_strx_to_uint32_(s,ov) MHD_str_to_uvalue_n_((s),SIZE_MAX,(ov),\
253 sizeof(uint32_t),UINT32_MAX,16)
254
255#define MHD_strx_to_uint32_n_(s,ml,ov) MHD_str_to_uvalue_n_((s),(ml),(ov),\
256 sizeof(uint32_t),UINT32_MAX,16)
257
258#define MHD_strx_to_uint64_(s,ov) MHD_str_to_uvalue_n_((s),SIZE_MAX,(ov),\
259 sizeof(uint64_t),UINT64_MAX,16)
260
261#define MHD_strx_to_uint64_n_(s,ml,ov) MHD_str_to_uvalue_n_((s),(ml),(ov),\
262 sizeof(uint64_t),UINT64_MAX,16)
263
264#endif /* MHD_FAVOR_SMALL_CODE */
265
266#endif /* MHD_STR_H */
diff --git a/src/lib/mhd_threads.c b/src/lib/mhd_threads.c
new file mode 100644
index 00000000..6578e4b1
--- /dev/null
+++ b/src/lib/mhd_threads.c
@@ -0,0 +1,363 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2016 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file microhttpd/mhd_threads.c
23 * @brief Implementation for thread functions
24 * @author Karlson2k (Evgeny Grin)
25 */
26
27#include "mhd_threads.h"
28#ifdef MHD_USE_W32_THREADS
29#include "mhd_limits.h"
30#include <process.h>
31#endif
32#ifdef MHD_USE_THREAD_NAME_
33#include <stdlib.h>
34#ifdef HAVE_PTHREAD_NP_H
35#include <pthread_np.h>
36#endif /* HAVE_PTHREAD_NP_H */
37#endif /* MHD_USE_THREAD_NAME_ */
38#include <errno.h>
39
40
41#ifndef MHD_USE_THREAD_NAME_
42
43#define MHD_set_thread_name_(t, n) (void)
44#define MHD_set_cur_thread_name_(n) (void)
45
46#else /* MHD_USE_THREAD_NAME_ */
47
48#if defined(MHD_USE_POSIX_THREADS)
49#if defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD) || defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
50# define MHD_USE_THREAD_ATTR_SETNAME 1
51#endif /* HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD || HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI */
52
53#if defined(HAVE_PTHREAD_SETNAME_NP_GNU) || defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD) \
54 || defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
55
56/**
57 * Set thread name
58 *
59 * @param thread_id ID of thread
60 * @param thread_name name to set
61 * @return non-zero on success, zero otherwise
62 */
63static int
64MHD_set_thread_name_(const MHD_thread_ID_ thread_id,
65 const char *thread_name)
66{
67 if (NULL == thread_name)
68 return 0;
69
70#if defined(HAVE_PTHREAD_SETNAME_NP_GNU)
71 return !pthread_setname_np (thread_id, thread_name);
72#elif defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD)
73 /* FreeBSD and OpenBSD use different name and void return type */
74 pthread_set_name_np (thread_id, thread_name);
75 return !0;
76#elif defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
77 /* NetBSD use 3 arguments: second argument is string in printf-like format,
78 * third argument is single argument for printf;
79 * OSF1 use 3 arguments too, but last one always must be zero (NULL).
80 * MHD doesn't use '%' in thread names, so both form are used in same way.
81 */
82 return !pthread_setname_np (thread_id, thread_name, 0);
83#endif /* HAVE_PTHREAD_SETNAME_NP_NETBSD */
84}
85
86
87#ifndef __QNXNTO__
88/**
89 * Set current thread name
90 * @param n name to set
91 * @return non-zero on success, zero otherwise
92 */
93#define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(pthread_self(),(n))
94#else /* __QNXNTO__ */
95/* Special case for QNX Neutrino - using zero for thread ID sets name faster. */
96#define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(0,(n))
97#endif /* __QNXNTO__ */
98#elif defined(HAVE_PTHREAD_SETNAME_NP_DARWIN)
99
100/**
101 * Set current thread name
102 * @param n name to set
103 * @return non-zero on success, zero otherwise
104 */
105#define MHD_set_cur_thread_name_(n) (!(pthread_setname_np((n))))
106#endif /* HAVE_PTHREAD_SETNAME_NP_DARWIN */
107
108#elif defined(MHD_USE_W32_THREADS)
109#ifndef _MSC_FULL_VER
110/* Thread name available only for VC-compiler */
111#else /* _MSC_FULL_VER */
112/**
113 * Set thread name
114 *
115 * @param thread_id ID of thread, -1 for current thread
116 * @param thread_name name to set
117 * @return non-zero on success, zero otherwise
118 */
119static int
120MHD_set_thread_name_(const MHD_thread_ID_ thread_id,
121 const char *thread_name)
122{
123 static const DWORD VC_SETNAME_EXC = 0x406D1388;
124#pragma pack(push,8)
125 struct thread_info_struct
126 {
127 DWORD type; /* Must be 0x1000. */
128 LPCSTR name; /* Pointer to name (in user address space). */
129 DWORD ID; /* Thread ID (-1 = caller thread). */
130 DWORD flags; /* Reserved for future use, must be zero. */
131 } thread_info;
132#pragma pack(pop)
133
134 if (NULL == thread_name)
135 return 0;
136
137 thread_info.type = 0x1000;
138 thread_info.name = thread_name;
139 thread_info.ID = thread_id;
140 thread_info.flags = 0;
141
142 __try
143 { /* This exception is intercepted by debugger */
144 RaiseException (VC_SETNAME_EXC,
145 0,
146 sizeof (thread_info) / sizeof(ULONG_PTR),
147 (ULONG_PTR *) &thread_info);
148 }
149 __except (EXCEPTION_EXECUTE_HANDLER)
150 {}
151
152 return !0;
153}
154
155
156/**
157 * Set current thread name
158 * @param n name to set
159 * @return non-zero on success, zero otherwise
160 */
161#define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(-1,(n))
162#endif /* _MSC_FULL_VER */
163#endif /* MHD_USE_W32_THREADS */
164
165#endif /* MHD_USE_THREAD_NAME_ */
166
167
168/**
169 * Create a thread and set the attributes according to our options.
170 *
171 * @param thread handle to initialize
172 * @param stack_size size of stack for new thread, 0 for default
173 * @param start_routine main function of thread
174 * @param arg argument for start_routine
175 * @return non-zero on success; zero otherwise (with errno set)
176 */
177int
178MHD_create_thread_ (MHD_thread_handle_ID_ *thread,
179 size_t stack_size,
180 MHD_THREAD_START_ROUTINE_ start_routine,
181 void *arg)
182{
183#if defined(MHD_USE_POSIX_THREADS)
184 int res;
185
186 if (0 != stack_size)
187 {
188 pthread_attr_t attr;
189 res = pthread_attr_init (&attr);
190 if (0 == res)
191 {
192 res = pthread_attr_setstacksize (&attr,
193 stack_size);
194 if (0 == res)
195 res = pthread_create (&(thread->handle),
196 &attr,
197 start_routine,
198 arg);
199 pthread_attr_destroy (&attr);
200 }
201 }
202 else
203 res = pthread_create (&(thread->handle),
204 NULL,
205 start_routine,
206 arg);
207
208 if (0 != res)
209 errno = res;
210
211 return !res;
212#elif defined(MHD_USE_W32_THREADS)
213#if SIZE_MAX != UINT_MAX
214 if (stack_size > UINT_MAX)
215 {
216 errno = EINVAL;
217 return 0;
218 }
219#endif /* SIZE_MAX != UINT_MAX */
220
221 thread->handle = (MHD_thread_handle_)
222 _beginthreadex (NULL,
223 (unsigned int) stack_size,
224 start_routine,
225 arg,
226 0,
227 NULL);
228
229 if ((MHD_thread_handle_)-1 == thread->handle)
230 return 0;
231
232 return !0;
233#endif
234}
235
236#ifdef MHD_USE_THREAD_NAME_
237
238#ifndef MHD_USE_THREAD_ATTR_SETNAME
239struct MHD_named_helper_param_
240{
241 /**
242 * Real thread start routine
243 */
244 MHD_THREAD_START_ROUTINE_ start_routine;
245
246 /**
247 * Argument for thread start routine
248 */
249 void *arg;
250
251 /**
252 * Name for thread
253 */
254 const char *name;
255};
256
257
258static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
259named_thread_starter (void *data)
260{
261 struct MHD_named_helper_param_ * const param =
262 (struct MHD_named_helper_param_ *) data;
263 void * arg;
264 MHD_THREAD_START_ROUTINE_ thr_func;
265
266 if (NULL == data)
267 return (MHD_THRD_RTRN_TYPE_)0;
268
269 MHD_set_cur_thread_name_ (param->name);
270
271 arg = param->arg;
272 thr_func = param->start_routine;
273 free(data);
274
275 return thr_func(arg);
276}
277#endif /* ! MHD_USE_THREAD_ATTR_SETNAME */
278
279
280/**
281 * Create a named thread and set the attributes according to our options.
282 *
283 * @param thread handle to initialize
284 * @param thread_name name for new thread
285 * @param stack_size size of stack for new thread, 0 for default
286 * @param start_routine main function of thread
287 * @param arg argument for start_routine
288 * @return non-zero on success; zero otherwise (with errno set)
289 */
290int
291MHD_create_named_thread_ (MHD_thread_handle_ID_ *thread,
292 const char* thread_name,
293 size_t stack_size,
294 MHD_THREAD_START_ROUTINE_ start_routine,
295 void *arg)
296{
297#if defined(MHD_USE_THREAD_ATTR_SETNAME)
298 int res;
299 pthread_attr_t attr;
300
301 res = pthread_attr_init (&attr);
302 if (0 == res)
303 {
304#if defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD)
305 /* NetBSD use 3 arguments: second argument is string in printf-like format,
306 * third argument is single argument for printf;
307 * OSF1 use 3 arguments too, but last one always must be zero (NULL).
308 * MHD doesn't use '%' in thread names, so both form are used in same way.
309 */
310 res = pthread_attr_setname_np (&attr, thread_name, 0);
311#elif defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
312 res = pthread_attr_setname_np (&attr, thread_name);
313#else
314#error No pthread_attr_setname_np() function.
315#endif
316 if (res == 0 && 0 != stack_size)
317 res = pthread_attr_setstacksize (&attr,
318 stack_size);
319 if (0 == res)
320 res = pthread_create (&(thread->handle),
321 &attr,
322 start_routine,
323 arg);
324 pthread_attr_destroy (&attr);
325 }
326 if (0 != res)
327 errno = res;
328
329 return !res;
330#else /* ! MHD_USE_THREAD_ATTR_SETNAME */
331 struct MHD_named_helper_param_ *param;
332
333 if (NULL == thread_name)
334 {
335 errno = EINVAL;
336 return 0;
337 }
338
339 param = malloc (sizeof (struct MHD_named_helper_param_));
340 if (NULL == param)
341 return 0;
342
343 param->start_routine = start_routine;
344 param->arg = arg;
345 param->name = thread_name;
346
347 /* Set thread name in thread itself to avoid problems with
348 * threads which terminated before name is set in other thread.
349 */
350 if (! MHD_create_thread_(thread,
351 stack_size,
352 &named_thread_starter,
353 (void*)param))
354 {
355 free (param);
356 return 0;
357 }
358
359 return !0;
360#endif /* ! MHD_USE_THREAD_ATTR_SETNAME */
361}
362
363#endif /* MHD_USE_THREAD_NAME_ */
diff --git a/src/lib/mhd_threads.h b/src/lib/mhd_threads.h
new file mode 100644
index 00000000..6d69b9ed
--- /dev/null
+++ b/src/lib/mhd_threads.h
@@ -0,0 +1,229 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2016 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file microhttpd/mhd_threads.h
23 * @brief Header for platform-independent threads abstraction
24 * @author Karlson2k (Evgeny Grin)
25 *
26 * Provides basic abstraction for threads.
27 * Any functions can be implemented as macro on some platforms
28 * unless explicitly marked otherwise.
29 * Any function argument can be skipped in macro, so avoid
30 * variable modification in function parameters.
31 *
32 * @warning Unlike pthread functions, most of functions return
33 * nonzero on success.
34 */
35
36#ifndef MHD_THREADS_H
37#define MHD_THREADS_H 1
38
39#include "mhd_options.h"
40#ifdef HAVE_STDDEF_H
41# include <stddef.h> /* for size_t */
42#else /* ! HAVE_STDDEF_H */
43# include <stdlib.h> /* for size_t */
44#endif /* ! HAVE_STDDEF_H */
45
46#if defined(MHD_USE_POSIX_THREADS)
47# undef HAVE_CONFIG_H
48# include <pthread.h>
49# define HAVE_CONFIG_H 1
50#elif defined(MHD_USE_W32_THREADS)
51# ifndef WIN32_LEAN_AND_MEAN
52# define WIN32_LEAN_AND_MEAN 1
53# endif /* !WIN32_LEAN_AND_MEAN */
54# include <windows.h>
55#else
56# error No threading API is available.
57#endif
58
59#ifndef MHD_NO_THREAD_NAMES
60# if defined(MHD_USE_POSIX_THREADS)
61# if defined(HAVE_PTHREAD_SETNAME_NP_GNU) || defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD) || \
62 defined(HAVE_PTHREAD_SETNAME_NP_DARWIN) || defined(HAVE_PTHREAD_SETNAME_NP_NETBSD) || \
63 defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD) || defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
64# define MHD_USE_THREAD_NAME_
65# endif /* HAVE_PTHREAD_SETNAME_NP */
66# elif defined(MHD_USE_W32_THREADS)
67# ifdef _MSC_FULL_VER
68 /* Thread names only available with VC compiler */
69# define MHD_USE_THREAD_NAME_
70# endif /* _MSC_FULL_VER */
71# endif
72#endif
73
74#if defined(MHD_USE_POSIX_THREADS)
75 typedef pthread_t MHD_thread_handle_;
76#elif defined(MHD_USE_W32_THREADS)
77 typedef HANDLE MHD_thread_handle_;
78#endif
79
80#if defined(MHD_USE_POSIX_THREADS)
81# define MHD_THRD_RTRN_TYPE_ void*
82# define MHD_THRD_CALL_SPEC_
83#elif defined(MHD_USE_W32_THREADS)
84# define MHD_THRD_RTRN_TYPE_ unsigned
85# define MHD_THRD_CALL_SPEC_ __stdcall
86#endif
87
88#if defined(MHD_USE_POSIX_THREADS)
89 typedef pthread_t MHD_thread_ID_;
90#elif defined(MHD_USE_W32_THREADS)
91 typedef DWORD MHD_thread_ID_;
92#endif
93
94/* Depending on implementation, pthread_create() MAY set thread ID into
95 * provided pointer and after it start thread OR start thread and after
96 * if set thread ID. In latter case, to avoid data races, additional
97 * pthread_self() call is required in thread routine. Is some platform
98 * is known for setting thread ID BEFORE starting thread macro
99 * MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD could be defined
100 * to save some resources. */
101#if defined(MHD_USE_POSIX_THREADS)
102# ifdef MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD
103 union _MHD_thread_handle_ID_
104 {
105 MHD_thread_handle_ handle; /**< To be used in other threads */
106 MHD_thread_ID_ ID; /**< To be used in thread itself */
107 };
108 typedef union _MHD_thread_handle_ID_ MHD_thread_handle_ID_;
109# else /* ! MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD */
110 struct _MHD_thread_handle_ID_
111 {
112 MHD_thread_handle_ handle; /**< To be used in other threads */
113 MHD_thread_ID_ ID; /**< To be used in thread itself */
114 };
115 typedef struct _MHD_thread_handle_ID_ MHD_thread_handle_ID_;
116# endif /* ! MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD */
117#elif defined(MHD_USE_W32_THREADS)
118 struct _MHD_thread_handle_ID_
119 {
120 MHD_thread_handle_ handle; /**< To be used in other threads */
121 MHD_thread_ID_ ID; /**< To be used in thread itself */
122 };
123 typedef struct _MHD_thread_handle_ID_ MHD_thread_handle_ID_;
124#endif
125
126#if defined(MHD_USE_POSIX_THREADS)
127/**
128 * Wait until specified thread is ended and free thread handle on success.
129 * @param thread handle to watch
130 * @return nonzero on success, zero otherwise
131 */
132#define MHD_join_thread_(thread) (!pthread_join((thread), NULL))
133#elif defined(MHD_USE_W32_THREADS)
134/**
135 * Wait until specified thread is ended and free thread handle on success.
136 * @param thread handle to watch
137 * @return nonzero on success, zero otherwise
138 */
139#define MHD_join_thread_(thread) (WAIT_OBJECT_0 == WaitForSingleObject((thread), INFINITE) ? (CloseHandle((thread)), !0) : 0)
140#endif
141
142#if defined(MHD_USE_POSIX_THREADS)
143/**
144 * Check whether provided thread ID match current thread.
145 * @param ID thread ID to match
146 * @return nonzero on match, zero otherwise
147 */
148#define MHD_thread_ID_match_current_(ID) (pthread_equal((ID), pthread_self()))
149#elif defined(MHD_USE_W32_THREADS)
150/**
151 * Check whether provided thread ID match current thread.
152 * @param ID thread ID to match
153 * @return nonzero on match, zero otherwise
154 */
155#define MHD_thread_ID_match_current_(ID) (GetCurrentThreadId() == (ID))
156#endif
157
158#if defined(MHD_USE_POSIX_THREADS)
159# ifdef MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD
160/**
161 * Initialise thread ID.
162 * @param thread_handle_ID_ptr pointer to thread handle-ID
163 */
164#define MHD_thread_init_(thread_handle_ID_ptr) (void)0
165# else /* ! MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD */
166/**
167 * Initialise thread ID.
168 * @param thread_handle_ID_ptr pointer to thread handle-ID
169 */
170#define MHD_thread_init_(thread_handle_ID_ptr) ((thread_handle_ID_ptr)->ID=pthread_self())
171# endif /* ! MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD */
172#elif defined(MHD_USE_W32_THREADS)
173/**
174 * Initialise thread ID.
175 * @param thread_handle_ID_ptr pointer to thread handle-ID
176 */
177#define MHD_thread_init_(thread_handle_ID_ptr) ((thread_handle_ID_ptr)->ID=GetCurrentThreadId())
178#endif
179
180/**
181 * Signature of main function for a thread.
182 *
183 * @param cls closure argument for the function
184 * @return termination code from the thread
185 */
186typedef MHD_THRD_RTRN_TYPE_
187(MHD_THRD_CALL_SPEC_ *MHD_THREAD_START_ROUTINE_)(void *cls);
188
189
190/**
191 * Create a thread and set the attributes according to our options.
192 *
193 * If thread is created, thread handle must be freed by MHD_join_thread_().
194 *
195 * @param thread handle to initialize
196 * @param stack_size size of stack for new thread, 0 for default
197 * @param start_routine main function of thread
198 * @param arg argument for start_routine
199 * @return non-zero on success; zero otherwise
200 */
201int
202MHD_create_thread_ (MHD_thread_handle_ID_ *thread,
203 size_t stack_size,
204 MHD_THREAD_START_ROUTINE_ start_routine,
205 void *arg);
206
207#ifndef MHD_USE_THREAD_NAME_
208#define MHD_create_named_thread_(t,n,s,r,a) MHD_create_thread_((t),(s),(r),(a))
209#else /* MHD_USE_THREAD_NAME_ */
210/**
211 * Create a named thread and set the attributes according to our options.
212 *
213 * @param thread handle to initialize
214 * @param thread_name name for new thread
215 * @param stack_size size of stack for new thread, 0 for default
216 * @param start_routine main function of thread
217 * @param arg argument for start_routine
218 * @return non-zero on success; zero otherwise
219 */
220int
221MHD_create_named_thread_ (MHD_thread_handle_ID_ *thread,
222 const char* thread_name,
223 size_t stack_size,
224 MHD_THREAD_START_ROUTINE_ start_routine,
225 void *arg);
226
227#endif /* MHD_USE_THREAD_NAME_ */
228
229#endif /* ! MHD_THREADS_H */
diff --git a/src/lib/sysfdsetsize.c b/src/lib/sysfdsetsize.c
new file mode 100644
index 00000000..fe7fba75
--- /dev/null
+++ b/src/lib/sysfdsetsize.c
@@ -0,0 +1,80 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2015 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file microhttpd/sysfdsetsize.c
22 * @brief Helper for obtaining FD_SETSIZE system default value
23 * @author Karlson2k (Evgeny Grin)
24 */
25
26
27#include "MHD_config.h"
28
29#ifdef FD_SETSIZE
30/* FD_SETSIZE was defined before system headers. */
31/* To get system value of FD_SETSIZE, undefine FD_SETSIZE
32 here. */
33#undef FD_SETSIZE
34#endif /* FD_SETSIZE */
35
36#include <stdlib.h>
37#if defined(__VXWORKS__) || defined(__vxworks) || defined(OS_VXWORKS)
38#include <sockLib.h>
39#endif /* OS_VXWORKS */
40#if HAVE_SYS_SELECT_H
41#include <sys/select.h>
42#endif /* HAVE_SYS_SELECT_H */
43#if HAVE_SYS_TYPES_H
44#include <sys/types.h>
45#endif /* HAVE_SYS_TYPES_H */
46#if HAVE_SYS_TIME_H
47#include <sys/time.h>
48#endif /* HAVE_SYS_TIME_H */
49#if HAVE_TIME_H
50#include <time.h>
51#endif /* HAVE_TIME_H */
52#ifdef HAVE_UNISTD_H
53#include <unistd.h>
54#endif /* HAVE_UNISTD_H */
55#if HAVE_SYS_SOCKET_H
56#include <sys/socket.h>
57#endif /* HAVE_SYS_SOCKET_H */
58
59#if defined(_WIN32) && !defined(__CYGWIN__)
60#ifndef WIN32_LEAN_AND_MEAN
61#define WIN32_LEAN_AND_MEAN 1
62#endif /* !WIN32_LEAN_AND_MEAN */
63#include <winsock2.h>
64#endif /* _WIN32 && !__CYGWIN__ */
65
66#ifndef FD_SETSIZE
67#error FD_SETSIZE must be defined in system headers
68#endif /* !FD_SETSIZE */
69
70#include "sysfdsetsize.h"
71
72/**
73 * Get system default value of FD_SETSIZE
74 * @return system default value of FD_SETSIZE
75 */
76int
77get_system_fdsetsize_value (void)
78{
79 return FD_SETSIZE;
80}
diff --git a/src/lib/sysfdsetsize.h b/src/lib/sysfdsetsize.h
new file mode 100644
index 00000000..e3585b22
--- /dev/null
+++ b/src/lib/sysfdsetsize.h
@@ -0,0 +1,36 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2015 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file microhttpd/sysfdsetsize.h
22 * @brief Helper for obtaining FD_SETSIZE system default value
23 * @author Karlson2k (Evgeny Grin)
24 */
25
26#ifndef SYSFDSETSIZE_H
27#define SYSFDSETSIZE_H 1
28
29/**
30 * Get system default value of FD_SETSIZE
31 * @return system default value of FD_SETSIZE
32 */
33int
34get_system_fdsetsize_value (void);
35
36#endif /* !SYSFDSETSIZE_H */
diff --git a/src/lib/tsearch.c b/src/lib/tsearch.c
new file mode 100644
index 00000000..fe5fcd5b
--- /dev/null
+++ b/src/lib/tsearch.c
@@ -0,0 +1,143 @@
1/*
2 * Tree search generalized from Knuth (6.2.2) Algorithm T just like
3 * the AT&T man page says.
4 *
5 * The node_t structure is for internal use only, lint doesn't grok it.
6 *
7 * Written by reading the System V Interface Definition, not the code.
8 *
9 * Totally public domain.
10 */
11
12#include "tsearch.h"
13#include <stdlib.h>
14
15
16typedef struct node
17{
18 const void *key;
19 struct node *llink;
20 struct node *rlink;
21} node_t;
22
23
24/* $NetBSD: tsearch.c,v 1.5 2005/11/29 03:12:00 christos Exp $ */
25/* find or insert datum into search tree */
26void *
27tsearch (const void *vkey, /* key to be located */
28 void **vrootp, /* address of tree root */
29 int (*compar)(const void *, const void *))
30{
31 node_t *q;
32 node_t **rootp = (node_t **)vrootp;
33
34 if (NULL == rootp)
35 return NULL;
36
37 while (*rootp != NULL)
38 { /* Knuth's T1: */
39 int r;
40
41 if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
42 return *rootp; /* we found it! */
43
44 rootp = (r < 0) ?
45 &(*rootp)->llink : /* T3: follow left branch */
46 &(*rootp)->rlink; /* T4: follow right branch */
47 }
48
49 q = malloc (sizeof(node_t)); /* T5: key not found */
50 if (q)
51 { /* make new node */
52 *rootp = q; /* link new node to old */
53 q->key = vkey; /* initialize new node */
54 q->llink = q->rlink = NULL;
55 }
56 return q;
57}
58
59
60/* $NetBSD: tfind.c,v 1.5 2005/03/23 08:16:53 kleink Exp $ */
61/* find a node, or return NULL */
62void *
63tfind (const void *vkey, /* key to be found */
64 void * const *vrootp, /* address of the tree root */
65 int (*compar)(const void *, const void *))
66{
67 node_t * const *rootp = (node_t * const*)vrootp;
68
69 if (NULL == rootp)
70 return NULL;
71
72 while (*rootp != NULL)
73 { /* T1: */
74 int r;
75
76 if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
77 return *rootp; /* key found */
78 rootp = (r < 0) ?
79 &(*rootp)->llink : /* T3: follow left branch */
80 &(*rootp)->rlink; /* T4: follow right branch */
81 }
82 return NULL;
83}
84
85
86/* $NetBSD: tdelete.c,v 1.2 1999/09/16 11:45:37 lukem Exp $ */
87/*
88 * delete node with given key
89 *
90 * vkey: key to be deleted
91 * vrootp: address of the root of the tree
92 * compar: function to carry out node comparisons
93 */
94void *
95tdelete (const void * __restrict vkey,
96 void ** __restrict vrootp,
97 int (*compar)(const void *, const void *))
98{
99 node_t **rootp = (node_t **)vrootp;
100 node_t *p;
101 node_t *q;
102 node_t *r;
103 int cmp;
104
105 if (rootp == NULL || (p = *rootp) == NULL)
106 return NULL;
107
108 while ((cmp = (*compar)(vkey, (*rootp)->key)) != 0)
109 {
110 p = *rootp;
111 rootp = (cmp < 0) ?
112 &(*rootp)->llink : /* follow llink branch */
113 &(*rootp)->rlink; /* follow rlink branch */
114 if (*rootp == NULL)
115 return NULL; /* key not found */
116 }
117 r = (*rootp)->rlink; /* D1: */
118 if ((q = (*rootp)->llink) == NULL) /* Left NULL? */
119 {
120 q = r;
121 }
122 else if (r != NULL)
123 { /* Right link is NULL? */
124 if (r->llink == NULL)
125 { /* D2: Find successor */
126 r->llink = q;
127 q = r;
128 }
129 else
130 { /* D3: Find NULL link */
131 for (q = r->llink; q->llink != NULL; q = r->llink)
132 r = q;
133 r->llink = q->rlink;
134 q->llink = (*rootp)->llink;
135 q->rlink = (*rootp)->rlink;
136 }
137 }
138 free(*rootp); /* D4: Free node */
139 *rootp = q; /* link parent to new node */
140 return p;
141}
142
143/* end of tsearch.c */
diff --git a/src/lib/tsearch.h b/src/lib/tsearch.h
new file mode 100644
index 00000000..aa186495
--- /dev/null
+++ b/src/lib/tsearch.h
@@ -0,0 +1,38 @@
1/*-
2 * Written by J.T. Conklin <jtc@netbsd.org>
3 * Public domain.
4 *
5 * $NetBSD: search.h,v 1.12 1999/02/22 10:34:28 christos Exp $
6 * $FreeBSD: release/9.0.0/include/search.h 105250 2002-10-16 14:29:23Z robert $
7 */
8
9#ifndef _TSEARCH_H_
10#define _TSEARCH_H_
11
12#if defined(__cplusplus)
13extern "C" {
14#endif /* __cplusplus */
15
16
17void *
18tdelete (const void * __restrict,
19 void ** __restrict,
20 int (*)(const void *, const void *));
21
22
23void *
24tfind (const void *,
25 void * const *,
26 int (*)(const void *, const void *));
27
28
29void *
30tsearch (const void *,
31 void **,
32 int (*)(const void *, const void *));
33
34#if defined(__cplusplus)
35};
36#endif /* __cplusplus */
37
38#endif /* !_TSEARCH_H_ */
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index fdc81ccc..639add58 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -5526,7 +5526,17 @@ MHD_start_daemon_va (unsigned int flags,
5526 (0 == (*pflags & MHD_USE_NO_LISTEN_SOCKET)) ) 5526 (0 == (*pflags & MHD_USE_NO_LISTEN_SOCKET)) )
5527 { 5527 {
5528 /* try to open listen socket */ 5528 /* try to open listen socket */
5529 listen_fd = MHD_socket_create_listen_(*pflags & MHD_USE_IPv6); 5529 int domain;
5530
5531#ifdef HAVE_INET6
5532 domain = (*pflags & MHD_USE_IPv6) ? PF_INET6 : PF_INET;
5533#else /* ! HAVE_INET6 */
5534 if (*pflags & MHD_USE_IPv6)
5535 goto free_and_fail;
5536 domain = PF_INET;
5537#endif /* ! HAVE_INET6 */
5538
5539 listen_fd = MHD_socket_create_listen_(domain);
5530 if (MHD_INVALID_SOCKET == listen_fd) 5540 if (MHD_INVALID_SOCKET == listen_fd)
5531 { 5541 {
5532#ifdef HAVE_MESSAGES 5542#ifdef HAVE_MESSAGES
diff --git a/src/microhttpd/mhd_sockets.c b/src/microhttpd/mhd_sockets.c
index ddcc1f25..356d288f 100644
--- a/src/microhttpd/mhd_sockets.c
+++ b/src/microhttpd/mhd_sockets.c
@@ -464,31 +464,22 @@ MHD_socket_noninheritable_ (MHD_socket sock)
464/** 464/**
465 * Create a listen socket, with noninheritable flag if possible. 465 * Create a listen socket, with noninheritable flag if possible.
466 * 466 *
467 * @param use_ipv6 if set to non-zero IPv6 is used 467 * @param pf protocol family to use
468 * @return created socket or MHD_INVALID_SOCKET in case of errors 468 * @return created socket or MHD_INVALID_SOCKET in case of errors
469 */ 469 */
470MHD_socket 470MHD_socket
471MHD_socket_create_listen_ (bool use_ipv6) 471MHD_socket_create_listen_ (int pf)
472{ 472{
473 int domain;
474 MHD_socket fd; 473 MHD_socket fd;
475 int cloexec_set; 474 int cloexec_set;
476 475
477#ifdef HAVE_INET6
478 domain = (use_ipv6) ? PF_INET6 : PF_INET;
479#else /* ! HAVE_INET6 */
480 if (use_ipv6)
481 return MHD_INVALID_SOCKET;
482 domain = PF_INET;
483#endif /* ! HAVE_INET6 */
484
485#if defined(MHD_POSIX_SOCKETS) && defined(SOCK_CLOEXEC) 476#if defined(MHD_POSIX_SOCKETS) && defined(SOCK_CLOEXEC)
486 fd = socket (domain, 477 fd = socket (pf,
487 SOCK_STREAM | SOCK_CLOEXEC, 478 SOCK_STREAM | SOCK_CLOEXEC,
488 0); 479 0);
489 cloexec_set = !0; 480 cloexec_set = !0;
490#elif defined(MHD_WINSOCK_SOCKETS) && defined (WSA_FLAG_NO_HANDLE_INHERIT) 481#elif defined(MHD_WINSOCK_SOCKETS) && defined (WSA_FLAG_NO_HANDLE_INHERIT)
491 fd = WSASocketW (domain, 482 fd = WSASocketW (pf,
492 SOCK_STREAM, 483 SOCK_STREAM,
493 0, 484 0,
494 NULL, 485 NULL,
@@ -500,7 +491,7 @@ MHD_socket_create_listen_ (bool use_ipv6)
500#endif /* !SOCK_CLOEXEC */ 491#endif /* !SOCK_CLOEXEC */
501 if (MHD_INVALID_SOCKET == fd) 492 if (MHD_INVALID_SOCKET == fd)
502 { 493 {
503 fd = socket (domain, 494 fd = socket (pf,
504 SOCK_STREAM, 495 SOCK_STREAM,
505 0); 496 0);
506 cloexec_set = 0; 497 cloexec_set = 0;