crossroads

Git mirror of https://crossroads.e-tunity.com/
git clone git://git.finwo.net/app/crossroads
Log | Files | Refs | LICENSE

commit 08e0eaba939f8e4c87f90f58506492bb0a5ad916
parent 85ade5f61924adf0296eac7eeb06405f6d28d6bd
Author: finwo <finwo@pm.me>
Date:   Sat,  3 Jan 2026 19:37:37 +0100

2.51

Diffstat:
MChangeLog | 5+++++
MMakefile | 4++--
Mdoc/xr.odt | 0
Mdoc/xr.pdf | 0
Atest/xr-client-ping | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mxr/Checkers/checkupthread/execute.cc | 34+++++++++++++++++++---------------
Mxr/Checkers/wakeupthread/execute.cc | 15++++++++++-----
Mxr/Dispatchers/httpdispatcher/dispatch.cc | 4++--
Mxr/Dispatchers/httpdispatcher/handle.cc | 11++++++-----
Mxr/Dispatchers/httpdispatcher/senderrorpage.cc | 2+-
Mxr/Dispatchers/tcpdispatcher/execute.cc | 1+
Mxr/Dispatchers/tcpdispatcher/handle.cc | 7++++---
Mxr/ThreadsAndMutexes/thread/run.cc | 3+++
Mxr/ThreadsAndMutexes/threadinfo/threadinfo | 8+++++++-
Axr/ThreadsAndMutexes/threadlist/clientip.cc | 5+++++
Mxr/ThreadsAndMutexes/threadlist/threadlist | 1+
Mxr/backend/check.cc | 7++++---
Mxr/backend/connect.cc | 2+-
Mxr/config/config | 34++++++++++++++++++++++++++++------
Mxr/config/config1.cc | 4+++-
Mxr/config/parsecmdline.cc | 23+++++++++++++++++++++--
Axr/etc/status-nosavebutton.xslt | 869+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Axr/etc/status-savebutton.xslt | 833+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Txr/etc/status.xslt | 0
Mxr/etc/usage.txt | 6++++--
Mxr/netbuffer/setstring.cc | 2+-
Axr/sys/maxtimeout.cc | 9+++++++++
Mxr/sys/sys | 1+
Mxr/webinterface/answer.cc | 44++++++++++++++++++++++++++++++++++----------
Mxr/webinterface/answerblob.cc | 2+-
Mxr/webinterface/answerstatus.cc | 7+++++--
Mxr/webinterface/execute.cc | 2+-
Mxr/webinterface/serve.cc | 2+-
Mxrctl/xrctl | 30+++++++++++++++++++++++++-----
34 files changed, 2017 insertions(+), 70 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,8 @@ +2.51 [KK 2009-04-15] +- Separate "write" timeouts introduced in flags -t and -T +- Web interface activity overview includes client ip addresses +- Added test/xr-client-ping (see docs) + 2.50 [KK 2009-03-30] - Bugfix in activation of the onfail script in the checkup thread. - Compilation flag -Werror only passed to the compiler when on the diff --git a/Makefile b/Makefile @@ -1,7 +1,7 @@ # Top-level Makefile for XR # ------------------------- -VER = 2.50 +VER = 2.51 PREFIX = $(DESTDIR)/usr BINDIR = $(PREFIX)/sbin MANDIR = $(PREFIX)/share/man @@ -102,4 +102,4 @@ commit: local clean test `svn status | grep '^\?' | wc -l` -eq 0 || \ (echo 'SVN not fully up to date: run "svn status"' && exit 1) perl -c xrctl/xrctl - svn commit + svn -m $(VER) commit diff --git a/doc/xr.odt b/doc/xr.odt Binary files differ. diff --git a/doc/xr.pdf b/doc/xr.pdf Binary files differ. diff --git a/test/xr-client-ping b/test/xr-client-ping @@ -0,0 +1,110 @@ +#!/usr/bin/perl + +use LWP::UserAgent; +use POSIX ':sys_wait_h'; +use strict; + +# Main +usage() if ($#ARGV != 1); +my $sleeptime = sprintf('%d', $ARGV[1]); +die("$0: bad interval $ARGV[1]\n") if ($sleeptime < 2); +$SIG{CHLD} = \&reaper; +while (1) { + do_test(); + my $slept = 0; + while ($slept < $sleeptime) { + $slept += sleep($sleeptime - $slept); + } +} + +# Show usage and croak +sub usage() { + die <<"ENDUSAGE"; + +Usage: xr-client-ping http://webinterface-address interval +The web interface is queried for clients. Connections to non-pingable clients +are killed. + +The interval specifies the delay between runs. Minimum is 2 (seconds). + +ENDUSAGE +} + +# Start a single test +my $_tries = 0; +sub do_test() { + my $ua = LWP::UserAgent->new(); + $ua->timeout(3); + + msg ("-----------------------------------------------------------------\n"); + msg ("Starting check run\n"); + my $res = $ua->get($ARGV[0]); + if (! $res->is_success()) { + msg ("Could not access web interface\n"); + die ("Too many tries now, giving up...\n") if ($_tries++ > 5); + return; + } + $_tries = 0; + + my $active = 0; + my ($id, $clientip); + for my $line (split(/\n/, $res->content())) { + $active = 1 if ($line =~ /<thread>/); + $active = 0 if ($line =~ /<\/thread>/); + + if ($active) { + if ($line =~ /<id>/) { + $id = $line; + $id =~ s/\s*<id>//; + $id =~ s/<\/id>.*//; + } elsif ($line =~ /<clientip>/) { + $clientip = $line; + $clientip =~ s/\s*<clientip>//; + $clientip =~ s/<\/clientip>//; + check_client($id, $clientip) if ($clientip ne '0.0.0.0'); + } + } + } +} + +# Check one thread ID and client IP +sub check_client($$) { + my ($id, $clientip) = @_; + + + msg ("Checking connection for client $clientip (XR thread $id)\n"); + return if (fork()); + + my $cmd = "ping -c2 -t1 $clientip >/dev/null"; + msg ("$clientip: pinging (external '$cmd')\n"); + $SIG{CHLD} = undef; + my $status = system($cmd); + msg ("$clientip: ping status '$status' $!\n"); + if ($status != 0) { + msg ("$clientip: not reachable, stopping XR thread $id\n"); + my $ua = LWP::UserAgent->new(); + my $res = $ua->get("$ARGV[0]/thread/kill/$id"); + if (! $res->is_success()) { + msg ("$clientip: failed to stop (", + $res->status_line(), ")\n"); + } + } else { + msg ("$clientip: reachable, connection assumed valid\n"); + } + exit(0); +} + +# Child reaper +sub reaper { + my $child; + + while ( ($child = waitpid(-1, WNOHANG)) > 0 ) { + # msg ("Checker $child stopped.\n"); + } + $SIG{CHLD} = \&reaper; +} + +# Verbose messaging +sub msg { + print ("$$ ", @_); +} diff --git a/xr/Checkers/checkupthread/execute.cc b/xr/Checkers/checkupthread/execute.cc @@ -9,22 +9,26 @@ void Checkupthread::execute() { msg ("Running checkup thread\n"); for (unsigned i = 0; i < balancer.nbackends(); i++) { Backend target(balancer.backend(i).backenddef()); - target.check(); - if (target.live()) { - balancer.backend(i).live(true); - msg ("Checkup call: backend " + target.description() + - " is alive\n"); - } else { - balancer.backend(i).live(false); - msg ("Checkup call: backend " + target.description() + - " is unavailable\n"); - if (config.onfail().length()) { - ostringstream o; - o << config.onfail() << " 0.0.0.0 " - << target.description() << ' ' - << balancer.backend(i).connections(); - sysrun(o.str()); + try { + target.check(); + if (target.live()) { + balancer.backend(i).live(true); + msg ("Checkup call: backend " + target.description() + + " is alive\n"); + } else { + balancer.backend(i).live(false); + msg ("Checkup call: backend " + target.description() + + " is unavailable\n"); + if (config.onfail().length()) { + ostringstream o; + o << config.onfail() << " 0.0.0.0 " + << target.description() << ' ' + << balancer.backend(i).connections(); + sysrun(o.str()); + } } + } catch (...) { + socketclose(target.sock()); } } sleep (config.checkupsec()); diff --git a/xr/Checkers/wakeupthread/execute.cc b/xr/Checkers/wakeupthread/execute.cc @@ -8,11 +8,16 @@ void Wakeupthread::execute() { for (unsigned i = 0; i < balancer.nbackends(); i++) { if (! balancer.backend(i).live()) { Backend target(balancer.backend(i).backenddef()); - target.check(); - if (target.live()) { - msg ("Wakeup call: backend " + target.description() + - " has awoken\n"); - balancer.backend(i).live(true); + try { + target.check(); + if (target.live()) { + msg ("Wakeup call: backend " + + target.description() + + " has awoken\n"); + balancer.backend(i).live(true); + } + } catch (...) { + socketclose(target.sock()); } } } diff --git a/xr/Dispatchers/httpdispatcher/dispatch.cc b/xr/Dispatchers/httpdispatcher/dispatch.cc @@ -13,7 +13,7 @@ void HttpDispatcher::dispatch() { // Get the client's request. May need for cookie inspection or for the // host header. while (!buf().headersreceived()) - if (!buf().netread(clientfd(), config.client_timeout())) + if (!buf().netread(clientfd(), config.client_read_timeout())) throw Error("Didn't receive a valid client request."); msg ("Received client request: '" + buf().firstline() + "'\n"); @@ -28,7 +28,7 @@ void HttpDispatcher::dispatch() { // Build new target list if host matching applies. if (hostmatchused) { host_header = buf().headerval ("Host"); - msg ("Will try to dispatch request host '" + + msg ("Will try to dispatch request for host '" + host_header + "'\n"); // We need to build tcpdispatcher's target list now! diff --git a/xr/Dispatchers/httpdispatcher/handle.cc b/xr/Dispatchers/httpdispatcher/handle.cc @@ -19,7 +19,7 @@ void HttpDispatcher::handle() { // Flush client info received so far to the back end. debugmsg("Sending client request to back end\n"); - buf().netwrite(backendfd(), config.backend_timeout()); + buf().netwrite(backendfd(), config.backend_write_timeout()); // Let's see if we will need to modify the server headers. bool modify_serverheaders = false; @@ -34,7 +34,8 @@ void HttpDispatcher::handle() { // their first appearance and modify them. bool backend_response_checked = false; while (1) { - Fdset readset (config.client_timeout()); + Fdset readset (maxtimeout(config.client_read_timeout(), + config.backend_read_timeout())); readset.add(clientfd()); readset.add(backendfd()); @@ -51,7 +52,7 @@ void HttpDispatcher::handle() { debugmsg("Back end response seen, applying modifications\n"); modify_serverheaders = false; while (! buf().headersreceived()) - if (!buf().netread (sock, config.backend_timeout())) + if (!buf().netread (sock, config.backend_read_timeout())) throw Error("Failed to get headers from back end"); if (config.addxrversion()) buf().setheader("XR", VER); @@ -78,14 +79,14 @@ void HttpDispatcher::handle() { int othersock, timeout; if (sock == clientfd()) { othersock = backendfd(); - timeout = config.backend_timeout(); + timeout = config.backend_read_timeout(); // Re-patch Host header if requested if (config.replacehostheader()) buf().replaceheader("Host:", balancer.backend(targetbackend()).server()); } else { othersock = clientfd(); - timeout = config.client_timeout(); + timeout = config.client_read_timeout(); } debugmsg (Mstr("Had data on ") + sock + diff --git a/xr/Dispatchers/httpdispatcher/senderrorpage.cc b/xr/Dispatchers/httpdispatcher/senderrorpage.cc @@ -23,7 +23,7 @@ void HttpDispatcher::senderrorpage(string const &reason) { "\r\n" << txt; Netbuffer buf(mess.str()); - buf.netwrite(clientfd(), config.client_timeout()); + buf.netwrite(clientfd(), config.client_write_timeout()); } catch (Error const &e) { // Silently discard, we are not interested in errors // that ocur when an error page is being sent diff --git a/xr/Dispatchers/tcpdispatcher/execute.cc b/xr/Dispatchers/tcpdispatcher/execute.cc @@ -2,6 +2,7 @@ void TcpDispatcher::execute() { Threadlist::clientfd(clientfd()); + Threadlist::clientip(clientip()); if (!check_dos() || !check_acl()) diff --git a/xr/Dispatchers/tcpdispatcher/handle.cc b/xr/Dispatchers/tcpdispatcher/handle.cc @@ -7,7 +7,8 @@ void TcpDispatcher::handle() { (Mstr(" and backend fd ") + backendfd()) + "\n"); while (1) { - Fdset readset (config.client_timeout()); + Fdset readset(maxtimeout(config.client_read_timeout(), + config.backend_read_timeout())); readset.add (clientfd()); readset.add (backendfd()); @@ -20,10 +21,10 @@ void TcpDispatcher::handle() { int othersock, timeout; if (sock == clientfd()) { othersock = backendfd(); - timeout = config.backend_timeout(); + timeout = config.backend_write_timeout(); } else { othersock = clientfd(); - timeout = config.client_timeout(); + timeout = config.client_write_timeout(); } debugmsg (Mstr("Had data on ") + sock + diff --git a/xr/ThreadsAndMutexes/thread/run.cc b/xr/ThreadsAndMutexes/thread/run.cc @@ -1,8 +1,10 @@ #include "thread" +#include "sys/sys" void *Thread::_run (void *data) { Thread *t = (Thread*) data; + debugmsg(Mstr("Thread: starting run\n")); Threadlist::enregister(); try { t->execute(); @@ -12,6 +14,7 @@ void *Thread::_run (void *data) { unlock(&cerr); } Threadlist::deregister(); + debugmsg(Mstr("Thread: ending run\n")); // Cleanups delete (t); diff --git a/xr/ThreadsAndMutexes/threadinfo/threadinfo b/xr/ThreadsAndMutexes/threadinfo/threadinfo @@ -9,7 +9,9 @@ class Threadinfo { public: Threadinfo(): th_desc(), th_tm(), th_backend(-1), th_backendfd(-1), th_clientfd(-1) - {} + { + memset(&th_clientip, 0, sizeof(th_clientip)); + } void desc(string s) { th_desc = s; } string const &desc() const { return th_desc; } @@ -25,10 +27,14 @@ public: void clientfd(int f) { th_clientfd = f; } int clientfd() const { return th_clientfd; } + void clientip(struct in_addr c) { th_clientip = c; } + struct in_addr clientip() const { return th_clientip; } + private: string th_desc; Timestamp th_tm; int th_backend, th_backendfd, th_clientfd; + struct in_addr th_clientip; }; #endif diff --git a/xr/ThreadsAndMutexes/threadlist/clientip.cc b/xr/ThreadsAndMutexes/threadlist/clientip.cc @@ -0,0 +1,5 @@ +#include "threadlist" + +void Threadlist::clientip(struct in_addr adr) { + th_map[pthread_self()].clientip(adr); +} diff --git a/xr/ThreadsAndMutexes/threadlist/threadlist b/xr/ThreadsAndMutexes/threadlist/threadlist @@ -17,6 +17,7 @@ public: static void backend(int b); static void clientfd(int f); static void backendfd(int f); + static void clientip(struct in_addr adr); private: static Threadmap th_map; diff --git a/xr/backend/check.cc b/xr/backend/check.cc @@ -13,6 +13,7 @@ void Backend::check() { if (backendcheck().server() == "" && backendcheck().port() == 0) { // Most common: TCP connect to the actual back end connect(); + socketclose(sock()); } else { // TCP connects to an alternative server or port. // We instantiate a dummy backend and let it connect to the "other" @@ -28,7 +29,6 @@ void Backend::check() { msg (Mstr("Alternative back end for testing ") + tester.description() + " is " + livestr() + "\n"); } - socketclose (sock()); break; case BackendCheck::c_get: @@ -48,10 +48,11 @@ void Backend::check() { "Connection: close\r\n" "\r\n"; httpbuffer.setstring (o.str()); - httpbuffer.netwrite(tester.sock(), config.backend_timeout()); + httpbuffer.netwrite(tester.sock(), config.backend_write_timeout()); httpbuffer.reset(); while (!httpbuffer.headersreceived()) - httpbuffer.netread(tester.sock(), config.backend_timeout()); + httpbuffer.netread(tester.sock(), + config.backend_read_timeout()); msg((Mstr("HTTP GET checker got answer: '") + httpbuffer.firstline()) + "'\n"); if (httpbuffer.stringat(9, 3) == "200") diff --git a/xr/backend/connect.cc b/xr/backend/connect.cc @@ -50,7 +50,7 @@ bool Backend::connect() { // Check on the outcome of the connect if (!conres || conerrno == EINPROGRESS) { // Wait for socket to go writable. - Fdset fdset (config.backend_timeout()); + Fdset fdset (config.backend_write_timeout()); fdset.add (clsocket); int rwsock = fdset.readwriteable(); int wsock = fdset.writeable(); diff --git a/xr/config/config b/xr/config/config @@ -35,11 +35,33 @@ public: int backends() const { return (blist.size()); } - unsigned client_timeout() const { return (c_timeout); } - void client_timeout (unsigned c) { c_timeout = c; } + /* Client timeouts */ + unsigned client_read_timeout() const { + return (c_timeout); + } + void client_read_timeout (unsigned c) { + c_timeout = c; + } + unsigned client_write_timeout() const { + return c_write_timeout; + } + void client_write_timeout(unsigned c) { + c_write_timeout = c; + } - unsigned backend_timeout() const { return (b_timeout); } - void backend_timeout (unsigned b) { b_timeout = b; } + /* Back end timeouts */ + unsigned backend_read_timeout() const { + return (b_timeout); + } + void backend_read_timeout (unsigned b) { + b_timeout = b; + } + unsigned backend_write_timeout() const { + return b_write_timeout; + } + void backend_write_timeout(unsigned b) { + b_write_timeout = b; + } unsigned wakeupsec() const { return (wakeup); } void wakeupsec (unsigned w) { wakeup = w; } @@ -172,8 +194,8 @@ private: static string sip; static vector<BackendDef> blist; static Dispatchmode dmode; - static unsigned c_timeout; - static unsigned b_timeout; + static unsigned c_timeout, c_write_timeout; + static unsigned b_timeout, b_write_timeout; static unsigned wakeup; static unsigned checkup; static unsigned bufsize; diff --git a/xr/config/config1.cc b/xr/config/config1.cc @@ -7,7 +7,9 @@ string Config::sip = "0"; vector<BackendDef> Config::blist; Dispatchmode Config::dmode; unsigned Config::c_timeout = 30; -unsigned Config::b_timeout = 30; +unsigned Config::b_timeout = 3; +unsigned Config::c_write_timeout = 30; +unsigned Config::b_write_timeout = 3; unsigned Config::wakeup = 5; unsigned Config::checkup = 0; unsigned Config::bufsize = 2048; diff --git a/xr/config/parsecmdline.cc b/xr/config/parsecmdline.cc @@ -68,6 +68,7 @@ void Config::parsecmdline (int ac, char **av) { bool tryout = false, wakeup_used = false; string current_hostmatch = ""; BackendCheck current_backendcheck; + vector<string> parts; # ifdef HAVE_GETOPT_LONG while ( (opt = getopt_long (ac, av, OPTSTRING, longopts, 0)) > 0) @@ -161,10 +162,28 @@ void Config::parsecmdline (int ac, char **av) { sticky_http = true; break; case 't': - b_timeout = setinteger (optarg); + parts = str2parts(optarg, ':'); + if (parts.size() == 1) { + backend_read_timeout(atoi(parts[0].c_str())); + backend_write_timeout(atoi(parts[0].c_str())); + } else if (parts.size() == 2) { + backend_read_timeout(atoi(parts[0].c_str())); + backend_write_timeout(atoi(parts[1].c_str())); + } else + throw Error("Bad backend timeout specifier, " + "expected SEC or RSEC:WSEC"); break; case 'T': - c_timeout = setinteger (optarg); + parts = str2parts(optarg, ':'); + if (parts.size() == 1) { + client_read_timeout(atoi(parts[0].c_str())); + client_write_timeout(atoi(parts[0].c_str())); + } else if (parts.size() == 2) { + client_read_timeout(atoi(parts[0].c_str())); + client_write_timeout(atoi(parts[1].c_str())); + } else + throw Error("Bad backend timeout specifier, " + "expected SEC or RSEC:WSEC"); break; case 'U': defer_time = (unsigned) setinteger(optarg); diff --git a/xr/etc/status-nosavebutton.xslt b/xr/etc/status-nosavebutton.xslt @@ -0,0 +1,869 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> +<xsl:output method="html" + encoding="UTF-8" + doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/> + +<xsl:template match="/"> + <html> + <head> + <title>XR Status Overview</title> + <style type="text/css"> + h1 { + font-family: Verdana,Helvetica; + font-size: 12pt; + color: blue; + } + body { + font-family: Verdana,Helvetica; + font-size: 8pt; + } + table { + border-collapse: collapse; + border-style: hidden; + } + td { + font-family: Verdana,Helvetica; + font-size: 8pt; + background-color: #ffff99; + border: 1px solid #f0f090; + } + input { + font-family: Verdana,Helvetica; + font-size: 8pt; + } + .header { background-color: #f3f399; } + .footer { color: gray; } + </style> + <script type="text/javascript"> + function goto(uri, input) { + if (input == '') + document.location = uri; + else { + var el = document.getElementById(input); + if (el) { + var value = el.value; + if (value != "") + document.location = uri + encodeURIComponent(value); + else + document.location = uri; + } + } + } + </script> + </head> + <body> + <h1>XR Status Overview</h1> + <hr/> + <xsl:apply-templates/> + </body> + </html> +</xsl:template> + +<xsl:template match="/status"> + <table> + <tr> + <td valign="top"> + <!-- This is the left hand detailed status view --> + <table> + <tr> + <td colspan="4"><b>Detailed Status</b></td> + </tr> + <tr> + <td colspan="4"><hr/></td> + </tr> + <xsl:apply-templates select="/status/server"/> + <xsl:apply-templates select="/status/backend"/> + + <tr> <td colspan="4"><hr/></td></tr> + <tr> + <td class="header" colspan="2"> + <b>Add back end ip:port</b> + </td> + <td class="header" colspan="2" align="right"> + <input type="text" size="30" name="addbackend" id="addbackend" + onchange="goto('/server/addbackend/', 'addbackend');"/> + </td> + </tr> + <tr> <td colspan="4"><hr/></td></tr> + + </table> + <xsl:apply-templates select="/status/id"/> + </td> + <td valign="top"> + <!-- This is the right-hand overview --> + <table width="100%"> + <tr> + <td colspan="2"><b>Quick Overview</b></td> + </tr> + <tr> + <td colspan="2"><hr/></td> + </tr> + <xsl:for-each select="/status/backend"> + <tr> + <td> + <b>Back end + <a href="#{nr}"><xsl:value-of select="address"/></a> + </b> + </td> + <td> + <xsl:value-of select="up"/>, + <xsl:value-of select="live"/>, + <xsl:value-of select="available"/>, + <xsl:value-of select="connections"/> connections + </td> + </tr> + </xsl:for-each> + </table> + <!-- This is the activity overview --> + <table width="100%"> + <tr> + <td colspan="5"><hr/></td> + </tr> + <tr> + <td colspan="5"><b>Activity</b></td> + </tr> + <tr> + <td colspan="5"><hr/></td> + </tr> + <tr> + <td colspan="3">Number of threads</td> + <td><xsl:value-of select="/status/activity/threadcount"/></td> + <td></td> + </tr> + <tr> + <td colspan="3">Used file descriptors (approx.)</td> + <td><xsl:value-of select="/status/activity/openfiles"/></td> + <td></td> + </tr> + <tr> + <td colspan="3">File descriptor limit</td> + <td><xsl:value-of select="/status/activity/maxopenfiles"/></td> + <td></td> + </tr> + <tr> + <td><b>Thread</b></td> + <td><b>Description</b></td> + <td><b>Back end</b></td> + <td><b>Duration</b></td> + <td></td> + </tr> + <xsl:apply-templates select="/status/activity/threadlist/thread"> + <xsl:sort select="duration" data-type="number"/> + </xsl:apply-templates> + </table> + </td> + </tr> + </table> +</xsl:template> + +<xsl:template match="/status/activity/threadlist/thread"> + <tr> + <td><xsl:value-of select="id"/></td> + <td> + <xsl:value-of select="description"/> + <xsl:if test="clientip != '0.0.0.0'"> + (client <xsl:value-of select="clientip"/>) + </xsl:if> + </td> + <xsl:choose> + <xsl:when test="backend = -1"> + <td></td> + </xsl:when> + <xsl:otherwise> + <td><xsl:value-of select="address"/></td> + </xsl:otherwise> + </xsl:choose> + <td><xsl:value-of select="duration"/></td> + <xsl:choose> + <xsl:when test="backend = -1"> + <td></td> + </xsl:when> + <xsl:otherwise> + <td><input type="button" value="Kill" + onclick="goto('/thread/kill/{id}', '');"/> + </td> + </xsl:otherwise> + </xsl:choose> + </tr> +</xsl:template> + +<xsl:template match="/status/id"> + <i> + Powered by Crossroads V<xsl:value-of select="version"/>. + Visit + <a href="{distsite}" + target="_blank"><xsl:value-of select="distsite"/></a> + for more info. + </i> +</xsl:template> + +<xsl:template match="/status/server"> + <tr> + <td class="header" colspan="3"> + <b>Server <xsl:value-of select="address"/> </b> + </td> + <td class="header"> + <input type="button" onclick="goto('/', '');" value="Refresh"/> + </td> + </tr> + <tr> + <td>Status</td> + <td colspan="3"> + <xsl:choose> + <xsl:when test="terminating = 0"> + Accepting connections, + <xsl:value-of select="connections"/> concurrent client(s), + </xsl:when> + <xsl:otherwise> + <font color="red"> + Terminating, still serving + <xsl:value-of select="connections"/> connections, + </font> + </xsl:otherwise> + </xsl:choose> + <xsl:value-of select="backends"/> defined back ends + </td> + </tr> + <tr> + <td>Dispatch mode</td> + <td colspan="3"> <xsl:value-of select="dispatchmode"/> </td> + </tr> + <tr> + <td>Type</td> + <td colspan="2"></td> + <td> + <xsl:choose> + <xsl:when test="type = 'http'"> + <select onchange="goto('/server/type/tcp', '');"> + <option value="tcp">tcp</option> + <option value="http" selected="1">http</option> + </select> + </xsl:when> + <xsl:otherwise> + <select onchange="goto('/server/type/http', '');"> + <option value="tcp" selected="1">tcp</option> + <option value="http">http</option> + </select> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <tr> + <td>Checks</td> + <td>Wakeup interval</td> + <td> + <xsl:choose> + <xsl:when test="checks/wakeupinterval = 0"> + off + </xsl:when> + <xsl:otherwise> + sec + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="wakeupinterval" + id="wakeupinterval" value="{checks/wakeupinterval}" + onchange="goto('/server/wakeupinterval/', 'wakeupinterval');"/> + </td> + </tr> + <tr> + <td></td> + <td>Checkup interval</td> + <td> + <xsl:choose> + <xsl:when test="checks/checkupinterval = 0"> + off + </xsl:when> + <xsl:otherwise> + sec + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="checkupinterval" + id="checkupinterval" value="{checks/checkupinterval}" + onchange="goto('/server/checkupinterval/', 'checkupinterval');"/> + </td> + </tr> + <tr> + <td>Timeouts</td> + <td>Client read</td> + <td> + <xsl:choose> + <xsl:when test="clientreadtimeout = 0"> + unlimited + </xsl:when> + <xsl:otherwise> + sec + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="clientreadtimeout" + id="clientreadtimeout" value="{clientreadtimeout}" + onchange="goto('/server/clientreadtimeout/', 'clientreadtimeout');"/> + </td> + </tr> + <tr> + <td></td> + <td>Client write</td> + <td> + <xsl:choose> + <xsl:when test="clientwritetimeout = 0"> + unlimited + </xsl:when> + <xsl:otherwise> + sec + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="clientwritetimeout" + id="clientwritetimeout" value="{clientwritetimeout}" + onchange="goto('/server/clientwritetimeout/', 'clientwritetimeout');"/> + </td> + </tr> + <tr> + <td></td> + <td>Back end read</td> + <td> + <xsl:choose> + <xsl:when test="backendreadtimeout = 0"> + unlimited + </xsl:when> + <xsl:otherwise> + sec + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="backendreadtimeout" + id="backendreadtimeout" value="{backendreadtimeout}" + onchange="goto('/server/backendreadtimeout/', 'backendreadtimeout');"/> + </td> + </tr> + <tr> + <td></td> + <td>Back end write</td> + <td> + <xsl:choose> + <xsl:when test="backendwritetimeout = 0"> + unlimited + </xsl:when> + <xsl:otherwise> + sec + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="backendwritetimeout" + id="backendwritetimeout" value="{backendwritetimeout}" + onchange="goto('/server/backendwritetimeout/', 'backendwritetimeout');"/> + </td> + </tr> + <tr> + <td></td> + <td>DNS cache validity</td> + <td> + <xsl:choose> + <xsl:when test="dnscachetimeout = 0"> + unused + </xsl:when> + <xsl:otherwise> + sec + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="dnscachetimeout" + id="dnscachetimeout" value="{dnscachetimeout}" + onchange="goto('/server/dnscachetimeout/', 'dnscachetimeout');"/> + </td> + </tr> + + <tr> + <td>Fast sockets closing</td> + <td colspan="2">eliminates TIME_WAIT state</td> + <td> + <xsl:choose> + <xsl:when test="closesocketsfast = 0"> + <select onchange="goto('/server/closesocketsfast/on', '');"> + <option value="yes">yes</option> + <option value="no" selected="1">no</option> + </select> + </xsl:when> + <xsl:otherwise> + <select onchange="goto('/server/closesocketsfast/off', '');"> + <option value="yes" selected="1">yes</option> + <option value="no">no</option> + </select> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <tr> + <td>Debugging</td> + <td colspan="2">Verbose logging</td> + <td> + <xsl:choose> + <xsl:when test="debugging/verbose = 0"> + <select onchange="goto('/server/verbose/on', '');"> + <option value="yes">yes</option> + <option value="no" selected="1">no</option> + </select> + </xsl:when> + <xsl:otherwise> + <select onchange="goto('/server/verbose/off', '');"> + <option value="yes" selected="1">yes</option> + <option value="no">no</option> + </select> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <tr> + <td></td> + <td colspan="2">Debug logging</td> + <td> + <xsl:choose> + <xsl:when test="debugging/debug = 0"> + <select onchange="goto('/server/debug/on', '');"> + <option value="yes">yes</option> + <option value="no" selected="1">no</option> + </select> + </xsl:when> + <xsl:otherwise> + <select onchange="goto('/server/debug/off', '');"> + <option value="yes" selected="1">yes</option> + <option value="no">no</option> + </select> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <tr> + <td></td> + <td>Traffic log directory</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="logtrafficdir" id="logtrafficdir" + value="{debugging/logtrafficdir}" + onchange="goto('/server/logtrafficdir/', 'logtrafficdir');"/> + </td> + </tr> + <tr> + <td>Activity scripts</td> + <td>Onstart command</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="onstart" id="onstart" + value="{onstart}" + onchange="goto('/server/onstart/', 'onstart');"/> + </td> + </tr> + <tr> + <td></td> + <td>Onend command</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="onend" id="onend" + value="{onend}" + onchange="goto('/server/onend/', 'onend');"/> + </td> + </tr> + <tr> + <td></td> + <td>Onfail command</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="onfail" id="onfail" + value="{onfail}" + onchange="goto('/server/onfail/', 'onfail');"/> + </td> + </tr> + <tr> + <td>Network buffer size</td> + <td colspan="2">bytes</td> + <td> + <input type="text" size="8" name="serverbufsz" id="serverbufsz" + value="{buffersize}" + onchange="goto('/server/buffersize/', 'serverbufsz');"/> + </td> + </tr> + <tr> + <td>DOS Protection</td> + <td>Max. connections </td> + <td> + <xsl:choose> + <xsl:when test="/dosprotection/maxconnections = 0"> + unlimited + </xsl:when> + <xsl:otherwise> + maximum value (0 for unlimited) + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="setservermaxcon" class="input" + id="setservermaxcon" value="{dosprotection/maxconnections}" + onchange="goto('/server/maxconnections/', 'setservermaxcon');"/> + </td> + </tr> + + <tr> + <td></td> + <td>Sample duration</td> + <td>sec</td> + <td> + <input type="text" size="8" name="timeinterval" class="input" + id="timeinterval" value="{dosprotection/timeinterval}" + onchange="goto('/server/timeinterval/', 'timeinterval');"/> + </td> + </tr> + <tr> + <td></td> + <td>Hard max connection rate</td> + <td> + <xsl:choose> + <xsl:when test="/dosprotection/hardmaxconnrate = 0"> + unlimited + </xsl:when> + <xsl:otherwise> + sessions per sample (0 for unlimited) + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="hardmaxconnrate" class="input" + id="hardmaxconnrate" value="{dosprotection/hardmaxconnrate}" + onchange="goto('/server/hardmaxconnrate/', 'hardmaxconnrate');"/> + </td> + </tr> + <tr> + <td></td> + <td>Soft max connection rate</td> + <td> + <xsl:choose> + <xsl:when test="/dosprotection/softmaxconnrate = 0"> + unlimited + </xsl:when> + <xsl:otherwise> + sessions per sample (0 for unlimited) + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="softmaxconnrate" class="input" + id="softmaxconnrate" value="{dosprotection/softmaxconnrate}" + onchange="goto('/server/softmaxconnrate/', 'softmaxconnrate');"/> + </td> + </tr> + <tr> + <td></td> + <td>Defer time</td> + <td>in microsec, 1.000.000 = 1 sec</td> + <td> + <input type="text" size="8" name="defertime" class="input" + id="defertime" value="{dosprotection/defertime}" + onchange="goto('/server/defertime/', 'defertime');"/> + </td> + </tr> + + <tr> + <td></td> + <td>Hard excess signal program</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="hardexcess" class="input" + id="hardexcess" value="{dosprotection/hardmaxconnexcess}" + onchange="goto('/server/hardmaxconnexcess/', 'hardexcess');"/> + </td> + </tr> + + <tr> + <td></td> + <td>Soft excess signal program</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="softexcess" class="input" + id="softexcess" value="{dosprotection/softmaxconnexcess}" + onchange="goto('/server/softmaxconnexcess/', 'softexcess');"/> + </td> + </tr> + + <tr> + <td>Access Control Lists</td> + <td>New allow-from</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="addallowfrom" class="input" + id="addallowfrom" + onchange="goto('/server/addallowfrom/', 'addallowfrom');"/> + </td> + </tr> + <xsl:apply-templates select="/status/server/acl/allow"/> + <tr> + <td></td> + <td>New deny-from</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="adddenyfrom" class="input" + id="adddenyfrom" + onchange="goto('/server/adddenyfrom/', 'adddenyfrom');"/> + </td> + </tr> + <xsl:apply-templates select="/status/server/acl/deny"/> + + <xsl:if test="/status/server/type = 'http'"> + <xsl:apply-templates select="/status/server/http"/> + </xsl:if> +</xsl:template> + +<xsl:template match="/status/backend"> + <tr> <td colspan="4"><hr/></td></tr> + <tr> + <td class="header" colspan="3"> + <a name="{nr}"/> + <b> Back end <xsl:value-of select="address"/> </b> + </td> + <td class="header"> + <input type="button" value="Delete" + onclick="goto('/server/deletebackend/{nr}', '');"/> + </td> + </tr> + <tr> + <td><b>State</b></td> + <td>Health</td> + <td colspan="2"> + <xsl:value-of select="live"/>, + <xsl:value-of select="available"/> + </td> + </tr> + <tr> + <td></td> + <td>Connections</td> + <td colspan="2"> + <xsl:value-of select="connections"/> + <xsl:if test="anticipated &gt; 0"> + (anticipating <xsl:value-of select="anticipated"/>) + </xsl:if> + </td> + </tr> + <tr> + <td></td> + <td>Served</td> + <td colspan="2"> + <xsl:value-of select="bytesserved"/> bytes, + <xsl:value-of select="clientsserved"/> clients + </td> + </tr> + <tr> + <td><b>Options</b></td> + <td colspan="2">Weight</td> + <td> + <input type="text" size="8" name="setbackendweight{nr}" + id="setbackendweight{nr}" value="{weight}" + onchange="goto('/backend/{nr}/weight/', 'setbackendweight{nr}');"/> + </td> + </tr> + <tr> + <td></td> + <td>Max. connections</td> + <td> + <xsl:choose> + <xsl:when test="maxconnections = 0"> + unlimited + </xsl:when> + <xsl:otherwise> + maximum value (0 for unlimited) + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="setbackendmaxcon{nr}" class="input" + id="setbackendmaxcon{nr}" value="{maxconnections}" + onchange="goto('/backend/{nr}/maxconnections/', 'setbackendmaxcon{nr}');"/> + </td> + </tr> + <tr> + <td></td> + <td colspan="2">Load average</td> + <td> + <input type="text" size="8" name="setloadaverage{nr}" + id="setloadaverage{nr}" value="{loadavg}" + onchange="goto('/backend/{nr}/loadavg/', 'setloadaverage{nr}');"/> + </td> + </tr> + <tr> + <td></td> + <td colspan="2">Backend check (. to reset)</td> + <td> + <input type="text" size="8" name="backendcheck{nr}" + id="backendcheck{nr}" value="{backendcheck}" + onchange="goto('/backend/{nr}/backendcheck/', 'backendcheck{nr}');"/> + </td> + </tr> + <xsl:if test="/status/server/type = 'http'"> + <tr> + <td></td> + <td>Host match</td> + <td> + <xsl:choose> + <xsl:when test="hostmatch = '.'"> + any host request + </xsl:when> + <xsl:otherwise> + (. for any host) + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="sethostmatch{nr}" + id="sethostmatch{nr}" value="{hostmatch}" + onchange="goto('/backend/{nr}/hostmatch/', 'sethostmatch{nr}');"/> + </td> + </tr> + </xsl:if> + <tr> + <td></td> + <td colspan="2">Up state</td> + <td> + <xsl:choose> + <xsl:when test="up = 'up'"> + <select onchange="goto('/backend/{nr}/up/off', '');"> + <option value="yes" selected="1">yes</option> + <option value="no">no</option> + </select> + </xsl:when> + <xsl:otherwise> + <select onchange="goto('/backend/{nr}/up/on', '');"> + <option value="yes">yes</option> + <option value="no" selected="1">no</option> + </select> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <tr> + <td></td> + <td colspan="2">Stop all connections</td> + <td> + <input type="button" value="Stop now" + onclick="goto('/backend/{nr}/stopconnections', '');"/> + </td> + </tr> +</xsl:template> + +<xsl:template match="/status/server/http"> + <tr> + <td>HTTP Goodies</td> + <td colspan="2">Add X-Forwarded-For</td> + <td> + <xsl:choose> + <xsl:when test="addxforwardedfor = 0"> + <select onchange="goto('/server/addxforwardedfor/on', '');"> + <option value="yes">yes</option> + <option value="no" selected="1">no</option> + </select> + </xsl:when> + <xsl:otherwise> + <select onchange="goto('/server/addxforwardedfor/off', '');"> + <option value="yes" selected="1">yes</option> + <option value="no">no</option> + </select> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <tr> + <td></td> + <td colspan="2">Sticky HTTP</td> + <td> + <xsl:choose> + <xsl:when test="stickyhttp = 0"> + <select onchange="goto('/server/stickyhttp/on', '');"> + <option value="yes">yes</option> + <option value="no" selected="1">no</option> + </select> + </xsl:when> + <xsl:otherwise> + <select onchange="goto('/server/stickyhttp/off', '');"> + <option value="yes" selected="1">yes</option> + <option value="no">no</option> + </select> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <tr> + <td></td> + <td colspan="2">Replace Host: headers</td> + <td> + <xsl:choose> + <xsl:when test="replacehostheader = 0"> + <select onchange="goto('/server/replacehostheader/on', '');"> + <option value="yes">yes</option> + <option value="no" selected="1">no</option> + </select> + </xsl:when> + <xsl:otherwise> + <select onchange="goto('/server/replacehostheader/off', '');"> + <option value="yes" selected="1">yes</option> + <option value="no">no</option> + </select> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <xsl:apply-templates select="/status/server/http/serverheaders"/> +</xsl:template> + +<xsl:template match="/status/server/acl/allow"> + <xsl:for-each select="allowfrom"> + <tr> + <td></td> + <td>Allow from</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="allowfrom{nr}" + id="allowfrom{nr}" value="{mask}" + onchange="goto('/server/allowfrom/{nr}/', 'allowfrom{nr}');"/> + </td> + </tr> + </xsl:for-each> +</xsl:template> + +<xsl:template match="/status/server/acl/deny"> + <xsl:for-each select="denyfrom"> + <tr> + <td></td> + <td>Deny from</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="denyfrom{nr}" + id="denyfrom{nr}" value="{mask}" + onchange="goto('/server/denyfrom/{nr}/', 'denyfrom{nr}');"/> + </td> + </tr> + </xsl:for-each> +</xsl:template> + +<xsl:template match="/status/server/http/serverheaders"> + <xsl:for-each select="serverheader"> + <tr> + <td></td> + <td>Server header</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="serverheader{nr}" + id="serverheader{nr}" value="{header}" + onchange="goto('/server/changeheader/{nr}/', 'serverheader{nr}');"/> + </td> + </tr> + </xsl:for-each> + <tr> + <td></td> + <td>New server header</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="newserverheader" + id="newserverheader" + onchange="goto('/server/newheader/', 'newserverheader');"/> + </td> + </tr> +</xsl:template> + +<xsl:template match="*"/> + +</xsl:stylesheet> diff --git a/xr/etc/status-savebutton.xslt b/xr/etc/status-savebutton.xslt @@ -0,0 +1,833 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> +<xsl:output method="html" + encoding="UTF-8" + doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/> + +<xsl:template match="/"> + <html> + <head> + <title>XR Status Overview</title> + <style type="text/css"> + h1 { + font-family: Verdana,Helvetica; + font-size: 12pt; + color: blue; + } + body { + font-family: Verdana,Helvetica; + font-size: 8pt; + } + table { + border-collapse: collapse; + border-style: hidden; + } + td { + font-family: Verdana,Helvetica; + font-size: 8pt; + background-color: #ffff99; + border: 1px solid #f0f090; + } + input { + font-family: Verdana,Helvetica; + font-size: 8pt; + } + .header { background-color: #f3f399; } + .footer { color: gray; } + </style> + <script type="text/javascript"> + function goto(uri, input) { + if (input == '') + document.location = uri; + else { + var el = document.getElementById(input); + if (el) { + var value = el.value; + if (value != "") + document.location = uri + encodeURIComponent(value); + else + document.location = uri; + } + } + function save(uri, name) { + var elem = getElementById(name); + var val = name.value; + alert('name: ' + name + ', value: ' + val); + } + } + </script> + </head> + <body> + <h1>XR Status Overview</h1> + <hr/> + <xsl:apply-templates/> + </body> + </html> +</xsl:template> + +<xsl:template match="/status"> + <table> + <tr> + <td valign="top"> + <!-- This is the left hand detailed status view --> + <table> + <tr> + <td colspan="4"><b>Detailed Status</b></td> + </tr> + <tr> + <td colspan="4"><hr/></td> + </tr> + <xsl:apply-templates select="/status/server"/> + <xsl:apply-templates select="/status/backend"/> + + <tr> <td colspan="4"><hr/></td></tr> + <tr> + <td class="header" colspan="2"> + <b>Add back end ip:port</b> + </td> + <td class="header" colspan="2" align="right"> + <input type="text" size="30" name="addbackend" id="addbackend" + onchange="goto('/server/addbackend/', 'addbackend');"/> + </td> + </tr> + <tr> <td colspan="4"><hr/></td></tr> + + </table> + <xsl:apply-templates select="/status/id"/> + </td> + <td valign="top"> + <!-- This is the right-hand overview --> + <table width="100%"> + <tr> + <td colspan="2"><b>Quick Overview</b></td> + </tr> + <tr> + <td colspan="2"><hr/></td> + </tr> + <xsl:for-each select="/status/backend"> + <tr> + <td> + <b>Back end + <a href="#{nr}"><xsl:value-of select="address"/></a> + </b> + </td> + <td> + <xsl:value-of select="up"/>, + <xsl:value-of select="live"/>, + <xsl:value-of select="available"/>, + <xsl:value-of select="connections"/> connections + </td> + </tr> + </xsl:for-each> + </table> + <!-- This is the activity overview --> + <table width="100%"> + <tr> + <td colspan="5"><hr/></td> + </tr> + <tr> + <td colspan="5"><b>Activity</b></td> + </tr> + <tr> + <td colspan="5"><hr/></td> + </tr> + <tr> + <td colspan="3">Number of threads</td> + <td><xsl:value-of select="/status/activity/threadcount"/></td> + <td></td> + </tr> + <tr> + <td colspan="3">Used file descriptors (approx.)</td> + <td><xsl:value-of select="/status/activity/openfiles"/></td> + <td></td> + </tr> + <tr> + <td colspan="3">File descriptor limit</td> + <td><xsl:value-of select="/status/activity/maxopenfiles"/></td> + <td></td> + </tr> + <tr> + <td><b>Thread</b></td> + <td><b>Description</b></td> + <td><b>Back end</b></td> + <td><b>Duration</b></td> + <td></td> + </tr> + <xsl:apply-templates select="/status/activity/threadlist/thread"> + <xsl:sort select="duration" data-type="number"/> + </xsl:apply-templates> + </table> + </td> + </tr> + </table> +</xsl:template> + +<xsl:template match="/status/activity/threadlist/thread"> + <tr> + <td><xsl:value-of select="id"/></td> + <td><xsl:value-of select="description"/></td> + <xsl:choose> + <xsl:when test="backend = -1"> + <td></td> + </xsl:when> + <xsl:otherwise> + <td><xsl:value-of select="address"/></td> + </xsl:otherwise> + </xsl:choose> + <td><xsl:value-of select="duration"/></td> + <xsl:choose> + <xsl:when test="backend = -1"> + <td></td> + </xsl:when> + <xsl:otherwise> + <td><input type="button" value="Kill" + onclick="goto('/thread/kill/{id}', '');"/> + </td> + </xsl:otherwise> + </xsl:choose> + </tr> +</xsl:template> + +<xsl:template match="/status/id"> + <i> + Powered by Crossroads V<xsl:value-of select="version"/>. + Visit + <a href="{distsite}" + target="_blank"><xsl:value-of select="distsite"/></a> + for more info. + </i> +</xsl:template> + +<xsl:template match="/status/server"> + <tr> + <td class="header" colspan="3"> + <b>Server <xsl:value-of select="address"/> </b> + </td> + <td class="header"> + <input type="button" onclick="goto('/', '');" value="Refresh"/> + </td> + </tr> + <tr> + <td>Status</td> + <td colspan="3"> + <xsl:choose> + <xsl:when test="terminating = 0"> + Accepting connections, + <xsl:value-of select="connections"/> concurrent client(s), + </xsl:when> + <xsl:otherwise> + <font color="red"> + Terminating, still serving + <xsl:value-of select="connections"/> connections, + </font> + </xsl:otherwise> + </xsl:choose> + <xsl:value-of select="backends"/> defined back ends + </td> + </tr> + <tr> + <td>Dispatch mode</td> + <td colspan="3"> <xsl:value-of select="dispatchmode"/> </td> + </tr> + <tr> + <td>Type</td> + <td colspan="2"></td> + <td align="right"> + <xsl:choose> + <xsl:when test="type = 'http'"> + <select name="servertype" id="servertype"> + <option value="tcp">tcp</option> + <option value="http" selected="1">http</option> + </select> + </xsl:when> + <xsl:otherwise> + <select name="servertype" id="servertype"> + <option value="tcp" selected="1">tcp</option> + <option value="http">http</option> + </select> + </xsl:otherwise> + </xsl:choose> + <input type="button" value="Save" + onclick="save('/server/type', 'servertype');"/> + </td> + </tr> + <tr> + <td>Checks</td> + <td>Wakeup interval</td> + <td> + <xsl:choose> + <xsl:when test="checks/wakeupinterval = 0"> + off + </xsl:when> + <xsl:otherwise> + sec + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="wakeupinterval" + id="wakeupinterval" value="{checks/wakeupinterval}" + onchange="goto('/server/wakeupinterval/', 'wakeupinterval');"/> + </td> + </tr> + <tr> + <td></td> + <td>Checkup interval</td> + <td> + <xsl:choose> + <xsl:when test="checks/checkupinterval = 0"> + off + </xsl:when> + <xsl:otherwise> + sec + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="checkupinterval" + id="checkupinterval" value="{checks/checkupinterval}" + onchange="goto('/server/checkupinterval/', 'checkupinterval');"/> + </td> + </tr> + <tr> + <td>Timeouts</td> + <td>Client read/write</td> + <td> + <xsl:choose> + <xsl:when test="clienttimeout = 0"> + unlimited + </xsl:when> + <xsl:otherwise> + sec + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="clienttimeout" + id="clienttimeout" value="{clienttimeout}" + onchange="goto('/server/clienttimeout/', 'clienttimeout');"/> + </td> + </tr> + <tr> + <td></td> + <td>Backend read/write/connect</td> + <td> + <xsl:choose> + <xsl:when test="backendtimeout = 0"> + unlimited + </xsl:when> + <xsl:otherwise> + sec + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="backendtimeout" + id="backendtimeout" value="{backendtimeout}" + onchange="goto('/server/backendtimeout/', 'backendtimeout');"/> + </td> + </tr> + <tr> + <td></td> + <td>DNS cache validity</td> + <td> + <xsl:choose> + <xsl:when test="dnscachetimeout = 0"> + unused + </xsl:when> + <xsl:otherwise> + sec + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="dnscachetimeout" + id="dnscachetimeout" value="{dnscachetimeout}" + onchange="goto('/server/dnscachetimeout/', 'dnscachetimeout');"/> + </td> + </tr> + + <tr> + <td>Fast sockets closing</td> + <td colspan="2">eliminates TIME_WAIT state</td> + <td> + <xsl:choose> + <xsl:when test="closesocketsfast = 0"> + <select onchange="goto('/server/closesocketsfast/on', '');"> + <option value="yes">yes</option> + <option value="no" selected="1">no</option> + </select> + </xsl:when> + <xsl:otherwise> + <select onchange="goto('/server/closesocketsfast/off', '');"> + <option value="yes" selected="1">yes</option> + <option value="no">no</option> + </select> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <tr> + <td>Debugging</td> + <td colspan="2">Verbose logging</td> + <td> + <xsl:choose> + <xsl:when test="debugging/verbose = 0"> + <select onchange="goto('/server/verbose/on', '');"> + <option value="yes">yes</option> + <option value="no" selected="1">no</option> + </select> + </xsl:when> + <xsl:otherwise> + <select onchange="goto('/server/verbose/off', '');"> + <option value="yes" selected="1">yes</option> + <option value="no">no</option> + </select> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <tr> + <td></td> + <td colspan="2">Debug logging</td> + <td> + <xsl:choose> + <xsl:when test="debugging/debug = 0"> + <select onchange="goto('/server/debug/on', '');"> + <option value="yes">yes</option> + <option value="no" selected="1">no</option> + </select> + </xsl:when> + <xsl:otherwise> + <select onchange="goto('/server/debug/off', '');"> + <option value="yes" selected="1">yes</option> + <option value="no">no</option> + </select> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <tr> + <td></td> + <td>Traffic log directory</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="logtrafficdir" id="logtrafficdir" + value="{debugging/logtrafficdir}" + onchange="goto('/server/logtrafficdir/', 'logtrafficdir');"/> + </td> + </tr> + <tr> + <td>Activity scripts</td> + <td>Onstart command</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="onstart" id="onstart" + value="{onstart}" + onchange="goto('/server/onstart/', 'onstart');"/> + </td> + </tr> + <tr> + <td></td> + <td>Onend command</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="onend" id="onend" + value="{onend}" + onchange="goto('/server/onend/', 'onend');"/> + </td> + </tr> + <tr> + <td></td> + <td>Onfail command</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="onfail" id="onfail" + value="{onfail}" + onchange="goto('/server/onfail/', 'onfail');"/> + </td> + </tr> + <tr> + <td>Network buffer size</td> + <td colspan="2">bytes</td> + <td> + <input type="text" size="8" name="serverbufsz" id="serverbufsz" + value="{buffersize}" + onchange="goto('/server/buffersize/', 'serverbufsz');"/> + </td> + </tr> + <tr> + <td>DOS Protection</td> + <td>Max. connections </td> + <td> + <xsl:choose> + <xsl:when test="/dosprotection/maxconnections = 0"> + unlimited + </xsl:when> + <xsl:otherwise> + maximum value (0 for unlimited) + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="setservermaxcon" class="input" + id="setservermaxcon" value="{dosprotection/maxconnections}" + onchange="goto('/server/maxconnections/', 'setservermaxcon');"/> + </td> + </tr> + + <tr> + <td></td> + <td>Sample duration</td> + <td>sec</td> + <td> + <input type="text" size="8" name="timeinterval" class="input" + id="timeinterval" value="{dosprotection/timeinterval}" + onchange="goto('/server/timeinterval/', 'timeinterval');"/> + </td> + </tr> + <tr> + <td></td> + <td>Hard max connection rate</td> + <td> + <xsl:choose> + <xsl:when test="/dosprotection/hardmaxconnrate = 0"> + unlimited + </xsl:when> + <xsl:otherwise> + sessions per sample (0 for unlimited) + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="hardmaxconnrate" class="input" + id="hardmaxconnrate" value="{dosprotection/hardmaxconnrate}" + onchange="goto('/server/hardmaxconnrate/', 'hardmaxconnrate');"/> + </td> + </tr> + <tr> + <td></td> + <td>Soft max connection rate</td> + <td> + <xsl:choose> + <xsl:when test="/dosprotection/softmaxconnrate = 0"> + unlimited + </xsl:when> + <xsl:otherwise> + sessions per sample (0 for unlimited) + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="softmaxconnrate" class="input" + id="softmaxconnrate" value="{dosprotection/softmaxconnrate}" + onchange="goto('/server/softmaxconnrate/', 'softmaxconnrate');"/> + </td> + </tr> + <tr> + <td></td> + <td>Defer time</td> + <td>in microsec, 1.000.000 = 1 sec</td> + <td> + <input type="text" size="8" name="defertime" class="input" + id="defertime" value="{dosprotection/defertime}" + onchange="goto('/server/defertime/', 'defertime');"/> + </td> + </tr> + + <tr> + <td></td> + <td>Hard excess signal program</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="hardexcess" class="input" + id="hardexcess" value="{dosprotection/hardmaxconnexcess}" + onchange="goto('/server/hardmaxconnexcess/', 'hardexcess');"/> + </td> + </tr> + + <tr> + <td></td> + <td>Soft excess signal program</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="softexcess" class="input" + id="softexcess" value="{dosprotection/softmaxconnexcess}" + onchange="goto('/server/softmaxconnexcess/', 'softexcess');"/> + </td> + </tr> + + <tr> + <td>Access Control Lists</td> + <td>New allow-from</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="addallowfrom" class="input" + id="addallowfrom" + onchange="goto('/server/addallowfrom/', 'addallowfrom');"/> + </td> + </tr> + <xsl:apply-templates select="/status/server/acl/allow"/> + <tr> + <td></td> + <td>New deny-from</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="adddenyfrom" class="input" + id="adddenyfrom" + onchange="goto('/server/adddenyfrom/', 'adddenyfrom');"/> + </td> + </tr> + <xsl:apply-templates select="/status/server/acl/deny"/> + + <xsl:if test="/status/server/type = 'http'"> + <xsl:apply-templates select="/status/server/http"/> + </xsl:if> +</xsl:template> + +<xsl:template match="/status/backend"> + <tr> <td colspan="4"><hr/></td></tr> + <tr> + <td class="header" colspan="3"> + <a name="{nr}"/> + <b> Back end <xsl:value-of select="address"/> </b> + </td> + <td class="header"> + <input type="button" value="Delete" + onclick="goto('/server/deletebackend/{nr}', '');"/> + </td> + </tr> + <tr> + <td><b>State</b></td> + <td>Health</td> + <td colspan="2"> + <xsl:value-of select="live"/>, + <xsl:value-of select="available"/> + </td> + </tr> + <tr> + <td></td> + <td>Connections</td> + <td colspan="2"> + <xsl:value-of select="connections"/> + <xsl:if test="anticipated &gt; 0"> + (anticipating <xsl:value-of select="anticipated"/>) + </xsl:if> + </td> + </tr> + <tr> + <td></td> + <td>Served</td> + <td colspan="2"> + <xsl:value-of select="bytesserved"/> bytes, + <xsl:value-of select="clientsserved"/> clients + </td> + </tr> + <tr> + <td><b>Options</b></td> + <td colspan="2">Weight</td> + <td> + <input type="text" size="8" name="setbackendweight{nr}" + id="setbackendweight{nr}" value="{weight}" + onchange="goto('/backend/{nr}/weight/', 'setbackendweight{nr}');"/> + </td> + </tr> + <tr> + <td></td> + <td>Max. connections</td> + <td> + <xsl:choose> + <xsl:when test="maxconnections = 0"> + unlimited + </xsl:when> + <xsl:otherwise> + maximum value (0 for unlimited) + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="setbackendmaxcon{nr}" class="input" + id="setbackendmaxcon{nr}" value="{maxconnections}" + onchange="goto('/backend/{nr}/maxconnections/', 'setbackendmaxcon{nr}');"/> + </td> + </tr> + <tr> + <td></td> + <td colspan="2">Load average</td> + <td> + <input type="text" size="8" name="setloadaverage{nr}" + id="setloadaverage{nr}" value="{loadavg}" + onchange="goto('/backend/{nr}/loadavg/', 'setloadaverage{nr}');"/> + </td> + </tr> + <tr> + <td></td> + <td colspan="2">Backend check (. to reset)</td> + <td> + <input type="text" size="8" name="backendcheck{nr}" + id="backendcheck{nr}" value="{backendcheck}" + onchange="goto('/backend/{nr}/backendcheck/', 'backendcheck{nr}');"/> + </td> + </tr> + <xsl:if test="/status/server/type = 'http'"> + <tr> + <td></td> + <td>Host match</td> + <td> + <xsl:choose> + <xsl:when test="hostmatch = '.'"> + any host request + </xsl:when> + <xsl:otherwise> + (. for any host) + </xsl:otherwise> + </xsl:choose> + </td> + <td> + <input type="text" size="8" name="sethostmatch{nr}" + id="sethostmatch{nr}" value="{hostmatch}" + onchange="goto('/backend/{nr}/hostmatch/', 'sethostmatch{nr}');"/> + </td> + </tr> + </xsl:if> + <tr> + <td></td> + <td colspan="2">Up state</td> + <td> + <xsl:choose> + <xsl:when test="up = 'up'"> + <select onchange="goto('/backend/{nr}/up/off', '');"> + <option value="yes" selected="1">yes</option> + <option value="no">no</option> + </select> + </xsl:when> + <xsl:otherwise> + <select onchange="goto('/backend/{nr}/up/on', '');"> + <option value="yes">yes</option> + <option value="no" selected="1">no</option> + </select> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <tr> + <td></td> + <td colspan="2">Stop all connections</td> + <td> + <input type="button" value="Stop now" + onclick="goto('/backend/{nr}/stopconnections', '');"/> + </td> + </tr> +</xsl:template> + +<xsl:template match="/status/server/http"> + <tr> + <td>HTTP Goodies</td> + <td colspan="2">Add X-Forwarded-For</td> + <td> + <xsl:choose> + <xsl:when test="addxforwardedfor = 0"> + <select onchange="goto('/server/addxforwardedfor/on', '');"> + <option value="yes">yes</option> + <option value="no" selected="1">no</option> + </select> + </xsl:when> + <xsl:otherwise> + <select onchange="goto('/server/addxforwardedfor/off', '');"> + <option value="yes" selected="1">yes</option> + <option value="no">no</option> + </select> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <tr> + <td></td> + <td colspan="2">Sticky HTTP</td> + <td> + <xsl:choose> + <xsl:when test="stickyhttp = 0"> + <select onchange="goto('/server/stickyhttp/on', '');"> + <option value="yes">yes</option> + <option value="no" selected="1">no</option> + </select> + </xsl:when> + <xsl:otherwise> + <select onchange="goto('/server/stickyhttp/off', '');"> + <option value="yes" selected="1">yes</option> + <option value="no">no</option> + </select> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <tr> + <td></td> + <td colspan="2">Replace Host: headers</td> + <td> + <xsl:choose> + <xsl:when test="replacehostheader = 0"> + <select onchange="goto('/server/replacehostheader/on', '');"> + <option value="yes">yes</option> + <option value="no" selected="1">no</option> + </select> + </xsl:when> + <xsl:otherwise> + <select onchange="goto('/server/replacehostheader/off', '');"> + <option value="yes" selected="1">yes</option> + <option value="no">no</option> + </select> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <xsl:apply-templates select="/status/server/http/serverheaders"/> +</xsl:template> + +<xsl:template match="/status/server/acl/allow"> + <xsl:for-each select="allowfrom"> + <tr> + <td></td> + <td>Allow from</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="allowfrom{nr}" + id="allowfrom{nr}" value="{mask}" + onchange="goto('/server/allowfrom/{nr}/', 'allowfrom{nr}');"/> + </td> + </tr> + </xsl:for-each> +</xsl:template> + +<xsl:template match="/status/server/acl/deny"> + <xsl:for-each select="denyfrom"> + <tr> + <td></td> + <td>Deny from</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="denyfrom{nr}" + id="denyfrom{nr}" value="{mask}" + onchange="goto('/server/denyfrom/{nr}/', 'denyfrom{nr}');"/> + </td> + </tr> + </xsl:for-each> +</xsl:template> + +<xsl:template match="/status/server/http/serverheaders"> + <xsl:for-each select="serverheader"> + <tr> + <td></td> + <td>Server header</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="serverheader{nr}" + id="serverheader{nr}" value="{header}" + onchange="goto('/server/changeheader/{nr}/', 'serverheader{nr}');"/> + </td> + </tr> + </xsl:for-each> + <tr> + <td></td> + <td>New server header</td> + <td colspan="2" align="right"> + <input type="text" size="30" name="newserverheader" + id="newserverheader" + onchange="goto('/server/newheader/', 'newserverheader');"/> + </td> + </tr> +</xsl:template> + +<xsl:template match="*"/> + +</xsl:stylesheet> diff --git a/xr/etc/status.xslt b/xr/etc/status.xslt diff --git a/xr/etc/usage.txt b/xr/etc/usage.txt @@ -124,10 +124,12 @@ may not exist on your platform): Default: tcp:0:10000 (TCP balancing, on all interfaces, via port 10000). -t SEC, --backend-timeout SEC Defines network timeouts for back ends, default 3 sec. Use 0 to - prevent timing out. + prevent timing out. SEC is the timeout for reads and writes. + Use -t RSEC:WSEC to specify separate timeouts for reads and writes. -T SEC, --client-timeout SEC Defines network timeouts for clients, default 30 sec. Use 0 to - prevent timing out. + prevent timing out. Use -T RSEC:WSEC to specify separate + timeouts for reads and writes. -u USEC, --defer-time USEC If a connection is going to be deferred due to hitting the "soft" rate (see --soft-maxconnrate), then this option sets how long the deferral diff --git a/xr/netbuffer/setstring.cc b/xr/netbuffer/setstring.cc @@ -1,7 +1,7 @@ #include "netbuffer" void Netbuffer::setstring(string const &s) { - debugmsg(Mstr("Netbuffer: setting to ") + s + "\n"); + debugmsg(Mstr("Netbuffer: setting to string\n")); destroy(); check_space(s.size() + 1); diff --git a/xr/sys/maxtimeout.cc b/xr/sys/maxtimeout.cc @@ -0,0 +1,9 @@ +#include "sys" + +int maxtimeout(int a, int b) { + if (!a) + return b; + if (!b) + return a; + return a < b ? a : b; +} diff --git a/xr/sys/sys b/xr/sys/sys @@ -92,6 +92,7 @@ void mt_srand(unsigned long s); unsigned long mt_rand(void); bool check_acl(string const &ipstr, struct in_addr ipaddr); int sysrun (string const &s); +int maxtimeout(int a, int b); #ifndef HAVE_INET_ATON int inet_aton (char const *name, struct in_addr *addr); diff --git a/xr/webinterface/answer.cc b/xr/webinterface/answer.cc @@ -227,26 +227,50 @@ void Webinterface::answer(Httpbuffer req) { return; } - // /server/clienttimeout - // /server/clienttimeout/NUMBER + // /server/clientreadtimeout + // /server/clientreadtimeout/NUMBER if (parts.size() == 3 && - parts[0] == "server" && parts[1] == "clienttimeout") { + parts[0] == "server" && parts[1] == "clientreadtimeout") { unsigned num = 0; if (parts[2] != "") - num = str2uns (parts[2], "client timeout"); - config.client_timeout(num); + num = str2uns (parts[2], "client read timeout"); + config.client_read_timeout(num); answer_status(); return; } - // /server/backendtimeout - // /server/backendtimeout/NUMBER + // /server/clientwritetimeout + // /server/clientwritetimeout/NUMBER if (parts.size() == 3 && - parts[0] == "server" && parts[1] == "backendtimeout") { + parts[0] == "server" && parts[1] == "clientwritetimeout") { unsigned num = 0; if (parts[2] != "") - num = str2uns (parts[2], "back end timeout"); - config.backend_timeout(num); + num = str2uns (parts[2], "client write timeout"); + config.client_write_timeout(num); + answer_status(); + return; + } + + // /server/backendreadtimeout + // /server/backendreadtimeout/NUMBER + if (parts.size() == 3 && + parts[0] == "server" && parts[1] == "backendreadtimeout") { + unsigned num = 0; + if (parts[2] != "") + num = str2uns (parts[2], "back end read timeout"); + config.backend_read_timeout(num); + answer_status(); + return; + } + + // /server/backendwritetimeout + // /server/backendwritetimeout/NUMBER + if (parts.size() == 3 && + parts[0] == "server" && parts[1] == "backendwritetimeout") { + unsigned num = 0; + if (parts[2] != "") + num = str2uns (parts[2], "back end write timeout"); + config.backend_write_timeout(num); answer_status(); return; } diff --git a/xr/webinterface/answerblob.cc b/xr/webinterface/answerblob.cc @@ -11,5 +11,5 @@ void Webinterface::answer_blob (string const &blob) { "\r\n" + blob; Netbuffer buf(resp); - buf.netwrite(cfd, config.client_timeout()); + buf.netwrite(cfd, config.client_write_timeout()); } diff --git a/xr/webinterface/answerstatus.cc b/xr/webinterface/answerstatus.cc @@ -18,8 +18,10 @@ void Webinterface::answer_status() { " <server>\n" " <address>" << config.sipaddr() << ":" << config.sport() << "</address>\n" " <type>" << config.stypestr() << "</type>\n" - " <clienttimeout>" << config.client_timeout() << "</clienttimeout>\n" - " <backendtimeout>" << config.backend_timeout() << "</backendtimeout>\n" + " <clientreadtimeout>" << config.client_read_timeout() << "</clientreadtimeout>\n" + " <clientwritetimeout>" << config.client_write_timeout() << "</clientwritetimeout>\n" + " <backendreadtimeout>" << config.backend_read_timeout() << "</backendreadtimeout>\n" + " <backendwritetimeout>" << config.backend_write_timeout() << "</backendwritetimeout>\n" " <dispatchmode>" << config.dispatchmodestr() << "</dispatchmode>\n" " <webinterface>" << config.webinterfaceip() << ':' << config.webinterfaceport() << "</webinterface>\n" " <dnscachetimeout>" << config.dnscachetimeout() << "</dnscachetimeout>\n" @@ -134,6 +136,7 @@ void Webinterface::answer_status() { o << "</address>\n" " <duration>" << thread_info.timestamp().elapsed() << "</duration>\n" + " <clientip>" << inet_ntoa(thread_info.clientip()) << "</clientip>\n" " </thread>\n"; } /* The estimate of the number of used fd's is: diff --git a/xr/webinterface/execute.cc b/xr/webinterface/execute.cc @@ -53,7 +53,7 @@ void Webinterface::execute() { "\r\n" << m.str(); Netbuffer buf(o.str()); - buf.netwrite(cfd, config.client_timeout()); + buf.netwrite(cfd, config.client_write_timeout()); socketclose(cfd); } } diff --git a/xr/webinterface/serve.cc b/xr/webinterface/serve.cc @@ -4,7 +4,7 @@ void Webinterface::serve () { msg ((Mstr("Webinterface serving request on client fd ") + cfd) + "\n"); Httpbuffer clientrequest; - clientrequest.netread(cfd, config.client_timeout()); + clientrequest.netread(cfd, config.client_read_timeout()); msg ("Webinterface request: " + clientrequest.firstline() + "\n"); answer(clientrequest); diff --git a/xrctl/xrctl b/xrctl/xrctl @@ -15,8 +15,12 @@ my $default_logger = 'logger'; # Default settings, must match xr's defaults my $default_dispatchmode = 'least-connections'; my $default_maxconnections = 0; -my $default_clienttimeout = 30; -my $default_backendtimeout = 30; +my $default_client_timeout = 30; +my $default_client_read_timeout = 30; +my $default_client_write_timeout = 30; +my $default_backend_timeout = 30; +my $default_backend_read_timeout = 3; +my $default_backend_write_timeout = 3; my $default_buffersize = 2048; my $default_wakeupinterval = 5; my $default_checkupinterval = 0; @@ -455,9 +459,9 @@ sub xr_cmdarr { flag($ss, '--max-connections', 'maxconnections', $default_maxconnections), flag($ss, '--client-timeout', 'clienttimeout', - $default_clienttimeout), + $default_client_timeout), flag($ss, '--backend-timeout', 'backendtimeout', - $default_backendtimeout), + $default_backend_timeout), flag($ss, '--buffer-size', 'buffersize', $default_buffersize), flag($ss, '--wakeup-interval', 'wakeupinterval', @@ -484,7 +488,23 @@ sub xr_cmdarr { flag($ss, '--log-traffic-dir', 'logtrafficdir', '')); for my $k (sort (keys (%boolflags))) { push (@cmd, $boolflags{$k}) if (istrue($ss->data($k))); - } + } + + # Timeouts when specified using separate tags + my $t = $ss->data('clientreadtimeout'); + if (defined($t)) { + my $fl = "--client-timeout $t"; + $t = $ss->data('clientwritetimeout'); + $fl .= ":$t" if (defined($t)); + push (@cmd, $fl); + } + $t = $ss->data('backendreadtimeout'); + if (defined($t)) { + my $fl = "--backend-timeout $t"; + $t = $ss->data('backendwritetimeout'); + $fl .= ":$t" if (defined($t)); + push (@cmd, $fl); + } # ACL's for (my $i = 0; ; $i++) {