📄 nth_server.c
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@internal @file nth_server.c * @brief HTTP server. * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Sat Oct 19 01:37:36 2002 ppessi */#include "config.h"#include <sofia-sip/string0.h>#include <sofia-sip/su.h>typedef struct server_s server_t;/** @internal SU timer argument pointer type */#define SU_TIMER_ARG_T server_t#include <sofia-sip/http_header.h>#include <sofia-sip/http_status.h>#include <sofia-sip/http_tag.h>#include "sofia-sip/nth.h"#include <sofia-sip/msg_date.h>#include <sofia-sip/msg_addr.h>#include <sofia-sip/su_tagarg.h>#include <sofia-sip/hostdomain.h>/* We are customer of tport_t */#define TP_STACK_T server_t#define TP_MAGIC_T void #include <sofia-sip/tport.h>#include <sofia-sip/htable.h>#include <sofia-sip/auth_module.h>#include <stddef.h>#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <errno.h>#include <assert.h>#ifndef UINT32_MAX#define UINT32_MAX (0xffffffffU)#endifenum { SERVER_TICK = 1000 };#define SERVER_VERSION "nth/" NTH_VERSIONHTABLE_DECLARE(hc_htable, hct, nth_client_t);struct server_s { su_home_t srv_home[1]; su_root_t *srv_root; su_timer_t *srv_timer; unsigned srv_now; msg_mclass_t const*srv_mclass; int srv_mflags; /**< Message flags */ tport_t *srv_tports; unsigned srv_queuesize; /**< Maximum number of queued responses */ size_t srv_max_bodylen; /**< Maximum accepted length */ unsigned srv_persistent:1; /**< Allow persistent connections */ /** Sites */ nth_site_t *srv_sites; /* Statistics */ struct { uint32_t st_requests; /**< Received requests */ uint32_t st_responses; /**< Sent responses */ uint32_t st_bad; /**< Bad requests */ } srv_stats[1]; http_server_t *srv_server; /**< Server header */};struct nth_site_s { nth_site_t *site_next, **site_prev; nth_site_t *site_kids; server_t *site_server; auth_mod_t *site_auth; url_t *site_url; char const *site_path; size_t site_path_len; nth_request_f *site_callback; nth_site_magic_t *site_magic; su_time_t site_access; /**< Last request served */ /** Host header must match with server name */ unsigned site_strict : 1; /** Site can have kids */ unsigned site_isdir : 1; /** Site does not have domain name */ unsigned site_wildcard : 1;};struct nth_request_s{ server_t *req_server; http_method_t req_method; char const *req_method_name; url_t const *req_url; /**< RequestURI */ char const *req_version; tport_t *req_tport; msg_t *req_request; msg_t *req_response; auth_status_t *req_as; unsigned short req_status; unsigned req_close : 1; /**< Client asked for close */ unsigned req_in_callback : 1; unsigned req_destroyed : 1;};/* ====================================================================== *//* Debug log settings */#define SU_LOG nth_server_log#ifdef SU_DEBUG_H#error <su_debug.h> included directly.#endif#include <sofia-sip/su_debug.h>/**Environment variable determining the debug log level for @b nth * module. * * The NTH_DEBUG environment variable is used to determine the debug * logging level for @b nth module. The default level is 1. * * @sa <sofia-sip/su_debug.h>, nth_server_log, SOFIA_DEBUG */extern char const NTH_DEBUG[];#ifndef SU_DEBUG#define SU_DEBUG 1#endif/**Debug log for @b nth module. * * The nth_server_log is the log object used by @b nth module. The level of * #nth_server_log is set using #NTH_DEBUG environment variable. */su_log_t nth_server_log[] = { SU_LOG_INIT("nth", "NTH_DEBUG", SU_DEBUG) };#if HAVE_FUNC#elif HAVE_FUNCTION#define __func__ __FUNCTION__#elsestatic char const __func__[] = "nth";#endif/* ====================================================================== *//** Server side */static server_t *server_create(url_t const *url, tag_type_t tag, tag_value_t value, ...);void server_destroy(server_t *srv);su_inline int server_timer_init(server_t *srv);static void server_timer(su_root_magic_t *rm, su_timer_t *timer, server_t *srv);su_inline uint32_t server_now(server_t const *srv);static void server_request(server_t *srv, tport_t *tport, msg_t *msg, void *arg, su_time_t now);static nth_site_t **site_get_host(nth_site_t **, char const *host, char const *port);static nth_site_t **site_get_rslot(nth_site_t *parent, char *path, char **return_rest);static nth_site_t *site_get_subdir(nth_site_t *parent, char const *path, char const **res);static void server_tport_error(server_t *srv, tport_t *tport, int errcode, char const *remote);static msg_t *server_msg_create(server_t *srv, int flags, char const data[], usize_t dlen, tport_t const *tp, tp_client_t *tpc);static void server_reply(server_t *srv, tport_t *tport, msg_t *request, msg_t *response, int status, char const *phrase);staticvoid nth_site_request(server_t *srv, nth_site_t *site, tport_t *tport, msg_t *request, http_t *http, char const *path, msg_t *response);/* ---------------------------------------------------------------------- * 5) Site functions *//** Create a http site object. * * The function nth_site_create() allocates and initializes a web site * object. A web site object can be either * - a primary http server (@a parent is NULL), * - a virtual http server (@a address contains hostpart), or * - a site within a server * (@a address does not have hostpart, only path part). * * @param parent pointer to parent site * (NULL when creating a primary server object) * @param callback pointer to callback function called when * a request is received * @param magic application context included in callback parameters * @param address absolute or relative URI specifying the address of * site * @param tag, value, ... list of tagged parameters * * @TAGS * If the @a parent is NULL, the list of tagged parameters must contain * NTHTAG_ROOT() used to create the server engine. Tags supported when @a * parent is NULL are NTHTAG_ROOT(), NTHTAG_MCLASS(), TPTAG_REUSE(), * HTTPTAG_SERVER(), and HTTPTAG_SERVER_STR(). All the tags are passed to * tport_tcreate() and tport_tbind(), too. * * @since Support for multiple sites was added to @VERSION_1_12_4 */nth_site_t *nth_site_create(nth_site_t *parent, nth_request_f *callback, nth_site_magic_t *magic, url_string_t const *address, tag_type_t tag, tag_value_t value, ...){ nth_site_t *site = NULL, **prev = NULL; su_home_t home[SU_HOME_AUTO_SIZE(256)]; url_t *url, url0[1]; server_t *srv = NULL; ta_list ta; char *path = NULL; size_t usize; int is_host, is_path, wildcard = 0; su_home_auto(home, sizeof home); if (parent && url_is_string(address)) { char const *s = (char const *)address; size_t sep = strcspn(s, "/:"); if (parent->site_path) { /* subpath */ url_init(url0, parent->site_url->url_type); url0->url_path = s; address = (url_string_t*)url0; } else if (s[sep] == ':') /* absolute URL with scheme */; else if (s[sep] == '\0' && strchr(s, '.') && host_is_valid(s)) { /* looks like a domain name */; url_init(url0, parent->site_url->url_type); url0->url_host = s; address = (url_string_t*)url0; } else { /* looks like a path */ url_init(url0, parent->site_url->url_type); url0->url_path = s; address = (url_string_t*)url0; } } url = url_hdup(home, address->us_url); if (!url || !callback) return NULL; is_host = url->url_host != NULL; is_path = url->url_path != NULL; if (is_host && is_path) { SU_DEBUG_3(("nth_site_create(): virtual host and path simultanously\n")); errno = EINVAL; goto error; } if (!parent && !is_host) { SU_DEBUG_3(("nth_site_create(): host is required\n")); errno = EINVAL; goto error; } if (parent) { if (!parent->site_isdir) { SU_DEBUG_3(("nth_site_create(): invalid parent resource \n")); errno = EINVAL; goto error; } srv = parent->site_server; assert(srv); if (is_host) { prev = site_get_host(&srv->srv_sites, url->url_host, url->url_port); if (prev == NULL) { SU_DEBUG_3(("nth_site_create(): host %s:%s already exists\n", url->url_host, url->url_port ? url->url_port : "")); errno = EEXIST; goto error; } } else { size_t i, j; path = (char *)url->url_path; while (path[0] == '/') path++; /* Remove duplicate // */ for (i = j = 0; path[i];) { while (path[i] == '/' && path[i + 1] == '/') i++; path[j++] = path[i++]; } path[j] = path[i]; url = url0, *url = *parent->site_url; if (url->url_path) { url->url_path = su_strcat(home, url->url_path, path); if (!url->url_path) goto error; path = (char *)url->url_path + strlen(parent->site_url->url_path); } else url->url_path = path; prev = site_get_rslot(parent, path, &path); if (!prev || path[0] == '\0') { SU_DEBUG_3(("nth_site_create(): directory \"%s\" already exists\n", url->url_path)); errno = EEXIST; goto error; } } } if (!parent) { if (strcmp(url->url_host, "*") == 0 || host_cmp(url->url_host, "0.0.0.0") == 0 || host_cmp(url->url_host, "::") == 0) wildcard = 1, url->url_host = "*"; } usize = sizeof(*url) + url_xtra(url); ta_start(ta, tag, value); if (!parent) { srv = server_create(url, ta_tags(ta)); prev = &srv->srv_sites; } if (srv && (site = su_zalloc(srv->srv_home, (sizeof *site) + usize))) { site->site_url = (url_t *)(site + 1); url_dup((void *)(site->site_url + 1), usize - sizeof(*url), site->site_url, url); assert(prev); if ((site->site_next = *prev)) site->site_next->site_prev = &site->site_next; *prev = site, site->site_prev = prev; site->site_server = srv; if (path) { size_t path_len; site->site_path = site->site_url->url_path + (path - url->url_path); path_len = strlen(site->site_path); assert(path_len > 0); if (path_len > 0 && site->site_path[path_len - 1] == '/') path_len--, site->site_isdir = 1; site->site_path_len = path_len; } else { site->site_isdir = is_host; site->site_path = ""; site->site_path_len = 0; } site->site_wildcard = wildcard; site->site_callback = callback; site->site_magic = magic; if (parent) site->site_auth = parent->site_auth; nth_site_set_params(site, ta_tags(ta)); } ta_end(ta); error: su_home_deinit(home); return site;}void nth_site_destroy(nth_site_t *site){ if (site == NULL) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -