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

Generated on Sun Nov 16 16:53:03 2008 for GNU libmicrohttpd by  doxygen 1.5.1