diff options
author | Christian Grothoff <christian@grothoff.org> | 2018-02-09 06:09:02 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2018-02-09 06:09:02 +0100 |
commit | 7512349b3bb7ec147195cf25864f637e1a99c569 (patch) | |
tree | 6870c0438764b096bd380f90aa54d54629b6cf3a | |
parent | e77fce2749a06b448e496140e8ad7e51891972de (diff) | |
download | libmicrohttpd-7512349b3bb7ec147195cf25864f637e1a99c569.tar.gz libmicrohttpd-7512349b3bb7ec147195cf25864f637e1a99c569.zip |
allow passing pf instead of just v6 flag to listen socket creation
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 @@ | |||
1 | dnl @synopsis AC_DEFINE_DIR(VARNAME, DIR [, DESCRIPTION]) | ||
2 | dnl | ||
3 | dnl This macro _AC_DEFINEs VARNAME to the expansion of the DIR | ||
4 | dnl variable, taking care of fixing up ${prefix} and such. | ||
5 | dnl | ||
6 | dnl VARNAME is offered as both a C preprocessor symbol, and an output | ||
7 | dnl variable. | ||
8 | dnl | ||
9 | dnl Note that the 3 argument form is only supported with autoconf 2.13 | ||
10 | dnl and later (i.e. only where _AC_DEFINE supports 3 arguments). | ||
11 | dnl | ||
12 | dnl Examples: | ||
13 | dnl | ||
14 | dnl AC_DEFINE_DIR(DATADIR, datadir) | ||
15 | dnl AC_DEFINE_DIR(PROG_PATH, bindir, [Location of installed binaries]) | ||
16 | dnl | ||
17 | dnl @category Misc | ||
18 | dnl @author Stepan Kasal <kasal@ucw.cz> | ||
19 | dnl @author Andreas Schwab <schwab@suse.de> | ||
20 | dnl @author Guido Draheim <guidod@gmx.de> | ||
21 | dnl @author Alexandre Oliva | ||
22 | dnl @version 2005-01-17 | ||
23 | dnl @license AllPermissive | ||
24 | |||
25 | AC_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 | ||
2 | AM_CPPFLAGS = \ | ||
3 | -I$(top_srcdir)/src/include \ | ||
4 | -I$(top_srcdir)/src/lib | ||
5 | |||
6 | AM_CFLAGS = $(HIDDEN_VISIBILITY_CFLAGS) | ||
7 | |||
8 | lib_LTLIBRARIES = \ | ||
9 | libmicrohttpd.la | ||
10 | |||
11 | noinst_DATA = | ||
12 | MOSTLYCLEANFILES = | ||
13 | |||
14 | if W32_SHARED_LIB_EXP | ||
15 | W32_MHD_LIB_LDFLAGS = -Wl,--output-def,$(lt_cv_objdir)/libmicrohttpd.def -XCClinker -static-libgcc | ||
16 | noinst_DATA += $(lt_cv_objdir)/libmicrohttpd.lib $(lt_cv_objdir)/libmicrohttpd.def $(lt_cv_objdir)/libmicrohttpd.exp | ||
17 | MOSTLYCLEANFILES += $(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) | ||
24 | if 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 .. | ||
30 | else | ||
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. | ||
37 | endif | ||
38 | else | ||
39 | W32_MHD_LIB_LDFLAGS = | ||
40 | endif | ||
41 | |||
42 | if W32_STATIC_LIB | ||
43 | noinst_DATA += $(lt_cv_objdir)/libmicrohttpd-static.lib | ||
44 | MOSTLYCLEANFILES += $(lt_cv_objdir)/libmicrohttpd-static.lib | ||
45 | |||
46 | $(lt_cv_objdir)/libmicrohttpd-static.lib: libmicrohttpd.la $(libmicrohttpd_la_OBJECTS) | ||
47 | if USE_MS_LIB_TOOL | ||
48 | $(MS_LIB_TOOL) -out:$@ $(libmicrohttpd_la_OBJECTS:.lo=.o) | ||
49 | else | ||
50 | cp $(lt_cv_objdir)/libmicrohttpd.a $@ | ||
51 | endif | ||
52 | endif | ||
53 | |||
54 | |||
55 | libmicrohttpd_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 | |||
98 | libmicrohttpd_la_CPPFLAGS = \ | ||
99 | $(AM_CPPFLAGS) $(MHD_LIB_CPPFLAGS) \ | ||
100 | -DBUILDING_MHD_LIB=1 | ||
101 | libmicrohttpd_la_CFLAGS = \ | ||
102 | $(AM_CFLAGS) $(MHD_LIB_CFLAGS) | ||
103 | libmicrohttpd_la_LDFLAGS = \ | ||
104 | $(MHD_LIB_LDFLAGS) \ | ||
105 | $(W32_MHD_LIB_LDFLAGS) \ | ||
106 | -version-info @LIB_VERSION_CURRENT@:@LIB_VERSION_REVISION@:@LIB_VERSION_AGE@ | ||
107 | libmicrohttpd_la_LIBADD = \ | ||
108 | $(MHD_LIBDEPS) | ||
109 | |||
110 | if HAVE_W32 | ||
111 | MHD_DLL_RES_SRC = microhttpd_dll_res.rc | ||
112 | MHD_DLL_RES_LO = libmicrohttpd_la-$(MHD_DLL_RES_SRC:.rc=.lo) | ||
113 | |||
114 | EXTRA_libmicrohttpd_la_DEPENDENCIES = $(MHD_DLL_RES_LO) | ||
115 | libmicrohttpd_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 | ||
133 | endif | ||
134 | |||
135 | if USE_COVERAGE | ||
136 | AM_CFLAGS += --coverage | ||
137 | endif | ||
138 | |||
139 | if !MHD_HAVE_TSEARCH | ||
140 | libmicrohttpd_la_SOURCES += \ | ||
141 | tsearch.c tsearch.h | ||
142 | endif | ||
143 | |||
144 | # TBD! | ||
145 | if HAVE_POSTPROCESSOR | ||
146 | libmicrohttpd_la_SOURCES += \ | ||
147 | postprocessor.c | ||
148 | endif | ||
149 | |||
150 | # TBD! | ||
151 | if ENABLE_DAUTH | ||
152 | libmicrohttpd_la_SOURCES += \ | ||
153 | digestauth.c \ | ||
154 | md5.c md5.h | ||
155 | endif | ||
156 | |||
157 | # TBD! | ||
158 | if ENABLE_BAUTH | ||
159 | libmicrohttpd_la_SOURCES += \ | ||
160 | basicauth.c \ | ||
161 | base64.c base64.h | ||
162 | endif | ||
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 | |||
11 | static 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 | |||
26 | char * | ||
27 | BASE64Decode(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 | |||
14 | char * | ||
15 | BASE64Decode(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 | */ | ||
35 | const char * | ||
36 | MHD_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 | */ | ||
93 | void | ||
94 | MHD_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 | */ | ||
116 | void | ||
117 | MHD_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 | */ | ||
135 | size_t | ||
136 | MHD_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 | */ | ||
183 | int | ||
184 | MHD_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 | |||
39 | static 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 | */ | ||
49 | void | ||
50 | MD5Init(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 | */ | ||
66 | void | ||
67 | MD5Update(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 | */ | ||
110 | void | ||
111 | MD5Pad(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 | */ | ||
134 | void | ||
135 | MD5Final(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 | */ | ||
167 | void | ||
168 | MD5Transform(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 | |||
27 | struct 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 | */ | ||
38 | void MD5Init(struct MD5Context *ctx); | ||
39 | |||
40 | /* | ||
41 | * Update context to reflect the concatenation of another buffer full | ||
42 | * of bytes. | ||
43 | */ | ||
44 | void 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 | */ | ||
50 | void MD5Pad(struct MD5Context *ctx); | ||
51 | |||
52 | /* | ||
53 | * Final wrapup--call MD5Pad, fill in digest and zero out ctx. | ||
54 | */ | ||
55 | void 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 | */ | ||
62 | void 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 | */ | ||
50 | struct 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 | ||
89 | MHD_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 | */ | ||
101 | struct MemoryPool * | ||
102 | MHD_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 | */ | ||
156 | void | ||
157 | MHD_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 | */ | ||
184 | size_t | ||
185 | MHD_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 | */ | ||
202 | void * | ||
203 | MHD_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 | */ | ||
247 | void * | ||
248 | MHD_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 | */ | ||
313 | void * | ||
314 | MHD_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 | */ | ||
38 | struct MemoryPool; | ||
39 | |||
40 | |||
41 | /** | ||
42 | * Create a memory pool. | ||
43 | * | ||
44 | * @param max maximum size of the pool | ||
45 | * @return NULL on error | ||
46 | */ | ||
47 | struct MemoryPool * | ||
48 | MHD_pool_create (size_t max); | ||
49 | |||
50 | |||
51 | /** | ||
52 | * Destroy a memory pool. | ||
53 | * | ||
54 | * @param pool memory pool to destroy | ||
55 | */ | ||
56 | void | ||
57 | MHD_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 | */ | ||
71 | void * | ||
72 | MHD_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 | */ | ||
94 | void * | ||
95 | MHD_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 | */ | ||
107 | size_t | ||
108 | MHD_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 | */ | ||
124 | void * | ||
125 | MHD_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 */ | ||
45 | int | ||
46 | W32_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 | |||
96 | void *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 */ | ||
52 | int 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 | */ | ||
84 | void *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 | */ | ||
46 | int | ||
47 | MHD_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 | */ | ||
76 | static 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 | */ | ||
45 | struct 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 | */ | ||
56 | struct 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 | */ | ||
70 | struct 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 | |||
56 | static 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 | |||
75 | static 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) | ||
80 | static time_t mono_clock_start; | ||
81 | #endif /* HAVE_CLOCK_GETTIME || HAVE_CLOCK_GET_TIME || HAVE_GETHRTIME */ | ||
82 | static time_t sys_clock_start; | ||
83 | #ifdef HAVE_GETHRTIME | ||
84 | static hrtime_t hrtime_start; | ||
85 | #endif /* HAVE_GETHRTIME */ | ||
86 | #ifdef _WIN32 | ||
87 | #if _WIN32_WINNT >= 0x0600 | ||
88 | static uint64_t tick_start; | ||
89 | #else /* _WIN32_WINNT < 0x0600 */ | ||
90 | static int64_t perf_freq; | ||
91 | static int64_t perf_start; | ||
92 | #endif /* _WIN32_WINNT < 0x0600 */ | ||
93 | #endif /* _WIN32 */ | ||
94 | |||
95 | |||
96 | |||
97 | /** | ||
98 | * Type of monotonic clock source | ||
99 | */ | ||
100 | enum _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 | */ | ||
137 | void | ||
138 | MHD_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 | */ | ||
315 | void | ||
316 | MHD_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 | */ | ||
336 | time_t | ||
337 | MHD_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 | */ | ||
39 | void | ||
40 | MHD_monotonic_sec_counter_init(void); | ||
41 | |||
42 | |||
43 | /** | ||
44 | * Deinitialise monotonic seconds counter by freeing any allocated resources | ||
45 | */ | ||
46 | void | ||
47 | MHD_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 | */ | ||
57 | time_t | ||
58 | MHD_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 | */ | ||
40 | const 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 | */ | ||
248 | int | ||
249 | MHD_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 | */ | ||
373 | int | ||
374 | MHD_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 | */ | ||
403 | int | ||
404 | MHD_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 | */ | ||
438 | int | ||
439 | MHD_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 | */ | ||
470 | MHD_socket | ||
471 | MHD_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 | */ | ||
711 | int | ||
712 | MHD_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 | */ | ||
724 | int | ||
725 | MHD_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 | */ | ||
735 | int | ||
736 | MHD_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 | */ | ||
757 | MHD_socket | ||
758 | MHD_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 | ||
62 | isasciilower (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 | ||
76 | isasciiupper (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 | ||
90 | isasciialpha (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 | ||
104 | isasciidigit (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 | ||
117 | isasciixdigit (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 | ||
132 | isasciialnum (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 | ||
149 | toasciilower (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 | ||
166 | toasciiupper (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 | ||
181 | todigitvalue (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 | ||
198 | toxdigitvalue (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 | */ | ||
328 | int | ||
329 | MHD_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 | */ | ||
358 | int | ||
359 | MHD_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 | */ | ||
392 | bool | ||
393 | MHD_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 | */ | ||
449 | size_t | ||
450 | MHD_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 | */ | ||
491 | size_t | ||
492 | MHD_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 | */ | ||
534 | size_t | ||
535 | MHD_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 | */ | ||
580 | size_t | ||
581 | MHD_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 | */ | ||
620 | size_t | ||
621 | MHD_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 | */ | ||
665 | size_t | ||
666 | MHD_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 | */ | ||
713 | size_t | ||
714 | MHD_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 | */ | ||
60 | int | ||
61 | MHD_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 | */ | ||
79 | int | ||
80 | MHD_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 | */ | ||
98 | bool | ||
99 | MHD_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 | */ | ||
128 | size_t | ||
129 | MHD_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 | */ | ||
144 | size_t | ||
145 | MHD_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 | */ | ||
159 | size_t | ||
160 | MHD_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 | */ | ||
176 | size_t | ||
177 | MHD_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 | */ | ||
191 | size_t | ||
192 | MHD_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 | */ | ||
208 | size_t | ||
209 | MHD_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 | */ | ||
232 | size_t | ||
233 | MHD_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 | */ | ||
63 | static int | ||
64 | MHD_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 | */ | ||
119 | static int | ||
120 | MHD_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 | */ | ||
177 | int | ||
178 | MHD_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 | ||
239 | struct 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 | |||
258 | static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_ | ||
259 | named_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 | */ | ||
290 | int | ||
291 | MHD_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 | */ | ||
186 | typedef 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 | */ | ||
201 | int | ||
202 | MHD_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 | */ | ||
220 | int | ||
221 | MHD_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 | */ | ||
76 | int | ||
77 | get_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 | */ | ||
33 | int | ||
34 | get_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 | |||
16 | typedef 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 */ | ||
26 | void * | ||
27 | tsearch (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 */ | ||
62 | void * | ||
63 | tfind (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 | */ | ||
94 | void * | ||
95 | tdelete (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) | ||
13 | extern "C" { | ||
14 | #endif /* __cplusplus */ | ||
15 | |||
16 | |||
17 | void * | ||
18 | tdelete (const void * __restrict, | ||
19 | void ** __restrict, | ||
20 | int (*)(const void *, const void *)); | ||
21 | |||
22 | |||
23 | void * | ||
24 | tfind (const void *, | ||
25 | void * const *, | ||
26 | int (*)(const void *, const void *)); | ||
27 | |||
28 | |||
29 | void * | ||
30 | tsearch (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 | */ |
470 | MHD_socket | 470 | MHD_socket |
471 | MHD_socket_create_listen_ (bool use_ipv6) | 471 | MHD_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; |