From 3a88be29ecb1a2a67e85d8b8d8649865901b9b86 Mon Sep 17 00:00:00 2001 From: snowdrop Date: Mon, 13 Sep 2004 07:12:33 +0000 Subject: made win32 threaded httpd_run not threaded again --- examples/csoap/simpleserver.c | 188 ++++--- nanohttp/nanohttp-server.c | 1102 ++++++++++++++++++++--------------------- 2 files changed, 625 insertions(+), 665 deletions(-) diff --git a/examples/csoap/simpleserver.c b/examples/csoap/simpleserver.c index f4b7bef..85ea78f 100644 --- a/examples/csoap/simpleserver.c +++ b/examples/csoap/simpleserver.c @@ -1,103 +1,91 @@ -/****************************************************************** - * $Id: simpleserver.c,v 1.7 2004/09/07 18:43:49 rans Exp $ - * - * CSOAP Project: CSOAP examples project - * Copyright (C) 2003 Ferhat Ayaz - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA - * - * Email: ayaz@jprogrammer.net - ******************************************************************/ - -#include - - -static const char *url = "/csoapserver"; -static const char *urn = "urn:examples"; -static const char *method = "sayHello"; - - -void add_name(xmlNodePtr node, SoapEnv *env) -{ - char *name; - name = (char*)xmlNodeListGetString(node->doc, - node->xmlChildrenNode, 1); - - - if (!name) return; - - soap_env_add_itemf(env,"xsd:string", "echo", - "Hello '%s'", name); - - xmlFree(BAD_CAST name); - -} - - -SoapEnv* say_hello(SoapEnv *request) -{ - - SoapEnv *env; - xmlNodePtr method, node; - - env = soap_env_new_with_response(request); - - method = soap_env_get_method(request); - node = soap_xml_get_children(method); - - while (node) { - add_name(node, env); - node = soap_xml_get_next(node); - } - - return env; -} - - -int main(int argc, char *argv[]) -{ - char c; - SoapRouter *router; - - log_set_level(HLOG_VERBOSE); - - if (!soap_server_init_args(argc, argv)) { - return 1; - } - +/****************************************************************** + * $Id: simpleserver.c,v 1.8 2004/09/13 07:12:33 snowdrop Exp $ + * + * CSOAP Project: CSOAP examples project + * Copyright (C) 2003 Ferhat Ayaz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA + * + * Email: ayaz@jprogrammer.net + ******************************************************************/ + +#include + + +static const char *url = "/csoapserver"; +static const char *urn = "urn:examples"; +static const char *method = "sayHello"; + + +void add_name(xmlNodePtr node, SoapEnv *env) +{ + char *name; + name = (char*)xmlNodeListGetString(node->doc, + node->xmlChildrenNode, 1); + + + if (!name) return; + + soap_env_add_itemf(env,"xsd:string", "echo", + "Hello '%s'", name); + + xmlFree(BAD_CAST name); + +} + + +SoapEnv* say_hello(SoapEnv *request) +{ + + SoapEnv *env; + xmlNodePtr method, node; + + env = soap_env_new_with_response(request); + + method = soap_env_get_method(request); + node = soap_xml_get_children(method); + + while (node) { + add_name(node, env); + node = soap_xml_get_next(node); + } + + return env; +} + + +int main(int argc, char *argv[]) +{ + + SoapRouter *router; + + log_set_level(HLOG_VERBOSE); + + if (!soap_server_init_args(argc, argv)) { + return 1; + } + router = soap_router_new(); soap_router_register_service(router, say_hello, method, urn); soap_server_register_router(router, url); - -#ifndef WIN32 - log_info1("send SIGTERM to shutdown"); -#endif - soap_server_run(); - -#ifdef WIN32 - log_info1("press ENTER to continue!"); - gets(&c); -#endif - - log_info1("shutting down\n"); - soap_server_destroy(); - - return 0; -} - - - - - + + log_info1("send SIGTERM to shutdown"); + soap_server_run(); + + log_info1("shutting down\n"); + soap_server_destroy(); + + return 0; +} \ No newline at end of file diff --git a/nanohttp/nanohttp-server.c b/nanohttp/nanohttp-server.c index edf9290..36cdf3b 100644 --- a/nanohttp/nanohttp-server.c +++ b/nanohttp/nanohttp-server.c @@ -1,565 +1,537 @@ -/****************************************************************** -* $Id: nanohttp-server.c,v 1.18 2004/09/07 18:40:38 rans Exp $ -* -* CSOAP Project: A http client/server library in C -* Copyright (C) 2003 Ferhat Ayaz -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Library General Public -* License as published by the Free Software Foundation; either -* version 2 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Library General Public License for more details. -* -* You should have received a copy of the GNU Library General Public -* License along with this library; if not, write to the -* Free Software Foundation, Inc., 59 Temple Place - Suite 330, -* Boston, MA 02111-1307, USA. -* -* Email: ayaz@jprogrammer.net -******************************************************************/ -#include - -#include -#include -#include - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef WIN32 -/* According to POSIX 1003.1-2001 */ -#include - -/* According to earlier standards */ -#include -#include -#include - -#endif - -/* - * ----------------------------------------------------- - * nano httpd - * internally globals - * ----------------------------------------------------- - */ -static int _httpd_port = 10000; -static int _httpd_max_connections = 20; -static int _httpd_max_idle = 120; -static hsocket_t _httpd_socket; -static hservice_t *_httpd_services_head = NULL; -static hservice_t *_httpd_services_tail = NULL; -static int _httpd_run = 1; -static int _httpd_terminate_signal = SIGTERM; -static conndata_t *_httpd_connection; - -#ifdef WIN32 -#include -#endif - -/* - * ----------------------------------------------------- - * FUNCTION: httpd_init - * NOTE: This will be called from soap_server_init_args() - * ----------------------------------------------------- - */ -int -httpd_init (int argc, char *argv[]) -{ - int i, status; - status = hsocket_module_init (); - if (status != 0) - return status; - - /* write argument information */ - log_verbose1 ("Arguments:"); - for (i = 0; i < argc; i++) - log_verbose3 ("argv[%i] = '%s'", i, SAVE_STR (argv[i])); - - /* initialize from arguments */ - for (i = 0; i < argc; i++) - { - if (!strcmp (argv[i], NHTTPD_ARG_PORT) && i < argc - 1) - { - _httpd_port = atoi (argv[i + 1]); - } - else if (!strcmp (argv[i], NHTTPD_ARG_TERMSIG) && i < argc - 1) - { - _httpd_terminate_signal = atoi (argv[i + 1]); - } - else if (!strcmp (argv[i], NHTTPD_ARG_MAXCONN) && i < argc - 1) - { - _httpd_max_connections = atoi (argv[i + 1]); - } - } - - log_verbose2 ("socket bind to port '%d'", _httpd_port); - - /* init built-in services */ - - /* httpd_register("/httpd/list", service_list);*/ - - _httpd_connection = calloc (_httpd_max_connections, sizeof (conndata_t)); - for (i = 0; i < _httpd_max_connections; i++) - { - memset ((char *) &_httpd_connection[i], 0, sizeof (_httpd_connection[i])); - } - -#ifdef WIN32 - if (_beginthread (WSAReaper, 0, NULL) == -1) - { - log_error1 ("Winsock reaper thread failed to start"); - return (-1); - } -#endif - - /* create socket */ - hsocket_init (&_httpd_socket); - status = hsocket_bind (&_httpd_socket, _httpd_port); - - return status; -} - -/* - * ----------------------------------------------------- - * FUNCTION: httpd_register - * ----------------------------------------------------- - */ - -int -httpd_register (const char *ctx, httpd_service func) -{ - hservice_t *service; - - service = (hservice_t *) malloc (sizeof (hservice_t)); - service->next = NULL; - service->func = func; - strcpy (service->ctx, ctx); - - log_verbose3 ("register service:t(%p):%s", service, SAVE_STR (ctx)); - if (_httpd_services_head == NULL) - { - _httpd_services_head = _httpd_services_tail = service; - } - else - { - _httpd_services_tail->next = service; - _httpd_services_tail = service; - } - - return 1; -} - - -/* - * ----------------------------------------------------- - * FUNCTION: httpd_services - * ----------------------------------------------------- - */ -hservice_t * -httpd_services () -{ - return _httpd_services_head; -} - - -/* - * ----------------------------------------------------- - * FUNCTION: httpd_find_service - * ----------------------------------------------------- - */ -static hservice_t * -httpd_find_service (const char *ctx) -{ - hservice_t *cur = _httpd_services_head; - - while (cur != NULL) - { - if (!strcmp (cur->ctx, ctx)) - { - return cur; - } - cur = cur->next; - } - - return NULL; -} - - -/* - * ----------------------------------------------------- - * FUNCTION: httpd_response_set_content_type - * ----------------------------------------------------- - */ -void -httpd_response_set_content_type (httpd_conn_t * res, const char *content_type) -{ - strncpy (res->content_type, content_type, 25); -} - - -/* - * ----------------------------------------------------- - * FUNCTION: httpd_response_send_header - * ----------------------------------------------------- - */ -int -httpd_send_header (httpd_conn_t * res, - int code, const char *text, hpair_t * pair) -{ - struct tm stm; - time_t nw; - char buffer[255]; - char header[1024]; - hpair_t *cur; - int status; - - /* set status code */ - sprintf (header, "HTTP/1.1 %d %s\r\n", code, text); - - /* set date */ - nw = time (NULL); - localtime_r (&nw, &stm); - strftime (buffer, 255, "Date: %a, %d %b %y %T GMT", &stm); - strcat (header, buffer); - strcat (header, "\r\n"); - - /* set content-type */ - /* - * if (res->content_type[0] == '\0') { strcat(header, "Content-Type: - * text/html\r\n"); } else { sprintf(buffer, "Content-Type: %s\r\n", - * res->content_type); strcat(header, buffer); } - */ - - /* set server name */ - strcat (header, "Server: Nano HTTPD library\r\n"); - - /* set _httpd_connection status */ - strcat (header, "Connection: close\r\n"); - - /* add pairs */ - cur = pair; - while (cur != NULL) - { - sprintf (buffer, "%s: %s\r\n", cur->key, cur->value); - strcat (header, buffer); - cur = cur->next; - } - - /* set end of header */ - strcat (header, "\r\n"); - - /* send header */ - status = hsocket_nsend (res->sock, header, strlen (header)); - - return status; -} - - -int -httpd_send_internal_error (httpd_conn_t * conn, const char *errmsg) -{ - const char *template1 = - "

