daemon.c

Go to the documentation of this file.
00001 /*
00002   This file is part of libmicrohttpd
00003   (C) 2007, 2008, 2009 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_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   /* IPv4 addresses */
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   /* IPv6 addresses */
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   /* Some other address */
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   /* Ignore if no connection limit assigned */
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   /* Initialize key */
00195   if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, key))
00196     {
00197       /* Allow unhandled address types through */
00198       free (key);
00199       return MHD_YES;
00200     }
00201 
00202   MHD_ip_count_lock (daemon);
00203 
00204   /* Search for the IP address */
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   /* If we got an existing node back, free the one we created */
00218   if (node != key)
00219     free(key);
00220   key = (struct MHD_IPCount*)node;
00221 
00222   /* Test if there is room for another connection; if so,
00223    * increment count */
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   /* Ignore if no connection limit assigned */
00247   if (daemon->per_ip_connection_limit == 0)
00248     return;
00249 
00250   /* Initialize search key */
00251   if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, &search_key))
00252     return;
00253 
00254   MHD_ip_count_lock (daemon);
00255 
00256   /* Search for the IP address */
00257   node = TFIND (&search_key, &daemon->per_ip_connection_count, MHD_ip_addr_compare);
00258 
00259   /* Something's wrong if we couldn't find an IP address
00260    * that was previously added */
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   /* Validate existing count for IP address */
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   /* Remove the node entirely if count reduces to 0 */
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   /* certificate & key loaded from memory */
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   /* update max file descriptor */
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           /* do not block (we're waiting for our callback to succeed) */
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       /* call appropriate connection handler if necessary */
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 ();                   /* fatal, serious error */
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       /* This could be a common occurance with multiple worker threads */
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           /* just in case */
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       /* above connection limit - reject */
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   /* apply connection acceptance policy if present */
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   /* set default connection handlers  */
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           /* set needed credentials for certificate authentication. */
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   /* attempt to create handler thread */
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;              /* no connections */
00807   now = time (NULL);
00808   /* start with conservative estimate */
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       /* single-threaded, go over everything */
00857       if (MHD_NO == MHD_get_fdset (daemon, &rs, &ws, &es, &max))
00858         return MHD_NO;
00859 
00860       /* If we're at the connection limit, no need to
00861          accept new connections. */
00862       if ( (daemon->max_connections == 0) && (daemon->socket_fd != -1) )
00863         FD_CLR(daemon->socket_fd, &rs);
00864     }
00865   else
00866     {
00867       /* accept only, have one thread per connection */
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       /* ltimeout is in ms */
00882       if (MHD_YES == MHD_get_timeout (daemon, &ltimeout))
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   /* select connection thread handling type */
00909   if (FD_ISSET (ds, &rs))
00910     MHD_accept_connection (daemon);
00911   if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
00912     {
00913       /* do not have a thread per connection, process all connections now */
00914       now = time (NULL);
00915       pos = daemon->connections;
00916       while (pos != NULL)
00917         {
00918           ds = pos->socket_fd;
00919           if (ds != -1)
00920             {
00921               /* TODO call con->read handler */
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;       /* no timeout */
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       /* lock MHD_gnutls_global mutex since it uses reference counting */
01055       pthread_mutex_lock (&MHD_gnutls_init_mutex);
01056       MHD__gnutls_global_init ();
01057       pthread_mutex_unlock (&MHD_gnutls_init_mutex);
01058       /* set default priorities */
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   /* Thread pooling currently works only with internal select thread model */
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   /* check for user supplied sockaddr */
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   /* initialize HTTPS daemon certificate aspects & send / recv functions */
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       /* Coarse-grained count of connections per thread (note error
01286        * due to integer division). Also keep track of how many
01287        * connections are leftover after an equal split. */
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; /* we need this in case fcntl or malloc fails */
01294 
01295       /* Accept must be non-blocking. Multiple children may wake up
01296        * to handle a new connection, but only one will win the race.
01297        * The others must immediately return. */
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       /* Allocate memory for pooled objects */
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       /* Start the workers in the pool */
01322       for (i = 0; i < retVal->worker_pool_size; ++i)
01323         {
01324           /* Create copy of the Daemon object for each worker */
01325           struct MHD_Daemon *d = &retVal->worker_pool[i];
01326           memcpy (d, retVal, sizeof (struct MHD_Daemon));
01327 
01328           /* Adjust pooling params for worker daemons; note that memcpy()
01329              has already copied MHD_USE_SELECT_INTERNALLY thread model into
01330              the worker threads. */
01331           d->master = retVal;
01332           d->worker_pool_size = 0;
01333           d->worker_pool = NULL;
01334 
01335           /* Divide available connections evenly amongst the threads.
01336            * Thread indexes in [0, leftover_conns) each get one of the
01337            * leftover connections. */
01338           d->max_connections = conns_per_thread;
01339           if (i < leftover_conns)
01340             ++d->max_connections;
01341 
01342           /* Spawn the worker thread */
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               /* Free memory for this worker; cleanup below handles
01350                * all previously-created workers. */
01351               goto thread_failed;
01352             }
01353         }
01354     }
01355   return retVal;
01356 
01357 thread_failed:
01358   /* If no worker threads created, then shut down normally. Calling
01359      MHD_stop_daemon (as we do below) doesn't work here since it
01360      assumes a 0-sized thread pool means we had been in the default
01361      MHD_USE_SELECT_INTERNALLY mode. */
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   /* Shutdown worker threads we've already created. Pretend
01373      as though we had fully initialized our daemon, but
01374      with a smaller number of threads than had been
01375      requested. */
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   /* Prepare workers for shutdown */
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   /* without this, either (thread pool = 0) threads would get stuck or
01428    * CLOSE would get stuck if attempted before (thread pool > 0) 
01429    * threads have ended */
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   /* Signal workers to stop and clean them up */
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   /* TLS clean up */
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       /* lock MHD_gnutls_global mutex since it uses reference counting */
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   /* make sure SIGALRM does not kill us */
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 /* end of daemon.c */

Generated on Sun Jul 26 17:20:54 2009 for GNU libmicrohttpd by  doxygen 1.5.9