commit 59795206769652ca9498bbd2b1743136be4f3f0e
parent 8919cc1eda7a76e1deec7547d7988d465b093b74
Author: finwo <finwo@pm.me>
Date: Sat, 3 Jan 2026 19:37:42 +0100
2.53
Diffstat:
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);
}