diff options
-rw-r--r-- | Makefile | 37 | ||||
-rw-r--r-- | httpd/Makefile | 35 | ||||
-rw-r--r-- | httpd/dispatcher.cpp | 109 | ||||
-rw-r--r-- | httpd/job.cpp | 240 | ||||
-rw-r--r-- | httpd/listener.cpp | 167 | ||||
-rw-r--r-- | httpd/poller.cpp | 190 | ||||
-rw-r--r-- | httpd/regex.cpp | 175 | ||||
-rw-r--r-- | httpd/tnt/dispatcher.h | 121 | ||||
-rw-r--r-- | httpd/tnt/gcryptinit.h | 37 | ||||
-rw-r--r-- | httpd/tnt/gnutls.h | 146 | ||||
-rw-r--r-- | httpd/tnt/job.h | 201 | ||||
-rw-r--r-- | httpd/tnt/listener.h | 78 | ||||
-rw-r--r-- | httpd/tnt/openssl.h | 121 | ||||
-rw-r--r-- | httpd/tnt/poller.h | 61 | ||||
-rw-r--r-- | httpd/tnt/regex.h | 79 | ||||
-rw-r--r-- | httpd/tnt/ssl.h | 52 | ||||
-rw-r--r-- | httpd/tnt/tntnet.h | 99 | ||||
-rw-r--r-- | httpd/tnt/worker.h | 91 | ||||
-rw-r--r-- | httpd/tntnet.cpp | 832 | ||||
-rw-r--r-- | httpd/worker.cpp | 364 |
20 files changed, 2 insertions, 3233 deletions
@@ -1,5 +1,5 @@ # -# Makefile for a Video Disk Recorder plugin +# Makefile for the 'LIVE' Video Disk Recorder plugin # # The official name of this plugin. @@ -64,18 +64,8 @@ PACKAGE = vdr-$(ARCHIVE) SOFILE = libvdr-$(PLUGIN).so ### Includes and Defines (add further entries here): -ifneq ($(TNTVERS7),yes) - INCLUDES += -Ihttpd - LIBS += httpd/libhttpd.a -endif - DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' -DTNTVERSION=$(TNTVERSION) -DCXXTOOLVER=$(CXXTOOLVER) - SUBDIRS = pages css javascript -ifneq ($(TNTVERS7),yes) - SUBDIRS += httpd -endif - VERSIONSUFFIX = gen_version_suffix.h ### The object files (add further files here): @@ -142,36 +132,13 @@ $(SOFILE): $(VERSIONSUFFIX) $(SUBDIRS) $(PLUGINOBJS) for SUBDIR in $(SUBDIRS); \ do $(MAKE) -C $${SUBDIR} PLUGINFEATURES="$(PLUGINFEATURES)" all; \ done - $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(PLUGINOBJS) -Wl,--whole-archive $(WEBLIBS) -Wl,--no-whole-archive $(LIBS) -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(PLUGINOBJS) -Wl,--whole-archive $(WEBLIBS) -Wl,--no-whole-archive $(LIBS) -o $@ install-lib: $(SOFILE) install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION) install: install-lib install-i18n -ifneq ($(TNTVERS7),yes) - @echo "" - @echo "LIVE was built successfully and you can try to use it!" - @echo "" - @echo "" - @echo "" - @echo "" - @echo "IMPORTANT INFORMATION:" - @echo "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" - @echo "+ This is one of the *last* CVS versions of LIVE which will +" - @echo "+ work with versions of tntnet *less* than 1.6.0.6! +" - @echo "+ +" - @echo "+ This version of LIVE already supports tntnet >= 1.6.0.6. +" - @echo "+ +" - @echo "+ Please upgrade tntnet to at least version 1.6.0.6 soon, if +" - @echo "+ you want to keep track of bleeding edge LIVE development. +" - @echo "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" - @echo "" - @echo "" - @echo "" - @echo "" -endif - dist: $(I18Npo) clean @-rm -rf $(TMPDIR)/$(ARCHIVE) @mkdir $(TMPDIR)/$(ARCHIVE) diff --git a/httpd/Makefile b/httpd/Makefile deleted file mode 100644 index d21eb2f..0000000 --- a/httpd/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -### The official name of this plugin. -PLUGIN = live - -### Includes and Defines (add further entries here): -INCLUDES += -I. - -### The object files (add further files here): -OBJS = dispatcher.o job.o regex.o worker.o \ - listener.o poller.o tntnet.o - -### The main target: -all: libhttpd.a - -### Implicit rules: - -%.o: %.cpp - $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $< - -### Dependencies: -MAKEDEP = $(CXX) -MM -MG -DEPFILE = .dependencies -$(DEPFILE): Makefile - @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.cpp) > $@ - --include $(DEPFILE) - -### Targets: -libhttpd.a: $(OBJS) - $(AR) r $@ $^ - -clean: - @rm -f *~ *.o core* libhttpd.a proctest $(DEPFILE) - -dist: clean - @echo "Nothing to do for distribution here ..." diff --git a/httpd/dispatcher.cpp b/httpd/dispatcher.cpp deleted file mode 100644 index 8620e76..0000000 --- a/httpd/dispatcher.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* dispatcher.cpp - * Copyright (C) 2003-2005 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "tnt/dispatcher.h" -#include <tnt/httperror.h> -#include <functional> -#include <iterator> -#include <algorithm> -#include <cxxtools/log.h> - -log_define("tntnet.dispatcher") - -namespace tnt -{ - -void Dispatcher::addUrlMapEntry(const std::string& url, const CompidentType& ci) -{ - cxxtools::WrLock lock(rwlock); - - urlmap.push_back(urlmap_type::value_type(regex(url), ci)); -} - -Compident Dispatcher::mapComp(const std::string& compUrl) const -{ - urlmap_type::const_iterator pos = urlmap.begin(); - return mapCompNext(compUrl, pos); -} - -namespace { - class regmatch_formatter : public std::unary_function<const std::string&, std::string> - { - public: - regex_smatch what; - std::string operator() (const std::string& s) const - { return what.format(s); } - }; -} - -Dispatcher::urlMapCacheType::size_type Dispatcher::maxUrlMapCache = 8192; - -Dispatcher::CompidentType Dispatcher::mapCompNext(const std::string& compUrl, - Dispatcher::urlmap_type::const_iterator& pos) const -{ - // check cache - urlMapCacheType::key_type cacheKey = urlMapCacheType::key_type(compUrl, pos); - urlMapCacheType::const_iterator um = urlMapCache.find(cacheKey); - if (um != urlMapCache.end()) - return um->second; - - // no cache hit - regmatch_formatter formatter; - - for (; pos != urlmap.end(); ++pos) - { - if (pos->first.match(compUrl, formatter.what)) - { - const CompidentType& src = pos->second; - - CompidentType ci; - ci.libname = formatter(src.libname); - ci.compname = formatter(src.compname); - if (src.hasPathInfo()) - ci.setPathInfo(formatter(src.getPathInfo())); - std::transform(src.getArgs().begin(), src.getArgs().end(), - std::back_inserter(ci.getArgsRef()), formatter); - - // clear cache after maxUrlMapCache distict requests - if (urlMapCache.size() >= maxUrlMapCache) - { - log_warn("clear url-map-cache"); - urlMapCache.clear(); - } - - urlMapCache.insert(urlMapCacheType::value_type(cacheKey, ci)); - - return ci; - } - } - - throw NotFoundException(compUrl); -} - -Dispatcher::CompidentType Dispatcher::PosType::getNext() -{ - if (first) - first = false; - else - ++pos; - - return dis.mapCompNext(url, pos); -} - -} diff --git a/httpd/job.cpp b/httpd/job.cpp deleted file mode 100644 index 49ecba6..0000000 --- a/httpd/job.cpp +++ /dev/null @@ -1,240 +0,0 @@ -/* job.cpp - * Copyright (C) 2003-2005 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "tnt/job.h" -#include <tnt/httpreply.h> -#include <cxxtools/log.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> - -log_define("tntnet.job") - -namespace tnt -{ - unsigned Job::socket_read_timeout = 200; - unsigned Job::socket_write_timeout = 10000; - unsigned Job::keepalive_max = 1000; - unsigned Job::socket_buffer_size = 16384; - - Job::~Job() - { } - - void Job::clear() - { - parser.reset(); - request.clear(); - touch(); - } - - int Job::msecToTimeout(time_t currentTime) const - { - return (lastAccessTime - currentTime + 1) * 1000 - + getKeepAliveTimeout() - - getSocketReadTimeout(); - } - - unsigned Job::getKeepAliveTimeout() - { - return HttpReply::getKeepAliveTimeout(); - } - - //////////////////////////////////////////////////////////////////////// - // Tcpjob - // - void Tcpjob::accept(const cxxtools::net::Server& listener) - { - log_debug("accept"); - socket.accept(listener); - - struct sockaddr_storage s = socket.getSockAddr(); - struct sockaddr_storage sockaddr; - memcpy(&sockaddr, &s, sizeof(sockaddr)); - - char buffer[INET6_ADDRSTRLEN]; - log_debug("connection accepted from " - << inet_ntop(AF_INET6, &(socket.getPeeraddr()), buffer, sizeof(buffer))); - - getRequest().setPeerAddr(socket.getPeeraddr()); - getRequest().setServerAddr(sockaddr); - getRequest().setSsl(false); - } - - std::iostream& Tcpjob::getStream() - { - return socket; - } - - int Tcpjob::getFd() const - { - return socket.getFd(); - } - - void Tcpjob::setRead() - { - socket.setTimeout(getSocketReadTimeout()); - } - - void Tcpjob::setWrite() - { - socket.setTimeout(getSocketWriteTimeout()); - } - -#ifdef USE_SSL - //////////////////////////////////////////////////////////////////////// - // SslTcpjob - // - void SslTcpjob::accept(const SslServer& listener) - { - log_debug("accept (ssl)"); - socket.accept(listener); - log_debug("connection accepted (ssl)"); - - struct sockaddr_storage s = socket.getSockAddr(); - struct sockaddr_storage sockaddr; - memcpy(&sockaddr, &s, sizeof(sockaddr)); - - getRequest().setPeerAddr(socket.getPeeraddr()); - getRequest().setServerAddr(sockaddr); - getRequest().setSsl(true); - - setRead(); - } - - std::iostream& SslTcpjob::getStream() - { - return socket; - } - - int SslTcpjob::getFd() const - { - return socket.getFd(); - } - - void SslTcpjob::setRead() - { - socket.setTimeout(getSocketReadTimeout()); - } - - void SslTcpjob::setWrite() - { - socket.setTimeout(getSocketWriteTimeout()); - } - -#endif // USE_SSL - -#ifdef USE_GNUTLS - //////////////////////////////////////////////////////////////////////// - // GnuTlsTcpjob - // - void GnuTlsTcpjob::accept(const GnuTlsServer& listener) - { - log_debug("accept (ssl)"); - socket.accept(listener); - log_debug("connection accepted (ssl)"); - - struct sockaddr_storage s = socket.getSockAddr(); - struct sockaddr_storage sockaddr; - memcpy(&sockaddr, &s, sizeof(sockaddr)); - - getRequest().setPeerAddr(socket.getPeeraddr()); - getRequest().setServerAddr(sockaddr); - getRequest().setSsl(true); - - setRead(); - } - - std::iostream& GnuTlsTcpjob::getStream() - { - return socket; - } - - int GnuTlsTcpjob::getFd() const - { - return socket.getFd(); - } - - void GnuTlsTcpjob::setRead() - { - socket.setTimeout(getSocketReadTimeout()); - } - - void GnuTlsTcpjob::setWrite() - { - socket.setTimeout(getSocketWriteTimeout()); - } - -#endif // USE_GNUTLS - - ////////////////////////////////////////////////////////////////////// - // Jobqueue - // - void Jobqueue::put(JobPtr j) - { - log_debug("Jobqueue::put"); - j->touch(); - - cxxtools::MutexLock lock(mutex); - - if (capacity > 0) - { - while (jobs.size() >= capacity) - { - log_warn("Jobqueue full"); - notFull.wait(lock); - } - } - - jobs.push_back(j); - - if (waitThreads == 0) - { - log_info("no waiting threads left"); - noWaitThreads.signal(); - } - - notEmpty.signal(); - } - - Jobqueue::JobPtr Jobqueue::get() - { - // wait, until a job is available - ++waitThreads; - - cxxtools::MutexLock lock(mutex); - while (jobs.empty()) - notEmpty.wait(lock); - - --waitThreads; - - log_debug("Jobqueue: fetch job " << waitThreads << " waiting threads left"); - - // take next job (queue is locked) - JobPtr j = jobs.front(); - jobs.pop_front(); - - // if there are more jobs, wake onther thread - if (!jobs.empty()) - notEmpty.signal(); - notFull.signal(); - - return j; - } - -} diff --git a/httpd/listener.cpp b/httpd/listener.cpp deleted file mode 100644 index 57c334d..0000000 --- a/httpd/listener.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* listener.cpp - * Copyright (C) 2003 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "tnt/listener.h" -#include "tnt/tntnet.h" -#include <cxxtools/log.h> -#include <errno.h> -#include <unistd.h> - -#ifdef WITH_GNUTLS -# include "tnt/gnutls.h" -#endif - -#ifdef WITH_OPENSSL -# include "tnt/openssl.h" -#endif - -log_define("tntnet.listener") - -static void doListenRetry(cxxtools::net::Server& server, - const char* ipaddr, unsigned short int port) -{ - for (unsigned n = 1; true; ++n) - { - try - { - log_debug("listen " << ipaddr << ':' << port); - server.listen(ipaddr, port, tnt::Listener::getBacklog()); - return; - } - catch (const cxxtools::net::Exception& e) - { - log_debug("cxxtools::net::Exception caught: errno=" << e.getErrno() << " msg=" << e.what()); - if (e.getErrno() != EADDRINUSE || n > tnt::Listener::getListenRetry()) - { - log_debug("rethrow exception"); - throw; - } - log_warn("address " << ipaddr << ':' << port << " in use - retry; n = " << n); - ::sleep(1); - } - } -} - -namespace tnt -{ - void ListenerBase::doStop() - { - log_warn("stop listener " << ipaddr << ':' << port); - try - { - // connect once to wake up listener, so it will check stop-flag - cxxtools::net::Stream(ipaddr, port); - } - catch (const std::exception& e) - { - log_warn("error waking up listener: " << e.what() << " try 127.0.0.1"); - cxxtools::net::Stream("127.0.0.1", port); - } - } - - int Listener::backlog = 16; - unsigned Listener::listenRetry = 5; - - Listener::Listener(const std::string& ipaddr, unsigned short int port, Jobqueue& q) - : ListenerBase(ipaddr, port), - queue(q) - { - log_info("listen ip=" << ipaddr << " port=" << port); - doListenRetry(server, ipaddr.c_str(), port); - } - - void Listener::run() - { - // accept-loop - log_debug("enter accept-loop"); - while (!Tntnet::shouldStop()) - { - try - { - Tcpjob* j = new Tcpjob; - Jobqueue::JobPtr p(j); - j->accept(server); - log_debug("connection accepted"); - - if (Tntnet::shouldStop()) - break; - - queue.put(p); - } - catch (const std::exception& e) - { - log_error("error in accept-loop: " << e.what()); - } - } - - log_debug("stop listener"); - } - -#ifdef WITH_GNUTLS -#define USE_SSL - -#endif - -#ifdef WITH_OPENSSL -#define USE_SSL - -#endif - -#ifdef USE_SSL - Ssllistener::Ssllistener(const char* certificateFile, - const char* keyFile, - const std::string& ipaddr, unsigned short int port, - Jobqueue& q) - : ListenerBase(ipaddr, port), - server(certificateFile, keyFile), - queue(q) - { - log_info("listen ip=" << ipaddr << " port=" << port << " (ssl)"); - doListenRetry(server, ipaddr.c_str(), port); - } - - void Ssllistener::run() - { - // accept-loop - log_debug("enter accept-loop (ssl)"); - while (!Tntnet::shouldStop()) - { - try - { - SslTcpjob* j = new SslTcpjob; - Jobqueue::JobPtr p(j); - j->accept(server); - - if (Tntnet::shouldStop()) - break; - - queue.put(p); - } - catch (const std::exception& e) - { - log_error("error in ssl-accept-loop: " << e.what()); - } - } - - log_debug("stop ssl-listener"); - } - -#endif // USE_SSL - -} diff --git a/httpd/poller.cpp b/httpd/poller.cpp deleted file mode 100644 index c604f55..0000000 --- a/httpd/poller.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/* poller.cpp - * Copyright (C) 2005 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "tnt/poller.h" -#include "tnt/tntnet.h" -#include <cxxtools/log.h> -#include <unistd.h> -#include <fcntl.h> - -log_define("tntnet.poller") - -namespace tnt -{ - Poller::Poller(Jobqueue& q) - : queue(q), - poll_timeout(-1) - { - pipe(notify_pipe); - fcntl(notify_pipe[0], F_SETFL, O_NONBLOCK); - - pollfds.reserve(16); - pollfds[0].fd = notify_pipe[0]; - pollfds[0].events = POLLIN; - pollfds[0].revents = 0; - } - - void Poller::append_new_jobs() - { - cxxtools::MutexLock lock(mutex); - if (!new_jobs.empty()) - { - // append new jobs to current - log_debug("add " << new_jobs.size() << " new jobs to poll-list"); - - pollfds.reserve(current_jobs.size() + new_jobs.size() + 1); - - time_t currentTime; - time(¤tTime); - for (jobs_type::iterator it = new_jobs.begin(); - it != new_jobs.end(); ++it) - { - append(*it); - int msec; - if (poll_timeout < 0) - poll_timeout = (*it)->msecToTimeout(currentTime); - else if ((msec = (*it)->msecToTimeout(currentTime)) < poll_timeout) - poll_timeout = msec; - } - - new_jobs.clear(); - } - } - - void Poller::append(Jobqueue::JobPtr& job) - { - current_jobs.push_back(job); - - pollfd& p = *(pollfds.data() + current_jobs.size()); - p.fd = job->getFd(); - p.events = POLLIN; - } - - void Poller::run() - { - while (!Tntnet::shouldStop()) - { - append_new_jobs(); - - try - { - log_debug("poll timeout=" << poll_timeout); - ::poll(pollfds.data(), current_jobs.size() + 1, poll_timeout); - if (Tntnet::shouldStop()) - { - log_warn("stop poller"); - break; - } - - poll_timeout = -1; - - if (pollfds[0].revents != 0) - { - log_debug("read notify-pipe"); - char ch; - ::read(notify_pipe[0], &ch, 1); - pollfds[0].revents = 0; - } - - dispatch(); - } - catch (const std::exception& e) - { - log_error("error in poll-loop: " << e.what()); - } - } - } - - void Poller::doStop() - { - log_debug("notify stop"); - char ch = 'A'; - ::write(notify_pipe[1], &ch, 1); - } - - void Poller::dispatch() - { - log_debug("dispatch " << current_jobs.size() << " jobs"); - - time_t currentTime; - time(¤tTime); - for (unsigned i = 0; i < current_jobs.size(); ) - { - if (pollfds[i + 1].revents & POLLIN) - { - log_debug("job found " << pollfds[i + 1].fd); - - // put job into work-queue - queue.put(current_jobs[i]); - remove(i); - } - else if (pollfds[i + 1].revents != 0) - { - log_debug("pollevent " << std::hex << pollfds[i + 1].revents << " on fd " << pollfds[i + 1].fd); - remove(i); - } - else - { - // check timeout - int msec = current_jobs[i]->msecToTimeout(currentTime); - if (msec <= 0) - { - log_debug("keep-alive-timeout reached"); - remove(i); - } - else if (poll_timeout < 0 || msec < poll_timeout) - poll_timeout = msec; - - ++i; - } - } - } - - void Poller::remove(jobs_type::size_type n) - { - // replace job with last job in poller-list - jobs_type::size_type last = current_jobs.size() - 1; - - if (n != last) - { - pollfds[n + 1] = pollfds[last + 1]; - current_jobs[n] = current_jobs[last]; - } - - current_jobs.pop_back(); - } - - void Poller::addIdleJob(Jobqueue::JobPtr job) - { - log_debug("addIdleJob " << job->getFd()); - - { - cxxtools::MutexLock lock(mutex); - new_jobs.push_back(job); - } - - log_debug("notify " << job->getFd()); - - char ch = 'A'; - ::write(notify_pipe[1], &ch, 1); - - log_debug("addIdleJob ready"); - } - -} diff --git a/httpd/regex.cpp b/httpd/regex.cpp deleted file mode 100644 index a9f52fc..0000000 --- a/httpd/regex.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* regex.cpp - * Copyright (C) 2005 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "tnt/regex.h" -#include <stdexcept> -#include <locale> - -namespace tnt -{ - static inline bool isdigit(char ch) - { - return ch >= '0' && ch <= '9'; - } - - unsigned regex_smatch::size() const - { - unsigned n; - for (n = 0; n < 10 && matchbuf[n].rm_so >= 0; ++n) - ; - - return n; - } - - std::string regex_smatch::get(unsigned n) const - { - return str.substr(matchbuf[n].rm_so, matchbuf[n].rm_eo - matchbuf[n].rm_so); - } - - std::string regex_smatch::format(const std::string& s) const - { - enum state_type - { - state_0, - state_esc, - state_var0, - state_var1, - state_1 - } state; - - state = state_0; - std::string ret; - - for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) - { - char ch = *it; - - switch (state) - { - case state_0: - if (ch == '$') - state = state_var0; - else if (ch == '\\') - { - ret = std::string(s.begin(), it); - state = state_esc; - } - break; - - case state_esc: - ret += ch; - state = state_1; - break; - - case state_var0: - if (isdigit(ch)) - { - ret = std::string(s.begin(), it - 1); - regoff_t s = matchbuf[ch - '0'].rm_so; - regoff_t e = matchbuf[ch - '0'].rm_eo; - if (s >= 0 && e >= 0) - ret.append(str, s, e-s); - state = state_1; - } - else - state = state_0; - break; - - case state_1: - if (ch == '$') - state = state_var1; - else if (state == '\\') - state = state_esc; - else - ret += ch; - break; - - case state_var1: - if (isdigit(ch)) - { - unsigned s = matchbuf[ch - '0'].rm_so; - unsigned e = matchbuf[ch - '0'].rm_eo; - if (s >= 0 && e >= 0) - ret.append(str, s, e-s); - state = state_1; - } - else if (ch == '$') - ret += '$'; - else - { - ret += '$'; - ret += ch; - } - break; - } - } - - switch (state) - { - case state_0: - case state_var0: - return s; - - case state_esc: - return ret + '\\'; - - case state_var1: - return ret + '$'; - - case state_1: - return ret; - } - - return ret; - } - - void regex::checkerr(int ret) const - { - if (ret != 0) - { - char errbuf[256]; - regerror(ret, &expr, errbuf, sizeof(errbuf)); - throw std::runtime_error(errbuf); - } - } - - bool regex::match(const std::string& str_, int eflags) const - { - regex_smatch smatch; - return match(str_, smatch, eflags); - } - - bool regex::match(const std::string& str_, regex_smatch& smatch, int eflags) const - { - smatch.str = str_; - int ret = regexec(&expr, str_.c_str(), - sizeof(smatch.matchbuf) / sizeof(regmatch_t), smatch.matchbuf, eflags); - - if (ret ==REG_NOMATCH) - return false; - - checkerr(ret); - return true; - } - - void regex::free() - { - regfree(&expr); - } -} diff --git a/httpd/tnt/dispatcher.h b/httpd/tnt/dispatcher.h deleted file mode 100644 index 218efcb..0000000 --- a/httpd/tnt/dispatcher.h +++ /dev/null @@ -1,121 +0,0 @@ -/* tnt/dispatcher.h - * Copyright (C) 2003-2005 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef TNT_DISPATCHER_H -#define TNT_DISPATCHER_H - -#include <cxxtools/thread.h> -#include <tnt/urlmapper.h> -#include <vector> -#include <map> -#include "tnt/regex.h" - -namespace tnt -{ - // Dispatcher - one per host - class Dispatcher : public Urlmapper - { - public: - class CompidentType : public Compident - { - public: - typedef std::vector<std::string> args_type; - - private: - std::string pathinfo; - args_type args; - bool pathinfo_set; - - public: - CompidentType() - : pathinfo_set(false) - { } - - explicit CompidentType(const std::string& ident) - : Compident(ident), - pathinfo_set(false) - { } - - bool hasPathInfo() const - { return pathinfo_set; } - void setPathInfo(const std::string& p) - { pathinfo = p; pathinfo_set = true; } - void setArgs(const args_type& a) - { args = a; } - const std::string& getPathInfo() const - { return pathinfo; } - const args_type& getArgs() const - { return args; } - args_type& getArgsRef() - { return args; } - }; - - private: - typedef std::vector<std::pair<regex, CompidentType> > urlmap_type; - urlmap_type urlmap; // map url to soname/compname - mutable cxxtools::RWLock rwlock; - - typedef std::map<std::pair<std::string, urlmap_type::const_iterator>, - CompidentType> urlMapCacheType; - mutable urlMapCacheType urlMapCache; - static urlMapCacheType::size_type maxUrlMapCache; - - // don't make this public - it's not threadsafe: - CompidentType mapCompNext(const std::string& compUrl, - urlmap_type::const_iterator& pos) const; - - public: - virtual ~Dispatcher() { } - - void addUrlMapEntry(const std::string& url, const CompidentType& ci); - - Compident mapComp(const std::string& compUrl) const; - - static urlMapCacheType::size_type getMaxUrlMapCache() - { return maxUrlMapCache; } - static void setMaxUrlMapCache(urlMapCacheType::size_type s) - { maxUrlMapCache = s; } - - friend class PosType; - - class PosType - { - const Dispatcher& dis; - cxxtools::RdLock lock; - urlmap_type::const_iterator pos; - std::string url; - bool first; - - public: - PosType(const Dispatcher& d, const std::string& u) - : dis(d), - lock(dis.rwlock), - pos(dis.urlmap.begin()), - url(u), - first(true) - { } - - CompidentType getNext(); - }; - }; - -} - -#endif // TNT_DISPATCHER_H - diff --git a/httpd/tnt/gcryptinit.h b/httpd/tnt/gcryptinit.h deleted file mode 100644 index 3b6ee33..0000000 --- a/httpd/tnt/gcryptinit.h +++ /dev/null @@ -1,37 +0,0 @@ -/* tnt/gcryptinit.h - * Copyright (C) 2003-2005 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef TNT_GCRYPTINIT_H -#define TNT_GCRYPTINIT_H - -#include <gcrypt.h> - -#ifdef __cplusplus -extern "C" -{ -#endif - -gcry_error_t gcrypt_init(); - -#ifdef __cplusplus -} -#endif - -#endif // TNT_GCRYPTINIT_H - diff --git a/httpd/tnt/gnutls.h b/httpd/tnt/gnutls.h deleted file mode 100644 index 8d8811c..0000000 --- a/httpd/tnt/gnutls.h +++ /dev/null @@ -1,146 +0,0 @@ -/* tnt/gnutls.h - * Copyright (C) 2006 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef TNT_GNUTLS_H -#define TNT_GNUTLS_H - -#include <cxxtools/tcpstream.h> -#include <gnutls/gnutls.h> - -namespace tnt -{ - class GnuTlsException : public std::runtime_error - { - unsigned long code; - static std::string formatMessage(const std::string& function, int code_); - - public: - GnuTlsException(const std::string& function, int code_) - : std::runtime_error(formatMessage(function, code_)), - code(code_) - { } - - unsigned long getCode() const - { return code; } - }; - - class GnuTlsInit - { - static unsigned initCount; - static gnutls_dh_params dhParams; - - public: - GnuTlsInit(); - ~GnuTlsInit(); - - gnutls_dh_params getDhParams() const { return dhParams; } - }; - - class GnuTlsX509Cred - { - gnutls_certificate_credentials x509_cred; - GnuTlsInit init; - - public: - GnuTlsX509Cred(const char* certificateFile, const char* privateKeyFile); - ~GnuTlsX509Cred(); - - operator gnutls_certificate_credentials() const { return x509_cred; } - }; - - class GnuTlsServer : public cxxtools::net::Server - { - GnuTlsX509Cred cred; - - public: - GnuTlsServer(const char* certificateFile, const char* privateKeyFile); - - gnutls_certificate_credentials getCred() const { return cred; } - }; - - class GnuTlsStream : public cxxtools::net::Stream - { - gnutls_session session; - - public: - GnuTlsStream() - : session(0) - { } - - explicit GnuTlsStream(int fd) - : cxxtools::net::Stream(fd) - { } - - explicit GnuTlsStream(const GnuTlsServer& server) - { accept(server); } - - ~GnuTlsStream(); - - void accept(const GnuTlsServer& server); - int sslRead(char* buffer, int bufsize) const; - int sslWrite(const char* buffer, int bufsize) const; - void shutdown() const; - }; - - class GnuTls_streambuf : public std::streambuf - { - GnuTlsStream& m_stream; - char_type* m_buffer; - unsigned m_bufsize; - - public: - explicit GnuTls_streambuf(GnuTlsStream& stream, unsigned bufsize = 256, int timeout = -1); - ~GnuTls_streambuf() - { delete[] m_buffer; } - - void setTimeout(int t) { m_stream.setTimeout(t); } - int getTimeout() const { return m_stream.getTimeout(); } - - /// overload std::streambuf - int_type overflow(int_type c); - /// overload std::streambuf - int_type underflow(); - /// overload std::streambuf - int sync(); - }; - - class GnuTls_iostream : public GnuTlsStream, public std::iostream - { - GnuTls_streambuf m_buffer; - - public: - explicit GnuTls_iostream(unsigned bufsize = 256, int timeout = -1) - : GnuTlsStream(-1), - std::iostream(&m_buffer), - m_buffer(*this, bufsize, timeout) - { } - - explicit GnuTls_iostream(const GnuTlsServer& server, unsigned bufsize = 256, int timeout = -1) - : GnuTlsStream(server), - std::iostream(&m_buffer), - m_buffer(*this, bufsize, timeout) - { } - - void setTimeout(int timeout) { m_buffer.setTimeout(timeout); } - int getTimeout() const { return m_buffer.getTimeout(); } - }; -} - -#endif // TNT_GNUTLS_H - diff --git a/httpd/tnt/job.h b/httpd/tnt/job.h deleted file mode 100644 index 5e839fd..0000000 --- a/httpd/tnt/job.h +++ /dev/null @@ -1,201 +0,0 @@ -/* tnt/job.h - * Copyright (C) 2003-2005 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef TNT_JOB_H -#define TNT_JOB_H - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif -#include <deque> -#include <cxxtools/thread.h> -#include <cxxtools/tcpstream.h> -#include <tnt/httprequest.h> -#include <tnt/httpparser.h> -#include <tnt/pointer.h> -#include <time.h> -#include "tnt/ssl.h" - -/** -// in tntnet (mainthread): -Jobqueue queue; -void mainloop() -{ - while (1) - { - Jobqueue::JobPtr j = new Tcpjob(); - j->accept(poller.get()); - queue.put(j); - } -} - -// in server (workerthread): -void Server::run() -{ - while (1) - { - Jobqueue::JobPtr j = queue.get(); - std::iostream& socket = j->getStream(); - processRequest(socket); - } -} -*/ - -namespace tnt -{ - /** Job - one per request */ - class Job - { - unsigned keepAliveCounter; - - HttpRequest request; - HttpMessage::Parser parser; - time_t lastAccessTime; - - unsigned refs; - - static unsigned socket_read_timeout; - static unsigned socket_write_timeout; - static unsigned keepalive_max; - static unsigned socket_buffer_size; - - public: - Job() - : keepAliveCounter(keepalive_max), - parser(request), - lastAccessTime(0), - refs(0) - { } - - protected: - virtual ~Job(); - - public: - unsigned addRef() { return ++refs; } - unsigned release() - { - if (--refs == 0) - { - delete this; - return 0; - } - else - return refs; - } - - virtual std::iostream& getStream() = 0; - virtual int getFd() const = 0; - virtual void setRead() = 0; - virtual void setWrite() = 0; - - HttpRequest& getRequest() { return request; } - HttpMessage::Parser& getParser() { return parser; } - - unsigned decrementKeepAliveCounter() - { return keepAliveCounter > 0 ? --keepAliveCounter : 0; } - void clear(); - void touch() { time(&lastAccessTime); } - int msecToTimeout(time_t currentTime) const; - - static void setSocketReadTimeout(unsigned ms) { socket_read_timeout = ms; } - static void setSocketWriteTimeout(unsigned ms) { socket_write_timeout = ms; } - static void setKeepAliveMax(unsigned n) { keepalive_max = n; } - static void setSocketBufferSize(unsigned b) { socket_buffer_size = b; } - - static unsigned getSocketReadTimeout() { return socket_read_timeout; } - static unsigned getSocketWriteTimeout() { return socket_write_timeout; } - static unsigned getKeepAliveTimeout(); - static unsigned getKeepAliveMax() { return keepalive_max; } - static unsigned getSocketBufferSize() { return socket_buffer_size; } - }; - - class Tcpjob : public Job - { - cxxtools::net::iostream socket; - - public: - Tcpjob() - : socket(getSocketBufferSize(), getSocketReadTimeout()) - { } - - void accept(const cxxtools::net::Server& listener); - - std::iostream& getStream(); - int getFd() const; - void setRead(); - void setWrite(); - }; - -#ifdef USE_SSL - class SslTcpjob : public Job - { - ssl_iostream socket; - - public: - SslTcpjob() - : socket(getSocketBufferSize(), getSocketReadTimeout()) - { } - - void accept(const SslServer& listener); - - std::iostream& getStream(); - int getFd() const; - void setRead(); - void setWrite(); - }; -#endif // USE_SSL - - /** Jobqueue - one per process */ - class Jobqueue - { - public: - typedef Pointer<Job> JobPtr; - - cxxtools::Condition noWaitThreads; - - private: - std::deque<JobPtr> jobs; - cxxtools::Mutex mutex; - cxxtools::Condition notEmpty; - cxxtools::Condition notFull; - unsigned waitThreads; - unsigned capacity; - - public: - explicit Jobqueue(unsigned capacity_) - : waitThreads(0), - capacity(capacity_) - { } - - void put(JobPtr j); - JobPtr get(); - - void setCapacity(unsigned c) - { capacity = c; } - unsigned getCapacity() const - { return capacity; } - unsigned getWaitThreadCount() const - { return waitThreads; } - bool empty() const - { return jobs.empty(); } - }; -} - -#endif // TNT_JOB_H - diff --git a/httpd/tnt/listener.h b/httpd/tnt/listener.h deleted file mode 100644 index 4991763..0000000 --- a/httpd/tnt/listener.h +++ /dev/null @@ -1,78 +0,0 @@ -/* tnt/listener.h - * Copyright (C) 2003 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef TNT_LISTENER_H -#define TNT_LISTENER_H - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif -#include <cxxtools/thread.h> -#include "tnt/job.h" - -namespace tnt -{ - class ListenerBase : public cxxtools::AttachedThread - { - std::string ipaddr; - unsigned short int port; - - public: - ListenerBase(const std::string& ipaddr_, unsigned short int port_) - : ipaddr(ipaddr_), - port(port_) - { } - - void doStop(); - }; - - class Listener : public ListenerBase - { - cxxtools::net::Server server; - Jobqueue& queue; - static int backlog; - static unsigned listenRetry; - - public: - Listener(const std::string& ipaddr, unsigned short int port, Jobqueue& q); - virtual void run(); - - static void setBacklog(int backlog_) { backlog = backlog_; } - static int getBacklog() { return backlog; } - static void setListenRetry(unsigned listenRetry_) { listenRetry = listenRetry_; } - static unsigned getListenRetry() { return listenRetry; } - }; - -#ifdef USE_SSL - class Ssllistener : public ListenerBase - { - SslServer server; - Jobqueue& queue; - - public: - Ssllistener(const char* certificateFile, const char* keyFile, - const std::string& ipaddr, unsigned short int port, Jobqueue& q); - virtual void run(); - }; -#endif // USE_SSL - -} - -#endif // TNT_LISTENER_H - diff --git a/httpd/tnt/openssl.h b/httpd/tnt/openssl.h deleted file mode 100644 index 863782f..0000000 --- a/httpd/tnt/openssl.h +++ /dev/null @@ -1,121 +0,0 @@ -/* tnt/openssl.h - * Copyright (C) 2003 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef TNT_OPENSSL_H -#define TNT_OPENSSL_H - -#include <cxxtools/tcpstream.h> -#include <openssl/ssl.h> - -namespace tnt -{ - class OpensslException : public std::runtime_error - { - unsigned long code; - - public: - OpensslException(const std::string& what, unsigned long code_) - : std::runtime_error(what), - code(code_) - { } - - unsigned long getCode() const - { return code; } - }; - - class OpensslServer : public cxxtools::net::Server - { - SSL_CTX* ctx; - void installCertificates(const char* certificateFile, const char* privateKeyFile); - - public: - OpensslServer(const char* certificateFile); - OpensslServer(const char* certificateFile, const char* privateKeyFile); - ~OpensslServer(); - - SSL_CTX* getSslContext() const { return ctx; } - }; - - class OpensslStream : public cxxtools::net::Stream - { - SSL* ssl; - - public: - OpensslStream(); - - explicit OpensslStream(int fd) - : cxxtools::net::Stream(fd) - { } - - explicit OpensslStream(const OpensslServer& server); - ~OpensslStream(); - - void accept(const OpensslServer& server); - - int sslRead(char* buffer, int bufsize) const; - int sslWrite(const char* buffer, int bufsize) const; - void shutdown() const; - }; - - class openssl_streambuf : public std::streambuf - { - OpensslStream& m_stream; - char_type* m_buffer; - unsigned m_bufsize; - - public: - explicit openssl_streambuf(OpensslStream& stream, unsigned bufsize = 256, int timeout = -1); - ~openssl_streambuf() - { delete[] m_buffer; } - - void setTimeout(int t) { m_stream.setTimeout(t); } - int getTimeout() const { return m_stream.getTimeout(); } - - /// overload std::streambuf - int_type overflow(int_type c); - /// overload std::streambuf - int_type underflow(); - /// overload std::streambuf - int sync(); - }; - - class openssl_iostream : public OpensslStream, public std::iostream - { - openssl_streambuf m_buffer; - - public: - explicit openssl_iostream(unsigned bufsize = 256, int timeout = -1) - : OpensslStream(-1), - std::iostream(&m_buffer), - m_buffer(*this, bufsize, timeout) - { } - - explicit openssl_iostream(const OpensslServer& server, unsigned bufsize = 256, int timeout = -1) - : OpensslStream(server), - std::iostream(&m_buffer), - m_buffer(*this, bufsize, timeout) - { } - - void setTimeout(int timeout) { m_buffer.setTimeout(timeout); } - int getTimeout() const { return m_buffer.getTimeout(); } - }; -} - -#endif // TNT_OPENSSL_H - diff --git a/httpd/tnt/poller.h b/httpd/tnt/poller.h deleted file mode 100644 index d9b12e9..0000000 --- a/httpd/tnt/poller.h +++ /dev/null @@ -1,61 +0,0 @@ -/* tnt/poller.h - * Copyright (C) 2005 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef TNT_POLLER_H -#define TNT_POLLER_H - -#include "tnt/job.h" -#include <cxxtools/dynbuffer.h> -#include <cxxtools/thread.h> -#include <sys/poll.h> - -namespace tnt -{ - class Poller : public cxxtools::AttachedThread - { - Jobqueue& queue; - int notify_pipe[2]; - - typedef std::deque<Jobqueue::JobPtr> jobs_type; - - jobs_type current_jobs; - cxxtools::Dynbuffer<pollfd> pollfds; - - jobs_type new_jobs; - - cxxtools::Mutex mutex; - int poll_timeout; - - void append_new_jobs(); - void append(Jobqueue::JobPtr& job); - void dispatch(); - void remove(jobs_type::size_type n); - - public: - Poller(Jobqueue& q); - - virtual void run(); - void doStop(); - void addIdleJob(Jobqueue::JobPtr job); - }; - -} - -#endif // TNT_POLLER_H - diff --git a/httpd/tnt/regex.h b/httpd/tnt/regex.h deleted file mode 100644 index b2a30e8..0000000 --- a/httpd/tnt/regex.h +++ /dev/null @@ -1,79 +0,0 @@ -/* tnt/regex.h - * Copyright (C) 2005 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef TNT_REGEX_H -#define TNT_REGEX_H - -#include <string> -#include <sys/types.h> -#include <regex.h> - -namespace tnt -{ - /// collects matches in a regex - class regex_smatch - { - friend class regex; - - std::string str; - regmatch_t matchbuf[10]; - - public: - unsigned size() const; - std::string get(unsigned n) const; - std::string format(const std::string& s) const; - }; - - /// regex(3)-wrapper. - /// Warning: incomplete, but sufficient for tntnet. - /// Regular expression is not automatically freed. Tntnet needs to - /// put regex into a stl-container, so it needs to be copyable. - /// For this class to be complete, the regex_t needs to be - /// reference-counted. This is unneeded for tntnet, because the regex is - /// never freed anyway. - class regex - { - regex_t expr; - - void checkerr(int ret) const; - - public: - explicit regex(const char* ex, int cflags = REG_EXTENDED) - { - checkerr(::regcomp(&expr, ex, cflags)); - } - - explicit regex(const std::string& ex, int cflags = REG_EXTENDED) - { - checkerr(::regcomp(&expr, ex.c_str(), cflags)); - } - - bool match(const std::string& str_, regex_smatch& smatch, int eflags = 0) const; - bool match(const std::string& str_, int eflags = 0) const; - - void free(); - - private: - friend class value_type; - }; - -} - -#endif // TNT_REGEX_H - diff --git a/httpd/tnt/ssl.h b/httpd/tnt/ssl.h deleted file mode 100644 index 6660d2f..0000000 --- a/httpd/tnt/ssl.h +++ /dev/null @@ -1,52 +0,0 @@ -/* tnt/ssl.h - * Copyright (C) 2006 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef TNT_SSL_H -#define TNT_SSL_H - -#ifdef WITH_GNUTLS -# include "tnt/gnutls.h" -# define USE_SSL -#endif - -#ifdef WITH_OPENSSL -# include "tnt/openssl.h" -# define USE_SSL -#endif - -namespace tnt -{ -#ifdef WITH_GNUTLS - - typedef GnuTlsServer SslServer; - typedef GnuTls_iostream ssl_iostream; - -#endif - -#ifdef WITH_OPENSSL - - typedef OpensslServer SslServer; - typedef openssl_iostream ssl_iostream; - -#endif - -} - -#endif // TNT_SSL_H - diff --git a/httpd/tnt/tntnet.h b/httpd/tnt/tntnet.h deleted file mode 100644 index a83784e..0000000 --- a/httpd/tnt/tntnet.h +++ /dev/null @@ -1,99 +0,0 @@ -/* tnt/tntnet.h - * Copyright (C) 2003-2005 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef TNT_TNTNET_H -#define TNT_TNTNET_H - -#include <cxxtools/arg.h> -#include "tnt/tntconfig.h" -#include "tnt/job.h" -#include "tnt/poller.h" -#include "tnt/dispatcher.h" -#include <tnt/scopemanager.h> -#include <set> - -namespace tnt -{ - class ListenerBase; - - class Tntnet - { - std::string configFile; - Tntconfig config; - cxxtools::Arg<const char*> propertyfilename; - cxxtools::Arg<bool> debug; - bool isDaemon; - - unsigned minthreads; - unsigned maxthreads; - unsigned long threadstartdelay; - - Jobqueue queue; - - static bool stop; - static int ret; - typedef std::set<ListenerBase*> listeners_type; - listeners_type listeners; - - Poller pollerthread; - Dispatcher d_dispatcher; - - static std::string pidFileName; - - ScopeManager scopemanager; - - // helper methods - void setUser() const; - void setGroup() const; - void setDir(const char* def) const; - int mkDaemon() const; // returns pipe - void closeStdHandles() const; - - // noncopyable - Tntnet(const Tntnet&); - Tntnet& operator= (const Tntnet&); - - void initLogging(); - void writePidfile(int pid); - void monitorProcess(int workerPid); - void initWorkerProcess(); - void workerProcess(int filedes = -1); - - void timerTask(); - void loadConfiguration(); - - public: - Tntnet(int& argc, char* argv[]); - int run(); - - static void shutdown(); - static void restart(); - static bool shouldStop() { return stop; } - - Jobqueue& getQueue() { return queue; } - Poller& getPoller() { return pollerthread; } - const Dispatcher& getDispatcher() const { return d_dispatcher; } - const Tntconfig& getConfig() const { return config; } - ScopeManager& getScopemanager() { return scopemanager; } - }; - -} - -#endif // TNT_TNTNET_H - diff --git a/httpd/tnt/worker.h b/httpd/tnt/worker.h deleted file mode 100644 index be42841..0000000 --- a/httpd/tnt/worker.h +++ /dev/null @@ -1,91 +0,0 @@ -/* tnt/worker.h - * Copyright (C) 2003-2005 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef TNT_WORKER_H -#define TNT_WORKER_H - -#include <string> -#include <cxxtools/tcpstream.h> -#include <cxxtools/thread.h> -#include <cxxtools/pool.h> -#include <tnt/comploader.h> -#include <tnt/tntnet.h> -#include <tnt/scope.h> - -namespace tnt -{ - class HttpRequest; - class HttpReply; - - class Worker : public cxxtools::DetachedThread - { - static cxxtools::Mutex mutex; - static unsigned nextThreadNumber; - - Tntnet& application; - - typedef cxxtools::Pool<Comploader> ComploaderPoolType; - static ComploaderPoolType comploaderPool; - - ComploaderPoolType::objectptr_type comploaderObject; - Comploader& comploader; - - Scope threadScope; - - pthread_t threadId; - const char* state; - time_t lastWaitTime; - - typedef std::set<Worker*> workers_type; - static workers_type workers; - - static unsigned maxRequestTime; - static unsigned minThreads; - static bool enableCompression; - - bool processRequest(HttpRequest& request, std::iostream& socket, - unsigned keepAliveCount); - void healthCheck(time_t currentTime); - - ~Worker(); - - public: - Worker(Tntnet& app); - - virtual void run(); - - void dispatch(HttpRequest& request, HttpReply& reply); - - static void timer(); - - /// Sets a hard limit for request-time. - /// When the time is exceeded, this process exits. - static void setMaxRequestTime(unsigned sec) { maxRequestTime = sec; } - static unsigned getMaxRequestTime() { return maxRequestTime; } - - static workers_type::size_type getCountThreads(); - static void setMinThreads(unsigned n) { minThreads = n; } - - static void setEnableCompression(bool sw = true) { enableCompression = sw; } - static unsigned getEnableCompression() { return enableCompression; } - }; -} - -#endif // TNT_WORKER_H - diff --git a/httpd/tntnet.cpp b/httpd/tntnet.cpp deleted file mode 100644 index 98f2ac9..0000000 --- a/httpd/tntnet.cpp +++ /dev/null @@ -1,832 +0,0 @@ -/* tntnet.cpp - * Copyright (C) 2003-2005 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "tnt/worker.h" -#include "tnt/tntnet.h" -#include "tnt/listener.h" -#include "tnt/http.h" -#include "tnt/httpreply.h" -#include "tnt/sessionscope.h" - -#include <cxxtools/tcpstream.h> -#include <cxxtools/log.h> -#include <cxxtools/loginit.h> - -#include <iostream> -#include <fstream> -#include <vector> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <grp.h> -#include <pwd.h> -#include <signal.h> -#include <sys/wait.h> -#include <errno.h> -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#ifndef TNTNET_CONF -# define TNTNET_CONF "/etc/tntnet.conf" -#endif - -#ifndef TNTNET_PID -# define TNTNET_PID "/var/run/tntnet.pid" -#endif - -log_define("tntnet.tntnet") - -#define log_error_master(expr) \ - do { \ - std::cout << "ERROR: " << expr << std::endl; \ - } while(false) - -#define log_warn_master(expr) \ - do { \ - std::cout << "WARN: " << expr << std::endl; \ - } while(false) - -#define log_info_master(expr) \ - do { \ - std::cout << "INFO: " << expr << std::endl; \ - } while(false) - -#define log_debug_master(expr) \ - do { \ - std::cout << "DEBUG: " << expr << std::endl; \ - } while(false) - -namespace -{ - void sigEnd(int) - { - tnt::Tntnet::shutdown(); - } - - void sigReload(int) - { - // stopping child with 111 signals monitor-process to restart child - tnt::Tntnet::restart(); - } - - void configureDispatcher(tnt::Dispatcher& dis, const tnt::Tntconfig& config) - { - typedef tnt::Dispatcher::CompidentType CompidentType; - - const tnt::Tntconfig::config_entries_type& params = config.getConfigValues(); - - tnt::Tntconfig::config_entries_type::const_iterator vi; - for (vi = params.begin(); vi != params.end(); ++vi) - { - const tnt::Tntconfig::config_entry_type& v = *vi; - const tnt::Tntconfig::params_type& args = v.params; - if (v.key == "MapUrl") - { - if (args.size() < 2) - { - std::ostringstream msg; - msg << "invalid number of parameters (" << args.size() << ") in MapUrl"; - throw std::runtime_error(msg.str()); - } - - std::string url = args[0]; - - CompidentType ci = CompidentType(args[1]); - if (args.size() > 2) - { - ci.setPathInfo(args[2]); - if (args.size() > 3) - ci.setArgs(CompidentType::args_type(args.begin() + 3, args.end())); - } - - dis.addUrlMapEntry(url, ci); - } - } - } - - bool checkChildSuccess(int fd) - { - log_debug("checkChildSuccess"); - - char buffer; - int ret = ::read(fd, &buffer, 1); - if (ret < 0) - throw std::runtime_error( - std::string("error in read: ") + strerror(errno)); - close(fd); - return ret > 0; - } - - void signalParentSuccess(int fd) - { - log_debug("signalParentSuccess"); - - ssize_t s = write(fd, "1", 1); - if (s < 0) - throw std::runtime_error( - std::string("error in write(): ") + strerror(errno)); - close(fd); - } - -} - -namespace tnt -{ - //////////////////////////////////////////////////////////////////////// - // Tntnet - // - bool Tntnet::stop = false; - int Tntnet::ret = 0; - std::string Tntnet::pidFileName; - - Tntnet::Tntnet(int& argc, char* argv[]) - : propertyfilename(argc, argv, 'P'), - debug(argc, argv, 'd'), - queue(1000), - pollerthread(queue) - { - // check for argument -c - cxxtools::Arg<const char*> conf(argc, argv, 'c'); - if (conf.isSet()) - configFile = conf; - else - { - // read 1st parameter from argument-list - cxxtools::Arg<const char*> conf(argc, argv); - if (conf.isSet()) - configFile = conf; - else - { - // check environment-variable TNTNET_CONF - const char* tntnetConf = ::getenv("TNTNET_CONF"); - if (tntnetConf) - configFile = tntnetConf; - else - configFile = TNTNET_CONF; // take default - } - } - } - - void Tntnet::setGroup() const - { - Tntconfig::params_type group = config.getConfigValue("Group"); - if (group.size() >= 1) - { - struct group * gr = getgrnam(group.begin()->c_str()); - if (gr == 0) - throw std::runtime_error("unknown group " + *group.begin()); - - log_debug("change group to " << *group.begin() << '(' << gr->gr_gid << ')'); - - int ret = setgid(gr->gr_gid); - if (ret != 0) - { - std::ostringstream msg; - msg << "cannot change group to " << *group.begin() - << '(' << gr->gr_gid << "): " << strerror(errno); - throw std::runtime_error(msg.str()); - } - } - } - - void Tntnet::setDir(const char* def) const - { - std::string dir = config.getValue("Dir", def); - - if (!dir.empty()) - { - log_debug("chdir(" << dir << ')'); - if (chdir(dir.c_str()) == -1) - { - throw std::runtime_error( - std::string("error in chdir(): ") - + strerror(errno)); - } - } - - std::string chrootdir = config.getValue("Chroot"); - if (!chrootdir.empty() && chroot(chrootdir.c_str()) == -1) - throw std::runtime_error( - std::string("error in chroot(): ") - + strerror(errno)); - } - - void Tntnet::setUser() const - { - Tntconfig::params_type user = config.getConfigValue("User"); - if (user.size() >= 1) - { - struct passwd * pw = getpwnam(user.begin()->c_str()); - if (pw == 0) - throw std::runtime_error("unknown user " + *user.begin()); - - log_debug("change user to " << *user.begin() << '(' << pw->pw_uid << ')'); - - int ret = setuid(pw->pw_uid); - if (ret != 0) - { - std::ostringstream msg; - msg << "cannot change user to " << *user.begin() - << '(' << pw->pw_uid << "): " << strerror(errno); - throw std::runtime_error(msg.str()); - } - } - } - - int Tntnet::mkDaemon() const - { - log_info("start daemon-mode"); - - int filedes[2]; - - if (pipe(filedes) != 0) - throw std::runtime_error( - std::string("error in pipe(int[2]): ") + strerror(errno)); - - int pid = fork(); - if (pid > 0) - { - // parent - - close(filedes[1]); // close write-fd - - // exit with error, when nothing read - ::exit (checkChildSuccess(filedes[0]) ? 0 : 1); - } - else if (pid < 0) - throw std::runtime_error( - std::string("error in fork(): ") + strerror(errno)); - - // child - - close(filedes[0]); // close read-fd - - // setsid - if (setsid() == -1) - throw std::runtime_error( - std::string("error in setsid(): ") - + strerror(errno)); - - // return write-fd - return filedes[1]; - } - - void Tntnet::closeStdHandles() const - { - // close stdin, stdout and stderr - bool noclosestd = config.getBoolValue("NoCloseStdout", false); - if (noclosestd) - { - log_debug("not closing stdout"); - return; - } - - if (freopen("/dev/null", "r", stdin) == 0) - throw std::runtime_error( - std::string("unable to replace stdin with /dev/null: ") - + strerror(errno)); - - if (freopen("/dev/null", "w", stdout) == 0) - throw std::runtime_error( - std::string("unable to replace stdout with /dev/null: ") - + strerror(errno)); - - if (freopen("/dev/null", "w", stderr) == 0) - throw std::runtime_error( - std::string("unable to replace stderr with /dev/null: ") - + strerror(errno)); - } - - int Tntnet::run() - { - loadConfiguration(); - - if (debug) - { - log_init_debug(); - log_warn("Debugmode"); - isDaemon = false; - } - else - { - isDaemon = config.getBoolValue("Daemon", false); - } - - if (isDaemon) - { - int filedes = mkDaemon(); - - setDir(""); - - bool nomonitor = config.getBoolValue("NoMonitor", false); - if (nomonitor) - { - log_debug("start worker-process without monitor"); - writePidfile(getpid()); - initWorkerProcess(); - - // change group and user - setGroup(); - setUser(); - - initLogging(); - workerProcess(filedes); - } - else - { - initWorkerProcess(); - do - { - int filedes_monitor[2]; - - if (pipe(filedes_monitor) != 0) - throw std::runtime_error( - std::string("error in pipe(int[2]): ") + strerror(errno)); - - // fork workerprocess - int pid = fork(); - if (pid < 0) - throw std::runtime_error( - std::string("error in forking workerprocess: ") - + strerror(errno)); - - if (pid == 0) - { - // workerprocess - - close(filedes_monitor[0]); // close read-fd - - // change group and user - setGroup(); - setUser(); - - initLogging(); - workerProcess(filedes_monitor[1]); - return ret; - } - else - { - close(filedes_monitor[1]); // close write-fd - - // write child-pid - writePidfile(pid); - - // wait for worker to signal success - if (!checkChildSuccess(filedes_monitor[0])) - ::exit(1); - if (filedes >= 0) - { - signalParentSuccess(filedes); - filedes = -1; - } - - monitorProcess(pid); - if (!stop) - sleep(1); - } - - } while (!stop); - } - } - else - { - log_info("no daemon-mode"); - initLogging(); - initWorkerProcess(); - workerProcess(); - } - - return 0; - } - - void Tntnet::initLogging() - { - if (debug) - return; // logging already initialized - - std::string pf; - if (propertyfilename.isSet()) - pf = propertyfilename.getValue(); - else - pf = config.getValue("PropertyFile"); - - if (pf.empty()) - log_init(); - else - { - struct stat properties_stat; - if (stat(pf.c_str(), &properties_stat) != 0) - throw std::runtime_error("propertyfile " + pf + " not found"); - - log_init(pf.c_str()); - } - } - - void Tntnet::writePidfile(int pid) - { - pidFileName = config.getValue("PidFile", TNTNET_PID); - - log_debug("pidfile=" << pidFileName); - - if (!pidFileName.empty()) - { - if (pidFileName[0] != '/') - { - // prepend current working-directory to pidfilename if not absolute - std::vector<char> buf(256); - const char* cwd; - while (true) - { - cwd = ::getcwd(&buf[0], buf.size()); - if (cwd) - break; - else if (errno == ERANGE) - buf.resize(buf.size() * 2); - else - throw std::runtime_error( - std::string("error in getcwd: ") + strerror(errno)); - } - pidFileName = std::string(cwd) + '/' + pidFileName; - log_debug("pidfile=" << pidFileName); - } - - std::ofstream pidfile(pidFileName.c_str()); - if (!pidfile) - throw std::runtime_error("unable to open pid-file " + pidFileName); - pidfile << pid; - } - } - - void Tntnet::monitorProcess(int workerPid) - { - setDir(""); - - // close stdin, stdout and stderr - closeStdHandles(); - - int status; - waitpid(workerPid, &status, 0); - - if (WIFSIGNALED(status)) - { - // SIGTERM means normal exit - if (WTERMSIG(status) == SIGTERM) - { - log_info_master("child terminated normally"); - stop = true; - } - else - { - log_warn_master("child terminated with signal " - << WTERMSIG(status) << " - restart child"); - } - } - else if (WEXITSTATUS(status) == 111) - { - log_info_master("child requested restart"); - } - else - { - log_info_master("child exited with exitcode " << WEXITSTATUS(status)); - stop = true; - } - - if (unlink(pidFileName.c_str()) != 0) - log_error_master("failed to remove pidfile \"" << pidFileName << "\" error " << errno); - } - - void Tntnet::initWorkerProcess() - { - log_debug("init workerprocess"); - - //signal(SIGPIPE, SIG_IGN); - //signal(SIGABRT, SIG_IGN); - //signal(SIGTERM, sigEnd); - //signal(SIGHUP, sigReload); - - configureDispatcher(d_dispatcher, config); - - // create listener-threads - Tntconfig::config_entries_type configListen; - config.getConfigValues("Listen", configListen); - - if (configListen.empty()) - { - log_warn("no listeners defined - using 0.0.0.0:80"); - ListenerBase* s = new tnt::Listener("0.0.0.0", 80, queue); - listeners.insert(s); - } - else - { - for (Tntconfig::config_entries_type::const_iterator it = configListen.begin(); - it != configListen.end(); ++it) - { - if (it->params.empty()) - throw std::runtime_error("empty Listen-entry"); - - unsigned short int port = 80; - if (it->params.size() >= 2) - { - std::istringstream p(it->params[1]); - p >> port; - if (!p) - { - std::ostringstream msg; - msg << "invalid port " << it->params[1]; - throw std::runtime_error(msg.str()); - } - } - - std::string ip(it->params[0]); - log_debug("create listener ip=" << ip << " port=" << port); - ListenerBase* s = new tnt::Listener(ip, port, queue); - listeners.insert(s); - } - } - -#ifdef USE_SSL - // create ssl-listener-threads - std::string defaultCertificateFile = config.getValue("SslCertificate"); - std::string defaultCertificateKey = config.getValue("SslKey"); - configListen.clear(); - config.getConfigValues("SslListen", configListen); - - for (Tntconfig::config_entries_type::const_iterator it = configListen.begin(); - it != configListen.end(); ++it) - { - if (it->params.empty()) - throw std::runtime_error("empty SslListen-entry"); - - unsigned short int port = 443; - if (it->params.size() >= 2) - { - std::istringstream p(it->params[1]); - p >> port; - if (!p) - { - std::ostringstream msg; - msg << "invalid port " << it->params[1]; - throw std::runtime_error(msg.str()); - } - } - - std::string certificateFile = - it->params.size() >= 3 ? it->params[2] - : defaultCertificateFile; - std::string certificateKey = - it->params.size() >= 4 ? it->params[3] : - it->params.size() >= 3 ? it->params[2] : defaultCertificateKey; - - if (certificateFile.empty()) - throw std::runtime_error("Ssl-certificate not configured"); - - std::string ip(it->params[0]); - log_debug("create ssl-listener ip=" << ip << " port=" << port); - ListenerBase* s = new Ssllistener(certificateFile.c_str(), - certificateKey.c_str(), ip, port, queue); - listeners.insert(s); - } -#endif // USE_SSL - - // configure worker (static) - Comploader::configure(config); - - // configure http - HttpMessage::setMaxRequestSize( - config.getValue("MaxRequestSize", HttpMessage::getMaxRequestSize())); - Job::setSocketReadTimeout( - config.getValue("SocketReadTimeout", Job::getSocketReadTimeout())); - Job::setSocketWriteTimeout( - config.getValue("SocketWriteTimeout", Job::getSocketWriteTimeout())); - Job::setKeepAliveMax( - config.getValue("KeepAliveMax", Job::getKeepAliveMax())); - Job::setSocketBufferSize( - config.getValue("BufferSize", Job::getSocketBufferSize())); - HttpReply::setMinCompressSize( - config.getValue("MinCompressSize", HttpReply::getMinCompressSize())); - HttpReply::setKeepAliveTimeout( - config.getValue("KeepAliveTimeout", HttpReply::getKeepAliveTimeout())); - HttpReply::setDefaultContentType( - config.getValue("DefaultContentType", HttpReply::getDefaultContentType())); - - log_debug("listeners.size()=" << listeners.size()); - } - - void Tntnet::workerProcess(int filedes) - { - log_debug("worker-process"); - - // reload configuration - config = Tntconfig(); - loadConfiguration(); - - // initialize worker-process - minthreads = config.getValue<unsigned>("MinThreads", 5); - maxthreads = config.getValue<unsigned>("MaxThreads", 100); - threadstartdelay = config.getValue<unsigned>("ThreadStartDelay", 10); - Worker::setMinThreads(minthreads); - Worker::setMaxRequestTime(config.getValue<unsigned>("MaxRequestTime", Worker::getMaxRequestTime())); - Worker::setEnableCompression(config.getBoolValue("EnableCompression", Worker::getEnableCompression())); - queue.setCapacity(config.getValue<unsigned>("QueueSize", queue.getCapacity())); - Sessionscope::setDefaultTimeout(config.getValue<unsigned>("SessionTimeout", Sessionscope::getDefaultTimeout())); - Listener::setBacklog(config.getValue<int>("ListenBacklog", Listener::getBacklog())); - Listener::setListenRetry(config.getValue<int>("ListenRetry", Listener::getListenRetry())); - Dispatcher::setMaxUrlMapCache(config.getValue<unsigned>("MaxUrlMapCache", Dispatcher::getMaxUrlMapCache())); - - Tntconfig::config_entries_type configSetEnv; - config.getConfigValues("SetEnv", configSetEnv); - for (Tntconfig::config_entries_type::const_iterator it = configSetEnv.begin(); - it != configSetEnv.end(); ++it) - { - if (it->params.size() >= 2) - { -#ifdef HAVE_SETENV - log_debug("setenv " << it->params[0] << "=\"" << it->params[1] << '"'); - ::setenv(it->params[0].c_str(), it->params[1].c_str(), 1); -#else - std::string name = it->params[0]; - std::string value = it->params[1]; - - char* env = new char[name.size() + value.size() + 2]; - name.copy(env, name.size()); - env[name.size()] = '='; - value.copy(env + name.size() + 1, value.size()); - env[name.size() + value.size() + 1] = '\0'; - - log_debug("putenv(" << env); - ::putenv(env); -#endif - } - } - - // create worker-threads - log_info("create " << minthreads << " worker threads"); - for (unsigned i = 0; i < minthreads; ++i) - { - log_debug("create worker " << i); - Worker* s = new Worker(*this); - s->create(); - } - - // create poller-thread - log_debug("start poller thread"); - pollerthread.create(); - - // launch listener-threads - log_info("create " << listeners.size() << " listener threads"); - for (listeners_type::iterator it = listeners.begin(); - it != listeners.end(); ++it) - (*it)->create(); - - log_debug("start timer thread"); - cxxtools::MethodThread<Tntnet, cxxtools::AttachedThread> timerThread(*this, &Tntnet::timerTask); - timerThread.create(); - - if (filedes >= 0) - { - signalParentSuccess(filedes); - closeStdHandles(); - } - - // mainloop - cxxtools::Mutex mutex; - while (!stop) - { - { - cxxtools::MutexLock lock(mutex); - queue.noWaitThreads.wait(lock); - } - - if (stop) - break; - - if (Worker::getCountThreads() < maxthreads) - { - log_info("create workerthread"); - Worker* s = new Worker(*this); - s->create(); - } - else - log_warn("max worker-threadcount " << maxthreads << " reached"); - - if (threadstartdelay > 0) - usleep(threadstartdelay); - } - - log_warn("stopping Tntnet"); - - // join-loop - while (!listeners.empty()) - { - listeners_type::value_type s = *listeners.begin(); - log_debug("remove listener from listener-list"); - listeners.erase(s); - - log_debug("request listener to stop"); - s->doStop(); - - log_debug("join listener-thread"); - s->join(); - delete s; - - log_debug("listener stopped"); - } - - log_info("listeners stopped"); - } - - void Tntnet::timerTask() - { - log_debug("timer thread"); - - while (!stop) - { - sleep(1); - - log_debug("check sessiontimeout"); - getScopemanager().checkSessionTimeout(); - - log_debug("worker-timer"); - Worker::timer(); - } - - log_warn("stopping Tntnet"); - - if (!pidFileName.empty()) - unlink(pidFileName.c_str()); - - queue.noWaitThreads.signal(); - Worker::setMinThreads(0); - pollerthread.doStop(); - } - - void Tntnet::loadConfiguration() - { - config = Tntconfig(); - config.load(configFile.c_str()); - } - - void Tntnet::shutdown() - { - stop = true; - } - - void Tntnet::restart() - { - // stopping child with 111 signals monitor-process to restart child - stop = true; - ret = 111; - } - -} - -//////////////////////////////////////////////////////////////////////// -// main -// -#ifdef HAVE_TNTNET_MAIN -int main(int argc, char* argv[]) -{ - signal(SIGPIPE, SIG_IGN); - signal(SIGABRT, SIG_IGN); - signal(SIGTERM, sigEnd); - std::ios::sync_with_stdio(false); - - try - { - tnt::Tntnet app(argc, argv); - if (argc != 1) - { - std::cout << PACKAGE_STRING "\n\n" << - "usage: " << argv[0] << " {options}\n\n" - " -c file configurationfile (default: " TNTNET_CONF ")\n" - " -d enable all debug output (ignoring properties-file)\n"; - return -1; - } - - return app.run(); - } - catch(const std::exception& e) - { - log_fatal(e.what()); - std::cerr << e.what() << std::endl; - return -1; - } -} -#endif diff --git a/httpd/worker.cpp b/httpd/worker.cpp deleted file mode 100644 index 7552db9..0000000 --- a/httpd/worker.cpp +++ /dev/null @@ -1,364 +0,0 @@ -/* worker.cpp - * Copyright (C) 2003-2005 Tommi Maekitalo - * - * 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 - * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and - * NON-INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "tnt/worker.h" -#include "tnt/dispatcher.h" -#include "tnt/job.h" -#include <tnt/httprequest.h> -#include <tnt/httpreply.h> -#include <tnt/httperror.h> -#include <tnt/http.h> -#include <tnt/poller.h> -#include <cxxtools/log.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <locale> -#include <errno.h> - -log_define("tntnet.worker") - -namespace -{ - static const char stateStarting[] = "0 starting"; - static const char stateWaitingForJob[] = "1 waiting for job"; - static const char stateParsing[] = "2 parsing request"; - static const char statePostParsing[] = "3 post parsing"; - static const char stateDispatch[] = "4 dispatch"; - static const char stateProcessingRequest[] = "5 processing request"; - static const char stateFlush[] = "6 flush"; - static const char stateSendReply[] = "7 send reply"; - static const char stateSendError[] = "8 send error"; - static const char stateStopping[] = "9 stopping"; -} - -namespace tnt -{ - cxxtools::Mutex Worker::mutex; - unsigned Worker::nextThreadNumber = 0; - Worker::workers_type Worker::workers; - unsigned Worker::maxRequestTime = 600; - unsigned Worker::minThreads = 5; - bool Worker::enableCompression = true; - - Worker::ComploaderPoolType Worker::comploaderPool; - - Worker::Worker(Tntnet& app) - : application(app), - comploaderObject(comploaderPool.get()), - comploader(comploaderObject), - threadId(0), - state(stateStarting), - lastWaitTime(0) - { - log_debug("initialize thread " << threadId); - - cxxtools::MutexLock lock(mutex); - workers.insert(this); - } - - Worker::~Worker() - { - cxxtools::MutexLock lock(mutex); - workers.erase(this); - - log_debug("delete worker " << threadId << " - " << workers.size() << " threads left - " << application.getQueue().getWaitThreadCount() << " waiting threads"); - } - - void Worker::run() - { - threadId = pthread_self(); - Jobqueue& queue = application.getQueue(); - log_debug("start thread " << threadId); - while (queue.getWaitThreadCount() < minThreads) - { - log_debug("waiting for job"); - state = stateWaitingForJob; - Jobqueue::JobPtr j = queue.get(); - if (Tntnet::shouldStop()) - { - log_warn("stop worker"); - break; - } - log_debug("got job - fd=" << j->getFd()); - - std::iostream& socket = j->getStream(); - - try - { - bool keepAlive; - do - { - time(&lastWaitTime); - - log_debug("read request"); - - keepAlive = false; - state = stateParsing; - j->getParser().parse(socket); - state = statePostParsing; - - if (socket.eof()) - log_debug("eof"); - else if (j->getParser().failed()) - { - state = stateSendError; - log_warn("bad request"); - socket << "HTTP/1.0 500 bad request\r\n" - "Content-Type: text/html\r\n" - "\r\n" - "<html><body><h1>Error</h1><p>bad request</p></body></html>" - << std::endl; - } - else if (socket.fail()) - log_error("socket failed"); - else - { - j->getRequest().doPostParse(); - - j->setWrite(); - keepAlive = processRequest(j->getRequest(), socket, - j->decrementKeepAliveCounter()); - - if (keepAlive) - { - j->setRead(); - j->clear(); - - // if there is something to do and no threads waiting, we take - // the next job just to improve resposiveness. - if (queue.getWaitThreadCount() == 0 - && !queue.empty()) - { - application.getPoller().addIdleJob(j); - keepAlive = false; - } - else - { - struct pollfd fd; - fd.fd = j->getFd(); - fd.events = POLLIN; - if (::poll(&fd, 1, Job::getSocketReadTimeout()) == 0) - { - application.getPoller().addIdleJob(j); - keepAlive = false; - } - } - } - } - } while (keepAlive); - } - catch (const cxxtools::net::Timeout& e) - { - log_debug("timeout - put job in poller"); - application.getPoller().addIdleJob(j); - } - catch (const cxxtools::net::Exception& e) - { - if (e.getErrno() != ENOENT) - log_warn("unexpected exception: " << e.what()); - } - catch (const std::exception& e) - { - log_warn("unexpected exception: " << e.what()); - } - } - - time(&lastWaitTime); - - log_debug("end worker-thread " << threadId); - - state = stateStopping; - } - - bool Worker::processRequest(HttpRequest& request, std::iostream& socket, - unsigned keepAliveCount) - { - // log message - log_info("process request: " << request.getMethod() << ' ' << request.getQuery() - << " from client " << request.getPeerIp() << " user-Agent \"" << request.getUserAgent() - << '"'); - - // create reply-object - HttpReply reply(socket); - reply.setVersion(request.getMajorVersion(), request.getMinorVersion()); - reply.setMethod(request.getMethod()); - - std::locale loc = request.getLocale(); - reply.out().imbue(loc); - reply.sout().imbue(loc); - - if (request.keepAlive()) - reply.setKeepAliveCounter(keepAliveCount); - - if (enableCompression) - reply.setAcceptEncoding(request.getEncoding()); - - // process request - try - { - try - { - dispatch(request, reply); - - if (!request.keepAlive() || !reply.keepAlive()) - keepAliveCount = 0; - - if (keepAliveCount > 0) - log_debug("keep alive"); - else - { - log_debug("no keep alive request/reply=" - << request.keepAlive() << '/' << reply.keepAlive()); - } - } - catch (const HttpError& e) - { - throw; - } - catch (const std::exception& e) - { - throw HttpError(HTTP_INTERNAL_SERVER_ERROR, e.what()); - } - } - catch (const HttpError& e) - { - state = stateSendError; - log_warn("http-Error: " << e.what()); - HttpReply reply(socket); - reply.setVersion(request.getMajorVersion(), request.getMinorVersion()); - if (request.keepAlive()) - reply.setKeepAliveCounter(keepAliveCount); - else - keepAliveCount = 0; - reply.out() << "<html><body><h1>Error</h1><p>" - << e.what() << "</p></body></html>" << std::endl; - reply.sendReply(e.getErrcode(), e.getErrmsg()); - } - - return keepAliveCount > 0; - } - - void Worker::dispatch(HttpRequest& request, HttpReply& reply) - { - state = stateDispatch; - const std::string& url = request.getUrl(); - - log_debug("dispatch " << request.getQuery()); - - if (!HttpRequest::checkUrl(url)) - throw HttpError(HTTP_BAD_REQUEST, "illegal url"); - - request.setThreadScope(threadScope); - - Dispatcher::PosType pos(application.getDispatcher(), request.getUrl()); - while (true) - { - state = stateDispatch; - - // pos.getNext() throws NotFoundException at end - Dispatcher::CompidentType ci = pos.getNext(); - try - { - log_debug("load component " << ci); - Component& comp = comploader.fetchComp(ci, application.getDispatcher()); - request.setPathInfo(ci.hasPathInfo() ? ci.getPathInfo() : url); - request.setArgs(ci.getArgs()); - - application.getScopemanager().preCall(request, ci.libname); - - log_debug("call component " << ci << " path " << request.getPathInfo()); - state = stateProcessingRequest; - unsigned http_return = comp(request, reply, request.getQueryParams()); - if (http_return != DECLINED) - { - if (reply.isDirectMode()) - { - log_info("request ready, returncode " << http_return); - state = stateFlush; - reply.out().flush(); - } - else - { - log_info("request ready, returncode " << http_return << " - ContentSize: " << reply.getContentSize()); - - application.getScopemanager().postCall(request, reply, ci.libname); - - state = stateSendReply; - reply.sendReply(http_return); - } - - if (reply.out()) - log_debug("reply sent"); - else - log_warn("stream error"); - - return; - } - else - log_debug("component " << ci << " returned DECLINED"); - } - catch (const cxxtools::dl::DlopenError& e) - { - log_warn("DlopenError catched - libname " << e.getLibname()); - } - catch (const cxxtools::dl::SymbolNotFound& e) - { - log_warn("SymbolNotFound catched - symbol " << e.getSymbol()); - } - } - - throw NotFoundException(request.getUrl()); - } - - void Worker::timer() - { - time_t currentTime; - time(¤tTime); - - cxxtools::MutexLock lock(mutex); - for (workers_type::iterator it = workers.begin(); - it != workers.end(); ++it) - { - (*it)->healthCheck(currentTime); - } - } - - void Worker::healthCheck(time_t currentTime) - { - if (state == stateProcessingRequest - && lastWaitTime != 0 - && maxRequestTime > 0) - { - if (static_cast<unsigned>(currentTime - lastWaitTime) > maxRequestTime) - { - log_fatal("requesttime " << maxRequestTime << " seconds in thread " - << threadId << " exceeded - exit process"); - log_info("current state: " << state); - exit(111); - } - } - } - - Worker::workers_type::size_type Worker::getCountThreads() - { - cxxtools::MutexLock lock(mutex); - return workers.size(); - } -} |