00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00027 #include "platform.h"
00028 #include "internal.h"
00029 #include "response.h"
00030 #include "connection.h"
00031 #include "memorypool.h"
00032
00033 #if HTTPS_SUPPORT
00034 #include "connection_https.h"
00035 #include <gnutls/gnutls.h>
00036 #include <gcrypt.h>
00037 #endif
00038
00039 #ifdef HAVE_POLL_H
00040 #include <poll.h>
00041 #endif
00042
00043 #ifdef LINUX
00044 #include <sys/sendfile.h>
00045 #endif
00046
00050 #ifndef WINDOWS
00051 #define MHD_MAX_CONNECTIONS_DEFAULT FD_SETSIZE -4
00052 #else
00053 #define MHD_MAX_CONNECTIONS_DEFAULT FD_SETSIZE
00054 #endif
00055
00059 #define MHD_POOL_SIZE_DEFAULT (32 * 1024)
00060
00065 #define DEBUG_CLOSE MHD_NO
00066
00071 #define DEBUG_CONNECT MHD_NO
00072
00073 #ifndef LINUX
00074 #ifndef MSG_NOSIGNAL
00075 #define MSG_NOSIGNAL 0
00076 #endif
00077 #ifndef MSG_DONTWAIT
00078 #define MSG_DONTWAIT 0
00079 #endif
00080 #endif
00081
00082 #ifdef __SYMBIAN32__
00083 static void pthread_kill (int, int) {
00084
00085
00086 abort();
00087 }
00088 #endif // __SYMBIAN32__
00089
00093 static void
00094 mhd_panic_std(void *cls,
00095 const char *file,
00096 unsigned int line,
00097 const char *reason)
00098 {
00099 abort ();
00100 }
00101
00102
00106 MHD_PanicCallback mhd_panic;
00107
00111 void *mhd_panic_cls;
00112
00113
00121 static struct MHD_Daemon*
00122 MHD_get_master (struct MHD_Daemon *daemon)
00123 {
00124 while (NULL != daemon->master)
00125 daemon = daemon->master;
00126 return daemon;
00127 }
00128
00132 struct MHD_IPCount
00133 {
00137 int family;
00138
00142 union
00143 {
00147 struct in_addr ipv4;
00148 #if HAVE_IPV6
00149
00152 struct in6_addr ipv6;
00153 #endif
00154 } addr;
00155
00159 unsigned int count;
00160 };
00161
00167 static void
00168 MHD_ip_count_lock(struct MHD_Daemon *daemon)
00169 {
00170 if (0 != pthread_mutex_lock(&daemon->per_ip_connection_mutex))
00171 {
00172 #if HAVE_MESSAGES
00173 MHD_DLOG (daemon, "Failed to acquire IP connection limit mutex\n");
00174 #endif
00175 abort();
00176 }
00177 }
00178
00184 static void
00185 MHD_ip_count_unlock(struct MHD_Daemon *daemon)
00186 {
00187 if (0 != pthread_mutex_unlock(&daemon->per_ip_connection_mutex))
00188 {
00189 #if HAVE_MESSAGES
00190 MHD_DLOG (daemon, "Failed to release IP connection limit mutex\n");
00191 #endif
00192 abort();
00193 }
00194 }
00195
00205 static int
00206 MHD_ip_addr_compare(const void *a1, const void *a2)
00207 {
00208 return memcmp (a1, a2, offsetof(struct MHD_IPCount, count));
00209 }
00210
00219 static int
00220 MHD_ip_addr_to_key(const struct sockaddr *addr, socklen_t addrlen,
00221 struct MHD_IPCount *key)
00222 {
00223 memset(key, 0, sizeof(*key));
00224
00225
00226 if (addrlen == sizeof(struct sockaddr_in))
00227 {
00228 const struct sockaddr_in *addr4 = (const struct sockaddr_in*)addr;
00229 key->family = AF_INET;
00230 memcpy (&key->addr.ipv4, &addr4->sin_addr, sizeof(addr4->sin_addr));
00231 return MHD_YES;
00232 }
00233
00234 #if HAVE_IPV6
00235
00236 if (addrlen == sizeof (struct sockaddr_in6))
00237 {
00238 const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)addr;
00239 key->family = AF_INET6;
00240 memcpy (&key->addr.ipv6, &addr6->sin6_addr, sizeof(addr6->sin6_addr));
00241 return MHD_YES;
00242 }
00243 #endif
00244
00245
00246 return MHD_NO;
00247 }
00248
00258 static int
00259 MHD_ip_limit_add(struct MHD_Daemon *daemon,
00260 const struct sockaddr *addr,
00261 socklen_t addrlen)
00262 {
00263 struct MHD_IPCount *key;
00264 void *node;
00265 int result;
00266
00267 daemon = MHD_get_master (daemon);
00268
00269
00270 if (daemon->per_ip_connection_limit == 0)
00271 return MHD_YES;
00272
00273 key = malloc (sizeof(*key));
00274 if (NULL == key)
00275 return MHD_NO;
00276
00277
00278 if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, key))
00279 {
00280
00281 free (key);
00282 return MHD_YES;
00283 }
00284
00285 MHD_ip_count_lock (daemon);
00286
00287
00288 node = (void*)TSEARCH (key, &daemon->per_ip_connection_count, MHD_ip_addr_compare);
00289 if (!node)
00290 {
00291 #if HAVE_MESSAGES
00292 MHD_DLOG(daemon,
00293 "Failed to add IP connection count node\n");
00294 #endif
00295 MHD_ip_count_unlock (daemon);
00296 free (key);
00297 return MHD_NO;
00298 }
00299 node = *(void**)node;
00300
00301
00302 if (node != key)
00303 free(key);
00304 key = (struct MHD_IPCount*)node;
00305
00306
00307
00308 result = (key->count < daemon->per_ip_connection_limit);
00309 if (result == MHD_YES)
00310 ++key->count;
00311
00312 MHD_ip_count_unlock (daemon);
00313 return result;
00314 }
00315
00324 static void
00325 MHD_ip_limit_del(struct MHD_Daemon *daemon,
00326 const struct sockaddr *addr,
00327 socklen_t addrlen)
00328 {
00329 struct MHD_IPCount search_key;
00330 struct MHD_IPCount *found_key;
00331 void *node;
00332
00333 daemon = MHD_get_master (daemon);
00334
00335
00336 if (daemon->per_ip_connection_limit == 0)
00337 return;
00338
00339
00340 if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, &search_key))
00341 return;
00342
00343 MHD_ip_count_lock (daemon);
00344
00345
00346 node = (void*)TFIND (&search_key, &daemon->per_ip_connection_count, MHD_ip_addr_compare);
00347
00348
00349
00350 if (!node)
00351 {
00352 #if HAVE_MESSAGES
00353 MHD_DLOG (daemon,
00354 "Failed to find previously-added IP address\n");
00355 #endif
00356 abort();
00357 }
00358 found_key = (struct MHD_IPCount*)*(void**)node;
00359
00360
00361 if (found_key->count == 0)
00362 {
00363 #if HAVE_MESSAGES
00364 MHD_DLOG (daemon,
00365 "Previously-added IP address had 0 count\n");
00366 #endif
00367 abort();
00368 }
00369
00370
00371 if (--found_key->count == 0)
00372 {
00373 TDELETE (found_key, &daemon->per_ip_connection_count, MHD_ip_addr_compare);
00374 free (found_key);
00375 }
00376
00377 MHD_ip_count_unlock (daemon);
00378 }
00379
00380 #if HTTPS_SUPPORT
00381 static pthread_mutex_t MHD_gnutls_init_mutex;
00382
00391 static ssize_t
00392 recv_tls_adapter (struct MHD_Connection *connection, void *other, size_t i)
00393 {
00394 int res;
00395 res = gnutls_record_recv (connection->tls_session, other, i);
00396 if ( (res == GNUTLS_E_AGAIN) ||
00397 (res == GNUTLS_E_INTERRUPTED) )
00398 {
00399 errno = EINTR;
00400 return -1;
00401 }
00402 return res;
00403 }
00404
00405
00414 static ssize_t
00415 send_tls_adapter (struct MHD_Connection *connection,
00416 const void *other, size_t i)
00417 {
00418 int res;
00419 res = gnutls_record_send (connection->tls_session, other, i);
00420 if ( (res == GNUTLS_E_AGAIN) ||
00421 (res == GNUTLS_E_INTERRUPTED) )
00422 {
00423 errno = EINTR;
00424 return -1;
00425 }
00426 return res;
00427 }
00428
00429
00436 static int
00437 MHD_init_daemon_certificate (struct MHD_Daemon *daemon)
00438 {
00439 gnutls_datum_t key;
00440 gnutls_datum_t cert;
00441
00442
00443 if (daemon->https_mem_cert && daemon->https_mem_key)
00444 {
00445 key.data = (unsigned char *) daemon->https_mem_key;
00446 key.size = strlen (daemon->https_mem_key);
00447 cert.data = (unsigned char *) daemon->https_mem_cert;
00448 cert.size = strlen (daemon->https_mem_cert);
00449
00450 return gnutls_certificate_set_x509_key_mem (daemon->x509_cred,
00451 &cert, &key,
00452 GNUTLS_X509_FMT_PEM);
00453 }
00454 #if HAVE_MESSAGES
00455 MHD_DLOG (daemon, "You need to specify a certificate and key location\n");
00456 #endif
00457 return -1;
00458 }
00459
00466 static int
00467 MHD_TLS_init (struct MHD_Daemon *daemon)
00468 {
00469 switch (daemon->cred_type)
00470 {
00471 case GNUTLS_CRD_CERTIFICATE:
00472 if (0 !=
00473 gnutls_certificate_allocate_credentials (&daemon->x509_cred))
00474 return GNUTLS_E_MEMORY_ERROR;
00475 return MHD_init_daemon_certificate (daemon);
00476 default:
00477 #if HAVE_MESSAGES
00478 MHD_DLOG (daemon,
00479 "Error: invalid credentials type %d specified.\n",
00480 daemon->cred_type);
00481 #endif
00482 return -1;
00483 }
00484 }
00485 #endif
00486
00500 int
00501 MHD_get_fdset (struct MHD_Daemon *daemon,
00502 fd_set * read_fd_set,
00503 fd_set * write_fd_set, fd_set * except_fd_set, int *max_fd)
00504 {
00505 struct MHD_Connection *con_itr;
00506 int fd;
00507
00508 if ((daemon == NULL) || (read_fd_set == NULL) || (write_fd_set == NULL)
00509 || (except_fd_set == NULL) || (max_fd == NULL)
00510 || (-1 == (fd = daemon->socket_fd)) || (daemon->shutdown == MHD_YES)
00511 || ((daemon->options & MHD_USE_THREAD_PER_CONNECTION) != 0)
00512 || ((daemon->options & MHD_USE_POLL) != 0))
00513 return MHD_NO;
00514
00515 FD_SET (fd, read_fd_set);
00516
00517 if ((*max_fd) < fd)
00518 *max_fd = fd;
00519
00520 con_itr = daemon->connections;
00521 while (con_itr != NULL)
00522 {
00523 if (MHD_YES != MHD_connection_get_fdset (con_itr,
00524 read_fd_set,
00525 write_fd_set,
00526 except_fd_set, max_fd))
00527 return MHD_NO;
00528 con_itr = con_itr->next;
00529 }
00530 #if DEBUG_CONNECT
00531 MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd);
00532 #endif
00533 return MHD_YES;
00534 }
00535
00543 static void *
00544 MHD_handle_connection (void *data)
00545 {
00546 struct MHD_Connection *con = data;
00547 int num_ready;
00548 fd_set rs;
00549 fd_set ws;
00550 fd_set es;
00551 int max;
00552 struct timeval tv;
00553 unsigned int timeout;
00554 #ifdef HAVE_POLL_H
00555 struct MHD_Pollfd mp;
00556 struct pollfd p;
00557 #endif
00558
00559 timeout = con->daemon->connection_timeout;
00560 while ((!con->daemon->shutdown) && (con->socket_fd != -1)) {
00561 tv.tv_usec = 0;
00562 if ( (timeout > (time (NULL) - con->last_activity)) ||
00563 (timeout == 0) )
00564 {
00565
00566
00567 tv.tv_sec = 1;
00568 if ((con->state == MHD_CONNECTION_NORMAL_BODY_UNREADY) ||
00569 (con->state == MHD_CONNECTION_CHUNKED_BODY_UNREADY))
00570 {
00571
00572 tv.tv_sec = 0;
00573 }
00574 }
00575 else
00576 {
00577 tv.tv_sec = 0;
00578 }
00579 #ifdef HAVE_POLL_H
00580 if (0 == (con->daemon->options & MHD_USE_POLL)) {
00581 #else
00582 {
00583 #endif
00584
00585 FD_ZERO (&rs);
00586 FD_ZERO (&ws);
00587 FD_ZERO (&es);
00588 max = 0;
00589 MHD_connection_get_fdset (con, &rs, &ws, &es, &max);
00590 num_ready = SELECT (max + 1, &rs, &ws, &es, &tv);
00591 if (num_ready < 0) {
00592 if (errno == EINTR)
00593 continue;
00594 #if HAVE_MESSAGES
00595 MHD_DLOG (con->daemon, "Error during select (%d): `%s'\n", max,
00596 STRERROR (errno));
00597 #endif
00598 break;
00599 }
00600
00601 if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &rs)))
00602 con->read_handler (con);
00603 if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &ws)))
00604 con->write_handler (con);
00605 if (con->socket_fd != -1)
00606 con->idle_handler (con);
00607 }
00608 #ifdef HAVE_POLL_H
00609 else
00610 {
00611
00612 memset(&mp, 0, sizeof (struct MHD_Pollfd));
00613 MHD_connection_get_pollfd(con, &mp);
00614 memset(&p, 0, sizeof (struct pollfd));
00615 p.fd = mp.fd;
00616 if (mp.events & MHD_POLL_ACTION_IN)
00617 p.events |= POLLIN;
00618 if (mp.events & MHD_POLL_ACTION_OUT)
00619 p.events |= POLLOUT;
00620
00621
00622 if (poll (&p, 1, 1000) < 0) {
00623 if (errno == EINTR)
00624 continue;
00625 #if HAVE_MESSAGES
00626 MHD_DLOG (con->daemon, "Error during poll: `%s'\n",
00627 STRERROR (errno));
00628 #endif
00629 break;
00630 }
00631 if ( (con->socket_fd != -1) &&
00632 (0 != (p.revents & POLLIN)) )
00633 con->read_handler (con);
00634 if ( (con->socket_fd != -1) &&
00635 (0 != (p.revents & POLLOUT)) )
00636 con->write_handler (con);
00637 if (con->socket_fd != -1)
00638 con->idle_handler (con);
00639 if ( (con->socket_fd != -1) &&
00640 (0 != (p.revents & (POLLERR | POLLHUP))) )
00641 MHD_connection_close (con, MHD_REQUEST_TERMINATED_WITH_ERROR);
00642 }
00643 #endif
00644 }
00645 if (con->socket_fd != -1)
00646 {
00647 #if DEBUG_CLOSE
00648 #if HAVE_MESSAGES
00649 MHD_DLOG (con->daemon,
00650 "Processing thread terminating, closing connection\n");
00651 #endif
00652 #endif
00653 MHD_connection_close (con, MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
00654 }
00655 return NULL;
00656 }
00657
00666 static ssize_t
00667 recv_param_adapter (struct MHD_Connection *connection, void *other, size_t i)
00668 {
00669 if (connection->socket_fd == -1)
00670 return -1;
00671 if (0 != (connection->daemon->options & MHD_USE_SSL))
00672 return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL);
00673 return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL | MSG_DONTWAIT);
00674 }
00675
00684 static ssize_t
00685 send_param_adapter (struct MHD_Connection *connection,
00686 const void *other, size_t i)
00687 {
00688 #if LINUX
00689 int fd;
00690 off_t offset;
00691 int ret;
00692 #endif
00693 if (connection->socket_fd == -1)
00694 return -1;
00695 if (0 != (connection->daemon->options & MHD_USE_SSL))
00696 return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL);
00697 #if LINUX
00698 if ( (connection->write_buffer_append_offset ==
00699 connection->write_buffer_send_offset) &&
00700 (NULL != connection->response) &&
00701 (-1 != (fd = connection->response->fd)) )
00702 {
00703
00704 offset = (off_t) connection->response_write_position;
00705 ret = sendfile (connection->socket_fd,
00706 fd,
00707 &offset,
00708 connection->response->total_size - offset);
00709 if ( (ret == -1) &&
00710 (errno == EINTR) )
00711 return 0;
00712 return ret;
00713 }
00714 #endif
00715 return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL | MSG_DONTWAIT);
00716 }
00717
00718
00719 #if HTTPS_SUPPORT
00720
00724 static void
00725 socket_set_nonblocking (int fd)
00726 {
00727 #if MINGW
00728 u_long mode;
00729 mode = 1;
00730 if (ioctlsocket (fd, FIONBIO, &mode) == SOCKET_ERROR)
00731 {
00732 SetErrnoFromWinsockError (WSAGetLastError ());
00733 #if HAVE_MESSAGES
00734 FPRINTF(stderr, "Failed to make socket non-blocking: %s\n",
00735 STRERROR (errno));
00736 #endif
00737 }
00738 #else
00739
00740
00741 int flags = fcntl (fd, F_GETFL);
00742 if ( (flags == -1) ||
00743 (0 != fcntl (fd, F_SETFL, flags | O_NONBLOCK)) )
00744 {
00745 #if HAVE_MESSAGES
00746 FPRINTF(stderr, "Failed to make socket non-blocking: %s\n",
00747 STRERROR (errno));
00748 #endif
00749 }
00750 #endif
00751 }
00752 #endif
00753
00754
00763 static int
00764 MHD_accept_connection (struct MHD_Daemon *daemon)
00765 {
00766 struct MHD_Connection *connection;
00767 #if HAVE_INET6
00768 struct sockaddr_in6 addrstorage;
00769 #else
00770 struct sockaddr_in addrstorage;
00771 #endif
00772 struct sockaddr *addr = (struct sockaddr *) &addrstorage;
00773 socklen_t addrlen;
00774 int s;
00775 int res_thread_create;
00776 #if OSX
00777 static int on = 1;
00778 #endif
00779
00780 addrlen = sizeof (addrstorage);
00781 memset (addr, 0, sizeof (addrstorage));
00782
00783 s = ACCEPT (daemon->socket_fd, addr, &addrlen);
00784 if ((s == -1) || (addrlen <= 0))
00785 {
00786 #if HAVE_MESSAGES
00787
00788 if ((EAGAIN != errno) && (EWOULDBLOCK != errno))
00789 MHD_DLOG (daemon, "Error accepting connection: %s\n", STRERROR (errno));
00790 #endif
00791 if (s != -1)
00792 {
00793 SHUTDOWN (s, SHUT_RDWR);
00794 CLOSE (s);
00795
00796 }
00797 return MHD_NO;
00798 }
00799 #ifndef WINDOWS
00800 if ( (s >= FD_SETSIZE) &&
00801 (0 == (daemon->options & MHD_USE_POLL)) )
00802 {
00803 #if HAVE_MESSAGES
00804 MHD_DLOG (daemon,
00805 "Socket descriptor larger than FD_SETSIZE: %d > %d\n",
00806 s,
00807 FD_SETSIZE);
00808 #endif
00809 CLOSE (s);
00810 return MHD_NO;
00811 }
00812 #endif
00813
00814
00815 #if HAVE_MESSAGES
00816 #if DEBUG_CONNECT
00817 MHD_DLOG (daemon, "Accepted connection on socket %d\n", s);
00818 #endif
00819 #endif
00820 if ((daemon->max_connections == 0)
00821 || (MHD_ip_limit_add (daemon, addr, addrlen) == MHD_NO))
00822 {
00823
00824 #if HAVE_MESSAGES
00825 MHD_DLOG (daemon,
00826 "Server reached connection limit (closing inbound connection)\n");
00827 #endif
00828 SHUTDOWN (s, SHUT_RDWR);
00829 CLOSE (s);
00830 return MHD_NO;
00831 }
00832
00833
00834 if ((daemon->apc != NULL)
00835 && (MHD_NO == daemon->apc (daemon->apc_cls, addr, addrlen)))
00836 {
00837 #if DEBUG_CLOSE
00838 #if HAVE_MESSAGES
00839 MHD_DLOG (daemon, "Connection rejected, closing connection\n");
00840 #endif
00841 #endif
00842 SHUTDOWN (s, SHUT_RDWR);
00843 CLOSE (s);
00844 MHD_ip_limit_del (daemon, addr, addrlen);
00845 return MHD_YES;
00846 }
00847 #if OSX
00848 #ifdef SOL_SOCKET
00849 #ifdef SO_NOSIGPIPE
00850 setsockopt (s, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof (on));
00851 #endif
00852 #endif
00853 #endif
00854 connection = malloc (sizeof (struct MHD_Connection));
00855 if (NULL == connection)
00856 {
00857 #if HAVE_MESSAGES
00858 MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno));
00859 #endif
00860 SHUTDOWN (s, SHUT_RDWR);
00861 CLOSE (s);
00862 MHD_ip_limit_del (daemon, addr, addrlen);
00863 return MHD_NO;
00864 }
00865 memset (connection, 0, sizeof (struct MHD_Connection));
00866 connection->pool = NULL;
00867 connection->addr = malloc (addrlen);
00868 if (connection->addr == NULL)
00869 {
00870 #if HAVE_MESSAGES
00871 MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno));
00872 #endif
00873 SHUTDOWN (s, SHUT_RDWR);
00874 CLOSE (s);
00875 MHD_ip_limit_del (daemon, addr, addrlen);
00876 free (connection);
00877 return MHD_NO;
00878 }
00879 memcpy (connection->addr, addr, addrlen);
00880 connection->addr_len = addrlen;
00881 connection->socket_fd = s;
00882 connection->daemon = daemon;
00883 connection->last_activity = time (NULL);
00884
00885
00886 MHD_set_http_callbacks_ (connection);
00887 connection->recv_cls = &recv_param_adapter;
00888 connection->send_cls = &send_param_adapter;
00889 #if HTTPS_SUPPORT
00890 if (0 != (daemon->options & MHD_USE_SSL))
00891 {
00892 connection->recv_cls = &recv_tls_adapter;
00893 connection->send_cls = &send_tls_adapter;
00894 connection->state = MHD_TLS_CONNECTION_INIT;
00895 MHD_set_https_callbacks (connection);
00896 gnutls_init (&connection->tls_session, GNUTLS_SERVER);
00897 gnutls_priority_set (connection->tls_session,
00898 daemon->priority_cache);
00899 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
00900 {
00901
00902 socket_set_nonblocking (connection->socket_fd);
00903 }
00904 switch (connection->daemon->cred_type)
00905 {
00906
00907 case GNUTLS_CRD_CERTIFICATE:
00908 gnutls_credentials_set (connection->tls_session,
00909 GNUTLS_CRD_CERTIFICATE,
00910 connection->daemon->x509_cred);
00911 break;
00912 default:
00913 #if HAVE_MESSAGES
00914 MHD_DLOG (connection->daemon,
00915 "Failed to setup TLS credentials: unknown credential type %d\n",
00916 connection->daemon->cred_type);
00917 #endif
00918 SHUTDOWN (s, SHUT_RDWR);
00919 CLOSE (s);
00920 MHD_ip_limit_del (daemon, addr, addrlen);
00921 free (connection->addr);
00922 free (connection);
00923 mhd_panic (mhd_panic_cls, __FILE__, __LINE__,
00924 #if HAVE_MESSAGES
00925 "Unknown credential type"
00926 #else
00927 NULL
00928 #endif
00929 );
00930 return MHD_NO;
00931 }
00932 gnutls_transport_set_ptr (connection->tls_session,
00933 (gnutls_transport_ptr_t) connection);
00934 gnutls_transport_set_pull_function (connection->tls_session,
00935 (gnutls_pull_func) &
00936 recv_param_adapter);
00937 gnutls_transport_set_push_function (connection->tls_session,
00938 (gnutls_push_func) &
00939 send_param_adapter);
00940 }
00941 #endif
00942
00943
00944 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
00945 {
00946 res_thread_create = pthread_create (&connection->pid, NULL,
00947 &MHD_handle_connection, connection);
00948 if (res_thread_create != 0)
00949 {
00950 #if HAVE_MESSAGES
00951 MHD_DLOG (daemon, "Failed to create a thread: %s\n",
00952 STRERROR (res_thread_create));
00953 #endif
00954 SHUTDOWN (s, SHUT_RDWR);
00955 CLOSE (s);
00956 MHD_ip_limit_del (daemon, addr, addrlen);
00957 free (connection->addr);
00958 free (connection);
00959 return MHD_NO;
00960 }
00961 }
00962 connection->next = daemon->connections;
00963 daemon->connections = connection;
00964 daemon->max_connections--;
00965 return MHD_YES;
00966 }
00967
00975 static void
00976 MHD_cleanup_connections (struct MHD_Daemon *daemon)
00977 {
00978 struct MHD_Connection *pos;
00979 struct MHD_Connection *prev;
00980 void *unused;
00981 int rc;
00982
00983 pos = daemon->connections;
00984 prev = NULL;
00985 while (pos != NULL)
00986 {
00987 if ((pos->socket_fd == -1) ||
00988 (((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
00989 (daemon->shutdown) && (pos->socket_fd != -1))))
00990 {
00991 if (prev == NULL)
00992 daemon->connections = pos->next;
00993 else
00994 prev->next = pos->next;
00995 if (0 != (pos->daemon->options & MHD_USE_THREAD_PER_CONNECTION))
00996 {
00997 pthread_kill (pos->pid, SIGALRM);
00998 if (0 != (rc = pthread_join (pos->pid, &unused)))
00999 {
01000 #if HAVE_MESSAGES
01001 MHD_DLOG (daemon, "Failed to join a thread: %s\n",
01002 STRERROR (rc));
01003 #endif
01004 abort();
01005 }
01006 }
01007 MHD_pool_destroy (pos->pool);
01008 #if HTTPS_SUPPORT
01009 if (pos->tls_session != NULL)
01010 gnutls_deinit (pos->tls_session);
01011 #endif
01012 MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len);
01013 if (pos->response != NULL)
01014 {
01015 MHD_destroy_response (pos->response);
01016 pos->response = NULL;
01017 }
01018 free (pos->addr);
01019 free (pos);
01020 daemon->max_connections++;
01021 if (prev == NULL)
01022 pos = daemon->connections;
01023 else
01024 pos = prev->next;
01025 continue;
01026 }
01027 prev = pos;
01028 pos = pos->next;
01029 }
01030 }
01031
01044 int
01045 MHD_get_timeout (struct MHD_Daemon *daemon, unsigned long long *timeout)
01046 {
01047 time_t earliest_deadline;
01048 time_t now;
01049 struct MHD_Connection *pos;
01050 unsigned int dto;
01051
01052 dto = daemon->connection_timeout;
01053 if (0 == dto)
01054 return MHD_NO;
01055 pos = daemon->connections;
01056 if (pos == NULL)
01057 return MHD_NO;
01058 now = time (NULL);
01059
01060 earliest_deadline = now + dto;
01061 while (pos != NULL)
01062 {
01063 if (earliest_deadline > pos->last_activity + dto)
01064 earliest_deadline = pos->last_activity + dto;
01065 #if HTTPS_SUPPORT
01066 if ( (0 != (daemon->options & MHD_USE_SSL)) &&
01067 (0 != gnutls_record_check_pending (pos->tls_session)) )
01068 earliest_deadline = now;
01069 #endif
01070 pos = pos->next;
01071 }
01072 if (earliest_deadline < now)
01073 *timeout = 0;
01074 else
01075 *timeout = (earliest_deadline - now);
01076 return MHD_YES;
01077 }
01078
01079
01087 static int
01088 MHD_select (struct MHD_Daemon *daemon, int may_block)
01089 {
01090 struct MHD_Connection *pos;
01091 int num_ready;
01092 fd_set rs;
01093 fd_set ws;
01094 fd_set es;
01095 int max;
01096 struct timeval timeout;
01097 unsigned long long ltimeout;
01098 int ds;
01099
01100 timeout.tv_sec = 0;
01101 timeout.tv_usec = 0;
01102 if (daemon->shutdown == MHD_YES)
01103 return MHD_NO;
01104 FD_ZERO (&rs);
01105 FD_ZERO (&ws);
01106 FD_ZERO (&es);
01107 max = 0;
01108
01109 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
01110 {
01111
01112 if (MHD_NO == MHD_get_fdset (daemon, &rs, &ws, &es, &max))
01113 return MHD_NO;
01114
01115
01116
01117 if ( (daemon->max_connections == 0) && (daemon->socket_fd != -1) )
01118 FD_CLR(daemon->socket_fd, &rs);
01119 }
01120 else
01121 {
01122
01123 max = daemon->socket_fd;
01124 if (max == -1)
01125 return MHD_NO;
01126 FD_SET (max, &rs);
01127 }
01128
01129
01130
01131 timeout.tv_usec = 0;
01132 timeout.tv_sec = 1;
01133 if (may_block == MHD_NO)
01134 {
01135 timeout.tv_usec = 0;
01136 timeout.tv_sec = 0;
01137 }
01138 else
01139 {
01140
01141 if ( (MHD_YES == MHD_get_timeout (daemon, <imeout)) &&
01142 (ltimeout < 1000) )
01143 {
01144 timeout.tv_usec = ltimeout * 1000;
01145 timeout.tv_sec = 0;
01146 }
01147 }
01148 num_ready = SELECT (max + 1, &rs, &ws, &es, &timeout);
01149
01150 if (daemon->shutdown == MHD_YES)
01151 return MHD_NO;
01152 if (num_ready < 0)
01153 {
01154 if (errno == EINTR)
01155 return MHD_YES;
01156 #if HAVE_MESSAGES
01157 MHD_DLOG (daemon, "select failed: %s\n", STRERROR (errno));
01158 #endif
01159 return MHD_NO;
01160 }
01161 ds = daemon->socket_fd;
01162 if (ds == -1)
01163 return MHD_YES;
01164
01165
01166 if (FD_ISSET (ds, &rs))
01167 MHD_accept_connection (daemon);
01168 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
01169 {
01170
01171 pos = daemon->connections;
01172 while (pos != NULL)
01173 {
01174 ds = pos->socket_fd;
01175 if (ds != -1)
01176 {
01177
01178 if (FD_ISSET (ds, &rs))
01179 pos->read_handler (pos);
01180 if ((pos->socket_fd != -1) && (FD_ISSET (ds, &ws)))
01181 pos->write_handler (pos);
01182 if (pos->socket_fd != -1)
01183 pos->idle_handler (pos);
01184 }
01185 pos = pos->next;
01186 }
01187 }
01188 return MHD_YES;
01189 }
01190
01196 static int
01197 MHD_poll (struct MHD_Daemon *daemon)
01198 {
01199 #ifdef HAVE_POLL_H
01200 struct pollfd p;
01201
01202 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
01203 return MHD_NO;
01204 p.fd = daemon->socket_fd;
01205 p.events = POLLIN;
01206 p.revents = 0;
01207
01208 if (poll(&p, 1, 1000) < 0) {
01209 if (errno == EINTR)
01210 return MHD_YES;
01211 #if HAVE_MESSAGES
01212 MHD_DLOG (daemon, "poll failed: %s\n", STRERROR (errno));
01213 #endif
01214 return MHD_NO;
01215 }
01216
01217 if (daemon->shutdown == MHD_YES)
01218 return MHD_NO;
01219 if (daemon->socket_fd < 0)
01220 return MHD_YES;
01221 if (0 != (p.revents & POLLIN))
01222 MHD_accept_connection (daemon);
01223 return MHD_YES;
01224 #else
01225 return MHD_NO;
01226 #endif
01227 }
01228
01229
01240 int
01241 MHD_run (struct MHD_Daemon *daemon)
01242 {
01243 if ((daemon->shutdown != MHD_NO) || (0 != (daemon->options
01244 & MHD_USE_THREAD_PER_CONNECTION))
01245 || (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)))
01246 return MHD_NO;
01247 MHD_select (daemon, MHD_NO);
01248 MHD_cleanup_connections (daemon);
01249 return MHD_YES;
01250 }
01251
01252
01260 static void *
01261 MHD_select_thread (void *cls)
01262 {
01263 struct MHD_Daemon *daemon = cls;
01264 while (daemon->shutdown == MHD_NO)
01265 {
01266 if ((daemon->options & MHD_USE_POLL) == 0)
01267 MHD_select (daemon, MHD_YES);
01268 else
01269 MHD_poll(daemon);
01270 MHD_cleanup_connections (daemon);
01271 }
01272 return NULL;
01273 }
01274
01275
01287 struct MHD_Daemon *
01288 MHD_start_daemon (unsigned int options,
01289 uint16_t port,
01290 MHD_AcceptPolicyCallback apc,
01291 void *apc_cls,
01292 MHD_AccessHandlerCallback dh, void *dh_cls, ...)
01293 {
01294 struct MHD_Daemon *ret;
01295 va_list ap;
01296
01297 va_start (ap, dh_cls);
01298 ret = MHD_start_daemon_va (options, port, apc, apc_cls, dh, dh_cls, ap);
01299 va_end (ap);
01300 return ret;
01301 }
01302
01303
01304 typedef void (*VfprintfFunctionPointerType)(void *, const char *, va_list);
01305
01306
01315 static int
01316 parse_options_va (struct MHD_Daemon *daemon,
01317 const struct sockaddr **servaddr,
01318 va_list ap);
01319
01320
01329 static int
01330 parse_options (struct MHD_Daemon *daemon,
01331 const struct sockaddr **servaddr,
01332 ...)
01333 {
01334 va_list ap;
01335 int ret;
01336
01337 va_start (ap, servaddr);
01338 ret = parse_options_va (daemon, servaddr, ap);
01339 va_end (ap);
01340 return ret;
01341 }
01342
01343
01352 static int
01353 parse_options_va (struct MHD_Daemon *daemon,
01354 const struct sockaddr **servaddr,
01355 va_list ap)
01356 {
01357 enum MHD_OPTION opt;
01358 struct MHD_OptionItem *oa;
01359 unsigned int i;
01360 #if HTTPS_SUPPORT
01361 int ret;
01362 const char *pstr;
01363 #endif
01364
01365 while (MHD_OPTION_END != (opt = va_arg (ap, enum MHD_OPTION)))
01366 {
01367 switch (opt)
01368 {
01369 case MHD_OPTION_CONNECTION_MEMORY_LIMIT:
01370 daemon->pool_size = va_arg (ap, size_t);
01371 break;
01372 case MHD_OPTION_CONNECTION_LIMIT:
01373 daemon->max_connections = va_arg (ap, unsigned int);
01374 break;
01375 case MHD_OPTION_CONNECTION_TIMEOUT:
01376 daemon->connection_timeout = va_arg (ap, unsigned int);
01377 break;
01378 case MHD_OPTION_NOTIFY_COMPLETED:
01379 daemon->notify_completed =
01380 va_arg (ap, MHD_RequestCompletedCallback);
01381 daemon->notify_completed_cls = va_arg (ap, void *);
01382 break;
01383 case MHD_OPTION_PER_IP_CONNECTION_LIMIT:
01384 daemon->per_ip_connection_limit = va_arg (ap, unsigned int);
01385 break;
01386 case MHD_OPTION_SOCK_ADDR:
01387 *servaddr = va_arg (ap, const struct sockaddr *);
01388 break;
01389 case MHD_OPTION_URI_LOG_CALLBACK:
01390 daemon->uri_log_callback =
01391 va_arg (ap, LogCallback);
01392 daemon->uri_log_callback_cls = va_arg (ap, void *);
01393 break;
01394 case MHD_OPTION_THREAD_POOL_SIZE:
01395 daemon->worker_pool_size = va_arg (ap, unsigned int);
01396 if (daemon->worker_pool_size >= SIZE_MAX / sizeof (struct MHD_Daemon))
01397 {
01398 #if HAVE_MESSAGES
01399 FPRINTF (stderr,
01400 "Specified thread pool size too big\n");
01401 #endif
01402 return MHD_NO;
01403 }
01404 break;
01405 #if HTTPS_SUPPORT
01406 case MHD_OPTION_HTTPS_MEM_KEY:
01407 if (0 != (daemon->options & MHD_USE_SSL))
01408 daemon->https_mem_key = va_arg (ap, const char *);
01409 #if HAVE_MESSAGES
01410 else
01411 FPRINTF (stderr,
01412 "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
01413 opt);
01414 #endif
01415 break;
01416 case MHD_OPTION_HTTPS_MEM_CERT:
01417 if (0 != (daemon->options & MHD_USE_SSL))
01418 daemon->https_mem_cert = va_arg (ap, const char *);
01419 #if HAVE_MESSAGES
01420 else
01421 FPRINTF (stderr,
01422 "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
01423 opt);
01424 #endif
01425 break;
01426 case MHD_OPTION_HTTPS_CRED_TYPE:
01427 daemon->cred_type = va_arg (ap, gnutls_credentials_type_t);
01428 break;
01429 case MHD_OPTION_HTTPS_PRIORITIES:
01430 ret = gnutls_priority_init (&daemon->priority_cache,
01431 pstr = va_arg (ap, const char*),
01432 NULL);
01433 #if HAVE_MESSAGES
01434 if (ret != GNUTLS_E_SUCCESS)
01435 FPRINTF (stderr,
01436 "Setting priorities to `%s' failed: %s\n",
01437 pstr,
01438 gnutls_strerror (ret));
01439 #endif
01440 if (ret != GNUTLS_E_SUCCESS)
01441 return MHD_NO;
01442 break;
01443 #endif
01444 #ifdef DAUTH_SUPPORT
01445 case MHD_OPTION_DIGEST_AUTH_RANDOM:
01446 daemon->digest_auth_rand_size = va_arg (ap, size_t);
01447 daemon->digest_auth_random = va_arg (ap, const char *);
01448 break;
01449 case MHD_OPTION_NONCE_NC_SIZE:
01450 daemon->nonce_nc_size = va_arg (ap, unsigned int);
01451 break;
01452 #endif
01453 case MHD_OPTION_LISTEN_SOCKET:
01454 daemon->socket_fd = va_arg (ap, int);
01455 break;
01456 case MHD_OPTION_EXTERNAL_LOGGER:
01457 #if HAVE_MESSAGES
01458 daemon->custom_error_log =
01459 va_arg (ap, VfprintfFunctionPointerType);
01460 daemon->custom_error_log_cls = va_arg (ap, void *);
01461 #else
01462 va_arg (ap, VfprintfFunctionPointerType);
01463 va_arg (ap, void *);
01464 #endif
01465 break;
01466 case MHD_OPTION_ARRAY:
01467 oa = va_arg (ap, struct MHD_OptionItem*);
01468 i = 0;
01469 while (MHD_OPTION_END != (opt = oa[i].option))
01470 {
01471 switch (opt)
01472 {
01473
01474 case MHD_OPTION_CONNECTION_MEMORY_LIMIT:
01475 if (MHD_YES != parse_options (daemon,
01476 servaddr,
01477 opt,
01478 (size_t) oa[i].value,
01479 MHD_OPTION_END))
01480 return MHD_NO;
01481 break;
01482
01483 case MHD_OPTION_NONCE_NC_SIZE:
01484 case MHD_OPTION_CONNECTION_LIMIT:
01485 case MHD_OPTION_CONNECTION_TIMEOUT:
01486 case MHD_OPTION_PER_IP_CONNECTION_LIMIT:
01487 case MHD_OPTION_THREAD_POOL_SIZE:
01488 if (MHD_YES != parse_options (daemon,
01489 servaddr,
01490 opt,
01491 (unsigned int) oa[i].value,
01492 MHD_OPTION_END))
01493 return MHD_NO;
01494 break;
01495
01496 case MHD_OPTION_HTTPS_CRED_TYPE:
01497 case MHD_OPTION_LISTEN_SOCKET:
01498 if (MHD_YES != parse_options (daemon,
01499 servaddr,
01500 opt,
01501 (int) oa[i].value,
01502 MHD_OPTION_END))
01503 return MHD_NO;
01504 break;
01505
01506 case MHD_OPTION_SOCK_ADDR:
01507 case MHD_OPTION_HTTPS_MEM_KEY:
01508 case MHD_OPTION_HTTPS_MEM_CERT:
01509 case MHD_OPTION_HTTPS_PRIORITIES:
01510 case MHD_OPTION_ARRAY:
01511 if (MHD_YES != parse_options (daemon,
01512 servaddr,
01513 opt,
01514 oa[i].ptr_value,
01515 MHD_OPTION_END))
01516 return MHD_NO;
01517 break;
01518
01519 case MHD_OPTION_NOTIFY_COMPLETED:
01520 case MHD_OPTION_URI_LOG_CALLBACK:
01521 case MHD_OPTION_EXTERNAL_LOGGER:
01522 case MHD_OPTION_UNESCAPE_CALLBACK:
01523 if (MHD_YES != parse_options (daemon,
01524 servaddr,
01525 opt,
01526 (void *) oa[i].value,
01527 oa[i].ptr_value,
01528 MHD_OPTION_END))
01529 return MHD_NO;
01530 break;
01531
01532 case MHD_OPTION_DIGEST_AUTH_RANDOM:
01533 if (MHD_YES != parse_options (daemon,
01534 servaddr,
01535 opt,
01536 (size_t) oa[i].value,
01537 oa[i].ptr_value,
01538 MHD_OPTION_END))
01539 return MHD_NO;
01540 default:
01541 return MHD_NO;
01542 }
01543 i++;
01544 }
01545 break;
01546 case MHD_OPTION_UNESCAPE_CALLBACK:
01547 daemon->unescape_callback =
01548 va_arg (ap, UnescapeCallback);
01549 daemon->unescape_callback_cls = va_arg (ap, void *);
01550 break;
01551 default:
01552 #if HAVE_MESSAGES
01553 if ((opt >= MHD_OPTION_HTTPS_MEM_KEY) &&
01554 (opt <= MHD_OPTION_HTTPS_PRIORITIES))
01555 {
01556 FPRINTF (stderr,
01557 "MHD HTTPS option %d passed to MHD compiled without HTTPS support\n",
01558 opt);
01559 }
01560 else
01561 {
01562 FPRINTF (stderr,
01563 "Invalid option %d! (Did you terminate the list with MHD_OPTION_END?)\n",
01564 opt);
01565 }
01566 #endif
01567 return MHD_NO;
01568 }
01569 }
01570 return MHD_YES;
01571 }
01572
01573
01585 struct MHD_Daemon *
01586 MHD_start_daemon_va (unsigned int options,
01587 uint16_t port,
01588 MHD_AcceptPolicyCallback apc,
01589 void *apc_cls,
01590 MHD_AccessHandlerCallback dh, void *dh_cls,
01591 va_list ap)
01592 {
01593 const int on = 1;
01594 struct MHD_Daemon *retVal;
01595 int socket_fd;
01596 struct sockaddr_in servaddr4;
01597 #if HAVE_INET6
01598 struct sockaddr_in6 servaddr6;
01599 #endif
01600 const struct sockaddr *servaddr = NULL;
01601 socklen_t addrlen;
01602 unsigned int i;
01603 int res_thread_create;
01604
01605 if ((port == 0) || (dh == NULL))
01606 return NULL;
01607 retVal = malloc (sizeof (struct MHD_Daemon));
01608 if (retVal == NULL)
01609 return NULL;
01610 memset (retVal, 0, sizeof (struct MHD_Daemon));
01611 #if HTTPS_SUPPORT
01612 if (options & MHD_USE_SSL)
01613 {
01614 gnutls_priority_init (&retVal->priority_cache,
01615 "NORMAL",
01616 NULL);
01617 }
01618 #endif
01619 retVal->socket_fd = -1;
01620 retVal->options = (enum MHD_OPTION)options;
01621 retVal->port = port;
01622 retVal->apc = apc;
01623 retVal->apc_cls = apc_cls;
01624 retVal->default_handler = dh;
01625 retVal->default_handler_cls = dh_cls;
01626 retVal->max_connections = MHD_MAX_CONNECTIONS_DEFAULT;
01627 retVal->pool_size = MHD_POOL_SIZE_DEFAULT;
01628 retVal->unescape_callback = &MHD_http_unescape;
01629 retVal->connection_timeout = 0;
01630 #ifdef DAUTH_SUPPORT
01631 retVal->digest_auth_rand_size = 0;
01632 retVal->digest_auth_random = NULL;
01633 retVal->nonce_nc_size = 4;
01634 #endif
01635 #if HAVE_MESSAGES
01636 retVal->custom_error_log =
01637 (void (*)(void *, const char *, va_list)) &vfprintf;
01638 retVal->custom_error_log_cls = stderr;
01639 #endif
01640 #if HTTPS_SUPPORT
01641 if (options & MHD_USE_SSL)
01642 {
01643
01644 if (0 != pthread_mutex_lock (&MHD_gnutls_init_mutex))
01645 {
01646 #if HAVE_MESSAGES
01647 MHD_DLOG (retVal, "Failed to aquire gnutls mutex\n");
01648 #endif
01649 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
01650 }
01651 if (0 != pthread_mutex_unlock (&MHD_gnutls_init_mutex))
01652 {
01653 #if HAVE_MESSAGES
01654 MHD_DLOG (retVal, "Failed to release gnutls mutex\n");
01655 #endif
01656 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
01657 }
01658 retVal->cred_type = GNUTLS_CRD_CERTIFICATE;
01659 }
01660 #endif
01661
01662 if (MHD_YES != parse_options_va (retVal, &servaddr, ap))
01663 {
01664 free (retVal);
01665 return NULL;
01666 }
01667
01668 #ifdef DAUTH_SUPPORT
01669 if (retVal->nonce_nc_size > 0)
01670 {
01671 if ( ( (size_t) (retVal->nonce_nc_size * sizeof(struct MHD_NonceNc))) /
01672 sizeof(struct MHD_NonceNc) != retVal->nonce_nc_size)
01673 {
01674 #if HAVE_MESSAGES
01675 MHD_DLOG (retVal,
01676 "Specified value for NC_SIZE too large\n");
01677 #endif
01678 free (retVal);
01679 return NULL;
01680 }
01681 retVal->nnc = malloc (retVal->nonce_nc_size * sizeof(struct MHD_NonceNc));
01682 if (NULL == retVal->nnc)
01683 {
01684 #if HAVE_MESSAGES
01685 MHD_DLOG (retVal,
01686 "Failed to allocate memory for nonce-nc map: %s\n",
01687 STRERROR (errno));
01688 #endif
01689 free (retVal);
01690 return NULL;
01691 }
01692 }
01693 if (0 != pthread_mutex_init (&retVal->nnc_lock, NULL))
01694 {
01695 #if HAVE_MESSAGES
01696 MHD_DLOG (retVal,
01697 "MHD failed to initialize nonce-nc mutex\n");
01698 #endif
01699 free (retVal);
01700 return NULL;
01701 }
01702 #endif
01703
01704
01705 if ( (0 != (options & MHD_USE_POLL)) &&
01706 (0 == (options & MHD_USE_THREAD_PER_CONNECTION)) )
01707 {
01708 #if HAVE_MESSAGES
01709 MHD_DLOG (retVal,
01710 "MHD poll support only works with MHD_USE_THREAD_PER_CONNECTION\n");
01711 #endif
01712 free (retVal);
01713 return NULL;
01714 }
01715
01716
01717 if ( (0 == (options & MHD_USE_SELECT_INTERNALLY)) &&
01718 (retVal->worker_pool_size > 0) )
01719 {
01720 #if HAVE_MESSAGES
01721 MHD_DLOG (retVal,
01722 "MHD thread pooling only works with MHD_USE_SELECT_INTERNALLY\n");
01723 #endif
01724 free (retVal);
01725 return NULL;
01726 }
01727
01728 #ifdef __SYMBIAN32__
01729 if (0 != (options & (MHD_USE_SELECT_INTERNALLY | MHD_USE_THREAD_PER_CONNECTION)))
01730 {
01731 #if HAVE_MESSAGES
01732 MHD_DLOG (retVal,
01733 "Threaded operations are not supported on Symbian.\n");
01734 #endif
01735 free (retVal);
01736 return NULL;
01737 }
01738 #endif
01739 if (retVal->socket_fd == -1)
01740 {
01741 if ((options & MHD_USE_IPv6) != 0)
01742 #if HAVE_INET6
01743 socket_fd = SOCKET (PF_INET6, SOCK_STREAM, 0);
01744 #else
01745 {
01746 #if HAVE_MESSAGES
01747 MHD_DLOG (retVal,
01748 "AF_INET6 not supported\n");
01749 #endif
01750 free (retVal);
01751 return NULL;
01752 }
01753 #endif
01754 else
01755 socket_fd = SOCKET (PF_INET, SOCK_STREAM, 0);
01756 if (socket_fd == -1)
01757 {
01758 #if HAVE_MESSAGES
01759 if ((options & MHD_USE_DEBUG) != 0)
01760 MHD_DLOG (retVal,
01761 "Call to socket failed: %s\n",
01762 STRERROR (errno));
01763 #endif
01764 free (retVal);
01765 return NULL;
01766 }
01767 if ((SETSOCKOPT (socket_fd,
01768 SOL_SOCKET,
01769 SO_REUSEADDR,
01770 &on, sizeof (on)) < 0) && ((options & MHD_USE_DEBUG) != 0))
01771 {
01772 #if HAVE_MESSAGES
01773 MHD_DLOG (retVal,
01774 "setsockopt failed: %s\n",
01775 STRERROR (errno));
01776 #endif
01777 }
01778
01779
01780 #if HAVE_INET6
01781 if ((options & MHD_USE_IPv6) != 0)
01782 addrlen = sizeof (struct sockaddr_in6);
01783 else
01784 #endif
01785 addrlen = sizeof (struct sockaddr_in);
01786 if (NULL == servaddr)
01787 {
01788 #if HAVE_INET6
01789 if ((options & MHD_USE_IPv6) != 0)
01790 {
01791 memset (&servaddr6, 0, sizeof (struct sockaddr_in6));
01792 servaddr6.sin6_family = AF_INET6;
01793 servaddr6.sin6_port = htons (port);
01794 servaddr = (struct sockaddr *) &servaddr6;
01795 }
01796 else
01797 #endif
01798 {
01799 memset (&servaddr4, 0, sizeof (struct sockaddr_in));
01800 servaddr4.sin_family = AF_INET;
01801 servaddr4.sin_port = htons (port);
01802 servaddr = (struct sockaddr *) &servaddr4;
01803 }
01804 }
01805 retVal->socket_fd = socket_fd;
01806
01807 if ((options & MHD_USE_IPv6) != 0)
01808 {
01809 #ifdef IPPROTO_IPV6
01810 #ifdef IPV6_V6ONLY
01811
01812
01813
01814
01815 #ifndef WINDOWS
01816 const int on = 1;
01817 setsockopt (socket_fd,
01818 IPPROTO_IPV6, IPV6_V6ONLY,
01819 &on, sizeof (on));
01820 #else
01821 const char on = 1;
01822 setsockopt (socket_fd,
01823 IPPROTO_IPV6, IPV6_V6ONLY,
01824 &on, sizeof (on));
01825 #endif
01826 #endif
01827 #endif
01828 }
01829 if (BIND (socket_fd, servaddr, addrlen) == -1)
01830 {
01831 #if HAVE_MESSAGES
01832 if ((options & MHD_USE_DEBUG) != 0)
01833 MHD_DLOG (retVal,
01834 "Failed to bind to port %u: %s\n",
01835 (unsigned int) port,
01836 STRERROR (errno));
01837 #endif
01838 CLOSE (socket_fd);
01839 free (retVal);
01840 return NULL;
01841 }
01842
01843 if (LISTEN (socket_fd, 20) < 0)
01844 {
01845 #if HAVE_MESSAGES
01846 if ((options & MHD_USE_DEBUG) != 0)
01847 MHD_DLOG (retVal,
01848 "Failed to listen for connections: %s\n",
01849 STRERROR (errno));
01850 #endif
01851 CLOSE (socket_fd);
01852 free (retVal);
01853 return NULL;
01854 }
01855 }
01856 else
01857 {
01858 socket_fd = retVal->socket_fd;
01859 }
01860 #ifndef WINDOWS
01861 if ( (socket_fd >= FD_SETSIZE) &&
01862 (0 == (options & MHD_USE_POLL)) )
01863 {
01864 #if HAVE_MESSAGES
01865 if ((options & MHD_USE_DEBUG) != 0)
01866 MHD_DLOG (retVal,
01867 "Socket descriptor larger than FD_SETSIZE: %d > %d\n",
01868 socket_fd,
01869 FD_SETSIZE);
01870 #endif
01871 CLOSE (socket_fd);
01872 free (retVal);
01873 return NULL;
01874 }
01875 #endif
01876
01877 if (0 != pthread_mutex_init (&retVal->per_ip_connection_mutex, NULL))
01878 {
01879 #if HAVE_MESSAGES
01880 MHD_DLOG (retVal,
01881 "MHD failed to initialize IP connection limit mutex\n");
01882 #endif
01883 CLOSE (socket_fd);
01884 free (retVal);
01885 return NULL;
01886 }
01887
01888 #if HTTPS_SUPPORT
01889
01890 if ((0 != (options & MHD_USE_SSL)) && (0 != MHD_TLS_init (retVal)))
01891 {
01892 #if HAVE_MESSAGES
01893 MHD_DLOG (retVal,
01894 "Failed to initialize TLS support\n");
01895 #endif
01896 CLOSE (socket_fd);
01897 pthread_mutex_destroy (&retVal->per_ip_connection_mutex);
01898 free (retVal);
01899 return NULL;
01900 }
01901 #endif
01902 if ( ( (0 != (options & MHD_USE_THREAD_PER_CONNECTION)) ||
01903 ( (0 != (options & MHD_USE_SELECT_INTERNALLY)) &&
01904 (0 == retVal->worker_pool_size)) ) &&
01905 (0 != (res_thread_create =
01906 pthread_create (&retVal->pid, NULL, &MHD_select_thread, retVal))))
01907 {
01908 #if HAVE_MESSAGES
01909 MHD_DLOG (retVal,
01910 "Failed to create listen thread: %s\n",
01911 STRERROR (res_thread_create));
01912 #endif
01913 pthread_mutex_destroy (&retVal->per_ip_connection_mutex);
01914 free (retVal);
01915 CLOSE (socket_fd);
01916 return NULL;
01917 }
01918 if (retVal->worker_pool_size > 0)
01919 {
01920 #ifndef MINGW
01921 int sk_flags;
01922 #else
01923 unsigned long sk_flags;
01924 #endif
01925
01926
01927
01928
01929 unsigned int conns_per_thread = retVal->max_connections
01930 / retVal->worker_pool_size;
01931 unsigned int leftover_conns = retVal->max_connections
01932 % retVal->worker_pool_size;
01933
01934 i = 0;
01935
01936
01937
01938
01939 #ifndef MINGW
01940 sk_flags = fcntl (socket_fd, F_GETFL);
01941 if (sk_flags < 0)
01942 goto thread_failed;
01943 if (fcntl (socket_fd, F_SETFL, sk_flags | O_NONBLOCK) < 0)
01944 goto thread_failed;
01945 #else
01946 sk_flags = 1;
01947 #if HAVE_PLIBC_FD
01948 if (ioctlsocket (plibc_fd_get_handle (socket_fd), FIONBIO, &sk_flags) ==
01949 SOCKET_ERROR)
01950 #else
01951 if (ioctlsocket (socket_fd, FIONBIO, &sk_flags) == SOCKET_ERROR)
01952 #endif // PLIBC_FD
01953 goto thread_failed;
01954 #endif // MINGW
01955
01956
01957 retVal->worker_pool = malloc (sizeof (struct MHD_Daemon)
01958 * retVal->worker_pool_size);
01959 if (NULL == retVal->worker_pool)
01960 goto thread_failed;
01961
01962
01963 for (i = 0; i < retVal->worker_pool_size; ++i)
01964 {
01965
01966 struct MHD_Daemon *d = &retVal->worker_pool[i];
01967 memcpy (d, retVal, sizeof (struct MHD_Daemon));
01968
01969
01970
01971
01972 d->master = retVal;
01973 d->worker_pool_size = 0;
01974 d->worker_pool = NULL;
01975
01976
01977
01978
01979 d->max_connections = conns_per_thread;
01980 if (i < leftover_conns)
01981 ++d->max_connections;
01982
01983
01984 if (0 != (res_thread_create = pthread_create (&d->pid, NULL, &MHD_select_thread, d)))
01985 {
01986 #if HAVE_MESSAGES
01987 MHD_DLOG (retVal,
01988 "Failed to create pool thread: %s\n",
01989 STRERROR (res_thread_create));
01990 #endif
01991
01992
01993 goto thread_failed;
01994 }
01995 }
01996 }
01997 return retVal;
01998
01999 thread_failed:
02000
02001
02002
02003
02004 if (i == 0)
02005 {
02006 CLOSE (socket_fd);
02007 pthread_mutex_destroy (&retVal->per_ip_connection_mutex);
02008 if (NULL != retVal->worker_pool)
02009 free (retVal->worker_pool);
02010 free (retVal);
02011 return NULL;
02012 }
02013
02014
02015
02016
02017
02018 retVal->worker_pool_size = i - 1;
02019 MHD_stop_daemon (retVal);
02020 return NULL;
02021 }
02022
02026 static void
02027 MHD_close_connections (struct MHD_Daemon *daemon)
02028 {
02029 while (daemon->connections != NULL)
02030 {
02031 if (-1 != daemon->connections->socket_fd)
02032 {
02033 #if DEBUG_CLOSE
02034 #if HAVE_MESSAGES
02035 MHD_DLOG (daemon, "MHD shutdown, closing active connections\n");
02036 #endif
02037 #endif
02038 MHD_connection_close (daemon->connections,
02039 MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
02040 }
02041 MHD_cleanup_connections (daemon);
02042 }
02043 }
02044
02048 void
02049 MHD_stop_daemon (struct MHD_Daemon *daemon)
02050 {
02051 void *unused;
02052 int fd;
02053 unsigned int i;
02054 int rc;
02055
02056 if (daemon == NULL)
02057 return;
02058 daemon->shutdown = MHD_YES;
02059 fd = daemon->socket_fd;
02060 daemon->socket_fd = -1;
02061
02062
02063 for (i = 0; i < daemon->worker_pool_size; ++i)
02064 {
02065 daemon->worker_pool[i].shutdown = MHD_YES;
02066 daemon->worker_pool[i].socket_fd = -1;
02067 }
02068
02069 #if OSX
02070
02071
02072
02073 SHUTDOWN (fd, SHUT_RDWR);
02074 #else
02075 #if DEBUG_CLOSE
02076 #if HAVE_MESSAGES
02077 MHD_DLOG (daemon, "MHD shutdown, closing listen socket\n");
02078 #endif
02079 #endif
02080 CLOSE (fd);
02081 #endif
02082
02083
02084 for (i = 0; i < daemon->worker_pool_size; ++i)
02085 pthread_kill (daemon->worker_pool[i].pid, SIGALRM);
02086 for (i = 0; i < daemon->worker_pool_size; ++i)
02087 {
02088 if (0 != (rc = pthread_join (daemon->worker_pool[i].pid, &unused)))
02089 {
02090 #if HAVE_MESSAGES
02091 MHD_DLOG (daemon, "Failed to join a thread: %s\n",
02092 STRERROR (rc));
02093 #endif
02094 abort();
02095 }
02096 MHD_close_connections (&daemon->worker_pool[i]);
02097 }
02098 free (daemon->worker_pool);
02099
02100 if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
02101 ((0 != (daemon->options & MHD_USE_SELECT_INTERNALLY))
02102 && (0 == daemon->worker_pool_size)))
02103 {
02104 pthread_kill (daemon->pid, SIGALRM);
02105 if (0 != (rc = pthread_join (daemon->pid, &unused)))
02106 {
02107 #if HAVE_MESSAGES
02108 MHD_DLOG (daemon, "Failed to join a thread: %s\n",
02109 STRERROR (rc));
02110 #endif
02111 abort();
02112 }
02113 }
02114 MHD_close_connections (daemon);
02115
02116 #if OSX
02117 #if DEBUG_CLOSE
02118 #if HAVE_MESSAGES
02119 MHD_DLOG (daemon, "MHD shutdown, closing listen socket\n");
02120 #endif
02121 #endif
02122 CLOSE (fd);
02123 #endif
02124
02125
02126 #if HTTPS_SUPPORT
02127 if (daemon->options & MHD_USE_SSL)
02128 {
02129 gnutls_priority_deinit (daemon->priority_cache);
02130 if (daemon->x509_cred)
02131 gnutls_certificate_free_credentials (daemon->x509_cred);
02132
02133 if (0 != pthread_mutex_lock (&MHD_gnutls_init_mutex))
02134 {
02135 #if HAVE_MESSAGES
02136 MHD_DLOG (daemon, "Failed to aquire gnutls mutex\n");
02137 #endif
02138 abort();
02139 }
02140 if (0 != pthread_mutex_unlock (&MHD_gnutls_init_mutex))
02141 {
02142 #if HAVE_MESSAGES
02143 MHD_DLOG (daemon, "Failed to release gnutls mutex\n");
02144 #endif
02145 abort();
02146 }
02147 }
02148 #endif
02149
02150 #ifdef DAUTH_SUPPORT
02151 free (daemon->nnc);
02152 pthread_mutex_destroy (&daemon->nnc_lock);
02153 #endif
02154 pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
02155 free (daemon);
02156 }
02157
02168 const union MHD_DaemonInfo *
02169 MHD_get_daemon_info (struct MHD_Daemon *daemon,
02170 enum MHD_DaemonInfoType infoType, ...)
02171 {
02172 switch (infoType)
02173 {
02174 case MHD_DAEMON_INFO_LISTEN_FD:
02175 return (const union MHD_DaemonInfo *) &daemon->socket_fd;
02176 default:
02177 return NULL;
02178 };
02179 }
02180
02196 void MHD_set_panic_func (MHD_PanicCallback cb, void *cls)
02197 {
02198 mhd_panic = cb;
02199 mhd_panic_cls = cls;
02200 }
02201
02207 const char *
02208 MHD_get_version (void)
02209 {
02210 return PACKAGE_VERSION;
02211 }
02212
02213 #ifndef WINDOWS
02214
02215 static struct sigaction sig;
02216
02217 static struct sigaction old;
02218
02219 static void
02220 sigalrmHandler (int sig)
02221 {
02222 }
02223 #endif
02224
02225 #ifdef __GNUC__
02226 #define ATTRIBUTE_CONSTRUCTOR __attribute__ ((constructor))
02227 #define ATTRIBUTE_DESTRUCTOR __attribute__ ((destructor))
02228 #else // !__GNUC__
02229 #define ATTRIBUTE_CONSTRUCTOR
02230 #define ATTRIBUTE_DESTRUCTOR
02231 #endif // __GNUC__
02232
02233 #if HTTPS_SUPPORT
02234 GCRY_THREAD_OPTION_PTHREAD_IMPL;
02235 #endif
02236
02241 void ATTRIBUTE_CONSTRUCTOR MHD_init ()
02242 {
02243 mhd_panic = &mhd_panic_std;
02244 mhd_panic_cls = NULL;
02245
02246 #ifndef WINDOWS
02247
02248 memset (&sig, 0, sizeof (struct sigaction));
02249 memset (&old, 0, sizeof (struct sigaction));
02250 sig.sa_flags = SA_NODEFER;
02251 sig.sa_handler = &sigalrmHandler;
02252 sigaction (SIGALRM, &sig, &old);
02253 #else
02254 plibc_init ("GNU", "libmicrohttpd");
02255 #endif
02256 #if HTTPS_SUPPORT
02257 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
02258 gnutls_global_init ();
02259 if (0 != pthread_mutex_init(&MHD_gnutls_init_mutex, NULL))
02260 abort();
02261 #endif
02262 }
02263
02264 void ATTRIBUTE_DESTRUCTOR MHD_fini ()
02265 {
02266 #if HTTPS_SUPPORT
02267 gnutls_global_deinit ();
02268 if (0 != pthread_mutex_destroy(&MHD_gnutls_init_mutex))
02269 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
02270 #endif
02271 #ifndef WINDOWS
02272 sigaction (SIGALRM, &old, &sig);
02273 #else
02274 plibc_shutdown ();
02275 #endif
02276 }
02277
02278