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