crossroads

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

commit 59795206769652ca9498bbd2b1743136be4f3f0e
parent 8919cc1eda7a76e1deec7547d7988d465b093b74
Author: finwo <finwo@pm.me>
Date:   Sat,  3 Jan 2026 19:37:42 +0100

2.53

Diffstat:
MChangeLog | 7+++++++
MMakefile | 2+-
Mtest/xr-client-ping | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Mxr/balancer/serve.cc | 1-
Mxr/etc/status-savebutton.xslt | 162++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Mxr/fdset/readable.cc | 6++----
Mxr/fdset/readwriteable.cc | 3+--
Mxr/fdset/writeable.cc | 3+--
Mxr/netbuffer/netwrite.cc | 28+++++++++++++++-------------
Mxr/sys/socketclose.cc | 3++-
Mxr/webinterface/answer.cc | 6+++---
Mxr/webinterface/execute.cc | 1-
Mxrctl/xrctl | 29+++++++++++++++++++----------
13 files changed, 231 insertions(+), 118 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,10 @@ +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 diff --git a/Makefile b/Makefile @@ -1,7 +1,7 @@ # Top-level Makefile for XR # ------------------------- -VER = 2.52 +VER = 2.53 PREFIX = $(DESTDIR)/usr BINDIR = $(PREFIX)/sbin MANDIR = $(PREFIX)/share/man diff --git a/test/xr-client-ping b/test/xr-client-ping @@ -1,16 +1,26 @@ #!/usr/bin/perl -use LWP::UserAgent; 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); -$SIG{CHLD} = \&reaper; 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); @@ -21,11 +31,14 @@ while (1) { sub usage() { die <<"ENDUSAGE"; -Usage: xr-client-ping http://webinterface-address interval +Usage: xr-client-ping [-q] WEBINTERFACE-URL INTERVAL The web interface is queried for clients. Connections to non-pingable clients -are killed. +are killed. The process is repeated each interval. -The interval specifies the delay between runs. Minimum is 2 (seconds). +The arguments: + -q: quiet mode, suppresses verbose messaging + WEBINTERFACE-URL: the URL of XR's web interface, include http:// + INTERVAL: number of seconds ENDUSAGE } @@ -33,14 +46,14 @@ ENDUSAGE # Start a single test my $_tries = 0; sub do_test() { - my $ua = LWP::UserAgent->new(); - $ua->timeout(3); - msg ("-----------------------------------------------------------------\n"); msg ("Starting check run\n"); - my $res = $ua->get($ARGV[0]); - if (! $res->is_success()) { - msg ("Could not access web interface\n"); + 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; } @@ -48,7 +61,7 @@ sub do_test() { my $active = 0; my ($id, $clientip); - for my $line (split(/\n/, $res->content())) { + for my $line (split(/\n/, $xml)) { $active = 1 if ($line =~ /<thread>/); $active = 0 if ($line =~ /<\/thread>/); @@ -75,36 +88,63 @@ sub check_client($$) { msg ("Checking connection for client $clientip (XR thread $id)\n"); return if (fork()); - my $cmd = "ping -c2 -t1 $clientip >/dev/null"; + my $cmd = "ping -c3 -t3 $clientip >/dev/null"; msg ("$clientip: pinging (external '$cmd')\n"); - $SIG{CHLD} = undef; my $status = system($cmd); - msg ("$clientip: ping status '$status' $!\n"); if ($status != 0) { + msg ("$clientip: ping status '$status' $!\n"); msg ("$clientip: not reachable, stopping XR thread $id\n"); - my $ua = LWP::UserAgent->new(); - my $res = $ua->get("$ARGV[0]/thread/kill/$id"); - if (! $res->is_success()) { - msg ("$clientip: failed to stop (", - $res->status_line(), ")\n"); - } + 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); } -# Child reaper -sub reaper { - my $child; - - while ( ($child = waitpid(-1, WNOHANG)) > 0 ) { - # msg ("Checker $child stopped.\n"); +# 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(); } - $SIG{CHLD} = \&reaper; + + # 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 ("$$ ", @_); + print ($$, ' ', scalar(localtime()), ' ', @_) unless ($quiet); } diff --git a/xr/balancer/serve.cc b/xr/balancer/serve.cc @@ -183,7 +183,6 @@ void Balancer::serve() { // 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(); diff --git a/xr/etc/status-savebutton.xslt b/xr/etc/status-savebutton.xslt @@ -50,11 +50,15 @@ document.location = uri; } } - function save(uri, name) { - var elem = getElementById(name); - var val = name.value; - alert('name: ' + name + ', value: ' + val); - } + } + 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> @@ -204,7 +208,7 @@ <td class="header" colspan="3"> <b>Server <xsl:value-of select="address"/> </b> </td> - <td class="header"> + <td class="header" align="right"> <input type="button" onclick="goto('/', '');" value="Refresh"/> </td> </tr> @@ -249,7 +253,7 @@ </xsl:otherwise> </xsl:choose> <input type="button" value="Save" - onclick="save('/server/type', 'servertype');"/> + onclick="save('/server/type/', 'servertype');"/> </td> </tr> <tr> @@ -267,8 +271,9 @@ </td> <td> <input type="text" size="8" name="wakeupinterval" - id="wakeupinterval" value="{checks/wakeupinterval}" - onchange="goto('/server/wakeupinterval/', 'wakeupinterval');"/> + id="wakeupinterval" value="{checks/wakeupinterval}"/> + <input type="button" value="Save" + onclick="save('/server/wakeupinterval/', 'wakeupinterval');"/> </td> </tr> <tr> @@ -286,16 +291,37 @@ </td> <td> <input type="text" size="8" name="checkupinterval" - id="checkupinterval" value="{checks/checkupinterval}" - onchange="goto('/server/checkupinterval/', '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/write</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="clienttimeout = 0"> + <xsl:when test="clientwritetimeout = 0"> unlimited </xsl:when> <xsl:otherwise> @@ -303,18 +329,39 @@ </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> - <input type="text" size="8" name="clienttimeout" - id="clienttimeout" value="{clienttimeout}" - onchange="goto('/server/clienttimeout/', 'clienttimeout');"/> + <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>Backend read/write/connect</td> + <td>Back end write</td> <td> <xsl:choose> - <xsl:when test="backendtimeout = 0"> + <xsl:when test="backendwritetimeout = 0"> unlimited </xsl:when> <xsl:otherwise> @@ -323,9 +370,10 @@ </xsl:choose> </td> <td> - <input type="text" size="8" name="backendtimeout" - id="backendtimeout" value="{backendtimeout}" - onchange="goto('/server/backendtimeout/', 'backendtimeout');"/> + <input type="text" size="8" name="backendwritetimeout" + id="backendwritetimeout" value="{backendwritetimeout}"/> + <input type="button" value="Save" + onclick="save('/server/backendwritetimeout/', 'backendwritetimeout');"/> </td> </tr> <tr> @@ -343,69 +391,76 @@ </td> <td> <input type="text" size="8" name="dnscachetimeout" - id="dnscachetimeout" value="{dnscachetimeout}" - onchange="goto('/server/dnscachetimeout/', '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> + <td align="right"> <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 name="closesocketsfast" id="closesocketsfast"> + <option value="on">yes</option> + <option value="off" 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 name="closesocketsfast" id="closesocketsfast"> + <option value="on" selected="1">yes</option> + <option value="off">no</option> </select> </xsl:otherwise> - </xsl:choose> + </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> + <td align="right"> <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 name="serververbose" id="serververbose"> + <option value="on">yes</option> + <option value="off" 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 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> + <td align="right"> <xsl:choose> <xsl:when test="debugging/debug = 0"> - <select onchange="goto('/server/debug/on', '');"> + <select name="serverdebug" id="serverdebug"> <option value="yes">yes</option> <option value="no" selected="1">no</option> </select> </xsl:when> <xsl:otherwise> - <select onchange="goto('/server/debug/off', '');"> + <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> @@ -413,8 +468,9 @@ <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');"/> + value="{debugging/logtrafficdir}"/> + <input type="button" value="Save" + onclick="goto('/server/logtrafficdir/', 'logtrafficdir');"/> </td> </tr> <tr> @@ -422,8 +478,9 @@ <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');"/> + value="{onstart}"/> + <input type="button" value="Save" + onclick="save('/server/onstart/', 'onstart');"/> </td> </tr> <tr> @@ -431,8 +488,9 @@ <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');"/> + value="{onend}"/> + <input type="button" value="Save" + onclick="save('/server/onend/', 'onend');"/> </td> </tr> <tr> @@ -440,8 +498,9 @@ <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');"/> + value="{onfail}"/> + <input type="button" value="Save" + onclick="save('/server/onfail/', 'onfail');"/> </td> </tr> <tr> @@ -449,8 +508,9 @@ <td colspan="2">bytes</td> <td> <input type="text" size="8" name="serverbufsz" id="serverbufsz" - value="{buffersize}" - onchange="goto('/server/buffersize/', 'serverbufsz');"/> + value="{buffersize}"/> + <input type="button" value="Save" + onclick="save('/server/buffersize/', 'serverbufsz');"/> </td> </tr> <tr> diff --git a/xr/fdset/readable.cc b/xr/fdset/readable.cc @@ -43,10 +43,9 @@ int Fdset::readable() const { throw Error(string("Select failure: failed to wait for " "readable state: ") + strerror(errno)); - else - return (-1); + return (-1); } - + // Check for exceptions. for (unsigned i = 0; i < set.size(); i++) if (FD_ISSET (set[i], &exceptset)) { @@ -66,4 +65,3 @@ int Fdset::readable() const { debugmsg ("No readable fd's at this time\n"); return (-1); } - diff --git a/xr/fdset/readwriteable.cc b/xr/fdset/readwriteable.cc @@ -34,8 +34,7 @@ int Fdset::readwriteable() const { throw Error(string("Select failure: failed to wait for " "read/writeablestate: ") + strerror(errno)); - else - return (-1); + return (-1); } // Check for exceptions. diff --git a/xr/fdset/writeable.cc b/xr/fdset/writeable.cc @@ -34,8 +34,7 @@ int Fdset::writeable() const { throw Error(string("Select failure: failed to wait for " "writable state: ") + strerror(errno)); - else - return (-1); + return (-1); } // Check for exceptions. diff --git a/xr/netbuffer/netwrite.cc b/xr/netbuffer/netwrite.cc @@ -45,23 +45,25 @@ unsigned Netbuffer::netwrite (int fd, int timeout) const { 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) { + } 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; + << strerror(errno) << ", result=" << int(nwritten); throw Error(o.str()); } } diff --git a/xr/sys/socketclose.cc b/xr/sys/socketclose.cc @@ -13,6 +13,7 @@ void socketclose (int fd) { l.l_linger = 2; setsockopt (fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)); } - close (fd); + shutdown(fd, SHUT_RDWR); + close(fd); } } diff --git a/xr/webinterface/answer.cc b/xr/webinterface/answer.cc @@ -29,13 +29,13 @@ static double str2dbl (string const &s, string const &desc) { 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 Error("Bad " + desc); memcpy (&ret, &val, sizeof(ret)); diff --git a/xr/webinterface/execute.cc b/xr/webinterface/execute.cc @@ -59,5 +59,4 @@ void Webinterface::execute() { } msg ("Web interface stopping.\n"); socketclose(sfd); - shutdown (sfd, SHUT_RDWR); } diff --git a/xrctl/xrctl b/xrctl/xrctl @@ -327,9 +327,9 @@ sub is_running { # 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); @@ -417,9 +417,12 @@ sub xr_command { 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); } @@ -493,17 +496,17 @@ sub xr_cmdarr { # Timeouts when specified using separate tags my $t = $ss->data('clientreadtimeout'); if (defined($t)) { - my $fl = "--client-timeout $t"; + my $val = $t; $t = $ss->data('clientwritetimeout'); - $fl .= ":$t" if (defined($t)); - push (@cmd, $fl); + $val .= ":$t" if (defined($t)); + push (@cmd, '--client-timeout', $val); } $t = $ss->data('backendreadtimeout'); if (defined($t)) { - my $fl = "--backend-timeout $t"; + my $val = $t; $t = $ss->data('backendwritetimeout'); - $fl .= ":$t" if (defined($t)); - push (@cmd, $fl); + $val .= ":$t" if (defined($t)); + push (@cmd, '--backend-timeout', $val); } # ACL's @@ -573,9 +576,15 @@ sub xr_cmdarr { # 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); }