aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-02-07 23:28:38 +0100
committerChristian Grothoff <christian@grothoff.org>2018-02-07 23:28:38 +0100
commitf6e1ee426f9caebe49476ec88720d87032a433a6 (patch)
treef94ef39c8bf9289fa1d263ffc67ff65d57a12b83
parentb90f356c47e467407ae407723ddb02161b849f6a (diff)
downloadlibmicrohttpd-f6e1ee426f9caebe49476ec88720d87032a433a6.tar.gz
libmicrohttpd-f6e1ee426f9caebe49476ec88720d87032a433a6.zip
more work on mhd2 API implementation
-rw-r--r--src/include/microhttpd2.h173
-rw-r--r--src/lib/daemon.c954
-rw-r--r--src/lib/daemon_create.c134
-rw-r--r--src/lib/daemon_destroy.c178
-rw-r--r--src/lib/daemon_info.c60
-rw-r--r--src/lib/daemon_options.c30
-rw-r--r--src/lib/daemon_quiesce.c127
-rw-r--r--src/lib/init.c156
-rw-r--r--src/lib/init.h29
-rw-r--r--src/lib/internal.h604
-rw-r--r--src/lib/panic.c36
-rw-r--r--src/lib/request.c109
-rw-r--r--src/lib/version.c181
-rw-r--r--src/microhttpd/mhd_sockets.c2
-rw-r--r--src/microhttpd/mhd_sockets.h2
15 files changed, 2653 insertions, 122 deletions
diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h
index 4ee1b8d2..7a67fbd3 100644
--- a/src/include/microhttpd2.h
+++ b/src/include/microhttpd2.h
@@ -129,34 +129,181 @@ enum MHD_StatusCode
129 */ 129 */
130 MHD_SC_DAEMON_STARTED = 10000, 130 MHD_SC_DAEMON_STARTED = 10000,
131 131
132
133 /**
134 * MHD does not support the requested combination of
135 * EPOLL with thread-per-connection mode.
136 */
137 MHD_SC_SYSCALL_THREAD_COMBINATION_INVALID = 40000,
138
139 /**
140 * MHD does not support quiescing if ITC was disabled
141 * and threads are used.
142 */
143 MHD_SC_SYSCALL_QUIESCE_REQUIRES_ITC = 40001,
144
132 /** 145 /**
133 * This build of MHD does not support TLS, but the application 146 * This build of MHD does not support TLS, but the application
134 * requested TLS. 147 * requested TLS.
135 */ 148 */
136 MHD_TLS_DISABLED = 50000, 149 MHD_SC_TLS_DISABLED = 50000,
137 150
138 /** 151 /**
139 * The application requested an unsupported TLS backend to be used. 152 * The application requested an unsupported TLS backend to be used.
140 */ 153 */
141 MHD_TLS_BACKEND_UNSUPPORTED = 50001, 154 MHD_SC_TLS_BACKEND_UNSUPPORTED = 50001,
142 155
143 /** 156 /**
144 * The application requested a TLS cipher suite which is not 157 * The application requested a TLS cipher suite which is not
145 * supported by the selected backend. 158 * supported by the selected backend.
146 */ 159 */
147 MHD_TLS_CIPHERS_INVALID = 50002 160 MHD_SC_TLS_CIPHERS_INVALID = 50002
148 161
149 /** 162 /**
150 * The application attempted to setup TLS paramters before 163 * The application attempted to setup TLS paramters before
151 * enabling TLS. 164 * enabling TLS.
152 */ 165 */
153 MHD_TLS_BACKEND_UNINITIALIZED = 50003, 166 MHD_SC_TLS_BACKEND_UNINITIALIZED = 50003,
154 167
155 /** 168 /**
156 * The selected TLS backend does not yet support this operation. 169 * The selected TLS backend does not yet support this operation.
157 */ 170 */
158 MHD_TLS_BACKEND_OPERATION_UNSUPPORTED = 50004, 171 MHD_SC_TLS_BACKEND_OPERATION_UNSUPPORTED = 50004,
172
173 /**
174 * Failed to setup ITC channel.
175 */
176 MHD_SC_ITC_INITIALIZATION_FAILED = 50005,
177
178 /**
179 * File descriptor for ITC channel too large.
180 */
181 MHD_SC_ITC_DESCRIPTOR_TOO_LARGE = 50006,
182
183 /**
184 * The specified value for the NC length is way too large
185 * for this platform (integer overflow on `size_t`).
186 */
187 MHD_SC_DIGEST_AUTH_NC_LENGTH_TOO_BIG = 50007,
188
189 /**
190 * We failed to allocate memory for the specified nonce
191 * counter array. The option was not set.
192 */
193 MHD_SC_DIGEST_AUTH_NC_ALLOCATION_FAILURE = 50008,
194
195 /**
196 * This build of the library does not support
197 * digest authentication.
198 */
199 MHD_SC_DIGEST_AUTH_NOT_SUPPORTED_BY_BUILD = 50009,
200
201 /**
202 * IPv6 requested but not supported by this build.
203 */
204 MHD_SC_IPV6_NOT_SUPPORTED_BY_BUILD = 50010,
205
206 /**
207 * We failed to open the listen socket. Maybe the build
208 * supports IPv6, but your kernel does not?
209 */
210 MHD_SC_FAILED_TO_OPEN_LISTEN_SOCKET = 50011,
211
212 /**
213 * Specified address family is not supported by this build.
214 */
215 MHD_SC_AF_NOT_SUPPORTED_BY_BUILD = 50012,
216
217 /**
218 * Failed to enable listen address reuse.
219 */
220 MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_FAILED = 50013,
221
222 /**
223 * Enabling listen address reuse is not supported by this platform.
224 */
225 MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_NOT_SUPPORTED = 50014,
226
227 /**
228 * Failed to disable listen address reuse.
229 */
230 MHD_SC_LISTEN_ADDRESS_REUSE_DISABLE_FAILED = 50015,
231
232 /**
233 * Disabling listen address reuse is not supported by this platform.
234 */
235 MHD_SC_LISTEN_ADDRESS_REUSE_DISABLE_NOT_SUPPORTED = 50016,
236
237 /**
238 * We failed to explicitly enable or disable dual stack for
239 * the IPv6 listen socket. The socket will be used in whatever
240 * the default is the OS gives us.
241 */
242 MHD_SC_LISTEN_DUAL_STACK_CONFIGURATION_FAILED = 50017,
243
244 /**
245 * On this platform, MHD does not support explicitly configuring
246 * dual stack behavior.
247 */
248 MHD_SC_LISTEN_DUAL_STACK_CONFIGURATION_NOT_SUPPORTED = 50018,
249
250 /**
251 * We failed to bind the listen socket.
252 */
253 MHD_SC_LISTEN_SOCKET_BIND_FAILED = 50019,
254
255 /**
256 * Failed to enable TCP FAST OPEN option.
257 */
258 MHD_SC_FAST_OPEN_FAILURE = 50020,
159 259
260 /**
261 * Failed to start listening on listen socket.
262 */
263 MHD_SC_LISTEN_FAILURE = 50021,
264
265 /**
266 * Failed to obtain our listen port via introspection.
267 */
268 MHD_SC_LISTEN_PORT_INTROSPECTION_FAILURE = 50022,
269
270 /**
271 * Failed to obtain our listen port via introspection
272 * due to unsupported address family being used.
273 */
274 MHD_SC_LISTEN_PORT_INTROSPECTION_UNKNOWN_AF = 50023,
275
276 /**
277 * We failed to set the listen socket to non-blocking.
278 */
279 MHD_SC_LISTEN_SOCKET_NONBLOCKING_FAILURE = 50024,
280
281 /**
282 * Listen socket value is too large (for use with select()).
283 */
284 MHD_SC_LISTEN_SOCKET_TOO_LARGE = 50025,
285
286 /**
287 * We failed to allocate memory for the thread pool.
288 */
289 MHD_SC_THREAD_POOL_MALLOC_FAILURE = 50026,
290
291 /**
292 * We failed to allocate mutex for thread pool worker.
293 */
294 MHD_SC_THREAD_POOL_CREATE_MUTEX_FAILURE = 50027,
295
296 /**
297 * We failed to initialize the main thread for listening.
298 */
299 MHD_SC_THREAD_MAIN_LAUNCH_FAILURE = 50030,
300
301 /**
302 * We failed to initialize the threads for the worker pool.
303 */
304 MHD_SC_THREAD_POOL_LAUNCH_FAILURE = 50031,
305
306
160}; 307};
161 308
162 309
@@ -631,10 +778,17 @@ MHD_daemon_tcp_fastopen (struct MHD_Daemon *daemon,
631enum MHD_AddressFamily 778enum MHD_AddressFamily
632{ 779{
633 /** 780 /**
781 * Option not given, do not listen at all
782 * (unless listen socket or address specified by
783 * other means).
784 */
785 MHD_AF_NONE = 0,
786
787 /**
634 * Pick "best" available method automatically. 788 * Pick "best" available method automatically.
635 */ 789 */
636 MHD_AF_AUTO = 0, 790 MHD_AF_AUTO,
637 791
638 /** 792 /**
639 * Use IPv4. 793 * Use IPv4.
640 */ 794 */
@@ -662,8 +816,7 @@ enum MHD_AddressFamily
662 * is specified, MHD will simply not listen on any socket! 816 * is specified, MHD will simply not listen on any socket!
663 * 817 *
664 * @param daemon which instance to configure the TCP port for 818 * @param daemon which instance to configure the TCP port for
665 * @param af address family to use, i.e. #AF_INET or #AF_INET6, 819 * @param af address family to use
666 * or #AF_UNSPEC for dual stack
667 * @param port port to use, 0 to bind to a random (free) port 820 * @param port port to use, 0 to bind to a random (free) port
668 */ 821 */
669_MHD_EXTERN void 822_MHD_EXTERN void
@@ -1194,7 +1347,7 @@ MHD_daemon_digest_auth_random (struct MHD_Daemon *daemon,
1194 * @param daemon daemon to configure 1347 * @param daemon daemon to configure
1195 * @param nc_length desired array length 1348 * @param nc_length desired array length
1196 */ 1349 */
1197_MHD_EXTERN void 1350_MHD_EXTERN enum MHD_StatusCode
1198MHD_daemon_digest_auth_nc_length (struct MHD_Daemon *daemon, 1351MHD_daemon_digest_auth_nc_length (struct MHD_Daemon *daemon,
1199 size_t nc_length); 1352 size_t nc_length);
1200 1353
diff --git a/src/lib/daemon.c b/src/lib/daemon.c
index 6396cf9f..2973dd2e 100644
--- a/src/lib/daemon.c
+++ b/src/lib/daemon.c
@@ -19,154 +19,910 @@
19 19
20/** 20/**
21 * @file lib/daemon.c 21 * @file lib/daemon.c
22 * @brief main functions to create, start, quiesce and destroy a daemon 22 * @brief main functions to start a daemon
23 * @author Christian Grothoff 23 * @author Christian Grothoff
24 */ 24 */
25#include "internal.h" 25#include "internal.h"
26 26
27/* ************************* event loops ********************** */
28
29
30
31/* TODO: migrate! */
32
33
34/* ************* Functions for MHD_daemon_start() ************ */
35
27 36
28/** 37/**
29 * Logging implementation that logs to a file given 38 * Set listen socket options to allow port rebinding (or not)
30 * as the @a cls. 39 * depending on how MHD was configured.
31 * 40 *
32 * @param cls a `FILE *` to log to 41 * @param daemon[in,out] the daemon with the listen socket to configure
33 * @param sc status code of the event (ignored) 42 * @return #MHD_SC_OK on success (or non-fatal errors)
34 * @param fm format string (`printf()`-style)
35 * @param ap arguments to @a fm
36 * @ingroup logging
37 */ 43 */
38static void 44static enum MHD_StatusCode
39file_logger (void *cls, 45configure_listen_reuse (struct MHD_Daemon *daemon)
40 enum MHD_StatusCode sc,
41 const char *fm,
42 va_list ap)
43{ 46{
44 FILE *f = cls; 47 const MHD_SCKT_OPT_BOOL_ on = 1;
45 48
46 (void) sc; 49 /* Apply the socket options according to
47 (void) vfprintf (f, 50 listening_address_reuse. */
48 fm, 51 /* FIXME: used to be -1/0/1, now defined as a bool!
49 ap); 52 MISMATCH! */
53 if (0 == daemon->listening_address_reuse)
54 {
55#ifndef MHD_WINSOCK_SOCKETS
56 /* No user requirement, use "traditional" default SO_REUSEADDR
57 * on non-W32 platforms, and do not fail if it doesn't work.
58 * Don't use it on W32, because on W32 it will allow multiple
59 * bind to the same address:port, like SO_REUSEPORT on others. */
60 if (0 > setsockopt (listen_fd,
61 SOL_SOCKET,
62 SO_REUSEADDR,
63 (void*) &on, sizeof (on)))
64 {
65#ifdef HAVE_MESSAGES
66 MHD_DLOG (daemon,
67 MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_FAILED,
68 _("setsockopt failed: %s\n"),
69 MHD_socket_last_strerr_ ());
70#endif
71 }
72#endif /* ! MHD_WINSOCK_SOCKETS */
73 return MHD_SC_OK;
74 }
75 if (daemon->listening_address_reuse > 0)
76 {
77 /* User requested to allow reusing listening address:port. */
78#ifndef MHD_WINSOCK_SOCKETS
79 /* Use SO_REUSEADDR on non-W32 platforms, and do not fail if
80 * it doesn't work. */
81 if (0 > setsockopt (listen_fd,
82 SOL_SOCKET,
83 SO_REUSEADDR,
84 (void*)&on, sizeof (on)))
85 {
86#ifdef HAVE_MESSAGES
87 MHD_DLOG (daemon,
88 MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_FAILED,
89 _("setsockopt failed: %s\n"),
90 MHD_socket_last_strerr_ ());
91#endif
92 return MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_FAILED;
93 }
94#endif /* ! MHD_WINSOCK_SOCKETS */
95 /* Use SO_REUSEADDR on Windows and SO_REUSEPORT on most platforms.
96 * Fail if SO_REUSEPORT is not defined or setsockopt fails.
97 */
98 /* SO_REUSEADDR on W32 has the same semantics
99 as SO_REUSEPORT on BSD/Linux */
100#if defined(MHD_WINSOCK_SOCKETS) || defined(SO_REUSEPORT)
101 if (0 > setsockopt (listen_fd,
102 SOL_SOCKET,
103#ifndef MHD_WINSOCK_SOCKETS
104 SO_REUSEPORT,
105#else /* MHD_WINSOCK_SOCKETS */
106 SO_REUSEADDR,
107#endif /* MHD_WINSOCK_SOCKETS */
108 (void *) &on,
109 sizeof (on)))
110 {
111#ifdef HAVE_MESSAGES
112 MHD_DLOG (daemon,
113 MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_FAILED,
114 _("setsockopt failed: %s\n"),
115 MHD_socket_last_strerr_ ());
116#endif
117 return MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_FAILED;
118 }
119#else /* !MHD_WINSOCK_SOCKETS && !SO_REUSEPORT */
120 /* we're supposed to allow address:port re-use, but
121 on this platform we cannot; fail hard */
122#ifdef HAVE_MESSAGES
123 MHD_DLOG (daemon,
124 MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_NOT_SUPPORTED,
125 _("Cannot allow listening address reuse: SO_REUSEPORT not defined\n"));
126#endif
127 return MHD_SC_LISTEN_ADDRESS_REUSE_ENABLE_NOT_SUPPORTED;
128#endif /* !MHD_WINSOCK_SOCKETS && !SO_REUSEPORT */
129 }
130
131 /* if (daemon->listening_address_reuse < 0) */
132 /* User requested to disallow reusing listening address:port.
133 * Do nothing except for Windows where SO_EXCLUSIVEADDRUSE
134 * is used and Solaris with SO_EXCLBIND.
135 * Fail if MHD was compiled for W32 without SO_EXCLUSIVEADDRUSE
136 * or setsockopt fails.
137 */
138#if (defined(MHD_WINSOCK_SOCKETS) && defined(SO_EXCLUSIVEADDRUSE)) || \
139 (defined(__sun) && defined(SO_EXCLBIND))
140 if (0 > setsockopt (listen_fd,
141 SOL_SOCKET,
142#ifdef SO_EXCLUSIVEADDRUSE
143 SO_EXCLUSIVEADDRUSE,
144#else /* SO_EXCLBIND */
145 SO_EXCLBIND,
146#endif /* SO_EXCLBIND */
147 (void *) &on,
148 sizeof (on)))
149 {
150#ifdef HAVE_MESSAGES
151 MHD_DLOG (daemon,
152 MHD_SC_LISTEN_ADDRESS_REUSE_DISABLE_FAILED,
153 _("setsockopt failed: %s\n"),
154 MHD_socket_last_strerr_ ());
155#endif
156 return MHD_SC_LISTEN_ADDRESS_REUSE_DISABLE_FAILED;
157 }
158#elif defined(MHD_WINSOCK_SOCKETS) /* SO_EXCLUSIVEADDRUSE not defined on W32? */
159#ifdef HAVE_MESSAGES
160 MHD_DLOG (daemon,
161 MHD_SC_LISTEN_ADDRESS_REUSE_DISABLE_NOT_SUPPORTED,
162 _("Cannot disallow listening address reuse: SO_EXCLUSIVEADDRUSE not defined\n"));
163#endif
164 return MHD_SC_LISTEN_ADDRESS_REUSE_DISABLE_NOT_SUPPORTED;
165#endif /* MHD_WINSOCK_SOCKETS */
166 return MHD_SC_OK;
50} 167}
51 168
52 169
53/** 170/**
54 * Process escape sequences ('%HH') Updates val in place; the 171 * Open, configure and bind the listen socket (if required).
55 * result should be UTF-8 encoded and cannot be larger than the input.
56 * The result must also still be 0-terminated.
57 * 172 *
58 * @param cls closure (use NULL) 173 * @param daemon[in,out] daemon to open the socket for
59 * @param req handle to request, not used 174 * @return #MHD_SC_OK on success
60 * @param val value to unescape (modified in the process)
61 * @return length of the resulting val (strlen(val) maybe
62 * shorter afterwards due to elimination of escape sequences)
63 */ 175 */
64static size_t 176static enum MHD_StatusCode
65unescape_wrapper (void *cls, 177open_listen_socket (struct MHD_Daemon *daemon)
66 struct MHD_Request *req,
67 char *val)
68{ 178{
69 (void) cls; /* Mute compiler warning. */ 179 enum MHD_StatusCode sc;
70 (void) req; /* Mute compiler warning. */ 180 bool usev6;
71 return MHD_http_unescape (val); 181 socklen_t addrlen;
182 struct sockaddr_storage ss;
183 const struct sockaddr *sa;
184
185 if (MHD_INVALID_SOCKET != daemon->listen_fd)
186 return MHD_SC_OK; /* application opened it for us! */
187
188 /* Determine address family */
189 if (MHD_AF_NONE != daemon->address_family)
190 {
191 switch (daemon->address_family)
192 {
193 case MHD_AF_NONE:
194 abort ();
195 case MHD_AF_AUTO:
196#if HAVE_INET6
197 use_v6 = true;
198#else
199 use_v6 = false;
200#endif
201 break;
202 case MHD_AF_INET:
203 use_v6 = false;
204 break;
205 case MHD_AF_INET6:
206 case MHD_AF_DUAL:
207#if HAVE_INET6
208 use_v6 = true;
209 break;
210#else
211#ifdef HAVE_MESSAGES
212 MHD_DLOG (daemon,
213 MHD_SC_IPV6_NOT_SUPPORTED_BY_BUILD,
214 _("IPv6 not supported by this build\n"));
215#endif
216 return MHD_SC_IPV6_NOT_SUPPORTED_BY_BUILD;
217#endif
218 }
219 }
220 else if (0 != daemon->listen_sa_len)
221 {
222 /* we have a listen address, get AF from there! */
223 switch (daemon->listen_sa.ss_family)
224 {
225 case AF_INET:
226 use_v6 = false;
227 break;
228#ifdef AF_INET6
229 case AF_INET6:
230 use_v6 = true;
231 break;
232#endif
233#ifdef AF_UNIX
234 case AF_UNIX:
235 // FIXME: not implemented
236 // (need to change MHD_socket_create_listen_() API!)
237#endif
238 default:
239 return MHD_SC_AF_NOT_SUPPORTED_BY_BUILD;
240 }
241 }
242 else
243 {
244 /* no listening desired, that's OK */
245 return MHD_SC_OK;
246 }
247
248 /* try to open listen socket */
249 try_open_listen_socket:
250 daemon->listen_socket = MHD_socket_create_listen_(use_v6);
251 if ( (MHD_INVALID_SOCKET == daemon->listen_socket) &&
252 (MHD_AF_AUTO == daemon->address_family) &&
253 (use_v6) )
254 {
255 use_v6 = false;
256 goto try_open_listen_socket;
257 }
258 if (MHD_INVALID_SOCKET == daemon->listen_socket)
259 {
260#ifdef HAVE_MESSAGES
261 MHD_DLOG (daemon,
262 MHD_SC_FAILED_TO_OPEN_LISTEN_SOCKET,
263 _("Failed to create socket for listening: %s\n"),
264 MHD_socket_last_strerr_ ());
265#endif
266 return MHD_SC_FAILED_TO_OPEN_LISTEN_SOCKET;
267 }
268
269 if (MHD_SC_OK !=
270 (sc = configure_listen_reuse (daemon)))
271 return sc;
272
273 /* configure for dual stack (or not) */
274 if (use_v6)
275 {
276#if defined IPPROTO_IPV6 && defined IPV6_V6ONLY
277 /* Note: "IPV6_V6ONLY" is declared by Windows Vista ff., see "IPPROTO_IPV6 Socket Options"
278 (http://msdn.microsoft.com/en-us/library/ms738574%28v=VS.85%29.aspx);
279 and may also be missing on older POSIX systems; good luck if you have any of those,
280 your IPv6 socket may then also bind against IPv4 anyway... */
281 const MHD_SCKT_OPT_BOOL_ v6_only =
282 (MHD_AF_INET6 == daemon->address_family);
283 if (0 > setsockopt (listen_fd,
284 IPPROTO_IPV6,
285 IPV6_V6ONLY,
286 (const void *) &v6_only,
287 sizeof (v6_only)))
288 {
289#ifdef HAVE_MESSAGES
290 MHD_DLOG (daemon,
291 MHD_SC_LISTEN_DUAL_STACK_CONFIGURATION_FAILED,
292 _("setsockopt failed: %s\n"),
293 MHD_socket_last_strerr_ ());
294#endif
295 }
296#else
297#ifdef HAVE_MESSAGES
298 MHD_DLOG (daemon,
299 MHD_SC_LISTEN_DUAL_STACK_CONFIGURATION_NOT_SUPPORTED,
300 _("Cannot explicitly setup dual stack behavior on this platform\n"));
301#endif
302#endif
303 }
304
305 /* Determine address to bind to */
306 if (0 != daemon->listen_sa_len)
307 {
308 /* Bind address explicitly given */
309 sa = daemon->listen_sa;
310 addrlen = daemon->listen_sa_len;
311 }
312 else
313 {
314 /* Compute bind address based on port and AF */
315#if HAVE_INET6
316 if (use_v6)
317 {
318#ifdef IN6ADDR_ANY_INIT
319 static const struct in6_addr static_in6any = IN6ADDR_ANY_INIT;
320#endif
321 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss;
322
323 addrlen = sizeof (struct sockaddr_in6);
324 memset (sin6,
325 0,
326 sizeof (struct sockaddr_in6));
327 sin6->sin6_family = AF_INET6;
328 sin6->sin6_port = htons (daemon->listen_port);
329#ifdef IN6ADDR_ANY_INIT
330 sin6->sin6_addr = static_in6any;
331#endif
332#if HAVE_SOCKADDR_IN_SIN_LEN
333 sin6->sin6_len = sizeof (struct sockaddr_in6);
334#endif
335 }
336 else
337#endif
338 {
339 struct sockaddr_in *sin4 = (struct sockaddr_in *) &ss;
340
341 addrlen = sizeof (struct sockaddr_in);
342 memset (sin4,
343 0,
344 sizeof (struct sockaddr_in));
345 sin4->sin_family = AF_INET;
346 sin4->sin_port = htons (daemon->listen_port);
347 if (0 != INADDR_ANY)
348 sin4->sin_addr.s_addr = htonl (INADDR_ANY);
349#if HAVE_SOCKADDR_IN_SIN_LEN
350 sin4->sin_len = sizeof (struct sockaddr_in);
351#endif
352 }
353 sa = (const struct sockaddr *) ss;
354 }
355
356 /* actually do the bind() */
357 if (-1 == bind (daemon->listen_socket,
358 sa,
359 addrlen))
360 {
361#ifdef HAVE_MESSAGES
362 unsigned int port = 0;
363
364 switch (sa->sa_family)
365 {
366 case AF_INET:
367 if (addrlen == sizeof (struct sockaddr_in))
368 port = ntohs (((const struct sockaddr_in*)sa)->sin_port);
369 else
370 port = UINT16_MAX + 1; /* indicate size error */
371 break;
372 case AF_INET6:
373 if (addrlen == sizeof (struct sockaddr_in6))
374 port = ntohs (((const struct sockaddr_in6*)sa)->sin_port);
375 else
376 port = UINT16_MAX + 1; /* indicate size error */
377 break;
378 default:
379 port = UINT_MAX; /* AF_UNIX? */
380 break;
381 }
382 MHD_DLOG (daemon,
383 MHD_SC_LISTEN_SOCKET_BIND_FAILED,
384 _("Failed to bind to port %u: %s\n"),
385 port,
386 MHD_socket_last_strerr_ ());
387#endif
388 return MHD_SC_LISTEN_SOCKET_BIND_FAILED;
389 }
390
391 /* setup TCP_FASTOPEN */
392#ifdef TCP_FASTOPEN
393 if (MHD_FOM_DISABLE != daemon->fast_open_method)
394 {
395 if (0 != setsockopt (daemon->listen_socket,
396 IPPROTO_TCP,
397 TCP_FASTOPEN,
398 &daemon->fastopen_queue_size,
399 sizeof (daemon->fastopen_queue_size)))
400 {
401#ifdef HAVE_MESSAGES
402 MHD_DLOG (daemon,
403 MHD_SC_FAST_OPEN_FAILURE,
404 _("setsockopt failed: %s\n"),
405 MHD_socket_last_strerr_ ());
406#endif
407 if (MHD_FOM_REQUIRE == daemon->fast_open_method)
408 return MHD_SC_FAST_OPEN_FAILURE;
409 }
410 }
411#endif
412
413 /* setup listening */
414 if (0 > listen (daemon->listen_socket,
415 daemon->listen_backlog_size))
416 {
417#ifdef HAVE_MESSAGES
418 MHD_DLOG (daemon,
419 MHD_SC_LISTEN_FAILURE,
420 _("Failed to listen for connections: %s\n"),
421 MHD_socket_last_strerr_ ());
422#endif
423 return MHD_SC_LISTEN_FAILURE;
424 }
425 return MHD_SC_OK;
72} 426}
73 427
74 428
75/** 429/**
76 * Create (but do not yet start) an MHD daemon. 430 * Obtain the listen port number from the socket (if it
77 * Usually, you will want to set various options before 431 * was not explicitly set by us, i.e. if we were given
78 * starting the daemon with #MHD_daemon_start(). 432 * a listen socket or if the port was 0 and the OS picked
433 * a free one).
79 * 434 *
80 * @param cb function to be called for incoming requests 435 * @param daemon[in,out] daemon to obtain the port number for
81 * @param cb_cls closure for @a cb
82 * @return NULL on error
83 */ 436 */
84struct MHD_Daemon * 437static void
85MHD_daemon_create (MHD_RequestCallback cb, 438get_listen_port_number (struct MHD_Daemon *daemon)
86 void *cb_cls)
87{ 439{
88 struct MHD_Daemon *daemon; 440 struct sockaddr_storage servaddr;
89 441 socklen_t addrlen;
90 MHD_check_global_init_(); 442
91 if (NULL == cb) 443 if ( (0 != daemon->port) ||
92 return NULL; 444 (MHD_INVALID_SOCKET == daemon->listen_socket) )
93 if (NULL == (daemon = malloc (sizeof (struct MHD_Daemon)))) 445 return; /* nothing to be done */
94 return NULL; 446
95 memset (daemon, 447 memset (&servaddr,
96 0, 448 0,
97 sizeof (struct MHD_Daemon)); 449 sizeof (struct sockaddr_storage));
98 daemon->rc = cb; 450 addrlen = sizeof (servaddr);
99 daemon->rc_cls = cb_cls; 451 if (0 != getsockname (daemon->listen_socket,
100 daemon->logger = &file_logger; 452 (struct sockaddr *) &servaddr,
101 daemon->logger_cls = stderr; 453 &addrlen))
102 daemon->unescape_cb = &unescape_wrapper; 454 {
103 daemon->tls_ciphers = TLS_CIPHERS_DEFAULT; 455#ifdef HAVE_MESSAGES
104 daemon->connection_memory_limit_b = MHD_POOL_SIZE_DEFAULT; 456 MHD_DLOG (daemon,
105 daemon->connection_memory_increment_b = BUF_INC_SIZE_DEFAULT; 457 MHD_SC_LISTEN_PORT_INTROSPECTION_FAILURE,
106#if ENABLE_DAUTH 458 _("Failed to get listen port number: %s\n"),
107 daemon->digest_nc_length = DIGEST_NC_LENGTH_DEFAULT; 459 MHD_socket_last_strerr_ ());
108#endif 460#endif /* HAVE_MESSAGES */
109 daemon->listen_backlog = LISTEN_BACKLOG_DEFAULT; 461 return;
110 daemon->fo_queue_length = FO_QUEUE_LENGTH_DEFAULT; 462 }
111 daemon->listen_socket = MHD_INVALID_SOCKET; 463#ifdef MHD_POSIX_SOCKETS
112 return daemon; 464 if (sizeof (servaddr) < addrlen)
465 {
466 /* should be impossible with `struct sockaddr_storage` */
467#ifdef HAVE_MESSAGES
468 MHD_DLOG (daemon,
469 MHD_SC_LISTEN_PORT_INTROSPECTION_FAILURE,
470 _("Failed to get listen port number (`struct sockaddr_storage` too small!?)\n"));
471#endif /* HAVE_MESSAGES */
472 return;
473 }
474#endif /* MHD_POSIX_SOCKETS */
475 switch (servaddr.ss_family)
476 {
477 case AF_INET:
478 {
479 struct sockaddr_in *s4 = (struct sockaddr_in *) &servaddr;
480
481 daemon->port = ntohs (s4->sin_port);
482 break;
483 }
484#ifdef HAVE_INET6
485 case AF_INET6:
486 {
487 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &servaddr;
488
489 daemon->port = ntohs(s6->sin6_port);
490 break;
491 }
492#endif /* HAVE_INET6 */
493#ifdef AF_UNIX
494 case AF_UNIX:
495 daemon->port = 0; /* special value for UNIX domain sockets */
496 break;
497#endif
498 default:
499#ifdef HAVE_MESSAGES
500 MHD_DLOG (daemon,
501 MHD_SC_LISTEN_PORT_INTROSPECTION_UNKNOWN_AF,
502 _("Unknown address family!\n"));
503#endif
504 daemon->port = 0; /* ugh */
505 break;
506 }
113} 507}
114 508
115 509
116/** 510/**
117 * Start a webserver. 511 * Setup epoll() FD for the daemon and initialize it to listen
512 * on the listen FD.
513 * @remark To be called only from thread that process
514 * daemon's select()/poll()/etc.
118 * 515 *
119 * @param daemon daemon to start; you can no longer set 516 * @param daemon daemon to initialize for epoll()
120 * options on this daemon after this call!
121 * @return #MHD_SC_OK on success 517 * @return #MHD_SC_OK on success
122 * @ingroup event
123 */ 518 */
124enum MHD_StatusCode 519static enum MHD_StatusCode
125MHD_daemon_start (struct MHD_Daemon *daemon) 520setup_epoll_to_listen (struct MHD_Daemon *daemon)
126{ 521{
127 522 struct epoll_event event;
128 return -1; 523 MHD_socket ls;
524
525 /* FIXME: update function! */
526 daemon->epoll_fd = setup_epoll_fd (daemon);
527 if (-1 == daemon->epoll_fd)
528 return MHD_NO;
529#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
530 if (0 != (MHD_ALLOW_UPGRADE & daemon->options))
531 {
532 daemon->epoll_upgrade_fd = setup_epoll_fd (daemon);
533 if (MHD_INVALID_SOCKET == daemon->epoll_upgrade_fd)
534 return MHD_NO;
535 }
536#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
537 if ( (MHD_INVALID_SOCKET == (ls = daemon->listen_fd)) ||
538 (daemon->was_quiesced) )
539 return MHD_YES; /* non-listening daemon */
540 event.events = EPOLLIN;
541 event.data.ptr = daemon;
542 if (0 != epoll_ctl (daemon->epoll_fd,
543 EPOLL_CTL_ADD,
544 ls,
545 &event))
546 {
547#ifdef HAVE_MESSAGES
548 MHD_DLOG (daemon,
549 _("Call to epoll_ctl failed: %s\n"),
550 MHD_socket_last_strerr_ ());
551#endif
552 return MHD_NO;
553 }
554 daemon->listen_socket_in_epoll = true;
555 if (MHD_ITC_IS_VALID_(daemon->itc))
556 {
557 event.events = EPOLLIN;
558 event.data.ptr = (void *) epoll_itc_marker;
559 if (0 != epoll_ctl (daemon->epoll_fd,
560 EPOLL_CTL_ADD,
561 MHD_itc_r_fd_ (daemon->itc),
562 &event))
563 {
564#ifdef HAVE_MESSAGES
565 MHD_DLOG (daemon,
566 _("Call to epoll_ctl failed: %s\n"),
567 MHD_socket_last_strerr_ ());
568#endif
569 return MHD_NO;
570 }
571 }
572 return MHD_SC_OK;
129} 573}
574#endif
130 575
131 576
132/** 577/**
133 * Stop accepting connections from the listening socket. Allows 578 * Thread that runs the polling loop until the daemon
134 * clients to continue processing, but stops accepting new 579 * is explicitly shut down.
135 * connections. Note that the caller is responsible for closing the
136 * returned socket; however, if MHD is run using threads (anything but
137 * external select mode), it must not be closed until AFTER
138 * #MHD_stop_daemon has been called (as it is theoretically possible
139 * that an existing thread is still using it).
140 * 580 *
141 * Note that some thread modes require the caller to have passed 581 * @param cls `struct MHD_Deamon` to run select loop in a thread for
142 * #MHD_USE_ITC when using this API. If this daemon is 582 * @return always 0 (on shutdown)
143 * in one of those modes and this option was not given to 583 */
144 * #MHD_start_daemon, this function will return #MHD_INVALID_SOCKET. 584static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
585MHD_polling_thread (void *cls)
586{
587 struct MHD_Daemon *daemon = cls;
588
589 MHD_thread_init_ (&daemon->pid);
590 while (! daemon->shutdown)
591 {
592 switch (daemon->event_loop_syscall)
593 {
594 case MHD_ELS_AUTO:
595 MHD_PANIC ("MHD_ELS_AUTO should have been mapped to preferred style");
596 break;
597 case MHD_ELS_SELECT:
598 MHD_select (daemon,
599 MHD_YES);
600 break;
601 case MHD_ELS_POLL:
602 MHD_poll (daemon,
603 MHD_YES);
604 break;
605 case MHD_ELS_EPOLL:
606#ifdef EPOLL_SUPPORT
607 MHD_epoll (daemon,
608 MHD_YES);
609#else
610 MHD_PANIC ("MHD_ELS_EPOLL not supported, should have failed earlier");
611#endif
612 break;
613 }
614 MHD_cleanup_connections (daemon);
615 }
616 /* Resume any pending for resume connections, join
617 * all connection's threads (if any) and finally cleanup
618 * everything. */
619 close_all_connections (daemon);
620
621 return (MHD_THRD_RTRN_TYPE_)0;
622}
623
624
625/**
626 * Setup the thread pool (if needed).
145 * 627 *
146 * @param daemon daemon to stop accepting new connections for 628 * @param daemon[in,out] daemon to setup thread pool for
147 * @return old listen socket on success, #MHD_INVALID_SOCKET if 629 * @return #MHD_SC_OK on success
148 * the daemon was already not listening anymore, or
149 * was never started
150 * @ingroup specialized
151 */ 630 */
152MHD_socket 631static enum MHD_StatusCode
153MHD_daemon_quiesce (struct MHD_Daemon *daemon) 632setup_thread_pool (struct MHD_Daemon *daemon)
154{ 633{
155 return -1; 634 /* Coarse-grained count of connections per thread (note error
635 * due to integer division). Also keep track of how many
636 * connections are leftover after an equal split. */
637 unsigned int conns_per_thread = daemon->connection_limit
638 / daemon->threading_model;
639 unsigned int leftover_conns = daemon->connection_limit
640 % daemon->threading_model;
641 unsigned int i;
642 enum MHD_StatusCode sc;
643
644 /* Allocate memory for pooled objects */
645 daemon->worker_pool = calloc (daemon->threading_model,
646 sizeof (struct MHD_Daemon));
647 if (NULL == daemon->worker_pool)
648 return MHD_SC_THREAD_POOL_MALLOC_FAILURE;
649
650 /* Start the workers in the pool */
651 for (i = 0; i < daemon->threading_model; i++)
652 {
653 /* Create copy of the Daemon object for each worker */
654 struct MHD_Daemon *d = &daemon->worker_pool[i];
655
656 memcpy (d,
657 daemon,
658 sizeof (struct MHD_Daemon));
659 /* Adjust pooling params for worker daemons; note that memcpy()
660 has already copied MHD_USE_INTERNAL_POLLING_THREAD thread model into
661 the worker threads. */
662 d->master = daemon;
663 d->worker_pool_size = 0;
664 d->worker_pool = NULL;
665 /* Divide available connections evenly amongst the threads.
666 * Thread indexes in [0, leftover_conns) each get one of the
667 * leftover connections. */
668 d->connection_limit = conns_per_thread;
669 if (i < leftover_conns)
670 ++d->connection_limit;
671
672 if (! daemon->disable_itc)
673 {
674 if (! MHD_itc_init_ (d->itc))
675 {
676#ifdef HAVE_MESSAGES
677 MHD_DLOG (daemon,
678 MHD_SC_ITC_INITIALIZATION_FAILED,
679 _("Failed to create worker inter-thread communication channel: %s\n"),
680 MHD_itc_last_strerror_() );
681#endif
682 sc = MHD_SC_ITC_INITIALIZATION_FAILED;
683 goto thread_failed;
684 }
685 if ( (MHD_ELS_SELECT == daemon->event_loop_syscall) &&
686 (! MHD_SCKT_FD_FITS_FDSET_(MHD_itc_r_fd_ (d->itc),
687 NULL)) )
688 {
689#ifdef HAVE_MESSAGES
690 MHD_DLOG (daemon,
691 MHD_SC_ITC_DESCRIPTOR_TOO_LARGE,
692 _("File descriptor for inter-thread communication channel exceeds maximum value\n"));
693#endif
694 MHD_itc_destroy_chk_ (d->itc);
695 sc = MHD_SC_ITC_DESCRIPTOR_TOO_LARGE;
696 goto thread_failed;
697 }
698 }
699 else
700 {
701 MHD_itc_set_invalid_ (d->itc);
702 }
703
704#ifdef EPOLL_SUPPORT
705 if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) &&
706 (MHD_SC_OK != (sc = setup_epoll_to_listen (d))) )
707 goto thread_failed;
708#endif
709
710 /* Must init cleanup connection mutex for each worker */
711 if (! MHD_mutex_init_ (&d->cleanup_connection_mutex))
712 {
713#ifdef HAVE_MESSAGES
714 MHD_DLOG (daemon,
715 MHD_SC_THREAD_POOL_CREATE_MUTEX_FAILURE,
716 _("MHD failed to initialize cleanup connection mutex\n"));
717#endif
718 if (! daemon->disable_itc)
719 MHD_itc_destroy_chk_ (d->itc);
720 sc = MHD_SC_THREAD_POOL_CREATE_MUTEX_FAILURE;
721 goto thread_failed;
722 }
723
724 /* Spawn the worker thread */
725 if (! MHD_create_named_thread_ (&d->pid,
726 "MHD-worker",
727 daemon->thread_stack_size,
728 &MHD_polling_thread,
729 d))
730 {
731#ifdef HAVE_MESSAGES
732 MHD_DLOG (daemon,
733 MHD_SC_THREAD_POOL_LAUNCH_FAILURE,
734 _("Failed to create pool thread: %s\n"),
735 MHD_strerror_ (errno));
736#endif
737 sc = MHD_SC_THREAD_POOL_LAUNCH_FAILURE;
738 /* Free memory for this worker; cleanup below handles
739 * all previously-created workers. */
740 if (! daemon->disable_itc)
741 MHD_itc_destroy_chk_ (d->itc);
742 MHD_mutex_destroy_chk_ (&d->cleanup_connection_mutex);
743 goto thread_failed;
744 }
745 } /* end for() */
746 return MHD_SC_OK;
747
748thread_failed:
749 /* If no worker threads created, then shut down normally. Calling
750 MHD_stop_daemon (as we do below) doesn't work here since it
751 assumes a 0-sized thread pool means we had been in the default
752 MHD_USE_INTERNAL_POLLING_THREAD mode. */
753 if (0 == i)
754 {
755 if (NULL != daemon->worker_pool)
756 {
757 free (daemon->worker_pool);
758 daemon->worker_pool = NULL;
759 }
760 return MHD_SC_THREAD_LAUNCH_FAILURE;
761 }
762 /* Shutdown worker threads we've already created. Pretend
763 as though we had fully initialized our daemon, but
764 with a smaller number of threads than had been
765 requested. */
766 daemon->worker_pool_size = i;
767 daemon->listen_socket = MHD_daemon_quiesce (daemon);
768 return MHD_SC_THREAD_LAUNCH_FAILURE;
156} 769}
157 770
158 771
159/** 772/**
160 * Shutdown and destroy an HTTP daemon. 773 * Start a webserver.
161 * 774 *
162 * @param daemon daemon to stop 775 * @param daemon daemon to start; you can no longer set
776 * options on this daemon after this call!
777 * @return #MHD_SC_OK on success
163 * @ingroup event 778 * @ingroup event
164 */ 779 */
165void 780enum MHD_StatusCode
166MHD_daemon_destroy (struct MHD_Daemon *daemon) 781MHD_daemon_start (struct MHD_Daemon *daemon)
167{ 782{
168 free (daemon); 783 enum MHD_StatusCode sc;
784
785 if (MHD_ELS_AUTO == daemon->event_loop_syscall)
786 {
787#if EPOLL_SUPPORT
788 /* We do not support thread-per-connection in combination
789 with epoll, so use poll in this case, otherwise prefer
790 epoll. */
791 if (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_model)
792 daemon->event_loop_syscall = MHD_ELS_POLL;
793 else
794 daemon->event_loop_syscall = MHD_ELS_EPOLL;
795#elif HAVE_POLL
796 daemon->event_loop_syscall = MHD_ELS_POLL;
797#else
798 daemon->event_loop_syscall = MHD_ELS_SELECT;
799#endif
800 }
801
802#ifdef EPOLL_SUPPORT
803 if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) &&
804 (0 == daemon->worker_pool_size) &&
805 (MHD_INVALID_SOCKET != daemon->listen_socket) &&
806 (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_model) )
807 {
808#ifdef HAVE_MESSAGES
809 MHD_DLOG (daemon,
810 MHD_SC_SYSCALL_THREAD_COMBINATION_INVALID,
811 _("Combining MHD_USE_THREAD_PER_CONNECTION and MHD_USE_EPOLL is not supported.\n"));
812#endif
813 return MHD_SC_SYSCALL_THREAD_COMBINATION_INVALID;
814 }
815#endif
816
817 /* Setup ITC */
818 if ( (! daemon->disable_itc) &&
819 (0 == daemon->worker_pool_size) )
820 {
821 if (! MHD_itc_init_ (daemon->itc))
822 {
823#ifdef HAVE_MESSAGES
824 MHD_DLOG (daemon,
825 MHD_SC_ITC_INITIALIZATION_FAILED,
826 _("Failed to create inter-thread communication channel: %s\n"),
827 MHD_itc_last_strerror_ ());
828#endif
829 return MHD_SC_ITC_INITIALIZATION_FAILED;
830 }
831 if ( (MHD_ELS_SELECT == daemon->event_loop_syscall) &&
832 (! MHD_SCKT_FD_FITS_FDSET_(MHD_itc_r_fd_ (daemon->itc),
833 NULL)) )
834 {
835#ifdef HAVE_MESSAGES
836 MHD_DLOG (daemon,
837 MHD_SC_ITC_DESCRIPTOR_TOO_LARGE,
838 _("File descriptor for inter-thread communication channel exceeds maximum value\n"));
839#endif
840 return MHD_SC_ITC_DESCRIPTOR_TOO_LARGE;
841 }
842 }
843
844 if (MHD_SC_OK != (sc = open_listen_socket (daemon)))
845 return sc;
846
847 /* Check listen socket is in range (if we are limited) */
848 if ( (MHD_INVALID_SOCKET != daemon->listen_socket) &&
849 (MHD_ELS_SELECT == daemon->event_loop_syscall) &&
850 (! MHD_SCKT_FD_FITS_FDSET_(daemon->listen_socket,
851 NULL)) )
852 {
853#ifdef HAVE_MESSAGES
854 MHD_DLOG (daemon,
855 MHD_SC_LISTEN_SOCKET_TOO_LARGE,
856 _("Socket descriptor larger than FD_SETSIZE: %d > %d\n"),
857 daemon->listen_socket,
858 FD_SETSIZE);
859#endif
860 return MHD_SC_LISTEN_SOCKET_TOO_LARGE;
861 }
862
863 /* set listen socket to non-blocking */
864 if ( (MHD_INVALID_SOCKET != daemon->listen_socket) &&
865 (! MHD_socket_nonblocking_ (daemon->listen_socket)) )
866 {
867#ifdef HAVE_MESSAGES
868 MHD_DLOG (daemon,
869 MHD_SC_LISTEN_SOCKET_NONBLOCKING_FAILURE,
870 _("Failed to set nonblocking mode on listening socket: %s\n"),
871 MHD_socket_last_strerr_());
872#endif
873 if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) ||
874 (daemon->worker_pool_size > 0) )
875 {
876 /* Accept must be non-blocking. Multiple children may wake
877 * up to handle a new connection, but only one will win the
878 * race. The others must immediately return. As this is
879 * not possible, we must fail hard here. */
880 return MHD_SC_LISTEN_SOCKET_NONBLOCKING_FAILURE;
881 }
882 }
883
884#ifdef EPOLL_SUPPORT
885 /* Setup epoll */
886 if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) &&
887 (0 == daemon->worker_pool_size) &&
888 (MHD_INVALID_SOCKET != daemon->listen_socket) &&
889 (MHD_SC_OK != (sc = setup_epoll_to_listen (daemon))) )
890 return sc;
891#endif
892
893 /* Setup main listen thread (only if we have no thread pool or
894 external event loop and do have a listen socket) */
895 /* FIXME: why no worker thread if we have no listen socket? */
896 if ( ( (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_model) ||
897 (1 == daemon->threading_model) ) &&
898 (MHD_INVALID_SOCKET != daemon->listen_socket) &&
899 (! MHD_create_named_thread_ (&daemon->pid,
900 (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_model)
901 ? "MHD-listen"
902 : "MHD-single",
903 daemon->thread_stack_size,
904 &MHD_polling_thread,
905 daemon) )
906 {
907#ifdef HAVE_MESSAGES
908 MHD_DLOG (daemon,
909 MHD_SC_THREAD_MAIN_LAUNCH_FAILURE,
910 _("Failed to create listen thread: %s\n"),
911 MHD_strerror_ (errno));
912#endif
913 return MHD_SC_THREAD_MAIN_LAUNCH_FAILURE;
914 }
915
916 /* Setup worker threads */
917 /* FIXME: why no thread pool if we have no listen socket? */
918 if ( (1 < daemon->threading_model) &&
919 (MHD_INVALID_SOCKET != daemon->listen_socket) &&
920 (MHD_SC_OK != (sc = setup_thread_pool (daemon))) )
921 return sc;
922
923 return MHD_SC_OK;
169} 924}
170 925
171 926
927
172/* end of daemon.c */ 928/* end of daemon.c */
diff --git a/src/lib/daemon_create.c b/src/lib/daemon_create.c
new file mode 100644
index 00000000..6d903677
--- /dev/null
+++ b/src/lib/daemon_create.c
@@ -0,0 +1,134 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007-2018 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 lib/daemon_create.c
22 * @brief main functions to create a daemon
23 * @author Christian Grothoff
24 */
25#include "internal.h"
26
27
28/**
29 * Logging implementation that logs to a file given
30 * as the @a cls.
31 *
32 * @param cls a `FILE *` to log to
33 * @param sc status code of the event (ignored)
34 * @param fm format string (`printf()`-style)
35 * @param ap arguments to @a fm
36 * @ingroup logging
37 */
38static void
39file_logger (void *cls,
40 enum MHD_StatusCode sc,
41 const char *fm,
42 va_list ap)
43{
44 FILE *f = cls;
45
46 (void) sc;
47 (void) vfprintf (f,
48 fm,
49 ap);
50}
51
52
53/**
54 * Process escape sequences ('%HH') Updates val in place; the
55 * result should be UTF-8 encoded and cannot be larger than the input.
56 * The result must also still be 0-terminated.
57 *
58 * @param cls closure (use NULL)
59 * @param req handle to request, not used
60 * @param val value to unescape (modified in the process)
61 * @return length of the resulting val (strlen(val) maybe
62 * shorter afterwards due to elimination of escape sequences)
63 */
64static size_t
65unescape_wrapper (void *cls,
66 struct MHD_Request *req,
67 char *val)
68{
69 (void) cls; /* Mute compiler warning. */
70 (void) req; /* Mute compiler warning. */
71 return MHD_http_unescape (val);
72}
73
74
75/**
76 * Create (but do not yet start) an MHD daemon.
77 * Usually, you will want to set various options before
78 * starting the daemon with #MHD_daemon_start().
79 *
80 * @param cb function to be called for incoming requests
81 * @param cb_cls closure for @a cb
82 * @return NULL on error
83 */
84struct MHD_Daemon *
85MHD_daemon_create (MHD_RequestCallback cb,
86 void *cb_cls)
87{
88 struct MHD_Daemon *daemon;
89
90 MHD_check_global_init_();
91 if (NULL == cb)
92 return NULL;
93 if (NULL == (daemon = malloc (sizeof (struct MHD_Daemon))))
94 return NULL;
95 memset (daemon,
96 0,
97 sizeof (struct MHD_Daemon));
98 daemon->rc = cb;
99 daemon->rc_cls = cb_cls;
100 daemon->logger = &file_logger;
101 daemon->logger_cls = stderr;
102 daemon->unescape_cb = &unescape_wrapper;
103 daemon->tls_ciphers = TLS_CIPHERS_DEFAULT;
104 daemon->connection_memory_limit_b = MHD_POOL_SIZE_DEFAULT;
105 daemon->connection_memory_increment_b = BUF_INC_SIZE_DEFAULT;
106#if ENABLE_DAUTH
107 daemon->digest_nc_length = DIGEST_NC_LENGTH_DEFAULT;
108#endif
109 daemon->listen_backlog = LISTEN_BACKLOG_DEFAULT;
110 daemon->fo_queue_length = FO_QUEUE_LENGTH_DEFAULT;
111 daemon->listen_socket = MHD_INVALID_SOCKET;
112
113 if (! MHD_mutex_init_ (&daemon->cleanup_connection_mutex))
114 {
115 free (daemon);
116 return NULL;
117 }
118 if (! MHD_mutex_init_ (&daemon->per_ip_connection_mutex))
119 {
120 MHD_mutex_destroy_ (&daemon->cleanup_connection_mutex);
121 free (daemon);
122 return NULL;
123 }
124#ifdef DAUTH_SUPPORT
125 if (! MHD_mutex_init_ (&daemon->nnc_lock))
126 {
127 MHD_mutex_destroy_ (&daemon->cleanup_connection_mutex);
128 MHD_mutex_destroy_ (&daemon->per_ip_connection_mutex);
129 free (daemon);
130 return NULL;
131 }
132#endif
133 return daemon;
134}
diff --git a/src/lib/daemon_destroy.c b/src/lib/daemon_destroy.c
new file mode 100644
index 00000000..b1743088
--- /dev/null
+++ b/src/lib/daemon_destroy.c
@@ -0,0 +1,178 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007-2018 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 lib/daemon_destroy.c
22 * @brief main functions to destroy a daemon
23 * @author Christian Grothoff
24 */
25#include "internal.h"
26
27/* TODO: migrate logic below! */
28
29/**
30 * Shutdown and destroy an HTTP daemon.
31 *
32 * @param daemon daemon to stop
33 * @ingroup event
34 */
35void
36MHD_daemon_destroy (struct MHD_Daemon *daemon)
37{
38 MHD_socket fd;
39 unsigned int i;
40
41 if (NULL == daemon)
42 return;
43 daemon->shutdown = true;
44 if (daemon->was_quiesced)
45 fd = MHD_INVALID_SOCKET; /* Do not use FD if daemon was quiesced */
46 else
47 fd = daemon->listen_socket;
48
49 /* FIXME: convert from here to microhttpd2-style API! */
50
51 if (NULL != daemon->worker_pool)
52 { /* Master daemon with worker pool. */
53 mhd_assert (1 < daemon->worker_pool_size);
54 mhd_assert (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD));
55
56 /* Let workers shutdown in parallel. */
57 for (i = 0; i < daemon->worker_pool_size; ++i)
58 {
59 daemon->worker_pool[i].shutdown = true;
60 if (MHD_ITC_IS_VALID_(daemon->worker_pool[i].itc))
61 {
62 if (! MHD_itc_activate_ (daemon->worker_pool[i].itc, "e"))
63 MHD_PANIC (_("Failed to signal shutdown via inter-thread communication channel."));
64 }
65 else
66 mhd_assert (MHD_INVALID_SOCKET != fd);
67 }
68#ifdef HAVE_LISTEN_SHUTDOWN
69 if (MHD_INVALID_SOCKET != fd)
70 {
71 (void) shutdown (fd,
72 SHUT_RDWR);
73 }
74#endif /* HAVE_LISTEN_SHUTDOWN */
75 for (i = 0; i < daemon->worker_pool_size; ++i)
76 {
77 MHD_stop_daemon (&daemon->worker_pool[i]);
78 }
79 free (daemon->worker_pool);
80 mhd_assert (MHD_ITC_IS_INVALID_(daemon->itc));
81#ifdef EPOLL_SUPPORT
82 mhd_assert (-1 == daemon->epoll_fd);
83#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
84 mhd_assert (-1 == daemon->epoll_upgrade_fd);
85#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
86#endif /* EPOLL_SUPPORT */
87 }
88 else
89 { /* Worker daemon or single daemon. */
90 if (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD))
91 { /* Worker daemon or single daemon with internal thread(s). */
92 mhd_assert (0 == daemon->worker_pool_size);
93 if (0 != (MHD_TEST_ALLOW_SUSPEND_RESUME & daemon->options))
94 resume_suspended_connections (daemon);
95
96 if (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD))
97 {
98 /* Separate thread(s) is used for polling sockets. */
99 if (MHD_ITC_IS_VALID_(daemon->itc))
100 {
101 if (! MHD_itc_activate_ (daemon->itc, "e"))
102 MHD_PANIC (_("Failed to signal shutdown via inter-thread communication channel"));
103 }
104 else
105 {
106#ifdef HAVE_LISTEN_SHUTDOWN
107 if (MHD_INVALID_SOCKET != fd)
108 {
109 if (NULL == daemon->master)
110 (void) shutdown (fd,
111 SHUT_RDWR);
112 }
113 else
114#endif /* HAVE_LISTEN_SHUTDOWN */
115 mhd_assert (false); /* Should never happen */
116 }
117
118 if (! MHD_join_thread_ (daemon->pid.handle))
119 {
120 MHD_PANIC (_("Failed to join a thread\n"));
121 }
122 /* close_all_connections() was called in daemon thread. */
123 }
124 }
125 else
126 {
127 /* No internal threads are used for polling sockets. */
128 close_all_connections (daemon);
129 }
130 if (MHD_ITC_IS_VALID_ (daemon->itc))
131 MHD_itc_destroy_chk_ (daemon->itc);
132
133#ifdef EPOLL_SUPPORT
134 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
135 (-1 != daemon->epoll_fd) )
136 MHD_socket_close_chk_ (daemon->epoll_fd);
137#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
138 if ( (0 != (daemon->options & MHD_USE_EPOLL)) &&
139 (-1 != daemon->epoll_upgrade_fd) )
140 MHD_socket_close_chk_ (daemon->epoll_upgrade_fd);
141#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
142#endif /* EPOLL_SUPPORT */
143
144 MHD_mutex_destroy_chk_ (&daemon->cleanup_connection_mutex);
145 }
146
147 if (NULL != daemon->master)
148 return;
149 /* Cleanup that should be done only one time in master/single daemon.
150 * Do not perform this cleanup in worker daemons. */
151
152 if (MHD_INVALID_SOCKET != fd)
153 MHD_socket_close_chk_ (fd);
154
155 /* TLS clean up */
156#ifdef HTTPS_SUPPORT
157 if (daemon->have_dhparams)
158 {
159 gnutls_dh_params_deinit (daemon->https_mem_dhparams);
160 daemon->have_dhparams = false;
161 }
162 if (0 != (daemon->options & MHD_USE_TLS))
163 {
164 gnutls_priority_deinit (daemon->priority_cache);
165 if (daemon->x509_cred)
166 gnutls_certificate_free_credentials (daemon->x509_cred);
167 }
168#endif /* HTTPS_SUPPORT */
169
170#ifdef DAUTH_SUPPORT
171 free (daemon->nnc);
172 MHD_mutex_destroy_chk_ (&daemon->nnc_lock);
173#endif
174 MHD_mutex_destroy_chk_ (&daemon->per_ip_connection_mutex);
175 free (daemon);
176}
177
178/* end of daemon_destroy.c */
diff --git a/src/lib/daemon_info.c b/src/lib/daemon_info.c
new file mode 100644
index 00000000..b724094d
--- /dev/null
+++ b/src/lib/daemon_info.c
@@ -0,0 +1,60 @@
1
2/**
3 * Obtain information about the given daemon
4 * (not fully implemented!).
5 *
6 * @param daemon what daemon to get information about
7 * @param info_type what information is desired?
8 * @param ... depends on @a info_type
9 * @return NULL if this information is not available
10 * (or if the @a info_type is unknown)
11 * @ingroup specialized
12 */
13const union MHD_DaemonInfo *
14MHD_get_daemon_info (struct MHD_Daemon *daemon,
15 enum MHD_DaemonInfoType info_type,
16 ...)
17{
18 if (NULL == daemon)
19 return NULL;
20 switch (info_type)
21 {
22 case MHD_DAEMON_INFO_KEY_SIZE:
23 return NULL; /* no longer supported */
24 case MHD_DAEMON_INFO_MAC_KEY_SIZE:
25 return NULL; /* no longer supported */
26 case MHD_DAEMON_INFO_LISTEN_FD:
27 return (const union MHD_DaemonInfo *) &daemon->listen_fd;
28#ifdef EPOLL_SUPPORT
29 case MHD_DAEMON_INFO_EPOLL_FD:
30 return (const union MHD_DaemonInfo *) &daemon->epoll_fd;
31#endif
32 case MHD_DAEMON_INFO_CURRENT_CONNECTIONS:
33 if (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD))
34 {
35 /* Assume that MHD_run() in not called in other thread
36 * at the same time. */
37 MHD_cleanup_connections (daemon);
38 }
39 else if (daemon->worker_pool)
40 {
41 unsigned int i;
42 /* Collect the connection information stored in the workers. */
43 daemon->connections = 0;
44 for (i = 0; i < daemon->worker_pool_size; i++)
45 {
46 /* FIXME: next line is thread-safe only if read is atomic. */
47 daemon->connections += daemon->worker_pool[i].connections;
48 }
49 }
50 return (const union MHD_DaemonInfo *) &daemon->connections;
51 case MHD_DAEMON_INFO_FLAGS:
52 return (const union MHD_DaemonInfo *) &daemon->options;
53 case MHD_DAEMON_INFO_BIND_PORT:
54 return (const union MHD_DaemonInfo *) &daemon->port;
55 default:
56 return NULL;
57 }
58}
59
60
diff --git a/src/lib/daemon_options.c b/src/lib/daemon_options.c
index 576779e3..3adee960 100644
--- a/src/lib/daemon_options.c
+++ b/src/lib/daemon_options.c
@@ -698,14 +698,40 @@ MHD_daemon_digest_auth_random (struct MHD_Daemon *daemon,
698 * @param daemon daemon to configure 698 * @param daemon daemon to configure
699 * @param nc_length desired array length 699 * @param nc_length desired array length
700 */ 700 */
701void 701enum MHD_StatusCode
702MHD_daemon_digest_auth_nc_length (struct MHD_Daemon *daemon, 702MHD_daemon_digest_auth_nc_length (struct MHD_Daemon *daemon,
703 size_t nc_length) 703 size_t nc_length)
704{ 704{
705#if ENABLE_DAUTH 705#if ENABLE_DAUTH
706 if ( ( (size_t) (nc_length * sizeof (struct MHD_NonceNc))) /
707 sizeof (struct MHD_NonceNc) != nc_length)
708 {
709#ifdef HAVE_MESSAGES
710 MHD_DLOG (daemon,
711 _("Specified value for NC_SIZE too large\n"));
712#endif
713 return MHD_DIGEST_AUTH_NC_LENGTH_TOO_BIG;
714 }
715 if (0 < nc_length)
716 {
717 if (NULL != daemon->nnc)
718 free (daemon->nnc);
719 daemon->nnc = malloc (daemon->nonce_nc_size *
720 sizeof (struct MHD_NonceNc));
721 if (NULL == daemon->nnc)
722 {
723#ifdef HAVE_MESSAGES
724 MHD_DLOG (daemon,
725 _("Failed to allocate memory for nonce-nc map: %s\n"),
726 MHD_strerror_ (errno));
727#endif
728 return MHD_DIGEST_AUTH_NC_ALLOCATION_FAILURE;
729 }
730 }
706 daemon->digest_nc_length = nc_length; 731 daemon->digest_nc_length = nc_length;
732 return MHD_SC_OK;
707#else 733#else
708 MHD_PANIC ("digest authentication not supported by this build"); 734 return MHD_DIGEST_AUTH_NOT_SUPPORTED_BY_BUILD;
709#endif 735#endif
710} 736}
711 737
diff --git a/src/lib/daemon_quiesce.c b/src/lib/daemon_quiesce.c
new file mode 100644
index 00000000..31104a7d
--- /dev/null
+++ b/src/lib/daemon_quiesce.c
@@ -0,0 +1,127 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007-2018 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 lib/daemon.c
22 * @brief main functions to quiesce a daemon
23 * @author Christian Grothoff
24 */
25#include "internal.h"
26
27
28/**
29 * Stop accepting connections from the listening socket. Allows
30 * clients to continue processing, but stops accepting new
31 * connections. Note that the caller is responsible for closing the
32 * returned socket; however, if MHD is run using threads (anything but
33 * external select mode), it must not be closed until AFTER
34 * #MHD_stop_daemon has been called (as it is theoretically possible
35 * that an existing thread is still using it).
36 *
37 * Note that some thread modes require the caller to have passed
38 * #MHD_USE_ITC when using this API. If this daemon is
39 * in one of those modes and this option was not given to
40 * #MHD_start_daemon, this function will return #MHD_INVALID_SOCKET.
41 *
42 * @param daemon daemon to stop accepting new connections for
43 * @return old listen socket on success, #MHD_INVALID_SOCKET if
44 * the daemon was already not listening anymore, or
45 * was never started
46 * @ingroup specialized
47 */
48MHD_socket
49MHD_daemon_quiesce (struct MHD_Daemon *daemon)
50{
51 MHD_socket listen_socket;
52
53 if (MHD_INVALID_SOCKET == (listen_socket = daemon->listen_socket))
54 return MHD_INVALID_SOCKET;
55 if ( (daemon->disable_itc) &&
56 (MHD_TM_EXTERNAL_EVENT_LOOP != daemon->threading_model) )
57 {
58#ifdef HAVE_MESSAGES
59 MHD_DLOG (daemon,
60 MHD_SC_SYSCALL_QUIESCE_REQUIRES_ITC,
61 "Using MHD_quiesce_daemon in this mode requires ITC\n");
62#endif
63 return MHD_INVALID_SOCKET;
64 }
65
66 if (NULL != daemon->worker_pool)
67 {
68 unsigned int i;
69
70 for (i = 0; i < daemon->threading_model; i++)
71 {
72 struct MHD_Daemon *worker = &daemon->worker_pool[i];
73
74 worker->was_quiesced = true;
75#ifdef EPOLL_SUPPORT
76 if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) &&
77 (-1 != worker->epoll_fd) &&
78 (worker->listen_socket_in_epoll) )
79 {
80 if (0 != epoll_ctl (worker->epoll_fd,
81 EPOLL_CTL_DEL,
82 listen_socket,
83 NULL))
84 MHD_PANIC (_("Failed to remove listen FD from epoll set\n"));
85 worker->listen_socket_in_epoll = false;
86 }
87 else
88#endif
89 if (MHD_ITC_IS_VALID_(worker->itc))
90 {
91 if (! MHD_itc_activate_ (worker->itc,
92 "q"))
93 MHD_PANIC (_("Failed to signal quiesce via inter-thread communication channel"));
94 }
95 }
96 daemon->was_quiesced = true;
97#ifdef EPOLL_SUPPORT
98 if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) &&
99 (-1 != daemon->epoll_fd) &&
100 (daemon->listen_socket_in_epoll) )
101 {
102 if (0 != epoll_ctl (daemon->epoll_fd,
103 EPOLL_CTL_DEL,
104 listen_socket,
105 NULL))
106 MHD_PANIC ("Failed to remove listen FD from epoll set\n");
107 daemon->listen_socket_in_epoll = false;
108 }
109#endif
110 }
111
112 if ( (MHD_ITC_IS_VALID_(daemon->itc)) &&
113 (! MHD_itc_activate_ (daemon->itc,
114 "q")) )
115 MHD_PANIC (_("Failed to signal quiesce via inter-thread communication channel"));
116
117 /* FIXME: we might want some bi-directional communication here
118 (in both the thread-pool and single-thread case!)
119 to be sure that the threads have stopped using the listen
120 socket, otherwise there is still the possibility of a race
121 between a thread accept()ing and the caller closing and
122 re-binding the socket. */
123
124 return listen_socket;
125}
126
127
diff --git a/src/lib/init.c b/src/lib/init.c
new file mode 100644
index 00000000..d7a6faa1
--- /dev/null
+++ b/src/lib/init.c
@@ -0,0 +1,156 @@
1#include "init.h"
2
3
4#ifdef MHD_HTTPS_REQUIRE_GRYPT
5#if defined(HTTPS_SUPPORT) && GCRYPT_VERSION_NUMBER < 0x010600
6#if defined(MHD_USE_POSIX_THREADS)
7GCRY_THREAD_OPTION_PTHREAD_IMPL;
8#elif defined(MHD_W32_MUTEX_)
9
10static int
11gcry_w32_mutex_init (void **ppmtx)
12{
13 *ppmtx = malloc (sizeof (MHD_mutex_));
14
15 if (NULL == *ppmtx)
16 return ENOMEM;
17 if (!MHD_mutex_init_ ((MHD_mutex_*)*ppmtx))
18 {
19 free (*ppmtx);
20 *ppmtx = NULL;
21 return EPERM;
22 }
23
24 return 0;
25}
26
27
28static int
29gcry_w32_mutex_destroy (void **ppmtx)
30{
31 int res = (MHD_mutex_destroy_ ((MHD_mutex_*)*ppmtx)) ? 0 : EINVAL;
32 free (*ppmtx);
33 return res;
34}
35
36
37static int
38gcry_w32_mutex_lock (void **ppmtx)
39{
40 return MHD_mutex_lock_ ((MHD_mutex_*)*ppmtx) ? 0 : EINVAL;
41}
42
43
44static int
45gcry_w32_mutex_unlock (void **ppmtx)
46{
47 return MHD_mutex_unlock_ ((MHD_mutex_*)*ppmtx) ? 0 : EINVAL;
48}
49
50
51static struct gcry_thread_cbs gcry_threads_w32 = {
52 (GCRY_THREAD_OPTION_USER | (GCRY_THREAD_OPTION_VERSION << 8)),
53 NULL, gcry_w32_mutex_init, gcry_w32_mutex_destroy,
54 gcry_w32_mutex_lock, gcry_w32_mutex_unlock,
55 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
56
57#endif /* defined(MHD_W32_MUTEX_) */
58#endif /* HTTPS_SUPPORT && GCRYPT_VERSION_NUMBER < 0x010600 */
59#endif /* MHD_HTTPS_REQUIRE_GRYPT */
60
61
62#ifndef _AUTOINIT_FUNCS_ARE_SUPPORTED
63
64/**
65 * Track global initialisation
66 */
67volatile int global_init_count = 0;
68#ifdef MHD_MUTEX_STATIC_DEFN_INIT_
69/**
70 * Global initialisation mutex
71 */
72MHD_MUTEX_STATIC_DEFN_INIT_(global_init_mutex_);
73#endif /* MHD_MUTEX_STATIC_DEFN_INIT_ */
74
75
76/**
77 * Check whether global initialisation was performed
78 * and call initialiser if necessary.
79 */
80void
81MHD_check_global_init_ (void)
82{
83#ifdef MHD_MUTEX_STATIC_DEFN_INIT_
84 MHD_mutex_lock_chk_(&global_init_mutex_);
85#endif /* MHD_MUTEX_STATIC_DEFN_INIT_ */
86 if (0 == global_init_count++)
87 MHD_init ();
88#ifdef MHD_MUTEX_STATIC_DEFN_INIT_
89 MHD_mutex_unlock_chk_(&global_init_mutex_);
90#endif /* MHD_MUTEX_STATIC_DEFN_INIT_ */
91}
92
93
94/**
95 * Initialize do setup work.
96 */
97void
98MHD_init(void)
99{
100#if defined(_WIN32) && ! defined(__CYGWIN__)
101 WSADATA wsd;
102#endif /* _WIN32 && ! __CYGWIN__ */
103
104 if (NULL == mhd_panic)
105 mhd_panic = &mhd_panic_std;
106
107#if defined(_WIN32) && ! defined(__CYGWIN__)
108 if (0 != WSAStartup(MAKEWORD(2, 2), &wsd))
109 MHD_PANIC (_("Failed to initialize winsock\n"));
110 mhd_winsock_inited_ = 1;
111 if (2 != LOBYTE(wsd.wVersion) && 2 != HIBYTE(wsd.wVersion))
112 MHD_PANIC (_("Winsock version 2.2 is not available\n"));
113#endif
114#ifdef HTTPS_SUPPORT
115#ifdef MHD_HTTPS_REQUIRE_GRYPT
116#if GCRYPT_VERSION_NUMBER < 0x010600
117#if defined(MHD_USE_POSIX_THREADS)
118 if (0 != gcry_control (GCRYCTL_SET_THREAD_CBS,
119 &gcry_threads_pthread))
120 MHD_PANIC (_("Failed to initialise multithreading in libgcrypt\n"));
121#elif defined(MHD_W32_MUTEX_)
122 if (0 != gcry_control (GCRYCTL_SET_THREAD_CBS,
123 &gcry_threads_w32))
124 MHD_PANIC (_("Failed to initialise multithreading in libgcrypt\n"));
125#endif /* defined(MHD_W32_MUTEX_) */
126 gcry_check_version (NULL);
127#else
128 if (NULL == gcry_check_version ("1.6.0"))
129 MHD_PANIC (_("libgcrypt is too old. MHD was compiled for libgcrypt 1.6.0 or newer\n"));
130#endif
131#endif /* MHD_HTTPS_REQUIRE_GRYPT */
132 gnutls_global_init ();
133#endif /* HTTPS_SUPPORT */
134 MHD_monotonic_sec_counter_init();
135#ifdef HAVE_FREEBSD_SENDFILE
136 MHD_conn_init_static_ ();
137#endif /* HAVE_FREEBSD_SENDFILE */
138}
139
140
141void
142MHD_fini(void)
143{
144#ifdef HTTPS_SUPPORT
145 gnutls_global_deinit ();
146#endif /* HTTPS_SUPPORT */
147#if defined(_WIN32) && ! defined(__CYGWIN__)
148 if (mhd_winsock_inited_)
149 WSACleanup();
150#endif
151 MHD_monotonic_sec_counter_finish();
152}
153
154#ifdef _AUTOINIT_FUNCS_ARE_SUPPORTED
155_SET_INIT_AND_DEINIT_FUNCS(MHD_init, MHD_fini);
156#endif /* _AUTOINIT_FUNCS_ARE_SUPPORTED */
diff --git a/src/lib/init.h b/src/lib/init.h
new file mode 100644
index 00000000..25243c17
--- /dev/null
+++ b/src/lib/init.h
@@ -0,0 +1,29 @@
1
2
3#ifndef INIT_H
4#define INIT_H
5
6/**
7 * Globally initialise library.
8 */
9void
10MHD_init(void);
11
12
13#ifdef _AUTOINIT_FUNCS_ARE_SUPPORTED
14/**
15 * Do nothing - global initialisation is
16 * performed by library constructor.
17 */
18#define MHD_check_global_init_() (void)0
19#else /* ! _AUTOINIT_FUNCS_ARE_SUPPORTED */
20/**
21 * Check whether global initialisation was performed
22 * and call initialiser if necessary.
23 */
24void
25MHD_check_global_init_ (void);
26#endif /* ! _AUTOINIT_FUNCS_ARE_SUPPORTED */
27
28
29#endif /* INIT_H */
diff --git a/src/lib/internal.h b/src/lib/internal.h
index 8de88598..c14d96eb 100644
--- a/src/lib/internal.h
+++ b/src/lib/internal.h
@@ -126,6 +126,599 @@ extern void *mhd_panic_cls;
126#endif /* ! MHD_STATICSTR_LEN_ */ 126#endif /* ! MHD_STATICSTR_LEN_ */
127 127
128 128
129
130/**
131 * Ability to use same connection for next request
132 */
133enum MHD_ConnKeepAlive
134{
135 /**
136 * Connection must be closed after sending response.
137 */
138 MHD_CONN_MUST_CLOSE = -1,
139
140 /**
141 * KeelAlive state is not yet determined
142 */
143 MHD_CONN_KEEPALIVE_UNKOWN = 0,
144
145 /**
146 * Connection can be used for serving next request
147 */
148 MHD_CONN_USE_KEEPALIVE = 1
149};
150
151
152/**
153 * Function to receive plaintext data.
154 *
155 * @param conn the connection struct
156 * @param write_to where to write received data
157 * @param max_bytes maximum number of bytes to receive
158 * @return number of bytes written to @a write_to
159 */
160typedef ssize_t
161(*ReceiveCallback) (struct MHD_Connection *conn,
162 void *write_to,
163 size_t max_bytes);
164
165
166/**
167 * Function to transmit plaintext data.
168 *
169 * @param conn the connection struct
170 * @param read_from where to read data to transmit
171 * @param max_bytes maximum number of bytes to transmit
172 * @return number of bytes transmitted
173 */
174typedef ssize_t
175(*TransmitCallback) (struct MHD_Connection *conn,
176 const void *read_from,
177 size_t max_bytes);
178
179
180/**
181 * States in a state machine for a request.
182 *
183 * The main transitions are any-state to #MHD_REQUEST_CLOSED, any
184 * state to state+1, #MHD_REQUEST_FOOTERS_SENT to
185 * #MHD_REQUEST_INIT. #MHD_REQUEST_CLOSED is the terminal state
186 * and #MHD_REQUEST_INIT the initial state.
187 *
188 * Note that transitions for *reading* happen only after the input has
189 * been processed; transitions for *writing* happen after the
190 * respective data has been put into the write buffer (the write does
191 * not have to be completed yet). A transition to
192 * #MHD_REQUEST_CLOSED or #MHD_REQUEST_INIT requires the write
193 * to be complete.
194 */
195enum MHD_REQUEST_STATE
196{
197 /**
198 * Request just started (no headers received).
199 * Waiting for the line with the request type, URL and version.
200 */
201 MHD_REQUEST_INIT = 0,
202
203 /**
204 * 1: We got the URL (and request type and version). Wait for a header line.
205 */
206 MHD_REQUEST_URL_RECEIVED = MHD_REQUEST_INIT + 1,
207
208 /**
209 * 2: We got part of a multi-line request header. Wait for the rest.
210 */
211 MHD_REQUEST_HEADER_PART_RECEIVED = MHD_REQUEST_URL_RECEIVED + 1,
212
213 /**
214 * 3: We got the request headers. Process them.
215 */
216 MHD_REQUEST_HEADERS_RECEIVED = MHD_REQUEST_HEADER_PART_RECEIVED + 1,
217
218 /**
219 * 4: We have processed the request headers. Send 100 continue.
220 */
221 MHD_REQUEST_HEADERS_PROCESSED = MHD_REQUEST_HEADERS_RECEIVED + 1,
222
223 /**
224 * 5: We have processed the headers and need to send 100 CONTINUE.
225 */
226 MHD_REQUEST_CONTINUE_SENDING = MHD_REQUEST_HEADERS_PROCESSED + 1,
227
228 /**
229 * 6: We have sent 100 CONTINUE (or do not need to). Read the message body.
230 */
231 MHD_REQUEST_CONTINUE_SENT = MHD_REQUEST_CONTINUE_SENDING + 1,
232
233 /**
234 * 7: We got the request body. Wait for a line of the footer.
235 */
236 MHD_REQUEST_BODY_RECEIVED = MHD_REQUEST_CONTINUE_SENT + 1,
237
238 /**
239 * 8: We got part of a line of the footer. Wait for the
240 * rest.
241 */
242 MHD_REQUEST_FOOTER_PART_RECEIVED = MHD_REQUEST_BODY_RECEIVED + 1,
243
244 /**
245 * 9: We received the entire footer. Wait for a response to be queued
246 * and prepare the response headers.
247 */
248 MHD_REQUEST_FOOTERS_RECEIVED = MHD_REQUEST_FOOTER_PART_RECEIVED + 1,
249
250 /**
251 * 10: We have prepared the response headers in the writ buffer.
252 * Send the response headers.
253 */
254 MHD_REQUEST_HEADERS_SENDING = MHD_REQUEST_FOOTERS_RECEIVED + 1,
255
256 /**
257 * 11: We have sent the response headers. Get ready to send the body.
258 */
259 MHD_REQUEST_HEADERS_SENT = MHD_REQUEST_HEADERS_SENDING + 1,
260
261 /**
262 * 12: We are ready to send a part of a non-chunked body. Send it.
263 */
264 MHD_REQUEST_NORMAL_BODY_READY = MHD_REQUEST_HEADERS_SENT + 1,
265
266 /**
267 * 13: We are waiting for the client to provide more
268 * data of a non-chunked body.
269 */
270 MHD_REQUEST_NORMAL_BODY_UNREADY = MHD_REQUEST_NORMAL_BODY_READY + 1,
271
272 /**
273 * 14: We are ready to send a chunk.
274 */
275 MHD_REQUEST_CHUNKED_BODY_READY = MHD_REQUEST_NORMAL_BODY_UNREADY + 1,
276
277 /**
278 * 15: We are waiting for the client to provide a chunk of the body.
279 */
280 MHD_REQUEST_CHUNKED_BODY_UNREADY = MHD_REQUEST_CHUNKED_BODY_READY + 1,
281
282 /**
283 * 16: We have sent the response body. Prepare the footers.
284 */
285 MHD_REQUEST_BODY_SENT = MHD_REQUEST_CHUNKED_BODY_UNREADY + 1,
286
287 /**
288 * 17: We have prepared the response footer. Send it.
289 */
290 MHD_REQUEST_FOOTERS_SENDING = MHD_REQUEST_BODY_SENT + 1,
291
292 /**
293 * 18: We have sent the response footer. Shutdown or restart.
294 */
295 MHD_REQUEST_FOOTERS_SENT = MHD_REQUEST_FOOTERS_SENDING + 1,
296
297 /**
298 * 19: This request is to be closed.
299 */
300 MHD_REQUEST_CLOSED = MHD_REQUEST_FOOTERS_SENT + 1,
301
302 /**
303 * 20: This request is finished (only to be freed)
304 */
305 MHD_REQUEST_IN_CLEANUP = MHD_REQUEST_CLOSED + 1,
306
307#ifdef UPGRADE_SUPPORT
308 /**
309 * Request was "upgraded" and socket is now under the
310 * control of the application.
311 */
312 MHD_REQUEST_UPGRADE
313#endif /* UPGRADE_SUPPORT */
314
315};
316
317
318/**
319 * Header or cookie in HTTP request or response.
320 */
321struct MHD_HTTP_Header
322{
323 /**
324 * Headers are kept in a linked list.
325 */
326 struct MHD_HTTP_Header *next;
327
328 /**
329 * The name of the header (key), without the colon.
330 */
331 char *header;
332
333 /**
334 * The value of the header.
335 */
336 char *value;
337
338 /**
339 * Type of the header (where in the HTTP protocol is this header
340 * from).
341 */
342 enum MHD_ValueKind kind;
343
344};
345
346
347/**
348 * State kept for each HTTP request.
349 */
350struct MHD_Request
351{
352
353 /**
354 * Reference to the MHD_Daemon struct.
355 */
356 struct MHD_Daemon *daemon;
357
358 /**
359 * Connection this request is associated with.
360 */
361 struct MHD_Connection *connection;
362
363 /**
364 * Linked list of parsed headers.
365 */
366 struct MHD_HTTP_Header *headers_received;
367
368 /**
369 * Tail of linked list of parsed headers.
370 */
371 struct MHD_HTTP_Header *headers_received_tail;
372
373 /**
374 * The memory pool is created whenever we first read from the TCP
375 * stream and destroyed at the end of each request (and re-created
376 * for the next request). In the meantime, this pointer is NULL.
377 * The pool is used for all request-related data except for the
378 * response (which maybe shared between requests) and the IP
379 * address (which persists across individual requests).
380 */
381 struct MemoryPool *pool;
382
383 /**
384 * We allow the main application to associate some pointer with the
385 * HTTP request, which is passed to each #MHD_AccessHandlerCallback
386 * and some other API calls. Here is where we store it. (MHD does
387 * not know or care what it is).
388 */
389 void *client_context;
390
391 /**
392 * Request method. Should be GET/POST/etc. Allocated in pool.
393 */
394 char *method;
395
396 /**
397 * Requested URL (everything after "GET" only). Allocated
398 * in pool.
399 */
400 const char *url;
401
402 /**
403 * HTTP version string (i.e. http/1.1). Allocated
404 * in pool.
405 */
406 char *version;
407
408 /**
409 * Close connection after sending response?
410 * Functions may change value from "Unknown" or "KeepAlive" to "Must close",
411 * but no functions reset value "Must Close" to any other value.
412 */
413 enum MHD_ConnKeepAlive keepalive;
414
415 /**
416 * Buffer for reading requests. Allocated in pool. Actually one
417 * byte larger than @e read_buffer_size (if non-NULL) to allow for
418 * 0-termination.
419 */
420 char *read_buffer;
421
422 /**
423 * Buffer for writing response (headers only). Allocated
424 * in pool.
425 */
426 char *write_buffer;
427
428 /**
429 * Last incomplete header line during parsing of headers.
430 * Allocated in pool. Only valid if state is
431 * either #MHD_REQUEST_HEADER_PART_RECEIVED or
432 * #MHD_REQUEST_FOOTER_PART_RECEIVED.
433 */
434 char *last;
435
436 /**
437 * Position after the colon on the last incomplete header
438 * line during parsing of headers.
439 * Allocated in pool. Only valid if state is
440 * either #MHD_REQUEST_HEADER_PART_RECEIVED or
441 * #MHD_REQUEST_FOOTER_PART_RECEIVED.
442 */
443 char *colon;
444
445
446 /**
447 * Function used for reading HTTP request stream.
448 */
449 ReceiveCallback recv_cls;
450
451 /**
452 * Function used for writing HTTP response stream.
453 */
454 TransmitCallback send_cls;
455
456#ifdef UPGRADE_SUPPORT
457 /**
458 * If this connection was upgraded, this points to
459 * the upgrade response details such that the
460 * #thread_main_connection_upgrade()-logic can perform the
461 * bi-directional forwarding.
462 */
463 struct MHD_UpgradeResponseHandle *urh;
464#endif /* UPGRADE_SUPPORT */
465
466 /**
467 * Foreign address (of length @e addr_len).
468 */
469 struct sockaddr_storage addr;
470
471 /**
472 * Thread handle for this connection (if we are using
473 * one thread per connection).
474 */
475 MHD_thread_handle_ID_ pid;
476
477 /**
478 * Size of @e read_buffer (in bytes). This value indicates
479 * how many bytes we're willing to read into the buffer;
480 * the real buffer is one byte longer to allow for
481 * adding zero-termination (when needed).
482 */
483 size_t read_buffer_size;
484
485 /**
486 * Position where we currently append data in
487 * @e read_buffer (last valid position).
488 */
489 size_t read_buffer_offset;
490
491 /**
492 * Size of @e write_buffer (in bytes).
493 */
494 size_t write_buffer_size;
495
496 /**
497 * Offset where we are with sending from @e write_buffer.
498 */
499 size_t write_buffer_send_offset;
500
501 /**
502 * Last valid location in write_buffer (where do we
503 * append and up to where is it safe to send?)
504 */
505 size_t write_buffer_append_offset;
506
507 /**
508 * Number of bytes we had in the HTTP header, set once we
509 * pass #MHD_REQUEST_HEADERS_RECEIVED.
510 */
511 size_t header_size;
512
513 /**
514 * How many more bytes of the body do we expect
515 * to read? #MHD_SIZE_UNKNOWN for unknown.
516 */
517 uint64_t remaining_upload_size;
518
519 /**
520 * If we are receiving with chunked encoding, where are we right
521 * now? Set to 0 if we are waiting to receive the chunk size;
522 * otherwise, this is the size of the current chunk. A value of
523 * zero is also used when we're at the end of the chunks.
524 */
525 uint64_t current_chunk_size;
526
527 /**
528 * If we are receiving with chunked encoding, where are we currently
529 * with respect to the current chunk (at what offset / position)?
530 */
531 uint64_t current_chunk_offset;
532
533 /**
534 * Current write position in the actual response
535 * (excluding headers, content only; should be 0
536 * while sending headers).
537 */
538 uint64_t response_write_position;
539
540#if defined(_MHD_HAVE_SENDFILE)
541 enum MHD_resp_sender_
542 {
543 MHD_resp_sender_std = 0,
544 MHD_resp_sender_sendfile
545 } resp_sender;
546#endif /* _MHD_HAVE_SENDFILE */
547
548 /**
549 * Position in the 100 CONTINUE message that
550 * we need to send when receiving http 1.1 requests.
551 */
552 size_t continue_message_write_offset;
553
554 /**
555 * State in the FSM for this request.
556 */
557 enum MHD_REQUEST_STATE state;
558
559 /**
560 * What is this request waiting for?
561 */
562 enum MHD_RequestEventLoopInfo event_loop_info;
563
564 /**
565 * HTTP response code. Only valid if response object
566 * is already set.
567 */
568 unsigned int responseCode;
569
570 /**
571 * Did we ever call the "default_handler" on this request? (this
572 * flag will determine if we call the #MHD_OPTION_NOTIFY_COMPLETED
573 * handler when the request closes down).
574 */
575 bool client_aware;
576
577 /**
578 * Are we currently inside the "idle" handler (to avoid recursively
579 * invoking it).
580 */
581 bool in_idle;
582
583 /**
584 * Are we currently inside the "idle" handler (to avoid recursively
585 * invoking it).
586 */
587 bool in_cleanup;
588
589 /**
590 * Are we receiving with chunked encoding? This will be set to
591 * #MHD_YES after we parse the headers and are processing the body
592 * with chunks. After we are done with the body and we are
593 * processing the footers; once the footers are also done, this will
594 * be set to #MHD_NO again (before the final call to the handler).
595 */
596 bool have_chunked_upload;
597
598 /**
599 * Is the request suspended?
600 */
601 bool suspended;
602
603 /**
604 * Is the request wanting to resume?
605 */
606 bool resuming;
607};
608
609
610/**
611 * State kept per HTTP connection.
612 */
613struct MHD_Connection
614{
615
616#ifdef EPOLL_SUPPORT
617 /**
618 * Next pointer for the EDLL listing connections that are epoll-ready.
619 */
620 struct MHD_Connection *nextE;
621
622 /**
623 * Previous pointer for the EDLL listing connections that are epoll-ready.
624 */
625 struct MHD_Connection *prevE;
626#endif
627
628 /**
629 * Next pointer for the DLL describing our IO state.
630 */
631 struct MHD_Connection *next;
632
633 /**
634 * Previous pointer for the DLL describing our IO state.
635 */
636 struct MHD_Connection *prev;
637
638 /**
639 * Next pointer for the XDLL organizing connections by timeout.
640 * This DLL can be either the
641 * 'manual_timeout_head/manual_timeout_tail' or the
642 * 'normal_timeout_head/normal_timeout_tail', depending on whether a
643 * custom timeout is set for the connection.
644 */
645 struct MHD_Connection *nextX;
646
647 /**
648 * Previous pointer for the XDLL organizing connections by timeout.
649 */
650 struct MHD_Connection *prevX;
651
652 /**
653 * Reference to the MHD_Daemon struct.
654 */
655 struct MHD_Daemon *daemon;
656
657 /**
658 * Information about the current request we are processing
659 * on this connection.
660 */
661 struct MHD_Request request;
662
663
664 /**
665 * Set to `true` if the thread has been joined.
666 */
667 bool thread_joined;
668
669 /**
670 * true if #socket_fd is non-blocking, false otherwise.
671 */
672 bool sk_nonblck;
673
674 /**
675 * Has this socket been closed for reading (i.e. other side closed
676 * the connection)? If so, we must completely close the connection
677 * once we are done sending our response (and stop trying to read
678 * from this socket).
679 */
680 bool read_closed;
681
682
683 /**
684 * Length of the foreign address.
685 */
686 socklen_t addr_len;
687
688 /**
689 * Last time this connection had any activity
690 * (reading or writing).
691 */
692 time_t last_activity;
693
694 /**
695 * After how many seconds of inactivity should
696 * this connection time out? Zero for no timeout.
697 */
698 time_t connection_timeout;
699
700 /**
701 * Socket for this connection. Set to #MHD_INVALID_SOCKET if
702 * this connection has died (daemon should clean
703 * up in that case).
704 */
705 MHD_socket socket_fd;
706
707
708#ifdef EPOLL_SUPPORT
709 /**
710 * What is the state of this socket in relation to epoll?
711 */
712 enum MHD_EpollState epoll_state;
713#endif
714
715
716};
717
718
719
720
721
129/** 722/**
130 * State kept for each MHD daemon. All connections are kept in two 723 * State kept for each MHD daemon. All connections are kept in two
131 * doubly-linked lists. The first one reflects the state of the 724 * doubly-linked lists. The first one reflects the state of the
@@ -324,8 +917,14 @@ struct MHD_Daemon
324 MHD_socket listen_socket; 917 MHD_socket listen_socket;
325 918
326 /** 919 /**
920 * Inter-thread communication channel.
921 */
922 struct MHD_itc_ itc;
923
924 /**
327 * Which threading model do we use? Postive 925 * Which threading model do we use? Postive
328 * numbers indicate the number of worker threads to be used. 926 * numbers indicate the number of worker threads to be used.
927 * Values larger than 1 imply a thread pool.
329 */ 928 */
330 enum MHD_ThreadingModel threading_model; 929 enum MHD_ThreadingModel threading_model;
331 930
@@ -337,7 +936,7 @@ struct MHD_Daemon
337 936
338 /** 937 /**
339 * Address family to use when listening. 938 * Address family to use when listening.
340 * Default is #MHD_AF_AUTO. 939 * Default is #MHD_AF_NONE (do not listen).
341 */ 940 */
342 enum MHD_AddressFamily listen_af; 941 enum MHD_AddressFamily listen_af;
343 942
@@ -357,8 +956,7 @@ struct MHD_Daemon
357 /** 956 /**
358 * On which port should we listen on? Only effective if we were not 957 * On which port should we listen on? Only effective if we were not
359 * given a listen socket or a full address via 958 * given a listen socket or a full address via
360 * #MHD_daemon_bind_sa(). 0 means not set, which means to default 959 * #MHD_daemon_bind_sa(). 0 means to bind to random free port.
361 * to 80 (http) or 443 (https) respectively.
362 */ 960 */
363 uint16_t listen_port; 961 uint16_t listen_port;
364 962
diff --git a/src/lib/panic.c b/src/lib/panic.c
new file mode 100644
index 00000000..f3cfe82d
--- /dev/null
+++ b/src/lib/panic.c
@@ -0,0 +1,36 @@
1
2
3/**
4 * Handler for fatal errors.
5 */
6MHD_PanicCallback mhd_panic = NULL;
7
8/**
9 * Closure argument for #mhd_panic.
10 */
11void *mhd_panic_cls = NULL;
12
13
14/**
15 * Sets the global error handler to a different implementation. @a cb
16 * will only be called in the case of typically fatal, serious
17 * internal consistency issues. These issues should only arise in the
18 * case of serious memory corruption or similar problems with the
19 * architecture. While @a cb is allowed to return and MHD will then
20 * try to continue, this is never safe.
21 *
22 * The default implementation that is used if no panic function is set
23 * simply prints an error message and calls `abort()`. Alternative
24 * implementations might call `exit()` or other similar functions.
25 *
26 * @param cb new error handler
27 * @param cls passed to @a cb
28 * @ingroup logging
29 */
30void
31MHD_set_panic_func (MHD_PanicCallback cb,
32 void *cls)
33{
34 mhd_panic = cb;
35 mhd_panic_cls = cls;
36}
diff --git a/src/lib/request.c b/src/lib/request.c
index 8af35b28..0e280efa 100644
--- a/src/lib/request.c
+++ b/src/lib/request.c
@@ -1,3 +1,31 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007-2018 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 requests.c
22 * @brief Methods for managing HTTP requests
23 * @author Daniel Pittman
24 * @author Christian Grothoff
25 * @author Karlson2k (Evgeny Grin)
26 */
27
28
1/** 29/**
2 * Get all of the headers from the request. 30 * Get all of the headers from the request.
3 * 31 *
@@ -9,11 +37,35 @@
9 * @return number of entries iterated over 37 * @return number of entries iterated over
10 * @ingroup request 38 * @ingroup request
11 */ 39 */
12_MHD_EXTERN unsigned int 40unsigned int
13MHD_request_get_values (struct MHD_Request *request, 41MHD_request_get_values (struct MHD_Request *request,
14 enum MHD_ValueKind kind, 42 enum MHD_ValueKind kind,
15 MHD_KeyValueIterator iterator, 43 MHD_KeyValueIterator iterator,
16 void *iterator_cls); 44 void *iterator_cls)
45{
46 int ret;
47 struct MHD_HTTP_Header *pos;
48
49 if (NULL == request)
50 return -1;
51 ret = 0;
52 for (pos = request->headers_received;
53 NULL != pos;
54 pos = pos->next)
55 {
56 if (0 != (pos->kind & kind))
57 {
58 ret++;
59 if ( (NULL != iterator) &&
60 (MHD_YES != iterator (iterator_cls,
61 pos->kind,
62 pos->header,
63 pos->value)) )
64 return ret;
65 }
66 }
67 return ret;
68}
17 69
18 70
19/** 71/**
@@ -41,11 +93,36 @@ MHD_request_get_values (struct MHD_Request *request,
41 * #MHD_YES on success 93 * #MHD_YES on success
42 * @ingroup request 94 * @ingroup request
43 */ 95 */
44_MHD_EXTERN enum MHD_Bool 96enum MHD_Bool
45MHD_request_set_value (struct MHD_Request *request, 97MHD_request_set_value (struct MHD_Request *request,
46 enum MHD_ValueKind kind, 98 enum MHD_ValueKind kind,
47 const char *key, 99 const char *key,
48 const char *value); 100 const char *value)
101{
102 struct MHD_HTTP_Header *pos;
103
104 pos = MHD_pool_allocate (request->pool,
105 sizeof (struct MHD_HTTP_Header),
106 MHD_YES);
107 if (NULL == pos)
108 return MHD_NO;
109 pos->header = (char *) key;
110 pos->value = (char *) value;
111 pos->kind = kind;
112 pos->next = NULL;
113 /* append 'pos' to the linked list of headers */
114 if (NULL == request->headers_received_tail)
115 {
116 request->headers_received = pos;
117 request->headers_received_tail = pos;
118 }
119 else
120 {
121 request->headers_received_tail->next = pos;
122 request->headers_received_tail = pos;
123 }
124 return MHD_YES;
125}
49 126
50 127
51/** 128/**
@@ -58,11 +135,31 @@ MHD_request_set_value (struct MHD_Request *request,
58 * @return NULL if no such item was found 135 * @return NULL if no such item was found
59 * @ingroup request 136 * @ingroup request
60 */ 137 */
61_MHD_EXTERN const char * 138const char *
62MHD_request_lookup_value (struct MHD_Request *request, 139MHD_request_lookup_value (struct MHD_Request *request,
63 enum MHD_ValueKind kind, 140 enum MHD_ValueKind kind,
64 const char *key); 141 const char *key)
142{
143 struct MHD_HTTP_Header *pos;
144
145 if (NULL == request)
146 return NULL;
147 for (pos = request->headers_received;
148 NULL != pos;
149 pos = pos->next)
150 {
151 if ((0 != (pos->kind & kind)) &&
152 ( (key == pos->header) ||
153 ( (NULL != pos->header) &&
154 (NULL != key) &&
155 (MHD_str_equal_caseless_(key,
156 pos->header)))))
157 return pos->value;
158 }
159 return NULL;
160}
65 161
66 162
163/* end of request.c */
67 164
68 165
diff --git a/src/lib/version.c b/src/lib/version.c
new file mode 100644
index 00000000..84918fb7
--- /dev/null
+++ b/src/lib/version.c
@@ -0,0 +1,181 @@
1
2
3/**
4 * Obtain the version of this library
5 *
6 * @return static version string, e.g. "0.9.9"
7 * @ingroup specialized
8 */
9const char *
10MHD_get_version (void)
11{
12#ifdef PACKAGE_VERSION
13 return PACKAGE_VERSION;
14#else /* !PACKAGE_VERSION */
15 static char ver[12] = "\0\0\0\0\0\0\0\0\0\0\0";
16 if (0 == ver[0])
17 {
18 int res = MHD_snprintf_(ver,
19 sizeof(ver),
20 "%x.%x.%x",
21 (((int)MHD_VERSION >> 24) & 0xFF),
22 (((int)MHD_VERSION >> 16) & 0xFF),
23 (((int)MHD_VERSION >> 8) & 0xFF));
24 if (0 >= res || sizeof(ver) <= res)
25 return "0.0.0"; /* Can't return real version*/
26 }
27 return ver;
28#endif /* !PACKAGE_VERSION */
29}
30
31
32/**
33 * Get information about supported MHD features.
34 * Indicate that MHD was compiled with or without support for
35 * particular feature. Some features require additional support
36 * by kernel. Kernel support is not checked by this function.
37 *
38 * @param feature type of requested information
39 * @return #MHD_YES if feature is supported by MHD, #MHD_NO if
40 * feature is not supported or feature is unknown.
41 * @ingroup specialized
42 */
43_MHD_EXTERN int
44MHD_is_feature_supported(enum MHD_FEATURE feature)
45{
46 switch(feature)
47 {
48 case MHD_FEATURE_MESSAGES:
49#ifdef HAVE_MESSAGES
50 return MHD_YES;
51#else
52 return MHD_NO;
53#endif
54 case MHD_FEATURE_TLS:
55#ifdef HTTPS_SUPPORT
56 return MHD_YES;
57#else /* ! HTTPS_SUPPORT */
58 return MHD_NO;
59#endif /* ! HTTPS_SUPPORT */
60 case MHD_FEATURE_HTTPS_CERT_CALLBACK:
61#if defined(HTTPS_SUPPORT) && GNUTLS_VERSION_MAJOR >= 3
62 return MHD_YES;
63#else /* !HTTPS_SUPPORT || GNUTLS_VERSION_MAJOR < 3 */
64 return MHD_NO;
65#endif /* !HTTPS_SUPPORT || GNUTLS_VERSION_MAJOR < 3 */
66 case MHD_FEATURE_IPv6:
67#ifdef HAVE_INET6
68 return MHD_YES;
69#else
70 return MHD_NO;
71#endif
72 case MHD_FEATURE_IPv6_ONLY:
73#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
74 return MHD_YES;
75#else
76 return MHD_NO;
77#endif
78 case MHD_FEATURE_POLL:
79#ifdef HAVE_POLL
80 return MHD_YES;
81#else
82 return MHD_NO;
83#endif
84 case MHD_FEATURE_EPOLL:
85#ifdef EPOLL_SUPPORT
86 return MHD_YES;
87#else
88 return MHD_NO;
89#endif
90 case MHD_FEATURE_SHUTDOWN_LISTEN_SOCKET:
91#ifdef HAVE_LISTEN_SHUTDOWN
92 return MHD_YES;
93#else
94 return MHD_NO;
95#endif
96 case MHD_FEATURE_SOCKETPAIR:
97#ifdef _MHD_ITC_SOCKETPAIR
98 return MHD_YES;
99#else
100 return MHD_NO;
101#endif
102 case MHD_FEATURE_TCP_FASTOPEN:
103#ifdef TCP_FASTOPEN
104 return MHD_YES;
105#else
106 return MHD_NO;
107#endif
108 case MHD_FEATURE_BASIC_AUTH:
109#ifdef BAUTH_SUPPORT
110 return MHD_YES;
111#else
112 return MHD_NO;
113#endif
114 case MHD_FEATURE_DIGEST_AUTH:
115#ifdef DAUTH_SUPPORT
116 return MHD_YES;
117#else
118 return MHD_NO;
119#endif
120 case MHD_FEATURE_POSTPROCESSOR:
121#ifdef HAVE_POSTPROCESSOR
122 return MHD_YES;
123#else
124 return MHD_NO;
125#endif
126 case MHD_FEATURE_HTTPS_KEY_PASSWORD:
127#if defined(HTTPS_SUPPORT) && GNUTLS_VERSION_NUMBER >= 0x030111
128 return MHD_YES;
129#else /* !HTTPS_SUPPORT || GNUTLS_VERSION_NUMBER < 0x030111 */
130 return MHD_NO;
131#endif /* !HTTPS_SUPPORT || GNUTLS_VERSION_NUMBER < 0x030111 */
132 case MHD_FEATURE_LARGE_FILE:
133#if defined(HAVE_PREAD64) || defined(_WIN32)
134 return MHD_YES;
135#elif defined(HAVE_PREAD)
136 return (sizeof(uint64_t) > sizeof(off_t)) ? MHD_NO : MHD_YES;
137#elif defined(HAVE_LSEEK64)
138 return MHD_YES;
139#else
140 return (sizeof(uint64_t) > sizeof(off_t)) ? MHD_NO : MHD_YES;
141#endif
142 case MHD_FEATURE_THREAD_NAMES:
143#if defined(MHD_USE_THREAD_NAME_)
144 return MHD_YES;
145#else
146 return MHD_NO;
147#endif
148 case MHD_FEATURE_UPGRADE:
149#if defined(UPGRADE_SUPPORT)
150 return MHD_YES;
151#else
152 return MHD_NO;
153#endif
154 case MHD_FEATURE_RESPONSES_SHARED_FD:
155#if defined(HAVE_PREAD64) || defined(HAVE_PREAD) || defined(_WIN32)
156 return MHD_YES;
157#else
158 return MHD_NO;
159#endif
160 case MHD_FEATURE_AUTODETECT_BIND_PORT:
161#ifdef MHD_USE_GETSOCKNAME
162 return MHD_YES;
163#else
164 return MHD_NO;
165#endif
166 case MHD_FEATURE_AUTOSUPPRESS_SIGPIPE:
167#if defined(MHD_WINSOCK_SOCKETS) || defined(MHD_socket_nosignal_) || defined (MSG_NOSIGNAL)
168 return MHD_YES;
169#else
170 return MHD_NO;
171#endif
172 case MHD_FEATURE_SENDFILE:
173#ifdef _MHD_HAVE_SENDFILE
174 return MHD_YES;
175#else
176 return MHD_NO;
177#endif
178
179 }
180 return MHD_NO;
181}
diff --git a/src/microhttpd/mhd_sockets.c b/src/microhttpd/mhd_sockets.c
index 47c2d9dc..ddcc1f25 100644
--- a/src/microhttpd/mhd_sockets.c
+++ b/src/microhttpd/mhd_sockets.c
@@ -468,7 +468,7 @@ MHD_socket_noninheritable_ (MHD_socket sock)
468 * @return created socket or MHD_INVALID_SOCKET in case of errors 468 * @return created socket or MHD_INVALID_SOCKET in case of errors
469 */ 469 */
470MHD_socket 470MHD_socket
471MHD_socket_create_listen_ (int use_ipv6) 471MHD_socket_create_listen_ (bool use_ipv6)
472{ 472{
473 int domain; 473 int domain;
474 MHD_socket fd; 474 MHD_socket fd;
diff --git a/src/microhttpd/mhd_sockets.h b/src/microhttpd/mhd_sockets.h
index b013baad..c999ea35 100644
--- a/src/microhttpd/mhd_sockets.h
+++ b/src/microhttpd/mhd_sockets.h
@@ -755,6 +755,6 @@ MHD_socket_noninheritable_ (MHD_socket sock);
755 * @return created socket or MHD_INVALID_SOCKET in case of errors 755 * @return created socket or MHD_INVALID_SOCKET in case of errors
756 */ 756 */
757MHD_socket 757MHD_socket
758MHD_socket_create_listen_ (int use_ipv6); 758MHD_socket_create_listen_ (bool use_ipv6);
759 759
760#endif /* ! MHD_SOCKETS_H */ 760#endif /* ! MHD_SOCKETS_H */