nanohttp-server.c

Go to the documentation of this file.
00001 /******************************************************************
00002 *  $Id: nanohttp-server.c,v 1.80 2007/01/01 22:54:46 m0gg Exp $
00003 *
00004 * CSOAP Project:  A http client/server library in C
00005 * Copyright (C) 2003  Ferhat Ayaz
00006 *
00007 * This library is free software; you can redistribute it and/or
00008 * modify it under the terms of the GNU Library General Public
00009 * License as published by the Free Software Foundation; either
00010 * version 2 of the License, or (at your option) any later version.
00011 *
00012 * This library is distributed in the hope that it will be useful,
00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 * Library General Public License for more details.
00016 *
00017 * You should have received a copy of the GNU Library General Public
00018 * License along with this library; if not, write to the
00019 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020 * Boston, MA  02111-1307, USA.
00021 *
00022 * Email: ayaz@jprogrammer.net
00023 ******************************************************************/
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #ifdef HAVE_SYS_SELECT_H
00029 #include <sys/select.h>
00030 #endif
00031 
00032 #ifdef HAVE_SOCKET_H
00033 #include <sys/socket.h>
00034 #endif
00035 
00036 #ifdef HAVE_SYS_TIME_H
00037 #include <sys/time.h>
00038 #endif
00039 
00040 #ifdef HAVE_SYS_TYPES_H
00041 #include <sys/types.h>
00042 #endif
00043 
00044 #ifdef HAVE_NETINET_IN_H
00045 #include <netinet/in.h>
00046 #endif
00047 
00048 #ifdef HAVE_STDIO_H
00049 #include <stdio.h>
00050 #endif
00051 
00052 #ifdef HAVE_STDLIB_H
00053 #include <stdlib.h>
00054 #endif
00055 
00056 #ifdef HAVE_SIGNAL_H
00057 #include <signal.h>
00058 #endif
00059 
00060 #ifdef HAVE_STRING_H
00061 #include <string.h>
00062 #endif
00063 
00064 #ifdef HAVE_UNISTD_H
00065 #include <unistd.h>
00066 #endif
00067 
00068 #ifdef HAVE_ERRNO_H
00069 #include <errno.h>
00070 #endif
00071 
00072 #ifdef HAVE_PTHREAD_H
00073 #include <pthread.h>
00074 #endif
00075 
00076 #ifdef HAVE_PROCESS_H
00077 #include <process.h>
00078 #endif
00079 
00080 #include "nanohttp-logging.h"
00081 #include "nanohttp-error.h"
00082 #include "nanohttp-common.h"
00083 #include "nanohttp-socket.h"
00084 #include "nanohttp-stream.h"
00085 #include "nanohttp-request.h"
00086 #include "nanohttp-response.h"
00087 #include "nanohttp-server.h"
00088 #include "nanohttp-base64.h"
00089 #ifdef HAVE_SSL
00090 #ifdef HAVE_OPENSSL_SSL_H
00091 #include <openssl/ssl.h>
00092 #endif
00093 #include "nanohttp-ssl.h"
00094 #else
00095 static inline int hssl_enabled(void) { return 0; }
00096 #endif
00097 #include "nanohttp-admin.h"
00098 
00099 #ifndef timeradd
00100 #define timeradd(tvp, uvp, vvp)                                         \
00101         do {                                                            \
00102                 (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;          \
00103                 (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec;       \
00104                 if ((vvp)->tv_usec >= 1000000) {                        \
00105                         (vvp)->tv_sec++;                                \
00106                         (vvp)->tv_usec -= 1000000;                      \
00107                 }                                                       \
00108         } while (0)
00109 #endif
00110 
00111 #ifndef timersub
00112 #define timersub(tvp, uvp, vvp)                                         \
00113         do {                                                            \
00114                 (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;          \
00115                 (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;       \
00116                 if ((vvp)->tv_usec < 0) {                               \
00117                         (vvp)->tv_sec--;                                \
00118                         (vvp)->tv_usec += 1000000;                      \
00119                 }                                                       \
00120         } while (0)
00121 #endif
00122 
00123 typedef struct _conndata
00124 {
00125   volatile int flag;
00126   struct hsocket_t sock;
00127 #ifdef WIN32
00128   HANDLE tid;
00129 #else
00130   pthread_t tid;
00131   pthread_attr_t attr;
00132 #endif
00133 }
00134 conndata_t;
00135 
00136 #define CONNECTION_FREE         0
00137 #define CONNECTION_IN_USE       1
00138 
00144 static volatile int _httpd_run = 1;
00145 
00146 static struct hsocket_t _httpd_socket;
00147 static int _httpd_port = 10000;
00148 static int _httpd_max_connections = 20;
00149 
00150 static hservice_t *_httpd_services_default = NULL;
00151 static hservice_t *_httpd_services_head = NULL;
00152 static hservice_t *_httpd_services_tail = NULL;
00153 
00154 static conndata_t *_httpd_connection;
00155 
00156 #ifdef WIN32
00157 static DWORD _httpd_terminate_signal = CTRL_C_EVENT;
00158 static int _httpd_max_idle = 120;
00159 HANDLE _httpd_connection_lock;
00160 LPCTSTR _httpd_connection_lock_str;
00161 #define strncasecmp(s1, s2, num) strncmp(s1, s2, num)
00162 #define snprintf(buffer, num, s1, s2) sprintf(buffer, s1,s2)
00163 #else
00164 static int _httpd_terminate_signal = SIGINT;
00165 static sigset_t thrsigset;
00166 static pthread_mutex_t _httpd_connection_lock;
00167 #endif
00168 
00169 #ifdef WIN32
00170 BOOL WINAPI
00171 _httpd_term(DWORD sig)
00172 {
00173   /* log_debug2 ("Got signal %d", sig); */
00174   if (sig == _httpd_terminate_signal)
00175     _httpd_run = 0;
00176 
00177   return TRUE;
00178 }
00179 
00180 static void _httpd_sys_sleep(int secs)
00181 {
00182   Sleep(secs*1000);
00183 
00184   return;
00185 }
00186 #else
00187 static void
00188 _httpd_term(int sig)
00189 {
00190   log_debug2("Got signal %d", sig);
00191 
00192   if (sig == _httpd_terminate_signal)
00193     _httpd_run = 0;
00194 
00195   return;
00196 }
00197 
00198 static inline void _httpd_sys_sleep(int secs)
00199 {
00200   sleep(secs);
00201 
00202   return;
00203 }
00204 #endif
00205 
00206 static void
00207 _httpd_parse_arguments(int argc, char **argv)
00208 {
00209   int i;
00210 
00211   for (i = 1; i < argc; i++)
00212   {
00213     if (!strcmp(argv[i - 1], NHTTPD_ARG_PORT))
00214     {
00215       _httpd_port = atoi(argv[i]);
00216     }
00217     else if (!strcmp(argv[i - 1], NHTTPD_ARG_TERMSIG))
00218     {
00219       _httpd_terminate_signal = atoi(argv[i]);
00220     }
00221     else if (!strcmp(argv[i - 1], NHTTPD_ARG_MAXCONN))
00222     {
00223       _httpd_max_connections = atoi(argv[i]);
00224     }
00225     else if (!strcmp(argv[i - 1], NHTTPD_ARG_TIMEOUT))
00226     {
00227       hsocket_set_timeout(atoi(argv[i]));
00228     }
00229   }
00230 
00231   log_verbose2("socket bind to port '%d'", _httpd_port);
00232 
00233   return;
00234 }
00235 
00236 
00237 static void
00238 _httpd_connection_slots_init(void)
00239 {
00240   int i;
00241 
00242 #ifdef WIN32
00243   _httpd_connection_lock = CreateMutex( NULL, TRUE, _httpd_connection_lock_str );
00244 #else
00245   pthread_mutex_init(&_httpd_connection_lock, NULL);
00246 #endif
00247 
00248   _httpd_connection = calloc(_httpd_max_connections, sizeof(conndata_t));
00249   for (i = 0; i < _httpd_max_connections; i++)
00250     hsocket_init(&(_httpd_connection[i].sock));
00251 
00252   return;
00253 }
00254 
00255 static herror_t
00256 _httpd_register_builtin_services(int argc, char **argv)
00257 {
00258   herror_t status;
00259 
00260   if ((status = httpd_admin_init_args(argc, argv)) != H_OK)
00261   {
00262     log_error2("httpd_admin_init_args failed (%s)", herror_message(status));
00263     return status;
00264   }
00265 
00266   return H_OK;
00267 }
00268 
00269 herror_t
00270 httpd_init(int argc, char **argv)
00271 {
00272   herror_t status;
00273 
00274   _httpd_parse_arguments(argc, argv);
00275 
00276   if ((status = hsocket_module_init(argc, argv)) != H_OK)
00277   {
00278     log_error2("hsocket_modeule_init failed (%s)", herror_message(status));
00279     return status;
00280   } 
00281 
00282   _httpd_connection_slots_init();
00283 
00284   if ((status = _httpd_register_builtin_services(argc, argv)) != H_OK)
00285   {
00286     log_error2("_httpd_register_builtin_services failed (%s)", herror_message(status));
00287     return status;
00288   }
00289 
00290   if ((status = hsocket_init(&_httpd_socket)) != H_OK)
00291   {
00292     log_error2("hsocket_init failed (%s)", herror_message(status));
00293     return status;
00294   }
00295 
00296   if ((status = hsocket_bind(&_httpd_socket, _httpd_port)) != H_OK)
00297   {
00298     log_error2("hsocket_bind failed (%s)", herror_message(status));
00299     return status;
00300   }
00301 
00302   return H_OK;
00303 }
00304 
00305 herror_t
00306 httpd_register_secure(const char *context, httpd_service func, httpd_auth auth)
00307 {
00308   hservice_t *service;
00309 
00310   if (!(service = (hservice_t *) malloc(sizeof(hservice_t))))
00311   {
00312     log_error2("malloc failed (%s)", strerror(errno));
00313     return herror_new("httpd_register_secure", 0, "malloc failed (%s)", strerror(errno));
00314   }
00315 
00316   if (!(service->statistics = (struct service_statistics *)malloc(sizeof(struct service_statistics))))
00317   {
00318     log_error2("malloc failed (%s)", strerror(errno));
00319     free(service);
00320     return herror_new("httpd_register_secure", 0, "malloc failed (%s)", strerror(errno));
00321   }     
00322   memset(service->statistics, 0, sizeof(struct service_statistics));
00323   service->statistics->time.tv_sec = 0;
00324   service->statistics->time.tv_usec = 0;
00325   pthread_rwlock_init(&(service->statistics->lock), NULL);
00326 
00327   service->next = NULL;
00328   service->auth = auth;
00329   service->func = func;
00330   service->status = NHTTPD_SERVICE_UP;
00331   service->context = strdup(context);
00332 
00333   log_verbose3("register service (%p) for \"%s\"", service, context);
00334   if (_httpd_services_head == NULL)
00335   {
00336     _httpd_services_head = _httpd_services_tail = service;
00337   }
00338   else
00339   {
00340     _httpd_services_tail->next = service;
00341     _httpd_services_tail = service;
00342   }
00343 
00344   return H_OK;
00345 }
00346 
00347 herror_t
00348 httpd_register(const char *context, httpd_service service)
00349 {
00350   return httpd_register_secure(context, service, NULL);
00351 }
00352 
00353 herror_t
00354 httpd_register_default_secure(const char *context, httpd_service service, httpd_auth auth)
00355 {
00356   herror_t ret;
00357 
00358   ret = httpd_register_secure(context, service, auth);
00359 
00360   /* XXX: this is broken, but working */
00361   _httpd_services_default = _httpd_services_tail;
00362 
00363   return ret;
00364 }
00365 
00366 herror_t
00367 httpd_register_default(const char *context, httpd_service service)
00368 {
00369   return httpd_register_default_secure(context, service, NULL);
00370 }
00371 
00372 short
00373 httpd_get_port(void)
00374 {
00375   return _httpd_port;
00376 }
00377 
00378 int
00379 httpd_get_timeout(void)
00380 {
00381   return hsocket_get_timeout();
00382 }
00383 
00384 void
00385 httpd_set_timeout(int secs)
00386 {
00387   hsocket_set_timeout(secs);
00388 
00389   return;
00390 }
00391 
00392 const char *
00393 httpd_get_protocol(void)
00394 {
00395   return hssl_enabled() ? "https" : "http";
00396 }
00397 
00398 int
00399 httpd_get_conncount(void)
00400 {
00401   int i, ret;
00402 
00403   for (ret = i = 0; i<_httpd_max_connections; i++)
00404   {
00405     if (_httpd_connection[i].flag == CONNECTION_IN_USE)
00406       ret++;
00407   }
00408 
00409   return ret;
00410 }
00411 
00412 hservice_t *
00413 httpd_get_services(void)
00414 {
00415   return _httpd_services_head;
00416 }
00417 
00418 static void
00419 hservice_free(hservice_t * service)
00420 {
00421   if (!service)
00422     return;
00423 
00424   if (service->statistics)
00425     free(service->statistics);
00426 
00427   free(service);
00428 
00429   return;
00430 }
00431 
00432 int httpd_enable_service(hservice_t *service)
00433 {
00434   int ret;
00435 
00436   ret = service->status;
00437   service->status = NHTTPD_SERVICE_UP;
00438 
00439   return ret;
00440 }
00441 
00442 int httpd_disable_service(hservice_t *service)
00443 {
00444   int ret;
00445   
00446   ret = service->status;
00447   service->status = NHTTPD_SERVICE_DOWN;
00448 
00449   return ret;
00450 }
00451 
00452 hservice_t *
00453 httpd_find_service(const char *context)
00454 {
00455   hservice_t *cur;
00456 
00457   for (cur = _httpd_services_head; cur; cur = cur->next)
00458   {
00459     if (!strcmp(cur->context, context))
00460       return cur;
00461   }
00462 
00463   return _httpd_services_default;
00464 }
00465 
00466 void
00467 httpd_response_set_content_type(httpd_conn_t * res, const char *content_type)
00468 {
00469   strncpy(res->content_type, content_type, 25);
00470 
00471   return;
00472 }
00473 
00474 herror_t
00475 httpd_send_header(httpd_conn_t * res, int code, const char *text)
00476 {
00477   struct tm stm;
00478   time_t nw;
00479   char buffer[255];
00480   char header[1024];
00481   hpair_t *cur;
00482   herror_t status;
00483 
00484   /* set status code */
00485   sprintf(header, "HTTP/1.1 %d %s\r\n", code, text);
00486 
00487   /* set date */
00488   nw = time(NULL);
00489   localtime_r(&nw, &stm);
00490   strftime(buffer, 255, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", &stm);
00491   strcat(header, buffer);
00492 
00493   /* set content-type */
00494   /* 
00495    * if (res->content_type[0] == '\0') { strcat(header, "Content-Type:
00496    * text/html\r\n"); } else { sprintf(buffer, "Content-Type: %s\r\n",
00497    * res->content_type); strcat(header, buffer); }
00498    */
00499 
00500   /* set server name */
00501   strcat(header, "Server: nanoHTTP library\r\n");
00502 
00503   /* set _httpd_connection status */
00504   /* strcat (header, "Connection: close\r\n"); */
00505 
00506   /* add pairs */
00507   for (cur = res->header; cur; cur = cur->next)
00508   {
00509     sprintf(buffer, "%s: %s\r\n", cur->key, cur->value);
00510     strcat(header, buffer);
00511   }
00512 
00513   /* set end of header */
00514   strcat(header, "\r\n");
00515 
00516   /* send header */
00517   if ((status = hsocket_send(res->sock, header, strlen(header))) != H_OK)
00518     return status;
00519 
00520   res->out = http_output_stream_new(res->sock, res->header);
00521   return H_OK;
00522 }
00523 
00524 static herror_t
00525 _httpd_send_html_message(httpd_conn_t *conn, int reason, const char *phrase, const char *msg)
00526 {
00527   const char const *tmpl =
00528     "<html>"
00529       "<head>"
00530         "<title>%s</title>"
00531       "</head>"
00532       "<body>"
00533         "<h3>%s</h3>"
00534         "<hr/>"
00535         "<div>Message: '%s'</div>"
00536       "</body>"
00537     "</html>";
00538   char buf[4096];
00539   char slen[5];
00540   int len;
00541 
00542   len = snprintf(buf, 4096, tmpl, phrase, phrase, msg);
00543   snprintf(slen, 5, "%d", len);
00544 
00545   httpd_set_header(conn, HEADER_CONTENT_LENGTH, slen);
00546   httpd_send_header(conn, reason, phrase);
00547 
00548   return http_output_stream_write(conn->out, buf, len);
00549 }
00550 
00551 herror_t
00552 httpd_send_bad_request(httpd_conn_t *conn, const char *msg)
00553 {
00554   return _httpd_send_html_message(conn, 400, HTTP_STATUS_400_REASON_PHRASE, msg);
00555 }
00556 
00557 herror_t
00558 httpd_send_unauthorized(httpd_conn_t *conn, const char *realm)
00559 {
00560   char buf[128];
00561 
00562   snprintf(buf, 128, "Basic realm=\"%s\"", realm);
00563   httpd_set_header(conn, HEADER_WWW_AUTHENTICATE, buf);
00564 
00565   return _httpd_send_html_message(conn, 401, HTTP_STATUS_401_REASON_PHRASE, "Unauthorized request logged");
00566 }
00567 
00568 herror_t
00569 httpd_send_not_found(httpd_conn_t *conn, const char *msg)
00570 {
00571   return _httpd_send_html_message(conn, 404, HTTP_STATUS_404_REASON_PHRASE, msg);
00572 }
00573 
00574 herror_t
00575 httpd_send_internal_error(httpd_conn_t *conn, const char *msg)
00576 {
00577   return _httpd_send_html_message(conn, 500, HTTP_STATUS_500_REASON_PHRASE, msg);
00578 }
00579 
00580 herror_t
00581 httpd_send_not_implemented(httpd_conn_t *conn, const char *msg)
00582 {
00583   return _httpd_send_html_message(conn, 501, HTTP_STATUS_501_REASON_PHRASE, msg);
00584 }
00585 
00586 static void
00587 _httpd_request_print(struct hrequest_t * req)
00588 {
00589   hpair_t *pair;
00590 
00591   log_verbose1("++++++ Request +++++++++");
00592   log_verbose2(" Method : '%s'",
00593                (req->method == HTTP_REQUEST_POST) ? "POST" : "GET");
00594   log_verbose2(" Path   : '%s'", req->path);
00595   log_verbose2(" Spec   : '%s'",
00596                (req->version == HTTP_1_0) ? "HTTP/1.0" : "HTTP/1.1");
00597   log_verbose1(" Parsed query string :");
00598 
00599   for (pair = req->query; pair; pair = pair->next)
00600     log_verbose3(" %s = '%s'", pair->key, pair->value);
00601 
00602   log_verbose1(" Parsed header :");
00603   for (pair = req->header; pair; pair = pair->next)
00604     log_verbose3(" %s = '%s'", pair->key, pair->value);
00605 
00606   log_verbose1("++++++++++++++++++++++++");
00607 
00608   return;
00609 }
00610 
00611 httpd_conn_t *
00612 httpd_new(struct hsocket_t * sock)
00613 {
00614   httpd_conn_t *conn;
00615 
00616   if (!(conn = (httpd_conn_t *) malloc(sizeof(httpd_conn_t))))
00617   {
00618     log_error2("malloc failed (%s)", strerror(errno));
00619     return NULL;
00620   }
00621   conn->sock = sock;
00622   conn->out = NULL;
00623   conn->content_type[0] = '\0';
00624   conn->header = NULL;
00625 
00626   return conn;
00627 }
00628 
00629 void
00630 httpd_free(httpd_conn_t * conn)
00631 {
00632   if (!conn)
00633     return;
00634 
00635   if (conn->out)
00636     http_output_stream_free(conn->out);
00637 
00638   if (conn->header)
00639     hpairnode_free_deep(conn->header);
00640 
00641   free(conn);
00642 
00643   return;
00644 }
00645 
00646 static int
00647 _httpd_decode_authorization(const char *value, char **user, char **pass)
00648 {
00649   unsigned char *tmp, *tmp2;
00650   size_t len;
00651 
00652   len = strlen(value) * 2;
00653   if (!(tmp = (char *) calloc(1, len)))
00654   {
00655     log_error2("calloc failed (%s)", strerror(errno));
00656     return -1;
00657   }
00658 
00659   value = strstr(value, " ") + 1;
00660 
00661   log_verbose2("Authorization (base64) = \"%s\"", value);
00662 
00663   base64_decode_string(value, tmp);
00664 
00665   log_verbose2("Authorization (ascii) = \"%s\"", tmp);
00666 
00667   if ((tmp2 = strstr(tmp, ":")))
00668   {
00669     *tmp2++ = '\0';
00670     *pass = strdup(tmp2);
00671   }
00672   else
00673   {
00674     *pass = strdup("");
00675   }
00676   *user = strdup(tmp);
00677 
00678   free(tmp);
00679 
00680   return 0;
00681 }
00682 
00683 static int
00684 _httpd_authenticate_request(struct hrequest_t * req, httpd_auth auth)
00685 {
00686   char *user, *pass;
00687   char *authorization;
00688   int ret;
00689 
00690   if (!auth)
00691     return 1;
00692 
00693   if (!(authorization = hpairnode_get_ignore_case(req->header, HEADER_AUTHORIZATION)))
00694   {
00695     log_debug2("\"%s\" header not set", HEADER_AUTHORIZATION);
00696     return 0;
00697   }
00698 
00699   if (_httpd_decode_authorization(authorization, &user, &pass))
00700   {
00701     log_error1("httpd_base64_decode_failed");
00702     return 0;
00703   }
00704 
00705   if ((ret = auth(req, user, pass)))
00706     log_debug2("Access granted for user=\"%s\"", user);
00707   else
00708     log_info2("Authentication failed for user=\"%s\"", user);
00709 
00710   free(user);
00711   free(pass);
00712 
00713   return ret;
00714 }
00715 
00716 #ifdef WIN32
00717 static unsigned _stdcall
00718 httpd_session_main(void *data)
00719 #else
00720 static void *
00721 httpd_session_main(void *data)
00722 #endif
00723 {
00724   struct hrequest_t *req;
00725   conndata_t *conn;
00726   httpd_conn_t *rconn;
00727   hservice_t *service;
00728   herror_t status;
00729   struct timeval start, end, duration;
00730   int done;
00731 
00732   if (gettimeofday(&start, NULL) == -1)
00733     log_error2("gettimeofday failed (%s)", strerror(errno));
00734 
00735   conn = (conndata_t *) data;
00736 
00737   log_verbose2("starting new httpd session on socket %d", conn->sock);
00738 
00739   rconn = httpd_new(&(conn->sock));
00740 
00741   done = 0;
00742   while (!done)
00743   {
00744     log_verbose3("starting HTTP request on socket %d (%p)", conn->sock, conn->sock.sock);
00745 
00746     if ((status = hrequest_new_from_socket(&(conn->sock), &req)) != H_OK)
00747     {
00748       int code;
00749 
00750       switch ((code = herror_code(status)))
00751       {
00752         case HSOCKET_ERROR_SSLCLOSE:
00753         case HSOCKET_ERROR_RECEIVE:
00754           log_error2("hrequest_new_from_socket failed (%s)", herror_message(status));
00755           break;
00756         default:
00757           httpd_send_bad_request(rconn, herror_message(status));
00758           break;
00759       }
00760       herror_release(status);
00761       done = 1;
00762     }
00763     else
00764     {
00765       char *conn_str;
00766 
00767       _httpd_request_print(req);
00768 
00769       conn_str = hpairnode_get_ignore_case(req->header, HEADER_CONNECTION);
00770       if (conn_str && strncasecmp(conn_str, "close", 6) == 0)
00771         done = 1;
00772 
00773       if (!done)
00774         done = req->version == HTTP_1_0 ? 1 : 0;
00775 
00776       if ((service = httpd_find_service(req->path)))
00777       {
00778         log_verbose3("service '%s' for '%s' found", service->context, req->path);
00779 
00780         if (service->status == NHTTPD_SERVICE_UP)
00781         {
00782           pthread_rwlock_wrlock(&(service->statistics->lock));
00783           service->statistics->requests++;
00784           pthread_rwlock_unlock(&(service->statistics->lock));
00785 
00786           if (_httpd_authenticate_request(req, service->auth))
00787           {
00788             if (service->func != NULL)
00789             {
00790               service->func(rconn, req);
00791 
00792               if (gettimeofday(&end, NULL) == -1)
00793                 log_error2("gettimeofday failed (%s)", strerror(errno));
00794               timersub(&end, &start, &duration);
00795 
00796               pthread_rwlock_wrlock(&(service->statistics->lock));
00797               service->statistics->bytes_received += rconn->sock->bytes_received;
00798               service->statistics->bytes_transmitted += rconn->sock->bytes_transmitted;
00799               timeradd(&(service->statistics->time), &duration, &(service->statistics->time));
00800               pthread_rwlock_unlock(&(service->statistics->lock));
00801 
00802               if (rconn->out && rconn->out->type == HTTP_TRANSFER_CONNECTION_CLOSE)
00803               {
00804                 log_verbose1("Connection close requested");
00805                 done = 1;
00806               }
00807             }
00808             else
00809             {
00810               char buffer[256];
00811 
00812               snprintf(buffer, 256, "service '%s' is not registered properly (service function is NULL)", req->path);
00813               log_verbose1(buffer);
00814               httpd_send_not_implemented(rconn, buffer);
00815             }
00816           }
00817           else
00818           {
00819             httpd_send_unauthorized(rconn, req->path);
00820             done = 1;
00821           }
00822         }
00823         else
00824         {
00825           char buffer[256];
00826 
00827           sprintf(buffer, "service for '%s' is disabled", req->path);
00828           log_verbose1(buffer);
00829           httpd_send_internal_error(rconn, buffer);
00830         }
00831       }
00832       else
00833       {
00834         char buffer[256];
00835         sprintf(buffer, "no service for '%s' found", req->path);
00836         log_verbose1(buffer);
00837         httpd_send_not_implemented(rconn, buffer);
00838         done = 1;
00839       }
00840       hrequest_free(req);
00841     }
00842   }
00843 
00844   httpd_free(rconn);
00845 
00846   hsocket_close(&(conn->sock));
00847 
00848 #ifdef WIN32
00849   CloseHandle((HANDLE) conn->tid);
00850 #else
00851   pthread_attr_destroy(&(conn->attr));
00852 #endif
00853 
00854   conn->flag = CONNECTION_FREE;
00855 
00856 #ifdef WIN32
00857   _endthread();
00858   return 0;
00859 #else
00860   /* pthread_exits automagically */
00861   return NULL;
00862 #endif
00863 }
00864 
00865 int
00866 httpd_set_header(httpd_conn_t * conn, const char *key, const char *value)
00867 {
00868   hpair_t *p;
00869 
00870   if (conn == NULL)
00871   {
00872     log_warn1("Connection object is NULL");
00873     return 0;
00874   }
00875 
00876   for (p = conn->header; p; p = p->next)
00877   {
00878     if (p->key && !strcmp(p->key, key))
00879     {
00880       free(p->value);
00881       p->value = strdup(value);
00882       return 1;
00883     }
00884   }
00885 
00886   conn->header = hpairnode_new(key, value, conn->header);
00887 
00888   return 0;
00889 }
00890 
00891 void
00892 httpd_set_headers(httpd_conn_t * conn, hpair_t * header)
00893 {
00894   while (header)
00895   {
00896     httpd_set_header(conn, header->key, header->value);
00897     header = header->next;
00898   }
00899   return;
00900 }
00901 
00902 int
00903 httpd_add_header(httpd_conn_t * conn, const char *key, const char *value)
00904 {
00905   if (!conn)
00906   {
00907     log_warn1("Connection object is NULL");
00908     return 0;
00909   }
00910 
00911   conn->header = hpairnode_new(key, value, conn->header);
00912 
00913   return 1;
00914 }
00915 
00916 void
00917 httpd_add_headers(httpd_conn_t * conn, const hpair_t * values)
00918 {
00919   if (!conn)
00920   {
00921     log_warn1("Connection object is NULL");
00922     return;
00923   }
00924 
00925   while (values)
00926   {
00927     httpd_add_header(conn, values->key, values->value);
00928     values = values->next;
00929   }
00930   return;
00931 }
00932 
00933 /*
00934  * -----------------------------------------------------
00935  * FUNCTION: _httpd_register_signal_handler
00936  * -----------------------------------------------------
00937  */
00938 static void
00939 _httpd_register_signal_handler(void)
00940 {
00941 
00942 #ifndef WIN32
00943   sigemptyset(&thrsigset);
00944   sigaddset(&thrsigset, SIGALRM);
00945 #endif
00946 
00947   log_verbose2("registering termination signal handler (SIGNAL:%d)",
00948                _httpd_terminate_signal);
00949 #ifdef WIN32
00950   if (SetConsoleCtrlHandler((PHANDLER_ROUTINE) _httpd_term, TRUE) == FALSE)
00951   {
00952     log_error1("Unable to install console event handler!");
00953   }
00954 
00955 #else
00956   signal(_httpd_terminate_signal, _httpd_term);
00957 #endif
00958 
00959   return;
00960 }
00961 
00962 static conndata_t *
00963 _httpd_wait_for_empty_conn(void)
00964 {
00965   int i;
00966 
00967 #ifdef WIN32
00968   WaitForSingleObject(_httpd_connection_lock, INFINITE);
00969 #else
00970   pthread_mutex_lock(&_httpd_connection_lock);
00971 #endif
00972 
00973   for (i = 0;; i++)
00974   {
00975     if (!_httpd_run)
00976     {
00977 #ifdef WIN32
00978       ReleaseMutex(_httpd_connection_lock);
00979 #else
00980       pthread_mutex_unlock(&_httpd_connection_lock);
00981 #endif
00982       return NULL;
00983     }
00984 
00985     if (i >= _httpd_max_connections)
00986     {
00987       _httpd_sys_sleep(1);
00988       i = -1;
00989     }
00990     else if (_httpd_connection[i].flag == CONNECTION_FREE)
00991     {
00992       _httpd_connection[i].flag = CONNECTION_IN_USE;
00993       break;
00994     }
00995   }
00996 
00997 #ifdef WIN32
00998   ReleaseMutex(_httpd_connection_lock);
00999 #else
01000   pthread_mutex_unlock(&_httpd_connection_lock);
01001 #endif
01002 
01003   return &_httpd_connection[i];
01004 }
01005 
01006 static void
01007 _httpd_start_thread(conndata_t * conn)
01008 {
01009   int err;
01010 
01011 #ifdef WIN32
01012   conn->tid =
01013     (HANDLE) _beginthreadex(NULL, 65535, httpd_session_main, conn, 0, &err);
01014 #else
01015   pthread_attr_init(&(conn->attr));
01016 
01017 #ifdef PTHREAD_CREATE_DETACHED
01018   pthread_attr_setdetachstate(&(conn->attr), PTHREAD_CREATE_DETACHED);
01019 #endif
01020 
01021   pthread_sigmask(SIG_BLOCK, &thrsigset, NULL);
01022   if ((err =
01023        pthread_create(&(conn->tid), &(conn->attr), httpd_session_main, conn)))
01024     log_error2("pthread_create failed (%s)", strerror(err));
01025 #endif
01026 
01027   return;
01028 }
01029 
01030 herror_t
01031 httpd_run(void)
01032 {
01033   struct timeval timeout;
01034   conndata_t *conn;
01035   herror_t err;
01036   fd_set fds;
01037 
01038   log_verbose1("starting run routine");
01039 
01040   _httpd_register_signal_handler();
01041 
01042   if ((err = hsocket_listen(&_httpd_socket)) != H_OK)
01043   {
01044     log_error2("hsocket_listen failed (%s)", herror_message(err));
01045     return err;
01046   }
01047 
01048   while (_httpd_run)
01049   {
01050     conn = _httpd_wait_for_empty_conn();
01051     if (!_httpd_run)
01052       break;
01053 
01054     /* Wait for a socket to accept */
01055     while (_httpd_run)
01056     {
01057 
01058       /* set struct timeval to the proper timeout */
01059       timeout.tv_sec = 1;
01060       timeout.tv_usec = 0;
01061 
01062       /* zero and set file descriptior */
01063       FD_ZERO(&fds);
01064       FD_SET(_httpd_socket.sock, &fds);
01065 
01066       /* select socket descriptor */
01067       switch (select(_httpd_socket.sock + 1, &fds, NULL, NULL, &timeout))
01068       {
01069       case 0:
01070         /* descriptor is not ready */
01071         continue;
01072       case -1:
01073         /* got a signal? */
01074         continue;
01075       default:
01076         /* no nothing */
01077         break;
01078       }
01079       if (FD_ISSET(_httpd_socket.sock, &fds))
01080       {
01081         break;
01082       }
01083     }
01084 
01085     /* check signal status */
01086     if (!_httpd_run)
01087       break;
01088 
01089     if ((err = hsocket_accept(&_httpd_socket, &(conn->sock))) != H_OK)
01090     {
01091       log_error2("hsocket_accept failed (%s)", herror_message(err));
01092 
01093       hsocket_close(&(conn->sock));
01094 
01095       continue;
01096     }
01097 
01098     _httpd_start_thread(conn);
01099   }
01100 
01101   return 0;
01102 }
01103 
01104 void
01105 httpd_destroy(void)
01106 {
01107   hservice_t *tmp, *cur = _httpd_services_head;
01108 
01109   while (cur != NULL)
01110   {
01111     tmp = cur->next;
01112     hservice_free(cur);
01113     cur = tmp;
01114   }
01115 
01116   hsocket_module_destroy();
01117 
01118   free(_httpd_connection);
01119 
01120   return;
01121 }
01122 
01123 unsigned char *
01124 httpd_get_postdata(httpd_conn_t * conn, struct hrequest_t * req, long *received, long max)
01125 {
01126   char *content_length_str;
01127   long content_length = 0;
01128   unsigned char *postdata = NULL;
01129 
01130   if (req->method == HTTP_REQUEST_POST)
01131   {
01132 
01133     content_length_str =
01134       hpairnode_get_ignore_case(req->header, HEADER_CONTENT_LENGTH);
01135 
01136     if (content_length_str != NULL)
01137       content_length = atol(content_length_str);
01138 
01139   }
01140   else
01141   {
01142     log_warn1("Not a POST method");
01143     return NULL;
01144   }
01145 
01146   if (content_length > max && max != -1)
01147     return NULL;
01148 
01149   if (content_length == 0)
01150   {
01151     *received = 0;
01152     if (!(postdata = (char *) malloc(1)))
01153     {
01154 
01155       log_error2("malloc failed (%s)", strerror(errno));
01156       return NULL;
01157     }
01158     postdata[0] = '\0';
01159     return postdata;
01160   }
01161   if (!(postdata = (unsigned char *) malloc(content_length + 1)))
01162   {
01163     log_error2("malloc failed (%)", strerror(errno));
01164     return NULL;
01165   }
01166   if (http_input_stream_read(req->in, postdata, (int) content_length) > 0)
01167   {
01168     *received = content_length;
01169     postdata[content_length] = '\0';
01170     return postdata;
01171   }
01172   free(postdata);
01173   return NULL;
01174 }
01175 
01176 
01177 /*
01178   MIME support httpd_mime_* function set
01179 */
01180 
01181 static void
01182 _httpd_mime_get_boundary(httpd_conn_t * conn, char *dest)
01183 {
01184   sprintf(dest, "---=.Part_NH_%p", conn);
01185   log_verbose2("boundary= \"%s\"", dest);
01186 
01187   return;
01188 }
01189 
01190 
01195 herror_t
01196 httpd_mime_send_header(httpd_conn_t * conn, const char *related_start,
01197                        const char *related_start_info,
01198                        const char *related_type, int code, const char *text)
01199 {
01200   char buffer[300];
01201   char temp[250];
01202   char boundary[250];
01203 
01204   /* Set Content-type Set multipart/related parameter type=..; start=.. ;
01205      start-info= ..; boundary=... using sprintf instead of snprintf because 
01206      visual c does not support snprintf */
01207 
01208   sprintf(buffer, "multipart/related;");
01209 
01210   if (related_type)
01211   {
01212     snprintf(temp, 75, " type=\"%s\";", related_type);
01213     strcat(buffer, temp);
01214   }
01215 
01216   if (related_start)
01217   {
01218     snprintf(temp, 250, " start=\"%s\";", related_start);
01219     strcat(buffer, temp);
01220   }
01221 
01222   if (related_start_info)
01223   {
01224     snprintf(temp, 250, " start-info=\"%s\";", related_start_info);
01225     strcat(buffer, temp);
01226   }
01227 
01228   _httpd_mime_get_boundary(conn, boundary);
01229   snprintf(temp, 250, " boundary=\"%s\"", boundary);
01230   strcat(buffer, temp);
01231 
01232   httpd_set_header(conn, HEADER_CONTENT_TYPE, buffer);
01233 
01234   return httpd_send_header(conn, code, text);
01235 }
01236 
01237 
01242 herror_t
01243 httpd_mime_next(httpd_conn_t * conn, const char *content_id,
01244                 const char *content_type, const char *transfer_encoding)
01245 {
01246   herror_t status;
01247   char buffer[512];
01248   char boundary[75];
01249   int len;
01250 
01251   /* Get the boundary string */
01252   _httpd_mime_get_boundary(conn, boundary);
01253   len = sprintf(buffer, "\r\n--%s\r\n", boundary);
01254 
01255   /* Send boundary */
01256   if ((status = http_output_stream_write(conn->out, buffer, len)) != H_OK)
01257     return status;
01258 
01259   /* Send Content header */
01260   len = sprintf(buffer, "%s: %s\r\n%s: %s\r\n%s: %s\r\n\r\n",
01261             HEADER_CONTENT_TYPE, content_type ? content_type : "text/plain",
01262             HEADER_CONTENT_TRANSFER_ENCODING,
01263             transfer_encoding ? transfer_encoding : "binary",
01264             HEADER_CONTENT_ID,
01265             content_id ? content_id : "<content-id-not-set>");
01266 
01267   return http_output_stream_write(conn->out, buffer, len);
01268 }
01269 
01274 herror_t
01275 httpd_mime_send_file(httpd_conn_t * conn, const char *content_id,
01276                      const char *content_type, const char *transfer_encoding,
01277                      const char *filename)
01278 {
01279   unsigned char buffer[MAX_FILE_BUFFER_SIZE];
01280   herror_t status;
01281   FILE *fd;
01282   size_t size;
01283 
01284   if ((fd = fopen(filename, "rb")) == NULL)
01285     return herror_new("httpd_mime_send_file", FILE_ERROR_OPEN,
01286                       "Can not open file '%d'", filename);
01287 
01288   status = httpd_mime_next(conn, content_id, content_type, transfer_encoding);
01289   if (status != H_OK)
01290   {
01291     fclose(fd);
01292     return status;
01293   }
01294 
01295   while (!feof(fd))
01296   {
01297     size = fread(buffer, 1, MAX_FILE_BUFFER_SIZE, fd);
01298     if (size == -1)
01299     {
01300       fclose(fd);
01301       return herror_new("httpd_mime_send_file", FILE_ERROR_READ,
01302                         "Can not read from file '%d'", filename);
01303     }
01304 
01305     if ((status = http_output_stream_write(conn->out, buffer, size)) != H_OK)
01306     {
01307       fclose(fd);
01308       return status;
01309     }
01310   }
01311 
01312   fclose(fd);
01313   return H_OK;
01314 }
01315 
01320 herror_t
01321 httpd_mime_end(httpd_conn_t * conn)
01322 {
01323   herror_t status;
01324   char buffer[512];
01325   char boundary[75];
01326   int len;
01327 
01328   /* Get the boundary string */
01329   _httpd_mime_get_boundary(conn, boundary);
01330   len = sprintf(buffer, "\r\n--%s--\r\n\r\n", boundary);
01331 
01332   /* Send boundary */
01333   if ((status = http_output_stream_write(conn->out, buffer, len)) != H_OK)
01334     return status;
01335 
01336   return http_output_stream_flush(conn->out);
01337 }

Generated on Thu Jan 25 23:36:03 2007 for csoap by  doxygen 1.4.6