Error!


Message: '%s' \r\n"; - - char buffer[4064]; - sprintf (buffer, template1, errmsg); - httpd_send_header (conn, 500, "INTERNAL", NULL); - return send (conn->sock, buffer, strlen (buffer), 0); -} - -/* - * ----------------------------------------------------- - * FUNCTION: httpd_request_print - * ----------------------------------------------------- - */ -static void -httpd_request_print (hrequest_t * req) -{ - hpair_t *pair; - - log_verbose1 ("++++++ Request +++++++++"); - log_verbose2 (" Method : '%s'", req->method); - log_verbose2 (" Path : '%s'", req->path); - log_verbose2 (" Spec : '%s'", req->spec); - log_verbose1 (" Parsed query string :"); - - pair = req->query; - while (pair != NULL) - { - log_verbose3 (" %s = '%s'", pair->key, pair->value); - pair = pair->next; - } - log_verbose1 ("++++++++++++++++++++++++"); - -} - -/* - * ----------------------------------------------------- - * FUNCTION: httpd_session_main - * ----------------------------------------------------- - */ -#ifdef WIN32 -static unsigned _stdcall -httpd_session_main (void *data) -#else -static void * -httpd_session_main (void *data) -#endif -{ - conndata_t *conn = (conndata_t *) data; - const char *msg = "SESSION 1.0\n"; - int len = strlen (msg); - char ch[2]; - char buffer[256]; /* temp buffer for recv() */ - char header[4064]; /* received header */ - int total; /* result from recv() */ - int headerreached = 0; /* whether reach header * "\n\n" */ - hrequest_t *req = NULL; /* only for test */ - httpd_conn_t *rconn; - hservice_t *service = NULL; - long content_length = 0; - - header[0] = '\0'; - len = 0; - - - log_verbose1 ("starting httpd_session_main()"); - conn->atime = time ((time_t) 0); - while (len < 4064) - { - /* printf("receiving ...\n"); */ - total = recv (conn->sock, ch, 1, 0); - if (total == 0) - break; - header[len] = ch[0]; - len++; - if (len > 3) - { - if (!strncmp (&header[len - 4], "\r\n\r\n", 4)) - { - header[len] = '\0'; - break; - } - } - } - - /* log_verbose2("=== HEADER ===\n%s\n============\n", header); */ - /* call the service */ - req = hrequest_new_from_buffer (header); - httpd_request_print (req); - - - rconn = (httpd_conn_t *) malloc (sizeof (httpd_conn_t)); - rconn->sock = conn->sock; - rconn->content_type[0] = '\0'; - - service = httpd_find_service (req->path); - if (service != NULL) - { - log_verbose2 ("service '%s' found", req->path); - if (service->func != NULL) - { - service->func (rconn, req); - } - else - { - sprintf (buffer, - "service '%s' not registered properly (func == NULL)", - req->path); - log_verbose1 (buffer); - httpd_send_internal_error (rconn, buffer); - } - } - else - { - sprintf (buffer, "service '%s' not found", req->path); - log_verbose1 (buffer); - httpd_send_internal_error (rconn, buffer); - } - - close (conn->sock); - conn->sock = 0; - - /* httpd_response_free(res); */ - hrequest_free (req); - -#ifdef WIN32 - CloseHandle ((HANDLE) conn->tid); - _endthread (); - return 0; -#else - pthread_exit (NULL); - return service; -#endif -} - - -/* - * ----------------------------------------------------- - * FUNCTION: httpd_term - * ----------------------------------------------------- - */ -void -httpd_term (int sig) -{ - if (sig == _httpd_terminate_signal) - _httpd_run = 0; -} - -static void __httpd_run(void *p) -{ - int err; - fd_set fds; - struct timeval timeout; - - - log_verbose1 ("starting run routine"); - timeout.tv_sec = 1; - timeout.tv_usec = 0; - - /* listen to port */ - err = hsocket_listen (_httpd_socket, 15); - if (err != HSOCKET_OK) - { - log_error2 ("httpd_run(): '%d'", err); - return; - } - log_verbose2 ("registering termination signal handler (SIGNAL:%d)", - _httpd_terminate_signal); - signal (_httpd_terminate_signal, httpd_term); - log_verbose2 ("listening to port '%d'", _httpd_port); - - - err = hsocket_makenonblock (_httpd_socket); - if (err != HSOCKET_OK) - { - log_error2 ("httpd_run(): '%d'", err); - return; - } - timeout.tv_sec = 1; - timeout.tv_usec = 0; - - while (_httpd_run) - { - -#ifdef WIN32 - Sleep(10); -#endif - FD_ZERO (&fds); - FD_SET (_httpd_socket, &fds); - -#ifndef WIN32 - select (1, &fds, NULL, NULL, &timeout); -#else - if (select (1, &fds, NULL, NULL, &timeout) == SOCKET_ERROR) - { - err = WSAGetLastError (); - log_error1 ("select error"); - return; - } -#endif - - while (_httpd_run && (FD_ISSET (_httpd_socket, &fds))) - { - if (!_httpd_run) - { - break; - } -#ifdef WIN32 - else - { - Sleep(10); - } -#endif - } - if (hsocket_accept - (_httpd_socket, httpd_session_main, _httpd_connection, - _httpd_max_connections) != 0) - { - continue; - } - } - free (_httpd_connection); -#ifdef WIN32 - _endthread (); -#endif -} - -/* - * ----------------------------------------------------- - * FUNCTION: httpd_run - * ----------------------------------------------------- - */ - -int -httpd_run () -{ -#ifdef WIN32 - if (_beginthread (__httpd_run, 0, NULL) == -1) - { - log_error1 ("httpd_run thread failed to start"); - return (-1); - } -#else - void *p; - __httpd_run(p); -#endif -} - -char * -httpd_get_postdata (httpd_conn_t * conn, hrequest_t * req, long *received, - long max) -{ - char *content_length_str; - long content_length = 0; - long total = 0; - char *postdata = NULL; - - if (!strcmp (req->method, "POST")) - { - - content_length_str = - hpairnode_get_ignore_case (req->header, HEADER_CONTENT_LENGTH); - - if (content_length_str != NULL) - content_length = atol (content_length_str); - - } - else - { - log_warn1 ("Not a POST method"); - return NULL; - } - - if (content_length > max && max != -1) - return NULL; - - if (content_length == 0) - { - *received = 0; - postdata = (char *) malloc (1); - postdata[0] = '\0'; - return postdata; - } - postdata = (char *) malloc (content_length + 1); - if (postdata == NULL) - { - log_error1 ("Not enough memory"); - return NULL; - } - if (hsocket_read (conn->sock, postdata, - (int) content_length, 1) == HSOCKET_OK) - { - *received = content_length; - postdata[content_length] = '\0'; - return postdata; - } - free (postdata); - return NULL; -} +/****************************************************************** +* $Id: nanohttp-server.c,v 1.19 2004/09/13 07:12:36 snowdrop Exp $ +* +* CSOAP Project: A http client/server library in C +* Copyright (C) 2003 Ferhat Ayaz +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Library General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Library General Public License for more details. +* +* You should have received a copy of the GNU Library General Public +* License along with this library; if not, write to the +* Free Software Foundation, Inc., 59 Temple Place - Suite 330, +* Boston, MA 02111-1307, USA. +* +* Email: ayaz@jprogrammer.net +******************************************************************/ +#include + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef WIN32 +/* According to POSIX 1003.1-2001 */ +#include + +/* According to earlier standards */ +#include +#include +#include + +#endif + +/* + * ----------------------------------------------------- + * nano httpd + * internally globals + * ----------------------------------------------------- + */ +static int _httpd_port = 10000; +static int _httpd_max_connections = 20; +static int _httpd_max_idle = 120; +static hsocket_t _httpd_socket; +static hservice_t *_httpd_services_head = NULL; +static hservice_t *_httpd_services_tail = NULL; +static int _httpd_run = 1; +static int _httpd_terminate_signal = SIGTERM; +static conndata_t *_httpd_connection; + +#ifdef WIN32 +#include +#endif + +/* + * ----------------------------------------------------- + * FUNCTION: httpd_init + * NOTE: This will be called from soap_server_init_args() + * ----------------------------------------------------- + */ +int +httpd_init (int argc, char *argv[]) +{ + int i, status; + status = hsocket_module_init (); + if (status != 0) + return status; + + /* write argument information */ + log_verbose1 ("Arguments:"); + for (i = 0; i < argc; i++) + log_verbose3 ("argv[%i] = '%s'", i, SAVE_STR (argv[i])); + + /* initialize from arguments */ + for (i = 0; i < argc; i++) + { + if (!strcmp (argv[i], NHTTPD_ARG_PORT) && i < argc - 1) + { + _httpd_port = atoi (argv[i + 1]); + } + else if (!strcmp (argv[i], NHTTPD_ARG_TERMSIG) && i < argc - 1) + { + _httpd_terminate_signal = atoi (argv[i + 1]); + } + else if (!strcmp (argv[i], NHTTPD_ARG_MAXCONN) && i < argc - 1) + { + _httpd_max_connections = atoi (argv[i + 1]); + } + } + + log_verbose2 ("socket bind to port '%d'", _httpd_port); + + /* init built-in services */ + + /* httpd_register("/httpd/list", service_list);*/ + + _httpd_connection = calloc (_httpd_max_connections, sizeof (conndata_t)); + for (i = 0; i < _httpd_max_connections; i++) + { + memset ((char *) &_httpd_connection[i], 0, sizeof (_httpd_connection[i])); + } + +#ifdef WIN32 + if (_beginthread (WSAReaper, 0, NULL) == -1) + { + log_error1 ("Winsock reaper thread failed to start"); + return (-1); + } +#endif + + /* create socket */ + hsocket_init (&_httpd_socket); + status = hsocket_bind (&_httpd_socket, _httpd_port); + + return status; +} + +/* + * ----------------------------------------------------- + * FUNCTION: httpd_register + * ----------------------------------------------------- + */ + +int +httpd_register (const char *ctx, httpd_service func) +{ + hservice_t *service; + + service = (hservice_t *) malloc (sizeof (hservice_t)); + service->next = NULL; + service->func = func; + strcpy (service->ctx, ctx); + + log_verbose3 ("register service:t(%p):%s", service, SAVE_STR (ctx)); + if (_httpd_services_head == NULL) + { + _httpd_services_head = _httpd_services_tail = service; + } + else + { + _httpd_services_tail->next = service; + _httpd_services_tail = service; + } + + return 1; +} + + +/* + * ----------------------------------------------------- + * FUNCTION: httpd_services + * ----------------------------------------------------- + */ +hservice_t * +httpd_services () +{ + return _httpd_services_head; +} + + +/* + * ----------------------------------------------------- + * FUNCTION: httpd_find_service + * ----------------------------------------------------- + */ +static hservice_t * +httpd_find_service (const char *ctx) +{ + hservice_t *cur = _httpd_services_head; + + while (cur != NULL) + { + if (!strcmp (cur->ctx, ctx)) + { + return cur; + } + cur = cur->next; + } + + return NULL; +} + + +/* + * ----------------------------------------------------- + * FUNCTION: httpd_response_set_content_type + * ----------------------------------------------------- + */ +void +httpd_response_set_content_type (httpd_conn_t * res, const char *content_type) +{ + strncpy (res->content_type, content_type, 25); +} + + +/* + * ----------------------------------------------------- + * FUNCTION: httpd_response_send_header + * ----------------------------------------------------- + */ +int +httpd_send_header (httpd_conn_t * res, + int code, const char *text, hpair_t * pair) +{ + struct tm stm; + time_t nw; + char buffer[255]; + char header[1024]; + hpair_t *cur; + int status; + + /* set status code */ + sprintf (header, "HTTP/1.1 %d %s\r\n", code, text); + + /* set date */ + nw = time (NULL); + localtime_r (&nw, &stm); + strftime (buffer, 255, "Date: %a, %d %b %y %T GMT", &stm); + strcat (header, buffer); + strcat (header, "\r\n"); + + /* set content-type */ + /* + * if (res->content_type[0] == '\0') { strcat(header, "Content-Type: + * text/html\r\n"); } else { sprintf(buffer, "Content-Type: %s\r\n", + * res->content_type); strcat(header, buffer); } + */ + + /* set server name */ + strcat (header, "Server: Nano HTTPD library\r\n"); + + /* set _httpd_connection status */ + strcat (header, "Connection: close\r\n"); + + /* add pairs */ + cur = pair; + while (cur != NULL) + { + sprintf (buffer, "%s: %s\r\n", cur->key, cur->value); + strcat (header, buffer); + cur = cur->next; + } + + /* set end of header */ + strcat (header, "\r\n"); + + /* send header */ + status = hsocket_nsend (res->sock, header, strlen (header)); + + return status; +} + + +int +httpd_send_internal_error (httpd_conn_t * conn, const char *errmsg) +{ + const char *template1 = + "

