GNU libmicrohttpd 0.9.5
|
00001 /* 00002 This file is part of libmicrohttpd 00003 (C) 2007, 2008, 2009, 2010 Daniel Pittman and Christian Grothoff 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Lesser General Public 00007 License as published by the Free Software Foundation; either 00008 version 2.1 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Lesser General Public License for more details. 00014 00015 You should have received a copy of the GNU Lesser General Public 00016 License along with this library; if not, write to the Free Software 00017 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 // Symbian doesn't have signals. The user of the library is required to 00085 // run it in an external select loop. 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 /* IPv4 addresses */ 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 /* IPv6 addresses */ 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 /* Some other address */ 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 /* Ignore if no connection limit assigned */ 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 /* Initialize key */ 00278 if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, key)) 00279 { 00280 /* Allow unhandled address types through */ 00281 free (key); 00282 return MHD_YES; 00283 } 00284 00285 MHD_ip_count_lock (daemon); 00286 00287 /* Search for the IP address */ 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 /* If we got an existing node back, free the one we created */ 00302 if (node != key) 00303 free(key); 00304 key = (struct MHD_IPCount*)node; 00305 00306 /* Test if there is room for another connection; if so, 00307 * increment count */ 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 /* Ignore if no connection limit assigned */ 00336 if (daemon->per_ip_connection_limit == 0) 00337 return; 00338 00339 /* Initialize search key */ 00340 if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, &search_key)) 00341 return; 00342 00343 MHD_ip_count_lock (daemon); 00344 00345 /* Search for the IP address */ 00346 node = (void*)TFIND (&search_key, &daemon->per_ip_connection_count, MHD_ip_addr_compare); 00347 00348 /* Something's wrong if we couldn't find an IP address 00349 * that was previously added */ 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 /* Validate existing count for IP address */ 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 /* Remove the node entirely if count reduces to 0 */ 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 if (daemon->https_mem_trust) { 00443 cert.data = (unsigned char *) daemon->https_mem_trust; 00444 cert.size = strlen(daemon->https_mem_trust); 00445 if (gnutls_certificate_set_x509_trust_mem(daemon->x509_cred, &cert, 00446 GNUTLS_X509_FMT_PEM) < 0) { 00447 #if HAVE_MESSAGES 00448 MHD_DLOG(daemon, 00449 "Bad trust certificate format\n"); 00450 #endif 00451 return -1; 00452 } 00453 } 00454 00455 /* certificate & key loaded from memory */ 00456 if (daemon->https_mem_cert && daemon->https_mem_key) 00457 { 00458 key.data = (unsigned char *) daemon->https_mem_key; 00459 key.size = strlen (daemon->https_mem_key); 00460 cert.data = (unsigned char *) daemon->https_mem_cert; 00461 cert.size = strlen (daemon->https_mem_cert); 00462 00463 return gnutls_certificate_set_x509_key_mem (daemon->x509_cred, 00464 &cert, &key, 00465 GNUTLS_X509_FMT_PEM); 00466 } 00467 #if HAVE_MESSAGES 00468 MHD_DLOG (daemon, "You need to specify a certificate and key location\n"); 00469 #endif 00470 return -1; 00471 } 00472 00479 static int 00480 MHD_TLS_init (struct MHD_Daemon *daemon) 00481 { 00482 switch (daemon->cred_type) 00483 { 00484 case GNUTLS_CRD_CERTIFICATE: 00485 if (0 != 00486 gnutls_certificate_allocate_credentials (&daemon->x509_cred)) 00487 return GNUTLS_E_MEMORY_ERROR; 00488 return MHD_init_daemon_certificate (daemon); 00489 default: 00490 #if HAVE_MESSAGES 00491 MHD_DLOG (daemon, 00492 "Error: invalid credentials type %d specified.\n", 00493 daemon->cred_type); 00494 #endif 00495 return -1; 00496 } 00497 } 00498 #endif 00499 00513 int 00514 MHD_get_fdset (struct MHD_Daemon *daemon, 00515 fd_set * read_fd_set, 00516 fd_set * write_fd_set, fd_set * except_fd_set, int *max_fd) 00517 { 00518 struct MHD_Connection *con_itr; 00519 int fd; 00520 00521 if ((daemon == NULL) || (read_fd_set == NULL) || (write_fd_set == NULL) 00522 || (except_fd_set == NULL) || (max_fd == NULL) 00523 || (-1 == (fd = daemon->socket_fd)) || (daemon->shutdown == MHD_YES) 00524 || ((daemon->options & MHD_USE_THREAD_PER_CONNECTION) != 0) 00525 || ((daemon->options & MHD_USE_POLL) != 0)) 00526 return MHD_NO; 00527 00528 FD_SET (fd, read_fd_set); 00529 /* update max file descriptor */ 00530 if ((*max_fd) < fd) 00531 *max_fd = fd; 00532 00533 con_itr = daemon->connections; 00534 while (con_itr != NULL) 00535 { 00536 if (MHD_YES != MHD_connection_get_fdset (con_itr, 00537 read_fd_set, 00538 write_fd_set, 00539 except_fd_set, max_fd)) 00540 return MHD_NO; 00541 con_itr = con_itr->next; 00542 } 00543 #if DEBUG_CONNECT 00544 MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd); 00545 #endif 00546 return MHD_YES; 00547 } 00548 00556 static void * 00557 MHD_handle_connection (void *data) 00558 { 00559 struct MHD_Connection *con = data; 00560 int num_ready; 00561 fd_set rs; 00562 fd_set ws; 00563 fd_set es; 00564 int max; 00565 struct timeval tv; 00566 unsigned int timeout; 00567 #ifdef HAVE_POLL_H 00568 struct MHD_Pollfd mp; 00569 struct pollfd p; 00570 #endif 00571 00572 timeout = con->daemon->connection_timeout; 00573 while ((!con->daemon->shutdown) && (con->socket_fd != -1)) { 00574 tv.tv_usec = 0; 00575 if ( (timeout > (time (NULL) - con->last_activity)) || 00576 (timeout == 0) ) 00577 { 00578 /* in case we are missing the SIGALRM, keep going after 00579 at most 1s; see http://lists.gnu.org/archive/html/libmicrohttpd/2009-10/msg00013.html */ 00580 tv.tv_sec = 1; 00581 if ((con->state == MHD_CONNECTION_NORMAL_BODY_UNREADY) || 00582 (con->state == MHD_CONNECTION_CHUNKED_BODY_UNREADY)) 00583 { 00584 /* do not block (we're waiting for our callback to succeed) */ 00585 tv.tv_sec = 0; 00586 } 00587 } 00588 else 00589 { 00590 tv.tv_sec = 0; 00591 } 00592 #ifdef HAVE_POLL_H 00593 if (0 == (con->daemon->options & MHD_USE_POLL)) { 00594 #else 00595 { 00596 #endif 00597 /* use select */ 00598 FD_ZERO (&rs); 00599 FD_ZERO (&ws); 00600 FD_ZERO (&es); 00601 max = 0; 00602 MHD_connection_get_fdset (con, &rs, &ws, &es, &max); 00603 num_ready = SELECT (max + 1, &rs, &ws, &es, &tv); 00604 if (num_ready < 0) { 00605 if (errno == EINTR) 00606 continue; 00607 #if HAVE_MESSAGES 00608 MHD_DLOG (con->daemon, "Error during select (%d): `%s'\n", max, 00609 STRERROR (errno)); 00610 #endif 00611 break; 00612 } 00613 /* call appropriate connection handler if necessary */ 00614 if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &rs))) 00615 con->read_handler (con); 00616 if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &ws))) 00617 con->write_handler (con); 00618 if (con->socket_fd != -1) 00619 con->idle_handler (con); 00620 } 00621 #ifdef HAVE_POLL_H 00622 else 00623 { 00624 /* use poll */ 00625 memset(&mp, 0, sizeof (struct MHD_Pollfd)); 00626 MHD_connection_get_pollfd(con, &mp); 00627 memset(&p, 0, sizeof (struct pollfd)); 00628 p.fd = mp.fd; 00629 if (mp.events & MHD_POLL_ACTION_IN) 00630 p.events |= POLLIN; 00631 if (mp.events & MHD_POLL_ACTION_OUT) 00632 p.events |= POLLOUT; 00633 /* in case we are missing the SIGALRM, keep going after 00634 at most 1s */ 00635 if (poll (&p, 1, 1000) < 0) { 00636 if (errno == EINTR) 00637 continue; 00638 #if HAVE_MESSAGES 00639 MHD_DLOG (con->daemon, "Error during poll: `%s'\n", 00640 STRERROR (errno)); 00641 #endif 00642 break; 00643 } 00644 if ( (con->socket_fd != -1) && 00645 (0 != (p.revents & POLLIN)) ) 00646 con->read_handler (con); 00647 if ( (con->socket_fd != -1) && 00648 (0 != (p.revents & POLLOUT)) ) 00649 con->write_handler (con); 00650 if (con->socket_fd != -1) 00651 con->idle_handler (con); 00652 if ( (con->socket_fd != -1) && 00653 (0 != (p.revents & (POLLERR | POLLHUP))) ) 00654 MHD_connection_close (con, MHD_REQUEST_TERMINATED_WITH_ERROR); 00655 } 00656 #endif 00657 } 00658 if (con->socket_fd != -1) 00659 { 00660 #if DEBUG_CLOSE 00661 #if HAVE_MESSAGES 00662 MHD_DLOG (con->daemon, 00663 "Processing thread terminating, closing connection\n"); 00664 #endif 00665 #endif 00666 MHD_connection_close (con, MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); 00667 } 00668 return NULL; 00669 } 00670 00679 static ssize_t 00680 recv_param_adapter (struct MHD_Connection *connection, void *other, size_t i) 00681 { 00682 if (connection->socket_fd == -1) 00683 return -1; 00684 if (0 != (connection->daemon->options & MHD_USE_SSL)) 00685 return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL); 00686 return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL | MSG_DONTWAIT); 00687 } 00688 00697 static ssize_t 00698 send_param_adapter (struct MHD_Connection *connection, 00699 const void *other, size_t i) 00700 { 00701 #if LINUX 00702 int fd; 00703 off_t offset; 00704 int ret; 00705 #endif 00706 if (connection->socket_fd == -1) 00707 return -1; 00708 if (0 != (connection->daemon->options & MHD_USE_SSL)) 00709 return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL); 00710 #if LINUX 00711 if ( (connection->write_buffer_append_offset == 00712 connection->write_buffer_send_offset) && 00713 (NULL != connection->response) && 00714 (-1 != (fd = connection->response->fd)) ) 00715 { 00716 /* can use sendfile */ 00717 offset = (off_t) connection->response_write_position + connection->response->fd_off; 00718 ret = sendfile (connection->socket_fd, 00719 fd, 00720 &offset, 00721 connection->response->total_size - offset); 00722 if ( (ret == -1) && 00723 (errno == EINTR) ) 00724 return 0; 00725 return ret; 00726 } 00727 #endif 00728 return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL | MSG_DONTWAIT); 00729 } 00730 00731 00732 #if HTTPS_SUPPORT 00733 00737 static void 00738 socket_set_nonblocking (int fd) 00739 { 00740 #if MINGW 00741 u_long mode; 00742 mode = 1; 00743 if (ioctlsocket (fd, FIONBIO, &mode) == SOCKET_ERROR) 00744 { 00745 SetErrnoFromWinsockError (WSAGetLastError ()); 00746 #if HAVE_MESSAGES 00747 FPRINTF(stderr, "Failed to make socket non-blocking: %s\n", 00748 STRERROR (errno)); 00749 #endif 00750 } 00751 #else 00752 00753 /* not MINGW */ 00754 int flags = fcntl (fd, F_GETFL); 00755 if ( (flags == -1) || 00756 (0 != fcntl (fd, F_SETFL, flags | O_NONBLOCK)) ) 00757 { 00758 #if HAVE_MESSAGES 00759 FPRINTF(stderr, "Failed to make socket non-blocking: %s\n", 00760 STRERROR (errno)); 00761 #endif 00762 } 00763 #endif 00764 } 00765 #endif 00766 00767 00777 static int 00778 create_thread (pthread_t * thread, 00779 const struct MHD_Daemon *daemon, 00780 void *(*start_routine)(void*), 00781 void *arg) 00782 { 00783 pthread_attr_t attr; 00784 pthread_attr_t *pattr; 00785 int ret; 00786 00787 if (daemon->thread_stack_size != 0) 00788 { 00789 if (0 != (ret = pthread_attr_init (&attr))) 00790 goto ERR; 00791 if (0 != (ret = pthread_attr_setstacksize (&attr, daemon->thread_stack_size))) 00792 { 00793 pthread_attr_destroy (&attr); 00794 goto ERR; 00795 } 00796 pattr = &attr; 00797 } 00798 else 00799 { 00800 pattr = NULL; 00801 } 00802 ret = pthread_create (thread, pattr, 00803 start_routine, arg); 00804 if (daemon->thread_stack_size != 0) 00805 pthread_attr_destroy (&attr); 00806 return ret; 00807 ERR: 00808 #if HAVE_MESSAGES 00809 MHD_DLOG (daemon, 00810 "Failed to set thread stack size\n"); 00811 #endif 00812 errno = EINVAL; 00813 return ret; 00814 } 00815 00816 00817 00826 static int 00827 MHD_accept_connection (struct MHD_Daemon *daemon) 00828 { 00829 struct MHD_Connection *connection; 00830 #if HAVE_INET6 00831 struct sockaddr_in6 addrstorage; 00832 #else 00833 struct sockaddr_in addrstorage; 00834 #endif 00835 struct sockaddr *addr = (struct sockaddr *) &addrstorage; 00836 socklen_t addrlen; 00837 int s; 00838 int res_thread_create; 00839 #if OSX 00840 static int on = 1; 00841 #endif 00842 00843 addrlen = sizeof (addrstorage); 00844 memset (addr, 0, sizeof (addrstorage)); 00845 00846 s = ACCEPT (daemon->socket_fd, addr, &addrlen); 00847 if ((s == -1) || (addrlen <= 0)) 00848 { 00849 #if HAVE_MESSAGES 00850 /* This could be a common occurance with multiple worker threads */ 00851 if ((EAGAIN != errno) && (EWOULDBLOCK != errno)) 00852 MHD_DLOG (daemon, "Error accepting connection: %s\n", STRERROR (errno)); 00853 #endif 00854 if (s != -1) 00855 { 00856 SHUTDOWN (s, SHUT_RDWR); 00857 CLOSE (s); 00858 /* just in case */ 00859 } 00860 return MHD_NO; 00861 } 00862 #ifndef WINDOWS 00863 if ( (s >= FD_SETSIZE) && 00864 (0 == (daemon->options & MHD_USE_POLL)) ) 00865 { 00866 #if HAVE_MESSAGES 00867 MHD_DLOG (daemon, 00868 "Socket descriptor larger than FD_SETSIZE: %d > %d\n", 00869 s, 00870 FD_SETSIZE); 00871 #endif 00872 CLOSE (s); 00873 return MHD_NO; 00874 } 00875 #endif 00876 00877 00878 #if HAVE_MESSAGES 00879 #if DEBUG_CONNECT 00880 MHD_DLOG (daemon, "Accepted connection on socket %d\n", s); 00881 #endif 00882 #endif 00883 if ((daemon->max_connections == 0) 00884 || (MHD_ip_limit_add (daemon, addr, addrlen) == MHD_NO)) 00885 { 00886 /* above connection limit - reject */ 00887 #if HAVE_MESSAGES 00888 MHD_DLOG (daemon, 00889 "Server reached connection limit (closing inbound connection)\n"); 00890 #endif 00891 SHUTDOWN (s, SHUT_RDWR); 00892 CLOSE (s); 00893 return MHD_NO; 00894 } 00895 00896 /* apply connection acceptance policy if present */ 00897 if ((daemon->apc != NULL) 00898 && (MHD_NO == daemon->apc (daemon->apc_cls, addr, addrlen))) 00899 { 00900 #if DEBUG_CLOSE 00901 #if HAVE_MESSAGES 00902 MHD_DLOG (daemon, "Connection rejected, closing connection\n"); 00903 #endif 00904 #endif 00905 SHUTDOWN (s, SHUT_RDWR); 00906 CLOSE (s); 00907 MHD_ip_limit_del (daemon, addr, addrlen); 00908 return MHD_YES; 00909 } 00910 #if OSX 00911 #ifdef SOL_SOCKET 00912 #ifdef SO_NOSIGPIPE 00913 setsockopt (s, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof (on)); 00914 #endif 00915 #endif 00916 #endif 00917 connection = malloc (sizeof (struct MHD_Connection)); 00918 if (NULL == connection) 00919 { 00920 #if HAVE_MESSAGES 00921 MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno)); 00922 #endif 00923 SHUTDOWN (s, SHUT_RDWR); 00924 CLOSE (s); 00925 MHD_ip_limit_del (daemon, addr, addrlen); 00926 return MHD_NO; 00927 } 00928 memset (connection, 0, sizeof (struct MHD_Connection)); 00929 connection->pool = NULL; 00930 connection->addr = malloc (addrlen); 00931 if (connection->addr == NULL) 00932 { 00933 #if HAVE_MESSAGES 00934 MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno)); 00935 #endif 00936 SHUTDOWN (s, SHUT_RDWR); 00937 CLOSE (s); 00938 MHD_ip_limit_del (daemon, addr, addrlen); 00939 free (connection); 00940 return MHD_NO; 00941 } 00942 memcpy (connection->addr, addr, addrlen); 00943 connection->addr_len = addrlen; 00944 connection->socket_fd = s; 00945 connection->daemon = daemon; 00946 connection->last_activity = time (NULL); 00947 00948 /* set default connection handlers */ 00949 MHD_set_http_callbacks_ (connection); 00950 connection->recv_cls = &recv_param_adapter; 00951 connection->send_cls = &send_param_adapter; 00952 #if HTTPS_SUPPORT 00953 if (0 != (daemon->options & MHD_USE_SSL)) 00954 { 00955 connection->recv_cls = &recv_tls_adapter; 00956 connection->send_cls = &send_tls_adapter; 00957 connection->state = MHD_TLS_CONNECTION_INIT; 00958 MHD_set_https_callbacks (connection); 00959 gnutls_init (&connection->tls_session, GNUTLS_SERVER); 00960 gnutls_priority_set (connection->tls_session, 00961 daemon->priority_cache); 00962 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 00963 { 00964 /* use non-blocking IO for gnutls */ 00965 socket_set_nonblocking (connection->socket_fd); 00966 } 00967 switch (connection->daemon->cred_type) 00968 { 00969 /* set needed credentials for certificate authentication. */ 00970 case GNUTLS_CRD_CERTIFICATE: 00971 gnutls_credentials_set (connection->tls_session, 00972 GNUTLS_CRD_CERTIFICATE, 00973 connection->daemon->x509_cred); 00974 break; 00975 default: 00976 #if HAVE_MESSAGES 00977 MHD_DLOG (connection->daemon, 00978 "Failed to setup TLS credentials: unknown credential type %d\n", 00979 connection->daemon->cred_type); 00980 #endif 00981 SHUTDOWN (s, SHUT_RDWR); 00982 CLOSE (s); 00983 MHD_ip_limit_del (daemon, addr, addrlen); 00984 free (connection->addr); 00985 free (connection); 00986 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, 00987 #if HAVE_MESSAGES 00988 "Unknown credential type" 00989 #else 00990 NULL 00991 #endif 00992 ); 00993 return MHD_NO; 00994 } 00995 gnutls_transport_set_ptr (connection->tls_session, 00996 (gnutls_transport_ptr_t) connection); 00997 gnutls_transport_set_pull_function (connection->tls_session, 00998 (gnutls_pull_func) & 00999 recv_param_adapter); 01000 gnutls_transport_set_push_function (connection->tls_session, 01001 (gnutls_push_func) & 01002 send_param_adapter); 01003 01004 if (daemon->https_mem_trust){ 01005 gnutls_certificate_server_set_request(connection->tls_session, GNUTLS_CERT_REQUEST); 01006 } 01007 } 01008 #endif 01009 01010 /* attempt to create handler thread */ 01011 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 01012 { 01013 res_thread_create = create_thread (&connection->pid, daemon, 01014 &MHD_handle_connection, connection); 01015 if (res_thread_create != 0) 01016 { 01017 #if HAVE_MESSAGES 01018 MHD_DLOG (daemon, "Failed to create a thread: %s\n", 01019 STRERROR (res_thread_create)); 01020 #endif 01021 SHUTDOWN (s, SHUT_RDWR); 01022 CLOSE (s); 01023 MHD_ip_limit_del (daemon, addr, addrlen); 01024 free (connection->addr); 01025 free (connection); 01026 return MHD_NO; 01027 } 01028 } 01029 connection->next = daemon->connections; 01030 daemon->connections = connection; 01031 daemon->max_connections--; 01032 return MHD_YES; 01033 } 01034 01042 static void 01043 MHD_cleanup_connections (struct MHD_Daemon *daemon) 01044 { 01045 struct MHD_Connection *pos; 01046 struct MHD_Connection *prev; 01047 void *unused; 01048 int rc; 01049 01050 pos = daemon->connections; 01051 prev = NULL; 01052 while (pos != NULL) 01053 { 01054 if ((pos->socket_fd == -1) || 01055 (((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && 01056 (daemon->shutdown) && (pos->socket_fd != -1)))) 01057 { 01058 if (prev == NULL) 01059 daemon->connections = pos->next; 01060 else 01061 prev->next = pos->next; 01062 if (0 != (pos->daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 01063 { 01064 pthread_kill (pos->pid, SIGALRM); 01065 if (0 != (rc = pthread_join (pos->pid, &unused))) 01066 { 01067 #if HAVE_MESSAGES 01068 MHD_DLOG (daemon, "Failed to join a thread: %s\n", 01069 STRERROR (rc)); 01070 #endif 01071 abort(); 01072 } 01073 } 01074 MHD_pool_destroy (pos->pool); 01075 #if HTTPS_SUPPORT 01076 if (pos->tls_session != NULL) 01077 gnutls_deinit (pos->tls_session); 01078 #endif 01079 MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len); 01080 if (pos->response != NULL) 01081 { 01082 MHD_destroy_response (pos->response); 01083 pos->response = NULL; 01084 } 01085 free (pos->addr); 01086 free (pos); 01087 daemon->max_connections++; 01088 if (prev == NULL) 01089 pos = daemon->connections; 01090 else 01091 pos = prev->next; 01092 continue; 01093 } 01094 prev = pos; 01095 pos = pos->next; 01096 } 01097 } 01098 01111 int 01112 MHD_get_timeout (struct MHD_Daemon *daemon, unsigned MHD_LONG_LONG *timeout) 01113 { 01114 time_t earliest_deadline; 01115 time_t now; 01116 struct MHD_Connection *pos; 01117 unsigned int dto; 01118 01119 dto = daemon->connection_timeout; 01120 if (0 == dto) 01121 return MHD_NO; 01122 pos = daemon->connections; 01123 if (pos == NULL) 01124 return MHD_NO; /* no connections */ 01125 now = time (NULL); 01126 /* start with conservative estimate */ 01127 earliest_deadline = now + dto; 01128 while (pos != NULL) 01129 { 01130 if (earliest_deadline > pos->last_activity + dto) 01131 earliest_deadline = pos->last_activity + dto; 01132 #if HTTPS_SUPPORT 01133 if ( (0 != (daemon->options & MHD_USE_SSL)) && 01134 (0 != gnutls_record_check_pending (pos->tls_session)) ) 01135 earliest_deadline = now; 01136 #endif 01137 pos = pos->next; 01138 } 01139 if (earliest_deadline < now) 01140 *timeout = 0; 01141 else 01142 *timeout = (earliest_deadline - now); 01143 return MHD_YES; 01144 } 01145 01146 01154 static int 01155 MHD_select (struct MHD_Daemon *daemon, int may_block) 01156 { 01157 struct MHD_Connection *pos; 01158 int num_ready; 01159 fd_set rs; 01160 fd_set ws; 01161 fd_set es; 01162 int max; 01163 struct timeval timeout; 01164 unsigned MHD_LONG_LONG ltimeout; 01165 int ds; 01166 01167 timeout.tv_sec = 0; 01168 timeout.tv_usec = 0; 01169 if (daemon->shutdown == MHD_YES) 01170 return MHD_NO; 01171 FD_ZERO (&rs); 01172 FD_ZERO (&ws); 01173 FD_ZERO (&es); 01174 max = 0; 01175 01176 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 01177 { 01178 /* single-threaded, go over everything */ 01179 if (MHD_NO == MHD_get_fdset (daemon, &rs, &ws, &es, &max)) 01180 return MHD_NO; 01181 01182 /* If we're at the connection limit, no need to 01183 accept new connections. */ 01184 if ( (daemon->max_connections == 0) && (daemon->socket_fd != -1) ) 01185 FD_CLR(daemon->socket_fd, &rs); 01186 } 01187 else 01188 { 01189 /* accept only, have one thread per connection */ 01190 max = daemon->socket_fd; 01191 if (max == -1) 01192 return MHD_NO; 01193 FD_SET (max, &rs); 01194 } 01195 01196 /* in case we are missing the SIGALRM, keep going after 01197 at most 1s; see http://lists.gnu.org/archive/html/libmicrohttpd/2009-10/msg00013.html */ 01198 timeout.tv_usec = 0; 01199 timeout.tv_sec = 1; 01200 if (may_block == MHD_NO) 01201 { 01202 timeout.tv_usec = 0; 01203 timeout.tv_sec = 0; 01204 } 01205 else 01206 { 01207 /* ltimeout is in ms */ 01208 if ( (MHD_YES == MHD_get_timeout (daemon, <imeout)) && 01209 (ltimeout < 1000) ) 01210 { 01211 timeout.tv_usec = ltimeout * 1000; 01212 timeout.tv_sec = 0; 01213 } 01214 } 01215 num_ready = SELECT (max + 1, &rs, &ws, &es, &timeout); 01216 01217 if (daemon->shutdown == MHD_YES) 01218 return MHD_NO; 01219 if (num_ready < 0) 01220 { 01221 if (errno == EINTR) 01222 return MHD_YES; 01223 #if HAVE_MESSAGES 01224 MHD_DLOG (daemon, "select failed: %s\n", STRERROR (errno)); 01225 #endif 01226 return MHD_NO; 01227 } 01228 ds = daemon->socket_fd; 01229 if (ds == -1) 01230 return MHD_YES; 01231 01232 /* select connection thread handling type */ 01233 if (FD_ISSET (ds, &rs)) 01234 MHD_accept_connection (daemon); 01235 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 01236 { 01237 /* do not have a thread per connection, process all connections now */ 01238 pos = daemon->connections; 01239 while (pos != NULL) 01240 { 01241 ds = pos->socket_fd; 01242 if (ds != -1) 01243 { 01244 /* TODO call con->read handler */ 01245 if (FD_ISSET (ds, &rs)) 01246 pos->read_handler (pos); 01247 if ((pos->socket_fd != -1) && (FD_ISSET (ds, &ws))) 01248 pos->write_handler (pos); 01249 if (pos->socket_fd != -1) 01250 pos->idle_handler (pos); 01251 } 01252 pos = pos->next; 01253 } 01254 } 01255 return MHD_YES; 01256 } 01257 01263 static int 01264 MHD_poll (struct MHD_Daemon *daemon) 01265 { 01266 #ifdef HAVE_POLL_H 01267 struct pollfd p; 01268 01269 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 01270 return MHD_NO; 01271 p.fd = daemon->socket_fd; 01272 p.events = POLLIN; 01273 p.revents = 0; 01274 01275 if (poll(&p, 1, 1000) < 0) { 01276 if (errno == EINTR) 01277 return MHD_YES; 01278 #if HAVE_MESSAGES 01279 MHD_DLOG (daemon, "poll failed: %s\n", STRERROR (errno)); 01280 #endif 01281 return MHD_NO; 01282 } 01283 /* handle shutdown cases */ 01284 if (daemon->shutdown == MHD_YES) 01285 return MHD_NO; 01286 if (daemon->socket_fd < 0) 01287 return MHD_YES; 01288 if (0 != (p.revents & POLLIN)) 01289 MHD_accept_connection (daemon); 01290 return MHD_YES; 01291 #else 01292 return MHD_NO; 01293 #endif 01294 } 01295 01296 01307 int 01308 MHD_run (struct MHD_Daemon *daemon) 01309 { 01310 if ((daemon->shutdown != MHD_NO) || (0 != (daemon->options 01311 & MHD_USE_THREAD_PER_CONNECTION)) 01312 || (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY))) 01313 return MHD_NO; 01314 MHD_select (daemon, MHD_NO); 01315 MHD_cleanup_connections (daemon); 01316 return MHD_YES; 01317 } 01318 01319 01327 static void * 01328 MHD_select_thread (void *cls) 01329 { 01330 struct MHD_Daemon *daemon = cls; 01331 while (daemon->shutdown == MHD_NO) 01332 { 01333 if ((daemon->options & MHD_USE_POLL) == 0) 01334 MHD_select (daemon, MHD_YES); 01335 else 01336 MHD_poll(daemon); 01337 MHD_cleanup_connections (daemon); 01338 } 01339 return NULL; 01340 } 01341 01342 01354 struct MHD_Daemon * 01355 MHD_start_daemon (unsigned int options, 01356 uint16_t port, 01357 MHD_AcceptPolicyCallback apc, 01358 void *apc_cls, 01359 MHD_AccessHandlerCallback dh, void *dh_cls, ...) 01360 { 01361 struct MHD_Daemon *ret; 01362 va_list ap; 01363 01364 va_start (ap, dh_cls); 01365 ret = MHD_start_daemon_va (options, port, apc, apc_cls, dh, dh_cls, ap); 01366 va_end (ap); 01367 return ret; 01368 } 01369 01370 01371 typedef void (*VfprintfFunctionPointerType)(void *, const char *, va_list); 01372 01373 01382 static int 01383 parse_options_va (struct MHD_Daemon *daemon, 01384 const struct sockaddr **servaddr, 01385 va_list ap); 01386 01387 01396 static int 01397 parse_options (struct MHD_Daemon *daemon, 01398 const struct sockaddr **servaddr, 01399 ...) 01400 { 01401 va_list ap; 01402 int ret; 01403 01404 va_start (ap, servaddr); 01405 ret = parse_options_va (daemon, servaddr, ap); 01406 va_end (ap); 01407 return ret; 01408 } 01409 01410 01419 static int 01420 parse_options_va (struct MHD_Daemon *daemon, 01421 const struct sockaddr **servaddr, 01422 va_list ap) 01423 { 01424 enum MHD_OPTION opt; 01425 struct MHD_OptionItem *oa; 01426 unsigned int i; 01427 #if HTTPS_SUPPORT 01428 int ret; 01429 const char *pstr; 01430 #endif 01431 01432 while (MHD_OPTION_END != (opt = va_arg (ap, enum MHD_OPTION))) 01433 { 01434 switch (opt) 01435 { 01436 case MHD_OPTION_CONNECTION_MEMORY_LIMIT: 01437 daemon->pool_size = va_arg (ap, size_t); 01438 break; 01439 case MHD_OPTION_CONNECTION_LIMIT: 01440 daemon->max_connections = va_arg (ap, unsigned int); 01441 break; 01442 case MHD_OPTION_CONNECTION_TIMEOUT: 01443 daemon->connection_timeout = va_arg (ap, unsigned int); 01444 break; 01445 case MHD_OPTION_NOTIFY_COMPLETED: 01446 daemon->notify_completed = 01447 va_arg (ap, MHD_RequestCompletedCallback); 01448 daemon->notify_completed_cls = va_arg (ap, void *); 01449 break; 01450 case MHD_OPTION_PER_IP_CONNECTION_LIMIT: 01451 daemon->per_ip_connection_limit = va_arg (ap, unsigned int); 01452 break; 01453 case MHD_OPTION_SOCK_ADDR: 01454 *servaddr = va_arg (ap, const struct sockaddr *); 01455 break; 01456 case MHD_OPTION_URI_LOG_CALLBACK: 01457 daemon->uri_log_callback = 01458 va_arg (ap, LogCallback); 01459 daemon->uri_log_callback_cls = va_arg (ap, void *); 01460 break; 01461 case MHD_OPTION_THREAD_POOL_SIZE: 01462 daemon->worker_pool_size = va_arg (ap, unsigned int); 01463 if (daemon->worker_pool_size >= SIZE_MAX / sizeof (struct MHD_Daemon)) 01464 { 01465 #if HAVE_MESSAGES 01466 FPRINTF (stderr, 01467 "Specified thread pool size (%u) too big\n", 01468 daemon->worker_pool_size); 01469 #endif 01470 return MHD_NO; 01471 } 01472 break; 01473 #if HTTPS_SUPPORT 01474 case MHD_OPTION_HTTPS_MEM_KEY: 01475 if (0 != (daemon->options & MHD_USE_SSL)) 01476 daemon->https_mem_key = va_arg (ap, const char *); 01477 #if HAVE_MESSAGES 01478 else 01479 FPRINTF (stderr, 01480 "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n", 01481 opt); 01482 #endif 01483 break; 01484 case MHD_OPTION_HTTPS_MEM_CERT: 01485 if (0 != (daemon->options & MHD_USE_SSL)) 01486 daemon->https_mem_cert = va_arg (ap, const char *); 01487 #if HAVE_MESSAGES 01488 else 01489 FPRINTF (stderr, 01490 "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n", 01491 opt); 01492 #endif 01493 break; 01494 case MHD_OPTION_HTTPS_MEM_TRUST: 01495 if (0 != (daemon->options & MHD_USE_SSL)) 01496 daemon->https_mem_trust = va_arg (ap, const char *); 01497 #if HAVE_MESSAGES 01498 else 01499 FPRINTF (stderr, 01500 "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n", 01501 opt); 01502 #endif 01503 break; 01504 case MHD_OPTION_HTTPS_CRED_TYPE: 01505 daemon->cred_type = va_arg (ap, gnutls_credentials_type_t); 01506 break; 01507 case MHD_OPTION_HTTPS_PRIORITIES: 01508 ret = gnutls_priority_init (&daemon->priority_cache, 01509 pstr = va_arg (ap, const char*), 01510 NULL); 01511 #if HAVE_MESSAGES 01512 if (ret != GNUTLS_E_SUCCESS) 01513 FPRINTF (stderr, 01514 "Setting priorities to `%s' failed: %s\n", 01515 pstr, 01516 gnutls_strerror (ret)); 01517 #endif 01518 if (ret != GNUTLS_E_SUCCESS) 01519 return MHD_NO; 01520 break; 01521 #endif 01522 #ifdef DAUTH_SUPPORT 01523 case MHD_OPTION_DIGEST_AUTH_RANDOM: 01524 daemon->digest_auth_rand_size = va_arg (ap, size_t); 01525 daemon->digest_auth_random = va_arg (ap, const char *); 01526 break; 01527 case MHD_OPTION_NONCE_NC_SIZE: 01528 daemon->nonce_nc_size = va_arg (ap, unsigned int); 01529 break; 01530 #endif 01531 case MHD_OPTION_LISTEN_SOCKET: 01532 daemon->socket_fd = va_arg (ap, int); 01533 break; 01534 case MHD_OPTION_EXTERNAL_LOGGER: 01535 #if HAVE_MESSAGES 01536 daemon->custom_error_log = 01537 va_arg (ap, VfprintfFunctionPointerType); 01538 daemon->custom_error_log_cls = va_arg (ap, void *); 01539 #else 01540 va_arg (ap, VfprintfFunctionPointerType); 01541 va_arg (ap, void *); 01542 #endif 01543 break; 01544 case MHD_OPTION_THREAD_STACK_SIZE: 01545 daemon->thread_stack_size = va_arg (ap, size_t); 01546 break; 01547 case MHD_OPTION_ARRAY: 01548 oa = va_arg (ap, struct MHD_OptionItem*); 01549 i = 0; 01550 while (MHD_OPTION_END != (opt = oa[i].option)) 01551 { 01552 switch (opt) 01553 { 01554 /* all options taking 'size_t' */ 01555 case MHD_OPTION_CONNECTION_MEMORY_LIMIT: 01556 case MHD_OPTION_THREAD_STACK_SIZE: 01557 if (MHD_YES != parse_options (daemon, 01558 servaddr, 01559 opt, 01560 (size_t) oa[i].value, 01561 MHD_OPTION_END)) 01562 return MHD_NO; 01563 break; 01564 /* all options taking 'unsigned int' */ 01565 case MHD_OPTION_NONCE_NC_SIZE: 01566 case MHD_OPTION_CONNECTION_LIMIT: 01567 case MHD_OPTION_CONNECTION_TIMEOUT: 01568 case MHD_OPTION_PER_IP_CONNECTION_LIMIT: 01569 case MHD_OPTION_THREAD_POOL_SIZE: 01570 if (MHD_YES != parse_options (daemon, 01571 servaddr, 01572 opt, 01573 (unsigned int) oa[i].value, 01574 MHD_OPTION_END)) 01575 return MHD_NO; 01576 break; 01577 /* all options taking 'int' or 'enum' */ 01578 case MHD_OPTION_HTTPS_CRED_TYPE: 01579 case MHD_OPTION_LISTEN_SOCKET: 01580 if (MHD_YES != parse_options (daemon, 01581 servaddr, 01582 opt, 01583 (int) oa[i].value, 01584 MHD_OPTION_END)) 01585 return MHD_NO; 01586 break; 01587 /* all options taking one pointer */ 01588 case MHD_OPTION_SOCK_ADDR: 01589 case MHD_OPTION_HTTPS_MEM_KEY: 01590 case MHD_OPTION_HTTPS_MEM_CERT: 01591 case MHD_OPTION_HTTPS_MEM_TRUST: 01592 case MHD_OPTION_HTTPS_PRIORITIES: 01593 case MHD_OPTION_ARRAY: 01594 if (MHD_YES != parse_options (daemon, 01595 servaddr, 01596 opt, 01597 oa[i].ptr_value, 01598 MHD_OPTION_END)) 01599 return MHD_NO; 01600 break; 01601 /* all options taking two pointers */ 01602 case MHD_OPTION_NOTIFY_COMPLETED: 01603 case MHD_OPTION_URI_LOG_CALLBACK: 01604 case MHD_OPTION_EXTERNAL_LOGGER: 01605 case MHD_OPTION_UNESCAPE_CALLBACK: 01606 if (MHD_YES != parse_options (daemon, 01607 servaddr, 01608 opt, 01609 (void *) oa[i].value, 01610 oa[i].ptr_value, 01611 MHD_OPTION_END)) 01612 return MHD_NO; 01613 break; 01614 /* options taking size_t-number followed by pointer */ 01615 case MHD_OPTION_DIGEST_AUTH_RANDOM: 01616 if (MHD_YES != parse_options (daemon, 01617 servaddr, 01618 opt, 01619 (size_t) oa[i].value, 01620 oa[i].ptr_value, 01621 MHD_OPTION_END)) 01622 return MHD_NO; 01623 break; 01624 default: 01625 return MHD_NO; 01626 } 01627 i++; 01628 } 01629 break; 01630 case MHD_OPTION_UNESCAPE_CALLBACK: 01631 daemon->unescape_callback = 01632 va_arg (ap, UnescapeCallback); 01633 daemon->unescape_callback_cls = va_arg (ap, void *); 01634 break; 01635 default: 01636 #if HAVE_MESSAGES 01637 if (((opt >= MHD_OPTION_HTTPS_MEM_KEY) && 01638 (opt <= MHD_OPTION_HTTPS_PRIORITIES)) || (opt == MHD_OPTION_HTTPS_MEM_TRUST)) 01639 { 01640 FPRINTF (stderr, 01641 "MHD HTTPS option %d passed to MHD compiled without HTTPS support\n", 01642 opt); 01643 } 01644 else 01645 { 01646 FPRINTF (stderr, 01647 "Invalid option %d! (Did you terminate the list with MHD_OPTION_END?)\n", 01648 opt); 01649 } 01650 #endif 01651 return MHD_NO; 01652 } 01653 } 01654 return MHD_YES; 01655 } 01656 01657 01669 struct MHD_Daemon * 01670 MHD_start_daemon_va (unsigned int options, 01671 uint16_t port, 01672 MHD_AcceptPolicyCallback apc, 01673 void *apc_cls, 01674 MHD_AccessHandlerCallback dh, void *dh_cls, 01675 va_list ap) 01676 { 01677 const int on = 1; 01678 struct MHD_Daemon *retVal; 01679 int socket_fd; 01680 struct sockaddr_in servaddr4; 01681 #if HAVE_INET6 01682 struct sockaddr_in6 servaddr6; 01683 #endif 01684 const struct sockaddr *servaddr = NULL; 01685 socklen_t addrlen; 01686 unsigned int i; 01687 int res_thread_create; 01688 01689 if ((port == 0) || (dh == NULL)) 01690 return NULL; 01691 retVal = malloc (sizeof (struct MHD_Daemon)); 01692 if (retVal == NULL) 01693 return NULL; 01694 memset (retVal, 0, sizeof (struct MHD_Daemon)); 01695 #if HTTPS_SUPPORT 01696 if (options & MHD_USE_SSL) 01697 { 01698 gnutls_priority_init (&retVal->priority_cache, 01699 "NORMAL", 01700 NULL); 01701 } 01702 #endif 01703 retVal->socket_fd = -1; 01704 retVal->options = (enum MHD_OPTION)options; 01705 retVal->port = port; 01706 retVal->apc = apc; 01707 retVal->apc_cls = apc_cls; 01708 retVal->default_handler = dh; 01709 retVal->default_handler_cls = dh_cls; 01710 retVal->max_connections = MHD_MAX_CONNECTIONS_DEFAULT; 01711 retVal->pool_size = MHD_POOL_SIZE_DEFAULT; 01712 retVal->unescape_callback = &MHD_http_unescape; 01713 retVal->connection_timeout = 0; /* no timeout */ 01714 #ifdef DAUTH_SUPPORT 01715 retVal->digest_auth_rand_size = 0; 01716 retVal->digest_auth_random = NULL; 01717 retVal->nonce_nc_size = 4; /* tiny */ 01718 #endif 01719 #if HAVE_MESSAGES 01720 retVal->custom_error_log = 01721 (void (*)(void *, const char *, va_list)) &vfprintf; 01722 retVal->custom_error_log_cls = stderr; 01723 #endif 01724 #if HTTPS_SUPPORT 01725 if (options & MHD_USE_SSL) 01726 { 01727 /* lock MHD_gnutls_global mutex since it uses reference counting */ 01728 if (0 != pthread_mutex_lock (&MHD_gnutls_init_mutex)) 01729 { 01730 #if HAVE_MESSAGES 01731 MHD_DLOG (retVal, "Failed to aquire gnutls mutex\n"); 01732 #endif 01733 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); 01734 } 01735 if (0 != pthread_mutex_unlock (&MHD_gnutls_init_mutex)) 01736 { 01737 #if HAVE_MESSAGES 01738 MHD_DLOG (retVal, "Failed to release gnutls mutex\n"); 01739 #endif 01740 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); 01741 } 01742 retVal->cred_type = GNUTLS_CRD_CERTIFICATE; 01743 } 01744 #endif 01745 01746 if (MHD_YES != parse_options_va (retVal, &servaddr, ap)) 01747 { 01748 free (retVal); 01749 return NULL; 01750 } 01751 01752 #ifdef DAUTH_SUPPORT 01753 if (retVal->nonce_nc_size > 0) 01754 { 01755 if ( ( (size_t) (retVal->nonce_nc_size * sizeof(struct MHD_NonceNc))) / 01756 sizeof(struct MHD_NonceNc) != retVal->nonce_nc_size) 01757 { 01758 #if HAVE_MESSAGES 01759 MHD_DLOG (retVal, 01760 "Specified value for NC_SIZE too large\n"); 01761 #endif 01762 free (retVal); 01763 return NULL; 01764 } 01765 retVal->nnc = malloc (retVal->nonce_nc_size * sizeof(struct MHD_NonceNc)); 01766 if (NULL == retVal->nnc) 01767 { 01768 #if HAVE_MESSAGES 01769 MHD_DLOG (retVal, 01770 "Failed to allocate memory for nonce-nc map: %s\n", 01771 STRERROR (errno)); 01772 #endif 01773 free (retVal); 01774 return NULL; 01775 } 01776 } 01777 if (0 != pthread_mutex_init (&retVal->nnc_lock, NULL)) 01778 { 01779 #if HAVE_MESSAGES 01780 MHD_DLOG (retVal, 01781 "MHD failed to initialize nonce-nc mutex\n"); 01782 #endif 01783 free (retVal); 01784 return NULL; 01785 } 01786 #endif 01787 01788 /* poll support currently only works with MHD_USE_THREAD_PER_CONNECTION */ 01789 if ( (0 != (options & MHD_USE_POLL)) && 01790 (0 == (options & MHD_USE_THREAD_PER_CONNECTION)) ) 01791 { 01792 #if HAVE_MESSAGES 01793 MHD_DLOG (retVal, 01794 "MHD poll support only works with MHD_USE_THREAD_PER_CONNECTION\n"); 01795 #endif 01796 #if DAUTH_SUPPORT 01797 free (retVal->nnc); 01798 pthread_mutex_destroy (&retVal->nnc_lock); 01799 #endif 01800 free (retVal); 01801 return NULL; 01802 } 01803 01804 /* Thread pooling currently works only with internal select thread model */ 01805 if ( (0 == (options & MHD_USE_SELECT_INTERNALLY)) && 01806 (retVal->worker_pool_size > 0) ) 01807 { 01808 #if HAVE_MESSAGES 01809 MHD_DLOG (retVal, 01810 "MHD thread pooling only works with MHD_USE_SELECT_INTERNALLY\n"); 01811 #endif 01812 free (retVal); 01813 return NULL; 01814 } 01815 01816 #ifdef __SYMBIAN32__ 01817 if (0 != (options & (MHD_USE_SELECT_INTERNALLY | MHD_USE_THREAD_PER_CONNECTION))) 01818 { 01819 #if HAVE_MESSAGES 01820 MHD_DLOG (retVal, 01821 "Threaded operations are not supported on Symbian.\n"); 01822 #endif 01823 free (retVal); 01824 return NULL; 01825 } 01826 #endif 01827 if (retVal->socket_fd == -1) 01828 { 01829 if ((options & MHD_USE_IPv6) != 0) 01830 #if HAVE_INET6 01831 socket_fd = SOCKET (PF_INET6, SOCK_STREAM, 0); 01832 #else 01833 { 01834 #if HAVE_MESSAGES 01835 MHD_DLOG (retVal, 01836 "AF_INET6 not supported\n"); 01837 #endif 01838 free (retVal); 01839 return NULL; 01840 } 01841 #endif 01842 else 01843 socket_fd = SOCKET (PF_INET, SOCK_STREAM, 0); 01844 if (socket_fd == -1) 01845 { 01846 #if HAVE_MESSAGES 01847 if ((options & MHD_USE_DEBUG) != 0) 01848 MHD_DLOG (retVal, 01849 "Call to socket failed: %s\n", 01850 STRERROR (errno)); 01851 #endif 01852 free (retVal); 01853 return NULL; 01854 } 01855 if ((SETSOCKOPT (socket_fd, 01856 SOL_SOCKET, 01857 SO_REUSEADDR, 01858 &on, sizeof (on)) < 0) && ((options & MHD_USE_DEBUG) != 0)) 01859 { 01860 #if HAVE_MESSAGES 01861 MHD_DLOG (retVal, 01862 "setsockopt failed: %s\n", 01863 STRERROR (errno)); 01864 #endif 01865 } 01866 01867 /* check for user supplied sockaddr */ 01868 #if HAVE_INET6 01869 if ((options & MHD_USE_IPv6) != 0) 01870 addrlen = sizeof (struct sockaddr_in6); 01871 else 01872 #endif 01873 addrlen = sizeof (struct sockaddr_in); 01874 if (NULL == servaddr) 01875 { 01876 #if HAVE_INET6 01877 if ((options & MHD_USE_IPv6) != 0) 01878 { 01879 memset (&servaddr6, 0, sizeof (struct sockaddr_in6)); 01880 servaddr6.sin6_family = AF_INET6; 01881 servaddr6.sin6_port = htons (port); 01882 servaddr = (struct sockaddr *) &servaddr6; 01883 } 01884 else 01885 #endif 01886 { 01887 memset (&servaddr4, 0, sizeof (struct sockaddr_in)); 01888 servaddr4.sin_family = AF_INET; 01889 servaddr4.sin_port = htons (port); 01890 servaddr = (struct sockaddr *) &servaddr4; 01891 } 01892 } 01893 retVal->socket_fd = socket_fd; 01894 01895 if ((options & MHD_USE_IPv6) != 0) 01896 { 01897 #ifdef IPPROTO_IPV6 01898 #ifdef IPV6_V6ONLY 01899 /* Note: "IPV6_V6ONLY" is declared by Windows Vista ff., see "IPPROTO_IPV6 Socket Options" 01900 (http://msdn.microsoft.com/en-us/library/ms738574%28v=VS.85%29.aspx); 01901 and may also be missing on older POSIX systems; good luck if you have any of those, 01902 your IPv6 socket may then also bind against IPv4... */ 01903 #ifndef WINDOWS 01904 const int on = 1; 01905 setsockopt (socket_fd, 01906 IPPROTO_IPV6, IPV6_V6ONLY, 01907 &on, sizeof (on)); 01908 #else 01909 const char on = 1; 01910 setsockopt (socket_fd, 01911 IPPROTO_IPV6, IPV6_V6ONLY, 01912 &on, sizeof (on)); 01913 #endif 01914 #endif 01915 #endif 01916 } 01917 if (BIND (socket_fd, servaddr, addrlen) == -1) 01918 { 01919 #if HAVE_MESSAGES 01920 if ((options & MHD_USE_DEBUG) != 0) 01921 MHD_DLOG (retVal, 01922 "Failed to bind to port %u: %s\n", 01923 (unsigned int) port, 01924 STRERROR (errno)); 01925 #endif 01926 CLOSE (socket_fd); 01927 free (retVal); 01928 return NULL; 01929 } 01930 01931 if (LISTEN (socket_fd, 20) < 0) 01932 { 01933 #if HAVE_MESSAGES 01934 if ((options & MHD_USE_DEBUG) != 0) 01935 MHD_DLOG (retVal, 01936 "Failed to listen for connections: %s\n", 01937 STRERROR (errno)); 01938 #endif 01939 CLOSE (socket_fd); 01940 free (retVal); 01941 return NULL; 01942 } 01943 } 01944 else 01945 { 01946 socket_fd = retVal->socket_fd; 01947 } 01948 #ifndef WINDOWS 01949 if ( (socket_fd >= FD_SETSIZE) && 01950 (0 == (options & MHD_USE_POLL)) ) 01951 { 01952 #if HAVE_MESSAGES 01953 if ((options & MHD_USE_DEBUG) != 0) 01954 MHD_DLOG (retVal, 01955 "Socket descriptor larger than FD_SETSIZE: %d > %d\n", 01956 socket_fd, 01957 FD_SETSIZE); 01958 #endif 01959 CLOSE (socket_fd); 01960 free (retVal); 01961 return NULL; 01962 } 01963 #endif 01964 01965 if (0 != pthread_mutex_init (&retVal->per_ip_connection_mutex, NULL)) 01966 { 01967 #if HAVE_MESSAGES 01968 MHD_DLOG (retVal, 01969 "MHD failed to initialize IP connection limit mutex\n"); 01970 #endif 01971 CLOSE (socket_fd); 01972 free (retVal); 01973 return NULL; 01974 } 01975 01976 #if HTTPS_SUPPORT 01977 /* initialize HTTPS daemon certificate aspects & send / recv functions */ 01978 if ((0 != (options & MHD_USE_SSL)) && (0 != MHD_TLS_init (retVal))) 01979 { 01980 #if HAVE_MESSAGES 01981 MHD_DLOG (retVal, 01982 "Failed to initialize TLS support\n"); 01983 #endif 01984 CLOSE (socket_fd); 01985 #ifdef DAUTH_SUPPORT 01986 pthread_mutex_destroy (&retVal->nnc_lock); 01987 free (retVal->nnc); 01988 #endif 01989 pthread_mutex_destroy (&retVal->per_ip_connection_mutex); 01990 free (retVal); 01991 return NULL; 01992 } 01993 #endif 01994 if ( ( (0 != (options & MHD_USE_THREAD_PER_CONNECTION)) || 01995 ( (0 != (options & MHD_USE_SELECT_INTERNALLY)) && 01996 (0 == retVal->worker_pool_size)) ) && 01997 (0 != (res_thread_create = 01998 create_thread (&retVal->pid, retVal, &MHD_select_thread, retVal)))) 01999 { 02000 #if HAVE_MESSAGES 02001 MHD_DLOG (retVal, 02002 "Failed to create listen thread: %s\n", 02003 STRERROR (res_thread_create)); 02004 #endif 02005 #ifdef DAUTH_SUPPORT 02006 pthread_mutex_destroy (&retVal->nnc_lock); 02007 free (retVal->nnc); 02008 #endif 02009 pthread_mutex_destroy (&retVal->per_ip_connection_mutex); 02010 free (retVal); 02011 CLOSE (socket_fd); 02012 return NULL; 02013 } 02014 if (retVal->worker_pool_size > 0) 02015 { 02016 #ifndef MINGW 02017 int sk_flags; 02018 #else 02019 unsigned long sk_flags; 02020 #endif 02021 02022 /* Coarse-grained count of connections per thread (note error 02023 * due to integer division). Also keep track of how many 02024 * connections are leftover after an equal split. */ 02025 unsigned int conns_per_thread = retVal->max_connections 02026 / retVal->worker_pool_size; 02027 unsigned int leftover_conns = retVal->max_connections 02028 % retVal->worker_pool_size; 02029 02030 i = 0; /* we need this in case fcntl or malloc fails */ 02031 02032 /* Accept must be non-blocking. Multiple children may wake up 02033 * to handle a new connection, but only one will win the race. 02034 * The others must immediately return. */ 02035 #ifndef MINGW 02036 sk_flags = fcntl (socket_fd, F_GETFL); 02037 if (sk_flags < 0) 02038 goto thread_failed; 02039 if (fcntl (socket_fd, F_SETFL, sk_flags | O_NONBLOCK) < 0) 02040 goto thread_failed; 02041 #else 02042 sk_flags = 1; 02043 #if HAVE_PLIBC_FD 02044 if (ioctlsocket (plibc_fd_get_handle (socket_fd), FIONBIO, &sk_flags) == 02045 SOCKET_ERROR) 02046 #else 02047 if (ioctlsocket (socket_fd, FIONBIO, &sk_flags) == SOCKET_ERROR) 02048 #endif // PLIBC_FD 02049 goto thread_failed; 02050 #endif // MINGW 02051 02052 /* Allocate memory for pooled objects */ 02053 retVal->worker_pool = malloc (sizeof (struct MHD_Daemon) 02054 * retVal->worker_pool_size); 02055 if (NULL == retVal->worker_pool) 02056 goto thread_failed; 02057 02058 /* Start the workers in the pool */ 02059 for (i = 0; i < retVal->worker_pool_size; ++i) 02060 { 02061 /* Create copy of the Daemon object for each worker */ 02062 struct MHD_Daemon *d = &retVal->worker_pool[i]; 02063 memcpy (d, retVal, sizeof (struct MHD_Daemon)); 02064 02065 /* Adjust pooling params for worker daemons; note that memcpy() 02066 has already copied MHD_USE_SELECT_INTERNALLY thread model into 02067 the worker threads. */ 02068 d->master = retVal; 02069 d->worker_pool_size = 0; 02070 d->worker_pool = NULL; 02071 02072 /* Divide available connections evenly amongst the threads. 02073 * Thread indexes in [0, leftover_conns) each get one of the 02074 * leftover connections. */ 02075 d->max_connections = conns_per_thread; 02076 if (i < leftover_conns) 02077 ++d->max_connections; 02078 02079 /* Spawn the worker thread */ 02080 if (0 != (res_thread_create = create_thread (&d->pid, retVal, &MHD_select_thread, d))) 02081 { 02082 #if HAVE_MESSAGES 02083 MHD_DLOG (retVal, 02084 "Failed to create pool thread: %s\n", 02085 STRERROR (res_thread_create)); 02086 #endif 02087 /* Free memory for this worker; cleanup below handles 02088 * all previously-created workers. */ 02089 goto thread_failed; 02090 } 02091 } 02092 } 02093 return retVal; 02094 02095 thread_failed: 02096 /* If no worker threads created, then shut down normally. Calling 02097 MHD_stop_daemon (as we do below) doesn't work here since it 02098 assumes a 0-sized thread pool means we had been in the default 02099 MHD_USE_SELECT_INTERNALLY mode. */ 02100 if (i == 0) 02101 { 02102 CLOSE (socket_fd); 02103 pthread_mutex_destroy (&retVal->per_ip_connection_mutex); 02104 if (NULL != retVal->worker_pool) 02105 free (retVal->worker_pool); 02106 free (retVal); 02107 return NULL; 02108 } 02109 02110 /* Shutdown worker threads we've already created. Pretend 02111 as though we had fully initialized our daemon, but 02112 with a smaller number of threads than had been 02113 requested. */ 02114 retVal->worker_pool_size = i - 1; 02115 MHD_stop_daemon (retVal); 02116 return NULL; 02117 } 02118 02122 static void 02123 MHD_close_connections (struct MHD_Daemon *daemon) 02124 { 02125 while (daemon->connections != NULL) 02126 { 02127 if (-1 != daemon->connections->socket_fd) 02128 { 02129 #if DEBUG_CLOSE 02130 #if HAVE_MESSAGES 02131 MHD_DLOG (daemon, "MHD shutdown, closing active connections\n"); 02132 #endif 02133 #endif 02134 MHD_connection_close (daemon->connections, 02135 MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); 02136 } 02137 MHD_cleanup_connections (daemon); 02138 } 02139 } 02140 02144 void 02145 MHD_stop_daemon (struct MHD_Daemon *daemon) 02146 { 02147 void *unused; 02148 int fd; 02149 unsigned int i; 02150 int rc; 02151 02152 if (daemon == NULL) 02153 return; 02154 daemon->shutdown = MHD_YES; 02155 fd = daemon->socket_fd; 02156 daemon->socket_fd = -1; 02157 02158 /* Prepare workers for shutdown */ 02159 for (i = 0; i < daemon->worker_pool_size; ++i) 02160 { 02161 daemon->worker_pool[i].shutdown = MHD_YES; 02162 daemon->worker_pool[i].socket_fd = -1; 02163 } 02164 02165 #if OSX 02166 /* without this, either (thread pool = 0) threads would get stuck or 02167 * CLOSE would get stuck if attempted before (thread pool > 0) 02168 * threads have ended */ 02169 SHUTDOWN (fd, SHUT_RDWR); 02170 #else 02171 #if DEBUG_CLOSE 02172 #if HAVE_MESSAGES 02173 MHD_DLOG (daemon, "MHD shutdown, closing listen socket\n"); 02174 #endif 02175 #endif 02176 CLOSE (fd); 02177 #endif 02178 02179 /* Signal workers to stop and clean them up */ 02180 for (i = 0; i < daemon->worker_pool_size; ++i) 02181 pthread_kill (daemon->worker_pool[i].pid, SIGALRM); 02182 for (i = 0; i < daemon->worker_pool_size; ++i) 02183 { 02184 if (0 != (rc = pthread_join (daemon->worker_pool[i].pid, &unused))) 02185 { 02186 #if HAVE_MESSAGES 02187 MHD_DLOG (daemon, "Failed to join a thread: %s\n", 02188 STRERROR (rc)); 02189 #endif 02190 abort(); 02191 } 02192 MHD_close_connections (&daemon->worker_pool[i]); 02193 } 02194 free (daemon->worker_pool); 02195 02196 if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) || 02197 ((0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) 02198 && (0 == daemon->worker_pool_size))) 02199 { 02200 pthread_kill (daemon->pid, SIGALRM); 02201 if (0 != (rc = pthread_join (daemon->pid, &unused))) 02202 { 02203 #if HAVE_MESSAGES 02204 MHD_DLOG (daemon, "Failed to join a thread: %s\n", 02205 STRERROR (rc)); 02206 #endif 02207 abort(); 02208 } 02209 } 02210 MHD_close_connections (daemon); 02211 02212 #if OSX 02213 #if DEBUG_CLOSE 02214 #if HAVE_MESSAGES 02215 MHD_DLOG (daemon, "MHD shutdown, closing listen socket\n"); 02216 #endif 02217 #endif 02218 CLOSE (fd); 02219 #endif 02220 02221 /* TLS clean up */ 02222 #if HTTPS_SUPPORT 02223 if (daemon->options & MHD_USE_SSL) 02224 { 02225 gnutls_priority_deinit (daemon->priority_cache); 02226 if (daemon->x509_cred) 02227 gnutls_certificate_free_credentials (daemon->x509_cred); 02228 /* lock MHD_gnutls_global mutex since it uses reference counting */ 02229 if (0 != pthread_mutex_lock (&MHD_gnutls_init_mutex)) 02230 { 02231 #if HAVE_MESSAGES 02232 MHD_DLOG (daemon, "Failed to aquire gnutls mutex\n"); 02233 #endif 02234 abort(); 02235 } 02236 if (0 != pthread_mutex_unlock (&MHD_gnutls_init_mutex)) 02237 { 02238 #if HAVE_MESSAGES 02239 MHD_DLOG (daemon, "Failed to release gnutls mutex\n"); 02240 #endif 02241 abort(); 02242 } 02243 } 02244 #endif 02245 02246 #ifdef DAUTH_SUPPORT 02247 free (daemon->nnc); 02248 pthread_mutex_destroy (&daemon->nnc_lock); 02249 #endif 02250 pthread_mutex_destroy (&daemon->per_ip_connection_mutex); 02251 free (daemon); 02252 } 02253 02264 const union MHD_DaemonInfo * 02265 MHD_get_daemon_info (struct MHD_Daemon *daemon, 02266 enum MHD_DaemonInfoType infoType, ...) 02267 { 02268 switch (infoType) 02269 { 02270 case MHD_DAEMON_INFO_LISTEN_FD: 02271 return (const union MHD_DaemonInfo *) &daemon->socket_fd; 02272 default: 02273 return NULL; 02274 }; 02275 } 02276 02292 void MHD_set_panic_func (MHD_PanicCallback cb, void *cls) 02293 { 02294 mhd_panic = cb; 02295 mhd_panic_cls = cls; 02296 } 02297 02303 const char * 02304 MHD_get_version (void) 02305 { 02306 return PACKAGE_VERSION; 02307 } 02308 02309 #ifndef WINDOWS 02310 02311 static struct sigaction sig; 02312 02313 static struct sigaction old; 02314 02315 static void 02316 sigalrmHandler (int sig) 02317 { 02318 } 02319 #endif 02320 02321 #ifdef __GNUC__ 02322 #define ATTRIBUTE_CONSTRUCTOR __attribute__ ((constructor)) 02323 #define ATTRIBUTE_DESTRUCTOR __attribute__ ((destructor)) 02324 #else // !__GNUC__ 02325 #define ATTRIBUTE_CONSTRUCTOR 02326 #define ATTRIBUTE_DESTRUCTOR 02327 #endif // __GNUC__ 02328 02329 #if HTTPS_SUPPORT 02330 GCRY_THREAD_OPTION_PTHREAD_IMPL; 02331 #endif 02332 02337 void ATTRIBUTE_CONSTRUCTOR MHD_init () 02338 { 02339 mhd_panic = &mhd_panic_std; 02340 mhd_panic_cls = NULL; 02341 02342 #ifndef WINDOWS 02343 /* make sure SIGALRM does not kill us */ 02344 memset (&sig, 0, sizeof (struct sigaction)); 02345 memset (&old, 0, sizeof (struct sigaction)); 02346 sig.sa_flags = SA_NODEFER; 02347 sig.sa_handler = &sigalrmHandler; 02348 sigaction (SIGALRM, &sig, &old); 02349 #else 02350 plibc_init ("GNU", "libmicrohttpd"); 02351 #endif 02352 #if HTTPS_SUPPORT 02353 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); 02354 gnutls_global_init (); 02355 if (0 != pthread_mutex_init(&MHD_gnutls_init_mutex, NULL)) 02356 abort(); 02357 #endif 02358 } 02359 02360 void ATTRIBUTE_DESTRUCTOR MHD_fini () 02361 { 02362 #if HTTPS_SUPPORT 02363 gnutls_global_deinit (); 02364 if (0 != pthread_mutex_destroy(&MHD_gnutls_init_mutex)) 02365 mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); 02366 #endif 02367 #ifndef WINDOWS 02368 sigaction (SIGALRM, &old, &sig); 02369 #else 02370 plibc_shutdown (); 02371 #endif 02372 } 02373 02374 /* end of daemon.c */