daemon.c

Go to the documentation of this file.
00001 /*
00002   This file is part of libmicrohttpd
00003   (C) 2007, 2008 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 
00067 #if HTTPS_SUPPORT
00068 pthread_mutex_t MHD_gnutls_init_mutex;
00069 
00075 static int
00076 _set_priority (MHD_gtls_priority_st * st, const int *list)
00077 {
00078   int num = 0;
00079 
00080   while ((list[num] != 0) && (num < MAX_ALGOS))
00081     num++;
00082   st->num_algorithms = num;
00083   memcpy (st->priority, list, num * sizeof (int));
00084   return 0;
00085 }
00086 
00087 
00096 static ssize_t
00097 recv_tls_adapter (struct MHD_Connection *connection, void *other, size_t i)
00098 {
00099   return MHD__gnutls_record_recv (connection->tls_session, other, i);
00100 }
00101 
00110 static ssize_t
00111 send_tls_adapter (struct MHD_Connection *connection,
00112                   const void *other, size_t i)
00113 {
00114   return MHD__gnutls_record_send (connection->tls_session, other, i);
00115 }
00116 
00117 
00123 static int
00124 MHD_init_daemon_certificate (struct MHD_Daemon *daemon)
00125 {
00126   MHD_gnutls_datum_t key;
00127   MHD_gnutls_datum_t cert;
00128 
00129   /* certificate & key loaded from memory */
00130   if (daemon->https_mem_cert && daemon->https_mem_key)
00131     {
00132       key.data = (unsigned char *) daemon->https_mem_key;
00133       key.size = strlen (daemon->https_mem_key);
00134       cert.data = (unsigned char *) daemon->https_mem_cert;
00135       cert.size = strlen (daemon->https_mem_cert);
00136 
00137       return MHD__gnutls_certificate_set_x509_key_mem (daemon->x509_cred,
00138                                                        &cert, &key,
00139                                                        GNUTLS_X509_FMT_PEM);
00140     }
00141 #if HAVE_MESSAGES
00142   MHD_DLOG (daemon, "You need to specify a certificate and key location\n");
00143 #endif
00144   return -1;
00145 }
00146 
00152 static int
00153 MHD_TLS_init (struct MHD_Daemon *daemon)
00154 {
00155   switch (daemon->cred_type)
00156     {
00157     case MHD_GNUTLS_CRD_CERTIFICATE:
00158       if (0 !=
00159           MHD__gnutls_certificate_allocate_credentials (&daemon->x509_cred))
00160         return GNUTLS_E_MEMORY_ERROR;
00161       return MHD_init_daemon_certificate (daemon);
00162     default:
00163 #if HAVE_MESSAGES
00164       MHD_DLOG (daemon,
00165                 "Error: invalid credentials type %d specified.\n",
00166                 daemon->cred_type);
00167 #endif
00168       return -1;
00169     }
00170 }
00171 #endif
00172 
00180 int
00181 MHD_get_fdset (struct MHD_Daemon *daemon,
00182                fd_set * read_fd_set,
00183                fd_set * write_fd_set, fd_set * except_fd_set, int *max_fd)
00184 {
00185   struct MHD_Connection *con_itr;
00186   int fd;
00187 
00188   if ((daemon == NULL) || (read_fd_set == NULL) || (write_fd_set == NULL)
00189       || (except_fd_set == NULL) || (max_fd == NULL)
00190       || (-1 == (fd = daemon->socket_fd)) || (daemon->shutdown == MHD_YES)
00191       || ((daemon->options & MHD_USE_THREAD_PER_CONNECTION) != 0))
00192     return MHD_NO;
00193 
00194   FD_SET (fd, read_fd_set);
00195   /* update max file descriptor */
00196   if ((*max_fd) < fd)
00197     *max_fd = fd;
00198 
00199   con_itr = daemon->connections;
00200   while (con_itr != NULL)
00201     {
00202       if (MHD_YES != MHD_connection_get_fdset (con_itr,
00203                                                read_fd_set,
00204                                                write_fd_set,
00205                                                except_fd_set, max_fd))
00206         return MHD_NO;
00207       con_itr = con_itr->next;
00208     }
00209 #if DEBUG_CONNECT
00210   MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd);
00211 #endif
00212   return MHD_YES;
00213 }
00214 
00219 static void *
00220 MHD_handle_connection (void *data)
00221 {
00222   struct MHD_Connection *con = data;
00223   int num_ready;
00224   fd_set rs;
00225   fd_set ws;
00226   fd_set es;
00227   int max;
00228   struct timeval tv;
00229   unsigned int timeout;
00230   unsigned int now;
00231 
00232   if (con == NULL)
00233     abort ();
00234   timeout = con->daemon->connection_timeout;
00235   while ((!con->daemon->shutdown) && (con->socket_fd != -1))
00236     {
00237       FD_ZERO (&rs);
00238       FD_ZERO (&ws);
00239       FD_ZERO (&es);
00240       max = 0;
00241       MHD_connection_get_fdset (con, &rs, &ws, &es, &max);
00242       now = time (NULL);
00243       tv.tv_usec = 0;
00244       if (timeout > (now - con->last_activity))
00245         tv.tv_sec = timeout - (now - con->last_activity);
00246       else
00247         tv.tv_sec = 0;
00248       if ((con->state == MHD_CONNECTION_NORMAL_BODY_UNREADY) ||
00249           (con->state == MHD_CONNECTION_CHUNKED_BODY_UNREADY))
00250         {
00251           /* do not block (we're waiting for our callback to succeed) */
00252           timeout = 1;  
00253           tv.tv_sec = 0;
00254         }
00255       num_ready = SELECT (max + 1,
00256                           &rs, &ws, &es, (timeout != 0) ? &tv : NULL);
00257       if (num_ready < 0)
00258         {
00259           if (errno == EINTR)
00260             continue;
00261 #if HAVE_MESSAGES
00262           MHD_DLOG (con->daemon, "Error during select (%d): `%s'\n", max,
00263                     STRERROR (errno));
00264 #endif
00265           break;
00266         }
00267       /* call appropriate connection handler if necessary */
00268       if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &rs)))
00269         con->read_handler (con);
00270       if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &ws)))
00271         con->write_handler (con);
00272       if (con->socket_fd != -1)
00273         con->idle_handler (con);
00274     }
00275   if (con->socket_fd != -1)
00276     {
00277 #if DEBUG_CLOSE
00278 #if HAVE_MESSAGES
00279       MHD_DLOG (con->daemon,
00280                 "Processing thread terminating, closing connection\n");
00281 #endif
00282 #endif
00283       MHD_connection_close (con, MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
00284     }
00285   return NULL;
00286 }
00287 
00296 static ssize_t
00297 recv_param_adapter (struct MHD_Connection *connection, void *other, size_t i)
00298 {
00299   if (connection->socket_fd == -1)
00300     return -1;
00301   return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL);
00302 }
00303 
00312 static ssize_t
00313 send_param_adapter (struct MHD_Connection *connection,
00314                     const void *other, size_t i)
00315 {
00316   if (connection->socket_fd == -1)
00317     return -1;
00318   return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL);
00319 }
00320 
00326 static int
00327 MHD_accept_connection (struct MHD_Daemon *daemon)
00328 {
00329   struct MHD_Connection *pos;
00330   struct MHD_Connection *connection;
00331 #if HAVE_INET6
00332   struct sockaddr_in6 addrstorage;
00333 #else
00334   struct sockaddr_in addrstorage;
00335 #endif
00336   struct sockaddr *addr = (struct sockaddr *) &addrstorage;
00337   socklen_t addrlen;
00338   unsigned int have;
00339   int s, res_thread_create;
00340 #if OSX
00341   static int on = 1;
00342 #endif
00343 
00344 #if HAVE_INET6
00345   if (sizeof (struct sockaddr) > sizeof (struct sockaddr_in6))
00346     abort ();                   /* fatal, serious error */
00347 #endif
00348   addrlen = sizeof (addrstorage);
00349   memset (addr, 0, sizeof (addrstorage));
00350 
00351   s = ACCEPT (daemon->socket_fd, addr, &addrlen);
00352 
00353   if ((s < 0) || (addrlen <= 0))
00354     {
00355 #if HAVE_MESSAGES
00356       MHD_DLOG (daemon, "Error accepting connection: %s\n", STRERROR (errno));
00357 #endif
00358       if (s != -1)
00359         {
00360           SHUTDOWN (s, SHUT_RDWR);
00361           CLOSE (s);
00362           /* just in case */
00363         }
00364       return MHD_NO;
00365     }
00366 #if HAVE_MESSAGES
00367 #if DEBUG_CONNECT
00368   MHD_DLOG (daemon, "Accepted connection on socket %d\n", s);
00369 #endif
00370 #endif
00371   have = 0;
00372   if ((daemon->per_ip_connection_limit != 0) && (daemon->max_connections > 0))
00373     {
00374       pos = daemon->connections;
00375       while (pos != NULL)
00376         {
00377           if ((pos->addr != NULL) && (pos->addr_len == addrlen))
00378             {
00379               if (addrlen == sizeof (struct sockaddr_in))
00380                 {
00381                   const struct sockaddr_in *a1 =
00382                     (const struct sockaddr_in *) addr;
00383                   const struct sockaddr_in *a2 =
00384                     (const struct sockaddr_in *) pos->addr;
00385                   if (0 == memcmp (&a1->sin_addr, &a2->sin_addr,
00386                                    sizeof (struct in_addr)))
00387                     have++;
00388                 }
00389 #if HAVE_INET6
00390               if (addrlen == sizeof (struct sockaddr_in6))
00391                 {
00392                   const struct sockaddr_in6 *a1 =
00393                     (const struct sockaddr_in6 *) addr;
00394                   const struct sockaddr_in6 *a2 =
00395                     (const struct sockaddr_in6 *) pos->addr;
00396                   if (0 == memcmp (&a1->sin6_addr, &a2->sin6_addr,
00397                                    sizeof (struct in6_addr)))
00398                     have++;
00399                 }
00400 #endif
00401             }
00402           pos = pos->next;
00403         }
00404     }
00405 
00406   if ((daemon->max_connections == 0) || ((daemon->per_ip_connection_limit
00407                                           != 0)
00408                                          && (daemon->per_ip_connection_limit
00409                                              <= have)))
00410     {
00411       /* above connection limit - reject */
00412 #if HAVE_MESSAGES
00413       MHD_DLOG (daemon,
00414                 "Server reached connection limit (closing inbound connection)\n");
00415 #endif
00416       SHUTDOWN (s, SHUT_RDWR);
00417       CLOSE (s);
00418       return MHD_NO;
00419     }
00420 
00421   /* apply connection acceptance policy if present */
00422   if ((daemon->apc != NULL)
00423       && (MHD_NO == daemon->apc (daemon->apc_cls, addr, addrlen)))
00424     {
00425 #if DEBUG_CLOSE
00426 #if HAVE_MESSAGES
00427       MHD_DLOG (daemon, "Connection rejected, closing connection\n");
00428 #endif
00429 #endif
00430       SHUTDOWN (s, SHUT_RDWR);
00431       CLOSE (s);
00432       return MHD_YES;
00433     }
00434 #if OSX
00435 #ifdef SOL_SOCKET
00436 #ifdef SO_NOSIGPIPE
00437   setsockopt (s, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof (on));
00438 #endif
00439 #endif
00440 #endif
00441   connection = malloc (sizeof (struct MHD_Connection));
00442   if (connection == NULL)
00443     {
00444 #if HAVE_MESSAGES
00445       MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno));
00446 #endif
00447       SHUTDOWN (s, SHUT_RDWR);
00448       CLOSE (s);
00449       return MHD_NO;
00450     }
00451   memset (connection, 0, sizeof (struct MHD_Connection));
00452   connection->pool = NULL;
00453   connection->addr = malloc (addrlen);
00454   if (connection->addr == NULL)
00455     {
00456 #if HAVE_MESSAGES
00457       MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno));
00458 #endif
00459       SHUTDOWN (s, SHUT_RDWR);
00460       CLOSE (s);
00461       free (connection);
00462       return MHD_NO;
00463     }
00464   memcpy (connection->addr, addr, addrlen);
00465   connection->addr_len = addrlen;
00466   connection->socket_fd = s;
00467   connection->daemon = daemon;
00468   connection->last_activity = time (NULL);
00469 
00470   /* set default connection handlers  */
00471   MHD_set_http_calbacks (connection);
00472   connection->recv_cls = &recv_param_adapter;
00473   connection->send_cls = &send_param_adapter;
00474 #if HTTPS_SUPPORT
00475   if (0 != (daemon->options & MHD_USE_SSL))
00476     {
00477       connection->recv_cls = &recv_tls_adapter;
00478       connection->send_cls = &send_tls_adapter;
00479       connection->state = MHD_TLS_CONNECTION_INIT;
00480       MHD_set_https_calbacks (connection);
00481       MHD__gnutls_init (&connection->tls_session, GNUTLS_SERVER);
00482       MHD__gnutls_priority_set (connection->tls_session,
00483                                 connection->daemon->priority_cache);
00484       switch (connection->daemon->cred_type)
00485         {
00486           /* set needed credentials for certificate authentication. */
00487         case MHD_GNUTLS_CRD_CERTIFICATE:
00488           MHD__gnutls_credentials_set (connection->tls_session,
00489                                        MHD_GNUTLS_CRD_CERTIFICATE,
00490                                        connection->daemon->x509_cred);
00491           break;
00492         default:
00493 #if HAVE_MESSAGES
00494           MHD_DLOG (connection->daemon,
00495                     "Failed to setup TLS credentials: unknown credential type %d\n",
00496                     connection->daemon->cred_type);
00497 #endif
00498           abort ();
00499         }
00500       MHD__gnutls_transport_set_ptr (connection->tls_session,
00501                                      (MHD_gnutls_transport_ptr_t) connection);
00502       MHD__gnutls_transport_set_pull_function (connection->tls_session,
00503                                                (MHD_gtls_pull_func) &
00504                                                recv_param_adapter);
00505       MHD__gnutls_transport_set_push_function (connection->tls_session,
00506                                                (MHD_gtls_push_func) &
00507                                                send_param_adapter);
00508     }
00509 #endif
00510 
00511   /* attempt to create handler thread */
00512   if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
00513     {
00514       res_thread_create = pthread_create (&connection->pid, NULL,
00515                                           &MHD_handle_connection, connection);
00516       if (res_thread_create != 0)
00517         {
00518 #if HAVE_MESSAGES
00519           MHD_DLOG (daemon, "Failed to create a thread: %s\n",
00520                     STRERROR (errno));
00521 #endif
00522           SHUTDOWN (s, SHUT_RDWR);
00523           CLOSE (s);
00524           free (connection->addr);
00525           free (connection);
00526           return MHD_NO;
00527         }
00528     }
00529   connection->next = daemon->connections;
00530   daemon->connections = connection;
00531   daemon->max_connections--;
00532   return MHD_YES;
00533 }
00534 
00540 static void
00541 MHD_cleanup_connections (struct MHD_Daemon *daemon)
00542 {
00543   struct MHD_Connection *pos;
00544   struct MHD_Connection *prev;
00545   void *unused;
00546 
00547   pos = daemon->connections;
00548   prev = NULL;
00549   while (pos != NULL)
00550     {
00551       if ((pos->socket_fd == -1) ||
00552           (((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
00553             (daemon->shutdown) && (pos->socket_fd != -1))))
00554         {
00555           if (prev == NULL)
00556             daemon->connections = pos->next;
00557           else
00558             prev->next = pos->next;
00559           if (0 != (pos->daemon->options & MHD_USE_THREAD_PER_CONNECTION))
00560             {
00561               pthread_kill (pos->pid, SIGALRM);
00562               pthread_join (pos->pid, &unused);
00563             }
00564           MHD_destroy_response (pos->response);
00565           MHD_pool_destroy (pos->pool);
00566 #if HTTPS_SUPPORT
00567           if (pos->tls_session != NULL)
00568             MHD__gnutls_deinit (pos->tls_session);
00569 #endif
00570           free (pos->addr);
00571           free (pos);
00572           daemon->max_connections++;
00573           if (prev == NULL)
00574             pos = daemon->connections;
00575           else
00576             pos = prev->next;
00577           continue;
00578         }
00579       prev = pos;
00580       pos = pos->next;
00581     }
00582 }
00583 
00595 int
00596 MHD_get_timeout (struct MHD_Daemon *daemon, unsigned long long *timeout)
00597 {
00598   time_t earliest_deadline;
00599   time_t now;
00600   struct MHD_Connection *pos;
00601   unsigned int dto;
00602 
00603   dto = daemon->connection_timeout;
00604   if (0 == dto)
00605     return MHD_NO;
00606   pos = daemon->connections;
00607   if (pos == NULL)
00608     return MHD_NO;              /* no connections */
00609   now = time (NULL);
00610   /* start with conservative estimate */
00611   earliest_deadline = now + dto;
00612   while (pos != NULL)
00613     {
00614       if (earliest_deadline > pos->last_activity + dto)
00615         earliest_deadline = pos->last_activity + dto;
00616       pos = pos->next;
00617     }
00618   if (earliest_deadline < now)
00619     *timeout = 0;
00620   else
00621     *timeout = (earliest_deadline - now);
00622   return MHD_YES;
00623 }
00624 
00631 static int
00632 MHD_select (struct MHD_Daemon *daemon, int may_block)
00633 {
00634   struct MHD_Connection *pos;
00635   int num_ready;
00636   fd_set rs;
00637   fd_set ws;
00638   fd_set es;
00639   int max;
00640   struct timeval timeout;
00641   unsigned long long ltimeout;
00642   int ds;
00643   time_t now;
00644 
00645   timeout.tv_sec = 0;
00646   timeout.tv_usec = 0;
00647   if (daemon == NULL)
00648     abort ();
00649   if (daemon->shutdown == MHD_YES)
00650     return MHD_NO;
00651   FD_ZERO (&rs);
00652   FD_ZERO (&ws);
00653   FD_ZERO (&es);
00654   max = 0;
00655 
00656   if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
00657     {
00658       /* single-threaded, go over everything */
00659       if (MHD_NO == MHD_get_fdset (daemon, &rs, &ws, &es, &max))
00660         return MHD_NO;
00661     }
00662   else
00663     {
00664       /* accept only, have one thread per connection */
00665       max = daemon->socket_fd;
00666       if (max == -1)
00667         return MHD_NO;
00668       FD_SET (max, &rs);
00669     }
00670 
00671   if (may_block == MHD_NO)
00672     {
00673       timeout.tv_usec = 0;
00674       timeout.tv_sec = 0;
00675     }
00676   else
00677     {
00678       /* ltimeout is in ms */
00679       if (MHD_YES == MHD_get_timeout (daemon, &ltimeout))
00680         {
00681           timeout.tv_usec = (ltimeout % 1000) * 1000;
00682           timeout.tv_sec = ltimeout / 1000;
00683           may_block = MHD_NO;
00684         }
00685     }
00686 
00687   num_ready = select (max + 1, &rs, &ws, &es, may_block == MHD_NO ? &timeout
00688                       : NULL);
00689 
00690   if (daemon->shutdown == MHD_YES)
00691     return MHD_NO;
00692   if (num_ready < 0)
00693     {
00694       if (errno == EINTR)
00695         return MHD_YES;
00696 #if HAVE_MESSAGES
00697       MHD_DLOG (daemon, "select failed: %s\n", STRERROR (errno));
00698 #endif
00699       return MHD_NO;
00700     }
00701   ds = daemon->socket_fd;
00702   if (ds == -1)
00703     return MHD_YES;
00704 
00705   /* select connection thread handling type */
00706   if (FD_ISSET (ds, &rs))
00707     MHD_accept_connection (daemon);
00708   if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
00709     {
00710       /* do not have a thread per connection, process all connections now */
00711       now = time (NULL);
00712       pos = daemon->connections;
00713       while (pos != NULL)
00714         {
00715           ds = pos->socket_fd;
00716           if (ds != -1)
00717             {
00718               /* TODO call con->read handler */
00719               if (FD_ISSET (ds, &rs))
00720                 pos->read_handler (pos);
00721               if ((pos->socket_fd != -1) && (FD_ISSET (ds, &ws)))
00722                 pos->write_handler (pos);
00723               if (pos->socket_fd != -1)
00724                 pos->idle_handler (pos);
00725             }
00726           pos = pos->next;
00727         }
00728     }
00729   return MHD_YES;
00730 }
00731 
00742 int
00743 MHD_run (struct MHD_Daemon *daemon)
00744 {
00745   if ((daemon->shutdown != MHD_NO) || (0 != (daemon->options
00746                                              & MHD_USE_THREAD_PER_CONNECTION))
00747       || (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)))
00748     return MHD_NO;
00749   MHD_select (daemon, MHD_NO);
00750   MHD_cleanup_connections (daemon);
00751   return MHD_YES;
00752 }
00753 
00758 static void *
00759 MHD_select_thread (void *cls)
00760 {
00761   struct MHD_Daemon *daemon = cls;
00762   while (daemon->shutdown == MHD_NO)
00763     {
00764       MHD_select (daemon, MHD_YES);
00765       MHD_cleanup_connections (daemon);
00766     }
00767   return NULL;
00768 }
00769 
00781 struct MHD_Daemon *
00782 MHD_start_daemon (unsigned int options,
00783                   unsigned short port,
00784                   MHD_AcceptPolicyCallback apc,
00785                   void *apc_cls,
00786                   MHD_AccessHandlerCallback dh, void *dh_cls, ...)
00787 {
00788   struct MHD_Daemon *ret;
00789   va_list ap;
00790 
00791   va_start (ap, dh_cls);
00792   ret = MHD_start_daemon_va (options, port, apc, apc_cls, dh, dh_cls, ap);
00793   va_end (ap);
00794   return ret;
00795 }
00796 
00808 struct MHD_Daemon *
00809 MHD_start_daemon_va (unsigned int options,
00810                      unsigned short port,
00811                      MHD_AcceptPolicyCallback apc,
00812                      void *apc_cls,
00813                      MHD_AccessHandlerCallback dh, void *dh_cls, va_list ap)
00814 {
00815   const int on = 1;
00816   struct MHD_Daemon *retVal;
00817   int socket_fd;
00818   struct sockaddr_in servaddr4;
00819 #if HAVE_INET6
00820   struct sockaddr_in6 servaddr6;
00821 #endif
00822   const struct sockaddr *servaddr = NULL;
00823   socklen_t addrlen;
00824   enum MHD_OPTION opt;
00825 
00826   if ((port == 0) || (dh == NULL))
00827     return NULL;
00828   retVal = malloc (sizeof (struct MHD_Daemon));
00829   if (retVal == NULL)
00830     return NULL;
00831   memset (retVal, 0, sizeof (struct MHD_Daemon));
00832   retVal->options = options;
00833   retVal->port = port;
00834   retVal->apc = apc;
00835   retVal->apc_cls = apc_cls;
00836   retVal->default_handler = dh;
00837   retVal->default_handler_cls = dh_cls;
00838   retVal->max_connections = MHD_MAX_CONNECTIONS_DEFAULT;
00839   retVal->pool_size = MHD_POOL_SIZE_DEFAULT;
00840   retVal->connection_timeout = 0;       /* no timeout */
00841 #if HAVE_MESSAGES
00842   retVal->custom_error_log =
00843     (void (*)(void *, const char *, va_list)) &vfprintf;
00844   retVal->custom_error_log_cls = stderr;
00845 #endif
00846 #if HTTPS_SUPPORT
00847   if (options & MHD_USE_SSL)
00848     {
00849       /* lock MHD_gnutls_global mutex since it uses reference counting */
00850       pthread_mutex_lock (&MHD_gnutls_init_mutex);
00851       MHD__gnutls_global_init ();
00852       pthread_mutex_unlock (&MHD_gnutls_init_mutex);
00853       /* set default priorities */
00854       MHD_tls_set_default_priority (&retVal->priority_cache, "", NULL);
00855       retVal->cred_type = MHD_GNUTLS_CRD_CERTIFICATE;
00856     }
00857 #endif
00858 
00859   while (MHD_OPTION_END != (opt = va_arg (ap, enum MHD_OPTION)))
00860     {
00861       switch (opt)
00862         {
00863         case MHD_OPTION_CONNECTION_MEMORY_LIMIT:
00864           retVal->pool_size = va_arg (ap, size_t);
00865           break;
00866         case MHD_OPTION_CONNECTION_LIMIT:
00867           retVal->max_connections = va_arg (ap, unsigned int);
00868           break;
00869         case MHD_OPTION_CONNECTION_TIMEOUT:
00870           retVal->connection_timeout = va_arg (ap, unsigned int);
00871           break;
00872         case MHD_OPTION_NOTIFY_COMPLETED:
00873           retVal->notify_completed =
00874             va_arg (ap, MHD_RequestCompletedCallback);
00875           retVal->notify_completed_cls = va_arg (ap, void *);
00876           break;
00877         case MHD_OPTION_PER_IP_CONNECTION_LIMIT:
00878           retVal->per_ip_connection_limit = va_arg (ap, unsigned int);
00879           break;
00880         case MHD_OPTION_SOCK_ADDR:
00881           servaddr = va_arg (ap, struct sockaddr *);
00882           break;
00883         case MHD_OPTION_URI_LOG_CALLBACK:
00884           retVal->uri_log_callback =
00885             va_arg (ap, LogCallback);
00886           retVal->uri_log_callback_cls = va_arg (ap, void *);
00887           break;
00888 #if HTTPS_SUPPORT
00889         case MHD_OPTION_PROTOCOL_VERSION:
00890           _set_priority (&retVal->priority_cache->protocol,
00891                          va_arg (ap, const int *));
00892           break;
00893         case MHD_OPTION_HTTPS_MEM_KEY:
00894           retVal->https_mem_key = va_arg (ap, const char *);
00895           break;
00896         case MHD_OPTION_HTTPS_MEM_CERT:
00897           retVal->https_mem_cert = va_arg (ap, const char *);
00898           break;
00899         case MHD_OPTION_CIPHER_ALGORITHM:
00900           _set_priority (&retVal->priority_cache->cipher,
00901                          va_arg (ap, const int *));
00902           break;
00903 #endif
00904         case MHD_OPTION_EXTERNAL_LOGGER:
00905 #if HAVE_MESSAGES
00906           retVal->custom_error_log =
00907             va_arg (ap, void (*)(void *cls, const char *, va_list));
00908           retVal->custom_error_log_cls = va_arg (ap, void *);
00909 #else
00910           va_arg (ap, void (*)(void *cls, const char *, ...));
00911           va_arg (ap, void *);
00912 #endif
00913           break;
00914         default:
00915 #if HAVE_MESSAGES
00916           if ((opt >= MHD_OPTION_HTTPS_MEM_KEY) &&
00917               (opt <= MHD_OPTION_CIPHER_ALGORITHM))
00918             {
00919               FPRINTF (stderr,
00920                        "MHD HTTPS option %d passed to MHD compiled without HTTPS support\n",
00921                        opt);
00922             }
00923           else
00924             {
00925               FPRINTF (stderr,
00926                        "Invalid option %d! (Did you terminate the list with MHD_OPTION_END?)\n",
00927                        opt);
00928             }
00929 #endif
00930           abort ();
00931         }
00932     }
00933 
00934   if ((options & MHD_USE_IPv6) != 0)
00935 #if HAVE_INET6
00936     socket_fd = SOCKET (PF_INET6, SOCK_STREAM, 0);
00937 #else
00938     {
00939 #if HAVE_MESSAGES
00940       FPRINTF (stderr, "AF_INET6 not supported\n");
00941 #endif
00942       return NULL;
00943     }
00944 #endif
00945   else
00946     socket_fd = SOCKET (PF_INET, SOCK_STREAM, 0);
00947   if (socket_fd < 0)
00948     {
00949 #if HAVE_MESSAGES
00950       if ((options & MHD_USE_DEBUG) != 0)
00951         FPRINTF (stderr, "Call to socket failed: %s\n", STRERROR (errno));
00952 #endif
00953       free (retVal);
00954       return NULL;
00955     }
00956   if ((SETSOCKOPT (socket_fd,
00957                    SOL_SOCKET,
00958                    SO_REUSEADDR,
00959                    &on, sizeof (on)) < 0) && (options & MHD_USE_DEBUG) != 0)
00960     {
00961 #if HAVE_MESSAGES
00962       FPRINTF (stderr, "setsockopt failed: %s\n", STRERROR (errno));
00963 #endif
00964     }
00965 
00966   /* check for user supplied sockaddr */
00967 #if HAVE_INET6
00968   if ((options & MHD_USE_IPv6) != 0)
00969     addrlen = sizeof (struct sockaddr_in6);
00970   else
00971 #endif
00972     addrlen = sizeof (struct sockaddr_in);
00973   if (NULL == servaddr)
00974     {
00975 #if HAVE_INET6
00976       if ((options & MHD_USE_IPv6) != 0)
00977         {
00978           memset (&servaddr6, 0, sizeof (struct sockaddr_in6));
00979           servaddr6.sin6_family = AF_INET6;
00980           servaddr6.sin6_port = htons (port);
00981           servaddr = (struct sockaddr *) &servaddr6;
00982         }
00983       else
00984 #endif
00985         {
00986           memset (&servaddr4, 0, sizeof (struct sockaddr_in));
00987           servaddr4.sin_family = AF_INET;
00988           servaddr4.sin_port = htons (port);
00989           servaddr = (struct sockaddr *) &servaddr4;
00990         }
00991     }
00992   retVal->socket_fd = socket_fd;
00993   if (BIND (socket_fd, servaddr, addrlen) < 0)
00994     {
00995 #if HAVE_MESSAGES
00996       if ((options & MHD_USE_DEBUG) != 0)
00997         FPRINTF (stderr,
00998                  "Failed to bind to port %u: %s\n", port, STRERROR (errno));
00999 #endif
01000       CLOSE (socket_fd);
01001       free (retVal);
01002       return NULL;
01003     }
01004 
01005 
01006   if (LISTEN (socket_fd, 20) < 0)
01007     {
01008 #if HAVE_MESSAGES
01009       if ((options & MHD_USE_DEBUG) != 0)
01010         FPRINTF (stderr,
01011                  "Failed to listen for connections: %s\n", STRERROR (errno));
01012 #endif
01013       CLOSE (socket_fd);
01014       free (retVal);
01015       return NULL;
01016     }
01017 
01018 #if HTTPS_SUPPORT
01019   /* initialize HTTPS daemon certificate aspects & send / recv functions */
01020   if ((0 != (options & MHD_USE_SSL)) && (0 != MHD_TLS_init (retVal)))
01021     {
01022 #if HAVE_MESSAGES
01023       MHD_DLOG (retVal, "Failed to initialize TLS support\n");
01024 #endif
01025       CLOSE (socket_fd);
01026       free (retVal);
01027       return NULL;
01028     }
01029 #endif
01030   if (((0 != (options & MHD_USE_THREAD_PER_CONNECTION)) ||
01031        (0 != (options & MHD_USE_SELECT_INTERNALLY)))
01032       && (0 !=
01033           pthread_create (&retVal->pid, NULL, &MHD_select_thread, retVal)))
01034     {
01035 #if HAVE_MESSAGES
01036       MHD_DLOG (retVal,
01037                 "Failed to create listen thread: %s\n", STRERROR (errno));
01038 #endif
01039       free (retVal);
01040       CLOSE (socket_fd);
01041       return NULL;
01042     }
01043   return retVal;
01044 }
01045 
01049 void
01050 MHD_stop_daemon (struct MHD_Daemon *daemon)
01051 {
01052   void *unused;
01053   int fd;
01054 
01055   if (daemon == NULL)
01056     return;
01057   daemon->shutdown = MHD_YES;
01058   fd = daemon->socket_fd;
01059   daemon->socket_fd = -1;
01060 #if DEBUG_CLOSE
01061 #if HAVE_MESSAGES
01062   MHD_DLOG (daemon, "MHD shutdown, closing listen socket\n");
01063 #endif
01064 #endif
01065   CLOSE (fd);
01066   if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
01067       (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)))
01068     {
01069       pthread_kill (daemon->pid, SIGALRM);
01070       pthread_join (daemon->pid, &unused);
01071     }
01072   while (daemon->connections != NULL)
01073     {
01074       if (-1 != daemon->connections->socket_fd)
01075         {
01076 #if DEBUG_CLOSE
01077 #if HAVE_MESSAGES
01078           MHD_DLOG (daemon, "MHD shutdown, closing active connections\n");
01079 #endif
01080 #endif
01081           MHD_connection_close (daemon->connections,
01082                                 MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
01083         }
01084       MHD_cleanup_connections (daemon);
01085     }
01086 
01087   /* TLS clean up */
01088 #if HTTPS_SUPPORT
01089   if (daemon->options & MHD_USE_SSL)
01090     {
01091       MHD__gnutls_priority_deinit (daemon->priority_cache);
01092       if (daemon->x509_cred)
01093         MHD__gnutls_certificate_free_credentials (daemon->x509_cred);
01094       /* lock MHD_gnutls_global mutex since it uses reference counting */
01095       pthread_mutex_lock (&MHD_gnutls_init_mutex);
01096       MHD__gnutls_global_deinit ();
01097       pthread_mutex_unlock (&MHD_gnutls_init_mutex);
01098     }
01099 #endif
01100   free (daemon);
01101 }
01102 
01113 const union MHD_DaemonInfo *
01114 MHD_get_daemon_info (struct MHD_Daemon *daemon,
01115                      enum MHD_DaemonInfoType infoType, ...)
01116 {
01117   return NULL;
01118 }
01119 
01120 #ifndef WINDOWS
01121 
01122 static struct sigaction sig;
01123 
01124 static struct sigaction old;
01125 
01126 static void
01127 sigalrmHandler (int sig)
01128 {
01129 }
01130 #endif
01131 
01136 void __attribute__ ((constructor)) MHD_init ()
01137 {
01138 #ifndef WINDOWS
01139   /* make sure SIGALRM does not kill us */
01140   memset (&sig, 0, sizeof (struct sigaction));
01141   memset (&old, 0, sizeof (struct sigaction));
01142   sig.sa_flags = SA_NODEFER;
01143   sig.sa_handler = &sigalrmHandler;
01144   sigaction (SIGALRM, &sig, &old);
01145 #else
01146   plibc_init ("CRISP", "libmicrohttpd");
01147 #endif
01148 #if HTTPS_SUPPORT
01149   if (0 != pthread_mutex_init(&MHD_gnutls_init_mutex, NULL))
01150     abort();
01151 #endif
01152 }
01153 
01154 void __attribute__ ((destructor)) MHD_fini ()
01155 {
01156 #if HTTPS_SUPPORT
01157   if (0 != pthread_mutex_destroy(&MHD_gnutls_init_mutex))
01158     abort ();
01159 #endif
01160 #ifndef WINDOWS
01161   sigaction (SIGALRM, &old, &sig);
01162 #else
01163   plibc_shutdown ();
01164 #endif
01165 }
01166 
01167 /* end of daemon.c */

Generated on Tue May 19 23:21:07 2009 for GNU libmicrohttpd by  doxygen 1.5.8