commit 42b59853f31cfc5a45104fc891507377a0a85de2
parent a9e440801e66c92ffbdf8cc7362fc0af36d32345
Author: finwo <finwo@pm.me>
Date: Sat, 3 Jan 2026 19:35:59 +0100
2.16
Diffstat:
14 files changed, 253 insertions(+), 36 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -1,3 +1,11 @@
+2.16
+- Enhanced web interface to show debug, verbose and traffic log states
+- Altering parameters for the web interface get sent in encoded form
+- Option --log-traffic was renamed to --log-traffic-dir for
+ consistency
+- Enhanced web interface to modify client and back end timeouts
+- Enhanced web interface to modify wakeup / checkup intervals.
+
2.15
- Sanity checks in Config::parsecmdline(): -w/-c together throws error.
- Network sends are now using write(), unless under Solaris, which
diff --git a/Makefile b/Makefile
@@ -1,7 +1,7 @@
# Top-level Makefile for XR
# -------------------------
-VER = 2.15
+VER = 2.16
BINDIR = /usr/sbin
TAR = /tmp/crossroads-$(VER).tar.gz
AUTHOR = Karel Kubat <karel@kubat.nl>
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/config/config b/xr/config/config
@@ -19,7 +19,10 @@ public:
// Accessors
bool verbose() const { return (verbose_flag); }
+ void verbose (bool v) { verbose_flag = v; }
+
bool debug() const { return (debug_flag); }
+ void debug (bool d) { debug_flag = d; }
Servertype::Type stype() const { return (styp.type()); }
string stypestr() const { return (styp.typestr()); }
@@ -28,11 +31,17 @@ public:
int backends() const { return (blist.size()); }
- int client_timeout() const { return (c_timeout); }
- int backend_timeout() const { return (b_timeout); }
+ unsigned client_timeout() const { return (c_timeout); }
+ void client_timeout (unsigned c) { c_timeout = c; }
+
+ unsigned backend_timeout() const { return (b_timeout); }
+ void backend_timeout (unsigned b) { b_timeout = b; }
+
+ unsigned wakeupsec() const { return (wakeup); }
+ void wakeupsec (unsigned w) { wakeup = w; }
- int wakeupsec() const { return (wakeup); }
- int checkupsec() const { return (checkup); }
+ unsigned checkupsec() const { return (checkup); }
+ void checkupsec (unsigned w) { checkup = w; }
unsigned buffersize() const { return (bufsize); }
void buffersize (unsigned b);
@@ -111,10 +120,10 @@ private:
static string sip;
static vector<BackendDef> blist;
static Dispatchmode dmode;
- static int c_timeout;
- static int b_timeout;
- static int wakeup;
- static int checkup;
+ static unsigned c_timeout;
+ static unsigned b_timeout;
+ static unsigned wakeup;
+ static unsigned checkup;
static unsigned bufsize;
static bool foreground_mode;
static bool add_xr_version;
diff --git a/xr/config/config1.cc b/xr/config/config1.cc
@@ -6,10 +6,10 @@ Servertype Config::styp;
string Config::sip = "0";
vector<BackendDef> Config::blist;
Dispatchmode Config::dmode;
-int Config::c_timeout = 30;
-int Config::b_timeout = 30;
-int Config::wakeup = 5;
-int Config::checkup = 0;
+unsigned Config::c_timeout = 30;
+unsigned Config::b_timeout = 30;
+unsigned Config::wakeup = 5;
+unsigned Config::checkup = 0;
unsigned Config::bufsize = 2048;
bool Config::foreground_mode = false;
bool Config::add_xr_version = false;
diff --git a/xr/config/parsecmdline.cc b/xr/config/parsecmdline.cc
@@ -30,7 +30,7 @@ void Config::parsecmdline (int ac, char **av) {
{ "foreground", no_argument, 0, 'f' },
{ "help", no_argument, 0, 'h' },
{ "add-server-header", required_argument, 0, 'H' },
- { "log-traffic", required_argument, 0, 'l' },
+ { "log-traffic-dir", required_argument, 0, 'l' },
{ "max-connections", required_argument, 0, 'm' },
{ "host-match", required_argument, 0, 'M' },
{ "tryout", no_argument, 0, 'n' },
diff --git a/xr/etc/status.xslt b/xr/etc/status.xslt
@@ -40,7 +40,9 @@
if (el) {
var value = el.value;
if (value != "")
- document.location = uri + value;
+ document.location = uri + encodeURIComponent(value);
+ else
+ document.location = uri;
}
}
}
@@ -71,41 +73,125 @@
<td colspan="3"> <xsl:value-of select="type"/> </td>
</tr>
<tr>
- <td>Timeouts</td>
- <td>client: <xsl:value-of select="clienttimeout"/></td>
- <td colspan="2">backend: <xsl:value-of select="backendtimeout"/></td>
- </tr>
+ <td>Dispatch mode</td>
+ <td colspan="3"> <xsl:value-of select="dispatchmode"/> </td>
+ </tr>
<tr>
<td>Checks</td>
- <td>wakeups</td>
- <td colspan="2">
+ <td>Wakeup interval</td>
+ <td>
<xsl:choose>
<xsl:when test="checks/wakeupinterval = 0">
off
</xsl:when>
<xsl:otherwise>
- each <xsl:value-of select="checks/wakeupinterval"/> sec.
+ sec
</xsl:otherwise>
</xsl:choose>
</td>
+ <td>
+ <input type="text" size="8" name="wakeupinterval"
+ id="wakeupinterval" value="{checks/wakeupinterval}"
+ onchange="goto('/server/wakeupinterval/', 'wakeupinterval');"/>
+ </td>
</tr>
<tr>
<td></td>
- <td>checkups</td>
- <td colspan="2">
+ <td>Checkup interval</td>
+ <td>
<xsl:choose>
<xsl:when test="checks/checkupinterval = 0">
off
</xsl:when>
<xsl:otherwise>
- each <xsl:value-of select="checks/checkupinterval"/> sec.
+ sec
</xsl:otherwise>
</xsl:choose>
</td>
+ <td>
+ <input type="text" size="8" name="checkupinterval"
+ id="checkupinterval" value="{checks/checkupinterval}"
+ onchange="goto('/server/checkupinterval/', 'checkupinterval');"/>
+ </td>
</tr>
<tr>
- <td>Dispatch mode</td>
- <td colspan="3"> <xsl:value-of select="dispatchmode"/> </td>
+ <td>Timeouts</td>
+ <td>Client</td>
+ <td>
+ <xsl:choose>
+ <xsl:when test="clienttimeout = 0">
+ unlimited
+ </xsl:when>
+ <xsl:otherwise>
+ sec
+ </xsl:otherwise>
+ </xsl:choose>
+ </td>
+ <td>
+ <input type="text" size="8" name="clienttimeout"
+ id="clienttimeout" value="{clienttimeout}"
+ onchange="goto('/server/clienttimeout/', 'clienttimeout');"/>
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>Backend</td>
+ <td>
+ <xsl:choose>
+ <xsl:when test="backendtimeout = 0">
+ unlimited
+ </xsl:when>
+ <xsl:otherwise>
+ sec
+ </xsl:otherwise>
+ </xsl:choose>
+ </td>
+ <td>
+ <input type="text" size="8" name="backendtimeout"
+ id="backendtimeout" value="{backendtimeout}"
+ onchange="goto('/server/backendtimeout/', 'backendtimeout');"/>
+ </td>
+ </tr>
+ <tr>
+ <td>Debugging</td>
+ <td colspan="2">Verbose logging</td>
+ <td>
+ <xsl:choose>
+ <xsl:when test="debugging/verbose = 0">
+ <input type="text" size="8" name="verbose" id="verbose" value="off"
+ onchange="goto('/server/verbose/', 'verbose');"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <input type="text" size="8" name="verbose" id="verbose" value="on"
+ onchange="goto('/server/verbose/', 'verbose');"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td colspan="2">Debug logging</td>
+ <td>
+ <xsl:choose>
+ <xsl:when test="debugging/debug = 0">
+ <input type="text" size="8" name="debug" id="debug" value="off"
+ onchange="goto('/server/debug/', 'debug');"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <input type="text" size="8" name="debug" id="debug" value="on"
+ onchange="goto('/server/debug/', 'debug');"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td colspan="2">Traffic log directory</td>
+ <td>
+ <input type="text" size="8" name="logtrafficdir" id="logtrafficdir"
+ value="{debugging/logtrafficdir}"
+ onchange="goto('/server/logtrafficdir/', 'logtrafficdir');"/>
+ </td>
</tr>
<tr>
<td>Network buffer size</td>
diff --git a/xr/etc/usage.txt b/xr/etc/usage.txt
@@ -52,8 +52,9 @@ may not exist on your platform):
This text.
-H HDR, --add-server-header HDR
Inserts HDR into back end bound HTTP messages.
- -l DIR, --log-traffic DIR
- Log passing traffic with dumps in DIR. Only for debugging, very slow!
+ -l DIR, --log-traffic-dir DIR
+ Log passing traffic with dumps in DIR. Only for debugging, slows
+ down the balancer.
-m MAX, --max-connections MAX
Sets the maximum number of connections to the balancer. Default is 0,
no maximum.
diff --git a/xr/sys/fdwrite.cc b/xr/sys/fdwrite.cc
@@ -17,10 +17,12 @@ void fdwrite (int fd, int timeout, char const *buf, unsigned buflen) {
FILE *f;
if ( (!(f = fopen (of.str().c_str(), "a"))) &&
(!(f = fopen (of.str().c_str(), "w"))) )
- throw static_cast<Error>("Cannot write traffic log ") +
- of.str() + ": " + strerror(errno);
- fwrite (buf, 1, buflen, f);
- fclose (f);
+ warnmsg ("Cannot write traffic log " + of.str() + ": " +
+ strerror(errno) + "\n");
+ else {
+ fwrite (buf, 1, buflen, f);
+ fclose (f);
+ }
}
// Send to the socket
diff --git a/xr/sys/sys b/xr/sys/sys
@@ -53,6 +53,7 @@ bool ipmatch (struct in_addr addr, struct in_addr mask);
void socketclose (int fd);
vector<string> str2parts (string const &s, char sep);
void fdwrite (int fd, int timeout, char const *buf, unsigned buflen);
+void warnmsg (string const &s);
#ifndef HAVE_INET_ATON
int inet_aton (char const *name, struct in_addr *addr);
diff --git a/xr/sys/warnmsg.cc b/xr/sys/warnmsg.cc
@@ -0,0 +1,12 @@
+#include "sys"
+#include "config/config"
+#include "ThreadsAndMutexes/mutex/mutex"
+
+void warnmsg (string const &s) {
+ Mutex::lock(&cerr);
+ if (config.prefixtimestamp())
+ cerr << timestamp() << ' ';
+ cerr << pthread_self() << " WARNING: " << s;
+ cerr.flush();
+ Mutex::unlock(&cerr);
+}
diff --git a/xr/webinterface/answer.cc b/xr/webinterface/answer.cc
@@ -55,6 +55,8 @@ string decode (string const &s) {
}else {
ret += '%';
}
+ } else if (*cp == '+') {
+ ret += ' ';
} else {
ret += *cp;
cp++;
@@ -99,10 +101,13 @@ void Webinterface::answer(Httpbuffer req) {
return;
}
+ // /server/maxconnections/
// /server/maxconnections/NUMBER
- if (parts.size() == 3 &&
- parts[0] == "server" && parts[1] == "maxconnections") {
- unsigned num = str2uns (parts[2], "server weight");
+ if ( (parts.size() == 2 || parts.size() == 3) &&
+ (parts[0] == "server" && parts[1] == "maxconnections") ) {
+ unsigned num = 0;
+ if (parts.size() == 3)
+ num = str2uns (parts[2], "server weight");
config.maxconn(num);
answer_status();
return;
@@ -154,6 +159,94 @@ void Webinterface::answer(Httpbuffer req) {
return;
}
+ // /server/verbose
+ // /server/verbose/VALUE
+ if ( (parts.size() == 2 || parts.size() == 3) &&
+ (parts[0] == "server" && parts[1] == "verbose") ) {
+ if (parts.size() == 2 || parts[2] == "off" || parts[2] == "0")
+ config.verbose(false);
+ else
+ config.verbose(true);
+ answer_status();
+ return;
+ }
+
+ // /server/debug
+ // /server/debug/VALUE
+ if ( (parts.size() == 2 || parts.size() == 3) &&
+ (parts[0] == "server" && parts[1] == "debug") ) {
+ if (parts.size() == 2 || parts[2] == "off" || parts[2] == "0")
+ config.debug(false);
+ else
+ config.debug(true);
+ answer_status();
+ return;
+ }
+
+ // /server/logtrafficdir
+ // /server/logtrafficdir/VALUE
+ if ( (parts.size() == 2 || parts.size() == 3) &&
+ (parts[0] == "server" && parts[1] == "logtrafficdir") ) {
+ if (parts.size() == 2)
+ config.dumpdir("");
+ else
+ config.dumpdir(parts[2]);
+ answer_status();
+ return;
+ }
+
+ // /server/clienttimeout
+ // /server/clienttimeout/NUMBER
+ if ( (parts.size() == 2 || parts.size() == 3) &&
+ (parts[0] == "server" && parts[1] == "clienttimeout") ) {
+ unsigned num = 0;
+ if (parts.size() == 3)
+ num = str2uns (parts[2], "client timeout");
+ config.client_timeout(num);
+ answer_status();
+ return;
+ }
+
+ // /server/backendtimeout
+ // /server/backendtimeout/NUMBER
+ if ( (parts.size() == 2 || parts.size() == 3) &&
+ (parts[0] == "server" && parts[1] == "backendtimeout") ) {
+ unsigned num = 0;
+ if (parts.size() == 3)
+ num = str2uns (parts[2], "client timeout");
+ config.backend_timeout(num);
+ answer_status();
+ return;
+ }
+
+ // /server/wakeupinterval
+ // /server/wakeupinterval/NUMBER
+ if ( (parts.size() == 2 || parts.size() == 3) &&
+ (parts[0] == "server" && parts[1] == "wakeupinterval") ) {
+ unsigned num = 0;
+ if (parts.size() == 3)
+ num = str2uns (parts[2], "wakeup interval");
+ if (num)
+ config.checkupsec(0);
+ config.wakeupsec(num);
+ answer_status();
+ return;
+ }
+
+ // /server/checkupinterval
+ // /server/checkupinterval/NUMBER
+ if ( (parts.size() == 2 || parts.size() == 3) &&
+ (parts[0] == "server" && parts[1] == "checkupinterval") ) {
+ unsigned num = 0;
+ if (parts.size() == 3)
+ num = str2uns (parts[2], "checkup interval");
+ if (num)
+ config.wakeupsec(0);
+ config.checkupsec(num);
+ answer_status();
+ return;
+ }
+
// /backend/NR/weight/NUMBER
if (parts.size() == 4 &&
parts[0] == "backend" && parts[2] == "weight") {
diff --git a/xr/webinterface/answerstatus.cc b/xr/webinterface/answerstatus.cc
@@ -23,6 +23,11 @@ void Webinterface::answer_status() {
" <wakeupinterval>" << config.wakeupsec() << "</wakeupinterval>\n"
" <checkupinterval>" << config.checkupsec() << "</checkupinterval>\n"
" </checks>\n"
+ " <debugging>\n"
+ " <verbose>" << config.verbose() << "</verbose>\n"
+ " <debug>" << config.debug() << "</debug>\n"
+ " <logtrafficdir>" << config.dumpdir() << "</logtrafficdir>\n"
+ " </debugging>\n"
" <http>\n"
" <addxrversion>" << config.addxrversion() << "</addxrversion>\n"
" <addxforwardedfor>" << config.addxforwardedfor() << "</addxforwardedfor>\n"