commit f918d5b94e797ed0459a12f0b146db505ea6cc54
parent 2dbec574cac34303db2f6f1256a7cd5b8272b0d8
Author: finwo <finwo@pm.me>
Date: Sat, 3 Jan 2026 19:38:59 +0100
2.75
Diffstat:
14 files changed, 106 insertions(+), 45 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -1,3 +1,11 @@
+2.75 [KK 2011-05-23]
+- Signal SIGUSR1 toggles verbose logging, SIGUSR2 toggles debug
+ logging.
+- Back end connection attempts improved (assumes "alive" unless a
+ failure is seen).
+- Flag parsing for -p / --pidfile fixed.
+- Warning: Memory leak reported with high load. Under investigation.
+
2.74 [KK 2011-04-05]
- Promoted to STABLE. A word of warning: DOS protection under high
load may be unstable, currently under investigation.
diff --git a/Makefile b/Makefile
@@ -1,7 +1,7 @@
# Top-level Makefile for XR
# -------------------------
-VER ?= 2.74
+VER ?= 2.75
PREFIX ?= $(DESTDIR)/usr
BINDIR ?= $(PREFIX)/sbin
MANDIR ?= $(PREFIX)/share/man
diff --git a/xr/Dispatchers/httpdispatcher/dispatch.cc b/xr/Dispatchers/httpdispatcher/dispatch.cc
@@ -13,12 +13,15 @@ void HttpDispatcher::dispatch() {
// 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())) {
- msg ("Didn't receive a valid client request, stopping");
- return;
+ while (!buf().headersreceived()) {
+ // cout << "BUFFER fetching headers: " << buf().as_string() << '\n';
+ if (! buf().netread(clientfd(), config.client_read_timeout())) {
+ msg("Didn't receive a valid client request, stopping");
+ throw Error("No HTTP request received");
}
- msg ("Received client request: '" + buf().firstline() + "'\n");
+ }
+ msg("Received client request: '" + buf().firstline() + "'\n");
+ // cout << "BUFFER with headers: " << buf().as_string() << '\n';
// See if hostmatching or urlmatching is used.
// This is true when hosts or urls are matched against non-dot.
@@ -33,7 +36,7 @@ void HttpDispatcher::dispatch() {
// Build new target list if host- or url matching applies.
if (hostmatchused || urlmatchused) {
- msg ("Creating matched target list for the HTTP dispatcher\n");
+ msg("Creating matched target list for the HTTP dispatcher\n");
if (hostmatchused)
host_header = buf().headerval("Host");
@@ -75,10 +78,10 @@ void HttpDispatcher::dispatch() {
// 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) ||
+ (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();
@@ -87,11 +90,12 @@ void HttpDispatcher::dispatch() {
// to non-sticky dispatching.
targetbackend(stickytarget);
Backend tb = balancer.backend(stickytarget);
- msg ("Sticky HTTP request for " + tb.description() + "\n");
+ tb.live(true);
+ 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");
+ msg("Failed to connect to back end " + tb.description() +
+ ", trying to dispatch to other\n");
issticky(false);
TcpDispatcher::dispatch();
} else {
diff --git a/xr/Dispatchers/httpdispatcher/handle.cc b/xr/Dispatchers/httpdispatcher/handle.cc
@@ -42,16 +42,19 @@ void HttpDispatcher::handle() {
readset.wait_r();
Socket sock;
- if (readset.readable(clientfd()))
+ unsigned timeout;
+ if (readset.readable(clientfd())) {
sock = clientfd();
- else if (readset.readable(backendfd()))
+ timeout = config.client_read_timeout();
+ } else if (readset.readable(backendfd())) {
sock = backendfd();
- else
+ timeout = config.backend_read_timeout();
+ } else
break;
buf().reset();
- if (!buf().netread(sock))
+ if (!buf().netread(sock, timeout))
break;
if (sock == backendfd() && modify_serverheaders) {
@@ -83,10 +86,9 @@ void HttpDispatcher::handle() {
// Flush info to the other connected side.
Socket othersock;
- int timeout;
if (sock == clientfd()) {
othersock = backendfd();
- timeout = config.backend_read_timeout();
+ timeout = config.backend_write_timeout();
// Re-patch Host header if requested
if (config.replacehostheader())
buf().replaceheader("Host:",
@@ -94,7 +96,7 @@ void HttpDispatcher::handle() {
.server());
} else {
othersock = clientfd();
- timeout = config.client_read_timeout();
+ timeout = config.client_write_timeout();
}
debugmsg ("Had data on " << sock.fd() <<
@@ -104,5 +106,4 @@ void HttpDispatcher::handle() {
if (sock == backendfd())
balancer.backend(targetbackend()).addbytes(buf().bufsz());
}
-
}
diff --git a/xr/Dispatchers/tcpdispatcher/execute.cc b/xr/Dispatchers/tcpdispatcher/execute.cc
@@ -15,7 +15,9 @@ void TcpDispatcher::execute() {
Threadlist::desc("Dispatching");
dispatch();
} catch (Error const &e) {
- warnmsg(e.what() << '\n');
+ warnmsg(e.what() << " ("
+ << inet2string(clientfd().clientaddr().sin_addr)
+ << ")\n");
return;
}
@@ -49,7 +51,9 @@ void TcpDispatcher::execute() {
try {
handle();
} catch (Error const &e) {
- warnmsg(e.what() << '\n');
+ warnmsg(e.what() << " ("
+ << inet2string(clientfd().clientaddr().sin_addr)
+ << ")\n");
failed = true;
if (config.onfail().length()) {
ostringstream o;
diff --git a/xr/backend/connect.cc b/xr/backend/connect.cc
@@ -3,9 +3,6 @@
bool Backend::connect() {
PROFILE("Backend::connect");
- // Assume the backend is dead
- islive = false;
-
debugmsg("About to connect to back end " << description() << '\n');
// Resolve hostname, prepare binding
@@ -45,12 +42,14 @@ bool Backend::connect() {
# ifdef CONNECTCHECK_ONLY_WRITABLE
if (fdset.writeable(clsocket))
- islive = true;
- else
+ live(true);
+ else {
markconnecterror();
-# else
+ live(false);
+ }
+# else
if (fdset.writeable(clsocket) && !fdset.readable(clsocket))
- islive = true;
+ live(true);
else {
debugmsg("Connect socket writable: " <<
(fdset.writeable(clsocket) ? "yes" : "no") <<
@@ -58,6 +57,7 @@ bool Backend::connect() {
(fdset.readable(clsocket) ? "yes" : "no") <<
'\n');
markconnecterror();
+ live(false);
}
# endif
}
diff --git a/xr/config/parsecmdline.cc b/xr/config/parsecmdline.cc
@@ -19,7 +19,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:Gg:hH:Ij:l:" \
- "m:M:nPQ:r:R:Ss:t:T:u:U:vVW:w:xXy:Y:z:Z:"
+ "m:M:np:PQ:r:R:Ss:t:T:u:U:vVW:w:xXy:Y:z:Z:"
# ifdef HAVE_GETOPT_LONG
static struct option longopts[] = {
{ "allow-from", required_argument, 0, 'a' },
@@ -157,6 +157,9 @@ void Config::parsecmdline (int ac, char **av) {
case 'P':
prefix_timestamp = true;
break;
+ case 'p':
+ pidfile(optarg);
+ break;
case 'Q':
quit_after = (unsigned) setinteger(optarg);
break;
diff --git a/xr/etc/usage.txt b/xr/etc/usage.txt
@@ -182,6 +182,9 @@ may not exist on your platform):
XR's errors and warnings are sent to stderr, debugging and verbose
messages go to stdout. Invoke XR daemons using something like
"xr --backend ... [other flags] 2>&1 | logger &", or use xrctl.
-Send signal SIGHUP (-1) to xr to have it report back end states. Other
-typical signals request termination.
+
+Send signal SIGHUP (-1) to write back end states to the log.
+Send signal SUGUSR1 (-30) to toggle verbose logging.
+Send signal SIGUSR2 (-31) to toggle debug logging.
+Other typical signals request termination.
diff --git a/xr/fdset/fdset b/xr/fdset/fdset
@@ -22,10 +22,10 @@ public:
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); }
+ double wait(bool wait_read, bool wait_write);
+ double wait_rw() { return wait(true, true); }
+ double wait_r() { return wait(true, false); }
+ double wait_w() { return wait(false, true); }
bool readable(int fd) { return FD_ISSET(fd, &readset); }
bool readable(Socket &s) { return FD_ISSET(s.fd(), &readset); }
diff --git a/xr/fdset/wait.cc b/xr/fdset/wait.cc
@@ -1,8 +1,9 @@
#include "fdset"
-void Fdset::wait(bool wait_read, bool wait_write) {
+double Fdset::wait(bool wait_read, bool wait_write) {
PROFILE("Fdset::wait");
+ Timestamp start;
struct timeval tv, *tvp;
// No fd's? Nothing to wait for.
@@ -42,7 +43,7 @@ void Fdset::wait(bool wait_read, bool wait_write) {
FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_ZERO(&exceptset);
- return;
+ return start.elapsed();
}
// Check for exceptions.
@@ -76,4 +77,7 @@ void Fdset::wait(bool wait_read, bool wait_write) {
debugmsg(o.str());
}
}
+
+ // All done. Return microsecs since start.
+ return start.elapsed();
}
diff --git a/xr/httpbuffer/asstring.cc b/xr/httpbuffer/asstring.cc
@@ -0,0 +1,10 @@
+#include "httpbuffer"
+
+string Httpbuffer::as_string() const {
+ string ret = "";
+
+ for (unsigned i = 0; i < bufsz(); i++)
+ ret += charat(i);
+
+ return ret;
+}
diff --git a/xr/httpbuffer/httpbuffer b/xr/httpbuffer/httpbuffer
@@ -41,6 +41,7 @@ public:
string requesturi();
+ string as_string() const;
void reset();
private:
diff --git a/xr/netbuffer/netread.cc b/xr/netbuffer/netread.cc
@@ -4,10 +4,15 @@
unsigned Netbuffer::netread (Socket &s, unsigned timeout) {
PROFILE("Netbuffer::netread");
+// cout << "Netbuffer::netread: socket " << s.fd() << ", timeout "
+// << timeout << '\n';
+
+ double usec = 0;
+
if (timeout) {
Fdset set(timeout);
set.add(s);
- set.wait_r();
+ usec = set.wait_r();
if (! set.readable(s)) {
msg("Fd "<< s.fd() << " failed to become readable within " <<
timeout << " sec\n");
@@ -15,6 +20,8 @@ unsigned Netbuffer::netread (Socket &s, unsigned timeout) {
}
}
+ // cout << "fd " << s.fd() << " readable after " << usec << "usec\n";
+
check_space(config.buffersize());
// Read from the network. If this fails, don't throw an exception
@@ -28,12 +35,15 @@ unsigned Netbuffer::netread (Socket &s, unsigned timeout) {
if (config.debug() && nread) {
ostringstream o;
- o << "Got " << nread << " bytes from fd " << s.fd() << ": ";
+ o << "Got " << nread << " bytes from fd " << s.fd()
+ << ", timeout " << timeout << ": ";
for (unsigned i = 0; i < (unsigned)nread; i++)
o << printable(buf_data[i]);
o << "\n";
debugmsg (o.str());
}
+ // cout << "Fetched " << nread << " bytes\n";
+
return nread;
}
diff --git a/xr/sys/main.cc b/xr/sys/main.cc
@@ -57,10 +57,23 @@ static void sigcatcher (int sig) {
debugmsg("Seen signal " << sig << '\n');
switch (sig) {
case SIGHUP:
- /* Generate a report to the log. Somewhat stale given the
- * web interface. */
+ // Generate a report to the log.
balancer.report(true);
break;
+ case SIGUSR1:
+ // Toggle verbosity.
+ if (config.verbose())
+ config.verbose(false);
+ else
+ config.verbose(true);
+ break;
+ case SIGUSR2:
+ // Toggle debugging.
+ if (config.debug())
+ config.debug(false);
+ else
+ config.debug(true);
+ break;
default:
balancer.terminate(true);
break;
@@ -72,7 +85,7 @@ int main (int argc, char **argv) {
PROFILE("main");
static int relevant_sig[] = {
- SIGHUP, SIGINT, SIGQUIT, SIGABRT, SIGTERM, SIGSTOP,
+ SIGHUP, SIGINT, SIGQUIT, SIGABRT, SIGTERM, SIGSTOP, SIGUSR1, SIGUSR2
};
try {