Error!


Message: '%s' \r\n"; + + char buffer[4064]; + sprintf (buffer, template1, errmsg); + httpd_send_header (conn, 500, "INTERNAL", NULL); + return send (conn->sock, buffer, strlen (buffer), 0); +} + +/* + * ----------------------------------------------------- + * FUNCTION: httpd_request_print + * ----------------------------------------------------- + */ +static void +httpd_request_print (hrequest_t * req) +{ + hpair_t *pair; + + log_verbose1 ("++++++ Request +++++++++"); + log_verbose2 (" Method : '%s'", req->method); + log_verbose2 (" Path : '%s'", req->path); + log_verbose2 (" Spec : '%s'", req->spec); + log_verbose1 (" Parsed query string :"); + + pair = req->query; + while (pair != NULL) + { + log_verbose3 (" %s = '%s'", pair->key, pair->value); + pair = pair->next; + } + log_verbose1 ("++++++++++++++++++++++++"); + +} + +/* + * ----------------------------------------------------- + * FUNCTION: httpd_session_main + * ----------------------------------------------------- + */ +#ifdef WIN32 +static unsigned _stdcall +httpd_session_main (void *data) +#else +static void * +httpd_session_main (void *data) +#endif +{ + conndata_t *conn = (conndata_t *) data; + const char *msg = "SESSION 1.0\n"; + int len = strlen (msg); + char ch[2]; + char buffer[256]; /* temp buffer for recv() */ + char header[4064]; /* received header */ + int total; /* result from recv() */ + int headerreached = 0; /* whether reach header * "\n\n" */ + hrequest_t *req = NULL; /* only for test */ + httpd_conn_t *rconn; + hservice_t *service = NULL; + long content_length = 0; + + header[0] = '\0'; + len = 0; + + + log_verbose1 ("starting httpd_session_main()"); + conn->atime = time ((time_t) 0); + while (len < 4064) + { + /* printf("receiving ...\n"); */ + total = recv (conn->sock, ch, 1, 0); + if (total == 0) + break; + header[len] = ch[0]; + len++; + if (len > 3) + { + if (!strncmp (&header[len - 4], "\r\n\r\n", 4)) + { + header[len] = '\0'; + break; + } + } + } + + /* log_verbose2("=== HEADER ===\n%s\n============\n", header); */ + /* call the service */ + req = hrequest_new_from_buffer (header); + httpd_request_print (req); + + + rconn = (httpd_conn_t *) malloc (sizeof (httpd_conn_t)); + rconn->sock = conn->sock; + rconn->content_type[0] = '\0'; + + service = httpd_find_service (req->path); + if (service != NULL) + { + log_verbose2 ("service '%s' found", req->path); + if (service->func != NULL) + { + service->func (rconn, req); + } + else + { + sprintf (buffer, + "service '%s' not registered properly (func == NULL)", + req->path); + log_verbose1 (buffer); + httpd_send_internal_error (rconn, buffer); + } + } + else + { + sprintf (buffer, "service '%s' not found", req->path); + log_verbose1 (buffer); + httpd_send_internal_error (rconn, buffer); + } + + close (conn->sock); + conn->sock = 0; + + /* httpd_response_free(res); */ + hrequest_free (req); + +#ifdef WIN32 + CloseHandle ((HANDLE) conn->tid); + _endthread (); + return 0; +#else + pthread_exit (NULL); + return service; +#endif +} + + +/* + * ----------------------------------------------------- + * FUNCTION: httpd_term + * ----------------------------------------------------- + */ +void +httpd_term (int sig) +{ + if (sig == _httpd_terminate_signal) + _httpd_run = 0; +} + +/* + * ----------------------------------------------------- + * FUNCTION: httpd_run + * ----------------------------------------------------- + */ + +int +httpd_run () +{ + int err; + fd_set fds; + struct timeval timeout; + + + log_verbose1 ("starting run routine"); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + /* listen to port */ + err = hsocket_listen (_httpd_socket, 15); + if (err != HSOCKET_OK) + { + log_error2 ("httpd_run(): '%d'", err); + return err; + } + log_verbose2 ("registering termination signal handler (SIGNAL:%d)", + _httpd_terminate_signal); + signal (_httpd_terminate_signal, httpd_term); + log_verbose2 ("listening to port '%d'", _httpd_port); + + + err = hsocket_makenonblock (_httpd_socket); + if (err != HSOCKET_OK) + { + log_error2 ("httpd_run(): '%d'", err); + return err; + } + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + while (_httpd_run) + { + + FD_ZERO (&fds); + FD_SET (_httpd_socket, &fds); + +#ifndef WIN32 + select (1, &fds, NULL, NULL, &timeout); +#else + if (select (1, &fds, NULL, NULL, &timeout) == SOCKET_ERROR) + { + err = WSAGetLastError (); + log_error1 ("select error"); + return -1; + } +#endif + + while (_httpd_run && (FD_ISSET (_httpd_socket, &fds))) + if (!_httpd_run) + break; + + if (hsocket_accept + (_httpd_socket, httpd_session_main, _httpd_connection, + _httpd_max_connections) != 0) + { + continue; + } + } + free (_httpd_connection); + return 0; +} + +char * +httpd_get_postdata (httpd_conn_t * conn, hrequest_t * req, long *received, + long max) +{ + char *content_length_str; + long content_length = 0; + long total = 0; + char *postdata = NULL; + + if (!strcmp (req->method, "POST")) + { + + content_length_str = + hpairnode_get_ignore_case (req->header, HEADER_CONTENT_LENGTH); + + if (content_length_str != NULL) + content_length = atol (content_length_str); + + } + else + { + log_warn1 ("Not a POST method"); + return NULL; + } + + if (content_length > max && max != -1) + return NULL; + + if (content_length == 0) + { + *received = 0; + postdata = (char *) malloc (1); + postdata[0] = '\0'; + return postdata; + } + postdata = (char *) malloc (content_length + 1); + if (postdata == NULL) + { + log_error1 ("Not enough memory"); + return NULL; + } + if (hsocket_read (conn->sock, postdata, + (int) content_length, 1) == HSOCKET_OK) + { + *received = content_length; + postdata[content_length] = '\0'; + return postdata; + } + free (postdata); + return NULL; +} \ No newline at end of file -- cgit v1.1-32-gdbae