crossroads

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

commit 6c73980ed2056b919b7af2fd15c2716199995268
parent 18ca72abe3c1e23f6448d970a84e8b0843d3b7e1
Author: finwo <finwo@pm.me>
Date:   Sat,  3 Jan 2026 19:37:31 +0100

2.49

Diffstat:
MChangeLog | 3+++
MMakefile | 2+-
Mdoc/xr.odt | 0
Mdoc/xrctl.xml.5 | 5+++++
Mxr/Checkers/checkupthread/execute.cc | 6++++++
Mxr/Dispatchers/dispatcher/checkdos.cc | 16+++++-----------
Mxr/Dispatchers/tcpdispatcher/execute.cc | 30++++++++++--------------------
Mxr/config/config | 4+++-
Mxr/config/config1.cc | 1+
Mxr/config/parsecmdline.cc | 6+++++-
Mxr/etc/c-conf | 11+++++++----
Mxr/etc/status.xslt | 11++++++++++-
Mxr/etc/usage.txt | 10+++++++---
Mxr/sys/sys | 1+
Axr/sys/sysrun.cc | 22++++++++++++++++++++++
Mxr/webinterface/answer.cc | 9+++++++++
Mxr/webinterface/answerstatus.cc | 1+
17 files changed, 96 insertions(+), 42 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,6 @@ +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 diff --git a/Makefile b/Makefile @@ -1,7 +1,7 @@ # Top-level Makefile for XR # ------------------------- -VER = 2.48 +VER = 2.49 PREFIX = $(DESTDIR)/usr BINDIR = $(PREFIX)/sbin MANDIR = $(PREFIX)/share/man diff --git a/doc/xr.odt b/doc/xr.odt Binary files differ. diff --git a/doc/xrctl.xml.5 b/doc/xrctl.xml.5 @@ -125,9 +125,14 @@ distributed with the sources for a full description. echo Client $1 is going to back end $2 >> /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: diff --git a/xr/Checkers/checkupthread/execute.cc b/xr/Checkers/checkupthread/execute.cc @@ -19,6 +19,12 @@ void Checkupthread::execute() { balancer.backend(i).live(false); msg ("Checkup call: backend " + target.description() + " has gone asleep\n"); + if (config.onfail().length()) { + ostringstream o; + o << config.onfail() << " 0.0.0.0 " + << target.description(); + sysrun(o.str()); + } } } sleep (config.checkupsec()); diff --git a/xr/Dispatchers/dispatcher/checkdos.cc b/xr/Dispatchers/dispatcher/checkdos.cc @@ -10,21 +10,15 @@ static void run_excess(string const &prog, char const *ip) { o << prog << ' ' << ip; msg ((Mstr("Max connection rate exceeded, invoking '") + o.str()) + "'\n"); - int ret = system(o.str().c_str()); + int ret = sysrun(o.str()); if (ret == -1) throw Error(string("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 + else if (ret) warnmsg((Mstr("Program '") + o.str()) + - "' terminated abnormally!\n"); + (Mstr("' exited with exit status ") + ret) + "\n"); + else + msg((Mstr("Program '") + o.str()) + "' finished.\n"); } bool Dispatcher::check_dos() { diff --git a/xr/Dispatchers/tcpdispatcher/execute.cc b/xr/Dispatchers/tcpdispatcher/execute.cc @@ -1,24 +1,5 @@ #include "tcpdispatcher" -static void sysrun(string const &s) { - int ret = system(s.c_str()); - if (ret == -1) { - warnmsg(Mstr("Failed to start command: ") + s + "\n"); - return; - } - 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; - } - warnmsg(Mstr("Command ") + s + Mstr(" failed miserably!\n")); -} - void TcpDispatcher::execute() { Threadlist::clientfd(clientfd()); @@ -58,19 +39,28 @@ void TcpDispatcher::execute() { 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(); + msg(Mstr("Running onfail script: ") + o.str() + "\n"); + sysrun(o.str()); + } } socketclose (clientfd()); socketclose (backendfd()); balancer.backend(targetbackend()).endconnection(); - if (config.onend().length()) { + if (!failed && config.onend().length()) { ostringstream o; o << config.onend() << ' ' << clientipstr() << ' ' << balancer.backend(targetbackend()).description(); diff --git a/xr/config/config b/xr/config/config @@ -154,6 +154,8 @@ public: 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: @@ -202,7 +204,7 @@ private: static string soft_maxconn_excess_prog; static string hard_maxconn_excess_prog; static unsigned dns_cache_timeout; - static string on_start, on_end; + static string on_start, on_end, on_fail; }; extern Config config; diff --git a/xr/config/config1.cc b/xr/config/config1.cc @@ -40,6 +40,7 @@ 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 () { } diff --git a/xr/config/parsecmdline.cc b/xr/config/parsecmdline.cc @@ -16,7 +16,7 @@ void Config::parsecmdline (int ac, char **av) { throw Error("Bad command line '" + cmdline + "'\n" + USAGE); # 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:xXz:Z:" + "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' }, @@ -56,6 +56,7 @@ void Config::parsecmdline (int ac, char **av) { { "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 } @@ -229,6 +230,9 @@ void Config::parsecmdline (int ac, char **av) { case 'x': add_x_forwarded_for = true; break; + case 'y': + onfail(optarg); + break; case 'z': onstart(optarg); break; diff --git a/xr/etc/c-conf b/xr/etc/c-conf @@ -157,18 +157,21 @@ sub uname() { 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"); } } } diff --git a/xr/etc/status.xslt b/xr/etc/status.xslt @@ -419,7 +419,7 @@ onchange="goto('/server/onstart/', 'onstart');"/> </td> </tr> - <tr> + <tr> <td></td> <td>Onend command</td> <td colspan="2" align="right"> @@ -429,6 +429,15 @@ </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> diff --git a/xr/etc/usage.txt b/xr/etc/usage.txt @@ -154,11 +154,15 @@ may not exist on your platform): -x, --add-x-forwarded-for Adds X-Forwarded-For with external IP address to back end streams in HTTP messages. - -z CMD, --onstart CMD - Runs CMD just before connecting a client to a back end. The arguments + -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 termination of a client. For the arguments of CMD see -z. + 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. diff --git a/xr/sys/sys b/xr/sys/sys @@ -91,6 +91,7 @@ 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); #ifndef HAVE_INET_ATON int inet_aton (char const *name, struct in_addr *addr); diff --git a/xr/sys/sysrun.cc b/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; +} diff --git a/xr/webinterface/answer.cc b/xr/webinterface/answer.cc @@ -415,6 +415,15 @@ void Webinterface::answer(Httpbuffer req) { 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") { diff --git a/xr/webinterface/answerstatus.cc b/xr/webinterface/answerstatus.cc @@ -27,6 +27,7 @@ void Webinterface::answer_status() { " <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"