27 #if defined(_WIN32) && !defined(__CYGWIN__)
29 #define FD_SETSIZE 1024
30 #define MHD_DEFAULT_FD_SETSIZE 64
32 #define MHD_DEFAULT_FD_SETSIZE FD_SETSIZE
58 #include <sys/sendfile.h>
62 #ifndef WIN32_LEAN_AND_MEAN
63 #define WIN32_LEAN_AND_MEAN 1
69 #define HAVE_ACCEPT4 0
76 #define MHD_MAX_CONNECTIONS_DEFAULT FD_SETSIZE - 4
78 #define MHD_MAX_CONNECTIONS_DEFAULT FD_SETSIZE
84 #define MHD_POOL_SIZE_DEFAULT (32 * 1024)
90 #define MHD_TCP_FASTOPEN_QUEUE_SIZE_DEFAULT 10
97 #define DEBUG_CLOSE MHD_NO
103 #define DEBUG_CONNECT MHD_NO
107 #define MSG_NOSIGNAL 0
112 #define SOCK_CLOEXEC 0
115 #ifndef EPOLL_CLOEXEC
116 #define EPOLL_CLOEXEC 0
136 fprintf (stderr,
"Fatal error in GNU libmicrohttpd %s:%u: %s\n",
157 static int mhd_winsock_inited_ = 0;
199 struct in6_addr ipv6;
220 MHD_PANIC (
"Failed to acquire IP connection limit mutex\n");
235 MHD_PANIC (
"Failed to release IP connection limit mutex\n");
252 return memcmp (a1, a2, offsetof (
struct MHD_IPCount, count));
267 struct MHD_IPCount *key)
269 memset(key, 0,
sizeof(*key));
272 if (
sizeof (
struct sockaddr_in) == addrlen)
274 const struct sockaddr_in *addr4 = (
const struct sockaddr_in*) addr;
275 key->family = AF_INET;
276 memcpy (&key->addr.ipv4, &addr4->sin_addr,
sizeof(addr4->sin_addr));
282 if (
sizeof (
struct sockaddr_in6) == addrlen)
284 const struct sockaddr_in6 *addr6 = (
const struct sockaddr_in6*) addr;
285 key->family = AF_INET6;
286 memcpy (&key->addr.ipv6, &addr6->sin6_addr,
sizeof(addr6->sin6_addr));
307 const struct sockaddr *addr,
310 struct MHD_IPCount *key;
320 if (
NULL == (key = malloc (
sizeof(*key))))
339 "Failed to add IP connection count node\n");
349 key = (
struct MHD_IPCount *) node;
371 const struct sockaddr *addr,
374 struct MHD_IPCount search_key;
375 struct MHD_IPCount *found_key;
395 MHD_PANIC (
"Failed to find previously-added IP address\n");
397 found_key = (
struct MHD_IPCount *) *nodep;
399 if (0 == found_key->count)
401 MHD_PANIC (
"Previously-added IP address had 0 count\n");
404 if (0 == --found_key->count)
426 recv_tls_adapter (
struct MHD_Connection *connection,
void *other,
size_t i)
430 if (
MHD_YES == connection->tls_read_ready)
432 connection->
daemon->num_tls_read_ready--;
433 connection->tls_read_ready =
MHD_NO;
435 res = gnutls_record_recv (connection->tls_session, other, i);
436 if ( (GNUTLS_E_AGAIN == res) ||
437 (GNUTLS_E_INTERRUPTED == res) )
455 connection->tls_read_ready =
MHD_YES;
456 connection->
daemon->num_tls_read_ready++;
472 const void *other,
size_t i)
476 res = gnutls_record_send (connection->tls_session, other, i);
477 if ( (GNUTLS_E_AGAIN == res) ||
478 (GNUTLS_E_INTERRUPTED == res) )
506 MHD_init_daemon_certificate (
struct MHD_Daemon *daemon)
511 #if GNUTLS_VERSION_MAJOR >= 3
512 if (
NULL != daemon->cert_callback)
514 gnutls_certificate_set_retrieve_function2 (daemon->x509_cred,
515 daemon->cert_callback);
518 if (
NULL != daemon->https_mem_trust)
520 cert.data = (
unsigned char *) daemon->https_mem_trust;
521 cert.size = strlen (daemon->https_mem_trust);
522 if (gnutls_certificate_set_x509_trust_mem (daemon->x509_cred, &cert,
523 GNUTLS_X509_FMT_PEM) < 0)
527 "Bad trust certificate format\n");
533 if (
MHD_YES == daemon->have_dhparams)
535 gnutls_certificate_set_dh_params (daemon->x509_cred,
536 daemon->https_mem_dhparams);
539 if ( (
NULL != daemon->https_mem_cert) &&
540 (
NULL != daemon->https_mem_key) )
542 key.data = (
unsigned char *) daemon->https_mem_key;
543 key.size = strlen (daemon->https_mem_key);
544 cert.data = (
unsigned char *) daemon->https_mem_cert;
545 cert.size = strlen (daemon->https_mem_cert);
547 return gnutls_certificate_set_x509_key_mem (daemon->x509_cred,
549 GNUTLS_X509_FMT_PEM);
551 #if GNUTLS_VERSION_MAJOR >= 3
552 if (
NULL != daemon->cert_callback)
557 "You need to specify a certificate and key location\n");
572 switch (daemon->cred_type)
574 case GNUTLS_CRD_CERTIFICATE:
576 gnutls_certificate_allocate_credentials (&daemon->x509_cred))
577 return GNUTLS_E_MEMORY_ERROR;
578 return MHD_init_daemon_certificate (daemon);
582 "Error: invalid credentials type %d specified.\n",
605 unsigned int fd_setsize)
609 #ifdef MHD_WINSOCK_SOCKETS
610 if (set->fd_count >= fd_setsize)
612 if (FD_ISSET(fd, set))
617 #else // ! MHD_WINSOCK_SOCKETS
618 if (fd >= fd_setsize)
620 #endif // ! MHD_WINSOCK_SOCKETS
653 fd_set *write_fd_set,
654 fd_set *except_fd_set,
658 write_fd_set, except_fd_set,
686 fd_set *write_fd_set,
687 fd_set *except_fd_set,
689 unsigned int fd_setsize)
693 if ( (
NULL == daemon)
694 || (
NULL == read_fd_set)
695 || (
NULL == write_fd_set)
706 return add_to_fd_set (daemon->epoll_fd, read_fd_set, max_fd, fd_setsize);
742 "Maximum socket in select set: %d\n",
757 static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
767 unsigned int timeout;
789 if (
MHD_YES == con->tls_read_ready)
833 "Can't add FD to fd_set\n");
845 "Error during select (%d): `%s'\n",
854 || (
MHD_YES == con->tls_read_ready)
867 memset (&p, 0,
sizeof (p));
872 p[0].events |= POLLIN;
875 p[0].events |= POLLOUT;
877 p[0].events |= POLLIN;
881 p[0].events |= POLLIN;
891 (
NULL == tvp) ? -1 : tv.tv_sec * 1000) < 0)
896 MHD_DLOG (con->
daemon,
"Error during poll: `%s'\n",
901 if ( (0 != (p[0].revents & POLLIN))
903 || (
MHD_YES == con->tls_read_ready)
907 if (0 != (p[0].revents & POLLOUT))
909 if (0 != (p[0].revents & (POLLERR | POLLHUP)))
921 "Processing thread terminating, closing connection\n");
935 return (MHD_THRD_RTRN_TYPE_)0;
962 if (ret < (ssize_t) i)
1009 if (left > SSIZE_MAX)
1011 if (-1 != (ret = sendfile (connection->
socket_fd,
1026 if ( (EINTR == err) || (EAGAIN == err) || (
EWOULDBLOCK == err) )
1028 if ( (EINVAL == err) || (EBADF == err) )
1038 if (ret < (ssize_t) i)
1047 if ( (-1 == ret) && (0 == errno) )
1077 #if defined(MHD_USE_POSIX_THREADS)
1078 pthread_attr_t attr;
1079 pthread_attr_t *pattr;
1084 if (0 != (ret = pthread_attr_init (&attr)))
1088 pthread_attr_destroy (&attr);
1097 ret = pthread_create (thread, pattr,
1098 start_routine, arg);
1099 #ifdef HAVE_PTHREAD_SETNAME_NP
1100 (void) pthread_setname_np (*thread,
"libmicrohttpd");
1103 pthread_attr_destroy (&attr);
1108 "Failed to set thread stack size\n");
1112 #elif defined(MHD_USE_W32_THREADS)
1115 return (
NULL != (*thread)) ? 0 : 1;
1149 const struct sockaddr *addr,
1154 int res_thread_create;
1186 if ( (client_socket >= FD_SETSIZE) &&
1191 "Socket descriptor larger than FD_SETSIZE: %d > %d\n",
1208 "Accepted connection on socket %d\n",
1218 "Server reached connection limit (closing inbound connection)\n");
1236 "Connection rejected, closing connection\n");
1251 setsockopt (client_socket,
1252 SOL_SOCKET, SO_NOSIGPIPE,
1263 "Error allocating memory: %s\n",
1278 "Error allocating memory: %s\n",
1292 if (
NULL == (connection->
addr = malloc (addrlen)))
1297 "Error allocating memory: %s\n",
1308 memcpy (connection->
addr, addr, addrlen);
1311 connection->
daemon = daemon;
1330 #if !defined(WINDOWS) || defined(CYGWIN)
1331 int flags = fcntl (connection->
socket_fd, F_GETFL);
1332 if ( (-1 == flags) ||
1333 (0 != fcntl (connection->
socket_fd, F_SETFL, flags | O_NONBLOCK)) )
1337 "Failed to make socket non-blocking: %s\n",
1342 unsigned long flags = 1;
1343 if (0 != ioctlsocket (connection->
socket_fd, FIONBIO, &flags))
1347 "Failed to make socket non-blocking: %s\n",
1358 connection->
recv_cls = &recv_tls_adapter;
1359 connection->
send_cls = &send_tls_adapter;
1362 gnutls_init (&connection->tls_session, GNUTLS_SERVER);
1363 gnutls_priority_set (connection->tls_session,
1364 daemon->priority_cache);
1365 switch (daemon->cred_type)
1368 case GNUTLS_CRD_CERTIFICATE:
1369 gnutls_credentials_set (connection->tls_session,
1370 GNUTLS_CRD_CERTIFICATE,
1375 MHD_DLOG (connection->
daemon,
1376 "Failed to setup TLS credentials: unknown credential type %d\n",
1382 free (connection->
addr);
1390 gnutls_transport_set_ptr (connection->tls_session,
1391 (gnutls_transport_ptr_t) connection);
1392 gnutls_transport_set_pull_function (connection->tls_session,
1394 gnutls_transport_set_push_function (connection->tls_session,
1397 if (daemon->https_mem_trust)
1398 gnutls_certificate_server_set_request (connection->tls_session,
1399 GNUTLS_CERT_REQUEST);
1405 MHD_PANIC (
"Failed to acquire cleanup mutex\n");
1414 MHD_PANIC (
"Failed to release cleanup mutex\n");
1421 if (0 != res_thread_create)
1426 "Failed to create a thread: %s\n",
1433 if ( (
MHD_YES == external_add) &&
1439 "failed to signal new connection via pipe");
1447 struct epoll_event event;
1449 event.events = EPOLLIN | EPOLLOUT | EPOLLET;
1450 event.data.ptr = connection;
1451 if (0 != epoll_ctl (daemon->epoll_fd,
1459 "Call to epoll_ctl failed: %s\n",
1471 daemon->eready_tail,
1484 MHD_PANIC (
"Failed to acquire cleanup mutex\n");
1493 MHD_PANIC (
"Failed to release cleanup mutex\n");
1495 free (connection->
addr);
1536 daemon = connection->
daemon;
1538 MHD_PANIC (
"Cannot suspend connections without enabling MHD_USE_SUSPEND_RESUME!\n");
1541 MHD_PANIC (
"Failed to acquire cleanup mutex\n");
1562 daemon->eready_tail,
1568 if (0 != epoll_ctl (daemon->epoll_fd,
1572 MHD_PANIC (
"Failed to remove FD from epoll set\n");
1581 MHD_PANIC (
"Failed to release cleanup mutex\n");
1598 daemon = connection->
daemon;
1600 MHD_PANIC (
"Cannot resume connections without enabling MHD_USE_SUSPEND_RESUME!\n");
1603 MHD_PANIC (
"Failed to acquire cleanup mutex\n");
1611 "failed to signal resume via pipe");
1616 MHD_PANIC (
"Failed to release cleanup mutex\n");
1634 MHD_PANIC (
"Failed to acquire cleanup mutex\n");
1639 while (
NULL != (pos = next))
1663 MHD_PANIC (
"Resumed connection was already in EREADY set\n");
1667 daemon->eready_tail,
1679 MHD_PANIC (
"Failed to release cleanup mutex\n");
1695 unsigned long flags = 1;
1697 if (0 != ioctlsocket (sock, FIONBIO, &flags))
1701 "Failed to make socket non-blocking: %s\n",
1705 if (!GetHandleInformation ((HANDLE) sock, &dwFlags) ||
1706 ((dwFlags != (dwFlags & ~HANDLE_FLAG_INHERIT)) &&
1707 !SetHandleInformation ((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)))
1711 "Failed to make socket non-inheritable: %u\n",
1712 (
unsigned int) GetLastError ());
1719 nonblock = O_NONBLOCK;
1724 flags = fcntl (sock, F_GETFD);
1725 if ( ( (-1 == flags) ||
1726 ( (flags != (flags | FD_CLOEXEC)) &&
1727 (0 != fcntl (sock, F_SETFD, flags | nonblock | FD_CLOEXEC)) ) ) )
1731 "Failed to make socket non-inheritable: %s\n",
1771 const struct sockaddr *
addr,
1799 struct sockaddr_in6 addrstorage;
1801 struct sockaddr_in addrstorage;
1803 struct sockaddr *addr = (
struct sockaddr *) &addrstorage;
1809 addrlen =
sizeof (addrstorage);
1810 memset (addr, 0,
sizeof (addrstorage));
1813 #ifdef HAVE_SOCK_NONBLOCK
1814 nonblock = SOCK_NONBLOCK;
1823 s = accept4 (fd, addr, &addrlen,
SOCK_CLOEXEC | nonblock);
1825 s = accept (fd, addr, &addrlen);
1834 "Error accepting connection: %s\n",
1845 #if !defined(HAVE_ACCEPT4) || HAVE_ACCEPT4+0 == 0 || !defined(HAVE_SOCK_NONBLOCK) || SOCK_CLOEXEC+0 == 0
1851 "Accepted connection on socket %d\n",
1876 MHD_PANIC (
"Failed to acquire cleanup mutex\n");
1885 if (0 != MHD_join_thread_ (pos->
pid))
1887 MHD_PANIC (
"Failed to join a thread\n");
1892 if (pos->tls_session !=
NULL)
1893 gnutls_deinit (pos->tls_session);
1896 (
struct sockaddr *) pos->
addr,
1902 daemon->eready_tail,
1916 if (0 != epoll_ctl (daemon->epoll_fd,
1920 MHD_PANIC (
"Failed to remove FD from epoll set\n");
1944 MHD_PANIC (
"Failed to release cleanup mutex\n");
1966 time_t earliest_deadline;
1975 "Illegal call to MHD_get_timeout\n");
1981 if (0 != daemon->num_tls_read_ready)
1991 earliest_deadline = 0;
1996 if ( (! have_timeout) ||
2001 (0 != gnutls_record_check_pending (pos->tls_session)) )
2002 earliest_deadline = 0;
2009 if ( (
NULL != pos) &&
2012 if ( (! have_timeout) ||
2017 (0 != gnutls_record_check_pending (pos->tls_session)) )
2018 earliest_deadline = 0;
2023 if (
MHD_NO == have_timeout)
2026 if (earliest_deadline < now)
2029 *timeout = 1000 * (1 + earliest_deadline - now);
2055 const fd_set *read_fd_set,
2056 const fd_set *write_fd_set,
2057 const fd_set *except_fd_set)
2069 if (daemon->epoll_fd >= FD_SETSIZE)
2071 if (FD_ISSET (daemon->epoll_fd, read_fd_set))
2079 (FD_ISSET (ds, read_fd_set)) )
2083 (FD_ISSET (daemon->
wpipe[0], read_fd_set)) )
2090 while (
NULL != (pos = next))
2099 if ( (FD_ISSET (ds, read_fd_set))
2101 || (
MHD_YES == pos->tls_read_ready)
2107 if ( (FD_ISSET (ds, read_fd_set)) &&
2110 if (FD_ISSET (ds, write_fd_set))
2114 if ( (FD_ISSET (ds, read_fd_set)) &&
2147 struct timeval timeout;
2152 timeout.tv_usec = 0;
2188 timeout.tv_usec = 0;
2196 timeout.tv_usec = (ltimeout % 1000) * 1000;
2197 timeout.tv_sec = ltimeout / 1000;
2211 "select failed: %s\n",
2233 unsigned int num_connections;
2241 num_connections = 0;
2245 struct pollfd p[2 + num_connections];
2249 unsigned int poll_server;
2252 memset (p, 0,
sizeof (p));
2260 p[poll_server].events = POLLIN;
2261 p[poll_server].revents = 0;
2262 poll_listen = (int) poll_server;
2267 p[poll_server].fd = daemon->
wpipe[0];
2268 p[poll_server].events = POLLIN;
2269 p[poll_server].revents = 0;
2278 timeout = (ltimeout > INT_MAX) ? INT_MAX : (
int) ltimeout;
2287 p[poll_server+i].events |= POLLIN;
2290 p[poll_server+i].events |= POLLOUT;
2292 p[poll_server+i].events |= POLLIN;
2296 p[poll_server+i].events |= POLLIN;
2304 if (0 == poll_server + num_connections)
2306 if (poll (p, poll_server + num_connections, timeout) < 0)
2312 "poll failed: %s\n",
2322 while (
NULL != (pos = next))
2329 if (i >= num_connections)
2331 if (p[poll_server+i].fd != pos->
socket_fd)
2334 if (0 != (p[poll_server+i].revents & POLLIN))
2341 if (i >= num_connections)
2343 if (p[poll_server+i].fd != pos->
socket_fd)
2346 if (0 != (p[poll_server+i].revents & POLLIN))
2348 if (0 != (p[poll_server+i].revents & POLLOUT))
2354 if (0 != (p[poll_server+i].revents & POLLIN))
2364 if ( (-1 != poll_listen) &&
2365 (0 != (p[poll_listen].revents & POLLIN)) )
2380 MHD_poll_listen_socket (
struct MHD_Daemon *daemon,
2385 unsigned int poll_count;
2388 memset (&p, 0,
sizeof (p));
2394 p[poll_count].events = POLLIN;
2395 p[poll_count].revents = 0;
2396 poll_listen = poll_count;
2401 p[poll_count].fd = daemon->
wpipe[0];
2402 p[poll_count].events = POLLIN;
2403 p[poll_count].revents = 0;
2410 if (0 == poll_count)
2412 if (poll (p, poll_count, timeout) < 0)
2418 "poll failed: %s\n",
2426 if ( (-1 != poll_listen) &&
2427 (0 != (p[poll_listen].revents & POLLIN)) )
2449 return MHD_poll_all (daemon, may_block);
2451 return MHD_poll_listen_socket (daemon, may_block);
2468 #define MAX_EVENTS 128
2485 struct epoll_event events[MAX_EVENTS];
2486 struct epoll_event event;
2491 unsigned int series_length;
2494 if (-1 == daemon->epoll_fd)
2500 (
MHD_NO == daemon->listen_socket_in_epoll) )
2502 event.events = EPOLLIN;
2503 event.data.ptr = daemon;
2504 if (0 != epoll_ctl (daemon->epoll_fd,
2511 "Call to epoll_ctl failed: %s\n",
2516 daemon->listen_socket_in_epoll =
MHD_YES;
2518 if ( (
MHD_YES == daemon->listen_socket_in_epoll) &&
2523 if (0 != epoll_ctl (daemon->epoll_fd,
2527 MHD_PANIC (
"Failed to remove listen FD from epoll set\n");
2528 daemon->listen_socket_in_epoll =
MHD_NO;
2536 timeout_ms = INT_MAX;
2538 timeout_ms = (int) timeout_ll;
2550 num_events = MAX_EVENTS;
2551 while (MAX_EVENTS == num_events)
2554 num_events = epoll_wait (daemon->epoll_fd,
2555 events, MAX_EVENTS, timeout_ms);
2556 if (-1 == num_events)
2562 "Call to epoll_wait failed: %s\n",
2567 for (i=0;i<(
unsigned int) num_events;i++)
2569 if (
NULL == events[i].data.ptr)
2572 (daemon->
wpipe[0] == events[i].data.fd) )
2577 if (daemon != events[i].data.ptr)
2582 pos = events[i].data.ptr;
2583 if (0 != (events[i].events & EPOLLIN))
2591 daemon->eready_tail,
2596 if (0 != (events[i].events & EPOLLOUT))
2603 daemon->eready_tail,
2616 (series_length < 128) )
2628 while (
NULL != (pos = daemon->eready_tail))
2631 daemon->eready_tail,
2649 while (
NULL != (pos = next))
2659 while (
NULL != (pos = next))
2705 MHD_epoll (daemon,
MHD_NO);
2725 static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
2742 return (MHD_THRD_RTRN_TYPE_)0;
2792 va_start (ap, dh_cls);
2832 "Using MHD_quiesce_daemon in this mode requires MHD_USE_PIPE_FOR_SHUTDOWN\n");
2846 if (0 != epoll_ctl (daemon->
worker_pool[i].epoll_fd,
2850 MHD_PANIC (
"Failed to remove listen FD from epoll set\n");
2858 (-1 != daemon->epoll_fd) &&
2859 (
MHD_YES == daemon->listen_socket_in_epoll) )
2861 if (0 != epoll_ctl (daemon->epoll_fd,
2865 MHD_PANIC (
"Failed to remove listen FD from epoll set\n");
2866 daemon->listen_socket_in_epoll =
MHD_NO;
2895 const struct sockaddr **servaddr,
2909 const struct sockaddr **servaddr,
2915 va_start (ap, servaddr);
2932 const struct sockaddr **servaddr,
2948 daemon->
pool_size = va_arg (ap,
size_t);
2968 *servaddr = va_arg (ap,
const struct sockaddr *);
2981 "Specified thread pool size (%u) too big\n",
2990 daemon->https_mem_key = va_arg (ap,
const char *);
2994 "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
3000 daemon->https_mem_cert = va_arg (ap,
const char *);
3004 "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
3010 daemon->https_mem_trust = va_arg (ap,
const char *);
3014 "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
3019 daemon->cred_type = (gnutls_credentials_type_t) va_arg (ap,
int);
3024 const char *arg = va_arg (ap,
const char *);
3025 gnutls_datum_t dhpar;
3027 if (gnutls_dh_params_init (&daemon->https_mem_dhparams) < 0)
3031 "Error initializing DH parameters\n");
3035 dhpar.data = (
unsigned char *) arg;
3036 dhpar.size = strlen (arg);
3037 if (gnutls_dh_params_import_pkcs3 (daemon->https_mem_dhparams, &dhpar,
3038 GNUTLS_X509_FMT_PEM) < 0)
3042 "Bad Diffie-Hellman parameters format\n");
3044 gnutls_dh_params_deinit (daemon->https_mem_dhparams);
3047 daemon->have_dhparams =
MHD_YES;
3053 "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
3062 gnutls_priority_deinit (daemon->priority_cache);
3063 ret = gnutls_priority_init (&daemon->priority_cache,
3064 pstr = va_arg (ap,
const char*),
3066 if (GNUTLS_E_SUCCESS != ret)
3070 "Setting priorities to `%s' failed: %s\n",
3072 gnutls_strerror (ret));
3074 daemon->priority_cache =
NULL;
3080 #if GNUTLS_VERSION_MAJOR < 3
3083 "MHD_OPTION_HTTPS_CERT_CALLBACK requires building MHD with GnuTLS >= 3.0\n");
3088 daemon->cert_callback = va_arg (ap, gnutls_certificate_retrieve_function2 *);
3092 #ifdef DAUTH_SUPPORT
3094 daemon->digest_auth_rand_size = va_arg (ap,
size_t);
3095 daemon->digest_auth_random = va_arg (ap,
const char *);
3098 daemon->nonce_nc_size = va_arg (ap,
unsigned int);
3106 daemon->custom_error_log =
3108 daemon->custom_error_log_cls = va_arg (ap,
void *);
3111 va_arg (ap,
void *);
3119 daemon->fastopen_queue_size = va_arg (ap,
unsigned int);
3139 (
size_t) oa[i].
value,
3154 (
unsigned int) oa[i].value,
3199 (
void *) oa[i].value,
3209 (
size_t) oa[i].value,
3231 "MHD HTTPS option %d passed to MHD compiled without HTTPS support\n",
3237 "Invalid option %d! (Did you terminate the list with MHD_OPTION_END?)\n",
3258 int domain,
int type,
int protocol)
3265 fd = socket (domain, ctype, protocol);
3269 fd = socket(domain, type, protocol);
3288 setup_epoll_to_listen (
struct MHD_Daemon *daemon)
3290 struct epoll_event event;
3293 if (-1 == daemon->epoll_fd)
3297 "Call to epoll_create1 failed: %s\n",
3307 event.events = EPOLLIN;
3308 event.data.ptr = daemon;
3309 if (0 != epoll_ctl (daemon->epoll_fd,
3316 "Call to epoll_ctl failed: %s\n",
3324 event.events = EPOLLIN | EPOLLET;
3325 event.data.ptr =
NULL;
3326 event.data.fd = daemon->
wpipe[0];
3327 if (0 != epoll_ctl (daemon->epoll_fd,
3334 "Call to epoll_ctl failed: %s\n",
3340 daemon->listen_socket_in_epoll =
MHD_YES;
3374 struct sockaddr_in servaddr4;
3376 struct sockaddr_in6 servaddr6;
3378 const struct sockaddr *servaddr =
NULL;
3381 int res_thread_create;
3396 #ifndef TCP_FASTOPEN
3404 memset (daemon, 0,
sizeof (
struct MHD_Daemon));
3406 daemon->epoll_fd = -1;
3410 if (0 != (flags & MHD_USE_SSL))
3412 gnutls_priority_init (&daemon->priority_cache,
3425 daemon->
port = port;
3440 daemon->custom_error_log_cls = stderr;
3442 #ifdef HAVE_LISTEN_SHUTDOWN
3453 "Failed to create control pipe: %s\n",
3460 if ( (0 == (flags & MHD_USE_POLL)) &&
3462 (daemon->
wpipe[0] >= FD_SETSIZE) )
3466 "file descriptor for control pipe exceeds maximum value\n");
3476 #ifdef DAUTH_SUPPORT
3477 daemon->digest_auth_rand_size = 0;
3478 daemon->digest_auth_random =
NULL;
3479 daemon->nonce_nc_size = 4;
3482 if (0 != (flags & MHD_USE_SSL))
3484 daemon->cred_type = GNUTLS_CRD_CERTIFICATE;
3492 if ( (0 != (flags & MHD_USE_SSL)) &&
3493 (
NULL != daemon->priority_cache) )
3494 gnutls_priority_deinit (daemon->priority_cache);
3499 #ifdef DAUTH_SUPPORT
3500 if (daemon->nonce_nc_size > 0)
3502 if ( ( (
size_t) (daemon->nonce_nc_size * sizeof (
struct MHD_NonceNc))) /
3503 sizeof(
struct MHD_NonceNc) != daemon->nonce_nc_size)
3507 "Specified value for NC_SIZE too large\n");
3510 if (0 != (flags & MHD_USE_SSL))
3511 gnutls_priority_deinit (daemon->priority_cache);
3516 daemon->nnc = malloc (daemon->nonce_nc_size * sizeof (
struct MHD_NonceNc));
3517 if (
NULL == daemon->nnc)
3521 "Failed to allocate memory for nonce-nc map: %s\n",
3525 if (0 != (flags & MHD_USE_SSL))
3526 gnutls_priority_deinit (daemon->priority_cache);
3533 if (
MHD_YES != MHD_mutex_create_ (&daemon->nnc_lock))
3537 "MHD failed to initialize nonce-nc mutex\n");
3540 if (0 != (flags & MHD_USE_SSL))
3541 gnutls_priority_deinit (daemon->priority_cache);
3555 "MHD thread pooling only works with MHD_USE_SELECT_INTERNALLY\n");
3565 "Combining MHD_USE_THREAD_PER_CONNECTION and MHD_USE_SUSPEND_RESUME is not supported.\n");
3570 #ifdef __SYMBIAN32__
3571 if (0 != (flags & (MHD_USE_SELECT_INTERNALLY | MHD_USE_THREAD_PER_CONNECTION)))
3575 "Threaded operations are not supported on Symbian.\n");
3584 if (0 != (flags & MHD_USE_IPv6))
3586 PF_INET6, SOCK_STREAM, 0);
3589 PF_INET, SOCK_STREAM, 0);
3594 "Call to socket failed: %s\n",
3605 if (0 > setsockopt (socket_fd,
3608 (
void*)&on,
sizeof (on)))
3612 "setsockopt failed: %s\n",
3626 if (0 > setsockopt (socket_fd,
3629 (
void*)&on,
sizeof (on)))
3633 "setsockopt failed: %s\n",
3639 #ifndef SO_REUSEPORT
3644 #define SO_REUSEPORT 15
3648 if (0 > setsockopt (socket_fd,
3651 (
void*)&on,
sizeof (on)))
3655 "setsockopt failed: %s\n",
3665 "Cannot allow listening address reuse: SO_REUSEPORT not defined\n");
3678 #ifdef SO_EXCLUSIVEADDRUSE
3679 if (0 > setsockopt (socket_fd,
3681 SO_EXCLUSIVEADDRUSE,
3682 (
void*)&on,
sizeof (on)))
3686 "setsockopt failed: %s\n",
3694 "Cannot disallow listening address reuse: SO_EXCLUSIVEADDRUSE not defined\n");
3703 if (0 != (flags & MHD_USE_IPv6))
3704 addrlen =
sizeof (
struct sockaddr_in6);
3707 addrlen =
sizeof (
struct sockaddr_in);
3708 if (
NULL == servaddr)
3711 if (0 != (flags & MHD_USE_IPv6))
3713 memset (&servaddr6, 0,
sizeof (
struct sockaddr_in6));
3714 servaddr6.sin6_family = AF_INET6;
3715 servaddr6.sin6_port = htons (port);
3716 #if HAVE_SOCKADDR_IN_SIN_LEN
3717 servaddr6.sin6_len =
sizeof (
struct sockaddr_in6);
3719 servaddr = (
struct sockaddr *) &servaddr6;
3724 memset (&servaddr4, 0,
sizeof (
struct sockaddr_in));
3725 servaddr4.sin_family = AF_INET;
3726 servaddr4.sin_port = htons (port);
3727 #if HAVE_SOCKADDR_IN_SIN_LEN
3728 servaddr4.sin_len =
sizeof (
struct sockaddr_in);
3730 servaddr = (
struct sockaddr *) &servaddr4;
3735 if (0 != (flags & MHD_USE_IPv6))
3749 if (0 > setsockopt (socket_fd,
3750 IPPROTO_IPV6, IPV6_V6ONLY,
3755 "setsockopt failed: %s\n",
3762 if (-1 == bind (socket_fd, servaddr, addrlen))
3766 "Failed to bind to port %u: %s\n",
3767 (
unsigned int) port,
3775 if (0 != (flags & MHD_USE_TCP_FASTOPEN))
3777 if (0 == daemon->fastopen_queue_size)
3778 daemon->fastopen_queue_size = MHD_TCP_FASTOPEN_QUEUE_SIZE_DEFAULT;
3779 if (0 != setsockopt (socket_fd,
3780 IPPROTO_TCP, TCP_FASTOPEN,
3781 &daemon->fastopen_queue_size,
3782 sizeof (daemon->fastopen_queue_size)))
3786 "setsockopt failed: %s\n",
3795 int sk_flags = fcntl (socket_fd, F_GETFL);
3796 if (0 != fcntl (socket_fd, F_SETFL, sk_flags | O_NONBLOCK))
3800 "Failed to make listen socket non-blocking: %s\n",
3809 if (listen (socket_fd, 32) < 0)
3813 "Failed to listen for connections: %s\n",
3826 if ( (socket_fd >= FD_SETSIZE) &&
3831 "Socket descriptor larger than FD_SETSIZE: %d > %d\n",
3846 if (0 != (flags & MHD_USE_THREAD_PER_CONNECTION))
3850 "Combining MHD_USE_THREAD_PER_CONNECTION and MHD_USE_EPOLL_LINUX_ONLY is not supported.\n");
3854 if (
MHD_YES != setup_epoll_to_listen (daemon))
3858 if (0 != (flags & MHD_USE_EPOLL_LINUX_ONLY))
3862 "epoll is not supported on this platform by this build.\n");
3872 "MHD failed to initialize IP connection limit mutex\n");
3883 "MHD failed to initialize IP connection limit mutex\n");
3894 if ((0 != (flags & MHD_USE_SSL)) && (0 != MHD_TLS_init (daemon)))
3898 "Failed to initialize TLS support\n");
3908 if ( ( (0 != (flags & MHD_USE_THREAD_PER_CONNECTION)) ||
3912 (0 != (res_thread_create =
3917 "Failed to create listen thread: %s\n",
3930 #if !defined(WINDOWS) || defined(CYGWIN)
3933 unsigned long sk_flags;
3949 #if !defined(WINDOWS) || defined(CYGWIN)
3950 sk_flags = fcntl (socket_fd, F_GETFL);
3953 if (0 != fcntl (socket_fd, F_SETFL, sk_flags | O_NONBLOCK))
3957 if (SOCKET_ERROR == ioctlsocket (socket_fd, FIONBIO, &sk_flags))
3973 memcpy (d, daemon,
sizeof (
struct MHD_Daemon));
3981 if ( (MHD_USE_SUSPEND_RESUME == (flags & MHD_USE_SUSPEND_RESUME)) &&
3986 "Failed to create worker control pipe: %s\n",
3992 if ( (0 == (flags & MHD_USE_POLL)) &&
3993 (MHD_USE_SUSPEND_RESUME == (flags & MHD_USE_SUSPEND_RESUME)) &&
3994 (d->
wpipe[0] >= FD_SETSIZE) )
3998 "file descriptor for worker control pipe exceeds maximum value\n");
4012 if (i < leftover_conns)
4015 if ( (0 != (daemon->
options & MHD_USE_EPOLL_LINUX_ONLY)) &&
4016 (
MHD_YES != setup_epoll_to_listen (d)) )
4024 "MHD failed to initialize cleanup connection mutex for thread worker %d\n", i);
4030 if (0 != (res_thread_create =
4035 "Failed to create pool thread: %s\n",
4076 if (-1 != daemon->epoll_fd)
4077 close (daemon->epoll_fd);
4079 #ifdef DAUTH_SUPPORT
4081 (void) MHD_mutex_destroy_ (&daemon->nnc_lock);
4084 if (0 != (flags & MHD_USE_SSL))
4085 gnutls_priority_deinit (daemon->priority_cache);
4139 MHD_PANIC (
"Failed to acquire cleanup mutex\n");
4145 MHD_PANIC (
"Failed to release cleanup mutex\n");
4152 if (0 != MHD_join_thread_ (pos->
pid))
4153 MHD_PANIC (
"Failed to join a thread\n");
4174 struct epoll_event event;
4181 event.events = EPOLLOUT;
4182 event.data.ptr =
NULL;
4183 if (0 != epoll_ctl (daemon->epoll_fd,
4187 MHD_PANIC (
"Failed to add wpipe to epoll set to signal termination\n");
4228 MHD_PANIC (
"failed to signal shutdown via pipe");
4230 #ifdef HAVE_LISTEN_SHUTDOWN
4235 (void) shutdown (fd, SHUT_RDWR);
4240 (-1 != daemon->epoll_fd) &&
4242 epoll_shutdown (daemon);
4248 "MHD listen socket shutdown\n");
4262 MHD_PANIC (
"failed to signal shutdown via pipe");
4265 MHD_PANIC (
"Failed to join a thread\n");
4293 if (0 != MHD_join_thread_ (daemon->
pid))
4295 MHD_PANIC (
"Failed to join a thread\n");
4306 if (
MHD_YES == daemon->have_dhparams)
4308 gnutls_dh_params_deinit (daemon->https_mem_dhparams);
4309 daemon->have_dhparams =
MHD_NO;
4313 gnutls_priority_deinit (daemon->priority_cache);
4314 if (daemon->x509_cred)
4315 gnutls_certificate_free_credentials (daemon->x509_cred);
4320 (-1 != daemon->epoll_fd) &&
4325 #ifdef DAUTH_SUPPORT
4327 (void) MHD_mutex_destroy_ (&daemon->nnc_lock);
4425 #ifdef PACKAGE_VERSION
4426 return PACKAGE_VERSION;
4428 static char ver[12] =
"\0\0\0\0\0\0\0\0\0\0\0";
4435 if (0 >= res ||
sizeof(ver) <= res)
4472 #if HTTPS_SUPPORT && GNUTLS_VERSION_MAJOR >= 3
4484 #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
4502 #ifdef HAVE_LISTEN_SHUTDOWN
4508 #ifdef MHD_DONT_USE_PIPES
4532 #if HAVE_POSTPROCESSOR
4542 #if HTTPS_SUPPORT && GCRYPT_VERSION_NUMBER < 0x010600
4543 #if defined(MHD_USE_POSIX_THREADS)
4544 GCRY_THREAD_OPTION_PTHREAD_IMPL;
4545 #elif defined(MHD_W32_MUTEX_)
4546 static int gcry_w32_mutex_init (
void **ppmtx)
4548 *ppmtx = malloc (
sizeof (MHD_mutex_));
4553 if (
MHD_YES != MHD_mutex_create_ ((MHD_mutex_*)*ppmtx))
4562 static int gcry_w32_mutex_destroy (
void **ppmtx)
4563 {
int res = (
MHD_YES == MHD_mutex_destroy_ ((MHD_mutex_*)*ppmtx)) ? 0 : 1;
4564 free (*ppmtx);
return res; }
4565 static int gcry_w32_mutex_lock (
void **ppmtx)
4566 {
return (
MHD_YES == MHD_mutex_lock_ ((MHD_mutex_*)*ppmtx)) ? 0 : 1; }
4567 static int gcry_w32_mutex_unlock (
void **ppmtx)
4568 {
return (
MHD_YES == MHD_mutex_unlock_ ((MHD_mutex_*)*ppmtx)) ? 0 : 1; }
4570 static struct gcry_thread_cbs gcry_threads_w32 = {
4571 (GCRY_THREAD_OPTION_USER | (GCRY_THREAD_OPTION_VERSION << 8)),
4572 NULL, gcry_w32_mutex_init, gcry_w32_mutex_destroy,
4573 gcry_w32_mutex_lock, gcry_w32_mutex_unlock,
4576 #endif // defined(MHD_W32_MUTEX_)
4577 #endif // HTTPS_SUPPORT && GCRYPT_VERSION_NUMBER < 0x010600
4590 if (0 != WSAStartup(MAKEWORD(2, 2), &wsd))
4591 MHD_PANIC (
"Failed to initialize winsock\n");
4592 mhd_winsock_inited_ = 1;
4593 if (2 != LOBYTE(wsd.wVersion) && 2 != HIBYTE(wsd.wVersion))
4594 MHD_PANIC (
"Winsock version 2.2 is not available\n");
4597 #if GCRYPT_VERSION_NUMBER < 0x010600
4598 #if defined(MHD_USE_POSIX_THREADS)
4599 if (0 != gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread))
4600 MHD_PANIC (
"Failed to initialise multithreading in libgcrypt\n");
4601 #elif defined(MHD_W32_MUTEX_)
4602 if (0 != gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_w32))
4603 MHD_PANIC (
"Failed to initialise multithreading in libgcrypt\n");
4604 #endif // defined(MHD_W32_MUTEX_)
4605 gcry_check_version (
NULL);
4607 if (
NULL == gcry_check_version (
"1.6.0"))
4608 MHD_PANIC (
"libgcrypt is too old. MHD was compiled for libgcrypt 1.6.0 or newer\n");
4610 gnutls_global_init ();
4618 gnutls_global_deinit ();
4621 if (mhd_winsock_inited_)
unsigned int per_ip_connection_limit
void * unescape_callback_cls
#define XDLL_insert(head, tail, element)
_MHD_EXTERN struct MHD_Daemon * MHD_start_daemon_va(unsigned int flags, uint16_t port, MHD_AcceptPolicyCallback apc, void *apc_cls, MHD_AccessHandlerCallback dh, void *dh_cls, va_list ap)
static int parse_options(struct MHD_Daemon *daemon, const struct sockaddr **servaddr,...)
_MHD_EXTERN const char * MHD_get_version(void)
static int MHD_ip_limit_add(struct MHD_Daemon *daemon, const struct sockaddr *addr, socklen_t addrlen)
enum MHD_CONNECTION_STATE state
uint64_t response_write_position
#define EDLL_remove(head, tail, element)
void MHD_pool_destroy(struct MemoryPool *pool)
enum MHD_ConnectionEventLoopInfo event_loop_info
#define MHD_DEFAULT_FD_SETSIZE
#define DLL_remove(head, tail, element)
Methods for managing connections.
_MHD_EXTERN int MHD_get_timeout(struct MHD_Daemon *daemon, MHD_UNSIGNED_LONG_LONG *timeout)
static int MHD_ip_addr_to_key(const struct sockaddr *addr, socklen_t addrlen, struct MHD_IPCount *key)
static void MHD_cleanup_connections(struct MHD_Daemon *daemon)
_MHD_EXTERN int MHD_add_connection(struct MHD_Daemon *daemon, MHD_socket client_socket, const struct sockaddr *addr, socklen_t addrlen)
static ssize_t send_param_adapter(struct MHD_Connection *connection, const void *other, size_t i)
struct MHD_Response * response
struct MHD_Connection * normal_timeout_tail
static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_ MHD_handle_connection(void *data)
void *(* LogCallback)(void *cls, const char *uri, struct MHD_Connection *con)
MHD_AccessHandlerCallback default_handler
_MHD_EXTERN struct MHD_Daemon * MHD_start_daemon(unsigned int flags, uint16_t port, MHD_AcceptPolicyCallback apc, void *apc_cls, MHD_AccessHandlerCallback dh, void *dh_cls,...)
#define MHD_MAX_CONNECTIONS_DEFAULT
static ssize_t recv_param_adapter(struct MHD_Connection *connection, void *other, size_t i)
Methods for managing response objects.
_MHD_EXTERN void MHD_set_panic_func(MHD_PanicCallback cb, void *cls)
#define MHD_UNSIGNED_LONG_LONG
void * uri_log_callback_cls
void(* MHD_PanicCallback)(void *cls, const char *file, unsigned int line, const char *reason)
void(* MHD_LogCallback)(void *cls, const char *fm, va_list ap)
struct MHD_Daemon * daemon
int(* idle_handler)(struct MHD_Connection *connection)
int listening_address_reuse
MHD_mutex_ per_ip_connection_mutex
MHD_THRD_RTRN_TYPE_(MHD_THRD_CALL_SPEC_ * ThreadStartRoutine)(void *cls)
struct MHD_Connection * manual_timeout_head
struct MHD_Connection * cleanup_head
struct MHD_Connection * cleanup_tail
static void close_connection(struct MHD_Connection *pos)
size_t write_buffer_send_offset
struct MHD_Daemon * worker_pool
static void mhd_panic_std(void *cls, const char *file, unsigned int line, const char *reason)
static void MHD_ip_limit_del(struct MHD_Daemon *daemon, const struct sockaddr *addr, socklen_t addrlen)
_MHD_EXTERN void MHD_stop_daemon(struct MHD_Daemon *daemon)
struct MHD_Connection * nextX
static void MHD_ip_count_unlock(struct MHD_Daemon *daemon)
struct MHD_Connection * manual_timeout_tail
void MHD_suspend_connection(struct MHD_Connection *connection)
void MHD_resume_connection(struct MHD_Connection *connection)
#define MHD_INVALID_SOCKET
internal shared structures
void MHD_set_https_callbacks(struct MHD_Connection *connection)
static int MHD_select(struct MHD_Daemon *daemon, int may_block)
unsigned int connection_limit
unsigned int worker_pool_size
time_t MHD_monotonic_time(void)
static void resume_suspended_connections(struct MHD_Daemon *daemon)
_MHD_EXTERN int MHD_run_from_select(struct MHD_Daemon *daemon, const fd_set *read_fd_set, const fd_set *write_fd_set, const fd_set *except_fd_set)
LogCallback uri_log_callback
_MHD_EXTERN void MHD_destroy_response(struct MHD_Response *response)
static void cleanup(struct Proxy *proxy)
void(* VfprintfFunctionPointerType)(void *cls, const char *format, va_list va)
Methods for managing connections.
static void MHD_ip_count_lock(struct MHD_Daemon *daemon)
static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_ MHD_select_thread(void *cls)
int(* read_handler)(struct MHD_Connection *connection)
struct MHD_Connection * normal_timeout_head
void * tdelete(const void *__restrict vkey, void **__restrict vrootp, int(*compar)(const void *, const void *))
_SET_INIT_AND_DEINIT_FUNCS(MHD_init, MHD_fini)
static void make_nonblocking_noninheritable(struct MHD_Daemon *daemon, MHD_socket sock)
UnescapeCallback unescape_callback
static int MHD_ip_addr_compare(const void *a1, const void *a2)
int(* write_handler)(struct MHD_Connection *connection)
static struct MHD_Daemon * MHD_get_master(struct MHD_Daemon *daemon)
static int add_to_fd_set(MHD_socket fd, fd_set *set, MHD_socket *max_fd, unsigned int fd_setsize)
static MHD_socket create_socket(struct MHD_Daemon *daemon, int domain, int type, int protocol)
struct MHD_Connection * connections_head
struct MHD_Daemon * master
struct MHD_Connection * next
static int MHD_poll(struct MHD_Daemon *daemon, int may_block)
static int parse_options_va(struct MHD_Daemon *daemon, const struct sockaddr **servaddr, va_list ap)
MHD_AcceptPolicyCallback apc
unsigned int connection_timeout
int(* MHD_AccessHandlerCallback)(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls)
_MHD_EXTERN int MHD_get_fdset(struct MHD_Daemon *daemon, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *except_fd_set, MHD_socket *max_fd)
static int create_thread(MHD_thread_handle_ *thread, const struct MHD_Daemon *daemon, ThreadStartRoutine start_routine, void *arg)
void(* MHD_RequestCompletedCallback)(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe)
size_t write_buffer_append_offset
MHD_RequestCompletedCallback notify_completed
struct MHD_Connection * prevX
void MHD_set_http_callbacks_(struct MHD_Connection *connection)
#define MHD_POOL_SIZE_DEFAULT
static void close_all_connections(struct MHD_Daemon *daemon)
void * notify_completed_cls
struct MemoryPool * MHD_pool_create(size_t max)
TransmitCallback send_cls
_MHD_EXTERN int MHD_run(struct MHD_Daemon *daemon)
#define XDLL_remove(head, tail, element)
#define DLL_insert(head, tail, element)
size_t(* UnescapeCallback)(void *cls, struct MHD_Connection *conn, char *uri)
void * tfind(void *vkey, void *const *vrootp, int *compar) const
static int internal_add_connection(struct MHD_Daemon *daemon, MHD_socket client_socket, const struct sockaddr *addr, socklen_t addrlen, int external_add)
static size_t unescape_wrapper(void *cls, struct MHD_Connection *connection, char *val)
struct MHD_Connection * suspended_connections_tail
MHD_PanicCallback mhd_panic
void * per_ip_connection_count
_MHD_EXTERN int MHD_is_feature_supported(enum MHD_FEATURE feature)
size_t read_buffer_offset
_MHD_EXTERN int MHD_get_fdset2(struct MHD_Daemon *daemon, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *except_fd_set, MHD_socket *max_fd, unsigned int fd_setsize)
void * default_handler_cls
unsigned int connection_timeout
static int MHD_accept_connection(struct MHD_Daemon *daemon)
MHD_mutex_ cleanup_connection_mutex
_MHD_EXTERN MHD_socket MHD_quiesce_daemon(struct MHD_Daemon *daemon)
int(* MHD_AcceptPolicyCallback)(void *cls, const struct sockaddr *addr, socklen_t addrlen)
_MHD_EXTERN const union MHD_DaemonInfo * MHD_get_daemon_info(struct MHD_Daemon *daemon, enum MHD_DaemonInfoType info_type,...)
_MHD_EXTERN size_t MHD_http_unescape(char *val)
struct MHD_Connection * connections_tail
#define EDLL_insert(head, tail, element)
void MHD_connection_close(struct MHD_Connection *connection, enum MHD_RequestTerminationCode termination_code)
void * tsearch(void *vkey, void **vrootp, int *compar) const
struct MHD_Connection * suspended_connections_head
memory pool; mostly used for efficient (de)allocation for each connection and bounding memory use for...