crossroads

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

commit 0c0645fa76857155d5252c997d1ea87aa9691cb1
parent 74a71dbeeea3a2ce4cd28f0a21038dbac15756f6
Author: finwo <finwo@pm.me>
Date:   Sat,  3 Jan 2026 19:38:48 +0100

2.71

Diffstat:
MChangeLog | 16+++++++++++++++-
MMakefile | 6+++++-
Mdoc/xr.odt | 0
Mdoc/xr.pdf | 0
Mtest/externalchecker | 8++++++--
Mxr/Checkers/wakeupthread/execute.cc | 7++++++-
Mxr/Dispatchers/dispatcher/checkdos.cc | 18++++++++++--------
Mxr/Dispatchers/httpdispatcher/senderrorpage.cc | 3++-
Mxr/Dispatchers/tcpdispatcher/execute.cc | 11+++--------
Mxr/ThreadsAndMutexes/mutextable/hash.cc | 25++++++++++++++++++++++++-
Mxr/ThreadsAndMutexes/mutextable/mutextable | 2++
Mxr/ThreadsAndMutexes/mutextable/mutextable1.cc | 1+
Mxr/ThreadsAndMutexes/mutextree/copy.cc | 4++++
Mxr/ThreadsAndMutexes/mutextree/destroy.cc | 1+
Mxr/ThreadsAndMutexes/mutextree/lock.cc | 7+++++++
Axr/ThreadsAndMutexes/mutextree/locktree.cc | 11+++++++++++
Mxr/ThreadsAndMutexes/mutextree/mutextree | 8++++++--
Mxr/ThreadsAndMutexes/mutextree/mutextree1.cc | 4++++
Mxr/ThreadsAndMutexes/mutextree/mutextree2.cc | 3+++
Mxr/ThreadsAndMutexes/mutextree/mutextree3.cc | 3+++
Mxr/ThreadsAndMutexes/mutextree/nodelock.cc | 25+++++++++++++++++++++++--
Mxr/ThreadsAndMutexes/mutextree/unlock.cc | 6++++++
Axr/ThreadsAndMutexes/mutextree/unlocktree.cc | 11+++++++++++
Mxr/ThreadsAndMutexes/thread/run.cc | 4++++
Mxr/backend/addbytes.cc | 5+++--
Mxr/backend/endconnection.cc | 6++++--
Mxr/backend/live.cc | 8+++++---
Mxr/backend/markconnecterror.cc | 9++++++---
Mxr/backend/startconnection.cc | 9++++-----
Mxr/backend/up.cc | 8+++++---
Mxr/backenddef/weight.cc | 9++++++---
Mxr/balancer/addbackend2.cc | 9+++++----
Mxr/balancer/deletebackend.cc | 5+++--
Mxr/config/addserverheader.cc | 6++++--
Mxr/config/addxforwardedfor.cc | 6++++--
Mxr/config/addxrversion.cc | 6++++--
Mxr/config/buffersize.cc | 6++++--
Mxr/config/changeserverheader.cc | 6++++--
Mxr/config/config | 3+++
Mxr/config/config1.cc | 1+
Mxr/config/fastclose.cc | 6++++--
Mxr/config/ipstoretimeout.cc | 6++++--
Mxr/config/maxconn.cc | 6++++--
Mxr/config/pidfile.cc | 6++++--
Mxr/config/prefixtimestamp.cc | 6++++--
Mxr/config/removeserverheader.cc | 6++++--
Mxr/config/setwebinterface.cc | 4+++-
Mxr/config/stickyhttp.cc | 6++++--
Mxr/etc/Makefile.class | 2+-
Mxr/etc/status-nosavebutton.xslt | 13++++++++++++-
Mxr/etc/usage.txt | 11++++++-----
Mxr/ipstore/activity.cc | 6++++--
Mxr/ipstore/anticipated.cc | 5+++--
Mxr/ipstore/clear.cc | 7+++++--
Mxr/ipstore/clearoldest.cc | 5+++--
Mxr/ipstore/weed.cc | 5+++--
Mxr/memory/memdisplay.cc | 6++++--
Mxr/memory/memfree.cc | 10++++++----
Mxr/memory/memmalloc.cc | 6++++--
Mxr/memory/memmark.cc | 6++++--
Mxr/memory/memrealloc.cc | 6++++--
Mxr/sys/main.cc | 7++++++-
Mxr/sys/mutexlock.cc | 5++---
Mxr/webinterface/answerstatus.cc | 1+
Mxr/webinterface/execute.cc | 17+++++++++++++++--
Mxrctl/xrctl | 12+++++++++++-
66 files changed, 347 insertions(+), 115 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,17 @@ +2.71 [KK 2010-11-25] +- Recentness of doc/xr.pdf is checked (against doc/xr.odt) during + "make commit" +- Error messages are also prefixed with a timestamp when flagged so + (just as warnings, verbose messages etc.) +- Web interface flag --web-interface may hold a 3rd argument, a name. + This name is rendered in the browser. Xrctl tag "webinterfacename" + introduced for this purpose. +- Fixed 32-bit issue in MutexTable::hash(), the modulo-operation while + hashing worked on 64-bit systems, but not on 32-bit. (Thanks, + several people for reporting this.) +- Fixed mutex issue during pre-operation scanning of back ends. XR + would crash when started with only dead back ends in the pre-scan phase. + 2.70 [KK 2010-10-28] - Bugfix in 3-secs delay during out of file handles conditions (see xr/balancer/serve.cc) @@ -10,7 +24,7 @@ Just once appears to fail on some systems, twice fixes the problem. - Basic authentication for the web interface implemented. This can be given on the commandline using --webinterface-auth, in xrctl.xml - using <webinterfaceauth>, or injected later on the url + using the tag webinterfaceauth, or injected later on the url /server/webinterfaceauth/USER:PASS 2.69 [KK 2010-10-08] diff --git a/Makefile b/Makefile @@ -1,7 +1,7 @@ # Top-level Makefile for XR # ------------------------- -VER ?= 2.70 +VER ?= 2.71 PREFIX ?= $(DESTDIR)/usr BINDIR ?= $(PREFIX)/sbin MANDIR ?= $(PREFIX)/share/man @@ -91,5 +91,9 @@ tar: clean commit: local clean test `svn status | grep '^\?' | wc -l` -eq 0 || \ (echo 'SVN not fully up to date: run "svn status"' && exit 1) + test -f doc/xr.pdf || \ + (echo 'PDF version of the docs not present!' && exit 1) + test doc/xr.pdf -nt doc/xr.odt || \ + (echo 'PDF version of the docs is stale!!' && exit 1) perl -c xrctl/xrctl svn -m $(VER) commit 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/test/externalchecker b/test/externalchecker @@ -2,9 +2,13 @@ # Example of an external checker +# Alternate its-alive / its-dead every approx 10 sec +my $sec = int((localtime())[0] / 10); +my $out = $sec & 1 ? "1" : "0"; + print STDERR (">>>> External checker: ", scalar(localtime()), " @ARGV\n"); -if ($ARGV[0] eq 'localhost:8000') { - print("1\n"); +if ($ARGV[0] =~'localhost') { + print("$out\n"); } else { print("0\n"); } diff --git a/xr/Checkers/wakeupthread/execute.cc b/xr/Checkers/wakeupthread/execute.cc @@ -8,6 +8,9 @@ void Wakeupthread::execute() { for (unsigned i = 0; i < balancer.nbackends(); i++) { if (! balancer.backend(i).live()) { Backend target(balancer.backend(i).backenddef()); + debugmsg("Wakeup thread: checking " << + target.description() << '\n'); + target.live(balancer.backend(i).live()); try { target.check(); if (target.live()) { @@ -23,8 +26,10 @@ void Wakeupthread::execute() { } } sleep (config.wakeupsec()); - } else + } else { + debugmsg("Wakeup thread: no activity right now\n"); sleep(30); + } } } diff --git a/xr/Dispatchers/dispatcher/checkdos.cc b/xr/Dispatchers/dispatcher/checkdos.cc @@ -25,6 +25,8 @@ bool Dispatcher::check_dos() { msg ("Verifying DOS protection\n"); Threadlist::desc("Verifying"); + static int lock; + // Check 'softmaxconnrate' and 'hardmaxconnrate' now! // Descend into this block if connrate_time() is set, AND // either hardmaxconnrate() is set, @@ -38,16 +40,16 @@ bool Dispatcher::check_dos() { unsigned max_conns = max(config.hardmaxconnrate(), config.softmaxconnrate()); - mutex_lock (&accesslog[clientip().s_addr]); + mutex_lock (&lock); accesslog[clientip().s_addr].push(now); - mutex_unlock (&accesslog[clientip().s_addr]); + mutex_unlock (&lock); if (accesslog_lastclean < min_ts) { // Clean the entire access log, it's been a while... - mutex_lock(&accesslog_lastclean); + mutex_lock(&lock); accesslog_lastclean = now; - mutex_unlock(&accesslog_lastclean); + mutex_unlock(&lock); bool done = false; while (!done) { @@ -65,23 +67,23 @@ bool Dispatcher::check_dos() { } else { // Keep popping off this IP's oldest connection // until we have only "recent" connections left. - mutex_lock(&accesslog[i->first]); + mutex_lock(&lock); while ( accesslog[i->first].front() < min_ts || accesslog[i->first].size() > max_conns ) accesslog[i->first].pop(); - mutex_unlock(&accesslog[i->first]); + mutex_unlock(&lock); } } } } else { // The "big log" doesn't need to be fully cleaned, // but this particular IP should be! - mutex_lock(&accesslog[clientip().s_addr]); + mutex_lock(&lock); while ( accesslog[clientip().s_addr].front() < min_ts || accesslog[clientip().s_addr].size() > max_conns ) { accesslog[clientip().s_addr].pop(); } - mutex_unlock(&accesslog[clientip().s_addr]); + mutex_unlock(&lock); } if (config.hardmaxconnrate() && diff --git a/xr/Dispatchers/httpdispatcher/senderrorpage.cc b/xr/Dispatchers/httpdispatcher/senderrorpage.cc @@ -12,7 +12,8 @@ void HttpDispatcher::senderrorpage(string const &reason) { " </head>\n" " <body>\n" " <h1>Internal Server Error</h1>\n" - " You request could not be completed. Please retry later.\n" + " You request could not be completed. Please retry later.<p/>" + " (" + reason + ")\n" " </body>\n" "</html>\n"; ostringstream mess; diff --git a/xr/Dispatchers/tcpdispatcher/execute.cc b/xr/Dispatchers/tcpdispatcher/execute.cc @@ -15,9 +15,7 @@ void TcpDispatcher::execute() { Threadlist::desc("Dispatching"); dispatch(); } catch (Error const &e) { - mutex_lock(&cerr); - cerr << e.what() << "\n"; - mutex_unlock(&cerr); + warnmsg(e.what() << '\n'); socketclose(clientfd()); socketclose(backendfd()); return; @@ -25,8 +23,7 @@ void TcpDispatcher::execute() { // Verify that the target is within the allowed set. if (targetbackend() < 0 || targetbackend() >= (int)balancer.nbackends()) { - cerr << "WARNING: target back end " << targetbackend() - << " out of range\n"; + warnmsg("Target back end " << targetbackend() << "out of range\n"); socketclose(clientfd()); socketclose(backendfd()); return; @@ -55,9 +52,7 @@ void TcpDispatcher::execute() { try { handle(); } catch (Error const &e) { - mutex_lock(&cerr); - cerr << e.what() << "\n"; - mutex_unlock(&cerr); + warnmsg(e.what() << '\n'); failed = true; if (config.onfail().length()) { ostringstream o; diff --git a/xr/ThreadsAndMutexes/mutextable/hash.cc b/xr/ThreadsAndMutexes/mutextable/hash.cc @@ -1,5 +1,28 @@ #include "mutextable" +/* + * How to hash a pointer into an unsigned. Based on the famous hashpjw() + * function. + */ + +// #define DEBUG unsigned MutexTable::hash(void *obj) { - return (unsigned) ( (long)obj % (long)_size ); + unsigned v = 0; + unsigned char *cp = (unsigned char *)obj; + for (size_t i = 0; i < sizeof(obj); i++) { + v <<= 4; + v |= *cp++; + if (unsigned g = v & 0xf0000000) { + v = v ^ ( g >> 24 ); + v = v ^ g; + } + } + v %= _size; + +# ifdef DEBUG + debugmsg("Pointer " << obj << " hashed to bucket " << v << + " (given size " << _size << ")\n"); +# endif + + return v; } diff --git a/xr/ThreadsAndMutexes/mutextable/mutextable b/xr/ThreadsAndMutexes/mutextable/mutextable @@ -1,6 +1,8 @@ #ifndef _MUTEXTABLE_ #define _MUTEXTABLE_ +#include "sys/sys" +#include "config/config" #include "ThreadsAndMutexes/mutextree/mutextree" class MutexTable { diff --git a/xr/ThreadsAndMutexes/mutextable/mutextable1.cc b/xr/ThreadsAndMutexes/mutextable/mutextable1.cc @@ -1,6 +1,7 @@ #include "mutextable" MutexTable::MutexTable(unsigned sz): _size(sz) { + debugmsg("Initializing mutex table with " << sz << " slots"); _table = new MutexTree* [sz]; for (unsigned i = 0; i < sz; i++) _table[i] = new MutexTree; diff --git a/xr/ThreadsAndMutexes/mutextree/copy.cc b/xr/ThreadsAndMutexes/mutextree/copy.cc @@ -1,6 +1,10 @@ #include "mutextree" void MutexTree::copy(MutexTree const &other) { +# ifdef DEBUG + debugmsg("Mutex: WARNING - copy invoked\n"); +# endif + _treelock = other._treelock; _root = new MutexNode(other._root); } diff --git a/xr/ThreadsAndMutexes/mutextree/destroy.cc b/xr/ThreadsAndMutexes/mutextree/destroy.cc @@ -2,4 +2,5 @@ void MutexTree::destroy() { delete _root; + _root = 0; } diff --git a/xr/ThreadsAndMutexes/mutextree/lock.cc b/xr/ThreadsAndMutexes/mutextree/lock.cc @@ -1,7 +1,14 @@ #include "mutextree" void MutexTree::lock(void *o) { +# ifdef DEBUG + debugmsg("Mutex: locking object: " << o << + " (this=" << this << ", root=" << _root << ")\n"); +# endif locktree(); _root = nodelock(o, _root); unlocktree(); +# ifdef DEBUG + debugmsg("Mutex: object " << o << " locked\n"); +# endif } diff --git a/xr/ThreadsAndMutexes/mutextree/locktree.cc b/xr/ThreadsAndMutexes/mutextree/locktree.cc @@ -0,0 +1,11 @@ +#include "mutextree" + +void MutexTree::locktree() { +# ifdef DEBUG + debugmsg("Mutex: locking tree\n"); +# endif + _treelock.lock(); +# ifdef DEBUG + debugmsg("Mutex: tree locked\n"); +# endif +} diff --git a/xr/ThreadsAndMutexes/mutextree/mutextree b/xr/ThreadsAndMutexes/mutextree/mutextree @@ -2,6 +2,10 @@ #define _MUTEXTREE_ #include "ThreadsAndMutexes/mutexnode/mutexnode" +#include "config/config" + +// This adds verbosity to the below class functions +// #define DEBUG class MutexTree { public: @@ -18,8 +22,8 @@ public: int balance() const; private: - void locktree() { _treelock.lock(); }; - void unlocktree() { _treelock.unlock(); } + void locktree(); + void unlocktree(); MutexNode *nodelock(void *o, MutexNode *start); void nodeunlock(void *o, MutexNode *start); diff --git a/xr/ThreadsAndMutexes/mutextree/mutextree1.cc b/xr/ThreadsAndMutexes/mutextree/mutextree1.cc @@ -1,4 +1,8 @@ #include "mutextree" MutexTree::MutexTree(): _root(0), _treelock() { +# ifdef DEBUG + debugmsg("Mutex: constructed (this=" << this << ", root=" << _root + << ")\n"); +# endif } diff --git a/xr/ThreadsAndMutexes/mutextree/mutextree2.cc b/xr/ThreadsAndMutexes/mutextree/mutextree2.cc @@ -1,5 +1,8 @@ #include "mutextree" MutexTree::MutexTree(MutexTree const &other) { +# ifdef DEBUG + debugmsg("Mutex: copy constructor (this=" << this << ")\n"); +# endif copy(other); } diff --git a/xr/ThreadsAndMutexes/mutextree/mutextree3.cc b/xr/ThreadsAndMutexes/mutextree/mutextree3.cc @@ -1,5 +1,8 @@ #include "mutextree" MutexTree::~MutexTree() { +# ifdef DEBUG + debugmsg("Mutex: destroying " << this << "\n"); +# endif destroy(); } diff --git a/xr/ThreadsAndMutexes/mutextree/nodelock.cc b/xr/ThreadsAndMutexes/mutextree/nodelock.cc @@ -1,24 +1,45 @@ #include "mutextree" +#include "config/config" MutexNode *MutexTree::nodelock(void *o, MutexNode *start) { // No tree start yet? Create one. if (!start) { +# ifdef DEBUG + debugmsg("Mutex nodelock: new node for " << o <<", locking now\n"); +# endif start = new MutexNode(o); start->lock(); +# ifdef DEBUG + debugmsg("Mutex nodelock: new node for " << o <<" locked\n"); +# endif return start; } // At object? Dive into the Mutexnode. if (start->obj() == o) { +# ifdef DEBUG + debugmsg("Mutex nodelock: existing node for " << o << + ", locking now\n"); +# endif start->lock(); +# ifdef DEBUG + debugmsg("Mutex nodelock: existing node for " << o << " locked\n"); +# endif return start; } // Decide whether to recurse left or right. - if (start->obj() < o) + if (start->obj() < o) { +# ifdef DEBUG + debugmsg("Mutex nodelock: going left for " << o << '\n'); +# endif start->left(nodelock(o, start->left())); - else + } else { +# ifdef DEBUG + debugmsg("Mutex nodelock: going right for " << o << '\n'); +# endif start->right(nodelock(o, start->right())); + } return start; } diff --git a/xr/ThreadsAndMutexes/mutextree/unlock.cc b/xr/ThreadsAndMutexes/mutextree/unlock.cc @@ -1,5 +1,11 @@ #include "mutextree" void MutexTree::unlock(void *o) { +# ifdef DEBUG + debugmsg("Mutex: unlocking object: " << o << '\n'); +# endif nodeunlock(o, _root); +# ifdef DEBUG + debugmsg("Mutex: object " << o << " unlocked\n"); +# endif } diff --git a/xr/ThreadsAndMutexes/mutextree/unlocktree.cc b/xr/ThreadsAndMutexes/mutextree/unlocktree.cc @@ -0,0 +1,11 @@ +#include "mutextree" + +void MutexTree::unlocktree() { +# ifdef DEBUG + debugmsg("Mutex: unlocking tree\n"); +# endif + _treelock.unlock(); +# ifdef DEBUG + debugmsg("Mutex: tree unlocked\n"); +# endif +} diff --git a/xr/ThreadsAndMutexes/thread/run.cc b/xr/ThreadsAndMutexes/thread/run.cc @@ -10,6 +10,10 @@ void *Thread::_run (void *data) { t->execute(); } catch (Error const &e) { mutex_lock(&cerr); + if (config.prefixtimestamp()) { + Timestamp tm; + cerr << tm.desc() << ' '; + } cerr << e.what() << "\n"; mutex_unlock(&cerr); } diff --git a/xr/backend/addbytes.cc b/xr/backend/addbytes.cc @@ -1,7 +1,8 @@ #include "backend" void Backend::addbytes (unsigned n) { - mutex_lock(&bytes_served); + static int lock; + mutex_lock(&lock); bytes_served += n; - mutex_unlock (&bytes_served); + mutex_unlock (&lock); } diff --git a/xr/backend/endconnection.cc b/xr/backend/endconnection.cc @@ -1,7 +1,9 @@ #include "backend" void Backend::endconnection() { - mutex_lock (&nconn); + static int lock; + + mutex_lock(&lock); nconn--; - mutex_unlock (&nconn); + mutex_unlock (&lock); } diff --git a/xr/backend/live.cc b/xr/backend/live.cc @@ -2,8 +2,10 @@ void Backend::live (bool state) { PROFILE("Backend::live"); - - mutex_lock(&islive); + + static int lock; + + mutex_lock(&lock); islive = state; - mutex_unlock(&islive); + mutex_unlock(&lock); } diff --git a/xr/backend/markconnecterror.cc b/xr/backend/markconnecterror.cc @@ -1,8 +1,11 @@ #include "backend" void Backend::markconnecterror() { - mutex_lock(&nconnerr); + debugmsg("Logging connection error on back end " << description() << '\n'); + + static int lock; + + mutex_lock(&lock); nconnerr++; - mutex_unlock(&nconnerr); + mutex_unlock(&lock); } - diff --git a/xr/backend/startconnection.cc b/xr/backend/startconnection.cc @@ -1,11 +1,10 @@ #include "backend" void Backend::startconnection() { - mutex_lock (&nconn); + static int lock; + + mutex_lock (&lock); nconn++; - mutex_unlock (&nconn); - - mutex_lock (&totconn); totconn++; - mutex_unlock (&totconn); + mutex_unlock (&lock); } diff --git a/xr/backend/up.cc b/xr/backend/up.cc @@ -2,12 +2,14 @@ void Backend::up (bool state) { PROFILE("Backend::up"); + + static int lock; - mutex_lock (&isup); + mutex_lock (&lock); bool oldstate = isup; isup = state; - mutex_unlock (&isup); + mutex_unlock (&lock); if (oldstate != state) - msg ("Marking back end " + description() + " as " + upstr() + "\n"); + msg("Marking back end " << description() << " as " << upstr() << "\n"); } diff --git a/xr/backenddef/weight.cc b/xr/backenddef/weight.cc @@ -1,9 +1,11 @@ #include "backenddef" void BackendDef::weight(unsigned w) { - wt = w; + static int lock; - mutex_lock(&minmax_wt_set); + mutex_lock(&lock); + + wt = w; if (!minmax_wt_set) { min_wt = w; max_wt = w; @@ -14,5 +16,6 @@ void BackendDef::weight(unsigned w) { if (max_wt > w) max_wt = w; } - mutex_unlock(&minmax_wt_set); + + mutex_unlock(&lock); } diff --git a/xr/balancer/addbackend2.cc b/xr/balancer/addbackend2.cc @@ -3,16 +3,17 @@ void Balancer::addbackend (Backend const &b, bool is_up, bool is_live, bool do_check) { debugmsg("Adding back end " << b.description() << " to list\n"); - - mutex_lock(&backends); + + int lock; + mutex_lock(&lock); backends.push_back (b); backends[backends.size() - 1].up(is_up); backends[backends.size() - 1].live(is_live); backends[backends.size() - 1].balancerindex(backends.size() - 1); - mutex_unlock(&backends); + mutex_unlock(&lock); if (do_check) { - debugmsg("Verifying configured back end\n"); + debugmsg("Verifying added back end " << b.description() << '\n'); backends[backends.size() - 1].check(); } diff --git a/xr/balancer/deletebackend.cc b/xr/balancer/deletebackend.cc @@ -10,8 +10,9 @@ void Balancer::deletebackend(unsigned i) { throw Error(o.str()); } - mutex_lock(&backends); + int lock; + mutex_lock(&lock); backends.erase(backends.begin() + i, backends.begin() + i + 1); - mutex_unlock(&backends); + mutex_unlock(&lock); } diff --git a/xr/config/addserverheader.cc b/xr/config/addserverheader.cc @@ -1,7 +1,9 @@ #include "config" void Config::addserverheader (string const &s) { - mutex_lock (&serverheaders); + int lock; + + mutex_lock (&lock); serverheaders.push_back (s); - mutex_unlock (&serverheaders); + mutex_unlock (&lock); } diff --git a/xr/config/addxforwardedfor.cc b/xr/config/addxforwardedfor.cc @@ -1,7 +1,9 @@ #include "config" void Config::addxforwardedfor(bool b) { - mutex_lock (&add_x_forwarded_for); + int lock; + + mutex_lock (&lock); add_x_forwarded_for = b; - mutex_unlock (&add_x_forwarded_for); + mutex_unlock (&lock); } diff --git a/xr/config/addxrversion.cc b/xr/config/addxrversion.cc @@ -1,7 +1,9 @@ #include "config" void Config::addxrversion(bool b) { - mutex_lock (&add_xr_version); + int lock; + + mutex_lock (&lock); add_xr_version = b; - mutex_unlock (&add_xr_version); + mutex_unlock (&lock); } diff --git a/xr/config/buffersize.cc b/xr/config/buffersize.cc @@ -1,7 +1,9 @@ #include "config" void Config::buffersize(unsigned b) { - mutex_lock (&bufsize); + int lock; + + mutex_lock (&lock); bufsize = b; - mutex_unlock (&bufsize); + mutex_unlock (&lock); } diff --git a/xr/config/changeserverheader.cc b/xr/config/changeserverheader.cc @@ -1,7 +1,9 @@ #include "config" void Config::changeserverheader (unsigned i, string const &s) { - mutex_lock (&serverheaders); + int lock; + + mutex_lock (&lock); serverheaders[i] = s; - mutex_unlock (&serverheaders); + mutex_unlock (&lock); } diff --git a/xr/config/config b/xr/config/config @@ -114,6 +114,8 @@ public: void webinterface_auth(string const &s); string webinterface_auth() const { return web_auth; } + string webinterfacename() const { return webinterface_name; } + unsigned nserverheaders() const { return (serverheaders.size()); } string const &serverheader (unsigned n) { return (serverheaders[n]); @@ -232,6 +234,7 @@ private: static bool use_webinterface; static string webinterface_ip; static int webinterface_port; + static string webinterface_name; static string web_auth; static string dump_dir; static unsigned soft_maxconnrate; diff --git a/xr/config/config1.cc b/xr/config/config1.cc @@ -31,6 +31,7 @@ int Config::ipstore_timeout; bool Config::use_webinterface = false; string Config::webinterface_ip; int Config::webinterface_port; +string Config::webinterface_name; string Config::web_auth; string Config::dump_dir; unsigned Config::soft_maxconnrate = 0; diff --git a/xr/config/fastclose.cc b/xr/config/fastclose.cc @@ -1,7 +1,9 @@ #include "config" void Config::fastclose(bool b) { - mutex_lock (&fast_close); + int lock; + + mutex_lock (&lock); fast_close = b; - mutex_unlock (&fast_close); + mutex_unlock (&lock); } diff --git a/xr/config/ipstoretimeout.cc b/xr/config/ipstoretimeout.cc @@ -1,7 +1,9 @@ #include "config" void Config::ipstoretimeout (int t) { - mutex_lock (&ipstore_timeout); + int lock; + + mutex_lock (&lock); ipstore_timeout = t; - mutex_unlock (&ipstore_timeout); + mutex_unlock (&lock); } diff --git a/xr/config/maxconn.cc b/xr/config/maxconn.cc @@ -1,7 +1,9 @@ #include "config" void Config::maxconn (unsigned m) { - mutex_lock (&max_conn); + int lock; + + mutex_lock (&lock); max_conn = m; - mutex_unlock (&max_conn); + mutex_unlock (&lock); } diff --git a/xr/config/pidfile.cc b/xr/config/pidfile.cc @@ -1,7 +1,9 @@ #include "config" void Config::pidfile (string const &p) { - mutex_lock (&pid_file); + int lock; + + mutex_lock (&lock); pid_file = p; - mutex_unlock (&pid_file); + mutex_unlock (&lock); } diff --git a/xr/config/prefixtimestamp.cc b/xr/config/prefixtimestamp.cc @@ -1,7 +1,9 @@ #include "config" void Config::prefixtimestamp(bool b) { - mutex_lock (&prefix_timestamp); + int lock; + + mutex_lock (&lock); prefix_timestamp = b; - mutex_unlock (&prefix_timestamp); + mutex_unlock (&lock); } diff --git a/xr/config/removeserverheader.cc b/xr/config/removeserverheader.cc @@ -1,8 +1,10 @@ #include "config" void Config::removeserverheader (unsigned i) { - mutex_lock (&serverheaders); + int lock; + + mutex_lock (&lock); serverheaders.erase (serverheaders.begin() + i, serverheaders.begin() + i + 1); - mutex_unlock (&serverheaders); + mutex_unlock (&lock); } diff --git a/xr/config/setwebinterface.cc b/xr/config/setwebinterface.cc @@ -2,11 +2,13 @@ void Config::setwebinterface (string str) { vector<string> parts = str2parts (str, ':'); - if (parts.size() != 2) + if (parts.size() < 2 || parts.size() > 3) throw Error("Bad webinterface specifier in '-W" + str + "', expected: IP:PORT"); use_webinterface = true; webinterface_ip = parts[0]; webinterface_port = setinteger(parts[1]); + if (parts.size() == 3) + webinterface_name = parts[2]; } diff --git a/xr/config/stickyhttp.cc b/xr/config/stickyhttp.cc @@ -1,7 +1,9 @@ #include "config" void Config::stickyhttp (bool b) { - mutex_lock (&sticky_http); + int lock; + + mutex_lock (&lock); sticky_http = b; - mutex_unlock (&sticky_http); + mutex_unlock (&lock); } diff --git a/xr/etc/Makefile.class b/xr/etc/Makefile.class @@ -25,7 +25,7 @@ class-compile: $(OBJ) $(BASE)/xr/$(BUILDDIR)/$(DIR)_%.o: %.cc @echo "Compiling: " `pwd`$< - $(CONF_CC) $(PROF) $(PROFILER) $(CONF_OPTFLAGS) \ + @$(CONF_CC) $(PROF) $(PROFILER) $(CONF_OPTFLAGS) \ -DVER='"$(VER)"' -DAUTHOR='"$(AUTHOR)"' -DHST='"$(HST)"' \ -DMAINTAINER='"$(MAINTAINER)"' -DDISTSITE='"$(DISTSITE)"' \ -DSYS='"$(SYS)"' -D$(SYS) $(MEMDEBUG) $(CCC) \ diff --git a/xr/etc/status-nosavebutton.xslt b/xr/etc/status-nosavebutton.xslt @@ -54,13 +54,24 @@ </script> </head> <body> - <h1>XR Status Overview</h1> + <h1> + XR Status Overview + <xsl:apply-templates select="/status/server/webinterfacename"/> + </h1> <hr/> <xsl:apply-templates/> </body> </html> </xsl:template> +<xsl:template match="/status/server/webinterfacename"> + <xsl:if test="/status/server/webinterfacename != ''"> + <font color="red"> + service: <xsl:value-of select="/status/server/webinterfacename"/> + </font> + </xsl:if> +</xsl:template> + <xsl:template match="/status"> <table> <tr> diff --git a/xr/etc/usage.txt b/xr/etc/usage.txt @@ -165,11 +165,7 @@ may not exist on your platform): --url-match URL, -j URL Subsequently stated backends only apply when clients request a matching URL. Only available when the server is in http mode. - --web-interface IP:PORT, -W IP:PORT - Starts a web interface on specified IP address and port. - --web-interface-auth USER:PASS, -Y USER:PASS - Access to the web interface will be protected by basic authentication. - --verbose, -v + --verbose, -v Increases verbosity, default is silent operation. --version, -V Shows the version info, and author/maintainer contacts (for reporting @@ -177,6 +173,11 @@ may not exist on your platform): --wakeup-interval SEC, -w SEC Defines wakeup period (rechecking) in seconds, of unavailable back ends. Default is 5. Use -w0 to suppress. + --web-interface IP:PORT[:NAME], -W IP:PORT[:NAME] + Starts a web interface on specified IP address and port. The + optional NAME is displayed. + --web-interface-auth USER:PASS, -Y USER:PASS + Access to the web interface will be protected by basic authentication. XR's errors and warnings are sent to stderr, debugging and verbose messages go to stdout. Invoke XR daemons using something like diff --git a/xr/ipstore/activity.cc b/xr/ipstore/activity.cc @@ -6,10 +6,12 @@ void IPStore::activity(struct in_addr clientip, unsigned curbackend) { msg("Logging activity for back end " << curbackend << " from " << inet2string(clientip) << '\n'); + + int lock; - mutex_lock(&store); + mutex_lock(&lock); store[clientip].targetbackend = (int)curbackend; store[clientip].lastaccess = time(0); - mutex_unlock(&store); + mutex_unlock(&lock); } diff --git a/xr/ipstore/anticipated.cc b/xr/ipstore/anticipated.cc @@ -9,14 +9,15 @@ unsigned IPStore::anticipated(unsigned b) { // Get number of anticipated clients for given back end unsigned ret = 0; + static int lock; - mutex_lock(&store); + mutex_lock(&lock); for (StoreMap::iterator iter = store.begin(); iter != store.end(); iter++) if ((*iter).second.targetbackend == (int)b) ret++; - mutex_unlock(&store); + mutex_unlock(&lock); debugmsg("Anticipated connections for back end " << b << ": " << ret << '\n'); diff --git a/xr/ipstore/clear.cc b/xr/ipstore/clear.cc @@ -2,7 +2,10 @@ void IPStore::clear(struct in_addr clientip) { debugmsg("Erasing IP entry of " << inet2string(clientip) << '\n'); - mutex_lock(&store); + + static int lock; + + mutex_lock(&lock); store.erase(clientip); - mutex_unlock(&store); + mutex_unlock(&lock); } diff --git a/xr/ipstore/clearoldest.cc b/xr/ipstore/clearoldest.cc @@ -4,8 +4,9 @@ void IPStore::clearoldest() { time_t oldest_time = time(0) + 100; StoreMap::iterator oldest_entry; bool found = false; + static int lock; - mutex_lock(&store); + mutex_lock(&lock); dump(); @@ -31,6 +32,6 @@ void IPStore::clearoldest() { store.erase(oldest_entry); } - mutex_unlock(&store); + mutex_unlock(&lock); dump(); } diff --git a/xr/ipstore/weed.cc b/xr/ipstore/weed.cc @@ -3,8 +3,9 @@ void IPStore::weed() { time_t now = time(0); bool done = false; + static int lock; - mutex_lock(&store); + mutex_lock(&lock); while (!done) { done = true; @@ -24,5 +25,5 @@ void IPStore::weed() { } } - mutex_unlock(&store); + mutex_unlock(&lock); } diff --git a/xr/memory/memdisplay.cc b/xr/memory/memdisplay.cc @@ -1,7 +1,9 @@ #include "memory" void Memory::mem_display() { - mutex_lock(&s_memlog); + static int lock; + + mutex_lock(&lock); for (unsigned i = 0; i < s_memlog.size(); i++) { MemoryEntry ent = s_memlog[i]; mutex_lock(&cout); @@ -9,5 +11,5 @@ void Memory::mem_display() { << ' ' << ent.desc << '\n'; mutex_unlock(&cout); } - mutex_unlock(&s_memlog); + mutex_unlock(&lock); } diff --git a/xr/memory/memfree.cc b/xr/memory/memfree.cc @@ -3,11 +3,13 @@ void Memory::free(void *ptr) { if (!ptr) return; + + static int lock; for (unsigned i = 0; i < s_memlog.size(); i++) { - mutex_lock(&s_memlog); + mutex_lock(&lock); MemoryEntry ent = s_memlog[i]; - mutex_unlock(&s_memlog); + mutex_unlock(&lock); if (ent.ptr == ptr) { if (s_follow) { mutex_lock(&cout); @@ -15,9 +17,9 @@ void Memory::free(void *ptr) { mutex_unlock(&cout); } ::free (ent.ptr); - mutex_lock(&s_memlog); + mutex_lock(&lock); s_memlog.erase(s_memlog.begin() + i); - mutex_unlock(&s_memlog); + mutex_unlock(&lock); return; } } diff --git a/xr/memory/memmalloc.cc b/xr/memory/memmalloc.cc @@ -1,11 +1,13 @@ #include "memory" void *Memory::malloc(size_t sz, string const &desc) { + static int lock; void *ptr = ::malloc(sz); MemoryEntry ent = { ptr, sz, desc }; - mutex_lock(&s_memlog); + + mutex_lock(&lock); s_memlog.push_back(ent); - mutex_unlock(&s_memlog); + mutex_unlock(&lock); if (s_follow) { mutex_lock(&cout); cout << "Memory::malloc(" << sz << ") -> " << ptr << ' ' diff --git a/xr/memory/memmark.cc b/xr/memory/memmark.cc @@ -2,7 +2,9 @@ void Memory::mem_mark(string const &desc) { MemoryEntry ent = { 0, 0, "MARK " + desc }; - mutex_lock(&s_memlog); + static int lock; + + mutex_lock(&lock); s_memlog.push_back(ent); - mutex_unlock(&s_memlog); + mutex_unlock(&lock); } diff --git a/xr/memory/memrealloc.cc b/xr/memory/memrealloc.cc @@ -1,6 +1,8 @@ #include "memory" void *Memory::realloc(void *ptr, size_t newsz, string const &desc) { + static int lock; + if (!newsz) { free(ptr); return 0; @@ -11,9 +13,9 @@ void *Memory::realloc(void *ptr, size_t newsz, string const &desc) { ent.ptr = ::realloc(ptr, newsz); ent.sz = newsz; ent.desc = desc; - mutex_lock(&s_memlog); + mutex_lock(&lock); s_memlog[i] = ent; - mutex_unlock(&s_memlog); + mutex_unlock(&lock); if (s_follow) { mutex_lock(&cout); cout << "Memory::realloc(" << ptr << ", " << newsz diff --git a/xr/sys/main.cc b/xr/sys/main.cc @@ -4,11 +4,16 @@ #include "balancer/balancer" #include "error/error" #include "profiler/profiler" +#include "ThreadsAndMutexes/mutex/mutex" +#include "ThreadsAndMutexes/mutextable/mutextable" using namespace std; +// Global variables (definition) Config config; Balancer balancer; +MutexTable mt(100); +Mutex cout_lock, cerr_lock; static void showlimits() { typedef struct { @@ -29,7 +34,7 @@ static void showlimits() { # endif # ifdef RLIMIT_RSS { RLIMIT_RSS, "max resident set size (bytes)" }, -# endif +# endif { RLIMIT_STACK, "max stack size (bytes)" } }; diff --git a/xr/sys/mutexlock.cc b/xr/sys/mutexlock.cc @@ -2,7 +2,8 @@ #include "ThreadsAndMutexes/mutextable/mutextable" #include "ThreadsAndMutexes/mutex/mutex" -static MutexTable mt(100); +extern MutexTable mt; +extern Mutex cout_lock, cerr_lock; void mutex_lock(void *o) { mt.lock(o); @@ -12,8 +13,6 @@ void mutex_unlock(void *o) { mt.unlock(o); } -static Mutex cout_lock, cerr_lock; - bool mutex_lock_cout() { return cout_lock.trylock(); } diff --git a/xr/webinterface/answerstatus.cc b/xr/webinterface/answerstatus.cc @@ -27,6 +27,7 @@ void Webinterface::answer_status() { " <removereservations>" << config.removereservations() << "</removereservations>\n" " <webinterface>" << config.webinterfaceip() << ':' << config.webinterfaceport() << "</webinterface>\n" " <webinterfaceauth>" << config.webinterface_auth() << "</webinterfaceauth>\n" + " <webinterfacename>" << config.webinterfacename() << "</webinterfacename>\n" " <dnscachetimeout>" << config.dnscachetimeout() << "</dnscachetimeout>\n" " <buffersize>" << config.buffersize() << "</buffersize>\n" " <closesocketsfast>" << config.fastclose() << "</closesocketsfast>\n" diff --git a/xr/webinterface/execute.cc b/xr/webinterface/execute.cc @@ -16,8 +16,14 @@ void Webinterface::execute() { config.webinterfaceport(), "web interface", Servertype::t_tcp); } catch (Error const &e) { + mutex_lock(&cerr); + if (config.prefixtimestamp()) { + Timestamp tm; + cerr << tm.desc() << ' '; + } cerr << e.what() << " (webinterface, retrying in a sec)\n"; - sleep (1); + mutex_unlock(&cerr); + sleep(1); continue; } break; @@ -42,7 +48,14 @@ void Webinterface::execute() { } } } catch (Error const &e) { - cerr << e.what() << " (webinterface)\n"; + mutex_lock(&cerr); + if (config.prefixtimestamp()) { + Timestamp tm; + cerr << tm.desc() << ' '; + } + cerr << e.what() << " (webinterface)\n"; + mutex_unlock(&cerr); + if (cfd >= 0) { ostringstream m; m << "<h1>Web interface error</h1>\n" diff --git a/xrctl/xrctl b/xrctl/xrctl @@ -510,9 +510,17 @@ sub xr_cmdarr { debug => '--debug', removereservations => '--remove-reservations'); + # Web interface def comes from two tags + my $w = $ss->data('webinterface'); + if ($w) { + if (my $name = $ss->data('webinterfacename')) { + $w .= ":$name"; + push(@cmd, '--web-interface', $w); + } + } + # Handle general flags and boolflags push (@cmd, - flag($ss, '--web-interface', 'webinterface', ''), flag($ss, '--web-interface-auth', 'webinterfaceauth', ''), flag($ss, '--dispatch-mode', 'dispatchmode', $default_dispatchmode), @@ -732,6 +740,8 @@ sub generateconfig { my $sp = xml_serviceparser($s) or die ("No service '$s' known.\n"); my $webint = $sp->data('webinterface'); + + # Web interface at IP "0" means localhost $webint =~ s/^0:/localhost:/; if ($webint eq '') {