00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00027 #include "platform.h"
00028 #include "internal.h"
00029 #include "response.h"
00030 #include "connection.h"
00031 #include "memorypool.h"
00032
00033 #if HTTPS_SUPPORT
00034 #include "connection_https.h"
00035 #include "gnutls_int.h"
00036 #include "gnutls_global.h"
00037 #endif
00038
00042 #define MHD_MAX_CONNECTIONS_DEFAULT FD_SETSIZE -4
00043
00047 #define MHD_POOL_SIZE_DEFAULT (1024 * 1024)
00048
00053 #define DEBUG_CLOSE MHD_NO
00054
00059 #define DEBUG_CONNECT MHD_NO
00060
00061 #ifndef LINUX
00062 #ifndef MSG_NOSIGNAL
00063 #define MSG_NOSIGNAL 0
00064 #endif
00065 #endif
00066
00071 static struct MHD_Daemon*
00072 MHD_get_master (struct MHD_Daemon *daemon)
00073 {
00074 while (NULL != daemon->master)
00075 daemon = daemon->master;
00076 return daemon;
00077 }
00078
00082 struct MHD_IPCount
00083 {
00084 int family;
00085 union
00086 {
00087 struct in_addr ipv4;
00088 #if HAVE_IPV6
00089 struct in6_addr ipv6;
00090 #endif
00091 } addr;
00092 unsigned int count;
00093 };
00094
00098 static void
00099 MHD_ip_count_lock(struct MHD_Daemon *daemon)
00100 {
00101 if (0 != pthread_mutex_lock(&daemon->per_ip_connection_mutex))
00102 {
00103 #if HAVE_MESSAGES
00104 MHD_DLOG (daemon, "Failed to acquire IP connection limit mutex\n");
00105 #endif
00106 abort();
00107 }
00108 }
00109
00113 static void
00114 MHD_ip_count_unlock(struct MHD_Daemon *daemon)
00115 {
00116 if (0 != pthread_mutex_unlock(&daemon->per_ip_connection_mutex))
00117 {
00118 #if HAVE_MESSAGES
00119 MHD_DLOG (daemon, "Failed to release IP connection limit mutex\n");
00120 #endif
00121 abort();
00122 }
00123 }
00124
00130 static int
00131 MHD_ip_addr_compare(const void *a1, const void *a2)
00132 {
00133 return memcmp (a1, a2, offsetof(struct MHD_IPCount, count));
00134 }
00135
00140 static int
00141 MHD_ip_addr_to_key(struct sockaddr *addr, socklen_t addrlen,
00142 struct MHD_IPCount *key)
00143 {
00144 memset(key, 0, sizeof(*key));
00145
00146
00147 if (addrlen == sizeof(struct sockaddr_in))
00148 {
00149 const struct sockaddr_in *addr4 = (const struct sockaddr_in*)addr;
00150 key->family = AF_INET;
00151 memcpy (&key->addr.ipv4, &addr4->sin_addr, sizeof(addr4->sin_addr));
00152 return MHD_YES;
00153 }
00154
00155 #if HAVE_IPV6
00156
00157 if (addrlen == sizeof (struct sockaddr_in6))
00158 {
00159 const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)addr;
00160 key->family = AF_INET6;
00161 memcpy (&key->addr.ipv6, &addr6->sin6_addr, sizeof(addr6->sin6_addr));
00162 return MHD_YES;
00163 }
00164 #endif
00165
00166
00167 return MHD_NO;
00168 }
00169
00176 static int
00177 MHD_ip_limit_add(struct MHD_Daemon *daemon,
00178 struct sockaddr *addr, socklen_t addrlen)
00179 {
00180 struct MHD_IPCount *key;
00181 void *node;
00182 int result;
00183
00184 daemon = MHD_get_master (daemon);
00185
00186
00187 if (daemon->per_ip_connection_limit == 0)
00188 return MHD_YES;
00189
00190 key = malloc (sizeof(*key));
00191 if (NULL == key)
00192 return MHD_NO;
00193
00194
00195 if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, key))
00196 {
00197
00198 free (key);
00199 return MHD_YES;
00200 }
00201
00202 MHD_ip_count_lock (daemon);
00203
00204
00205 node = TSEARCH (key, &daemon->per_ip_connection_count, MHD_ip_addr_compare);
00206 if (!node)
00207 {
00208 #if HAVE_MESSAGES
00209 MHD_DLOG(daemon,
00210 "Failed to add IP connection count node\n");
00211 #endif
00212 MHD_ip_count_unlock (daemon);
00213 return MHD_NO;
00214 }
00215 node = *(void**)node;
00216
00217
00218 if (node != key)
00219 free(key);
00220 key = (struct MHD_IPCount*)node;
00221
00222
00223
00224 result = (key->count < daemon->per_ip_connection_limit);
00225 if (result == MHD_YES)
00226 ++key->count;
00227
00228 MHD_ip_count_unlock (daemon);
00229 return result;
00230 }
00231
00236 static void
00237 MHD_ip_limit_del(struct MHD_Daemon *daemon,
00238 struct sockaddr *addr, socklen_t addrlen)
00239 {
00240 struct MHD_IPCount search_key;
00241 struct MHD_IPCount *found_key;
00242 void *node;
00243
00244 daemon = MHD_get_master (daemon);
00245
00246
00247 if (daemon->per_ip_connection_limit == 0)
00248 return;
00249
00250
00251 if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, &search_key))
00252 return;
00253
00254 MHD_ip_count_lock (daemon);
00255
00256
00257 node = TFIND (&search_key, &daemon->per_ip_connection_count, MHD_ip_addr_compare);
00258
00259
00260
00261 if (!node)
00262 {
00263 #if HAVE_MESSAGES
00264 MHD_DLOG (daemon,
00265 "Failed to find previously-added IP address\n");
00266 #endif
00267 abort();
00268 }
00269 found_key = (struct MHD_IPCount*)*(void**)node;
00270
00271
00272 if (found_key->count == 0)
00273 {
00274 #if HAVE_MESSAGES
00275 MHD_DLOG (daemon,
00276 "Previously-added IP address had 0 count\n");
00277 #endif
00278 abort();
00279 }
00280
00281
00282 if (--found_key->count == 0)
00283 {
00284 TDELETE (found_key, &daemon->per_ip_connection_count, MHD_ip_addr_compare);
00285 free (found_key);
00286 }
00287
00288 MHD_ip_count_unlock (daemon);
00289 }
00290
00291 #if HTTPS_SUPPORT
00292 pthread_mutex_t MHD_gnutls_init_mutex;
00293
00299 static int
00300 _set_priority (MHD_gtls_priority_st * st, const int *list)
00301 {
00302 int num = 0;
00303
00304 while ((list[num] != 0) && (num < MAX_ALGOS))
00305 num++;
00306 st->num_algorithms = num;
00307 memcpy (st->priority, list, num * sizeof (int));
00308 return 0;
00309 }
00310
00311
00320 static ssize_t
00321 recv_tls_adapter (struct MHD_Connection *connection, void *other, size_t i)
00322 {
00323 return MHD__gnutls_record_recv (connection->tls_session, other, i);
00324 }
00325
00334 static ssize_t
00335 send_tls_adapter (struct MHD_Connection *connection,
00336 const void *other, size_t i)
00337 {
00338 return MHD__gnutls_record_send (connection->tls_session, other, i);
00339 }
00340
00341
00347 static int
00348 MHD_init_daemon_certificate (struct MHD_Daemon *daemon)
00349 {
00350 MHD_gnutls_datum_t key;
00351 MHD_gnutls_datum_t cert;
00352
00353
00354 if (daemon->https_mem_cert && daemon->https_mem_key)
00355 {
00356 key.data = (unsigned char *) daemon->https_mem_key;
00357 key.size = strlen (daemon->https_mem_key);
00358 cert.data = (unsigned char *) daemon->https_mem_cert;
00359 cert.size = strlen (daemon->https_mem_cert);
00360
00361 return MHD__gnutls_certificate_set_x509_key_mem (daemon->x509_cred,
00362 &cert, &key,
00363 GNUTLS_X509_FMT_PEM);
00364 }
00365 #if HAVE_MESSAGES
00366 MHD_DLOG (daemon, "You need to specify a certificate and key location\n");
00367 #endif
00368 return -1;
00369 }
00370
00376 static int
00377 MHD_TLS_init (struct MHD_Daemon *daemon)
00378 {
00379 switch (daemon->cred_type)
00380 {
00381 case MHD_GNUTLS_CRD_CERTIFICATE:
00382 if (0 !=
00383 MHD__gnutls_certificate_allocate_credentials (&daemon->x509_cred))
00384 return GNUTLS_E_MEMORY_ERROR;
00385 return MHD_init_daemon_certificate (daemon);
00386 default:
00387 #if HAVE_MESSAGES
00388 MHD_DLOG (daemon,
00389 "Error: invalid credentials type %d specified.\n",
00390 daemon->cred_type);
00391 #endif
00392 return -1;
00393 }
00394 }
00395 #endif
00396
00404 int
00405 MHD_get_fdset (struct MHD_Daemon *daemon,
00406 fd_set * read_fd_set,
00407 fd_set * write_fd_set, fd_set * except_fd_set, int *max_fd)
00408 {
00409 struct MHD_Connection *con_itr;
00410 int fd;
00411
00412 if ((daemon == NULL) || (read_fd_set == NULL) || (write_fd_set == NULL)
00413 || (except_fd_set == NULL) || (max_fd == NULL)
00414 || (-1 == (fd = daemon->socket_fd)) || (daemon->shutdown == MHD_YES)
00415 || ((daemon->options & MHD_USE_THREAD_PER_CONNECTION) != 0))
00416 return MHD_NO;
00417
00418 FD_SET (fd, read_fd_set);
00419
00420 if ((*max_fd) < fd)
00421 *max_fd = fd;
00422
00423 con_itr = daemon->connections;
00424 while (con_itr != NULL)
00425 {
00426 if (MHD_YES != MHD_connection_get_fdset (con_itr,
00427 read_fd_set,
00428 write_fd_set,
00429 except_fd_set, max_fd))
00430 return MHD_NO;
00431 con_itr = con_itr->next;
00432 }
00433 #if DEBUG_CONNECT
00434 MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd);
00435 #endif
00436 return MHD_YES;
00437 }
00438
00443 static void *
00444 MHD_handle_connection (void *data)
00445 {
00446 struct MHD_Connection *con = data;
00447 int num_ready;
00448 fd_set rs;
00449 fd_set ws;
00450 fd_set es;
00451 int max;
00452 struct timeval tv;
00453 unsigned int timeout;
00454 unsigned int now;
00455
00456 if (con == NULL)
00457 abort ();
00458 timeout = con->daemon->connection_timeout;
00459 while ((!con->daemon->shutdown) && (con->socket_fd != -1))
00460 {
00461 FD_ZERO (&rs);
00462 FD_ZERO (&ws);
00463 FD_ZERO (&es);
00464 max = 0;
00465 MHD_connection_get_fdset (con, &rs, &ws, &es, &max);
00466 now = time (NULL);
00467 tv.tv_usec = 0;
00468 if (timeout > (now - con->last_activity))
00469 tv.tv_sec = timeout - (now - con->last_activity);
00470 else
00471 tv.tv_sec = 0;
00472 if ((con->state == MHD_CONNECTION_NORMAL_BODY_UNREADY) ||
00473 (con->state == MHD_CONNECTION_CHUNKED_BODY_UNREADY))
00474 {
00475
00476 timeout = 1;
00477 tv.tv_sec = 0;
00478 }
00479 num_ready = SELECT (max + 1,
00480 &rs, &ws, &es, (timeout != 0) ? &tv : NULL);
00481 if (num_ready < 0)
00482 {
00483 if (errno == EINTR)
00484 continue;
00485 #if HAVE_MESSAGES
00486 MHD_DLOG (con->daemon, "Error during select (%d): `%s'\n", max,
00487 STRERROR (errno));
00488 #endif
00489 break;
00490 }
00491
00492 if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &rs)))
00493 con->read_handler (con);
00494 if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &ws)))
00495 con->write_handler (con);
00496 if (con->socket_fd != -1)
00497 con->idle_handler (con);
00498 }
00499 if (con->socket_fd != -1)
00500 {
00501 #if DEBUG_CLOSE
00502 #if HAVE_MESSAGES
00503 MHD_DLOG (con->daemon,
00504 "Processing thread terminating, closing connection\n");
00505 #endif
00506 #endif
00507 MHD_connection_close (con, MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
00508 }
00509 return NULL;
00510 }
00511
00520 static ssize_t
00521 recv_param_adapter (struct MHD_Connection *connection, void *other, size_t i)
00522 {
00523 if (connection->socket_fd == -1)
00524 return -1;
00525 if (0 != (connection->daemon->options & MHD_USE_SSL))
00526 return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL);
00527 else
00528 return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL | MSG_DONTWAIT);
00529 }
00530
00539 static ssize_t
00540 send_param_adapter (struct MHD_Connection *connection,
00541 const void *other, size_t i)
00542 {
00543 if (connection->socket_fd == -1)
00544 return -1;
00545 if (0 != (connection->daemon->options & MHD_USE_SSL))
00546 return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL);
00547 else
00548 return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL | MSG_DONTWAIT);
00549 }
00550
00556 static int
00557 MHD_accept_connection (struct MHD_Daemon *daemon)
00558 {
00559 struct MHD_Connection *connection;
00560 #if HAVE_INET6
00561 struct sockaddr_in6 addrstorage;
00562 #else
00563 struct sockaddr_in addrstorage;
00564 #endif
00565 struct sockaddr *addr = (struct sockaddr *) &addrstorage;
00566 socklen_t addrlen;
00567 int s, res_thread_create;
00568 #if OSX
00569 static int on = 1;
00570 #endif
00571
00572 #if HAVE_INET6
00573 if (sizeof (struct sockaddr) > sizeof (struct sockaddr_in6))
00574 abort ();
00575 #endif
00576 addrlen = sizeof (addrstorage);
00577 memset (addr, 0, sizeof (addrstorage));
00578
00579 s = ACCEPT (daemon->socket_fd, addr, &addrlen);
00580
00581 if ((s < 0) || (addrlen <= 0))
00582 {
00583 #if HAVE_MESSAGES
00584
00585 if ((EAGAIN != errno) && (EWOULDBLOCK != errno))
00586 MHD_DLOG (daemon, "Error accepting connection: %s\n", STRERROR (errno));
00587 #endif
00588 if (s != -1)
00589 {
00590 SHUTDOWN (s, SHUT_RDWR);
00591 CLOSE (s);
00592
00593 }
00594 return MHD_NO;
00595 }
00596 #if HAVE_MESSAGES
00597 #if DEBUG_CONNECT
00598 MHD_DLOG (daemon, "Accepted connection on socket %d\n", s);
00599 #endif
00600 #endif
00601 if ((daemon->max_connections == 0)
00602 || (MHD_ip_limit_add (daemon, addr, addrlen) == MHD_NO))
00603 {
00604
00605 #if HAVE_MESSAGES
00606 MHD_DLOG (daemon,
00607 "Server reached connection limit (closing inbound connection)\n");
00608 #endif
00609 SHUTDOWN (s, SHUT_RDWR);
00610 CLOSE (s);
00611 return MHD_NO;
00612 }
00613
00614
00615 if ((daemon->apc != NULL)
00616 && (MHD_NO == daemon->apc (daemon->apc_cls, addr, addrlen)))
00617 {
00618 #if DEBUG_CLOSE
00619 #if HAVE_MESSAGES
00620 MHD_DLOG (daemon, "Connection rejected, closing connection\n");
00621 #endif
00622 #endif
00623 SHUTDOWN (s, SHUT_RDWR);
00624 CLOSE (s);
00625 MHD_ip_limit_del (daemon, addr, addrlen);
00626 return MHD_YES;
00627 }
00628 #if OSX
00629 #ifdef SOL_SOCKET
00630 #ifdef SO_NOSIGPIPE
00631 setsockopt (s, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof (on));
00632 #endif
00633 #endif
00634 #endif
00635 connection = malloc (sizeof (struct MHD_Connection));
00636 if (NULL == connection)
00637 {
00638 #if HAVE_MESSAGES
00639 MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno));
00640 #endif
00641 SHUTDOWN (s, SHUT_RDWR);
00642 CLOSE (s);
00643 MHD_ip_limit_del (daemon, addr, addrlen);
00644 return MHD_NO;
00645 }
00646 memset (connection, 0, sizeof (struct MHD_Connection));
00647 connection->pool = NULL;
00648 connection->addr = malloc (addrlen);
00649 if (connection->addr == NULL)
00650 {
00651 #if HAVE_MESSAGES
00652 MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno));
00653 #endif
00654 SHUTDOWN (s, SHUT_RDWR);
00655 CLOSE (s);
00656 MHD_ip_limit_del (daemon, addr, addrlen);
00657 free (connection);
00658 return MHD_NO;
00659 }
00660 memcpy (connection->addr, addr, addrlen);
00661 connection->addr_len = addrlen;
00662 connection->socket_fd = s;
00663 connection->daemon = daemon;
00664 connection->last_activity = time (NULL);
00665
00666
00667 MHD_set_http_calbacks (connection);
00668 connection->recv_cls = &recv_param_adapter;
00669 connection->send_cls = &send_param_adapter;
00670 #if HTTPS_SUPPORT
00671 if (0 != (daemon->options & MHD_USE_SSL))
00672 {
00673 connection->recv_cls = &recv_tls_adapter;
00674 connection->send_cls = &send_tls_adapter;
00675 connection->state = MHD_TLS_CONNECTION_INIT;
00676 MHD_set_https_calbacks (connection);
00677 MHD__gnutls_init (&connection->tls_session, GNUTLS_SERVER);
00678 MHD__gnutls_priority_set (connection->tls_session,
00679 connection->daemon->priority_cache);
00680 switch (connection->daemon->cred_type)
00681 {
00682
00683 case MHD_GNUTLS_CRD_CERTIFICATE:
00684 MHD__gnutls_credentials_set (connection->tls_session,
00685 MHD_GNUTLS_CRD_CERTIFICATE,
00686 connection->daemon->x509_cred);
00687 break;
00688 default:
00689 #if HAVE_MESSAGES
00690 MHD_DLOG (connection->daemon,
00691 "Failed to setup TLS credentials: unknown credential type %d\n",
00692 connection->daemon->cred_type);
00693 #endif
00694 abort ();
00695 }
00696 MHD__gnutls_transport_set_ptr (connection->tls_session,
00697 (MHD_gnutls_transport_ptr_t) connection);
00698 MHD__gnutls_transport_set_pull_function (connection->tls_session,
00699 (MHD_gtls_pull_func) &
00700 recv_param_adapter);
00701 MHD__gnutls_transport_set_push_function (connection->tls_session,
00702 (MHD_gtls_push_func) &
00703 send_param_adapter);
00704 }
00705 #endif
00706
00707
00708 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
00709 {
00710 res_thread_create = pthread_create (&connection->pid, NULL,
00711 &MHD_handle_connection, connection);
00712 if (res_thread_create != 0)
00713 {
00714 #if HAVE_MESSAGES
00715 MHD_DLOG (daemon, "Failed to create a thread: %s\n",
00716 STRERROR (errno));
00717 #endif
00718 SHUTDOWN (s, SHUT_RDWR);
00719 CLOSE (s);
00720 MHD_ip_limit_del (daemon, addr, addrlen);
00721 free (connection->addr);
00722 free (connection);
00723 return MHD_NO;
00724 }
00725 }
00726 connection->next = daemon->connections;
00727 daemon->connections = connection;
00728 daemon->max_connections--;
00729 return MHD_YES;
00730 }
00731
00737 static void
00738 MHD_cleanup_connections (struct MHD_Daemon *daemon)
00739 {
00740 struct MHD_Connection *pos;
00741 struct MHD_Connection *prev;
00742 void *unused;
00743
00744 pos = daemon->connections;
00745 prev = NULL;
00746 while (pos != NULL)
00747 {
00748 if ((pos->socket_fd == -1) ||
00749 (((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
00750 (daemon->shutdown) && (pos->socket_fd != -1))))
00751 {
00752 if (prev == NULL)
00753 daemon->connections = pos->next;
00754 else
00755 prev->next = pos->next;
00756 if (0 != (pos->daemon->options & MHD_USE_THREAD_PER_CONNECTION))
00757 {
00758 pthread_kill (pos->pid, SIGALRM);
00759 pthread_join (pos->pid, &unused);
00760 }
00761 MHD_destroy_response (pos->response);
00762 MHD_pool_destroy (pos->pool);
00763 #if HTTPS_SUPPORT
00764 if (pos->tls_session != NULL)
00765 MHD__gnutls_deinit (pos->tls_session);
00766 #endif
00767 MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len);
00768 free (pos->addr);
00769 free (pos);
00770 daemon->max_connections++;
00771 if (prev == NULL)
00772 pos = daemon->connections;
00773 else
00774 pos = prev->next;
00775 continue;
00776 }
00777 prev = pos;
00778 pos = pos->next;
00779 }
00780 }
00781
00793 int
00794 MHD_get_timeout (struct MHD_Daemon *daemon, unsigned long long *timeout)
00795 {
00796 time_t earliest_deadline;
00797 time_t now;
00798 struct MHD_Connection *pos;
00799 unsigned int dto;
00800
00801 dto = daemon->connection_timeout;
00802 if (0 == dto)
00803 return MHD_NO;
00804 pos = daemon->connections;
00805 if (pos == NULL)
00806 return MHD_NO;
00807 now = time (NULL);
00808
00809 earliest_deadline = now + dto;
00810 while (pos != NULL)
00811 {
00812 if (earliest_deadline > pos->last_activity + dto)
00813 earliest_deadline = pos->last_activity + dto;
00814 pos = pos->next;
00815 }
00816 if (earliest_deadline < now)
00817 *timeout = 0;
00818 else
00819 *timeout = (earliest_deadline - now);
00820 return MHD_YES;
00821 }
00822
00829 static int
00830 MHD_select (struct MHD_Daemon *daemon, int may_block)
00831 {
00832 struct MHD_Connection *pos;
00833 int num_ready;
00834 fd_set rs;
00835 fd_set ws;
00836 fd_set es;
00837 int max;
00838 struct timeval timeout;
00839 unsigned long long ltimeout;
00840 int ds;
00841 time_t now;
00842
00843 timeout.tv_sec = 0;
00844 timeout.tv_usec = 0;
00845 if (daemon == NULL)
00846 abort ();
00847 if (daemon->shutdown == MHD_YES)
00848 return MHD_NO;
00849 FD_ZERO (&rs);
00850 FD_ZERO (&ws);
00851 FD_ZERO (&es);
00852 max = 0;
00853
00854 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
00855 {
00856
00857 if (MHD_NO == MHD_get_fdset (daemon, &rs, &ws, &es, &max))
00858 return MHD_NO;
00859
00860
00861
00862 if ( (daemon->max_connections == 0) && (daemon->socket_fd != -1) )
00863 FD_CLR(daemon->socket_fd, &rs);
00864 }
00865 else
00866 {
00867
00868 max = daemon->socket_fd;
00869 if (max == -1)
00870 return MHD_NO;
00871 FD_SET (max, &rs);
00872 }
00873
00874 if (may_block == MHD_NO)
00875 {
00876 timeout.tv_usec = 0;
00877 timeout.tv_sec = 0;
00878 }
00879 else
00880 {
00881
00882 if (MHD_YES == MHD_get_timeout (daemon, <imeout))
00883 {
00884 timeout.tv_usec = (ltimeout % 1000) * 1000;
00885 timeout.tv_sec = ltimeout / 1000;
00886 may_block = MHD_NO;
00887 }
00888 }
00889
00890 num_ready = select (max + 1, &rs, &ws, &es, may_block == MHD_NO ? &timeout
00891 : NULL);
00892
00893 if (daemon->shutdown == MHD_YES)
00894 return MHD_NO;
00895 if (num_ready < 0)
00896 {
00897 if (errno == EINTR)
00898 return MHD_YES;
00899 #if HAVE_MESSAGES
00900 MHD_DLOG (daemon, "select failed: %s\n", STRERROR (errno));
00901 #endif
00902 return MHD_NO;
00903 }
00904 ds = daemon->socket_fd;
00905 if (ds == -1)
00906 return MHD_YES;
00907
00908
00909 if (FD_ISSET (ds, &rs))
00910 MHD_accept_connection (daemon);
00911 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
00912 {
00913
00914 now = time (NULL);
00915 pos = daemon->connections;
00916 while (pos != NULL)
00917 {
00918 ds = pos->socket_fd;
00919 if (ds != -1)
00920 {
00921
00922 if (FD_ISSET (ds, &rs))
00923 pos->read_handler (pos);
00924 if ((pos->socket_fd != -1) && (FD_ISSET (ds, &ws)))
00925 pos->write_handler (pos);
00926 if (pos->socket_fd != -1)
00927 pos->idle_handler (pos);
00928 }
00929 pos = pos->next;
00930 }
00931 }
00932 return MHD_YES;
00933 }
00934
00945 int
00946 MHD_run (struct MHD_Daemon *daemon)
00947 {
00948 if ((daemon->shutdown != MHD_NO) || (0 != (daemon->options
00949 & MHD_USE_THREAD_PER_CONNECTION))
00950 || (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)))
00951 return MHD_NO;
00952 MHD_select (daemon, MHD_NO);
00953 MHD_cleanup_connections (daemon);
00954 return MHD_YES;
00955 }
00956
00961 static void *
00962 MHD_select_thread (void *cls)
00963 {
00964 struct MHD_Daemon *daemon = cls;
00965 while (daemon->shutdown == MHD_NO)
00966 {
00967 MHD_select (daemon, MHD_YES);
00968 MHD_cleanup_connections (daemon);
00969 }
00970 return NULL;
00971 }
00972
00984 struct MHD_Daemon *
00985 MHD_start_daemon (unsigned int options,
00986 unsigned short port,
00987 MHD_AcceptPolicyCallback apc,
00988 void *apc_cls,
00989 MHD_AccessHandlerCallback dh, void *dh_cls, ...)
00990 {
00991 struct MHD_Daemon *ret;
00992 va_list ap;
00993
00994 va_start (ap, dh_cls);
00995 ret = MHD_start_daemon_va (options, port, apc, apc_cls, dh, dh_cls, ap);
00996 va_end (ap);
00997 return ret;
00998 }
00999
01000
01012 struct MHD_Daemon *
01013 MHD_start_daemon_va (unsigned int options,
01014 unsigned short port,
01015 MHD_AcceptPolicyCallback apc,
01016 void *apc_cls,
01017 MHD_AccessHandlerCallback dh, void *dh_cls, va_list ap)
01018 {
01019 const int on = 1;
01020 struct MHD_Daemon *retVal;
01021 int socket_fd;
01022 struct sockaddr_in servaddr4;
01023 #if HAVE_INET6
01024 struct sockaddr_in6 servaddr6;
01025 #endif
01026 const struct sockaddr *servaddr = NULL;
01027 socklen_t addrlen;
01028 enum MHD_OPTION opt;
01029 unsigned int i;
01030
01031 if ((port == 0) || (dh == NULL))
01032 return NULL;
01033 retVal = malloc (sizeof (struct MHD_Daemon));
01034 if (retVal == NULL)
01035 return NULL;
01036 memset (retVal, 0, sizeof (struct MHD_Daemon));
01037 retVal->options = options;
01038 retVal->port = port;
01039 retVal->apc = apc;
01040 retVal->apc_cls = apc_cls;
01041 retVal->default_handler = dh;
01042 retVal->default_handler_cls = dh_cls;
01043 retVal->max_connections = MHD_MAX_CONNECTIONS_DEFAULT;
01044 retVal->pool_size = MHD_POOL_SIZE_DEFAULT;
01045 retVal->connection_timeout = 0;
01046 #if HAVE_MESSAGES
01047 retVal->custom_error_log =
01048 (void (*)(void *, const char *, va_list)) &vfprintf;
01049 retVal->custom_error_log_cls = stderr;
01050 #endif
01051 #if HTTPS_SUPPORT
01052 if (options & MHD_USE_SSL)
01053 {
01054
01055 pthread_mutex_lock (&MHD_gnutls_init_mutex);
01056 MHD__gnutls_global_init ();
01057 pthread_mutex_unlock (&MHD_gnutls_init_mutex);
01058
01059 MHD_tls_set_default_priority (&retVal->priority_cache, "", NULL);
01060 retVal->cred_type = MHD_GNUTLS_CRD_CERTIFICATE;
01061 }
01062 #endif
01063
01064 while (MHD_OPTION_END != (opt = va_arg (ap, enum MHD_OPTION)))
01065 {
01066 switch (opt)
01067 {
01068 case MHD_OPTION_CONNECTION_MEMORY_LIMIT:
01069 retVal->pool_size = va_arg (ap, size_t);
01070 break;
01071 case MHD_OPTION_CONNECTION_LIMIT:
01072 retVal->max_connections = va_arg (ap, unsigned int);
01073 break;
01074 case MHD_OPTION_CONNECTION_TIMEOUT:
01075 retVal->connection_timeout = va_arg (ap, unsigned int);
01076 break;
01077 case MHD_OPTION_NOTIFY_COMPLETED:
01078 retVal->notify_completed =
01079 va_arg (ap, MHD_RequestCompletedCallback);
01080 retVal->notify_completed_cls = va_arg (ap, void *);
01081 break;
01082 case MHD_OPTION_PER_IP_CONNECTION_LIMIT:
01083 retVal->per_ip_connection_limit = va_arg (ap, unsigned int);
01084 break;
01085 case MHD_OPTION_SOCK_ADDR:
01086 servaddr = va_arg (ap, struct sockaddr *);
01087 break;
01088 case MHD_OPTION_URI_LOG_CALLBACK:
01089 retVal->uri_log_callback =
01090 va_arg (ap, LogCallback);
01091 retVal->uri_log_callback_cls = va_arg (ap, void *);
01092 break;
01093 case MHD_OPTION_THREAD_POOL_SIZE:
01094 retVal->worker_pool_size = va_arg (ap, unsigned int);
01095 break;
01096 #if HTTPS_SUPPORT
01097 case MHD_OPTION_PROTOCOL_VERSION:
01098 _set_priority (&retVal->priority_cache->protocol,
01099 va_arg (ap, const int *));
01100 break;
01101 case MHD_OPTION_HTTPS_MEM_KEY:
01102 retVal->https_mem_key = va_arg (ap, const char *);
01103 break;
01104 case MHD_OPTION_HTTPS_MEM_CERT:
01105 retVal->https_mem_cert = va_arg (ap, const char *);
01106 break;
01107 case MHD_OPTION_CIPHER_ALGORITHM:
01108 _set_priority (&retVal->priority_cache->cipher,
01109 va_arg (ap, const int *));
01110 break;
01111 #endif
01112 case MHD_OPTION_EXTERNAL_LOGGER:
01113 #if HAVE_MESSAGES
01114 retVal->custom_error_log =
01115 va_arg (ap, void (*)(void *cls, const char *, va_list));
01116 retVal->custom_error_log_cls = va_arg (ap, void *);
01117 #else
01118 va_arg (ap, void (*)(void *cls, const char *, ...));
01119 va_arg (ap, void *);
01120 #endif
01121 break;
01122 default:
01123 #if HAVE_MESSAGES
01124 if ((opt >= MHD_OPTION_HTTPS_MEM_KEY) &&
01125 (opt <= MHD_OPTION_CIPHER_ALGORITHM))
01126 {
01127 FPRINTF (stderr,
01128 "MHD HTTPS option %d passed to MHD compiled without HTTPS support\n",
01129 opt);
01130 }
01131 else
01132 {
01133 FPRINTF (stderr,
01134 "Invalid option %d! (Did you terminate the list with MHD_OPTION_END?)\n",
01135 opt);
01136 }
01137 #endif
01138 abort ();
01139 }
01140 }
01141
01142
01143 if ((0 == (options & MHD_USE_SELECT_INTERNALLY))
01144 && (retVal->worker_pool_size > 0))
01145 {
01146 #if HAVE_MESSAGES
01147 FPRINTF (stderr,
01148 "MHD thread pooling only works with MHD_USE_SELECT_INTERNALLY\n");
01149 #endif
01150 free (retVal);
01151 return NULL;
01152 }
01153
01154 if ((options & MHD_USE_IPv6) != 0)
01155 #if HAVE_INET6
01156 socket_fd = SOCKET (PF_INET6, SOCK_STREAM, 0);
01157 #else
01158 {
01159 #if HAVE_MESSAGES
01160 FPRINTF (stderr, "AF_INET6 not supported\n");
01161 #endif
01162 return NULL;
01163 }
01164 #endif
01165 else
01166 socket_fd = SOCKET (PF_INET, SOCK_STREAM, 0);
01167 if (socket_fd < 0)
01168 {
01169 #if HAVE_MESSAGES
01170 if ((options & MHD_USE_DEBUG) != 0)
01171 FPRINTF (stderr, "Call to socket failed: %s\n", STRERROR (errno));
01172 #endif
01173 free (retVal);
01174 return NULL;
01175 }
01176 if ((SETSOCKOPT (socket_fd,
01177 SOL_SOCKET,
01178 SO_REUSEADDR,
01179 &on, sizeof (on)) < 0) && (options & MHD_USE_DEBUG) != 0)
01180 {
01181 #if HAVE_MESSAGES
01182 FPRINTF (stderr, "setsockopt failed: %s\n", STRERROR (errno));
01183 #endif
01184 }
01185
01186
01187 #if HAVE_INET6
01188 if ((options & MHD_USE_IPv6) != 0)
01189 addrlen = sizeof (struct sockaddr_in6);
01190 else
01191 #endif
01192 addrlen = sizeof (struct sockaddr_in);
01193 if (NULL == servaddr)
01194 {
01195 #if HAVE_INET6
01196 if ((options & MHD_USE_IPv6) != 0)
01197 {
01198 memset (&servaddr6, 0, sizeof (struct sockaddr_in6));
01199 servaddr6.sin6_family = AF_INET6;
01200 servaddr6.sin6_port = htons (port);
01201 servaddr = (struct sockaddr *) &servaddr6;
01202 }
01203 else
01204 #endif
01205 {
01206 memset (&servaddr4, 0, sizeof (struct sockaddr_in));
01207 servaddr4.sin_family = AF_INET;
01208 servaddr4.sin_port = htons (port);
01209 servaddr = (struct sockaddr *) &servaddr4;
01210 }
01211 }
01212 retVal->socket_fd = socket_fd;
01213 if (BIND (socket_fd, servaddr, addrlen) < 0)
01214 {
01215 #if HAVE_MESSAGES
01216 if ((options & MHD_USE_DEBUG) != 0)
01217 FPRINTF (stderr,
01218 "Failed to bind to port %u: %s\n", port, STRERROR (errno));
01219 #endif
01220 CLOSE (socket_fd);
01221 free (retVal);
01222 return NULL;
01223 }
01224
01225
01226 if (LISTEN (socket_fd, 20) < 0)
01227 {
01228 #if HAVE_MESSAGES
01229 if ((options & MHD_USE_DEBUG) != 0)
01230 FPRINTF (stderr,
01231 "Failed to listen for connections: %s\n", STRERROR (errno));
01232 #endif
01233 CLOSE (socket_fd);
01234 free (retVal);
01235 return NULL;
01236 }
01237
01238 if (0 != pthread_mutex_init (&retVal->per_ip_connection_mutex, NULL))
01239 {
01240 #if HAVE_MESSAGES
01241 MHD_DLOG (retVal,
01242 "MHD failed to initialize IP connection limit mutex\n");
01243 #endif
01244 CLOSE (socket_fd);
01245 free (retVal);
01246 return NULL;
01247 }
01248
01249 #if HTTPS_SUPPORT
01250
01251 if ((0 != (options & MHD_USE_SSL)) && (0 != MHD_TLS_init (retVal)))
01252 {
01253 #if HAVE_MESSAGES
01254 MHD_DLOG (retVal, "Failed to initialize TLS support\n");
01255 #endif
01256 CLOSE (socket_fd);
01257 pthread_mutex_destroy (&retVal->per_ip_connection_mutex);
01258 free (retVal);
01259 return NULL;
01260 }
01261 #endif
01262 if (((0 != (options & MHD_USE_THREAD_PER_CONNECTION)) ||
01263 ((0 != (options & MHD_USE_SELECT_INTERNALLY))
01264 && (0 == retVal->worker_pool_size)))
01265 && (0 !=
01266 pthread_create (&retVal->pid, NULL, &MHD_select_thread, retVal)))
01267 {
01268 #if HAVE_MESSAGES
01269 MHD_DLOG (retVal,
01270 "Failed to create listen thread: %s\n", STRERROR (errno));
01271 #endif
01272 pthread_mutex_destroy (&retVal->per_ip_connection_mutex);
01273 free (retVal);
01274 CLOSE (socket_fd);
01275 return NULL;
01276 }
01277 else if (retVal->worker_pool_size > 0)
01278 {
01279 #ifndef MINGW
01280 int sk_flags;
01281 #else
01282 unsigned long sk_flags;
01283 #endif
01284
01285
01286
01287
01288 unsigned int conns_per_thread = retVal->max_connections
01289 / retVal->worker_pool_size;
01290 unsigned int leftover_conns = retVal->max_connections
01291 % retVal->worker_pool_size;
01292
01293 i = 0;
01294
01295
01296
01297
01298 #ifndef MINGW
01299 sk_flags = fcntl (socket_fd, F_GETFL);
01300 if (sk_flags < 0)
01301 goto thread_failed;
01302 if (fcntl (socket_fd, F_SETFL, sk_flags | O_NONBLOCK) < 0)
01303 goto thread_failed;
01304 #else
01305 sk_flags = 1;
01306 #if HAVE_PLIBC_FD
01307 if (ioctlsocket (plibc_fd_get_handle (socket_fd), FIONBIO, &sk_flags) ==
01308 SOCKET_ERROR)
01309 #else
01310 if (ioctlsocket (socket_fd, FIONBIO, &sk_flags) == SOCKET_ERROR)
01311 #endif // PLIBC_FD
01312 goto thread_failed;
01313 #endif // MINGW
01314
01315
01316 retVal->worker_pool = malloc (sizeof (struct MHD_Daemon)
01317 * retVal->worker_pool_size);
01318 if (NULL == retVal->worker_pool)
01319 goto thread_failed;
01320
01321
01322 for (i = 0; i < retVal->worker_pool_size; ++i)
01323 {
01324
01325 struct MHD_Daemon *d = &retVal->worker_pool[i];
01326 memcpy (d, retVal, sizeof (struct MHD_Daemon));
01327
01328
01329
01330
01331 d->master = retVal;
01332 d->worker_pool_size = 0;
01333 d->worker_pool = NULL;
01334
01335
01336
01337
01338 d->max_connections = conns_per_thread;
01339 if (i < leftover_conns)
01340 ++d->max_connections;
01341
01342
01343 if (0 != pthread_create (&d->pid, NULL, &MHD_select_thread, d))
01344 {
01345 #if HAVE_MESSAGES
01346 MHD_DLOG (retVal,
01347 "Failed to create pool thread: %d\n", STRERROR (errno));
01348 #endif
01349
01350
01351 goto thread_failed;
01352 }
01353 }
01354 }
01355 return retVal;
01356
01357 thread_failed:
01358
01359
01360
01361
01362 if (i == 0)
01363 {
01364 CLOSE (socket_fd);
01365 pthread_mutex_destroy (&retVal->per_ip_connection_mutex);
01366 if (NULL != retVal->worker_pool)
01367 free (retVal->worker_pool);
01368 free (retVal);
01369 return NULL;
01370 }
01371
01372
01373
01374
01375
01376 retVal->worker_pool_size = i - 1;
01377 MHD_stop_daemon (retVal);
01378 return NULL;
01379 }
01380
01384 static void
01385 MHD_close_connections (struct MHD_Daemon *daemon)
01386 {
01387 while (daemon->connections != NULL)
01388 {
01389 if (-1 != daemon->connections->socket_fd)
01390 {
01391 #if DEBUG_CLOSE
01392 #if HAVE_MESSAGES
01393 MHD_DLOG (daemon, "MHD shutdown, closing active connections\n");
01394 #endif
01395 #endif
01396 MHD_connection_close (daemon->connections,
01397 MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
01398 }
01399 MHD_cleanup_connections (daemon);
01400 }
01401 }
01402
01406 void
01407 MHD_stop_daemon (struct MHD_Daemon *daemon)
01408 {
01409 void *unused;
01410 int fd;
01411 unsigned int i;
01412
01413 if (daemon == NULL)
01414 return;
01415 daemon->shutdown = MHD_YES;
01416 fd = daemon->socket_fd;
01417 daemon->socket_fd = -1;
01418
01419
01420 for (i = 0; i < daemon->worker_pool_size; ++i)
01421 {
01422 daemon->worker_pool[i].shutdown = MHD_YES;
01423 daemon->worker_pool[i].socket_fd = -1;
01424 }
01425
01426 #if OSX
01427
01428
01429
01430 SHUTDOWN (fd, SHUT_RDWR);
01431 #else
01432 #if DEBUG_CLOSE
01433 #if HAVE_MESSAGES
01434 MHD_DLOG (daemon, "MHD shutdown, closing listen socket\n");
01435 #endif
01436 #endif
01437 CLOSE (fd);
01438 #endif
01439
01440
01441 for (i = 0; i < daemon->worker_pool_size; ++i)
01442 pthread_kill (daemon->worker_pool[i].pid, SIGALRM);
01443 for (i = 0; i < daemon->worker_pool_size; ++i)
01444 {
01445 pthread_join (daemon->worker_pool[i].pid, &unused);
01446 MHD_close_connections (&daemon->worker_pool[i]);
01447 }
01448 free (daemon->worker_pool);
01449
01450 if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
01451 ((0 != (daemon->options & MHD_USE_SELECT_INTERNALLY))
01452 && (0 == daemon->worker_pool_size)))
01453 {
01454 pthread_kill (daemon->pid, SIGALRM);
01455 pthread_join (daemon->pid, &unused);
01456 }
01457 MHD_close_connections (daemon);
01458
01459 #if OSX
01460 #if DEBUG_CLOSE
01461 #if HAVE_MESSAGES
01462 MHD_DLOG (daemon, "MHD shutdown, closing listen socket\n");
01463 #endif
01464 #endif
01465 CLOSE (fd);
01466 #endif
01467
01468
01469 #if HTTPS_SUPPORT
01470 if (daemon->options & MHD_USE_SSL)
01471 {
01472 MHD__gnutls_priority_deinit (daemon->priority_cache);
01473 if (daemon->x509_cred)
01474 MHD__gnutls_certificate_free_credentials (daemon->x509_cred);
01475
01476 pthread_mutex_lock (&MHD_gnutls_init_mutex);
01477 MHD__gnutls_global_deinit ();
01478 pthread_mutex_unlock (&MHD_gnutls_init_mutex);
01479 }
01480 #endif
01481 pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
01482 free (daemon);
01483 }
01484
01495 const union MHD_DaemonInfo *
01496 MHD_get_daemon_info (struct MHD_Daemon *daemon,
01497 enum MHD_DaemonInfoType infoType, ...)
01498 {
01499 return NULL;
01500 }
01501
01507 const char *
01508 MHD_get_version (void)
01509 {
01510 return PACKAGE_VERSION;
01511 }
01512
01513 #ifndef WINDOWS
01514
01515 static struct sigaction sig;
01516
01517 static struct sigaction old;
01518
01519 static void
01520 sigalrmHandler (int sig)
01521 {
01522 }
01523 #endif
01524
01529 void __attribute__ ((constructor)) MHD_init ()
01530 {
01531 #ifndef WINDOWS
01532
01533 memset (&sig, 0, sizeof (struct sigaction));
01534 memset (&old, 0, sizeof (struct sigaction));
01535 sig.sa_flags = SA_NODEFER;
01536 sig.sa_handler = &sigalrmHandler;
01537 sigaction (SIGALRM, &sig, &old);
01538 #else
01539 plibc_init ("CRISP", "libmicrohttpd");
01540 #endif
01541 #if HTTPS_SUPPORT
01542 if (0 != pthread_mutex_init(&MHD_gnutls_init_mutex, NULL))
01543 abort();
01544 #endif
01545 }
01546
01547 void __attribute__ ((destructor)) MHD_fini ()
01548 {
01549 #if HTTPS_SUPPORT
01550 if (0 != pthread_mutex_destroy(&MHD_gnutls_init_mutex))
01551 abort ();
01552 #endif
01553 #ifndef WINDOWS
01554 sigaction (SIGALRM, &old, &sig);
01555 #else
01556 plibc_shutdown ();
01557 #endif
01558 }
01559
01560