[-]
[+]
|
Changed |
crossroads.spec
|
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/ChangeLog
^
|
@@ -1,3 +1,98 @@
+2.55 [KK 2009-05-13]
+- Implemented connection error counting of back ends.
+- Select-handling revised: atomic readability and writeability checks,
+ see xr/fdset/wait.cc and wait_r(), wait_w(), wait_rw().
+- Checks for connect() success can be configured to verify only
+ writeable status of a socket (see xr/backend/connect.cc, macro
+ CONNECTCHECK_ONLY_WRITABLE in xr/etc/Makefile.class).
+- Added test/xr-mysql-connect.
+- Added commands kill and killstart to xrctl. Action restart renamed
+ to stopstart.
+- Added simple benchmarking under test/: xr-http-test (based on an
+ older script) and xr-smtp-test. Plus a simple analyzer of the
+ reported timings, xr-analyze-test.
+- Revamped stored-ip dispatcher, added IPStore class to keep track of clients.
+
+2.54 [KK 2009-04-29]
+- Stamped new STABLE version.
+
+2.53 [KK 2009-04-24]
+- test/xr-client-ping now can live without LWP::UserAgent. When this
+ Perl module is not present, the script will fall back to wget/curl.
+- Upon thread kill, sockets are closed using socketclose()
+ (sys/socketclose.cc), which also shutdown()s the socket.
+- Bugfix in xrctl regarding new format of client/backend timeout.
+
+2.52 [KK 2009-04-21]
+- Bugfix in the roundrobin dispatcher. When only one back end would be
+ up, then the roundrobin dispatcher would incorrectly compute the
+ right back end. This bug only became visible with host-matching in
+ HTTP mode.
+
+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
+ development system Thera.local (see xr/etc/Makefile.class).
+- Onstart, onend and onfail scripts (when present) are invoked with a
+ third argument, the number of connections at the time
+- Set-Cookie header directive (see the HTTP dispatcher) attaches an
+ explicit path "/".
+- Rewired the tcp dispatcher and http dispatcher to use a common
+ buffer inside the tcp dispatcher (instead of 2 separate ones).
+
+2.49 [KK 2009-03-27]
+- Implemented onfail hook (to complement onstart/onend, flag -y).
+
+2.48 [KK 2009-03-26]
+- Implemented onstart/onend hooks (flags -z, -Z).
+- Sticky HTTP mode inspects the URI (parameter XRTarget) when no
+ sticky cookie is present.
+
+2.47 [KK 2009-03-04]
+- Stored-ip dispatching was enhanced to "anticipate" reconnects from
+ previously seen clients. The number of anticipated connections is taken
+ into account when dispatching a new client.
+- Bugfix in command line parsing of dispatch mode lax-stored-ip (would
+ be recognized as strict).
+
+2.46 [KK 2009-02-18]
+- Dispatcher-related classes moved under directory xr/Dispatchers/.
+- UDP balancer implementation started (code stubs in place).
+- xrctl bugfixed: a backend-scope maxconnections statement would
+ confuse the global server block. Thanks Rajeev for reporting.
+
+2.45 [KK 2009-02-18]
+- Usage information formatted.
+- Rubberstamped "stable"!
+
+2.44 [KK 2009-02-11]
+- Reviewed code for "throw"s (edited for consistency).
+- Bug in Webinterface::execute() (during accept()). Thanks Vladimir T.
+ for reporting and testing.
+
+2.43 [KK 2009-02-09]
+- Added Httpbuffer::replaceheader() methods
+- Added flag -I (to replace Host: headers), integrated in xrctl /
+ webinterface
+- Webinterface reports approx. # of open fd's and the limit (in activity)
+
+2.42 [KK 2009-01-28]
+- Bugfix in "xrctl generateconfig". The activity info introduced
+ before (which the web interface now emites), confused xrctl.
+- Bugfix in sys/ipmatch.cc: mask matching corrected for systems where
+ longs are not 4 bytes (64bit systems).
+- Bugfix in hashed-ip dispatch mode: When no back ends were available,
+ the dispatcher would crash (fixed).
+- XSLT stylesheet that transforms web interface slightly changed to
+ improve the looks.
+- Bugfix in xrctl's "rotate" action. Thanks "ncisrael" for reporting
+ it in the forum.
+
2.41 [KK 2009-01-05]
- Bugfix in xrctl, thanks Eddie for reporting it.
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/Makefile
^
|
@@ -1,7 +1,7 @@
# Top-level Makefile for XR
# -------------------------
-VER = 2.41
+VER = 2.55
PREFIX = $(DESTDIR)/usr
BINDIR = $(PREFIX)/sbin
MANDIR = $(PREFIX)/share/man
@@ -16,6 +16,7 @@
@echo 'Choose:'
@echo ' make local - local program construction'
@echo ' make localprof - local, with profiling info'
+ @echo ' make localmem - local, with memory debugging'
@echo ' make install - installation to $(BINDIR)'
@echo ' make uninstall - removes installed programs'
@echo ' make clean - removal after local/install'
@@ -28,12 +29,15 @@
xr/etc/gettools /usr/local/bin xr/etc c-conf e-ver
xr/etc/e-ver ChangeLog $(VER)
BASE=$(BASE) AUTHOR='$(AUTHOR)' MAINTAINER='$(MAINTAINER)' \
- DISTSITE='$(DISTSITE)' \
+ DISTSITE='$(DISTSITE)' MEMDEBUG=$(MEMDEBUG)\
VER='$(VER)' PROF=$(PROF) PROFILER=$(PROFILER) $(MAKE) -C xr
localprof:
PROF=-pg PROFILER=-DPROFILER make local
+localmem:
+ MEMDEBUG=-DMEMDEBUG make local
+
install: local $(BINDIR)/xrctl install-manpages
mkdir -p $(BINDIR)
BASE=$(BASE) AUTHOR='$(AUTHOR)' MAINTAINER='$(MAINTAINER)' \
@@ -98,4 +102,4 @@
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
|
|
Changed |
crossroads-devel.tar.gz/doc/xr.odt
^
|
|
Changed |
crossroads-devel.tar.gz/doc/xr.pdf
^
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/doc/xrctl.1
^
|
@@ -19,8 +19,10 @@
list [SERVICE] - show configuration of a service, or of all
start [SERVICE] - start a service, or all configured services
stop [SERVICE] - stop a service, or all configured services
+kill [SERVICE] - brutal stop, interrupts connections
force [SERVICE] - start a service (or all) if not running
-restart [SERVICE] - stop and start a service, or all
+stopstart [SERVICE] - stop and start a service, or all
+killstart [SERVICE] - kill and start a service, or all
status [SERVICE] - show running status of a service, or of all
rotate [SERVICE] - rotate logs of a service or of all
generateconfig [SERVICE] - queries running XR's for the configuration
@@ -35,4 +37,5 @@
http://crossroads.e-tunity.com
.P
-This man page was written by Frederik Dannemare <frederik@dannemare.net>.
+This man page was written by Frederik Dannemare
+<frederik@dannemare.net> and updated by Karel Kubat <karel@kubat.nl>.
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/doc/xrctl.xml.5
^
|
@@ -23,28 +23,28 @@
<system>
<!-- Path where the "xr" binary is searched, and zippers as "gzip"
and "bzip2", and the "ps" command. Default is that xrctl
- uses $PATH. -->
+ uses $PATH. -->
<path>/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/opt/local/bin:/opt/local/sbin</path>
<!-- "ps" command that shows the PID and command. On Solaris, use
/usr/bin/ps -ef "pid comm" and on Linux/MacOSX use
- /bin/ps -ax -o pid,command. Default is that xrctl guesses
- the right command. Example:
- <pscmd>/bin/ps ax -o pid,command</pscmd> -->
+ /bin/ps -ax -o pid,command. Default is that xrctl guesses
+ the right command. Example:
+ <pscmd>/bin/ps ax -o pid,command</pscmd> -->
<!-- Use "logger" to add output to syslog or not? Logger will be
used if the binary can be found, and if uselogger is true. -->
<uselogger>true</uselogger>
<!-- The default logger is the program "logger". Redefine here if
- you like, for example to a piping logrotate program. Example:
- <logger>clpipe /var/log/xr.clog</logger>
- The default <logger> command is: logger -t xr.{service} -->
+ you like, for example to a piping logrotate program. Example:
+ <logger>clpipe /var/log/xr.clog</logger>
+ The default <logger> command is: logger -t xr.{service} -->
<!-- If logger is NOT used, xrctl will manage log output. In that
- case, specify the following:
- - Where do logs get written?
- <logdir>/var/log</logdir>
- - How big may the logs become? Manipulated during "xrctl rotate".
- <maxlogsize>100000</maxlogsize>
- - How many history logs to keep?
- <loghistory>10</loghistory> -->
+ case, specify the following:
+ - Where do logs get written?
+ <logdir>/var/log</logdir>
+ - How big may the logs become? Manipulated during "xrctl rotate".
+ <maxlogsize>100000</maxlogsize>
+ - How many history logs to keep?
+ <loghistory>10</loghistory> -->
</system>
<!-- Service descriptions: This section defines all balancing
@@ -59,14 +59,19 @@
<name>ssh</name>
<server>
<!-- Type (tcp/http, here: tcp), and IP-address/port to bind
- to. Use "0" for IP-address to bind to all interfaces. The
- web interface will listen to localhost, port 20.001. -->
+ to. Use "0" for IP-address to bind to all interfaces. The
+ web interface will listen to localhost, port 20.001. -->
<type>tcp</type>
<address>0:20000</address>
<webinterface>0:20001</webinterface>
<!-- Clients may be idle for 30 minutes, then they are logged
- out. -->
- <clienttimeout>1800</clienttimeout>
+ out. But they must accept data from XR within 3 seconds,
+ the latter is the write timeout: -->
+ <clienttimeout>1800:3</clienttimeout>
+
+ <!-- DNS entries are by default cached for 3600 sec (1 hour).
+ Change if you like, for example to half an hour: -->
+ <dnscachetimeout>1800</dnscachetimeout>
</server>
<!-- Back ends for the service. -->
@@ -91,7 +96,7 @@
<server>
<!-- Server binding. XR will listen to any IP interface, on port
20.010. It'll be an HTTP balancer. The web interface will
- be on port 20.011. -->
+ be on port 20.011 and bound only to the local host address. -->
<address>0:20010</address>
<type>http</type>
<webinterface>127.0.0.1:20011</webinterface>
@@ -118,6 +123,24 @@
closing connections are in TIME_WAIT state, use: -->
<closesocketsfast>yes</closesocketsfast>
+ <!-- XR can run specific scripts when client activity starts or
+ ends. When given, the scripts are run with the arguments:
+ the client IP, and the back end (server:port), and the
+ number of connections to that back end. A very simple script
+ /where/ever/activitystart might e.g. do:
+ echo Client $1 going to back end $2, $3 connections so far \
+ >> /tmp/activity.log
+ A very simple script /where/ever/activityend might e.g. do:
+ echo Client $1 is done with back end $2 >> /tmp/activity.log
+ - onstart: is run when a client is about to be handled at a
+ back end
+ - onend: is run after succesful termination
+ - onfail: is run after unsuccesful termination
+ -->
+ <onstart>/where/ever/activitystart</onstart>
+ <onend>/where/ever/activityend</onend>
+ <onfail>/where/ever/activityaborted</onfail>
+
<!-- Access restrictions: we allow from two IP ranges, and deny
from one IP address. The overall results:will be:
- Access will be allowed from 10.*.*.*
@@ -136,22 +159,21 @@
softmaxconnrate (here: 150), then each connection is
delayed for defertime microsecs (here: 1.000.000, one
sec).
- Finally, the entire balancer will be allowed to serve up
- to 400 simultaneous connections.
- -->
+ Finally, the entire balancer will be allowed to serve up
+ to 400 simultaneous connections. -->
<timeinterval>2</timeinterval>
<hardmaxconnrate>200</hardmaxconnrate>
<softmaxconnrate>150</softmaxconnrate>
<defertime>1000000</defertime>
<maxconnections>400</maxconnections>
- <!-- Let's add some more protection. When a user exceeds their
- hard maxconn rate, "/path/to/program" will be invoked
- with the IP as argument. That program may eg. call
- iptables to block the client. There is also a tag
- softmaxconnexcess (not shown here). -->
- <hardmaxconnexcess>/path/to/program</hardmaxconnexcess>
-
+ <!-- Let's add some more protection. When a user exceeds their
+ hard maxconn rate, "/path/to/program" will be invoked
+ with the IP as argument. That program may eg. call
+ iptables to block the client. There is also a tag
+ softmaxconnexcess (not shown here). -->
+ <hardmaxconnexcess>/path/to/program</hardmaxconnexcess>
+
</dosprotection>
<http>
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/test/onend
^
|
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+echo Client $1 was handled by $2 and is now stopping, $3 connections remain \
+ >> /tmp/activity.log
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/test/onfail
^
|
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+echo Back end $2 with $3 connections failed for client $1 \
+ >> /tmp/activity.log
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/test/onstart
^
|
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+echo Client $1 will be handled by $2, $3 connections so far \
+ >> /tmp/activity.log
+
+
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/test/restricted-webinterface.xml
^
|
@@ -0,0 +1,50 @@
+<!-- This is an example of an XR configuration that limits the access
+ to the web interface to one address. -->
+
+<?xml version="1.0" encoding="UTF-8">
+
+<configuration>
+ <system>
+ <uselogger>false</uselogger>
+ <logdir>/tmp</logdir>
+ </system>
+
+ <service>
+ <!-- This is the main service that XR is responsible for.
+ The local web interface runs on port 11.001 but is accessible
+ only from localhost (127.0.0.1). The sample service runs on
+ port 11.000 and is accessible from wherever you like. -->
+ <name>web</name>
+ <server>
+ <type>tcp</type>
+ <address>0:11000</address>
+ <webinterface>127.0.0.1:11001</webinterface>
+ <verbose>yes</verbose>
+ </server>
+
+ <backend>
+ <address>server1:8000</address>
+ </backend>
+ </service>
+
+ <service>
+ <!-- Here's a forwarder that runs on port 11.002 and only accepts
+ traffic from IP address 10.50.45.189. The calls are
+ dispatched to localhost:11.001, so that this way, the web
+ interface is only accessible via:
+ a. port 11.001 from localhost, or
+ b. port 11.002 from 10.50.45.189 -->
+ <name>webinterface</name>
+ <server>
+ <type>tcp</type>
+ <address>0:11002</address>
+ <acl>
+ <allowfrom>10.50.45.189</allowfrom>
+ </acl>
+ </server>
+ <backend>
+ <address>localhost:11001</address>
+ </backend>
+ </service>
+
+</configuration>
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/test/sampleconf.xml
^
|
@@ -143,10 +143,12 @@
no header for the XR version,
a header X-Forwarded-For: client-ip
no sticky http sessions
+ modification of the Host: header to the back end server name
two serverheaders to insert -->
<addxrversion>off</addxrversion>
<addxforwardedfor>on</addxforwardedfor>
<stickyhttp>off</stickyhttp>
+ <replacehostheader>on</replacehostheader>
<serverheaders>
<header>MyFirstHeader: Whatever</header>
<header>MySecondHeader: WhateverElse</header>
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/test/xr-analyze-test
^
|
@@ -0,0 +1,15 @@
+#!/usr/bin/perl
+
+use strict;
+
+my $n = 0;
+my $tot = 0;
+while (my $line = <STDIN>) {
+ next unless ($line =~ /^\d/);
+ $tot += $line;
+ $n++;
+}
+exit(1) unless ($n);
+
+print ("Total : $n\n",
+ "Average : ", $tot / $n, "\n");
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/test/xr-client-ping
^
|
@@ -0,0 +1,150 @@
+#!/usr/bin/perl
+
+use POSIX ':sys_wait_h';
+use strict;
+
+# Main
+my $quiet = 0;
+while($ARGV[0] eq '-q') {
+ $quiet++;
+ shift(@ARGV);
+}
+
+usage() if ($#ARGV != 1);
+my $sleeptime = sprintf('%d', $ARGV[1]);
+die("$0: bad interval $ARGV[1]\n") if ($sleeptime < 2);
+while (1) {
+ # Clean up any zombies
+ while (waitpid(-1, WNOHANG) > 0) { }
+
+ # Run the test
+ do_test();
+
+ # Sleep for the duration of the interval
+ my $slept = 0;
+ while ($slept < $sleeptime) {
+ $slept += sleep($sleeptime - $slept);
+ }
+}
+
+# Show usage and croak
+sub usage() {
+ die <<"ENDUSAGE";
+
+Usage: xr-client-ping [-q] WEBINTERFACE-URL INTERVAL
+The web interface is queried for clients. Connections to non-pingable clients
+are killed. The process is repeated each interval.
+
+The arguments:
+ -q: quiet mode, suppresses verbose messaging
+ WEBINTERFACE-URL: the URL of XR's web interface, include http://
+ INTERVAL: number of seconds
+
+ENDUSAGE
+}
+
+# Start a single test
+my $_tries = 0;
+sub do_test() {
+ msg ("-----------------------------------------------------------------\n");
+ msg ("Starting check run\n");
+ my $xml;
+ eval {
+ $xml = http_get($ARGV[0]);
+ };
+ if ($@) {
+ 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/, $xml)) {
+ $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 -c3 -t3 $clientip >/dev/null";
+ msg ("$clientip: pinging (external '$cmd')\n");
+ my $status = system($cmd);
+ if ($status != 0) {
+ msg ("$clientip: ping status '$status' $!\n");
+ msg ("$clientip: not reachable, stopping XR thread $id\n");
+ eval {
+ http_get("$ARGV[0]/thread/kill/$id");
+ };
+ msg ("Failed to stop thread $id\n") if ($@);
+ } else {
+ msg ("$clientip: reachable, connection assumed valid\n");
+ }
+ exit(0);
+}
+
+# Do a HTTP GET. Try LWP::UserAgent if available, else try wget.
+sub http_get($) {
+ my $url = shift;
+ my $ua;
+
+ # Try LWP::UserAgent
+ eval {
+ require LWP::UserAgent;
+ };
+ if (! $@) {
+ $ua = LWP::UserAgent->new();
+ $ua->timeout(3);
+ my $res = $ua->get($url);
+ die ("Could not access url '$url'\n")
+ unless ($res->is_success());
+ return $res->content();
+ }
+
+ # Try wget or curl, or any other command (can be put in here)
+ for my $cmd ("wget -q -O- -T3 '$url'",
+ "curl --connect-timeout 3 -s '$url'") {
+ msg ("Running: $cmd\n");
+ open (my $if, "$cmd |");
+ if ($if) {
+ my $cont = '';
+ while (my $line = <$if>) {
+ $cont .= $line;
+ }
+ if (close($if)) {
+ return $cont;
+ } else {
+ msg("$cmd failed: $!\n");
+ }
+ }
+ }
+
+ # All failed, now what?
+ die ("No method to access url '$url'\n");
+}
+
+# Verbose messaging
+sub msg {
+ print ($$, ' ', scalar(localtime()), ' ', @_) unless ($quiet);
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/test/xr-http-test
^
|
@@ -0,0 +1,36 @@
+#!/usr/bin/perl
+
+use strict;
+use LWP::UserAgent;
+use Time::HiRes qw(sleep gettimeofday tv_interval);
+
+$|++;
+
+die <<"ENDUSAGE" if ($#ARGV != 2);
+
+Usage: $0 URL THREADS DURATION
+Will start THREADS to get URL. The entire test will run for DURATION
+seconds.
+
+ENDUSAGE
+
+my ($url, $threads, $duration) = @ARGV;
+for my $i (1..$threads) {
+ next if (fork());
+
+ my $t_start = [gettimeofday()];
+ my $runs = 0;
+ while (tv_interval($t_start) < $duration) {
+ $runs++;
+ my $t_run = [gettimeofday()];
+ my $ua = LWP::UserAgent->new();
+ $ua->timeout(5);
+ my $resp = $ua->get($url);
+ print(tv_interval($t_run), "\n")
+ if ($resp->is_success());
+ }
+ exit(0);
+}
+
+while(wait() != -1) {
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/test/xr-mysql-connect
^
|
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+# Where does your mysql live?
+mysql=/usr/local/mysql/bin/mysql
+
+# Get the host and port from the argument (which is the back end,
+# as host:port)
+host=`echo $1 | sed 's/:.*//'`
+port=`echo $1 | sed 's/.*://'`
+
+# Try to connect to the host and port. Print the result on stdout.
+echo quit | $mysql -h $host -P $port --protocol=tcp --connect-timeout=3
+echo $?
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/test/xr-smtp-test
^
|
@@ -0,0 +1,43 @@
+#!/usr/bin/perl
+
+use strict;
+use Net::SMTP;
+use Time::HiRes qw(sleep gettimeofday tv_interval);
+
+$|++;
+
+die <<"ENDUSAGE" if ($#ARGV != 4);
+
+Usage: $0 ENDPOINT FROM-ADDRESS TO-ADDRESS THREADS DURATION
+Will start THREADS to send dummy e-mails to TO-ADDRESS. The test will run
+for DURATION seconds. ENDPOINT is the IP address to connect to.
+
+ENDUSAGE
+
+my ($endpoint, $from, $address, $threads, $duration) = @ARGV;
+for my $i (1..$threads) {
+ next if (fork());
+
+ my $t_start = [gettimeofday()];
+ my $runs = 0;
+ while (tv_interval($t_start) < $duration) {
+ $runs++;
+ my $t_run = [gettimeofday()];
+ my $smtp = Net::SMTP->new($endpoint, Timeout => 5)
+ or die ("Cannot start SMTP\n");
+ $smtp->mail($from);
+ $smtp->to($address);
+ $smtp->data();
+ $smtp->datasend("To: $address\n");
+ $smtp->datasend("Subject: Testing mail\n");
+ $smtp->datasend("\n");
+ $smtp->datasend("This is just a test message.\n");
+ $smtp->dataend();
+ $smtp->quit();
+ print(tv_interval($t_run), "\n");
+ }
+ exit(0);
+}
+
+while(wait() != -1) {
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/test/xr-stdby
^
|
+(directory)
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/test/xr-stdby/xr-is-live
^
|
@@ -0,0 +1,42 @@
+#!/usr/bin/perl
+
+use strict;
+
+die <<"ENDUSAGE" if ($#ARGV < 0);
+
+Usage: xr-is-live HOST [HOST...]
+
+Polls stated host(s) for live status. Exits with the number of unreachable
+hosts.
+
+Sample usage:
+ xr-is-live onehost - checks if the one host is down
+ xr-is-live h1 h2 h3 h3 h5 - checks if this network is down (this can be
+ assumed when exit status is larger than 3)
+
+ENDUSAGE
+
+for my $h (@ARGV) {
+ next if fork();
+ if (!testlive($h)) {
+ print ("$h is not reachable\n");
+ exit (1);
+ }
+ exit (0);
+}
+my $ret = 0;
+while (1) {
+ last if (wait() == -1);
+ $ret++ if ($?);
+}
+
+print ("total $ret not reachable host(s)\n") if ($ret);
+exit ($ret);
+
+sub testlive($) {
+ my $h = shift;
+
+ system("ping -c3 -t1 '$h' >/dev/null") and return undef;
+ return 1;
+}
+
|
[-]
[+]
|
Deleted |
crossroads-devel.tar.gz/test/xr-test
^
|
@@ -1,36 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use LWP::UserAgent;
-use Time::HiRes qw(sleep gettimeofday tv_interval);
-
-die ("Usage: $0 URL TRIALS\n") if ($#ARGV != 1);
-$|++;
-
-my $n = 0;
-my $totaltime = 0;
-
-my $ua = LWP::UserAgent->new();
-$ua->timeout(5);
-while ($n < $ARGV[1]) {
- my $success = 0;
- for my $i (1..10) {
- my $t0 = [ gettimeofday() ];
- my $resp = $ua->get($ARGV[0]);
- if ($resp->is_success()) {
- $success++;
- $n++;
- $totaltime += tv_interval ($t0);
- last;
- }
- if ($i == 3) {
- die ($resp->status_line(), "\n");
- }
- sleep (1);
- }
- sleep (0.1);
- printf ("\rN: %5d Tot:%8.3g Avg:%8.3g", $n, $totaltime, $totaltime / $n)
- if (! ($n % 10));
-}
-
-print ("\n");
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/Checkers/checkupthread/execute.cc
^
|
@@ -6,19 +6,30 @@
while (1) {
if (config.checkupsec()) {
+ msg ("Running checkup thread\n");
for (unsigned i = 0; i < balancer.nbackends(); i++) {
Backend target(balancer.backend(i).backenddef());
- target.check();
- if (! balancer.backend(i).live() &&
- target.live() ) {
- balancer.backend(i).live(true);
- msg ("Checkup call: backend " + target.description() +
- " has awoken\n");
- } else if (balancer.backend(i).live() &&
- ! target.live()) {
- balancer.backend(i).live(false);
- msg ("Checkup call: backend " + target.description() +
- " has gone asleep\n");
+ 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);
+ balancer.backend(i).markconnecterror();
+ 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());
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/Checkers/wakeupthread/execute.cc
^
|
@@ -8,11 +8,17 @@
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);
+ } else
+ balancer.backend(i).markconnecterror();
+ } catch (...) {
+ socketclose(target.sock());
}
}
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/DispatchAlgorithms/external/target.cc
^
|
@@ -14,21 +14,23 @@
FILE *f;
if (! (f = popen (o.str().c_str(), "r")) )
- throw static_cast<Error>("Cannot start '") + o.str() + "': " +
- strerror(errno);
+ throw Error("Cannot start '" + o.str() + ": " + strerror(errno));
unsigned i;
if (fscanf (f, "%u", &i) < 1)
- throw static_cast<Error>("External algorithm '") + o.str() +
- "' did not reply with a number";
+ throw Error("External algorithm '" + o.str() +
+ "' did not reply with a number");
msg ((Mstr("External algorithm says:) ") + i) + "\n");
- if (i >= balancer.nbackends())
- throw static_cast<Error>("External algorithm '") + o.str() +
- "': answer " + i + " out of bounds";
+ if (i >= balancer.nbackends()) {
+ ostringstream o;
+ o << "External algorithm '" << o.str() << "': answer "
+ << i << " out of bounds";
+ throw Error(o.str());
+ }
if (pclose (f))
- throw static_cast<Error>("External algorithm '") + o.str() +
- "' terminated with error";
+ throw Error("External algorithm '" + o.str() +
+ "' terminated with error");
return (i);
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/DispatchAlgorithms/firstactive/target.cc
^
|
@@ -4,8 +4,7 @@
BackendVector const &targetlist) {
if ( targetlist.size() == 0 ||
! balancer.backend(targetlist[0]).available() )
- throw static_cast<Error>("First-active algorithm: "
- "no available back ends");
+ throw Error("First-active algorithm: no available back ends");
return (targetlist[0]);
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/DispatchAlgorithms/hashedip/target.cc
^
|
@@ -2,6 +2,11 @@
unsigned HashedIp::target(struct in_addr clientip,
BackendVector const &targetlist) {
+
+ // Nothing to do if we don't have targets.
+ if (!targetlist.size())
+ throw Error("Hashed-ip algorithm: no back ends to dispatch to");
+
// Hash the client's IP into an index
unsigned h = 0;
for (char *cp = (char*)&clientip;
@@ -21,8 +26,9 @@
// In lax mode, fall back to least-connections dispatching
if (! balancer.backend(index).available()) {
if (config.dispatchmode() == Dispatchmode::m_strict_hashed_ip)
- throw static_cast<Error>("Hashed-IP algorithm: target back end ") +
- balancer.backend(index).description() + " unavailable";
+ throw Error("Hashed-IP algorithm: target back end " +
+ balancer.backend(index).description() +
+ " unavailable");
else {
msg ("Hashed-IP algorithm: target back end " +
balancer.backend(index).description() + " unavailable, "
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/DispatchAlgorithms/leastconn/leastconn
^
|
@@ -5,6 +5,7 @@
#include "error/error"
#include "balancer/balancer"
#include "DispatchAlgorithms/algorithm/algorithm"
+#include "ipstore/ipstore"
class Leastconn: public Algorithm {
public:
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/DispatchAlgorithms/leastconn/target.cc
^
|
@@ -4,34 +4,27 @@
BackendVector const &targetlist) {
PROFILE("Leastconn::target");
+ msg (Mstr("Starting least-connections dispatcher\n"));
bool found = false;
- unsigned nconn = 0, t = 0;
+ unsigned best_weighted = 0, t = 0;
for (unsigned i = 0; i < targetlist.size(); i++) {
if (! balancer.backend(targetlist[i]).available())
continue;
- unsigned weighted_conn =
- balancer.backend(targetlist[i]).connections() *
+ unsigned this_weight =
+ (balancer.backend(targetlist[i]).connections() +
+ IPStore::anticipated(targetlist[i])) *
balancer.backend(targetlist[i]).adjustedweight();
- msg ("Back end " + balancer.backend(targetlist[i]).description() +
- (Mstr(": connections ")
- + balancer.backend(targetlist[i]).connections()) +
- (Mstr(", adjusted weight ") +
- balancer.backend(targetlist[i]).adjustedweight()) +
- (Mstr(", weighted connections ") + weighted_conn) +
- "\n");
-
- if (!found || weighted_conn < nconn) {
+ if (!found || this_weight < best_weighted) {
t = targetlist[i];
- nconn = balancer.backend(t).connections();
+ best_weighted = this_weight;
found = true;
}
}
if (!found)
- throw static_cast<Error>
- ("Least-connections algorithm: no available back ends");
+ throw Error("Least-connections algorithm: no available back ends");
return (t);
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/DispatchAlgorithms/roundrobin/target.cc
^
|
@@ -4,9 +4,18 @@
BackendVector const &targetlist) {
// No back ends? Don't even try. One back end? Always that one.
if (targetlist.size() == 0)
- throw static_cast<Error>("Round robin dispatcher: no backends\n");
+ throw Error("Round robin dispatcher: no backends\n");
+
+ if (config.debug())
+ for (unsigned i = 0; i < targetlist.size(); i++) {
+ unsigned backend_index = targetlist[i];
+ _debugmsg(Mstr("Round robin dispatcher: target ") +
+ Mstr(i) + Mstr(" is ") +
+ balancer.backend(backend_index).description() + "\n");
+ }
+
if (targetlist.size() == 1)
- return (0);
+ return (targetlist[0]);
static int prev_run_index = -1;
@@ -26,8 +35,7 @@
cur_val = prev_run_index + 1;
cur_val %= targetlist.size();
if (cur_val == first_try_val)
- throw static_cast<Error>("Round robin dispatcher: "
- "no backends\n");
+ throw Error("Round robin dispatcher: no backends\n");
}
// Store for next time 'round
@@ -42,4 +50,3 @@
return (targetlist[cur_val]);
}
}
-
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/DispatchAlgorithms/storedip/storedip
^
|
@@ -8,6 +8,7 @@
#include "timestamp/timestamp"
#include "DispatchAlgorithms/algorithm/algorithm"
#include "DispatchAlgorithms/leastconn/leastconn"
+#include "ipstore/ipstore"
class StoredIp: public Algorithm {
public:
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/DispatchAlgorithms/storedip/target.cc
^
|
@@ -1,90 +1,33 @@
#include "storedip"
-struct ClientData {
- int targetbackend;
- time_t lastaccess;
-};
-
-struct ClientDataCmp {
- bool operator() (struct in_addr a, struct in_addr b) const {
- long la, lb;
- memcpy (&la, &a, sizeof(long));
- memcpy (&lb, &b, sizeof(long));
- return (la - lb) < 0;
- }
-};
-
-typedef map<struct in_addr, ClientData, ClientDataCmp> StoreMap;
-static StoreMap store;
-
unsigned StoredIp::target(struct in_addr clientip,
BackendVector const &targetlist) {
- unsigned target;
- time_t now = time(0);
+ PROFILE("StoredIP::target");
+ IPStore::on();
- if (store.count(clientip) > 0) {
- // Client already known, maybe timed out.
- time_t diff = now - store[clientip].lastaccess;
+ msg(Mstr("Starting stored-ip dispatcher\n"));
- if (config.verbose()) {
- Timestamp tm(store[clientip].lastaccess);
- msg(Mstr("Client IP ") + Mstr(inet_ntoa(clientip)) +
- " last visited on " + tm.desc() +
- Mstr(Mstr(", ") + diff) + " sec ago, and went to " +
- balancer.backend(store[clientip].targetbackend).description() +
- "\n");
+ int tb;
+ if ( (tb = IPStore::target(clientip)) >= 0 ) {
+ unsigned target = tb;
+ IPStore::clear(clientip);
+ if (balancer.backend(target).available()) {
+ // Historical target is up, go there!
+ msg(Mstr("Sending ") + Mstr(inet_ntoa(clientip)) + " to " +
+ balancer.backend(target).description() + "\n");
+ return target;
}
-
- if (diff <= config.ipstoretimeout()) {
- // Recent 'nuff
- target = store[clientip].targetbackend;
- if (! balancer.backend(target).available()) {
- // Historical target down - get new one if in lax mode
- if (config.dispatchmode() == Dispatchmode::m_strict_stored_ip)
- throw static_cast<Error>
- ("Stored-IP algorithm: target back end ") +
+ msg (Mstr("Historical target ") +
+ balancer.backend(target).description() + " unavailable\n");
+ if (config.dispatchmode() == Dispatchmode::m_strict_stored_ip)
+ throw Error("Stored-IP algorithm: target back end " +
balancer.backend(target).description() +
- "unavailable";
- else {
- msg ("Stored IP algorithm: target back end " +
- balancer.backend(target).description() +
- " unavailable, falling back to least-connections\n");
- Leastconn l;
- target = l.target(clientip, targetlist);
- }
- }
- } else {
- // Not recent anymore
- msg ("Visit too long ago, re-dispatching with least-connections\n");
- Leastconn l;
- target = l.target(clientip, targetlist);
- }
- } else {
- // Historical target unknown, fetch new one
- msg ("New visit from " + static_cast<string>(inet_ntoa(clientip)) +
- "\n");
- Leastconn l;
- target = l.target(clientip, targetlist);
- }
-
- // Update the info.
- ClientData entry = {target, now};
- store[clientip] = entry;
-
- // Weed out store.
- for (StoreMap::iterator iter = store.begin(); iter != store.end();
- iter++) {
- if (config.debug()) {
- Timestamp tm((*iter).second.lastaccess);
- debugmsg (Mstr(inet_ntoa(iter->first)) + Mstr(" visited on ") +
- tm.desc() + "\n");
- }
- if (now - ((*iter).second.lastaccess) > config.ipstoretimeout()) {
- debugmsg (" Erasing stale entry, stale\n");
- store.erase(iter);
- }
+ " unavailable");
}
- // Return target to caller
- return (target);
+ // Client is seen for the first time, or after the timout period, or
+ // their preferred back end is down (and we're in lax mode ofc).
+ // Treat as new connection.
+ Leastconn l;
+ return l.target(clientip, targetlist);
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/DispatchAlgorithms/weightedload/target.cc
^
|
@@ -39,6 +39,6 @@
}
- throw static_cast<Error>("Weighted-load algorithm: no available back ends ");
+ throw Error("Weighted-load algorithm: no available back ends ");
return targetlist[0]; // We need some kind of default...
}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers
^
|
+(directory)
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/dispatcher
^
|
+(directory)
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/dispatcher/checkacl.cc
^
|
@@ -0,0 +1,26 @@
+#include "dispatcher"
+
+bool Dispatcher::check_acl() {
+ if (config.nallow()) {
+ bool allowed = false;
+ for (unsigned n = 0; n < config.nallow(); n++)
+ if (ipmatch(clientip(), config.allow(n))) {
+ allowed = true;
+ break;
+ }
+ if (!allowed) {
+ msg("Not serving client IP " + clientipstr() +
+ ": no match in allow list\n");
+ return false;
+ }
+ }
+ if (config.ndeny()) {
+ for (unsigned n = 0; n < config.ndeny(); n++)
+ if (ipmatch(clientip(), config.deny(n))) {
+ msg("Not serving client IP " + clientipstr() +
+ ": match in deny list\n");
+ return false;
+ }
+ }
+ return true;
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/dispatcher/checkdos.cc
^
|
@@ -0,0 +1,113 @@
+#include "dispatcher"
+
+typedef map < unsigned long, std::queue<time_t> > AccessMap;
+static AccessMap accesslog;
+static time_t accesslog_lastclean = 0;
+
+// Execute an external program upon excess of hard/soft rates
+static void run_excess(string const &prog, char const *ip) {
+ ostringstream o;
+ o << prog << ' ' << ip;
+ msg ((Mstr("Max connection rate exceeded, invoking '") + o.str()) +
+ "'\n");
+ int ret = sysrun(o.str());
+ if (ret == -1)
+ throw Error(string("Failed to start system call: ") +
+ strerror(errno));
+ else if (ret)
+ warnmsg((Mstr("Program '") + o.str()) +
+ (Mstr("' exited with exit status ") + ret) + "\n");
+ else
+ msg((Mstr("Program '") + o.str()) + "' finished.\n");
+}
+
+bool Dispatcher::check_dos() {
+ msg ("Verifying DOS protection\n");
+ Threadlist::desc("Verifying");
+
+ // Check 'softmaxconnrate' and 'hardmaxconnrate' now!
+ // Descend into this block if connrate_time() is set, AND
+ // either hardmaxconnrate() is set,
+ // or both softmaxconnrate() and defertime() are set.
+ if (config.connrate_time() &&
+ (config.hardmaxconnrate() ||
+ (config.softmaxconnrate() && config.defertime()))) {
+ time_t now, min_ts;
+ now = time(0);
+ min_ts = now - config.connrate_time();
+ unsigned max_conns = max(config.hardmaxconnrate(),
+ config.softmaxconnrate());
+
+ Mutex::lock (&accesslog[clientip().s_addr]);
+ accesslog[clientip().s_addr].push(now);
+ Mutex::unlock (&accesslog[clientip().s_addr]);
+
+ if (accesslog_lastclean < min_ts) {
+ // Clean the entire access log, it's been a while...
+
+ Mutex::lock(&accesslog_lastclean);
+ accesslog_lastclean = now;
+ Mutex::unlock(&accesslog_lastclean);
+
+ for (AccessMap::iterator i = accesslog.begin();
+ i != accesslog.end();
+ i++ ) {
+ if (accesslog[i->first].back() < min_ts) {
+ // This IP hasn't made ANY connections in a while -- erase!
+ accesslog.erase(i);
+ } else {
+ // Keep popping off this IP's oldest connection until we
+ // have only "recent" connections left.
+ Mutex::lock(&accesslog[i->first]);
+ while ( accesslog[i->first].front() < min_ts
+ || accesslog[i->first].size() > max_conns ) {
+ accesslog[i->first].pop();
+ }
+ Mutex::unlock(&accesslog[i->first]);
+ }
+ }
+ } else {
+ // The "big log" doesn't need to be fully cleaned,
+ // but this particular IP should be!
+ Mutex::lock(&accesslog[clientip().s_addr]);
+ while ( accesslog[clientip().s_addr].front() < min_ts
+ || accesslog[clientip().s_addr].size() > max_conns ) {
+ accesslog[clientip().s_addr].pop();
+ }
+ Mutex::unlock(&accesslog[clientip().s_addr]);
+ }
+
+ if (config.hardmaxconnrate() &&
+ accesslog[clientip().s_addr].size() >= config.hardmaxconnrate() ) {
+ // This IP has violated the "HARD" limit! Reject the connection
+ ostringstream o;
+ o << "Client " << clientipstr()
+ << " has hit the HARD maximum number of connections ("
+ << config.hardmaxconnrate() << " conections in "
+ << config.connrate_time() << " seconds; "
+ << accesslog[clientip().s_addr].size()
+ << " connections recorded). Client is refused.\n";
+ warnmsg (o.str());
+ socketclose(clientfd());
+ run_excess(config.hardmaxconnexcess(), clientipstr().c_str());
+ return false;
+ } else if (config.softmaxconnrate() &&
+ (accesslog[clientip().s_addr].size() >=
+ config.softmaxconnrate())) {
+ // This IP has violated the "SOFT" Limit. Go to sleep for a while.
+ ostringstream o;
+ o << "Client " << clientipstr()
+ << " has hit the SOFT maximum number of connections ("
+ << config.softmaxconnrate() << " connections in "
+ << config.connrate_time() << " sedonds; "
+ << accesslog[clientip().s_addr].size()
+ << " connections recorded). Client is deferred for "
+ << config.defertime() << " microseconds.\n";
+ warnmsg (o.str());
+ run_excess(config.softmaxconnexcess(), clientipstr().c_str());
+ usleep(config.defertime());
+ }
+ }
+
+ return true;
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/dispatcher/clientipstr.cc
^
|
@@ -0,0 +1,10 @@
+#include "dispatcher"
+
+string const &Dispatcher::clientipstr() {
+ if (clientip_str == "") {
+ Mutex::lock( (void*)inet_ntoa );
+ clientip_str = inet_ntoa(clientip());
+ Mutex::unlock( (void*)inet_ntoa );
+ }
+ return clientip_str;
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/dispatcher/dispatcher
^
|
@@ -0,0 +1,67 @@
+#ifndef _DISPATCHER_
+#define _DISPATCHER_
+
+#include "sys/sys"
+#include "memory/memory"
+
+#include "balancer/balancer"
+#include "config/config"
+#include "ThreadsAndMutexes/thread/thread"
+#include "ThreadsAndMutexes/threadlist/threadlist"
+#include "backendvector/backendvector"
+#include "netbuffer/netbuffer"
+
+// Dispatching algorithm workers
+#include "DispatchAlgorithms/algorithm/algorithm"
+#include "DispatchAlgorithms/roundrobin/roundrobin"
+#include "DispatchAlgorithms/firstactive/firstactive"
+#include "DispatchAlgorithms/leastconn/leastconn"
+#include "DispatchAlgorithms/external/external"
+#include "DispatchAlgorithms/hashedip/hashedip"
+#include "DispatchAlgorithms/storedip/storedip"
+#include "DispatchAlgorithms/weightedload/weightedload"
+
+#ifdef MEMDEBUG
+class Dispatcher: public Thread, public Memory
+#else
+class Dispatcher: public Thread
+#endif
+{
+public:
+
+ Dispatcher(int fd, struct in_addr ip);
+ Dispatcher(int fd);
+ virtual ~Dispatcher();
+
+ virtual void execute() = 0;
+ virtual void dispatch() = 0;
+ virtual void handle() = 0;
+
+ bool check_dos();
+ bool check_acl();
+
+ int targetbackend() const { return target_backend; }
+ void targetbackend(int t) { target_backend = t; }
+ struct in_addr clientip() const { return client_ip; }
+ void clientip(struct in_addr i) { client_ip = i;
+ clientip_str = ""; }
+ string const &clientipstr();
+ int clientfd() const { return client_fd; }
+ void clientfd(int c) { client_fd = c; }
+ int backendfd() const { return backend_fd; }
+ void backendfd(int b) { backend_fd = b; }
+ Algorithm *algorithm() const { return algo; }
+
+ BackendVector &targetlist() { return target_list; }
+ void targetlist (BackendVector t) { target_list = t; }
+
+private:
+ void start_dispatcher();
+ struct in_addr client_ip;
+ int target_backend, client_fd, backend_fd;
+ Algorithm *algo;
+ BackendVector target_list;
+ string clientip_str;
+};
+
+#endif
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/dispatcher/dispatcher1.cc
^
|
@@ -0,0 +1,8 @@
+#include "dispatcher"
+
+Dispatcher::Dispatcher(int cfd, struct in_addr cip):
+ Thread(), client_ip(cip), target_backend(-1), client_fd(cfd),
+ backend_fd(-1), target_list(), clientip_str() {
+
+ start_dispatcher();
+}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/Dispatchers/dispatcher/dispatcher2.cc
^
|
(renamed to xr/Dispatchers/dispatcher/dispatcher2.cc)
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/Dispatchers/dispatcher/dispatcher2.cc
^
|
(renamed to xr/Dispatchers/dispatcher/dispatcher2.cc)
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/dispatcher/dispatcher3.cc
^
|
@@ -0,0 +1,8 @@
+#include "dispatcher"
+
+Dispatcher::Dispatcher(int fd):
+ Thread(), target_backend(-1), client_fd(fd),
+ backend_fd(-1), target_list(), clientip_str() {
+
+ start_dispatcher();
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/dispatcher/startdispatcher.cc
^
|
@@ -0,0 +1,37 @@
+#include "dispatcher"
+
+void Dispatcher::start_dispatcher() {
+ // Instantiate dispatchmode algorithm
+ switch (config.dispatchmode()) {
+ case Dispatchmode::m_roundrobin:
+ algo = new Roundrobin;
+ break;
+ case Dispatchmode::m_firstactive:
+ algo = new Firstactive;
+ break;
+ case Dispatchmode::m_external:
+ algo = new External;
+ break;
+ case Dispatchmode::m_strict_hashed_ip:
+ case Dispatchmode::m_lax_hashed_ip:
+ algo = new HashedIp;
+ break;
+ case Dispatchmode::m_strict_stored_ip:
+ case Dispatchmode::m_lax_stored_ip:
+ algo = new StoredIp;
+ break;
+ case Dispatchmode::m_weighted_load:
+ algo = new Weightedload;
+ break;
+ case Dispatchmode::m_leastconn:
+ default:
+ algo = new Leastconn;
+ break;
+ }
+
+ // NOTE: Memory errors for algorithm pointer are not handled here,
+ // but in dispatch() (don't want to throw up in the constructor)
+
+ debugmsg("Dispatcher instantiated.\n");
+}
+
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/httpdispatcher
^
|
+(directory)
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/httpdispatcher/dispatch.cc
^
|
@@ -0,0 +1,86 @@
+#include "httpdispatcher"
+
+void HttpDispatcher::dispatch() {
+ PROFILE("HttpDispatcher::dispatch");
+
+ unsigned stickytarget;
+ string host_header = "";
+
+ // Try to dispatch. Since we're in HTTP mode, we must return an
+ // error page when dispatching fails.
+ try {
+
+ // Get the client's request. May need for cookie inspection or for the
+ // host header.
+ while (!buf().headersreceived())
+ if (!buf().netread(clientfd(), config.client_read_timeout()))
+ throw Error("Didn't receive a valid client request.");
+ msg ("Received client request: '" + buf().firstline() + "'\n");
+
+ // See if hostmatching is used. This is true when a backend
+ // matches against a non-dot host.
+ bool hostmatchused = false;
+ for (unsigned i = 0; i < balancer.nbackends(); i++)
+ if (balancer.backend(i).hostmatch() != ".") {
+ hostmatchused = true;
+ break;
+ }
+ // Build new target list if host matching applies.
+ if (hostmatchused) {
+ host_header = buf().headerval ("Host");
+ msg ("Will try to dispatch request for host '" +
+ host_header + "'\n");
+
+ // We need to build tcpdispatcher's target list now!
+ // Construct locally and poke into TcpDispatcher.
+ msg ("Creating host-based target list for the HTTP dispatcher\n");
+ BackendVector v;
+ v.isdefined(true);
+ for (unsigned i = 0; i < balancer.nbackends(); i++) {
+ if ( (balancer.backend(i).available()) &&
+ (!regexec (&(balancer.backend(i).hostregex()),
+ host_header.c_str(), 0, 0, 0)) ) {
+ v.add(i);
+ if (config.verbose())
+ msg (" Candidate target: " +
+ balancer.backend(i).description() + "\n");
+ }
+ }
+ targetlist(v);
+ }
+
+ // Dispatch as a normal backend if sticky HTTP is off, or if the
+ // sticky target is badly specified.
+ if (!config.stickyhttp() ||
+ (sscanf (buf().cookievalue ("XRTarget").c_str(),
+ "%d", &stickytarget) < 1 &&
+ sscanf (buf().paramvalue ("XRTarget").c_str(),
+ "%d", &stickytarget) < 1) ||
+ stickytarget >= balancer.nbackends()) {
+ issticky(false);
+ TcpDispatcher::dispatch();
+ } else {
+ // Got a sticky target. Try to connect. If that fails, fallback
+ // to non-sticky dispatching.
+ targetbackend(stickytarget);
+ Backend tb = balancer.backend(stickytarget);
+ msg ("Sticky HTTP request for " + tb.description() + "\n");
+ if (! tb.connect()) {
+ balancer.backend(stickytarget).live(false);
+ msg ("Failed to connect to back end " + tb.description() +
+ ", trying to dispatch to other\n");
+ issticky(false);
+ TcpDispatcher::dispatch();
+ } else {
+ backendfd(tb.sock());
+ issticky(true);
+ }
+ }
+
+
+ } catch (Error const &e) {
+ senderrorpage(e.what());
+ throw e;
+ }
+}
+
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/httpdispatcher/handle.cc
^
|
@@ -0,0 +1,105 @@
+#include "httpdispatcher"
+
+void HttpDispatcher::handle() {
+ PROFILE("HttpDispatcher::handle");
+
+ // The client request was already retrieved before starting the
+ // dispatcher. We can continue by applying server-directed headers.
+ if (config.addxrversion())
+ buf().setheader ("XR", VER);
+ if (config.addxforwardedfor())
+ buf().addheader ("X-Forwarded-For", clientipstr());
+ for (unsigned n = 0; n < config.nserverheaders(); n++)
+ buf().setheader (config.serverheader(n));
+
+ // Patch up the Host: header if requested so.
+ if (config.replacehostheader())
+ buf().replaceheader("Host:",
+ balancer.backend(targetbackend()).server());
+
+ // Flush client info received so far to the back end.
+ debugmsg("Sending client request to back end\n");
+ buf().netwrite(backendfd(), config.backend_write_timeout());
+
+ // Let's see if we will need to modify the server headers.
+ bool modify_serverheaders = false;
+ if (config.addxrversion() ||
+ (config.stickyhttp() && !issticky()))
+ modify_serverheaders = true;
+
+ // Store the client request. May want to log it later.
+ string client_request = buf().firstline();
+
+ // Go into copy-thru mode. If required, catch the server headers on
+ // their first appearance and modify them.
+ bool backend_response_checked = false;
+ while (1) {
+ Fdset readset (maxtimeout(config.client_read_timeout(),
+ config.backend_read_timeout()));
+ readset.add(clientfd());
+ readset.add(backendfd());
+ readset.wait_r();
+
+ int sock;
+ if (readset.readable(clientfd()))
+ sock = clientfd();
+ else if (readset.readable(backendfd()))
+ sock = backendfd();
+ else
+ break;
+
+ buf().reset();
+
+ if (!buf().netread(sock))
+ break;
+
+ if (sock == backendfd() && modify_serverheaders) {
+ debugmsg("Back end response seen, applying modifications\n");
+ modify_serverheaders = false;
+ while (! buf().headersreceived())
+ if (!buf().netread (sock, config.backend_read_timeout()))
+ throw Error("Failed to get headers from back end");
+ if (config.addxrversion())
+ buf().setheader("XR", VER);
+ if (config.stickyhttp() && !issticky()) {
+ ostringstream o;
+ o << "XRTarget=" << targetbackend() << "; path=/";
+ buf().setheader("Set-Cookie", o.str());
+ }
+ }
+
+ // The back end response may now get flushed to the client.
+ // If the response code is 4** or 5**, log it as a warning.
+ if (!backend_response_checked &&
+ sock == backendfd() && buf().headersreceived()) {
+ string respcode = buf().stringat(9, 3);
+ if (respcode[0] == '4' || respcode[0] == '5')
+ warnmsg("HTTP back end indicates fault: '" +
+ buf().firstline() + "' as response to '" +
+ client_request + "'\n");
+ backend_response_checked = true;
+ }
+
+ // Flush info to the other connected side.
+ int othersock, timeout;
+ if (sock == clientfd()) {
+ othersock = backendfd();
+ 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_read_timeout();
+ }
+
+ debugmsg (Mstr("Had data on ") + sock +
+ (Mstr(", sending to ") + othersock) + "\n");
+
+ buf().netwrite(othersock, timeout);
+ if (sock == backendfd())
+ balancer.backend(targetbackend()).addbytes(buf().bufsz());
+ }
+
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/httpdispatcher/httpdispatcher
^
|
@@ -0,0 +1,22 @@
+#ifndef _HTTPDISPATCHER_
+#define _HTTPDISPATCHER_
+
+#include "sys/sys"
+#include "Dispatchers/tcpdispatcher/tcpdispatcher"
+#include "httpbuffer/httpbuffer"
+
+class HttpDispatcher: public TcpDispatcher {
+public:
+ HttpDispatcher (int fd, struct in_addr ip);
+
+ void dispatch();
+ void handle();
+ bool issticky() const { return (is_sticky); }
+ void issticky (bool s) { is_sticky = s; }
+
+private:
+ void senderrorpage(string const &desc);
+ bool is_sticky;
+};
+
+#endif
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/Dispatchers/httpdispatcher/httpdispatcher1.cc
^
|
(renamed to xr/Dispatchers/httpdispatcher/httpdispatcher1.cc)
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/Dispatchers/httpdispatcher/httpdispatcher1.cc
^
|
(renamed to xr/Dispatchers/httpdispatcher/httpdispatcher1.cc)
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/httpdispatcher/senderrorpage.cc
^
|
@@ -0,0 +1,32 @@
+#include "httpdispatcher"
+
+void HttpDispatcher::senderrorpage(string const &reason) {
+ PROFILE("HttpDispatcher::senderrorpage");
+
+ msg ("Sending error page to client: '" + reason + "'\n");
+ try {
+ string txt =
+ "<html>\n"
+ " <head>\n"
+ " <title>Internal Server Error</title>\n"
+ " </head>\n"
+ " <body>\n"
+ " <h1>Internal Server Error</h1>\n"
+ " You request could not be completed. Please retry later.\n"
+ " </body>\n"
+ "</html>\n";
+ ostringstream mess;
+ mess <<
+ "HTTP/1.0 502 Internal Server Error\r\n"
+ "Content-Length: " << txt.size() << "\r\n"
+ "XR-Reason: " << reason << "\r\n"
+ "\r\n" <<
+ txt;
+ Netbuffer buf(mess.str());
+ 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
+ msg (Mstr(e.what()) + Mstr(" (while sending error page)\n"));
+ }
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/tcpdispatcher
^
|
+(directory)
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/tcpdispatcher/dispatch.cc
^
|
@@ -0,0 +1,44 @@
+#include "tcpdispatcher"
+
+void TcpDispatcher::dispatch() {
+ // Check that a working algorithm is available. May be missing if
+ // constructor's "new" failed.
+ if (!algorithm())
+ throw Error("No algorithm in Tcpdispatcher::dispatch");
+
+ bool connected = false;
+
+ // Build up the target list, if not yet done so. The HTTP dispatcher
+ // might've created it already for host-based matching (in which case
+ // we won't bother here).
+ if (! targetlist().isdefined()) {
+ msg ("Creating target list for the TCP dispatcher\n");
+ for (unsigned i = 0; i < balancer.nbackends(); i++)
+ if (balancer.backend(i).available()) {
+ targetlist().add(i);
+ if (config.verbose())
+ msg (" Candidate target: " +
+ balancer.backend(i).description() + "\n");
+ }
+ }
+
+ // Call the dispatch algorithm until we can connect,
+ // or until the algorithm is out of back ends (throws exception).
+ while (!connected) {
+ targetbackend(algorithm()->target(clientip(), targetlist()));
+ Backend tb = balancer.backend(targetbackend());
+ if (!tb.connect()) {
+ balancer.backend(targetbackend()).live(false);
+ if (config.verbose())
+ msg ("Failed to connect to back end " + tb.description() +
+ ", trying to dispatch to other\n");
+ } else {
+ connected = true;
+ backendfd(tb.sock());
+ msg ((Mstr("Will dispatch client to back end ") +
+ tb.description()) +
+ (Mstr(" on fd ") + tb.sock()) + "\n");
+ break;
+ }
+ }
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/tcpdispatcher/execute.cc
^
|
@@ -0,0 +1,78 @@
+#include "tcpdispatcher"
+
+void TcpDispatcher::execute() {
+ Threadlist::clientfd(clientfd());
+ Threadlist::clientip(clientip());
+
+ if (!check_dos() ||
+ !check_acl())
+ return;
+
+ msg ((Mstr("Dispatch request for client fd ") + clientfd()) + "\n");
+
+ try {
+ Threadlist::desc("Dispatching");
+ dispatch();
+ } catch (Error const &e) {
+ Mutex::lock(&cerr);
+ cerr << e.what() << "\n";
+ Mutex::unlock(&cerr);
+ socketclose(clientfd());
+ socketclose(backendfd());
+ return;
+ }
+
+ msg ((Mstr("Dispatching client fd ") + clientfd()) +
+ (Mstr(" to ") + balancer.backend(targetbackend()).description()) +
+ (Mstr(", fd ") + backendfd()) + "\n");
+
+
+ Threadlist::desc("Serving");
+ Threadlist::backend(targetbackend());
+ Threadlist::backendfd(backendfd());
+
+ balancer.backend(targetbackend()).startconnection();
+ if (config.onstart().length()) {
+ ostringstream o;
+ o << config.onstart() << ' ' << clientipstr() << ' '
+ << balancer.backend(targetbackend()).description()
+ << ' ' << balancer.backend(targetbackend()).connections();
+ msg (Mstr("Running onstart script: ") + o.str() + "\n");
+ sysrun(o.str());
+ }
+
+ bool failed = false;
+ try {
+ handle();
+ } catch (Error const &e) {
+ Mutex::lock(&cerr);
+ cerr << e.what() << "\n";
+ Mutex::unlock(&cerr);
+ failed = true;
+ if (config.onfail().length()) {
+ ostringstream o;
+ o << config.onfail() << ' ' << clientipstr() << ' '
+ << balancer.backend(targetbackend()).description() << ' '
+ << balancer.backend(targetbackend()).connections();
+ msg(Mstr("Running onfail script: ") + o.str() + "\n");
+ sysrun(o.str());
+ }
+ }
+
+ socketclose (clientfd());
+ socketclose (backendfd());
+
+ balancer.backend(targetbackend()).endconnection();
+ if (!failed && config.onend().length()) {
+ ostringstream o;
+ o << config.onend() << ' ' << clientipstr() << ' '
+ << balancer.backend(targetbackend()).description() << ' '
+ << balancer.backend(targetbackend()).connections();
+ msg (Mstr("Running onend script: ") + o.str() + "\n");
+ sysrun(o.str());
+ }
+
+ msg ((Mstr("Done dispatching to back end fd ") + backendfd()) +
+ (Mstr(" at ") + balancer.backend(targetbackend()).description()) +
+ "\n");
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/tcpdispatcher/handle.cc
^
|
@@ -0,0 +1,40 @@
+#include "tcpdispatcher"
+
+void TcpDispatcher::handle() {
+
+ debugmsg (Mstr("TCP dispatcher: About to shuttle between client fd ") +
+ clientfd() +
+ (Mstr(" and backend fd ") + backendfd()) + "\n");
+
+ while (1) {
+ Fdset readset(maxtimeout(config.client_read_timeout(),
+ config.backend_read_timeout()));
+ readset.add(clientfd());
+ readset.add(backendfd());
+ readset.wait_r();
+
+ int sock, othersock, timeout;
+ if (readset.readable(clientfd())) {
+ sock = clientfd();
+ othersock = backendfd();
+ timeout = config.backend_write_timeout();
+ } else if (readset.readable(backendfd())) {
+ sock = backendfd();
+ othersock = clientfd();
+ timeout = config.client_write_timeout();
+ } else
+ break;
+
+ if (!netbuffer.netread(sock))
+ break;
+ debugmsg (Mstr("Had data on ") + sock +
+ (Mstr(", sending to ") + othersock) + "\n");
+ netbuffer.netwrite (othersock, timeout);
+ if (sock == backendfd())
+ balancer.backend(targetbackend()).addbytes(netbuffer.bufsz());
+ else
+ IPStore::activity(clientip(), targetbackend());
+
+ netbuffer.reset();
+ }
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/tcpdispatcher/tcpdispatcher
^
|
@@ -0,0 +1,27 @@
+#ifndef _TCPDISPATCHER_
+#define _TCPDISPATCHER_
+
+#include "Dispatchers/dispatcher/dispatcher"
+#include "netbuffer/netbuffer"
+#include "httpbuffer/httpbuffer"
+#include "ipstore/ipstore"
+
+class TcpDispatcher: public Dispatcher {
+public:
+
+ TcpDispatcher (int fd, struct in_addr ip);
+
+ virtual void execute();
+ virtual void dispatch();
+ virtual void handle();
+
+ unsigned readchunk (int src);
+
+ Httpbuffer &buf() { return netbuffer; }
+
+private:
+ Httpbuffer netbuffer; // same as netbuffer, but
+ // httpdispatcher reuses it
+};
+
+#endif
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/Dispatchers/tcpdispatcher/tcpdispatcher1.cc
^
|
(renamed to xr/Dispatchers/tcpdispatcher/tcpdispatcher1.cc)
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/Dispatchers/tcpdispatcher/tcpdispatcher1.cc
^
|
(renamed to xr/Dispatchers/tcpdispatcher/tcpdispatcher1.cc)
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/udpdispatcher
^
|
+(directory)
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/udpdispatcher/dispatch.cc
^
|
@@ -0,0 +1,5 @@
+#include "udpdispatcher"
+
+void UdpDispatcher::dispatch() {
+ throw Error("UDP dispatcher: dispatch not yet implemented");
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/udpdispatcher/execute.cc
^
|
@@ -0,0 +1,5 @@
+#include "udpdispatcher"
+
+void UdpDispatcher::execute() {
+ throw Error("UDP dispatcher: execute not yet implemented");
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/udpdispatcher/handle.cc
^
|
@@ -0,0 +1,5 @@
+#include "udpdispatcher"
+
+void UdpDispatcher::handle() {
+ throw Error("UDP dispatcher: handle not yet implemented");
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/udpdispatcher/udpdispatcher
^
|
@@ -0,0 +1,16 @@
+#ifndef _UDPDISPATCHER_
+#define _UDPDISPATCHER_
+
+#include "Dispatchers/dispatcher/dispatcher"
+
+class UdpDispatcher: public Dispatcher {
+public:
+ UdpDispatcher(int fd);
+ virtual void execute();
+ virtual void dispatch();
+ virtual void handle();
+private:
+ Netbuffer netbuffer;
+};
+
+#endif
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/Dispatchers/udpdispatcher/udpdispatcher1.cc
^
|
@@ -0,0 +1,4 @@
+#include "udpdispatcher"
+
+UdpDispatcher::UdpDispatcher(int fd) : Dispatcher(fd), netbuffer() {
+}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/Makefile
^
|
@@ -35,7 +35,7 @@
echo "Making: $$f"; \
BASE=$(BASE) CC=$(CONF_CC) BUILDDIR=$(BUILDDIR) VER='$(VER)' \
AUTHOR='$(AUTHOR)' MAINTAINER='$(MAINTAINER)' \
- DISTSITE='$(DISTSITE)' \
+ DISTSITE='$(DISTSITE)' MEMDEBUG=$(MEMDEBUG)\
CONF_CC='$(CONF_CC)' CONF_LIB='$(CONF_LIB)' \
CONF_GETOPT=$(CONF_GETOPT) CONF_GETOPT_LONG=$(CONF_GETOPT_LONG) \
CONF_INET_ATON=$(CONF_INET_ATON) CONF_OPTFLAGS='$(CONF_OPTFLAGS)' \
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/ThreadsAndMutexes/mutex/plock.cc
^
|
@@ -6,12 +6,12 @@
if (iter == s_lock.end()) {
// No such lock yet, create the mutex
if (int res = pthread_mutex_init(&s_lock[target], 0))
- throw static_cast<Error>("Failed to initialize static mutex: ") +
- strerror(res);
+ throw Error(string("Failed to initialize static mutex: ") +
+ strerror(res));
}
if (int res = pthread_mutex_lock(&s_lock[target]))
- throw static_cast<Error>("Failed to obtain mutex lock: ") +
- strerror(res);
+ throw Error(string("Failed to obtain mutex lock: ") +
+ strerror(res));
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/ThreadsAndMutexes/mutex/unlock.cc
^
|
@@ -6,6 +6,6 @@
PROFILE("Mutex::unlock");
if (int res = pthread_mutex_unlock(&s_lock[target]))
- throw static_cast<Error>("Failed to release mutex lock: ") +
- strerror(res);
+ throw Error(string("Failed to release mutex lock: ") +
+ strerror(res));
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/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 @@
unlock(&cerr);
}
Threadlist::deregister();
+ debugmsg(Mstr("Thread: ending run\n"));
// Cleanups
delete (t);
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/ThreadsAndMutexes/thread/start.cc
^
|
@@ -12,9 +12,9 @@
int res;
if (pthread_attr_init (&attr))
- throw static_cast<Error>("Cannot initialize thread attributes");
+ throw Error("Cannot initialize thread attributes");
if (pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED))
- throw static_cast<Error>("Cannot set thread state as detached");
+ throw Error("Cannot set thread state as detached");
for (int i = 0; i < 3; i++) {
# ifdef MISTRUST_THREAD_CREATE_THREADSAFE
lock((void*)_run);
@@ -34,13 +34,12 @@
continue;
} else {
pthread_attr_destroy (&attr);
- throw static_cast<Error>("Failed to start thread: ") +
- strerror(res);
+ throw Error(string("Failed to start thread: ") +
+ strerror(res));
}
}
- throw static_cast<Error>("Failed to start thread: "
- "Resources unavailable after 3 tries, "
- "giving up");
+ throw Error("Failed to start thread: "
+ "Resources unavailable after 3 tries, giving up");
}
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/ThreadsAndMutexes/thread/thread
^
|
@@ -2,6 +2,7 @@
#define _THREAD_
#include "sys/sys"
+#include "memory/memory"
#include "error/error"
#include "config/config"
#include "timestamp/timestamp"
@@ -10,7 +11,12 @@
using namespace std;
-class Thread: public Mutex {
+#ifdef MEMDEBUG
+class Thread: public Mutex, public Memory
+#else
+class Thread: public Mutex
+#endif
+{
public:
virtual ~Thread();
void start();
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/ThreadsAndMutexes/threadinfo/threadinfo
^
|
@@ -9,7 +9,9 @@
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 @@
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
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/ThreadsAndMutexes/threadlist/clientip.cc
^
|
@@ -0,0 +1,5 @@
+#include "threadlist"
+
+void Threadlist::clientip(struct in_addr adr) {
+ th_map[pthread_self()].clientip(adr);
+}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/ThreadsAndMutexes/threadlist/threadlist
^
|
@@ -17,6 +17,7 @@
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;
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/backend/available.cc
^
|
@@ -1,16 +1,23 @@
#include "backend"
#include "profiler/profiler"
+#include "ipstore/ipstore"
bool Backend::available() const {
PROFILE("Backend::available");
- debugmsg((Mstr("Back end ") + description()) +
- (Mstr(": ") + livestr()) +
- (Mstr(", ") + upstr()) +
- (Mstr(", ") + connections()) +
- (Mstr(" connections of ") + maxconn()) +
- " max\n");
+ if (config.debug()) {
+ ostringstream o;
+ o << "Back end " << description() << ": "
+ << livestr() << ", " << upstr() << ", "
+ << connections() << " connections, "
+ << IPStore::anticipated(balancerindex()) << " anticipated, "
+ << maxconn() << " max\n";
+ _debugmsg(o.str());
+ }
if (!maxconn())
return (islive && isup);
- return (islive && isup && connections() < maxconn());
+ return (islive &&
+ isup &&
+ (connections() + IPStore::anticipated(balancerindex()) <
+ maxconn()));
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/backend/backend
^
|
@@ -19,7 +19,9 @@
Backend (BackendDef const &b);
virtual ~Backend();
bool connect();
- int sock() const { return (clsocket); }
+ void markconnecterror();
+
+ int sock() const { return clsocket; }
void check();
string description() const;
@@ -27,44 +29,46 @@
bool available() const;
string availablestr() const;
- bool live() const { return (islive); };
+ bool live() const { return islive; };
void live (bool state);
string livestr() const;
void up (bool state);
- bool up() const { return (isup); }
+ bool up() const { return isup; }
string upstr() const;
- string const &server() const { return (bdef.server()); }
+ string const &server() const { return bdef.server(); }
void server(string s) { bdef.server(s); }
- int port() const { return (bdef.port()); }
+ int port() const { return bdef.port(); }
void port(int p) { bdef.port(p); }
- unsigned maxconn() const { return (bdef.maxconn()); }
+ unsigned maxconn() const { return bdef.maxconn(); }
void maxconn (unsigned m) { bdef.maxconn(m); }
- string const &hostmatch() const { return (bdef.hostmatch()); }
+ string const &hostmatch() const { return bdef.hostmatch(); }
void hostmatch(string const &s) { bdef.hostmatch(s); }
- regex_t const &hostregex() const { return (bdef.hostregex()); }
+ regex_t const &hostregex() const { return bdef.hostregex(); }
- unsigned weight() const { return (bdef.weight()); }
+ unsigned weight() const { return bdef.weight(); }
void weight (unsigned w) { bdef.weight(w); }
- unsigned adjustedweight() const { return (bdef.adjustedweight()); }
+ unsigned adjustedweight() const { return bdef.adjustedweight(); }
- unsigned connections() const { return (nconn); }
- double bytesserved() const { return (bytes_served); }
- unsigned clientsserved() const { return (totconn); }
+ unsigned connections() const { return nconn; }
+ unsigned connecterrors() const { return nconnerr; }
+
+ double bytesserved() const { return bytes_served; }
+ unsigned clientsserved() const { return totconn; }
- double loadavg() const { return (loadaverage); }
+ double loadavg() const { return loadaverage; }
void loadavg(double l) { loadaverage = l; }
void addbytes (unsigned n);
void startconnection();
- void endconnection();
+ void endconnection();
BackendDef const &backenddef() const {
- return (bdef);
+ return bdef;
}
BackendCheck const &backendcheck() {
@@ -73,6 +77,9 @@
void backendcheck(BackendCheck const &b) {
bdef.backendcheck(b);
}
+
+ void balancerindex(int i) { index = i; }
+ int balancerindex() const { return index; }
private:
@@ -80,10 +87,11 @@
bool islive;
bool isup;
int clsocket;
- unsigned nconn, totconn;
+ unsigned nconn, totconn, nconnerr;
double bytes_served;
double loadaverage;
DNSEntry dnsentry;
+ int index;
};
#endif
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/backend/backend1.cc
^
|
@@ -2,6 +2,7 @@
Backend::Backend () :
islive(true), isup(true), clsocket(-1),
- nconn(0), totconn(0), bytes_served(0),
- loadaverage(0.1), dnsentry() {
+ nconn(0), totconn(0), nconnerr(0),
+ bytes_served(0),
+ loadaverage(0.1), dnsentry(), index(-1) {
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/backend/backend2.cc
^
|
@@ -2,5 +2,6 @@
Backend::Backend (BackendDef const &b) :
bdef(b), islive(true), isup(true), clsocket(-1), nconn(0), totconn(0),
- bytes_served(0), loadaverage(0.1), dnsentry() {
+ nconnerr(0),
+ bytes_served(0), loadaverage(0.1), dnsentry(), index(-1) {
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/backend/check.cc
^
|
@@ -13,6 +13,7 @@
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 @@
msg (Mstr("Alternative back end for testing ") +
tester.description() + " is " + livestr() + "\n");
}
- socketclose (sock());
break;
case BackendCheck::c_get:
@@ -48,10 +48,11 @@
"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")
@@ -92,6 +93,6 @@
break;
default:
- throw static_cast<Error>("Internal fry in Backend::check()");
+ throw Error("Internal fry in Backend::check()");
}
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/backend/connect.cc
^
|
@@ -10,8 +10,8 @@
// Create client socket
if ( (clsocket = socket (PF_INET, SOCK_STREAM, 0)) < 0 )
- throw static_cast<Error>("Failed to create client socket: ") +
- strerror(errno);
+ throw Error(string("Failed to create client socket: ") +
+ strerror(errno));
// Resolve hostname, prepare binding
struct sockaddr_in backendaddr;
@@ -25,12 +25,12 @@
int flags;
if ( (flags = fcntl (clsocket, F_GETFL, 0)) == -1 ) {
socketclose (clsocket);
- throw static_cast<Error>("Failed to get fd flags: ") + strerror(errno);
+ throw Error(string("Failed to get fd flags: ") + strerror(errno));
}
if (fcntl (clsocket, F_SETFL, flags | O_NONBLOCK) == -1) {
socketclose (clsocket);
- throw static_cast<Error>("Failed to fd in nonblocking mode: ") +
- strerror(errno);
+ throw Error(string("Failed to fd in nonblocking mode: ") +
+ strerror(errno));
}
// Do the connect
@@ -43,22 +43,30 @@
// Put socket again in blocking mode.
if (fcntl (clsocket, F_SETFL, flags) == -1) {
socketclose (clsocket);
- throw static_cast<Error>("Failed to put fd in blocking mode: ") +
- strerror(errno);
+ throw Error(string("Failed to put fd in blocking mode: ") +
+ strerror(errno));
}
// 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();
- debugmsg (Mstr("Connecting to ") + description() +
- Mstr(Mstr(": writesocket=") + wsock) +
- Mstr(Mstr(", read/writesocket=") + rwsock) + "\n");
- if (wsock == clsocket && rwsock == -1)
+ fdset.wait_rw();
+
+ debugmsg(Mstr("Connectiong to ") + description() + "\n");
+
+# ifdef CONNECTCHECK_ONLY_WRITABLE
+ if (fdset.writeable(clsocket))
+ islive = true;
+ else
+ markconnecterror();
+# else
+ if (fdset.writeable(clsocket) && !fdset.readable(clsocket))
islive = true;
+ else
+ markconnecterror();
+# endif
}
debugmsg ((Mstr("Back end ") + description()) +
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/backend/markconnecterror.cc
^
|
@@ -0,0 +1,8 @@
+#include "backend"
+
+void Backend::markconnecterror() {
+ Mutex::lock(&nconnerr);
+ nconnerr++;
+ Mutex::unlock(&nconnerr);
+}
+
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/backendcheck/description.cc
^
|
@@ -31,7 +31,7 @@
o << "External program " << extprog;
break;
default:
- throw static_cast<Error>("Internal jam in BackendCheck::description");
+ throw Error("Internal jam in BackendCheck::description");
}
return (o.str());
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/backendcheck/parse.cc
^
|
@@ -59,8 +59,7 @@
}
// No luck today
- throw static_cast<Error>
- ("Back end check specifiers must be either an empty string, "
- "or 'connect:IP:PORT' or 'get:IP:PORT' or 'get'IP:PORT/URI' "
- "or 'external:PROGRAM'");
+ throw Error("Back end check specifiers must be either an empty string, "
+ "or 'connect:IP:PORT' or 'get:IP:PORT' or 'get'IP:PORT/URI' "
+ "or 'external:PROGRAM'");
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/backenddef/backenddef1.cc
^
|
@@ -9,18 +9,18 @@
srv(server), prt(-1), max(0), host_match(""), wt(1) {
if (sscanf (port.c_str(), "%d", &prt) < 1)
- throw static_cast<Error>("Bad backend port specifier: '") + port +
- "' is not a number";
+ throw Error("Bad backend port specifier: '" + port +
+ "' is not a number");
if (maxclients.size() &&
sscanf (maxclients.c_str(), "%u", &max) < 1)
- throw static_cast<Error>("Bad maximum connections specifier: '") +
- maxclients + "' is not a number";
+ throw Error("Bad maximum connections specifier: '" +
+ maxclients + "' is not a number");
unsigned ww;
if (sscanf(w.c_str(), "%u", &ww) < 1)
- throw static_cast<Error>("Bad backend weight specifier: '") + w +
- "' is not a number";
+ throw Error("Bad backend weight specifier: '" + w +
+ "' is not a number");
if (ww < 1)
- throw static_cast<Error>("Weights less than 1 are not supported");
+ throw Error("Weights less than 1 are not supported");
weight(ww);
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/backenddef/hostmatch.cc
^
|
@@ -8,6 +8,6 @@
host_match = ".";
if (regcomp (&host_regex, host_match.c_str(),
REG_EXTENDED | REG_ICASE | REG_NOSUB))
- throw static_cast<Error>("Host match specifier '") +
- host_match + "' isn't a valid regular expression";
+ throw Error("Host match specifier '" +
+ host_match + "' isn't a valid regular expression");
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/balancer/addbackend2.cc
^
|
@@ -2,13 +2,19 @@
void Balancer::addbackend (Backend const &b,
bool is_up, bool is_live, bool do_check) {
- Mutex::lock(&backends);
- backends.push_back (b);
- Mutex::unlock(&backends);
+ debugmsg(Mstr("Adding back end ") + b.description() + " to list\n");
+ Mutex::lock(&backends);
+ backends.push_back (b);
backends[backends.size() - 1].up(is_up);
backends[backends.size() - 1].live(is_live);
+ backends[backends.size() - 1].balancerindex(backends.size() - 1);
+ Mutex::unlock(&backends);
+
+ if (do_check) {
+ debugmsg(Mstr("Verifying configured back end\n"));
+ backends[backends.size() - 1].check();
+ }
- if (do_check)
- backends[backends.size() - 1].check();
+ debugmsg(Mstr("Back end ") + b.description() + " added to list\n");
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/balancer/balancer
^
|
@@ -2,6 +2,7 @@
#define _BALANCER_
#include "sys/sys"
+#include "memory/memory"
#include "backend/backend"
#include "backenddef/backenddef"
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/balancer/deletebackend.cc
^
|
@@ -2,11 +2,13 @@
void Balancer::deletebackend(unsigned i) {
if (backend(i).up())
- throw static_cast<Error>("Only 'down' back ends can be deleted.");
- if (backend(i).connections())
- throw static_cast<Error>("Back end cannot be deleted, there are still ")
- + backend(i).connections() + " connections";
-
+ throw Error("Only 'down' back ends can be deleted.");
+ if (backend(i).connections()) {
+ ostringstream o;
+ o << "Back end cannot be deleted, there are still "
+ << backend(i).connections() << " connections";
+ throw Error(o.str());
+ }
Mutex::lock(&backends);
backends.erase(backends.begin() + i,
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/balancer/init.cc
^
|
@@ -2,17 +2,22 @@
void Balancer::init() {
// Set the listening socket.
- if (config.sport())
- server_fd = serversocket (config.sipaddr(), config.sport(),
- "balancer");
- else
- server_fd = 0;
-
+ if (config.stype() != Servertype::t_udp) {
+ if (config.sport())
+ server_fd = serversocket(config.sipaddr(), config.sport(),
+ "balancer", Servertype::t_tcp);
+ else
+ server_fd = 0;
+ } else {
+ server_fd = serversocket(config.sipaddr(), config.sport(),
+ "balancer", Servertype::t_udp);
+ }
+
// Start the web interface if requested.
- if (config.usewebinterface()) {
+ if (config.usewebinterface() && !config.foregroundmode()) {
Webinterface *w = new Webinterface();
if (! w)
- throw static_cast<Error>("Memory fault in Balancer::init");
+ throw Error("Memory fault in Balancer::init");
w->start();
}
@@ -20,7 +25,9 @@
for (int i = 0; i < config.backends(); i++)
addbackend (config.backend(i));
- for (unsigned i = 0; i < nbackends(); i++)
- msg ("Initial backend state: " + backend(i).description() + " is " +
- backend(i).availablestr() + "\n");
+ if (config.verbose()) {
+ for (unsigned i = 0; i < nbackends(); i++)
+ _msg ("Initial backend state: " + backend(i).description() +
+ " is " + backend(i).availablestr() + "\n");
+ }
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/balancer/serve.cc
^
|
@@ -1,9 +1,10 @@
#include "balancer"
-#include "../tcpdispatcher/tcpdispatcher"
-#include "../httpdispatcher/httpdispatcher"
+#include "Dispatchers/tcpdispatcher/tcpdispatcher"
+#include "Dispatchers/httpdispatcher/httpdispatcher"
+#include "Dispatchers/udpdispatcher/udpdispatcher"
void Balancer::serve() {
- int clsock;
+ int clsock = -1;
// Start up wakeup/checkup handlers. These are always started - even
// when config.wakeupsec() and config.checkupsec() are not defined
@@ -13,13 +14,13 @@
msg ("Starting wakeup thread.\n");
Wakeupthread *wt = new Wakeupthread();
if (!wt)
- throw static_cast<Error>("Memory fault in Balancer::serve");
+ throw Error("Memory fault in Balancer::serve");
wt->start();
msg ("Starting checkup thread.\n");
Checkupthread *ct = new Checkupthread();
if (!ct)
- throw static_cast<Error>("Memory fault in Balancer::serve");
+ throw Error("Memory fault in Balancer::serve");
ct->start();
}
@@ -27,18 +28,23 @@
if (config.pidfile() != "") {
FILE *f;
if (! (f = fopen (config.pidfile().c_str(), "w")) )
- throw static_cast<Error>("Cannot write pid file ") +
- config.pidfile() + ": " + strerror(errno);
+ throw Error(string("Cannot write pid file ") +
+ config.pidfile() + ": " + strerror(errno));
fprintf (f, "%u\n", getpid());
fclose (f);
}
// Wait for activity, serve it.
msg ((Mstr("Awaiting activity on fd ") + server_fd) + "\n");
+ MEM(Memory::mem_mark("Balancer start"));
+ MEM(Memory::mem_follow(true));
while (true) {
+ MEM(Memory::mem_display());
Fdset fdset(0);
fdset.add (server_fd);
- if (fdset.readable() < 0) {
+ fdset.wait_r();
+
+ if (! fdset.readable(server_fd)) {
// We caught a signal. Either a request to report status,
// or to terminate.
msg ("Interrupt seen\n");
@@ -70,96 +76,65 @@
}
}
- // Got activity!
+ // Got activity! Check total # of connections.
+ msg ((Mstr("Got activity on fd ") + server_fd) + "\n");
request_nr++;
+ if (config.maxconn() && connections() >= config.maxconn()) {
+ msg ((Mstr("Not serving connection: already ") + connections()) +
+ (Mstr(" connection(s) (max ") + config.maxconn()) + ")\n");
+ continue;
+ }
if (server_fd) {
- // If tcp-serving: server_fd > 0; serve and loop again
- int size;
+ // In daemon mode (server_fd > 0): serve and loop again
struct sockaddr_in clname;
-
- size = sizeof(clname);
- if ( (clsock = accept (server_fd, (struct sockaddr *) &clname,
- (socklen_t*) &size)) < 0 ) {
- warnmsg(Mstr("Failed to accept network connection: ") +
- Mstr(strerror(errno)) + "\n");
- continue;
- }
-
- string clientip = inet_ntoa(clname.sin_addr);
-
- // If there is an allow list, the client must match it.
- if (config.nallow()) {
- if (config.debug())
- debugmsg ("Matching " + clientip + " against allow list\n");
- bool allowed = false;
- for (unsigned n = 0; n < config.nallow(); n++) {
- if (ipmatch (clname.sin_addr, config.allow(n))) {
- allowed = true;
- break;
- }
- }
- if (!allowed) {
- msg ("Not serving client " + clientip +
- ": no match in allow list\n");
- socketclose (clsock);
+ int size = sizeof(clname);
+
+ // Accept the client if this is a TCP connection.
+ if (config.stype() != Servertype::t_udp) {
+ if ( (clsock = accept (server_fd, (struct sockaddr *) &clname,
+ (socklen_t*) &size)) < 0 ) {
+ warnmsg(Mstr("Failed to accept network connection: ") +
+ Mstr(strerror(errno)) + "\n");
continue;
}
- }
- // If the client is in the deny list, deny it.
- if (config.debug())
- debugmsg ("Matching " + clientip + " against deny list\n");
- bool denied = false;
- for (unsigned n = 0; n < config.ndeny(); n++)
- if (ipmatch (clname.sin_addr, config.deny(n))) {
- denied = true;
- break;
- }
- if (denied) {
- msg ("Not serving client " + clientip +
- ": match in deny list\n");
- socketclose (clsock);
- continue;
+ string clientip = inet_ntoa(clname.sin_addr);
+ msg ((Mstr("Accepted connection from ") + clientip) +
+ (Mstr(" as client fd ") + clsock) + "\n");
}
- // Show whom we've accepted
+ // Show how we look
if (config.verbose()) {
- msg ((Mstr("Accepted connection from ") + clientip) +
- (Mstr(" as client fd ") + clsock) + "\n");
+ ostringstream o;
msg ((Mstr("Balancer is serving ") + connections()) +
" clients\n");
msg ("Current back end states:\n");
for (unsigned i = 0; i < nbackends(); i++)
msg((Mstr(" Back end ") + backend(i).description()) +
(Mstr(": ") + backend(i).connections()) +
- (Mstr(" connections , max ") + backend(i).maxconn()) +
- (Mstr(", status ") + backend(i).availablestr()) + "\n");
- }
-
- // We got action! Check if the total connections to the
- // balancer doesn't exceed the max.
- if (config.maxconn() && connections() >= config.maxconn()) {
- msg ((Mstr("Not serving client: already ") + connections()) +
- (Mstr(" (max ") + config.maxconn()) + "\n");
- socketclose (clsock);
- continue;
+ (Mstr(" connections, max ") + backend(i).maxconn()) +
+ (Mstr(", status ") + backend(i).availablestr()) +
+ (Mstr(", anticipated ") + IPStore::anticipated(i)) +
+ "\n");
}
- TcpDispatcher *d;
+ Dispatcher *d;
switch (config.stype()) {
case Servertype::t_tcp:
- d = new TcpDispatcher (clsock, clname.sin_addr);
+ d = new TcpDispatcher(clsock, clname.sin_addr);
break;
case Servertype::t_http:
- d = new HttpDispatcher (clsock, clname.sin_addr);
+ d = new HttpDispatcher(clsock, clname.sin_addr);
+ break;
+ case Servertype::t_udp:
+ d = new UdpDispatcher(server_fd);
break;
default:
- throw static_cast<Error>("Internal error, "
- "can't choose dispatcher");
+ throw Error("Internal error, can't choose dispatcher");
break;
}
if (!d)
- throw static_cast<Error>("Memory fault in Balancer::serve");
+ throw Error("Memory fault in Balancer::serve");
// Allocation boundary printout
if (config.debug()) {
@@ -183,13 +158,15 @@
case Servertype::t_http:
d = new HttpDispatcher (server_fd, dummy);
break;
+ case Servertype::t_udp:
+ throw Error("UDP dispatching not allowed in inetd-mode");
+ break;
default:
- throw static_cast<Error>("Internal error, "
- "can't choose dispatcher");
+ throw Error("Internal error, can't choose dispatcher");
break;
}
if (!d)
- throw static_cast<Error>("Memory fault in Balancer::serve");
+ throw Error("Memory fault in Balancer::serve");
d->execute();
break;
}
@@ -211,7 +188,6 @@
// Wait for running threads to die off.
socketclose (server_fd);
- shutdown (server_fd, SHUT_RDWR);
unsigned prev_conn = 0x19081962;
while (1) {
unsigned curr_conn = balancer.connections();
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/config/addallow.cc
^
|
@@ -3,6 +3,6 @@
void Config::addallow (string a) {
struct in_addr in;
if (!inet_aton (a.c_str(), &in))
- throw static_cast<Error>("Bad allow-from specfier '") + a + "'";
+ throw Error("Bad allow-from specfier '" + a + "'");
allowlist.push_back (in);
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/config/adddeny.cc
^
|
@@ -3,6 +3,6 @@
void Config::adddeny (string d) {
struct in_addr in;
if (!inet_aton (d.c_str(), &in))
- throw static_cast<Error>("Bad deny-from specfier '") + d + "'";
+ throw Error("Bad deny-from specfier '" + d + "'");
denylist.push_back (in);
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/config/changeallow.cc
^
|
@@ -2,11 +2,11 @@
void Config::changeallow (string &a, unsigned index) {
if (index >= allowlist.size())
- throw static_cast<Error>("No such allow-from specifier");
+ throw Error("No such allow-from specifier");
struct in_addr in;
if (!inet_aton (a.c_str(), &in))
- throw static_cast<Error>("Bad allow-from specfier '") + a + "'";
+ throw Error("Bad allow-from specfier '" + a + "'");
allowlist[index] = (in);
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/config/changedeny.cc
^
|
@@ -2,11 +2,11 @@
void Config::changedeny (string &a, unsigned index) {
if (index >= denylist.size())
- throw static_cast<Error>("No such deny-from specifier");
+ throw Error("No such deny-from specifier");
struct in_addr in;
if (!inet_aton (a.c_str(), &in))
- throw static_cast<Error>("Bad deny-from specfier '") + a + "'";
+ throw Error("Bad deny-from specfier '" + a + "'");
denylist[index] = (in);
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/config/config
^
|
@@ -30,16 +30,38 @@
Servertype::Type stype() const { return (styp.type()); }
void stype(string const &s) { styp.type(s); }
string stypestr() const { return (styp.typestr()); }
- string sipaddr() const { return (sip); }
+ string const &sipaddr() const { return (sip); }
int sport() const { return (lport); }
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; }
@@ -61,12 +83,17 @@
bool stickyhttp() const { return (sticky_http); }
void stickyhttp(bool b);
+ bool replacehostheader() const { return replace_host_header; }
+ void replacehostheader(bool s) { replace_host_header = s; }
+
unsigned maxconn() const { return (max_conn); }
void maxconn (unsigned m);
- string externalalgorithm() const { return (external_algorithm); }
+ string const &externalalgorithm() const {
+ return (external_algorithm);
+ }
- string pidfile() const { return (pid_file); }
+ string const &pidfile() const { return (pid_file); }
void pidfile (string const &p);
bool prefixtimestamp() const { return (prefix_timestamp); }
@@ -76,16 +103,20 @@
void fastclose (bool f);
bool usewebinterface() const { return use_webinterface; }
- string webinterfaceip() const { return webinterface_ip; }
+ string const &webinterfaceip() const {
+ return webinterface_ip;
+ }
int webinterfaceport() const { return webinterface_port; }
unsigned nserverheaders() const { return (serverheaders.size()); }
- string serverheader (unsigned n) { return (serverheaders[n]); }
+ string const &serverheader (unsigned n) {
+ return (serverheaders[n]);
+ }
void addserverheader (string const &s);
void removeserverheader (unsigned i);
void changeserverheader (unsigned i, string const &s);
- string dumpdir() const { return (dump_dir); }
+ string const &dumpdir() const { return (dump_dir); }
void dumpdir (string s) { dump_dir = s; }
unsigned softmaxconnrate() const { return soft_maxconnrate; }
@@ -128,19 +159,26 @@
return (dmode.modestr());
}
- string softmaxconnexcess() const {
+ string const &softmaxconnexcess() const {
return soft_maxconn_excess_prog;
}
void softmaxconnexcess(string const &s) {
soft_maxconn_excess_prog = s;
}
- string hardmaxconnexcess() const {
+ string const &hardmaxconnexcess() const {
return hard_maxconn_excess_prog;
}
void hardmaxconnexcess(string const &s) {
hard_maxconn_excess_prog = s;
}
+ void onstart(string s) { on_start = s; }
+ string const &onstart() const { return on_start; }
+ void onend(string s) { on_end = s; }
+ string const &onend() const { return on_end; }
+ void onfail(string s) { on_fail = s; }
+ string const &onfail() const { return on_fail; }
+
private:
void setbackend (string const &s, string const &hostmatch,
@@ -156,8 +194,8 @@
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;
@@ -166,6 +204,7 @@
static bool debug_flag;
static bool add_x_forwarded_for;
static bool sticky_http;
+ static bool replace_host_header;
static unsigned max_conn;
static string external_algorithm;
static string pid_file;
@@ -187,6 +226,7 @@
static string soft_maxconn_excess_prog;
static string hard_maxconn_excess_prog;
static unsigned dns_cache_timeout;
+ static string on_start, on_end, on_fail;
};
extern Config config;
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/config/config1.cc
^
|
@@ -7,7 +7,9 @@
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;
@@ -16,6 +18,7 @@
bool Config::debug_flag = false;
bool Config::add_x_forwarded_for = false;
bool Config::sticky_http = false;
+bool Config::replace_host_header = false;
unsigned Config::max_conn = 0;
string Config::external_algorithm = "";
string Config::pid_file = "";
@@ -37,6 +40,9 @@
string Config::soft_maxconn_excess_prog = "";
string Config::hard_maxconn_excess_prog = "";
unsigned Config::dns_cache_timeout = 3600;
+string Config::on_start = "";
+string Config::on_end = "";
+string Config::on_fail = "";
Config::Config () {
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/config/deleteallow.cc
^
|
@@ -2,8 +2,7 @@
void Config::deleteallow(unsigned index) {
if (index >= allowlist.size())
- throw static_cast<Error>
- ("Index out of range, cannot delete allow-from");
+ throw Error("Index out of range, cannot delete allow-from");
allowlist.erase(allowlist.begin() + index,
allowlist.begin() + index + 1);
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/config/deletedeny.cc
^
|
@@ -2,8 +2,7 @@
void Config::deletedeny(unsigned index) {
if (index >= denylist.size())
- throw static_cast<Error>
- ("Index out of range, cannot delete deny-from");
+ throw Error("Index out of range, cannot delete deny-from");
denylist.erase(denylist.begin() + index,
denylist.begin() + index + 1);
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/config/parsecmdline.cc
^
|
@@ -13,50 +13,53 @@
}
// Not a single argument? Usage.
if (ac == 1)
- throw static_cast<Error>("Bad command line '") +
- cmdline + "'\n" + USAGE;
+ throw Error("Bad command line '" + cmdline + "'\n" + USAGE);
-# define OPTSTRING "?a:A:B:b:c:CDd:E:e:fF:g:hH:l:" \
- "m:M:nPp:Q:r:R:Ss:t:T:u:U:vVW:w:xX"
+# define OPTSTRING "?a:A:B:b:c:CDd:E:e:fF:g:hH:Il:" \
+ "m:M:nPp:Q:r:R:Ss:t:T:u:U:vVW:w:xXy:z:Z:"
# ifdef HAVE_GETOPT_LONG
static struct option longopts[] = {
- { "allow-from", required_argument, 0, 'a' },
- { "deny-from", required_argument, 0, 'A' },
- { "backend", required_argument, 0, 'b' },
- { "buffer-size", required_argument, 0, 'B' },
- { "checkup-interval", required_argument, 0, 'c' },
- { "close-sockets-fast", no_argument, 0, 'C' },
- { "debug", no_argument, 0, 'D' },
- { "dispatch-mode", required_argument, 0, 'd' },
- { "hard-maxconn-excess", required_argument, 0, 'E' },
- { "soft-maxconn-excess", required_argument, 0, 'e' },
- { "dns-cache-timeout", required_argument, 0, 'F' },
- { "foreground", no_argument, 0, 'f' },
- { "backend-check", required_argument, 0, 'g' },
- { "help", no_argument, 0, 'h' },
- { "add-server-header", required_argument, 0, 'H' },
- { "log-traffic-dir", required_argument, 0, 'l' },
- { "max-connections", required_argument, 0, 'm' },
- { "host-match", required_argument, 0, 'M' },
- { "tryout", no_argument, 0, 'n' },
- { "prefix-timestamp", no_argument, 0, 'P' },
- { "pidfile", required_argument, 0, 'p' },
- { "soft-maxconnrate", required_argument, 0, 'r' },
- { "quit-after", required_argument, 0, 'Q' },
- { "hard-maxconnrate", required_argument, 0, 'R' },
- { "server", required_argument, 0, 's' },
- { "sticky-http", no_argument, 0, 'S' },
- { "backend-timeout", required_argument, 0, 't' },
- { "client-timeout", required_argument, 0, 'T' },
- { "time-interval", required_argument, 0, 'u' },
- { "defer-time", required_argument, 0, 'U' },
- { "verbose", no_argument, 0, 'v' },
- { "version", no_argument, 0, 'V' },
- { "wakeup-interval", required_argument, 0, 'w' },
- { "web-interface", required_argument, 0, 'W' },
- { "add-xr-version", no_argument, 0, 'X' },
- { "add-x-forwarded-for", no_argument, 0, 'x' },
- { 0, 0, 0, 0 }
+ { "allow-from", required_argument, 0, 'a' },
+ { "deny-from", required_argument, 0, 'A' },
+ { "backend", required_argument, 0, 'b' },
+ { "buffer-size", required_argument, 0, 'B' },
+ { "checkup-interval", required_argument, 0, 'c' },
+ { "close-sockets-fast", no_argument, 0, 'C' },
+ { "debug", no_argument, 0, 'D' },
+ { "dispatch-mode", required_argument, 0, 'd' },
+ { "hard-maxconn-excess", required_argument, 0, 'E' },
+ { "soft-maxconn-excess", required_argument, 0, 'e' },
+ { "dns-cache-timeout", required_argument, 0, 'F' },
+ { "foreground", no_argument, 0, 'f' },
+ { "backend-check", required_argument, 0, 'g' },
+ { "help", no_argument, 0, 'h' },
+ { "add-server-header", required_argument, 0, 'H' },
+ { "replace-host-header", no_argument, 0, 'I' },
+ { "log-traffic-dir", required_argument, 0, 'l' },
+ { "max-connections", required_argument, 0, 'm' },
+ { "host-match", required_argument, 0, 'M' },
+ { "tryout", no_argument, 0, 'n' },
+ { "prefix-timestamp", no_argument, 0, 'P' },
+ { "pidfile", required_argument, 0, 'p' },
+ { "soft-maxconnrate", required_argument, 0, 'r' },
+ { "quit-after", required_argument, 0, 'Q' },
+ { "hard-maxconnrate", required_argument, 0, 'R' },
+ { "server", required_argument, 0, 's' },
+ { "sticky-http", no_argument, 0, 'S' },
+ { "backend-timeout", required_argument, 0, 't' },
+ { "client-timeout", required_argument, 0, 'T' },
+ { "time-interval", required_argument, 0, 'u' },
+ { "defer-time", required_argument, 0, 'U' },
+ { "verbose", no_argument, 0, 'v' },
+ { "version", no_argument, 0, 'V' },
+ { "wakeup-interval", required_argument, 0, 'w' },
+ { "web-interface", required_argument, 0, 'W' },
+ { "add-xr-version", no_argument, 0, 'X' },
+ { "add-x-forwarded-for", no_argument, 0, 'x' },
+ { "onfail", required_argument, 0, 'y' },
+ { "onstart", required_argument, 0, 'z' },
+ { "onend", required_argument, 0, 'Z' },
+ { 0, 0, 0, 0 }
};
# endif
@@ -65,6 +68,7 @@
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)
@@ -116,11 +120,14 @@
break;
case 'h':
case '?':
- throw static_cast<Error>(USAGE);
+ throw Error(USAGE);
break;
case 'H':
addserverheader (optarg);
break;
+ case 'I':
+ replacehostheader(true);
+ break;
case 'l':
dumpdir (optarg);
break;
@@ -155,10 +162,28 @@
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);
@@ -224,28 +249,34 @@
case 'x':
add_x_forwarded_for = true;
break;
+ case 'y':
+ onfail(optarg);
+ break;
+ case 'z':
+ onstart(optarg);
+ break;
+ case 'Z':
+ onend(optarg);
+ break;
default:
- throw static_cast<Error>("Unknown flag, try 'xr -h' for usage");
+ throw Error("Unknown flag, try 'xr -h' for usage");
break;
}
}
// Sanity checks.
if (ac != optind)
- throw static_cast<Error>("Bad command line '") + cmdline + "'\n" +
- USAGE;
+ throw Error("Bad command line '" + cmdline + "'\n" + USAGE);
if (!backend_set)
- throw static_cast<Error>
- ("No backend defined, use '-b...' at least once, "
- "or try 'xr -h' for usage");
+ throw Error("No backend defined, use '-b...' at least once, "
+ "or try 'xr -h' for usage");
if (checkup && wakeup) {
if (!wakeup_used)
wakeup = 0;
else
- throw static_cast<Error>
- ("Use either --checkup-interval or --wakeup-interval, "
- "but not both");
+ throw Error("Use either --checkup-interval or --wakeup-interval, "
+ "but not both");
}
// In tryout mode, stop now.
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/config/setbackend.cc
^
|
@@ -4,10 +4,9 @@
BackendCheck const &backend_check) {
vector<string> parts = str2parts (str, ':');
if (parts.size() < 2 || parts.size() > 4)
- throw static_cast<Error>
- ("Bad back end specifier in '-b") + str +
- "', expected: SERVER:PORT or SERVER:PORT:MAXCONNECTIONS or "
- "SERVER:PORT:MAXCONNECTIONS:WEIGHT";
+ throw Error("Bad back end specifier in '-b" + str +
+ "', expected: SERVER:PORT or SERVER:PORT:MAXCONNECTIONS"
+ " or SERVER:PORT:MAXCONNECTIONS:WEIGHT");
BackendDef *bdp = 0;
if (parts.size() == 2)
@@ -17,7 +16,7 @@
else if (parts.size() == 4)
bdp = new BackendDef(parts[0], parts[1], parts[2], parts[3]);
if (!bdp)
- throw static_cast<Error>("Memory fault in Config::setbackend");
+ throw Error("Memory fault in Config::setbackend");
bdp->hostmatch(host);
bdp->backendcheck(backend_check);
blist.push_back (*bdp);
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/config/setdispatcmode.cc
^
|
@@ -33,12 +33,12 @@
dmode.mode (Dispatchmode::m_lax_stored_ip);
ipstoretimeout(setinteger(s.substr(2)));
} else if (s.substr(0, 14) == "lax-stored-ip:") {
- dmode.mode (Dispatchmode::m_strict_stored_ip);
+ dmode.mode (Dispatchmode::m_lax_stored_ip);
ipstoretimeout(setinteger(s.substr(14)));
} else
- throw static_cast<Error>("Bad dispatch mode -d") + s;
+ throw Error("Bad dispatch mode -d" + s);
if (dmode.mode() == Dispatchmode::m_external &&
external_algorithm.size() < 1)
- throw static_cast<Error>("External algorithm handler missing");
+ throw Error("External algorithm handler missing");
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/config/setinteger.cc
^
|
@@ -3,7 +3,6 @@
int Config::setinteger (string s) const {
int ret;
if (sscanf (s.c_str(), "%d", &ret) < 1)
- throw static_cast<Error>("Bad numeric specifier in '") + s +
- ": not a number";
+ throw Error("Bad numeric specifier in '" + s + ": not a number");
return (ret);
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/config/setserver.cc
^
|
@@ -4,8 +4,7 @@
// Split into 3 parts
vector<string> parts = str2parts (str, ':');
if (parts.size() != 3)
- throw static_cast<Error>
- ("Bad server specifier, expected: TYPE:IPADDRESS:PORT");
+ throw Error("Bad server specifier, expected: TYPE:IPADDRESS:PORT");
// Store type, IP and port
styp.type (parts[0]);
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/config/setwebinterface.cc
^
|
@@ -3,8 +3,8 @@
void Config::setwebinterface (string str) {
vector<string> parts = str2parts (str, ':');
if (parts.size() != 2)
- throw static_cast<Error>("Bad webinterface specifier in '-W") +
- str + "', expected: IP:PORT";
+ throw Error("Bad webinterface specifier in '-W" +
+ str + "', expected: IP:PORT");
use_webinterface = true;
webinterface_ip = parts[0];
|
[-]
[+]
|
Deleted |
crossroads-devel.tar.gz/xr/dispatcher
^
|
-(directory)
|
[-]
[+]
|
Deleted |
crossroads-devel.tar.gz/xr/dispatcher/dispatcher
^
|
@@ -1,51 +0,0 @@
-#ifndef _DISPATCHER_
-#define _DISPATCHER_
-
-#include "sys/sys"
-#include "balancer/balancer"
-#include "config/config"
-#include "ThreadsAndMutexes/thread/thread"
-#include "ThreadsAndMutexes/threadlist/threadlist"
-#include "backendvector/backendvector"
-#include "netbuffer/netbuffer"
-
-// Dispatching algorithm workers
-#include "DispatchAlgorithms/algorithm/algorithm"
-#include "DispatchAlgorithms/roundrobin/roundrobin"
-#include "DispatchAlgorithms/firstactive/firstactive"
-#include "DispatchAlgorithms/leastconn/leastconn"
-#include "DispatchAlgorithms/external/external"
-#include "DispatchAlgorithms/hashedip/hashedip"
-#include "DispatchAlgorithms/storedip/storedip"
-#include "DispatchAlgorithms/weightedload/weightedload"
-
-class Dispatcher: public Thread {
-public:
-
- Dispatcher (int fd, struct in_addr ip);
- virtual ~Dispatcher();
-
- virtual void execute() = 0;
- virtual void dispatch() = 0;
- virtual void handle() = 0;
-
- int targetbackend() const { return target_backend; }
- void targetbackend(int t) { target_backend = t; }
- struct in_addr clientip() const { return client_ip; }
- int clientfd() const { return client_fd; }
- void clientfd(int c) { client_fd = c; }
- int backendfd() const { return backend_fd; }
- void backendfd(int b) { backend_fd = b; }
- Algorithm *algorithm() const { return algo; }
-
- BackendVector &targetlist() { return target_list; }
- void targetlist (BackendVector t) { target_list = t; }
-
-private:
- struct in_addr client_ip;
- int target_backend, client_fd, backend_fd;
- Algorithm *algo;
- BackendVector target_list;
-};
-
-#endif
|
[-]
[+]
|
Deleted |
crossroads-devel.tar.gz/xr/dispatcher/dispatcher1.cc
^
|
@@ -1,40 +0,0 @@
-#include "dispatcher"
-
-Dispatcher::Dispatcher(int cfd, struct in_addr cip):
- Thread(), client_ip(cip), target_backend(-1), client_fd(cfd),
- backend_fd(-1), target_list() {
-
- // Instantiate dispatchmode algorithm
- switch (config.dispatchmode()) {
- case Dispatchmode::m_roundrobin:
- algo = new Roundrobin;
- break;
- case Dispatchmode::m_firstactive:
- algo = new Firstactive;
- break;
- case Dispatchmode::m_external:
- algo = new External;
- break;
- case Dispatchmode::m_strict_hashed_ip:
- case Dispatchmode::m_lax_hashed_ip:
- algo = new HashedIp;
- break;
- case Dispatchmode::m_strict_stored_ip:
- case Dispatchmode::m_lax_stored_ip:
- algo = new StoredIp;
- break;
- case Dispatchmode::m_weighted_load:
- algo = new Weightedload;
- break;
- case Dispatchmode::m_leastconn:
- default:
- algo = new Leastconn;
- break;
- }
-
- // NOTE: Memory errors for algorithm pointer are not handled here,
- // but in dispatch() (don't want to throw up in the constructor)
-
- debugmsg("Dispatcher instantiated.\n");
-}
-
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/dnsentry/resolve.cc
^
|
@@ -13,8 +13,8 @@
Mutex::unlock((void*)gethostbyname);
if (!hostaddr)
- throw static_cast<Error>("Failed to resolve host '") + h + "'";
+ throw Error("Failed to resolve host '" + h + "'");
- debugmsg(Mstr("Host ") + h + "resolved\n");
+ debugmsg(Mstr("Host ") + h + " resolved\n");
return result;
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/etc/Makefile.class
^
|
@@ -2,17 +2,23 @@
OBJ = $(patsubst %.cc, $(BASE)/xr/$(BUILDDIR)/$(DIR)_%.o, $(SRC))
DIR = $(shell pwd | sed 's:.*/::')
SYS = $(shell uname)
+HST = $(shell hostname)
+# CCC = -DCONNECTCHECK_ONLY_WRITABLE
+
+ifeq ($(HST), Thera.local)
+ ERRFLAG = -Werror
+endif
class-compile: $(OBJ)
$(BASE)/xr/$(BUILDDIR)/$(DIR)_%.o: %.cc
@echo "Compiling: " `pwd` $<
- @$(CONF_CC) $(PROF) $(PROFILER) $(CONF_OPTFLAGS) \
- -DVER='"$(VER)"' -DAUTHOR='"$(AUTHOR)"' \
+ $(CONF_CC) $(PROF) $(PROFILER) $(CONF_OPTFLAGS) \
+ -DVER='"$(VER)"' -DAUTHOR='"$(AUTHOR)"' -DHST='"$(HST)"' \
-DMAINTAINER='"$(MAINTAINER)"' -DDISTSITE='"$(DISTSITE)"' \
- -DSYS='"$(SYS)"' -D$(SYS) \
+ -DSYS='"$(SYS)"' -D$(SYS) $(MEMDEBUG) $(CCC) \
-DCONF_CC='"$(CONF_CC)"' -DCONF_LIB='"$(CONF_LIB)"' \
-DCONF_OPTFLAGS='"$(CONF_OPTFLAGS)"' $(CONF_STRNSTR) \
$(CONF_GETOPT) $(CONF_GETOPT_LONG) $(CONF_INET_ATON) \
-I$(BASE)/xr \
- -c -g -Wall -o $@ $<
+ -c -g -Wall $(ERRFLAG) -o $@ $<
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/etc/c-conf
^
|
@@ -157,18 +157,21 @@
sub findbin($) {
my $bin = shift;
my $bestx = undef;
- my $bestver = 0;
+ my $bestver = -1;
foreach my $d (split (/:/, $ENV{PATH})) {
- for my $x (glob("$d/$bin"), glob("$d/$bin.exe"),
- glob("$d/$bin-*"), glob("$d/$bin-*.exe")) {
+ my @cand = (glob("$d/$bin"), glob("$d/$bin.exe"),
+ glob("$d/$bin-*"), glob("$d/$bin-*.exe"));
+ msg ("Candidates for '$bin' in '$d': [@cand]\n");
+ for my $x (@cand) {
if (-x $x) {
my $ver = $x;
$ver =~ s{^.*/[^\d]*}{};
$ver = sprintf("%g", $ver);
- # msg ("Candidate for '$bin': $x, version $ver\n");
+ msg ("Version of $x: $ver\n");
if ($bestver < $ver or !$bestx) {
$bestver = $ver;
$bestx = $x;
+ msg (" .. best so far\n");
}
}
}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/etc/status-nosavebutton.xslt
^
|
@@ -0,0 +1,876 @@
+<?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 > 0">
+ (anticipating <xsl:value-of select="anticipated"/>)
+ </xsl:if>
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>Connect failures</td>
+ <td colspan="2">
+ <xsl:value-of select="connecterrors"/>
+ </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>
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/etc/status-savebutton.xslt
^
|
@@ -0,0 +1,893 @@
+<?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 = document.getElementById(name);
+ var val = elem.value;
+ alert('name: ' + name + ', value: ' + val + ', uri: ' + uri);
+ if (val != "")
+ document.location = uri + encodeURIComponent(val);
+ 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"/></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" align="right">
+ <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}"/>
+ <input type="button" value="Save"
+ onclick="save('/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}"/>
+ <input type="button" value="Save"
+ onclick="save('/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 align="right">
+ <input type="text" size="8" name="clientreadtimeout"
+ id="clientreadtimeout" value="{clientreadtimeout}"/>
+ <input type="button" value="Save"
+ onclick="save('/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 align="right">
+ <input type="text" size="8" name="clientwritetimeout"
+ id="clientwritetimeout" value="{clientwritetimeout}"/>
+ <input type="button" value="Save"
+ onchange="save('/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 align="right">
+ <input type="text" size="8" name="backendreadtimeout"
+ id="backendreadtimeout" value="{backendreadtimeout}"/>
+ <input type="button" value="Save"
+ onclick="save('/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}"/>
+ <input type="button" value="Save"
+ onclick="save('/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}"/>
+ <input type="button" value="Save"
+ onclick="save('/server/dnscachetimeout/', 'dnscachetimeout');"/>
+ </td>
+ </tr>
+
+ <tr>
+ <td>Fast sockets closing</td>
+ <td colspan="2">eliminates TIME_WAIT state</td>
+ <td align="right">
+ <xsl:choose>
+ <xsl:when test="closesocketsfast = 0">
+ <select name="closesocketsfast" id="closesocketsfast">
+ <option value="on">yes</option>
+ <option value="off" selected="1">no</option>
+ </select>
+ </xsl:when>
+ <xsl:otherwise>
+ <select name="closesocketsfast" id="closesocketsfast">
+ <option value="on" selected="1">yes</option>
+ <option value="off">no</option>
+ </select>
+ </xsl:otherwise>
+ </xsl:choose>
+ <input type="button" value="Save"
+ onclick="save('/server/closesocketsfast/', 'closesocketsfast');"/>
+ </td>
+ </tr>
+ <tr>
+ <td>Debugging</td>
+ <td colspan="2">Verbose logging</td>
+ <td align="right">
+ <xsl:choose>
+ <xsl:when test="debugging/verbose = 0">
+ <select name="serververbose" id="serververbose">
+ <option value="on">yes</option>
+ <option value="off" selected="1">no</option>
+ </select>
+ </xsl:when>
+ <xsl:otherwise>
+ <select name="serververbose" id="serververbose">
+ <option value="on" selected="1">yes</option>
+ <option value="off">no</option>
+ </select>
+ </xsl:otherwise>
+ </xsl:choose>
+ <input type="button" value="Save"
+ onclick="save('/server/verbose/', 'serververbose');"/>
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td colspan="2">Debug logging</td>
+ <td align="right">
+ <xsl:choose>
+ <xsl:when test="debugging/debug = 0">
+ <select name="serverdebug" id="serverdebug">
+ <option value="yes">yes</option>
+ <option value="no" selected="1">no</option>
+ </select>
+ </xsl:when>
+ <xsl:otherwise>
+ <select name="serverdebug" id="serverdebug">
+ <option value="yes" selected="1">yes</option>
+ <option value="no">no</option>
+ </select>
+ </xsl:otherwise>
+ </xsl:choose>
+ <input type="button" value="Save"
+ onclick="save('/server/debug/', 'serververbose');"/>
+ </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}"/>
+ <input type="button" value="Save"
+ onclick="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}"/>
+ <input type="button" value="Save"
+ onclick="save('/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}"/>
+ <input type="button" value="Save"
+ onclick="save('/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}"/>
+ <input type="button" value="Save"
+ onclick="save('/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}"/>
+ <input type="button" value="Save"
+ onclick="save('/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 > 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>
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/etc/status.xslt
^
|
+(symlink to status-nosavebutton.xslt)
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/etc/usage.txt
^
|
@@ -59,7 +59,7 @@
-f, --foreground
Suppresses forking/threading, only for debugging. Also suppresses
wakeups (-w), checkups (-c) and the webinterface (-W).
- -g, --backend-check METHOD
+ -g METHOD, --backend-check METHOD
Defines how back ends are checked. This flag must be specified
PRIOR to defining back ends with -b... The checker will then
apply to all next back ends. Alternatives are:
@@ -71,15 +71,20 @@
/URI is not given, then "/" is assumed.
external:PROGRAM - The PROGRAM is called with the arguments
"IP:PORT", availability as "available" or "unavailable", and
- the number of connections. The program must exit(0) to
- indicate that the back end is alive.
+ the number of connections. The program must echo 0 to indicate
+ that the back end is alive.
The default behavior is a TCP connect, to the back end's IP, at
the back end's port. Use "-g connect::" to reset previous flags
to the default.
-h, -?, --help
This text.
-H HDR, --add-server-header HDR
- Inserts HDR into back end bound HTTP messages.
+ Inserts HDR into back end bound HTTP messages. The header value is
+ appended when a pre-existing header is present.
+ -I HDR, --replace-host-header HDR
+ Inserts "Host: <backend>" into back end bound HTTP messages.
+ Pre-existing Host headers are overwritten. The value of <backend> is
+ the server name as in the setting of --backend (-b).
-l DIR, --log-traffic-dir DIR
Log passing traffic with dumps in DIR. Only for debugging, slows
down the balancer.
@@ -97,12 +102,12 @@
FILE is written with the PID of XR upon startup
-Q REQUESTS, --quit-after REQUESTS
Stops the balancer after REQUESTS hits. For debugging / loadtesting.
- -r, --soft-maxconnrate MAXCONS
+ -r MAXCONS, --soft-maxconnrate MAXCONS
Sets the "SOFT" maximum average number of connections per IP allowed
within a given time period (see -U, --time-interval). If a
particular IP exceeds this number, then their connection is
deferred (see -u, --defer-time). Default is 0 (disabled).
- -R, --hard-maxconnrate MAXCONS
+ -R MAXCONS, --hard-maxconnrate MAXCONS
Sets the "HARD" maximum average number of connections per IP allowed
within a given time period (see -U, --time-interval). If a
particular IP exceeds this number, then their connection is
@@ -113,21 +118,23 @@
Enables sticky HTTP sessions by injecting XRTarget cookies into HTTP
streams. Only effective with -s http:....
-s TYPE:IPADDRESS:PORT, --server TYPE:IPADDRESS:PORT
- Specifies the server. TYPE is tcp or http. IPADDRESS is the IP address
- to listen to. PORT defines the TCP port to listen (for type tcp or
- http); when port is 0, XR will listen to stdin (inetd-mode).
+ Specifies the server. TYPE is tcp or http or udp. IPADDRESS is the IP
+ address to listen to. PORT defines the TCP port to listen; when port
+ is 0, XR will listen to stdin (inetd-mode, not available for udp).
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.
- -u, --defer-time USEC
+ 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
will last, in microseconds. Default is 500000 (0.5 seconds).
- -U, --time-interval SEC
+ -U SEC, --time-interval SEC
If either --soft-maxconnrate or --hard-maxconnrate is specified, this
option allows you to specify the time period to which those numbers of
connections apply. For example, "-r 200 -U 60" would trigger the "soft"
@@ -149,6 +156,16 @@
-x, --add-x-forwarded-for
Adds X-Forwarded-For with external IP address to back end streams in
HTTP messages.
+ -y CMD, --onfail CMD
+ Runs CMD when XR fails to connect to a back end. The arguments
+ to the command are: the client's IP address, and the back end address.
+ -z CMD, --onstart CMD
+ Runs CMD just before letting a back end handle a client's connection.
+ For the arguments of CMD see -y.
+ -Z CMD, --onend CMD
+ Runs CMD after successful termination of a client. For the
+ arguments of CMD see -y.
+
XR's messages are sent to stderr. Invoke XR daemons using something like
"xr -b ... [other flags] 2>&1 | logger &", or use xrctl.
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/fdset/fdset
^
|
@@ -11,29 +11,27 @@
public:
Fdset(int t);
- int timeout() const {
- return (tsec);
- }
- void timeout (int t) {
- tsec = t;
- }
- void add (int fd) {
- set.push_back(fd);
- }
- unsigned size() const {
- return (set.size());
- }
- int fd (unsigned index) const {
- return (set[index]);
- }
-
- int readable() const;
- int writeable() const;
- int readwriteable() const;
+ int timeout() const { return tsec; }
+ void timeout (int t) { tsec = t; }
+
+ void add (int fd) { set.push_back(fd); }
+
+ unsigned size() const { return set.size(); }
+
+ int fd (unsigned index) { return set[index]; }
+
+ void wait(bool wait_read, bool wait_write);
+ void wait_rw() { wait(true, true); }
+ void wait_r() { wait(true, false); }
+ void wait_w() { wait(false, true); }
+
+ bool readable(int fd) { return FD_ISSET(fd, &readset); }
+ bool writeable(int fd) { return FD_ISSET(fd, &writeset); }
private:
int tsec;
+ fd_set readset, writeset, exceptset;
vector<int> set;
};
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/fdset/fdset1.cc
^
|
@@ -1,4 +1,7 @@
#include "fdset"
Fdset::Fdset (int t) : tsec(t), set() {
+ FD_ZERO(&readset);
+ FD_ZERO(&writeset);
+ FD_ZERO(&exceptset);
}
|
[-]
[+]
|
Deleted |
crossroads-devel.tar.gz/xr/fdset/readable.cc
^
|
@@ -1,66 +0,0 @@
-#include "fdset"
-
-int Fdset::readable() const {
- PROFILE("Fdset::readable");
-
- fd_set readset, exceptset;
- struct timeval tv, *tvp;
-
- // No fd's? Nothing is readable.
- if (set.size() < 1)
- return (-1);
-
- if (config.debug()) {
- ostringstream o;
- o << "Candidate readable fd's:";
- for (unsigned i = 0; i < set.size(); i++)
- o << ' ' << set[i];
- _debugmsg(o.str() + '\n');
- }
-
- // Prepare select sets.
- FD_ZERO (&readset);
- FD_ZERO (&exceptset);
- for (unsigned i = 0; i < set.size(); i++) {
- FD_SET (set[i], &readset);
- FD_SET (set[i], &exceptset);
- }
-
- // Prepare timout specifier.
- if (tsec) {
- tv.tv_sec = tsec;
- tv.tv_usec = 0;
- tvp = &tv;
- } else
- tvp = 0;
-
- // Run the select. Signal interrupts are returned as -1, so that
- // the caller can handle them gracefully.
- if (select (FD_SETSIZE, &readset, 0, &exceptset, tvp) < 0) {
- debugmsg (Mstr("Select interrupted with errno ") + errno +
- " while waiting for readable fd\n");
- if (errno != EINTR)
- throw static_cast<Error>
- ("Select failure: failed to wait for readable state: ") +
- strerror(errno);
- else
- return (-1);
- }
-
- // Check for exceptions.
- for (unsigned i = 0; i < set.size(); i++)
- if (FD_ISSET (set[i], &exceptset))
- throw static_cast<Error>("Exception on fd/socket ") + int(set[i]);
-
- // Check what's readable.
- for (unsigned i = 0; i < set.size(); i++)
- if (FD_ISSET (set[i], &readset)) {
- debugmsg (Mstr("Fd ") + set[i] + " has become readable\n");
- return (set[i]);
- }
-
- // Nothing..
- debugmsg ("No readable fd's at this time\n");
- return (-1);
-}
-
|
[-]
[+]
|
Deleted |
crossroads-devel.tar.gz/xr/fdset/readwriteable.cc
^
|
@@ -1,56 +0,0 @@
-#include "fdset"
-
-int Fdset::readwriteable() const {
- PROFILE("Fdset::readwriteable");
-
- fd_set readset, writeset, exceptset;
- struct timeval tv, *tvp;
-
- // No fd's? Nothing is readable.
- if (set.size() < 1)
- return (-1);
-
- // Prepare select sets.
- FD_ZERO (&readset);
- FD_ZERO (&writeset);
- FD_ZERO (&exceptset);
- for (unsigned i = 0; i < set.size(); i++) {
- FD_SET (set[i], &readset);
- FD_SET (set[i], &writeset);
- FD_SET (set[i], &exceptset);
- }
-
- // Prepare timout specifier.
- if (tsec) {
- tv.tv_sec = tsec;
- tv.tv_usec = 0;
- tvp = &tv;
- } else
- tvp = 0;
-
- // Run the select.
- if (select (FD_SETSIZE, &readset, &writeset, &exceptset, tvp) < 0) {
- if (errno != EINTR)
- throw static_cast<Error>
- ("Select failure: failed to wait for read/writeablestate: ")
- + strerror(errno);
- else
- return (-1);
- }
-
- // Check for exceptions.
- for (unsigned i = 0; i < set.size(); i++)
- if (FD_ISSET (set[i], &exceptset))
- throw static_cast<Error>("Exception on fd/socket ") + int(set[i]);
-
- // Check what's active.
- for (unsigned i = 0; i < set.size(); i++)
- if (FD_ISSET (set[i], &readset) && FD_ISSET (set[i], &writeset)) {
- debugmsg(Mstr("Fd " ) + set[i] + " has become read/writeable\n");
- return (set[i]);
- }
-
- // Nothing..
- return (-1);
-}
-
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/fdset/wait.cc
^
|
@@ -0,0 +1,65 @@
+#include "fdset"
+
+void Fdset::wait(bool wait_read, bool wait_write) {
+ PROFILE("Fdset::wait");
+
+ struct timeval tv, *tvp;
+
+ // No fd's? Nothing to wait for.
+ if (set.size() < 1)
+ throw Error("Internal jam in Fdset::wait(): no fd's to wait for");
+
+ // Prepare select sets.
+ FD_ZERO (&readset);
+ FD_ZERO (&writeset);
+ FD_ZERO (&exceptset);
+ for (unsigned i = 0; i < set.size(); i++) {
+ FD_SET (set[i], &readset);
+ FD_SET (set[i], &writeset);
+ FD_SET (set[i], &exceptset);
+ debugmsg(Mstr("About to wait for fd ") + Mstr(set[i]) + "\n");
+ }
+
+ // Prepare timout specifier.
+ if (tsec) {
+ tv.tv_sec = tsec;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ debugmsg(Mstr("Waiting limitation: ") + Mstr(tsec) + "\n");
+ } else {
+ tvp = 0;
+ debugmsg(Mstr("No waiting limitation\n"));
+ }
+
+ // Run the select.
+ if (select (FD_SETSIZE,
+ wait_read ? &readset : 0,
+ wait_write ? &writeset : 0,
+ &exceptset, tvp) < 0) {
+ if (errno != EINTR)
+ throw Error(string("Select failure: failed to wait: ") +
+ strerror(errno));
+ FD_ZERO(&readset);
+ FD_ZERO(&writeset);
+ FD_ZERO(&exceptset);
+ return;
+ }
+
+ // Check for exceptions.
+ for (unsigned i = 0; i < set.size(); i++)
+ if (FD_ISSET (set[i], &exceptset)) {
+ ostringstream o;
+ o << "Exception on fd/socket " << int(set[i]);
+ throw Error(o.str());
+ }
+
+ // More debugging
+ if (config.debug()) {
+ for (unsigned int i = 0; i < FD_SETSIZE; i++) {
+ if (FD_ISSET(i, &readset))
+ _debugmsg(Mstr("Fd ") + Mstr(i) + " is readable\n");
+ if (FD_ISSET(i, &writeset))
+ _debugmsg(Mstr("Fd ") + Mstr(i) + " is writeable\n");
+ }
+ }
+}
|
[-]
[+]
|
Deleted |
crossroads-devel.tar.gz/xr/fdset/writeable.cc
^
|
@@ -1,57 +0,0 @@
-#include "fdset"
-
-int Fdset::writeable() const {
- PROFILE("Fdset::writeable");
-
- fd_set writeset, exceptset;
- struct timeval tv, *tvp;
-
- // No fd's? Nothing is writeable.
- if (set.size() < 1)
- return (-1);
-
- // Prepare select sets.
- FD_ZERO (&writeset);
- FD_ZERO (&exceptset);
- for (unsigned i = 0; i < set.size(); i++) {
- FD_SET (set[i], &writeset);
- FD_SET (set[i], &exceptset);
- }
-
- // Prepare timout specifier.
- if (tsec) {
- tv.tv_sec = tsec;
- tv.tv_usec = 0;
- tvp = &tv;
- } else
- tvp = 0;
-
- // Run the select.
- if (select (FD_SETSIZE, 0, &writeset, &exceptset, tvp) < 0) {
- debugmsg (Mstr("Select interrupted with errno ") + errno +
- " while waiting for writeable fd\n");
- if (errno != EINTR)
- throw static_cast<Error>
- ("Select failure: failed to wait for writable state: ") +
- strerror(errno);
- else
- return (-1);
- }
-
- // Check for exceptions.
- for (unsigned i = 0; i < set.size(); i++)
- if (FD_ISSET (set[i], &exceptset))
- throw static_cast<Error>("Exception on fd/socket ") + int(set[i]);
-
- // Check what's writeable.
- for (unsigned i = 0; i < set.size(); i++)
- if (FD_ISSET (set[i], &writeset)) {
- debugmsg (Mstr("Fd ") + set[i] + " has become writeable\n");
- return (set[i]);
- }
-
- // Nothing..
- debugmsg ("No writeable fd's at this time\n");
- return (-1);
-}
-
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/httpbuffer/cookievalue.cc
^
|
@@ -4,16 +4,19 @@
PROFILE("Httpheader::cookievalue");
string cval = headerval ("Cookie");
- size_t pos;
+ string match = c;
+ if (match[match.size() - 1] != '=')
+ match += '=';
string ret = "";
- if ( (pos = cval.find (c)) != string::npos) {
- pos++;
- pos += c.size();
+ size_t pos = cval.find(match);
+ if (pos != string::npos) {
+ pos += match.size();
for (char ch = cval[pos];
pos < cval.size() && ch != ';' && ch != ',' && ch;
ch = cval[++pos]) {
ret += ch;
}
}
+ msg(Mstr("Cookie value '") + c + Mstr("' : '") + ret + "'\n");
return (ret);
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/httpbuffer/httpbuffer
^
|
@@ -19,18 +19,22 @@
bool headersreceived();
- string headerval (string var);
+ string headerval (string const &var);
string &firstline();
bool setversion(char v);
- void setheader (string var, string val);
- void setheader (string h);
+ void setheader (string const &var, string const &val);
+ void setheader (string const &h);
- void addheader (string var, string val);
- void addheader (string h);
+ void addheader (string const &var, string const &val);
+ void addheader (string const &h);
+
+ void replaceheader (string const &var, string const &val);
+ void replaceheader (string const &h);
string cookievalue (string var);
+ string paramvalue(string var);
RequestMethod requestmethod();
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/httpbuffer/paramvalue.cc
^
|
@@ -0,0 +1,21 @@
+#include "httpbuffer"
+
+string Httpbuffer::paramvalue (string c) {
+ PROFILE("Httpheader::paramvalue");
+
+ string uri = requesturi();
+ string match = c;
+ if (match[match.size() - 1] != '=')
+ match += '=';
+ string ret = "";
+ size_t pos = uri.find(match);
+ if (pos != string::npos) {
+ pos += match.size();
+ for (char ch = uri[pos];
+ pos < uri.size() && ch != '&' && ch != '?';
+ ch = uri[++pos])
+ ret += ch;
+ }
+ msg(Mstr("Param value '") + c + Mstr("' : '") + ret + "'\n");
+ return ret;
+}
|
[-]
[+]
|
Deleted |
crossroads-devel.tar.gz/xr/httpdispatcher
^
|
-(directory)
|
[-]
[+]
|
Deleted |
crossroads-devel.tar.gz/xr/httpdispatcher/dispatch.cc
^
|
@@ -1,84 +0,0 @@
-#include "httpdispatcher"
-
-void HttpDispatcher::dispatch() {
- PROFILE("HttpDispatcher::dispatch");
-
- unsigned stickytarget;
- string host_header = "";
-
- // Try to dispatch. Since we're in HTTP mode, we must return an
- // error page when dispatching fails.
- try {
-
- // 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()))
- throw static_cast<Error>("Didn't receive a valid "
- "client request.");
- msg ("Received client request: '" + buf.firstline() + "'\n");
-
- // See if hostmatching is used. This is true when a backend
- // matches against a non-dot host.
- bool hostmatchused = false;
- for (unsigned i = 0; i < balancer.nbackends(); i++)
- if (balancer.backend(i).hostmatch() != ".") {
- hostmatchused = true;
- break;
- }
- // Build new target list if host matching applies.
- if (hostmatchused) {
- host_header = buf.headerval ("Host");
- msg ("Will try to dispatch request host '" +
- host_header + "'\n");
-
- // We need to build tcpdispatcher's target list now!
- // Construct locally and poke into TcpDispatcher.
- msg ("Creating host-based target list for the HTTP dispatcher\n");
- BackendVector v;
- v.isdefined(true);
- for (unsigned i = 0; i < balancer.nbackends(); i++) {
- if ( (balancer.backend(i).available()) &&
- (!regexec (&(balancer.backend(i).hostregex()),
- host_header.c_str(), 0, 0, 0)) ) {
- v.add(i);
- if (config.verbose())
- msg (" Candidate target: " +
- balancer.backend(i).description() + "\n");
- }
- }
- targetlist(v);
- }
-
- // Dispatch as a normal backend if sticky HTTP is off, or if the
- // sticky target is badly specified.
- if (!config.stickyhttp() ||
- sscanf (buf.cookievalue ("XRTarget").c_str(),
- "%d", &stickytarget) < 1 ||
- stickytarget >= balancer.nbackends()) {
- issticky(false);
- TcpDispatcher::dispatch();
- } else {
- // Got a sticky target. Try to connect. If that fails, fallback
- // to non-sticky dispatching.
- targetbackend(stickytarget);
- Backend tb = balancer.backend(stickytarget);
- msg ("Sticky HTTP request for " + tb.description() + "\n");
- if (! tb.connect()) {
- balancer.backend(stickytarget).live(false);
- msg ("Failed to connect to back end " + tb.description() +
- ", trying to dispatch to other\n");
- issticky(false);
- TcpDispatcher::dispatch();
- } else {
- backendfd(tb.sock());
- issticky(true);
- }
- }
-
- } catch (Error const &e) {
- senderrorpage(e.what());
- throw e;
- }
-}
-
|
[-]
[+]
|
Deleted |
crossroads-devel.tar.gz/xr/httpdispatcher/handle.cc
^
|
@@ -1,91 +0,0 @@
-#include "httpdispatcher"
-
-void HttpDispatcher::handle() {
- PROFILE("HttpDispatcher::handle");
-
- // The client request was already retrieved before starting the
- // dispatcher. We can continue by applying server-directed headers.
- if (config.addxrversion())
- buf.setheader ("XR", VER);
- if (config.addxforwardedfor())
- buf.addheader ("X-Forwarded-For", string(inet_ntoa(clientip())));
- for (unsigned n = 0; n < config.nserverheaders(); n++)
- buf.setheader (config.serverheader(n));
-
- // Flush client info received so far to the back end.
- debugmsg("Sending client request to back end\n");
- buf.netwrite(backendfd(), config.backend_timeout());
-
- // Let's see if we will need to modify the server headers.
- bool modify_serverheaders = false;
- if (config.addxrversion() ||
- (config.stickyhttp() && !issticky()))
- modify_serverheaders = true;
-
- // Store the client request. May want to log it later.
- string client_request = buf.firstline();
-
- // Go into copy-thru mode. If required, catch the server headers on
- // their first appearance and modify them.
- bool backend_response_checked = false;
- while (1) {
- Fdset readset (config.client_timeout());
- readset.add(clientfd());
- readset.add(backendfd());
-
- int sock;
- if ((sock = readset.readable()) < 0)
- break;
-
- buf.reset();
-
- if (!buf.netread(sock))
- break;
-
- if (sock == backendfd() && modify_serverheaders) {
- debugmsg("Back end response seen, applying modifications\n");
- modify_serverheaders = false;
- while (! buf.headersreceived())
- if (!buf.netread (sock, config.backend_timeout()))
- throw static_cast<Error>
- ("Failed to get headers from back end");
- if (config.addxrversion())
- buf.setheader("XR", VER);
- if (config.stickyhttp() && !issticky()) {
- ostringstream o;
- o << "XRTarget=" << targetbackend();
- buf.setheader("Set-Cookie", o.str());
- }
- }
-
- // The back end response may now get flushed to the client.
- // If the response code is 4** or 5**, log it as a warning.
- if (!backend_response_checked &&
- sock == backendfd() && buf.headersreceived()) {
- string respcode = buf.stringat(9, 3);
- if (respcode[0] == '4' || respcode[0] == '5')
- warnmsg("HTTP back end indicates fault: '" +
- buf.firstline() + "' as response to '" +
- client_request + "'\n");
- backend_response_checked = true;
- }
-
- // Flush info to the other connected side.
- int othersock, timeout;
- if (sock == clientfd()) {
- othersock = backendfd();
- timeout = config.backend_timeout();
- } else {
- othersock = clientfd();
- timeout = config.client_timeout();
- }
-
- debugmsg (Mstr("Had data on ") + sock +
- (Mstr(", sending to ") + othersock) + "\n");
-
- buf.netwrite(othersock, timeout);
- if (sock == backendfd())
- balancer.backend(targetbackend()).addbytes(buf.bufsz());
- }
-
-}
|
[-]
[+]
|
Deleted |
crossroads-devel.tar.gz/xr/httpdispatcher/httpdispatcher
^
|
@@ -1,24 +0,0 @@
-#ifndef _HTTPDISPATCHER_
-#define _HTTPDISPATCHER_
-
-#include "../sys/sys"
-#include "../tcpdispatcher/tcpdispatcher"
-#include "../httpbuffer/httpbuffer"
-
-class HttpDispatcher: public TcpDispatcher {
-public:
- HttpDispatcher (int fd, struct in_addr ip);
-
- void dispatch();
- void handle();
- bool issticky() const { return (is_sticky); }
- void issticky (bool s) { is_sticky = s; }
-
-private:
- void senderrorpage(string const &desc);
-
- Httpbuffer buf;
- bool is_sticky;
-};
-
-#endif
|
[-]
[+]
|
Deleted |
crossroads-devel.tar.gz/xr/httpdispatcher/senderrorpage.cc
^
|
@@ -1,34 +0,0 @@
-#include "httpdispatcher"
-
-void HttpDispatcher::senderrorpage(string const &reason) {
- PROFILE("HttpDispatcher::senderrorpage");
-
- msg ("Sending error page to client: '" + reason + "'\n");
- try {
- string txt =
- "<html>\n"
- " <head>\n"
- " <title>Internal Server Error</title>\n"
- " </head>\n"
- " <body>\n"
- " <h1>Internal Server Error</h1>\n"
- " You request could not be completed. Please retry later.\n"
- " </body>\n"
- "</html>\n";
- ostringstream mess;
- mess <<
- "HTTP/1.0 502 Internal Server Error\r\n"
- "Content-Length: " << txt.size() << "\r\n"
- "XR-Reason: " << reason << "\r\n"
- "\r\n" <<
- txt;
- Netbuffer buf(mess.str());
- buf.netwrite(clientfd(), config.client_timeout());
- } catch (Error const &e) {
- // Silently discard, we are not interested in errors
- // that ocur when an error page is being sent
- // Mutex::lock(&cerr);
- // cerr << e.what() << " (while sending error page)\n";
- // Mutex::unlock(&cerr);
- }
-}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/ipstore
^
|
+(directory)
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/ipstore/activity.cc
^
|
@@ -0,0 +1,15 @@
+#include "ipstore"
+
+void IPStore::activity(struct in_addr clientip, unsigned curbackend) {
+ if (!onoff)
+ return;
+
+ msg(Mstr("Logging activity for back end ") + Mstr(curbackend) +
+ Mstr(" from ") + inet_ntoa(clientip) + "\n");
+
+ Mutex::lock(&store);
+ store[clientip].targetbackend = (int)curbackend;
+ store[clientip].lastaccess = time(0);
+ Mutex::unlock(&store);
+}
+
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/ipstore/anticipated.cc
^
|
@@ -0,0 +1,20 @@
+#include "ipstore"
+
+unsigned IPStore::anticipated(unsigned b) {
+ if (!onoff || b >= balancer.nbackends())
+ return 0;
+
+ unsigned ret = 0;
+
+ Mutex::lock(&store);
+ for (StoreMap::iterator iter = store.begin();
+ iter != store.end();
+ iter++)
+ if ((*iter).second.targetbackend == (int)b)
+ ret++;
+ Mutex::unlock(&store);
+
+ return ret;
+}
+
+
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/ipstore/clear.cc
^
|
@@ -0,0 +1,9 @@
+#include "ipstore"
+
+void IPStore::clear(struct in_addr clientip) {
+ debugmsg(Mstr("Erasing IP entry of ") +
+ Mstr(inet_ntoa(clientip)) + "\n");
+ Mutex::lock(&store);
+ store.erase(clientip);
+ Mutex::unlock(&store);
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/ipstore/ipstore
^
|
@@ -0,0 +1,41 @@
+#ifndef _IPSTORE_
+#define _IPSTORE_
+
+#include "sys/sys"
+#include "config/config"
+#include "timestamp/timestamp"
+#include "balancer/balancer"
+#include "ThreadsAndMutexes/mutex/mutex"
+
+class IPStore {
+public:
+ struct ClientData {
+ int targetbackend;
+ time_t lastaccess;
+ };
+
+ struct ClientDataCmp {
+ bool operator() (struct in_addr a, struct in_addr b) const {
+ long la, lb;
+ memcpy (&la, &a, sizeof(long));
+ memcpy (&lb, &b, sizeof(long));
+ return (la - lb) < 0;
+ }
+ };
+
+ typedef map<struct in_addr, ClientData, ClientDataCmp> StoreMap;
+
+ static int target(struct in_addr clientip);
+ static void activity(struct in_addr clientip, unsigned curbackend);
+ static unsigned anticipated(unsigned bckend);
+ static void clear(struct in_addr clientip);
+
+ static void on() { onoff = true; }
+ static void off() { onoff = false; }
+
+private:
+ static StoreMap store;
+ static bool onoff;
+};
+
+#endif
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/ipstore/target.cc
^
|
@@ -0,0 +1,45 @@
+#include "ipstore"
+
+IPStore::StoreMap IPStore::store;
+bool IPStore::onoff = false;
+
+int IPStore::target(struct in_addr clientip) {
+ time_t now = time(0);
+
+ // Weed out store. Done first, because the store should be up to date
+ // for some decisions below.
+ bool done = false;
+ Mutex::lock(&store);
+ while (!done) {
+ done = true;
+ for (StoreMap::iterator iter = store.begin();
+ iter != store.end();
+ iter++) {
+ if (now - ((*iter).second.lastaccess) > config.ipstoretimeout()) {
+ if (config.debug()) {
+ done = false;
+ Timestamp tm((*iter).second.lastaccess);
+ debugmsg (Mstr(inet_ntoa(iter->first)) +
+ Mstr(" visited on ") + tm.desc() + ", erasing\n");
+ }
+ store.erase(iter);
+ break;
+ }
+ }
+ }
+ Mutex::unlock(&store);
+
+ // Let's see if we know the client.
+ if (store.count(clientip) > 0) {
+ if (config.verbose()) {
+ Timestamp tm(store[clientip].lastaccess);
+ msg(Mstr("Client IP ") + Mstr(inet_ntoa(clientip)) +
+ " last visited on " + tm.desc() + " and went to " +
+ balancer.backend(store[clientip].targetbackend).description() +
+ "\n");
+ }
+ return store[clientip].targetbackend;
+ }
+ return -1;
+}
+
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/memory
^
|
+(directory)
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/memory/memdata.cc
^
|
@@ -0,0 +1,4 @@
+#include "memory"
+
+Memory::MemoryLog Memory::s_memlog;
+bool Memory::s_follow;
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/memory/memdelete.cc
^
|
@@ -0,0 +1,5 @@
+#include "memory"
+
+void Memory::operator delete(void *ptr) {
+ free(ptr);
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/memory/memdelete1.cc
^
|
@@ -0,0 +1,5 @@
+#include "memory"
+
+void Memory::operator delete[](void *ptr) {
+ free(ptr);
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/memory/memdisplay.cc
^
|
@@ -0,0 +1,13 @@
+#include "memory"
+
+void Memory::mem_display() {
+ Mutex::lock(&s_memlog);
+ for (unsigned i = 0; i < s_memlog.size(); i++) {
+ MemoryEntry ent = s_memlog[i];
+ Mutex::lock(&cout);
+ cout << "Memory::mem_display " << ent.ptr << ' ' << ent.sz
+ << ' ' << ent.desc << '\n';
+ Mutex::unlock(&cout);
+ }
+ Mutex::unlock(&s_memlog);
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/memory/memfollow.cc
^
|
@@ -0,0 +1,5 @@
+#include "memory"
+
+void Memory::mem_follow(bool b) {
+ s_follow = b;
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/memory/memfollow1.cc
^
|
@@ -0,0 +1,5 @@
+#include "memory"
+
+bool Memory::mem_follow() {
+ return s_follow;
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/memory/memfree.cc
^
|
@@ -0,0 +1,25 @@
+#include "memory"
+
+void Memory::free(void *ptr) {
+ if (!ptr)
+ return;
+
+ for (unsigned i = 0; i < s_memlog.size(); i++) {
+ Mutex::lock(&s_memlog);
+ MemoryEntry ent = s_memlog[i];
+ Mutex::unlock(&s_memlog);
+ if (ent.ptr == ptr) {
+ if (s_follow) {
+ Mutex::lock(&cout);
+ cout << "Memory::free(" << ptr << ")\n";
+ Mutex::unlock(&cout);
+ }
+ ::free (ent.ptr);
+ Mutex::lock(&s_memlog);
+ s_memlog.erase(s_memlog.begin() + i);
+ Mutex::unlock(&s_memlog);
+ return;
+ }
+ }
+ cerr << "FREE Request for non previously allocated memory\n";
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/memory/memmalloc.cc
^
|
@@ -0,0 +1,16 @@
+#include "memory"
+
+void *Memory::malloc(size_t sz, string const &desc) {
+ void *ptr = ::malloc(sz);
+ MemoryEntry ent = { ptr, sz, desc };
+ Mutex::lock(&s_memlog);
+ s_memlog.push_back(ent);
+ Mutex::unlock(&s_memlog);
+ if (s_follow) {
+ Mutex::lock(&cout);
+ cout << "Memory::malloc(" << sz << ") -> " << ptr << ' '
+ << desc << '\n';
+ Mutex::unlock(&cout);
+ }
+ return ptr;
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/memory/memmark.cc
^
|
@@ -0,0 +1,8 @@
+#include "memory"
+
+void Memory::mem_mark(string const &desc) {
+ MemoryEntry ent = { 0, 0, "MARK " + desc };
+ Mutex::lock(&s_memlog);
+ s_memlog.push_back(ent);
+ Mutex::unlock(&s_memlog);
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/memory/memnew.cc
^
|
@@ -0,0 +1,5 @@
+#include "memory"
+
+void *Memory::operator new(size_t sz) {
+ return malloc(sz);
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/memory/memnew1.cc
^
|
@@ -0,0 +1,5 @@
+#include "memory"
+
+void *Memory::operator new[](size_t sz) {
+ return malloc(sz);
+}
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/memory/memory
^
|
@@ -0,0 +1,40 @@
+#ifndef _MEMORY_
+#define _MEMORY_
+
+#include "sys/sys"
+#include "ThreadsAndMutexes/mutex/mutex"
+
+class Memory {
+public:
+ // Memory accessing functions
+ static void *malloc(size_t sz, string const &desc = "");
+ static void *realloc(void *ptr, size_t newsz, string const &desc = "");
+ static void free(void *ptr);
+ static void *operator new(size_t sz);
+ static void operator delete(void *ptr);
+ static void *operator new[](size_t sz);
+ static void operator delete[](void *ptr);
+
+ // Follow actions immediately?
+ static void mem_follow(bool b);
+ static bool mem_follow();
+
+ // Dump what we have
+ static void mem_display();
+
+ // Marker in the overview
+ static void mem_mark(string const &desc = "");
+
+ // Internal storage types
+ struct MemoryEntry {
+ void *ptr;
+ size_t sz;
+ string desc;
+ };
+ typedef vector<MemoryEntry> MemoryLog;
+private:
+ static MemoryLog s_memlog;
+ static bool s_follow;
+};
+
+#endif
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/memory/memrealloc.cc
^
|
@@ -0,0 +1,29 @@
+#include "memory"
+
+void *Memory::realloc(void *ptr, size_t newsz, string const &desc) {
+ if (!newsz) {
+ free(ptr);
+ return 0;
+ } else {
+ for (unsigned i = 0; i < s_memlog.size(); i++) {
+ MemoryEntry ent = s_memlog[i];
+ if (ent.ptr == ptr) {
+ ent.ptr = ::realloc(ptr, newsz);
+ ent.sz = newsz;
+ ent.desc = desc;
+ Mutex::lock(&s_memlog);
+ s_memlog[i] = ent;
+ Mutex::unlock(&s_memlog);
+ if (s_follow) {
+ Mutex::lock(&cout);
+ cout << "Memory::realloc(" << ptr << ", " << newsz
+ << ") -> " << ent.ptr << ' ' << desc << '\n';
+ Mutex::unlock(&cout);
+ }
+ return ent.ptr;
+ }
+ }
+ cerr << "REALLOC Request for non previously allocated memory\n";
+ }
+ return 0;
+}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/mstr/mstr
^
|
@@ -7,6 +7,11 @@
public:
Mstr(string s): string(s) {}
Mstr(char const *s): string(s) {}
+ Mstr(int i) {
+ ostringstream o;
+ o << i;
+ *this = o.str();
+ }
Mstr const &operator+ (int i) {
ostringstream o;
o << i;
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/netbuffer/checkspace.cc
^
|
@@ -11,20 +11,22 @@
if (extra == config.buffersize() &&
config.stype() == Servertype::t_http)
buf_alloced <<= 1;
- msg (Mstr("Reserving ") + buf_alloced + " bytes for network buffer\n");
+ debugmsg (Mstr("Netbuffer: reserving ") + buf_alloced +
+ " bytes for network buffer\n");
LOCK_MALLOC;
buf_data = (char*)malloc(buf_alloced);
UNLOCK_MALLOC;
if (! buf_data)
- throw static_cast<Error>("Memory fault in Netbuffer::check_space");
+ throw Error("Memory fault in Netbuffer::check_space");
} else if (buf_sz + extra > buf_alloced) {
- msg((Mstr("Reallocating net buffer from ") + buf_alloced) +
- (Mstr(" to ") + (buf_alloced + extra)) + " bytes\n");
+ debugmsg((Mstr("Netbuffer: reallocating net buffer from ") +
+ buf_alloced) +
+ (Mstr(" to ") + (buf_alloced + extra)) + " bytes\n");
buf_alloced += extra;
LOCK_MALLOC;
buf_data = (char*)realloc(buf_data, buf_alloced);
UNLOCK_MALLOC;
if (! buf_data)
- throw static_cast<Error>("Memory fault in Netbuffer::check_space");
+ throw Error("Memory fault in Netbuffer::check_space");
}
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/netbuffer/copy.cc
^
|
@@ -1,13 +1,15 @@
#include "netbuffer"
void Netbuffer::copy (Netbuffer const &other) {
+ debugmsg("Netbuffer: copying other\n");
+
buf_sz = other.buf_sz;
buf_alloced = other.buf_alloced;
LOCK_MALLOC;
buf_data = (char*)malloc(buf_alloced);
UNLOCK_MALLOC;
if (!buf_data)
- throw static_cast<Error>("Memory fault in Netbuffer::copy");
+ throw Error("Memory fault in Netbuffer::copy");
memcpy (buf_data, other.buf_data, buf_alloced);
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/netbuffer/destroy.cc
^
|
@@ -1,7 +1,9 @@
#include "netbuffer"
void Netbuffer::destroy() {
- delete buf_data;
+ debugmsg(Mstr("Netbuffer: destroying ") + Mstr(buf_alloced) +
+ Mstr( " bytes\n"));
+ free(buf_data);
buf_data = 0;
buf_sz = 0;
buf_alloced = 0;
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/netbuffer/insertat.cc
^
|
@@ -2,6 +2,8 @@
bool Netbuffer::insertat(unsigned index, char const *s, unsigned len) {
PROFILE("Netbuffer::insertat");
+ debugmsg(Mstr("Netbuffer: inserting ") + Mstr(s) + Mstr(" at ") +
+ Mstr(index) + "\n");
if (!len)
len = strlen(s);
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/netbuffer/netbuffer
^
|
@@ -2,6 +2,8 @@
#define _NETBUFFER_
#include "sys/sys"
+#include "memory/memory"
+
#include "error/error"
#include "config/config"
#include "profiler/profiler"
@@ -18,7 +20,7 @@
#define UNLOCK_MALLOC
#endif
-class Netbuffer {
+class Netbuffer MEM(: public Memory) {
public:
Netbuffer();
Netbuffer (Netbuffer const &other);
@@ -55,6 +57,7 @@
void check_space(unsigned extra);
string printable(char c) const;
+ string printable() const;
char *buf_data;
unsigned buf_sz;
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/netbuffer/netbuffer1.cc
^
|
@@ -1,4 +1,5 @@
#include "netbuffer"
Netbuffer::Netbuffer(): buf_data(0), buf_sz(0), buf_alloced(0) {
+ debugmsg(Mstr("Netbuffer: creating zero size buffer\n"));
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/netbuffer/netread.cc
^
|
@@ -6,9 +6,13 @@
if (timeout) {
Fdset set(timeout);
set.add(fd);
- if (set.readable() != fd)
- throw static_cast<Error>("Fd ") + fd +
- " failed to become readable within " + int(timeout) + " sec";
+ set.wait_r();
+ if (! set.readable(fd)) {
+ ostringstream o;
+ o << "Fd " << fd << " failed to become readable within "
+ << int(timeout) << " sec";
+ throw Error(o.str());
+ }
}
check_space(config.buffersize());
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/netbuffer/netwrite.cc
^
|
@@ -33,32 +33,40 @@
if (timeout) {
Fdset set (timeout);
set.add (fd);
- if (set.writeable() != fd)
- throw static_cast<Error>("Fd ") + fd +
- " failed to become writable within " + timeout + " sec";
+ set.wait_w();
+ if (! set.writeable(fd)) {
+ ostringstream o;
+ o << "Fd " << fd << " failed to become writable within "
+ << timeout << " sec";
+ throw Error(o.str());
+ }
}
// Push bytes
ssize_t nwritten;
nwritten = write (fd, buf_data + totwritten, buf_sz - totwritten);
- if (config.debug() && nwritten > 0) {
- ostringstream o;
- o << "Sent " << nwritten << " bytes to fd " << fd << ": ";
- for (unsigned i = totwritten; i < totwritten + nwritten; i++)
- o << printable(buf_data[i]);
- o << "\n";
- _debugmsg (o.str());
- }
-
- // EINVAL / EINPROGRESS errors are handled as: retry
// If any bytes were written, we're ok
- if (nwritten >= 1)
+ // EINVAL / EINPROGRESS errors are handled as: retry
+ // All other errors mean the link is broken
+ if (nwritten >= 1) {
+ if (config.debug()) {
+ ostringstream o;
+ o << "Sent " << nwritten << " bytes to fd " << fd << ": ";
+ for (unsigned i = totwritten; i < totwritten + nwritten; i++)
+ o << printable(buf_data[i]);
+ o << "\n";
+ _debugmsg (o.str());
+ }
totwritten += nwritten;
- else if (errno != EINVAL && errno != EINPROGRESS)
- throw static_cast<Error>("Write/send failed: errno=") +
- int(errno) + ", " + strerror(errno) +
- ", result=" + (int)nwritten;
+ } else if (errno == EINVAL || errno == EINPROGRESS) {
+ msg(Mstr("Write warning: ") + Mstr(strerror(errno)) + "\n");
+ } else {
+ ostringstream o;
+ o << "Write/send failed: errno=" << int(errno) << ", "
+ << strerror(errno) << ", result=" << int(nwritten);
+ throw Error(o.str());
+ }
}
return buf_sz;
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/netbuffer/opassign.cc
^
|
@@ -1,6 +1,7 @@
#include "netbuffer"
Netbuffer const &Netbuffer::operator= (Netbuffer const &other) {
+ debugmsg(Mstr("Netbuffer: copying other\n"));
if (this != &other) {
destroy();
copy (other);
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/netbuffer/printable1.cc
^
|
@@ -0,0 +1,9 @@
+#include "netbuffer"
+
+string Netbuffer::printable() const {
+ string ret;
+
+ for (unsigned i = 0; i < buf_sz; i++)
+ ret += printable(buf_data[i]);
+ return ret;
+}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/netbuffer/removeat.cc
^
|
@@ -3,11 +3,11 @@
bool Netbuffer::removeat(unsigned index, unsigned len) {
if (index >= buf_sz)
return false;
-
+
if (index + len >= buf_sz)
buf_sz = index;
else {
- memmove (buf_data + index + len, buf_data + index,
+ memmove (buf_data + index, buf_data + index + len,
buf_sz - index - len);
buf_sz -= len;
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/netbuffer/reset.cc
^
|
@@ -1,5 +1,6 @@
#include "netbuffer"
void Netbuffer::reset() {
+ debugmsg("Netbuffer: resetting\n");
buf_sz = 0;
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/netbuffer/setstring.cc
^
|
@@ -1,10 +1,11 @@
#include "netbuffer"
void Netbuffer::setstring(string const &s) {
+ debugmsg(Mstr("Netbuffer: setting to string\n"));
+
destroy();
check_space(s.size() + 1);
buf_sz = s.size();
memcpy (buf_data, s.c_str(), buf_sz);
buf_data[buf_sz] = 0;
- debugmsg((Mstr("Set netbuffer to string, ") + buf_sz) + " bytes\n");
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/servertype/servertype
^
|
@@ -1,9 +1,7 @@
#ifndef _SERVERTYPE_
#define _SERVERTYPE_
-#include "../sys/sys"
-#include "../error/error"
-
+#include <string>
using namespace std;
class Servertype {
@@ -11,19 +9,15 @@
enum Type {
t_tcp,
t_http,
+ t_udp,
};
- Servertype() : t(t_tcp) {
- }
- Servertype (string id) {
- type (id);
- }
+ Servertype(): t(t_tcp) { }
+ Servertype(string id) { type(id); }
- void type (string id);
+ void type(string id);
string typestr() const;
- Type type() const {
- return (t);
- }
+ Type type() const { return t; }
private:
Type t;
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/servertype/type1.cc
^
|
@@ -1,11 +1,15 @@
#include "servertype"
+#include "error/error"
+
void Servertype::type (string id) {
if (id == "tcp")
t = t_tcp;
else if (id == "http")
t = t_http;
+ else if (id == "udp")
+ t = t_udp;
else
- throw static_cast<Error>("Bad server type '") + id +
- "', supported are 'tcp' or 'http'";
+ throw Error("Bad server type '" + id +
+ "', supported are 'tcp' or 'http' or 'udp'");
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/servertype/typestr.cc
^
|
@@ -1,10 +1,14 @@
#include "servertype"
+#include "error/error"
+
string Servertype::typestr() const {
if (t == t_tcp)
return ("tcp");
else if (t == t_http)
return ("http");
+ else if (t == t_udp)
+ return ("udp");
else
- return ("server type unknown");
+ throw Error("Server type unknown in Servertype::typestr");
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/sys/ipmatch.cc
^
|
@@ -4,9 +4,9 @@
bool ipmatch (struct in_addr adr, struct in_addr mask) {
PROFILE("ipmatch");
- long laddr, lmask;
- memcpy (&laddr, &adr, sizeof(long));
- memcpy (&lmask, &mask, sizeof(long));
+ long laddr = 0, lmask = 0;
+ memcpy (&laddr, &adr, sizeof(adr));
+ memcpy (&lmask, &mask, sizeof(mask));
bool match = ( (laddr & lmask) == laddr );
debugmsg ("Matching ip " + (string)inet_ntoa(adr) + " against mask " +
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/sys/main.cc
^
|
@@ -36,8 +36,8 @@
for (unsigned i = 0; i < sizeof(limit) / sizeof(Limit); i++) {
struct rlimit rl;
if (getrlimit(limit[i].resource, &rl))
- throw static_cast<Error>("Failed to request limit: ") +
- strerror(errno);
+ throw Error(string("Failed to request limit: ") +
+ strerror(errno));
ostringstream o;
o << "Limits for " << limit[i].description
<< ": hard limit " << unsigned(rl.rlim_max)
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/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;
+}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/sys/serversocket.cc
^
|
@@ -3,19 +3,22 @@
#include "profiler/profiler"
#include "config/config"
-int serversocket (string addr, int port, string desc) {
+int serversocket (string addr, int port, string desc, Servertype::Type type) {
PROFILE("serversocket");
- int sock;
-
// Create the server socket, set options
- if ( (sock = socket (PF_INET, SOCK_STREAM, 0)) < 0 )
- throw static_cast<Error>("Failed to create ") + desc + " socket: " +
- strerror(errno);
+ int sock;
+ if (type != Servertype::t_udp)
+ sock = socket(PF_INET, SOCK_STREAM, 0);
+ else
+ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (sock < 0)
+ throw Error("Failed to create " + desc + " socket: " +
+ strerror(errno));
int val = 1;
if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)))
- throw static_cast<Error>("Failed to set socket options for ") +
- desc + ": " + strerror(errno);
+ throw Error("Failed to set socket options for " +
+ desc + ": " + strerror(errno));
// Prepare binding
struct sockaddr_in saddr;
@@ -25,24 +28,25 @@
// Assign interface to listen to
if (addr[0] != '0') {
- msg ("Binding balancer to specific IP address " + addr + "\n");
+ msg ("Binding " + desc + " to specific IP address " + addr + "\n");
if ( (saddr.sin_addr.s_addr = inet_addr (addr.c_str())) == INADDR_NONE )
- throw static_cast<Error>("Cannot convert ") + desc + " IP '" +
- addr + "' to network bytes";
+ throw Error("Cannot convert " + desc + " IP '" +
+ addr + "' to network bytes");
} else {
- msg ("Binding balancer to all local IP addresses\n");
+ msg ("Binding " + desc + " to all local IP addresses\n");
saddr.sin_addr.s_addr = htonl (INADDR_ANY);
}
// Bind and listen
if (bind (sock, (sockaddr*) &saddr, sizeof(saddr)) < 0)
- throw static_cast<Error>("Failed to bind ") + desc +
- " to IP/port: " + strerror(errno);
- if (listen (sock, 5) < 0)
- throw static_cast<Error>("Failed to listen to ") + desc +
- " IP/port: " + strerror(errno);
+ throw Error("Failed to bind " + desc +
+ " to IP/port: " + strerror(errno));
+ if (type != Servertype::t_udp)
+ if (listen (sock, 5) < 0)
+ throw Error("Failed to listen to " + desc +
+ " IP/port: " + strerror(errno));
- msg ("TCP server for " + desc + " listening\n");
+ msg ("Server for " + desc + " listening\n");
return (sock);
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/sys/socketclose.cc
^
|
@@ -3,14 +3,17 @@
void socketclose (int fd) {
PROFILE("socketclose");
-
- debugmsg ((Mstr("Closing socket ") + fd) + "\n");
- if (config.fastclose()) {
- struct linger l;
- l.l_onoff = 1;
- l.l_linger = 2;
- setsockopt (fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
+ if (fd > 2) {
+ debugmsg ((Mstr("Closing socket ") + fd) + "\n");
+
+ if (config.fastclose()) {
+ struct linger l;
+ l.l_onoff = 1;
+ l.l_linger = 2;
+ setsockopt (fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
+ }
+ shutdown(fd, SHUT_RDWR);
+ close(fd);
}
- close (fd);
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/sys/sys
^
|
@@ -50,6 +50,13 @@
# define PROFILE(x)
#endif
+/* Memory debugging on/off */
+#ifdef MEMDEBUG
+# define MEM(x) x
+#else
+# define MEM(x)
+#endif
+
/* If you fear that your malloc() / realloc() may have threading problems,
* uncomment the following. It will cause mutex locks around the calls. */
// #define MISTRUST_MALLOC_THREADSAFE
@@ -63,6 +70,8 @@
// This we need locally for msg(), debugmsg()
#include "mstr/mstr"
+// This is for the Servertype of serversocket()
+#include "servertype/servertype"
/* Messaging. Conditionals are defined as a macro to speed things up. */
void _msg (Mstr const &s);
@@ -74,12 +83,16 @@
void anymsg(Mstr const &s, ostream &o, string const &label);
/* Other */
-int serversocket (string addr, int port, string description);
+int serversocket (string addr, int port, string description,
+ Servertype::Type t);
bool ipmatch (struct in_addr addr, struct in_addr mask);
void socketclose (int fd);
vector<string> str2parts (string const &s, char sep);
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);
|
[-]
[+]
|
Added |
crossroads-devel.tar.gz/xr/sys/sysrun.cc
^
|
@@ -0,0 +1,22 @@
+#include "sys"
+#include "config/config"
+
+int sysrun(string const &s) {
+ int ret = system(s.c_str());
+ if (ret == -1) {
+ warnmsg(Mstr("Failed to start command: ") + s + "\n");
+ return -1;
+ }
+ if (WIFEXITED(ret)) {
+ int stat = WEXITSTATUS(ret);
+ if (stat)
+ warnmsg(Mstr("Command" ) + s +
+ Mstr(" exited with status ") + Mstr(stat) + "\n");
+ else
+ msg(Mstr("Command ") + s +
+ Mstr(" terminated normally.\n"));
+ return stat;
+ }
+ warnmsg(Mstr("Command ") + s + Mstr(" failed miserably!\n"));
+ return ret;
+}
|
[-]
[+]
|
Deleted |
crossroads-devel.tar.gz/xr/tcpdispatcher
^
|
-(directory)
|
[-]
[+]
|
Deleted |
crossroads-devel.tar.gz/xr/tcpdispatcher/dispatch.cc
^
|
@@ -1,44 +0,0 @@
-#include "tcpdispatcher"
-
-void TcpDispatcher::dispatch() {
- // Check that a working algorithm is available. May be missing if
- // constructor's "new" failed.
- if (!algorithm())
- throw static_cast<Error>("No algorithm in Tcpdispatcher::dispatch");
-
- bool connected = false;
-
- // Build up the target list, if not yet done so. The HTTP dispatcher
- // might've created it already for host-based matching (in which case
- // we won't bother here).
- if (! targetlist().isdefined()) {
- msg ("Creating target list for the TCP dispatcher\n");
- for (unsigned i = 0; i < balancer.nbackends(); i++)
- if (balancer.backend(i).available()) {
- targetlist().add(i);
- if (config.verbose())
- msg (" Candidate target: " +
- balancer.backend(i).description() + "\n");
- }
- }
-
- // Call the dispatch algorithm until we can connect,
- // or until the algorithm is out of back ends (throws exception).
- while (!connected) {
- targetbackend(algorithm()->target(clientip(), targetlist()));
- Backend tb = balancer.backend(targetbackend());
- if (!tb.connect()) {
- balancer.backend(targetbackend()).live(false);
- if (config.verbose())
- msg ("Failed to connect to back end " + tb.description() +
- ", trying to dispatch to other\n");
- } else {
- connected = true;
- backendfd(tb.sock());
- msg ((Mstr("Will dispatch client to back end ") +
- tb.description()) +
- (Mstr(" on fd ") + tb.sock()) + "\n");
- break;
- }
- }
-}
|
[-]
[+]
|
Deleted |
crossroads-devel.tar.gz/xr/tcpdispatcher/execute.cc
^
|
@@ -1,158 +0,0 @@
-#include "tcpdispatcher"
-
-typedef map < unsigned long, std::queue<time_t> > AccessMap;
-static AccessMap accesslog;
-static time_t accesslog_lastclean = 0;
-
-// Execute an external program upon excess of hard/soft rates
-static void run_excess(string const &prog, char const *ip) {
- ostringstream o;
- o << prog << ' ' << ip;
- msg ((Mstr("Max connection rate exceeded, invoking '") + o.str()) +
- "'\n");
- int ret = system(o.str().c_str());
- if (ret == -1)
- throw static_cast<Error>("Failed to start system call: ") +
- strerror(errno);
- else if (WIFEXITED(ret)) {
- int exitstat = WEXITSTATUS(ret);
- if (exitstat)
- warnmsg((Mstr("Program '") + o.str()) +
- (Mstr("' exited with exit status ") + exitstat) +
- "\n");
- else
- msg ("Program terminated normally.\n");
- } else
- warnmsg((Mstr("Program '") + o.str()) +
- "' terminated abnormally!\n");
-}
-
-void TcpDispatcher::execute() {
- Threadlist::desc("Verifying");
- Threadlist::clientfd(clientfd());
-
- msg ((Mstr("Dispatch request for client fd ") + clientfd()) + "\n");
-
- // Check 'softmaxconnrate' and 'hardmaxconnrate' now!
- // Descend into this block if connrate_time() is set, AND
- // either hardmaxconnrate() is set,
- // or both softmaxconnrate() and defertime() are set.
- if (config.connrate_time() &&
- (config.hardmaxconnrate() ||
- (config.softmaxconnrate() && config.defertime()))) {
- time_t now, min_ts;
- now = time(0);
- min_ts = now - config.connrate_time();
- unsigned max_conns = max(config.hardmaxconnrate(),
- config.softmaxconnrate());
-
- Mutex::lock (&accesslog[clientip().s_addr]);
- accesslog[clientip().s_addr].push(now);
- Mutex::unlock (&accesslog[clientip().s_addr]);
-
- if (accesslog_lastclean < min_ts) {
- // Clean the entire access log, it's been a while...
-
- Mutex::lock(&accesslog_lastclean);
- accesslog_lastclean = now;
- Mutex::unlock(&accesslog_lastclean);
-
- for (AccessMap::iterator i = accesslog.begin();
- i != accesslog.end();
- i++ ) {
- if (accesslog[i->first].back() < min_ts) {
- // This IP hasn't made ANY connections in a while -- erase!
- accesslog.erase(i);
- } else {
- // Keep popping off this IP's oldest connection until we
- // have only "recent" connections left.
- Mutex::lock(&accesslog[i->first]);
- while ( accesslog[i->first].front() < min_ts
- || accesslog[i->first].size() > max_conns ) {
- accesslog[i->first].pop();
- }
- Mutex::unlock(&accesslog[i->first]);
- }
- }
- } else {
- // The "big log" doesn't need to be fully cleaned,
- // but this particular IP should be!
- Mutex::lock(&accesslog[clientip().s_addr]);
- while ( accesslog[clientip().s_addr].front() < min_ts
- || accesslog[clientip().s_addr].size() > max_conns ) {
- accesslog[clientip().s_addr].pop();
- }
- Mutex::unlock(&accesslog[clientip().s_addr]);
- }
-
- if (config.hardmaxconnrate() &&
- accesslog[clientip().s_addr].size() >= config.hardmaxconnrate() ) {
- // This IP has violated the "HARD" limit! Reject the connection
- ostringstream o;
- o << "Client " << inet_ntoa(clientip())
- << " has hit the HARD maximum number of connections ("
- << config.hardmaxconnrate() << " conections in "
- << config.connrate_time() << " seconds; "
- << accesslog[clientip().s_addr].size()
- << " connections recorded). Client is refused.\n";
- warnmsg (o.str());
- socketclose(clientfd());
- run_excess(config.hardmaxconnexcess(), inet_ntoa(clientip()));
- return;
- } else if (config.softmaxconnrate() &&
- (accesslog[clientip().s_addr].size() >=
- config.softmaxconnrate())) {
- // This IP has violated the "SOFT" Limit. Go to sleep for a while.
- ostringstream o;
- o << "Client " << inet_ntoa(clientip())
- << " has hit the SOFT maximum number of connections ("
- << config.softmaxconnrate() << " connections in "
- << config.connrate_time() << " sedonds; "
- << accesslog[clientip().s_addr].size()
- << " connections recorded). Client is deferred for "
- << config.defertime() << " microseconds.\n";
- warnmsg (o.str());
- run_excess(config.softmaxconnexcess(), inet_ntoa(clientip()));
- usleep(config.defertime());
- }
- }
-
- try {
- Threadlist::desc("Dispatching");
- dispatch();
- } catch (Error const &e) {
- Mutex::lock(&cerr);
- cerr << e.what() << "\n";
- Mutex::unlock(&cerr);
- socketclose(clientfd());
- socketclose(backendfd());
- return;
- }
-
- msg ((Mstr("Dispatching client fd ") + clientfd()) +
- (Mstr(" to ") + balancer.backend(targetbackend()).description()) +
- (Mstr(", fd ") + backendfd()) + "\n");
-
- Threadlist::desc("Serving");
- Threadlist::backend(targetbackend());
- Threadlist::backendfd(backendfd());
-
- balancer.backend(targetbackend()).startconnection();
-
- try {
- handle();
- } catch (Error const &e) {
- Mutex::lock(&cerr);
- cerr << e.what() << "\n";
- Mutex::unlock(&cerr);
- }
-
- balancer.backend(targetbackend()).endconnection();
-
- socketclose (clientfd());
- socketclose (backendfd());
-
- msg ((Mstr("Done dispatching to back end fd ") + backendfd()) +
- (Mstr(" at ") + balancer.backend(targetbackend()).description()) +
- "\n");
-}
|
[-]
[+]
|
Deleted |
crossroads-devel.tar.gz/xr/tcpdispatcher/handle.cc
^
|
@@ -1,38 +0,0 @@
-#include "tcpdispatcher"
-
-void TcpDispatcher::handle() {
-
- debugmsg (Mstr("TCP dispatcher: About to shuttle between client fd ") +
- clientfd() +
- (Mstr(" and backend fd ") + backendfd()) + "\n");
-
- while (1) {
- Fdset readset (config.client_timeout());
- readset.add (clientfd());
- readset.add (backendfd());
-
- int sock;
- if ((sock = readset.readable()) < 0)
- break;
- if (!netbuffer.netread(sock))
- break;
-
- int othersock, timeout;
- if (sock == clientfd()) {
- othersock = backendfd();
- timeout = config.backend_timeout();
- } else {
- othersock = clientfd();
- timeout = config.client_timeout();
- }
-
- debugmsg (Mstr("Had data on ") + sock +
- (Mstr(", sending to ") + othersock) + "\n");
-
- netbuffer.netwrite (othersock, timeout);
- if (sock == backendfd())
- balancer.backend(targetbackend()).addbytes(netbuffer.bufsz());
-
- netbuffer.reset();
- }
-}
|
[-]
[+]
|
Deleted |
crossroads-devel.tar.gz/xr/tcpdispatcher/tcpdispatcher
^
|
@@ -1,22 +0,0 @@
-#ifndef _TCPDISPATCHER_
-#define _TCPDISPATCHER_
-
-#include "dispatcher/dispatcher"
-#include "netbuffer/netbuffer"
-
-class TcpDispatcher: public Dispatcher {
-public:
-
- TcpDispatcher (int fd, struct in_addr ip);
-
- virtual void execute();
- virtual void dispatch();
- virtual void handle();
-
- unsigned readchunk (int src);
-
-private:
- Netbuffer netbuffer;
-};
-
-#endif
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/webinterface/answer.cc
^
|
@@ -15,7 +15,7 @@
unsigned ret;
if (sscanf (s.c_str(), "%u", &ret) < 1)
- throw static_cast<Error>("Bad ") + desc;
+ throw Error("Bad " + desc);
return (ret);
}
@@ -23,21 +23,21 @@
double ret;
if (sscanf (s.c_str(), "%lf", &ret) < 0)
- throw static_cast<Error>("Bad ") + desc;
+ throw Error("Bad " + desc);
return (ret);
}
static pthread_t str2threadid (string const &s, string const &desc) {
pthread_t ret;
- long val;
+ long long val;
int convret;
if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
- convret = sscanf(s.c_str() + 2, "%lx", &val);
+ convret = sscanf(s.c_str() + 2, "%llx", &val);
else
- convret = sscanf(s.c_str(), "%ld", &val);
+ convret = sscanf(s.c_str(), "%lld", &val);
if (convret < 1)
- throw static_cast<Error>("Bad ") + desc;
+ throw Error("Bad " + desc);
memcpy (&ret, &val, sizeof(ret));
return (ret);
}
@@ -47,7 +47,7 @@
ret = str2uns (s, "back end index");
if (ret >= balancer.nbackends())
- throw static_cast<Error>("Back end index out of range");
+ throw Error("Back end index out of range");
return (ret);
}
@@ -56,7 +56,7 @@
ret = str2uns (s, "header index");
if (ret >= config.nserverheaders())
- throw static_cast<Error>("Server header index out of range");
+ throw Error("Server header index out of range");
return (ret);
}
@@ -71,7 +71,7 @@
else if (s == "off" || s == "no" || s == "false")
ret = false;
else
- throw static_cast<Error>("Bad ") + desc + " switch '" + s + "'";
+ throw Error("Bad " + desc + " switch '" + s + "'");
return (ret);
}
@@ -104,7 +104,7 @@
void Webinterface::answer(Httpbuffer req) {
if (req.requestmethod() != Httpbuffer::m_get)
- throw static_cast<Error>("Only request method GET supported");
+ throw Error("Only request method GET supported");
string uri = req.requesturi();
@@ -131,7 +131,7 @@
parts[0] == "server" && parts[1] == "buffersize") {
unsigned sz = str2uns (parts[2], "buffer size");
if (sz < 1)
- throw static_cast<Error>("Buffer size may not be less than 1");
+ throw Error("Buffer size may not be less than 1");
config.buffersize(sz);
answer_status();
return;
@@ -173,6 +173,14 @@
return;
}
+ // /server/replacehostheader/BOOLEAN
+ if (parts.size() == 3 &&
+ parts[0] == "server" && parts[1] == "replacehostheader") {
+ config.replacehostheader (str2bool(parts[2], "replacehostheader"));
+ answer_status();
+ return;
+ }
+
// /server/newheader/NEWHEADER
if (parts.size() == 3 &&
parts[0] == "server" && parts[1] == "newheader") {
@@ -219,26 +227,50 @@
return;
}
- // /server/clienttimeout
- // /server/clienttimeout/NUMBER
+ // /server/clientreadtimeout
+ // /server/clientreadtimeout/NUMBER
+ if (parts.size() == 3 &&
+ parts[0] == "server" && parts[1] == "clientreadtimeout") {
+ unsigned num = 0;
+ if (parts[2] != "")
+ num = str2uns (parts[2], "client read timeout");
+ config.client_read_timeout(num);
+ answer_status();
+ return;
+ }
+
+ // /server/clientwritetimeout
+ // /server/clientwritetimeout/NUMBER
+ if (parts.size() == 3 &&
+ parts[0] == "server" && parts[1] == "clientwritetimeout") {
+ unsigned num = 0;
+ if (parts[2] != "")
+ 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] == "clienttimeout") {
+ parts[0] == "server" && parts[1] == "backendreadtimeout") {
unsigned num = 0;
if (parts[2] != "")
- num = str2uns (parts[2], "client timeout");
- config.client_timeout(num);
+ num = str2uns (parts[2], "back end read timeout");
+ config.backend_read_timeout(num);
answer_status();
return;
}
- // /server/backendtimeout
- // /server/backendtimeout/NUMBER
+ // /server/backendwritetimeout
+ // /server/backendwritetimeout/NUMBER
if (parts.size() == 3 &&
- parts[0] == "server" && parts[1] == "backendtimeout") {
+ parts[0] == "server" && parts[1] == "backendwritetimeout") {
unsigned num = 0;
if (parts[2] != "")
- num = str2uns (parts[2], "back end timeout");
- config.backend_timeout(num);
+ num = str2uns (parts[2], "back end write timeout");
+ config.backend_write_timeout(num);
answer_status();
return;
}
@@ -288,7 +320,7 @@
parts[0] == "server" && parts[1] == "timeinterval") {
unsigned num = str2uns(parts[2], "time interval");
if (num < 1)
- throw static_cast<Error>("Time interval may not be less than 1");
+ throw Error("Time interval may not be less than 1");
config.connrate_time(num);
answer_status();
return;
@@ -315,7 +347,7 @@
parts[0] == "server" && parts[1] == "defertime") {
unsigned num = str2uns(parts[2], "defer time");
if (num < 1)
- throw static_cast<Error>("Defer time may not be less than 1");
+ throw Error("Defer time may not be less than 1");
config.defertime(num);
answer_status();
return;
@@ -389,13 +421,39 @@
return;
}
+ // /server/onstart/
+ // /server/onstart/PROGRAM
+ if (parts.size() == 3 &&
+ parts[0] == "server" && parts[1] == "onstart") {
+ config.onstart(parts[2]);
+ answer_status();
+ return;
+ }
+
+ // /server/onend/
+ // /server/onend/PROGRAM
+ if (parts.size() == 3 &&
+ parts[0] == "server" && parts[1] == "onend") {
+ config.onend(parts[2]);
+ answer_status();
+ return;
+ }
+
+ // /server/onfail/
+ // /server/onfail/PROGRAM
+ if (parts.size() == 3 &&
+ parts[0] == "server" && parts[1] == "onfail") {
+ config.onfail(parts[2]);
+ answer_status();
+ return;
+ }
+
// /server/addbackend/IP:PORT
if (parts.size() == 3 &&
parts[0] == "server" && parts[1] == "addbackend") {
vector<string> address = str2parts(parts[2], ':');
if (address.size() != 2)
- throw static_cast<Error>
- ("When adding back ends, the address must be IP:PORT");
+ throw Error("When adding back ends, the address must be IP:PORT");
Backend b;
b.server(address[0]);
b.port(str2uns(address[1], "back end port"));
@@ -425,7 +483,7 @@
unsigned ind = backendindex(parts[1]);
unsigned num = str2uns (parts[3], "back end weight");
if (num < 1)
- throw static_cast<Error>("Weight may not be less than 1");
+ throw Error("Weight may not be less than 1");
balancer.backend(ind).weight(num);
answer_status();
return;
@@ -513,5 +571,5 @@
return;
}
- throw static_cast<Error>("No action for URI '/") + uri + "'";
+ throw Error("No action for URI '/" + uri + "'");
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/webinterface/answerblob.cc
^
|
@@ -11,5 +11,5 @@
"\r\n" +
blob;
Netbuffer buf(resp);
- buf.netwrite(cfd, config.client_timeout());
+ buf.netwrite(cfd, config.client_write_timeout());
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/webinterface/answerstatus.cc
^
|
@@ -18,13 +18,18 @@
" <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"
" <buffersize>" << config.buffersize() << "</buffersize>\n"
" <closesocketsfast>" << config.fastclose() << "</closesocketsfast>\n"
+ " <onstart>" << config.onstart() << "</onstart>\n"
+ " <onend>" << config.onend() << "</onend>\n"
+ " <onfail>" << config.onfail() << "</onfail>\n"
" <checks>\n"
" <wakeupinterval>" << config.wakeupsec() << "</wakeupinterval>\n"
" <checkupinterval>" << config.checkupsec() << "</checkupinterval>\n"
@@ -67,6 +72,7 @@
" <addxrversion>" << config.addxrversion() << "</addxrversion>\n"
" <addxforwardedfor>" << config.addxforwardedfor() << "</addxforwardedfor>\n"
" <stickyhttp>" << config.stickyhttp() << "</stickyhttp>\n"
+ " <replacehostheader>" << config.replacehostheader() << "</replacehostheader>\n"
" <serverheaders>\n"
;
for (unsigned i = 0; i < config.nserverheaders(); i++)
@@ -97,6 +103,7 @@
" <live>" << balancer.backend(i).livestr() << "</live>\n"
" <available>" << balancer.backend(i).availablestr() << "</available>\n"
" <connections>" << balancer.backend(i).connections() << "</connections>\n"
+ " <connecterrors>" << balancer.backend(i).connecterrors() << "</connecterrors>\n"
" <bytesserved>" << balancer.backend(i).bytesserved() << "</bytesserved>\n"
" <clientsserved>" << balancer.backend(i).clientsserved() << "</clientsserved>\n"
" <hostmatch>" << balancer.backend(i).hostmatch() << "</hostmatch>\n"
@@ -104,26 +111,47 @@
" </backend>\n"
;
- o << " <activity>\n";
+ o <<
+ " <activity>\n"
+ " <threadlist>\n";
+ unsigned nthreads = 0, max_open_files;
+ struct rlimit rl;
+ if (getrlimit(RLIMIT_NOFILE, &rl))
+ throw Error("Failed to get limit for open files");
+ max_open_files = unsigned(rl.rlim_cur);
for (Threadmap::iterator it = Threadlist::map().begin();
it != Threadlist::map().end();
it++) {
+ nthreads++;
pthread_t thread_id = (*it).first;
Threadinfo thread_info = (*it).second;
o <<
- " <thread>\n"
- " <id>" << thread_id << "</id>\n"
- " <description>" << thread_info.desc() << "</description>\n"
- " <backend>" << thread_info.backend() << "</backend>\n"
- " <address>";
+ " <thread>\n"
+ " <id>" << thread_id << "</id>\n"
+ " <description>" << thread_info.desc() << "</description>\n"
+ " <backend>" << thread_info.backend() << "</backend>\n"
+ " <address>";
if (thread_info.backend() >= 0)
o << balancer.backend(thread_info.backend()).description();
o <<
"</address>\n"
- " <duration>" << thread_info.timestamp().elapsed() << "</duration>\n"
- " </thread>\n";
+ " <duration>" << thread_info.timestamp().elapsed() << "</duration>\n"
+ " <clientip>" << inet_ntoa(thread_info.clientip()) << "</clientip>\n"
+ " </thread>\n";
}
- o << " </activity>\n";
+ /* The estimate of the number of used fd's is:
+ * Base is 5 (stdin/stdout/stderr, listen-fd for service, listen-fd
+ * for webinterface
+ * Plus 2 x #-threads (1 to client, 1 to backend)
+ * There will be fd's in use for shared libs etc., but we don't see
+ * those..
+ */
+ o <<
+ " </threadlist>\n"
+ " <threadcount>" << nthreads << "</threadcount>\n"
+ " <openfiles>" << nthreads * 2 + 5 << "</openfiles>\n"
+ " <maxopenfiles>" << max_open_files << "</maxopenfiles>\n"
+ " </activity>\n";
o <<
"</status>\n\n";
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/webinterface/execute.cc
^
|
@@ -11,7 +11,7 @@
msg ("Starting web interface\n");
sfd = serversocket (config.webinterfaceip(),
config.webinterfaceport(),
- "web interface");
+ "web interface", Servertype::t_tcp);
} catch (Error const &e) {
cerr << e.what() << "(webinterface, retrying in a sec)\n";
sleep (1);
@@ -25,13 +25,19 @@
try {
Fdset fdset(0);
fdset.add (sfd);
- if (fdset.readable() == sfd) {
+ fdset.wait_r();
+ if (fdset.readable(sfd)) {
int size;
struct sockaddr_in clname;
if ( (cfd = accept (sfd, (struct sockaddr *) &clname,
- (socklen_t *)&size)) > 0 )
+ (socklen_t *)&size)) < 0 )
+ warnmsg(Mstr("Web interface: failed to accept "
+ "network connection: ") +
+ Mstr(strerror(errno)) + "\n");
+ else {
serve ();
- socketclose(cfd);
+ socketclose(cfd);
+ }
}
} catch (Error const &e) {
cerr << e.what() << " (webinterface)\n";
@@ -48,11 +54,10 @@
"\r\n" <<
m.str();
Netbuffer buf(o.str());
- buf.netwrite(cfd, config.client_timeout());
+ buf.netwrite(cfd, config.client_write_timeout());
socketclose(cfd);
}
}
msg ("Web interface stopping.\n");
socketclose(sfd);
- shutdown (sfd, SHUT_RDWR);
}
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xr/webinterface/serve.cc
^
|
@@ -4,7 +4,7 @@
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);
|
[-]
[+]
|
Changed |
crossroads-devel.tar.gz/xrctl/xrctl
^
|
@@ -15,8 +15,12 @@
# 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;
@@ -49,35 +53,39 @@
# Load up the system config.
my %sysconf;
-my $sysxp = new XMLParser($xp->data('system'));
-for my $tag qw(pscmd logger uselogger logdir
- maxlogsize loghistory path) {
- $sysconf{$tag} = $sysxp->data($tag);
- msg("System config $tag: $sysconf{$tag}\n") if ($sysconf{$tag} ne '');
-}
-if ($sysconf{path} eq '') {
- msg ("No path in configuration, using environment\n");
- $sysconf{path} = $ENV{PATH};
-}
-if ($sysconf{logger} ne 'logger') {
- msg ("Using non-default logger\n");
- $default_logger = $sysconf{logger};
-}
-if ($sysconf{pscmd} eq '') {
- $sysconf{pscmd} = xfind_bin('ps');
- if (`uname` =~ /SunOS/) {
- $sysconf{pscmd} .= ' -ef pid,comm';
- } else {
- $sysconf{pscmd} .= ' ax -o pid,command';
+my $sysblock = $xp->data('system');
+if ($sysblock ne '') {
+ my $sysxp = new XMLParser($xp->data('system'));
+ for my $tag qw(pscmd logger uselogger logdir
+ maxlogsize loghistory path) {
+ $sysconf{$tag} = $sysxp->data($tag);
+ msg("System config $tag: $sysconf{$tag}\n") if ($sysconf{$tag} ne '');
+ }
+ if ($sysconf{path} eq '') {
+ msg ("No path in configuration, using environment\n");
+ $sysconf{path} = $ENV{PATH};
+ }
+ if ($sysconf{logger} ne 'logger') {
+ msg ("Using non-default logger\n");
+ $default_logger = $sysconf{logger};
+ }
+ if ($sysconf{pscmd} eq '') {
+ $sysconf{pscmd} = xfind_bin('ps');
+ if (`uname` =~ /SunOS/) {
+ $sysconf{pscmd} .= ' -ef pid,comm';
+ } else {
+ $sysconf{pscmd} .= ' ax -o pid,command';
+ }
}
+ msg ("PS command: $sysconf{pscmd}\n");
}
-msg ("PS command: $sysconf{pscmd}\n");
# Load up the service names.
my @service_name;
for (my $i = 0; ; $i++) {
my $serviceblock = $xp->data('service', $i) or last;
- my $servicexp = new XMLParser($serviceblock);
+ my $servicexp = new XMLParser($serviceblock)
+ or die ("No <service> blocks in configuration\n");
my $name = $servicexp->data('name')
or die ("<service> block lacks <name>\n");
push (@service_name, $name);
@@ -96,10 +104,14 @@
cmd_start(@ARGV);
} elsif ($cmd eq 'stop') {
cmd_stop(@ARGV);
+} elsif ($cmd eq 'kill') {
+ cmd_kill(@ARGV);
} elsif ($cmd eq 'force') {
cmd_force(@ARGV);
-} elsif ($cmd eq 'restart') {
- cmd_restart(@ARGV);
+} elsif ($cmd eq 'stopstart') {
+ cmd_stopstart(@ARGV);
+} elsif ($cmd eq 'killstart') {
+ cmd_killstart(@ARGV);
} elsif ($cmd eq 'status') {
cmd_status(@ARGV);
} elsif ($cmd eq 'rotate') {
@@ -145,12 +157,27 @@
push (@pids, @p);
}
for my $p (@pids) {
- msg ("About to kill PID: '$p'\n");
+ msg ("About to stop PID: '$p'\n");
}
kill (15, @pids) if ($#pids > -1);
print ("Services @_: stopped\n");
}
+sub cmd_kill {
+ my @pids;
+ for my $s (@_) {
+ my @p = is_running($s)
+ or die ("Cannot stop service $s, not running\n");
+ print ("Service $s: running at @p\n");
+ push (@pids, @p);
+ }
+ for my $p (@pids) {
+ msg ("About to kill PID: '$p'\n");
+ }
+ kill (9, @pids) if ($#pids > -1);
+ print ("Services @_: killed\n");
+}
+
sub cmd_force {
for my $s (@_) {
print ("Service $s: ");
@@ -163,11 +190,11 @@
}
}
-sub cmd_restart {
+sub cmd_stopstart {
my @pids;
for my $s (@_) {
my @p = is_running($s)
- or die ("Cannot restart service $s, not running\n");
+ or die ("Cannot stopstart service $s, not running\n");
push (@pids, @p);
}
print ("Service(s) @_: ");
@@ -180,6 +207,23 @@
}
}
+sub cmd_killstart {
+ my @pids;
+ for my $s (@_) {
+ my @p = is_running($s)
+ or die ("Cannot killstart service $s, not running\n");
+ push (@pids, @p);
+ }
+ print ("Service(s) @_: ");
+ kill (9, @pids) if ($#pids > -1);
+ print ("killed\n");
+ for my $s (@_) {
+ print ("Service $s: ");
+ start_service($s);
+ print ("started\n");
+ }
+}
+
sub cmd_status {
for my $s (@_) {
print ("Service $s: ");
@@ -197,7 +241,7 @@
print ("Service $s: ");
my $f = log_file($s);
print ("log file $f, ");
- if (substr($s, 0, 1) ne '>') {
+ if (substr($f, 0, 1) ne '>') {
print ("not a file\n");
next;
}
@@ -284,15 +328,17 @@
configtest builds invocations from the configuration file and validates them
list shows the xr command line
start starts the service(s) if they are not yet running
- stop stops the service(s) if they are running
+ stop gracefully stops the service(s) if they are running
+ kill brutally kills the service(s), interrupting all connections
force forces the service(s) up: starts if not running
- restart restarts the service(s) if they are running
+ stopstart gracefully restarts the service(s) if they are running
+ killstart brutally restarts
status shows which services are running
rotate rotates logs of the service(s)
generateconfig queries running XR's for the current configuration and
shows it in the format of $default_conf
-Services are the services stated in the configuration. When absent, all
-named services are handled.
+The SERVICES following an action are the services stated in the configuration.
+When absent, all configured services are handled.
ENDUSAGE
}
@@ -319,9 +365,9 @@
# Unconditionally start a given service
sub start_service {
my $s = shift;
- my @args = xr_cmdarr($s);
- my $xr = xfind_bin('xr');
- my $logstr = log_file($s);
+ my @args = xr_cmdarr($s);
+ my $xr = xfind_bin('xr');
+ my $logstr = log_file($s);
my $logtype = substr($logstr, 0, 1);
my $logout = substr($logstr, 1);
@@ -409,9 +455,12 @@
my $ret = xfind_bin('xr');
for (my $i = 1; $i <= $#parts; $i++) {
my $sub = $parts[$i];
+ $sub =~ s/^\s+//;
+ $sub =~ s/\s+$//;
$sub = "'$sub'" if ($sub =~ /\s/);
$ret .= ' ' . $sub;
}
+ msg ("Quoted command: $ret\n");
return ($ret);
}
@@ -429,11 +478,12 @@
my $sp = xml_serviceparser($service)
or die ("Failed to locate <service> block for service '$service'\n");
- # Service descriptions
+ # Service descriptions inside the <server> block
+ my $ss = xml_serverparser($sp);
my $type = 'tcp';
- $type = $sp->data('type') if ($sp->data('type'));
+ $type = $ss->data('type') if ($ss->data('type'));
my $addr = '0:10000';
- $addr = $sp->data('address') if ($sp->data('address'));
+ $addr = $ss->data('address') if ($ss->data('address'));
my $full = "$type:$addr";
push (@cmd, '--server', $full) if ($full ne 'tcp:0:10000');
@@ -444,62 +494,84 @@
# Handle general flags and boolflags
push (@cmd,
- flag($sp, '--web-interface', 'webinterface', ''),
- flag($sp, '--dispatch-mode', 'dispatchmode',
+ flag($ss, '--web-interface', 'webinterface', ''),
+ flag($ss, '--dispatch-mode', 'dispatchmode',
$default_dispatchmode),
- flag($sp, '--max-connections', 'maxconnections',
+ flag($ss, '--max-connections', 'maxconnections',
$default_maxconnections),
- flag($sp, '--client-timeout', 'clienttimeout',
- $default_clienttimeout),
- flag($sp, '--backend-timeout', 'backendtimeout',
- $default_backendtimeout),
- flag($sp, '--buffer-size', 'buffersize',
+ flag($ss, '--client-timeout', 'clienttimeout',
+ $default_client_timeout),
+ flag($ss, '--backend-timeout', 'backendtimeout',
+ $default_backend_timeout),
+ flag($ss, '--buffer-size', 'buffersize',
$default_buffersize),
- flag($sp, '--wakeup-interval', 'wakeupinterval',
+ flag($ss, '--wakeup-interval', 'wakeupinterval',
$default_wakeupinterval),
- flag($sp, '--checkup-interval', 'checkupinterval',
+ flag($ss, '--checkup-interval', 'checkupinterval',
$default_checkupinterval),
- flag($sp, '--time-interval', 'timeinterval',
+ flag($ss, '--time-interval', 'timeinterval',
$default_timeinterval),
- flag($sp, '--hard-maxconnrate', 'hardmaxconnrate',
+ flag($ss, '--hard-maxconnrate', 'hardmaxconnrate',
$default_hardmaxconnrate),
- flag($sp, '--soft-maxconnrate', 'softmaxconnrate',
+ flag($ss, '--soft-maxconnrate', 'softmaxconnrate',
$default_softmaxconnrate),
- flag($sp, '--defer-time', 'defertime',
+ flag($ss, '--defer-time', 'defertime',
$default_defertime),
- flag($sp, '--hard-maxconn-excess', 'hardmaxconnexcess',
+ flag($ss, '--hard-maxconn-excess', 'hardmaxconnexcess',
$default_hardmaxconnexcess),
- flag($sp, '--soft-maxconn-excess', 'softmaxconnexcess',
+ flag($ss, '--soft-maxconn-excess', 'softmaxconnexcess',
$default_softmaxconnexcess),
- flag($sp, '--dns-cache-timeout', 'dnscachetimeout',
+ flag($ss, '--dns-cache-timeout', 'dnscachetimeout',
$default_dnscachetimeout),
- flag($sp, '--log-traffic-dir', 'logtrafficdir', ''));
+ flag($ss, '--onstart', 'onstart'),
+ flag($ss, '--onend', 'onend'),
+ flag($ss, '--onfail', 'onfail'),
+ flag($ss, '--log-traffic-dir', 'logtrafficdir', ''));
for my $k (sort (keys (%boolflags))) {
- push (@cmd, $boolflags{$k}) if (istrue($sp->data($k)));
- }
+ push (@cmd, $boolflags{$k}) if (istrue($ss->data($k)));
+ }
+
+ # Timeouts when specified using separate tags
+ my $t = $ss->data('clientreadtimeout');
+ if (defined($t)) {
+ my $val = $t;
+ $t = $ss->data('clientwritetimeout');
+ $val .= ":$t" if (defined($t));
+ push (@cmd, '--client-timeout', $val);
+ }
+ $t = $ss->data('backendreadtimeout');
+ if (defined($t)) {
+ my $val = $t;
+ $t = $ss->data('backendwritetimeout');
+ $val .= ":$t" if (defined($t));
+ push (@cmd, '--backend-timeout', $val);
+ }
# ACL's
for (my $i = 0; ; $i++) {
- my $mask = $sp->data('allowfrom', $i) or last;
+ my $mask = $ss->data('allowfrom', $i) or last;
push (@cmd, '--allow-from', $mask);
}
for (my $i = 0; ; $i++) {
- my $mask = $sp->data('denyfrom', $i) or last;
+ my $mask = $ss->data('denyfrom', $i) or last;
push (@cmd, '--deny-from', $mask);
}
# HTTP goodies
push (@cmd, '--add-xr-version')
- if ($sp->data('addxrversion') and
- istrue($sp->data('addxrversion')));
+ if ($ss->data('addxrversion') and
+ istrue($ss->data('addxrversion')));
push (@cmd, '--add-x-forwarded-for')
- if ($sp->data('addxforwardedfor') and
- istrue($sp->data('addxforwardedfor')));
+ if ($ss->data('addxforwardedfor') and
+ istrue($ss->data('addxforwardedfor')));
push (@cmd, '--sticky-http')
- if ($sp->data('stickyhttp') and
- istrue($sp->data('stickyhttp')));
+ if ($ss->data('stickyhttp') and
+ istrue($ss->data('stickyhttp')));
+ push (@cmd, '--replace-host-header')
+ if ($ss->data('replacehostheader') and
+ istrue($ss->data('replacehostheader')));
for (my $i = 0; ; $i++) {
- my $h = $sp->data('header', $i) or last;
+ my $h = $ss->data('header', $i) or last;
push (@cmd, '--add-server-header', $h);
}
@@ -542,9 +614,15 @@
# All done
my @ret;
+ # msg("Generated flags/arguments:\n");
for my $c (@cmd) {
- push (@ret, $c) if ($c ne '');
+ if ($c ne '') {
+ push (@ret, $c);
+ # msg (" $c");
+ }
}
+ # msg ("\n");
+
return (@ret);
}
@@ -575,7 +653,7 @@
my $service = shift;
for (my $i = 0; ; $i++) {
- $xml = $xp->data('service', $i) or return (undef);
+ my $xml = $xp->data('service', $i) or return (undef);
msg ("XML service block: $xml\n");
my $sub = new XMLParser($xml);
return ($sub) if ($sub->data('name') eq $service);
@@ -583,6 +661,13 @@
return (undef);
}
+# Fetch an XMLParser for a <server> block given a service parser
+sub xml_serverparser {
+ my $serviceparser = shift;
+ my $xml = $serviceparser->data('server') or return undef;
+ return new XMLParser($xml);
+}
+
# Fetch an XMLParser for a <backend> block given a service parser and
# an order number
sub xml_backendparser {
@@ -643,12 +728,16 @@
my $active = 0;
for my $l (split (/\n/, $response_blob)) {
if ($l =~ /<server>/) {
- print ($l, "\n");
+ print (" $l\n");
$active = 1;
} elsif ($l =~ /<\/status>/) {
$active = 0;
+ } elsif ($l =~ /<activity>/) {
+ $active = 0;
+ } elsif ($l =~ /<\/activity>/) {
+ $active = 1;
} elsif ($active) {
- print ($l, "\n");
+ print (" $l\n");
}
}
@@ -664,8 +753,7 @@
sub new {
my ($proto, $doc) = @_;
my $self = {};
-
- die ("Invalid or missing XML document\n") unless ($doc);
+ die ("Missing XML document\n") unless($doc);
my $docstr = '';
for my $p (split (/\n/, $doc)) {
@@ -689,6 +777,9 @@
}
}
+ # Activity logs is trash
+ $docstr =~ s{<activity>.*</activity>}{}g;
+
# print $docstr, "\n";
$self->{xml} = $docstr;
|