📄 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 * *//**@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 <stddef.h>#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <errno.h>#include <assert.h>#include <sofia-sip/string0.h>#if !defined(EALREADY) && defined(_WIN32)#define EALREADY WSAEALREADY#endiftypedef 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>/* We are customer of tport_t */#define TP_STACK_T server_t#define TP_MAGIC_T void #ifndef TPORT_H #include <sofia-sip/tport.h>#endif#include <sofia-sip/htable.h>enum { 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; nth_site_t **site_prev; nth_site_t *site_kids; server_t *site_server; url_t *site_url; char const *site_path; size_t site_path_len; nth_request_f *site_callback; nth_site_magic_t *site_magic; unsigned site_strict : 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; 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>/**@var NTH_DEBUG * * 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 <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);static inline int server_timer_init(server_t *srv);static void server_timer(su_root_magic_t *rm, su_timer_t *timer, server_t *srv);static 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_directory(nth_site_t **list, 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[], unsigned 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 virtual * http server or a site within a server */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; url_t *url; server_t *srv; ta_list ta; su_home_t temphome[1] = { SU_HOME_INIT(temphome) }; char const *path = NULL; size_t len = 0; url = url_hdup(temphome, address->us_url); if (!url || !callback) return NULL; if (url->url_host && url->url_path) { SU_DEBUG_3(("nth_site_create(): virtual host and path simultanously\n")); su_home_deinit(temphome); errno = EINVAL; return NULL; } if (!parent && url->url_path) { SU_DEBUG_3(("nth_site_create(): no virtual host\n")); su_home_deinit(temphome); errno = EINVAL; return NULL; } ta_start(ta, tag, value); if (parent) { srv = parent->site_server; assert(srv); if (url->url_host) prev = site_get_host(&srv->srv_sites, url->url_host, url->url_port); else { len = strlen(url->url_path); if (len > 1 && url->url_path[len - 1] == '/') ((char *)url->url_path)[len - 1] = '\0'; prev = site_get_directory(&parent, url->url_path, &path); } } else { srv = server_create(url, ta_tags(ta)); prev = &srv->srv_sites; } if (url->url_path) { assert(path); len = strlen(path); if (len == 0) { SU_DEBUG_3(("nth_site_create(): directory \"%s\" already exists\n", url->url_path)); su_home_deinit(temphome); ta_end(ta); errno = EALREADY; return NULL; } } if (srv && (site = su_zalloc(srv->srv_home, sizeof *site))) { if (*prev) { /* The existing node should will be kid */ site->site_next = (*prev)->site_next; site->site_next->site_prev = &site->site_next; site->site_kids = *prev; (*prev)->site_prev = NULL; (*prev)->site_next = NULL; } *prev = site, site->site_prev = prev; site->site_server = srv; site->site_url = url_hdup(srv->srv_home, url); if (path) { site->site_path = site->site_url->url_path + (path - url->url_path); site->site_path_len = len; } else { site->site_path = ""; site->site_path_len = 0; } site->site_callback = callback; site->site_magic = magic; nth_site_set_params(site, ta_tags(ta)); } su_home_deinit(temphome); ta_end(ta); return site;}void nth_site_destroy(nth_site_t *site){ if (site == NULL) { } else if (site->site_server->srv_sites == site) { server_destroy(site->site_server); }}nth_site_magic_t *nth_site_magic(nth_site_t const *site){ return site ? site->site_magic : NULL;}void nth_site_bind(nth_site_t *site, nth_request_f *callback, nth_site_magic_t *magic){ if (site) { site->site_callback = callback; site->site_magic = magic; }}char const *nth_site_server_version(void){ return "nth/" NTH_VERSION;}int nth_site_set_params(nth_site_t *site, tag_type_t tag, tag_value_t value, ...){ int n; ta_list ta; server_t *server; int master; msg_mclass_t const *mclass; int mflags; if (site == NULL) return (errno = EINVAL), -1; server = site->site_server; master = site == server->srv_sites; mclass = server->srv_mclass; mflags = server->srv_mflags; ta_start(ta, tag, value); n = tl_gets(ta_args(ta), TAG_IF(master, NTHTAG_MCLASS_REF(mclass)), TAG_IF(master, NTHTAG_MFLAGS_REF(mflags)), TAG_END()); if (n > 0) { if (mclass) server->srv_mclass = mclass; else server->srv_mclass = http_default_mclass(); server->srv_mflags = mflags; } ta_end(ta); return n;}int nth_site_get_params(nth_site_t const *site, tag_type_t tag, tag_value_t value, ...){ int n; ta_list ta; server_t *server; int master; msg_mclass_t const *mclass; if (site == NULL) return (errno = EINVAL), -1; server = site->site_server; master = site == server->srv_sites; if (master && server->srv_mclass != http_default_mclass()) mclass = server->srv_mclass; else mclass = NULL; ta_start(ta, tag, value); n = tl_tgets(ta_args(ta), TAG_IF(master, NTHTAG_MCLASS(mclass)), TAG_IF(master, NTHTAG_MFLAGS(server->srv_mflags)), TAG_END()); ta_end(ta); return n;}int nth_site_get_stats(nth_site_t const *site, tag_type_t tag, tag_value_t value, ...){ int n; ta_list ta; if (site == NULL) return (errno = EINVAL), -1; ta_start(ta, tag, value); n = tl_tgets(ta_args(ta), TAG_END()); ta_end(ta); return n;}staticnth_site_t **site_get_host(nth_site_t **list, char const *host, char const *port){ nth_site_t *site; assert(host); for (; (site = *list); list = &site->site_next) { if (strcasecmp(host, site->site_url->url_host) == 0 && str0cmp(port, site->site_url->url_port) == 0) { break; } } return list;}staticnth_site_t **site_get_directory(nth_site_t **list, char const *path, char const **res){ nth_site_t *site, **prev; assert(path); if (path[0] == '/') while (path[1] == '/') path++; if (path[0] && (path[0] != '/' || path[1])) for (prev = &(*list)->site_kids; (site = *prev); prev = &site->site_next) { size_t len = site->site_path_len; if (strncmp(path, site->site_path, len) == 0) { return site_get_directory(prev, path + len, res); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -