commit 29c6fce29f9572bacbaddb0dfe126b5e956e04dc
parent 999c56944a289bbfecfa925fa0fc096a1dc26d75
Author: finwo <finwo@pm.me>
Date: Sat, 3 Jan 2026 19:34:55 +0100
2.01
Diffstat:
14 files changed, 46 insertions(+), 30 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -1 +1,10 @@
+2.01 [KK 2008-08-08] Implemented flag -C (--close-sockets-fast): this
+option *can* be used under heavy stress when too many network sockets
+remain in TIME_WAIT state (try with 'netstat -n | grep TIME_WAIT').
+Syntax of xrctl is checked upon "make commit".
+Added documentation about Solaris tcp_time_wait_interval and Linux
+ip_conntrack_max.
+Added documentation about binding XR to the same port, using different
+bind-to IP's.
+
2.00 [KK 2008-08-07] Release of 2.00.
diff --git a/Makefile b/Makefile
@@ -1,7 +1,7 @@
# Top-level Makefile for XR
# -------------------------
-VER = 2.00
+VER = 2.01
BINDIR = /usr/sbin
TAR = /tmp/crossroads-$(VER).tar.gz
AUTHOR = Karel Kubat <karel@kubat.nl>
@@ -50,6 +50,7 @@ tar:
commit: local clean
test `svn status | grep '^\?' | wc -l` -eq 0 || \
- (echo 'SVN not fully up to date' && exit 1)
+ (echo 'SVN not fully up to date: run "svn status"' && exit 1)
+ perl -c xrctl/xrctl
svn commit
\ No newline at end of file
diff --git a/doc/xr.odt b/doc/xr.odt
Binary files differ.
diff --git a/doc/xr.pdf b/doc/xr.pdf
Binary files differ.
diff --git a/xr/backend/check.cc b/xr/backend/check.cc
@@ -2,5 +2,5 @@
void Backend::check() {
connect();
- close (clsocket);
+ socketclose (clsocket);
}
diff --git a/xr/balancer/serve.cc b/xr/balancer/serve.cc
@@ -40,7 +40,7 @@ void Balancer::serve() {
msg ("Interrupt seen\n");
if (terminate()) {
msg ("Termination requested, XR will stop.\n");
- close (server_fd);
+ socketclose (server_fd);
shutdown (server_fd, SHUT_RDWR);
unsigned prev_conn = 0x19081962;
while (1) {
@@ -107,7 +107,7 @@ void Balancer::serve() {
if (!allowed) {
msg ("Not serving client " + clientip +
": no match in allow list\n");
- close (clsock);
+ socketclose (clsock);
continue;
}
}
@@ -122,7 +122,7 @@ void Balancer::serve() {
if (denied) {
msg ("Not serving client " + clientip +
": match in deny list\n");
- close (clsock);
+ socketclose (clsock);
continue;
}
@@ -154,7 +154,7 @@ void Balancer::serve() {
o << connections() << " connections (max "
<< config.maxconn() << ")";
msg ("Not serving client: already " + o.str() + "\n");
- close (clsock);
+ socketclose (clsock);
continue;
}
diff --git a/xr/config/config b/xr/config/config
@@ -44,6 +44,8 @@ public:
string serverheader (unsigned n) { return (serverheaders[n]); }
unsigned nallow() const { return (allowlist.size()); }
unsigned ndeny() const { return (denylist.size()); }
+ bool fastclose() const { return (fast_close); }
+ void fastclose (bool f) { fast_close = f; }
struct in_addr allow(unsigned n) const {
return (allowlist[n]);
@@ -90,6 +92,7 @@ private:
static vector<string> serverheaders;
static vector<struct in_addr> allowlist;
static vector<struct in_addr> denylist;
+ static bool fast_close;
};
extern Config config;
diff --git a/xr/config/config1.cc b/xr/config/config1.cc
@@ -23,6 +23,7 @@ bool Config::prefix_timestamp = false;
vector<string> Config::serverheaders;
vector<struct in_addr> Config::allowlist;
vector<struct in_addr> Config::denylist;
+bool Config::fast_close = false;
Config::Config () {
}
diff --git a/xr/config/parsecmdline.cc b/xr/config/parsecmdline.cc
@@ -21,6 +21,7 @@ void Config::parsecmdline (int ac, char **av) {
{ "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' },
{ "foreground", no_argument, 0, 'f' },
@@ -62,6 +63,9 @@ void Config::parsecmdline (int ac, char **av) {
case 'c':
checkup = setinteger (optarg);
break;
+ case 'C':
+ fast_close = true;
+ break;
case 'D':
verbose_flag = true;
debug_flag = true;
diff --git a/xr/etc/usage.txt b/xr/etc/usage.txt
@@ -12,6 +12,8 @@ Usage: xr [flags], where the flags may be:
defines the maximum connections for the back end.
-b SIZE, --buffer-size SIZE
Sets the network buffer size, default is 2048 (in bytes)
+ -C, --close-sockets-fast
+ Sockets are closed faster to avoid TIME_WAIT states.
-c SEC, --checkup-interval SEC
Defines the back end checking period. Each SEC seconds, every back end
is checked whether it is alive. Default is 0 (off).
diff --git a/xr/sys/socketclose.cc b/xr/sys/socketclose.cc
@@ -0,0 +1,12 @@
+#include "sys"
+#include "../config/config"
+
+void socketclose (int fd) {
+ if (config.fastclose()) {
+ struct linger l;
+ l.l_onoff = 1;
+ l.l_linger = 0;
+ setsockopt (fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
+ }
+ close (fd);
+}
diff --git a/xr/sys/sys b/xr/sys/sys
@@ -40,5 +40,6 @@ void reportmsg (string const &s);
int serversocket (string addr, int port, string description);
string timestamp();
bool ipmatch (struct in_addr addr, struct in_addr mask);
+void socketclose (int fd);
#endif
diff --git a/xr/tcpdispatcher/execute.cc b/xr/tcpdispatcher/execute.cc
@@ -9,7 +9,7 @@ void TcpDispatcher::execute() {
dispatch();
} catch (Error e) {
cerr << e.txt() << "\n";
- close (clientfd());
+ socketclose (clientfd());
return;
}
@@ -35,8 +35,8 @@ void TcpDispatcher::execute() {
balancer.backend(target_backend).endconnection();
unlock();
- close (clientfd());
- close (backendfd());
+ socketclose (clientfd());
+ socketclose (backendfd());
msg ("Done dispatching client fd " + co.str() + " at " +
balancer.backend(target_backend).description() + "\n");
diff --git a/xrctl/xrctl b/xrctl/xrctl
@@ -37,24 +37,6 @@ my @bindirs = qw(/bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin
my %services =
(
- # Basically just a port forwarder to localhost:80. I use it for
- # benchmarking.
- 'fwd1' =>
- { '--server' => [ qw(tcp:0:10000) ],
- '--backend' => [ qw(localhost:80) ],
- # '--verbose' => undef,
- # '--debug' => undef,
- },
-
- # Same thing, but a HTTP forwarder that adds X-Forwarded-For headers.
- # I use it for benchmarking HTTP handling.
- 'fwd2' =>
- { '--server' => [ qw(http:0:10001) ],
- '--backend' => [ qw(localhost:80) ],
- # '--verbose' => undef,
- },
-
-
# Web servers balancing to 3 back ends at 10.0.0.1 thru 3. The
# balancer will use HTTP mode and add X-Forwarded-For headers.
'webone' =>
@@ -78,7 +60,8 @@ my %services =
# An Access Control List (ACL) example, again using web balancing.
# Allowed clients are 127.0.0.1 (localhost) and 192.168.*.*, except
- # for 192.168.1.250.
+ # for 192.168.1.250. Also, flag -C / --close-sockets-fast is added to
+ # avoid TIME_WAIT states under heavy load.
'webthree' =>
{ '--server' => [ qw(http:0:82) ],
'--backend' => [ qw(10.1.1.1:80 10.1.1.2:80 10.1.1.3:80) ],
@@ -86,9 +69,9 @@ my %services =
'--add-x-forwarded-for' => undef,
'--allow-from' => [ qw(127.0.0.1 192.168.255.255) ],
'--deny-from' => [ qw(192.168.1.250) ],
+ '--close-sockets-fast' => undef,
},
-
# An SSH session balancer on port 2222. We set the client time out
# to 2 hours. Requests are balanced to server1, server2 and server3,
# all to port 22.