commit 99330d7c3c9d829d772df08b3923b23f223d8a24 parent 70ba40d536cb7cd72c03893e8837a9d2b9810c0a Author: finwo <finwo@pm.me> Date: Sat, 3 Jan 2026 19:36:15 +0100 2.22 Diffstat:
50 files changed, 281 insertions(+), 387 deletions(-)
diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,10 @@ +2.22 [KK 2008-10-16] +- Implemented up/down state in back ends. Fixed up the docs. +- Rewrote msg() and debugmsg() handling: these are now macros that + call _msg() and _debugmsg() depending on verbose/debug flags. The + argument is a Mstr object, used to concatenate strings with ints, + doubles and so on. + 2.21 [KK 2008-10-14] - Fixed round-robin dispatching with only 1 configured back end. The bug was that on the next-time around, no "other" back end would be diff --git a/Makefile b/Makefile @@ -1,7 +1,7 @@ # Top-level Makefile for XR # ------------------------- -VER = 2.21 +VER = 2.22 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/DispatchAlgorithms/external/target.cc b/xr/DispatchAlgorithms/external/target.cc @@ -21,13 +21,11 @@ unsigned External::target(struct in_addr clientip, throw static_cast<Error>("External algorithm '") + o.str() + "' did not reply with a number"; - ostringstream n; - n << i; - msg ("External algorithm says: " + n.str() + "\n"); + msg ((Mstr("External algorithm says:) ") + i) + "\n"); if (i >= balancer.nbackends()) throw static_cast<Error>("External algorithm '") + o.str() + - "': answer " + n.str() + " out of bounds"; + "': answer " + i + " out of bounds"; if (pclose (f)) throw static_cast<Error>("External algorithm '") + o.str() + "' terminated with error"; diff --git a/xr/DispatchAlgorithms/hashedip/target.cc b/xr/DispatchAlgorithms/hashedip/target.cc @@ -12,14 +12,10 @@ unsigned HashedIp::target(struct in_addr clientip, } unsigned index = targetlist[h]; - if (config.verbose()) { - ostringstream o; - o << index; - msg ("Client IP " + (string)inet_ntoa(clientip) + " hashes to " + - o.str() + ", back end " + - balancer.backend(index).description() + - "\n"); - } + msg ((Mstr("Client IP ") + static_cast<string>(inet_ntoa(clientip))) + + (Mstr(" hashes to ") + index) + + ", back end " + balancer.backend(index).description() + + "\n"); // In strict mode, back end must be available, or don't proceed // In lax mode, fall back to least-connections dispatching diff --git a/xr/DispatchAlgorithms/leastconn/target.cc b/xr/DispatchAlgorithms/leastconn/target.cc @@ -14,17 +14,13 @@ unsigned Leastconn::target(struct in_addr clientip, unsigned weighted_conn = balancer.backend(targetlist[i]).connections() * balancer.backend(targetlist[i]).adjustedweight(); - if (config.verbose()) { - ostringstream o; - o << "connections " - << balancer.backend(targetlist[i]).connections() - << ", adjusted weight " - << balancer.backend(targetlist[i]).adjustedweight() - << ", weighted connections " - << weighted_conn; - msg ("Back end " + balancer.backend(targetlist[i]).description() + - ": " + o.str() + "\n"); - } + msg ("Back end " + balancer.backend(targetlist[i]).description() + + (Mstr(": connections ") + + balancer.backend(targetlist[i]).connections()) + + (Mstr(", adjusted weight ") + + balancer.backend(targetlist[i]).adjustedweight()) + + (Mstr(", weighted connections ") + weighted_conn) + + "\n"); if (!found || weighted_conn < nconn) { t = targetlist[i]; diff --git a/xr/DispatchAlgorithms/storedip/target.cc b/xr/DispatchAlgorithms/storedip/target.cc @@ -26,13 +26,15 @@ unsigned StoredIp::target(struct in_addr clientip, store.find(clientip); if (store.count(clientip) > 0) { time_t diff = now - store[clientip].lastaccess; - ostringstream o; - o << diff; - msg ("Client IP " + string(inet_ntoa(clientip)) + - " last visited on " + timestamp(store[clientip].lastaccess) + - ", " + o.str() + " sec ago, and went to " + + + msg ("Client IP " + static_cast<string>(inet_ntoa(clientip)) + + (Mstr(" last visited on ") + + timestamp(store[clientip].lastaccess)) + + (Mstr(", ") + diff) + + " sec ago, and went to " + balancer.backend(store[clientip].targetbackend).description() + "\n"); + if (diff <= config.ipstoretimeout()) { // Recent 'nuff target = store[clientip].targetbackend; @@ -59,7 +61,8 @@ unsigned StoredIp::target(struct in_addr clientip, } } else { // Historical target unknown, fetch new one - msg ("New visit from " + (string)inet_ntoa(clientip) + "\n"); + msg ("New visit from " + static_cast<string>(inet_ntoa(clientip)) + + "\n"); Leastconn l; target = l.target(clientip, targetlist); } @@ -72,10 +75,9 @@ unsigned StoredIp::target(struct in_addr clientip, map<struct in_addr, ClientData, ClientDataCmp>::iterator iter = store.begin(); while (iter != store.end()) { - if (config.debug()) - debugmsg ("Stored-IP: " + - (string)inet_ntoa((*iter).first) + " visited on " + - timestamp((*iter).second.lastaccess) + "\n"); + debugmsg ("Stored-IP: " + + (string)inet_ntoa((*iter).first) + " visited on " + + timestamp((*iter).second.lastaccess) + "\n"); if (now - ((*iter).second.lastaccess) > config.ipstoretimeout()) store.erase(iter); else diff --git a/xr/DispatchAlgorithms/weightedload/target.cc b/xr/DispatchAlgorithms/weightedload/target.cc @@ -12,16 +12,12 @@ unsigned Weightedload::target(struct in_addr clientip, } // Now pick a random number from 0 to total_load - double pick_load = total_load * mt_rand() * (1.0 / 4294967295.0); // 4294967295 = 2^32 - 1 + // 4294967295 = 2^32 - 1 + double pick_load = total_load * mt_rand() * (1.0 / 4294967295.0); - if (config.verbose()) { - ostringstream o1, o2; - o1 << total_load; - o2 << pick_load; - msg ("Weighted by Load Average; load-range is " + o1.str() + ", and the " + - " selected load-range is " + o2.str() + - "\n"); - } + msg ((Mstr("Weighted by Load Average; load-range is ") + total_load) + + (Mstr(", and the selected load-range is ") + pick_load) + + "\n"); // Now see which server that means! total_load = 0; diff --git a/xr/backend/available.cc b/xr/backend/available.cc @@ -3,15 +3,14 @@ bool Backend::available() const { PROFILE("Backend::available"); - - if (config.debug()) { - ostringstream o; - o << (islive ? "alive" : "dead") << ", " - << connections() << " connections of " - << maxconn() << " max"; - debugmsg ("Backend " + description() + ": " + o.str() + "\n"); - } + + debugmsg((Mstr("Back end ") + description()) + + (Mstr(": ") + livestr()) + + (Mstr(", ") + upstr()) + + (Mstr(", ") + connections()) + + (Mstr(" connections of ") + maxconn()) + + " max\n"); if (!maxconn()) - return (islive); - return (islive && connections() < maxconn()); + return (islive && isup); + return (islive && isup && connections() < maxconn()); } diff --git a/xr/backend/backend b/xr/backend/backend @@ -20,10 +20,13 @@ public: string description() const; bool available() const; string availablestr() const; - string livestr() const; void live (bool state); + string livestr() const; + void up (bool state); + string upstr() const; bool live() const { return (islive); }; + bool up() const { return (isup); } int sock() const { return (clsocket); } string const &server() const { return (bdef.server()); } int port() const { return (bdef.port()); } @@ -52,6 +55,7 @@ public: private: BackendDef bdef; bool islive; + bool isup; int clsocket; unsigned nconn, totconn; double bytes_served; diff --git a/xr/backend/backend1.cc b/xr/backend/backend1.cc @@ -1,6 +1,7 @@ #include "backend" Backend::Backend () : - islive(true), clsocket(-1), nconn(0), totconn(0), bytes_served(0), + islive(true), isup(true), clsocket(-1), + nconn(0), totconn(0), bytes_served(0), loadaverage(0.1) { } diff --git a/xr/backend/connect.cc b/xr/backend/connect.cc @@ -60,15 +60,9 @@ bool Backend::connect() { islive = true; } - if (config.debug()) { - ostringstream o; - o << "Back end " << description() << " is "; - if (islive) - o << "alive on socket " << clsocket; - else - o << "NOT ALIVE"; - debugmsg (o.str() + "\n"); - } + debugmsg ((Mstr("Back end ") + description()) + + (Mstr(" is ") + livestr()) + + (Mstr(" (socket ") + clsocket) + ")\n"); return (islive); } diff --git a/xr/backend/up.cc b/xr/backend/up.cc @@ -0,0 +1,13 @@ +#include "backend" + +void Backend::up (bool state) { + PROFILE("Backend::up"); + + Mutex::lock (&isup); + bool oldstate = isup; + isup = state; + Mutex::unlock (&isup); + + if (oldstate != state) + msg ("Marking back end " + description() + " as " + upstr() + "\n"); +} diff --git a/xr/backend/upstr.cc b/xr/backend/upstr.cc @@ -0,0 +1,5 @@ +#include "backend" + +string Backend::upstr() const { + return (up() ? "up" : "down"); +} diff --git a/xr/balancer/serve.cc b/xr/balancer/serve.cc @@ -28,9 +28,7 @@ void Balancer::serve() { } // Wait for activity, serve it. - ostringstream o; - o << server_fd; - msg ("Awaiting activity on fd " + o.str() +"\n"); + msg ((Mstr("Awaiting activity on fd ") + server_fd) + "\n"); while (true) { Fdset fdset(0); fdset.add (server_fd); @@ -45,22 +43,17 @@ void Balancer::serve() { msg ("Report requested\n"); reportmsg ("*** XR STATUS REPORT STARTS ***\n"); for (unsigned i = 0; i < nbackends(); i++) { - ostringstream o; - o << "Back end " << backend(i).description() << "\n"; - reportmsg(o.str()); - o.str(""); - o << " Status: " << backend(i).availablestr() - << ", " << backend(i).livestr() << "\n"; - reportmsg(o.str()); - o.str(""); - o << " Connections: " << backend(i).connections() - << " (max " << backend(i).maxconn() << ")\n"; - reportmsg(o.str()); - o.str(""); - o << " Served: " << backend(i).bytesserved() - << " bytes, " << backend(i).clientsserved() - << " clients\n"; - reportmsg(o.str()); + reportmsg("Back end " + backend(i).description() + "\n"); + reportmsg((Mstr(" Status: ") + + backend(i).availablestr()) + + (Mstr(", ") + backend(i).livestr()) + "\n"); + reportmsg((Mstr(" Connections: ") + + backend(i).connections()) + + + (Mstr(" (max ") + backend(i).maxconn()) + "\n"); + reportmsg((Mstr(" Served:") + backend(i).bytesserved()) + + (Mstr(" bytes, ") + backend(i).clientsserved()) + + " clients\n"); } report (false); reportmsg ("*** XR STATUS REPORT ENDS ***\n"); @@ -122,32 +115,23 @@ void Balancer::serve() { // Show whom we've accepted if (config.verbose()) { - ostringstream o; - o << clsock; - msg ("Accepted connection from " + clientip + - " as client fd " + o.str() +"\n"); - ostringstream n; - n << connections(); - msg ("Balancer is serving " + n.str() + " clients\n"); + msg ((Mstr("Accepted connection from ") + clientip) + + (Mstr(" as client fd ") + clsock) + "\n"); + msg ((Mstr("Balancer is serving ") + connections()) + + " clients\n"); msg ("Current back end states:\n"); - for (unsigned i = 0; i < nbackends(); i++) { - ostringstream status; - status << backend(i).connections() << " connections"; - if (backend(i).maxconn()) - status << " (max " << backend(i).maxconn() << ")"; - status << ", status " << backend(i).availablestr(); - msg (" Back end " + backend(i).description() + ": " + - status.str() + "\n"); - } + for (unsigned i = 0; i < nbackends(); i++) + msg((Mstr(" Back end ") + backend(i).description()) + + (Mstr(": ") + backend(i).connections()) + + (Mstr(" connections , max ") + backend(i).maxconn()) + + (Mstr(", status ") + backend(i).availablestr()) + "\n"); } // We got action! Check if the total connections to the // balancer doesn't exceed the max. if (config.maxconn() && connections() >= config.maxconn()) { - ostringstream o; - o << connections() << " connections (max " - << config.maxconn() << ")"; - msg ("Not serving client: already " + o.str() + "\n"); + msg ((Mstr("Not serving client: already ") + connections()) + + (Mstr(" (max ") + config.maxconn()) + "\n"); socketclose (clsock); continue; } @@ -170,10 +154,8 @@ void Balancer::serve() { if (config.debug()) { void *mem = malloc(16); free (mem); - ostringstream o; - o << mem; - debugmsg ("Allocation boundary at dispatcher start: " + - o.str() + "\n"); + _debugmsg (Mstr("Allocation boundary at dispatcher start: ") + + mem + "\n"); } d->start(); @@ -201,10 +183,8 @@ void Balancer::serve() { // If we exceed the max # of requests, stop.. if (config.quitafter()) { - ostringstream o; - o << "Request " << requestnr() << " underway of max " - << config.quitafter() << "\n"; - msg (o.str()); + msg ((Mstr("Request ") + requestnr()) + + (Mstr(" underway of max ") + config.quitafter()) + "\n"); if (requestnr() >= (long)config.quitafter()) { msg ("Max requests served, will stop.\n"); break; @@ -222,9 +202,7 @@ void Balancer::serve() { if (!curr_conn) break; if (curr_conn != prev_conn) { - ostringstream o; - o << curr_conn; - msg ("There are still " + o.str() + " connections\n"); + msg ((Mstr("There are still ") + curr_conn) + " connections\n"); prev_conn = curr_conn; } sleep (1); diff --git a/xr/etc/status.xslt b/xr/etc/status.xslt @@ -64,9 +64,12 @@ <xsl:template match="/status/server"> <tr> - <td class="server" colspan="4"> + <td class="server" colspan="3"> <b>Server <xsl:value-of select="address"/> </b> </td> + <td> + <input type="button" onclick="goto('/', '');" value="Refresh"/> + </td> </tr> <tr> <td>Type</td> @@ -319,6 +322,26 @@ </td> </tr> </xsl:if> + <tr> + <td></td> + <td colspan="2">Up state</td> + <td> + <xsl:choose> + <xsl:when test="up = 'up'"> + <select onchange="goto('/backend/{nr}/up/off', '');"> + <option value="yes" selected="1">yes</option> + <option value="no">no</option> + </select> + </xsl:when> + <xsl:otherwise> + <select onchange="goto('/backend/{nr}/up/on', '');"> + <option value="yes">yes</option> + <option value="no" selected="1">no</option> + </select> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> </xsl:template> <xsl:template match="/status/server/http"> diff --git a/xr/fdset/readable.cc b/xr/fdset/readable.cc @@ -45,11 +45,7 @@ int Fdset::readable() const { // Check what's readable. for (unsigned i = 0; i < set.size(); i++) if (FD_ISSET (set[i], &readset)) { - if (config.debug()) { - ostringstream o; - o << set[i]; - debugmsg ("Fd " + o.str() + " has become readable\n"); - } + debugmsg (Mstr("Fd ") + set[i] + " has become readable\n"); return (set[i]); } diff --git a/xr/fdset/writeable.cc b/xr/fdset/writeable.cc @@ -44,11 +44,7 @@ int Fdset::writeable() const { // Check what's writeable. for (unsigned i = 0; i < set.size(); i++) if (FD_ISSET (set[i], &writeset)) { - if (config.debug()) { - ostringstream o; - o << set[i]; - debugmsg ("Fd " + o.str() + " has become writeable\n"); - } + debugmsg (Mstr("Fd ") + set[i] + " has become writeable\n"); return (set[i]); } diff --git a/xr/httpdispatcher/handle.cc b/xr/httpdispatcher/handle.cc @@ -28,13 +28,6 @@ void HttpDispatcher::handle() { (config.stickyhttp() && !issticky())) modify_serverheaders = true; - /* - ostringstream o; - o << "stickyhttp:" << config.stickyhttp() << " issticky:" - << issticky() << " modifyheaders:" << modify_serverheaders << "\n"; - debugmsg(o.str()); - */ - // Go into copy-thru mode. If required, catch the server headers on // their first appearance and modify them. while (1) { @@ -77,11 +70,8 @@ void HttpDispatcher::handle() { timeout = config.client_timeout(); } - if (config.debug()) { - ostringstream o; - o << "Had data on " << sock << ", sending to " << othersock << "\n"; - debugmsg (o.str()); - } + debugmsg (Mstr("Had data on ") + sock + + (Mstr(", sending to ") + othersock) + "\n"); buf.netwrite(othersock, timeout); if (sock == backendfd()) diff --git a/xr/httpdispatcher/senderrorpage.cc b/xr/httpdispatcher/senderrorpage.cc @@ -20,14 +20,14 @@ void HttpDispatcher::senderrorpage() { " You request could not be completed. Please retry later.\n" " </body>\n" "</html>\n"; - ostringstream msg; - msg << + ostringstream mess; + mess << "HTTP/1.0 502 Internal Server Error\r\n" "Content-Length: " << txt.size() << "\r\n" "\r\n" << txt; - fdwrite (clientfd(), config.client_timeout(), - msg.str().c_str(), msg.str().size()); + Netbuffer buf(mess.str()); + buf.netwrite(clientfd(), config.client_timeout()); } catch (Error const &e) { cerr << e.what() << " (while sending error page)\n"; } diff --git a/xr/mstr/mstr b/xr/mstr/mstr @@ -0,0 +1,46 @@ +#ifndef _MSTR_ +#define _MSTR_ + +#include "sys/sys" + +class Mstr: public string { +public: + Mstr(string s): string(s) {} + Mstr(char const *s): string(s) {} + Mstr const &operator+ (int i) { + ostringstream o; + o << i; + *this += o.str(); + return *this; + } + Mstr const &operator+ (unsigned i) { + ostringstream o; + o << i; + *this += o.str(); + return *this; + } + Mstr const &operator+ (time_t i) { + ostringstream o; + o << i; + *this += o.str(); + return *this; + } + Mstr const &operator+ (double i) { + ostringstream o; + o << i; + *this += o.str(); + return *this; + } + Mstr const &operator+(string const &s) { + *this += s; + return *this; + } + Mstr const &operator+(void const *p) { + ostringstream o; + o << p; + *this += o.str(); + return *this; + } +}; + +#endif diff --git a/xr/netbuffer/checkspace.cc b/xr/netbuffer/checkspace.cc @@ -9,12 +9,8 @@ void Netbuffer::check_space(unsigned extra) { if (! buf_data) throw static_cast<Error>("Memory fault in Netbuffer::check_space"); } else if (buf_sz + extra > buf_alloced) { - if (config.verbose()) { - ostringstream o; - o << "Reallocating net buffer from " << buf_alloced - << " to " << buf_alloced + extra << " bytes\n"; - msg (o.str()); - } + msg((Mstr("Reallocating net buffer from ") + buf_alloced) + + (Mstr(" to ") + (buf_alloced + extra)) + " bytes\n"); buf_alloced += extra; buf_data = (char*)realloc(buf_data, buf_alloced); if (! buf_data) diff --git a/xr/netbuffer/netbuffer b/xr/netbuffer/netbuffer @@ -11,6 +11,7 @@ class Netbuffer { public: Netbuffer(); Netbuffer (Netbuffer const &other); + Netbuffer (string const &s); virtual ~Netbuffer(); Netbuffer const &operator= (Netbuffer const &other); diff --git a/xr/netbuffer/netbuffer4.cc b/xr/netbuffer/netbuffer4.cc @@ -0,0 +1,13 @@ +#include "netbuffer" + +Netbuffer::Netbuffer (string const &s): + buf_data(0), buf_sz(0), buf_alloced(0) { + + check_space(s.size() + 1); + + buf_sz = s.size(); + + memcpy (buf_data, s.c_str(), buf_sz); + buf_data[buf_sz] = 0; + debugmsg((Mstr("Created netbuffer from string, ") + buf_sz) + " bytes\n"); +} diff --git a/xr/netbuffer/netread.cc b/xr/netbuffer/netread.cc @@ -24,7 +24,7 @@ unsigned Netbuffer::netread (int fd, int timeout) { for (unsigned i = 0; i < (unsigned)nread; i++) o << printable(buf_data[i]); o << "\n"; - debugmsg (o.str()); + _debugmsg (o.str()); } return nread; diff --git a/xr/netbuffer/netwrite.cc b/xr/netbuffer/netwrite.cc @@ -4,13 +4,10 @@ unsigned Netbuffer::netwrite (int fd, int timeout) const { PROFILE("Netbuffer::netwrite"); - if (config.debug()) { - ostringstream o; - o << "About to write " << buf_sz << " bytes to fd " << fd - << ", timeout " << timeout << "\n"; - debugmsg (o.str()); - } - + debugmsg((Mstr("About to write ") + buf_sz) + + (Mstr(" bytes to fd ") + fd) + + (Mstr(", timeout ") + timeout) + "\n"); + if (!buf_sz) return (0); @@ -51,7 +48,7 @@ unsigned Netbuffer::netwrite (int fd, int timeout) const { for (unsigned i = totwritten; i < totwritten + nwritten; i++) o << printable(buf_data[i]); o << "\n"; - debugmsg (o.str()); + _debugmsg (o.str()); } // EINVAL / EINPROGRESS errors are handled as: retry diff --git a/xr/sys/debugmsg.cc b/xr/sys/debugmsg.cc @@ -2,16 +2,15 @@ #include "config/config" #include "ThreadsAndMutexes/mutex/mutex" #include "profiler/profiler" +#include "mstr/mstr" -void debugmsg (string const &s) { +void _debugmsg (Mstr const &s) { PROFILE("debugmsg"); - if (config.debug()) { - Mutex::lock(&cerr); - if (config.prefixtimestamp()) - cerr << timestamp() << ' '; - cerr << pthread_self() << " DEBUG: " << s; - cerr.flush(); - Mutex::unlock(&cerr); - } + Mutex::lock(&cerr); + if (config.prefixtimestamp()) + cerr << timestamp() << ' '; + cerr << pthread_self() << " DEBUG: " << s; + cerr.flush(); + Mutex::unlock(&cerr); } diff --git a/xr/sys/fdwrite.cc b/xr/sys/fdwrite.cc @@ -1,70 +0,0 @@ -#include "sys" -#include "fdset/fdset" -#include "balancer/balancer" - -// obsolete -> replaced by netbuffer - -void fdwrite (int fd, int timeout, char const *buf, unsigned buflen) { - PROFILE("fdwrite"); - - if (config.debug()) { - ostringstream o; - o << "About to write " << buflen << " bytes to fd " << fd - << ", timeout " << timeout << "\n"; - debugmsg (o.str()); - } - - // Log to dump directory if requested - if (config.dumpdir().length()) { - ostringstream of; - of << config.dumpdir() << "/" << balancer.requestnr() << "." << fd; - FILE *f; - if ( (!(f = fopen (of.str().c_str(), "a"))) && - (!(f = fopen (of.str().c_str(), "w"))) ) - warnmsg ("Cannot write traffic log " + of.str() + ": " + - strerror(errno) + "\n"); - else { - fwrite (buf, 1, buflen, f); - fclose (f); - } - } - - // Send to the socket - unsigned totwritten = 0; - while (totwritten < buflen) { - // Wait for the socket to become writeable. - if (timeout) { - Fdset set (timeout); - set.add (fd); - if (set.writeable() != fd) - throw static_cast<Error>("Fd ") + fd + - " failed to become writable within " + timeout + " sec"; - } - - // Push bytes - ssize_t nwritten; -# ifdef SunOS - if (fd < 3) - nwritten = write (fd, buf + totwritten, buflen - totwritten); - else - nwritten = send (fd, buf + totwritten, buflen - totwritten, 0); -# else - nwritten = write (fd, buf + totwritten, buflen - totwritten); -# endif - - if (config.debug()) { - ostringstream o; - o << "Sent " << nwritten << " bytes to fd " << fd << "\n"; - debugmsg (o.str()); - } - - // EINVAL / EINPROGRESS errors are handled as: retry - // If any bytes were written, we're ok - if (nwritten >= 1) - totwritten += nwritten; - else if (errno != EINVAL && errno != EINPROGRESS) - throw static_cast<Error>("Write/send failed: errno=") + - errno + ", " + strerror(errno) + ", result=" + nwritten; - } -} - diff --git a/xr/sys/ipmatch.cc b/xr/sys/ipmatch.cc @@ -9,9 +9,9 @@ bool ipmatch (struct in_addr adr, struct in_addr mask) { memcpy (&lmask, &mask, sizeof(long)); bool match = ( (laddr & lmask) == laddr ); - if (config.debug()) - debugmsg ("Matching ip " + (string)inet_ntoa(adr) + " against mask " + - (string)inet_ntoa(mask) + ": " + - (match ? "match" : "miss") + "\n"); + debugmsg ("Matching ip " + (string)inet_ntoa(adr) + " against mask " + + (string)inet_ntoa(mask) + ": " + + (match ? "match" : "miss") + "\n"); + return (match); } diff --git a/xr/sys/main.cc b/xr/sys/main.cc @@ -29,9 +29,7 @@ int main (int argc, char **argv) { // Load configuration from the commandline, promote verbosity config.parsecmdline (argc, argv); - ostringstream o; - o << getpid(); - msg ("XR running as PID " + o.str() + "\n"); + msg ((Mstr("XR running as PID ") + getpid()) + "\n"); // Load the signal handler. for (unsigned i = 0; i < sizeof(relevant_sig) / sizeof(int); i++) diff --git a/xr/sys/msg.cc b/xr/sys/msg.cc @@ -2,16 +2,15 @@ #include "config/config" #include "ThreadsAndMutexes/mutex/mutex" #include "profiler/profiler" +#include "mstr/mstr" -void msg (string const &s) { +void _msg (Mstr const &s) { PROFILE("msg"); - if (config.verbose()) { - Mutex::lock(&cerr); - if (config.prefixtimestamp()) - cerr << timestamp() << ' '; - cerr << pthread_self() << " INFO: " << s; - cerr.flush(); - Mutex::unlock(&cerr); - } + Mutex::lock(&cerr); + if (config.prefixtimestamp()) + cerr << timestamp() << ' '; + cerr << pthread_self() << " INFO: " << s; + cerr.flush(); + Mutex::unlock(&cerr); } diff --git a/xr/sys/reportmsg.cc b/xr/sys/reportmsg.cc @@ -1,8 +1,9 @@ #include "sys" #include "config/config" #include "ThreadsAndMutexes/mutex/mutex" +#include "mstr/mstr" -void reportmsg (string const &s) { +void reportmsg (Mstr const &s) { Mutex::lock(&cerr); if (config.prefixtimestamp()) cerr << timestamp() << ' '; diff --git a/xr/sys/serversocket.cc b/xr/sys/serversocket.cc @@ -1,6 +1,7 @@ #include "sys" -#include "../error/error" +#include "error/error" #include "profiler/profiler" +#include "config/config" int serversocket (string addr, int port, string desc) { PROFILE("serversocket"); @@ -23,28 +24,25 @@ int serversocket (string addr, int port, string desc) { saddr.sin_port = htons(port); // Assign interface to listen to - ostringstream display_ip; if (addr[0] != '0') { msg ("Binding balancer to specific IP address " + addr + "\n"); if ( (saddr.sin_addr.s_addr = inet_addr (addr.c_str())) == INADDR_NONE ) throw static_cast<Error>("Cannot convert ") + desc + " IP '" + addr + "' to network bytes"; - display_ip << addr; } else { + msg ("Binding balancer to all local IP addresses\n"); saddr.sin_addr.s_addr = htonl (INADDR_ANY); - display_ip << "0.0.0.0"; } - display_ip << ":" << port; // Bind and listen if (bind (sock, (sockaddr*) &saddr, sizeof(saddr)) < 0) - throw static_cast<Error>("Failed to bind ") + desc + " to " + - display_ip.str() + ": " + strerror(errno); + throw static_cast<Error>("Failed to bind ") + desc + + " to IP/port: " + strerror(errno); if (listen (sock, 5) < 0) - throw static_cast<Error>("Failed to listen to ") + desc + " IP " + - display_ip.str() + ": " + strerror(errno); + throw static_cast<Error>("Failed to listen to ") + desc + + " IP/port: " + strerror(errno); - msg ("TCP server for " + desc + " listening to " + display_ip.str() + "\n"); + msg ("TCP server for " + desc + " listening\n"); return (sock); } diff --git a/xr/sys/socketclose.cc b/xr/sys/socketclose.cc @@ -4,11 +4,7 @@ void socketclose (int fd) { PROFILE("socketclose"); - if (config.debug()) { - ostringstream o; - o << fd; - debugmsg ("Closing socket " + o.str() + "\n"); - } + debugmsg ((Mstr("Closing socket ") + fd) + "\n"); if (config.fastclose()) { struct linger l; diff --git a/xr/sys/sys b/xr/sys/sys @@ -48,20 +48,25 @@ # define PROFILE(x) #endif -/* Generic functions */ - using namespace std; -void msg (string const &s); -void debugmsg (string const &s); -void reportmsg (string const &s); +// This we need locally for msg(), debugmsg() +#include "mstr/mstr" + +/* Messaging. Conditionals are defined as a macro to speed things up. */ +void _msg (Mstr const &s); +#define msg(x) if(config.verbose()) _msg(x) +void _debugmsg (Mstr const &s); +#define debugmsg(x) if (config.debug()) _debugmsg(x) +void reportmsg (Mstr const &s); +void warnmsg (Mstr const &s); + +/* Other */ int serversocket (string addr, int port, string description); string timestamp(time_t s = 0); 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); void mt_srand(unsigned long s); unsigned long mt_rand(void); diff --git a/xr/sys/warnmsg.cc b/xr/sys/warnmsg.cc @@ -1,8 +1,9 @@ #include "sys" #include "config/config" #include "ThreadsAndMutexes/mutex/mutex" +#include "mstr/mstr" -void warnmsg (string const &s) { +void warnmsg (Mstr const &s) { Mutex::lock(&cerr); if (config.prefixtimestamp()) cerr << timestamp() << ' '; diff --git a/xr/tcpdispatcher/dispatch.cc b/xr/tcpdispatcher/dispatch.cc @@ -30,14 +30,9 @@ void TcpDispatcher::dispatch() { } else { connected = true; backendfd(tb.sock()); - - if (config.verbose()) { - ostringstream o; - o << tb.sock(); - msg ("Will dispatch client to back end " + tb.description() + - " on fd " + o.str() + "\n"); - } - + msg ((Mstr("Will dispatch client to back end ") + + tb.description()) + + (Mstr(" on fd ") + tb.sock()) + "\n"); break; } } diff --git a/xr/tcpdispatcher/execute.cc b/xr/tcpdispatcher/execute.cc @@ -4,11 +4,7 @@ static map <unsigned long, queue <time_t> > accesslog; static time_t accesslog_lastclean = 0; void TcpDispatcher::execute() { - ostringstream o; - o << clientfd(); - - if (config.verbose()) - msg ("Dispatch request for client fd " + o.str() + "\n"); + msg ((Mstr("Dispatch request for client fd ") + clientfd()) + "\n"); // Check 'softmaxconnrate' and 'hardmaxconnrate' now! // Descend into this block if connrate_time() is set, AND @@ -101,13 +97,9 @@ void TcpDispatcher::execute() { return; } - if (config.verbose()) { - ostringstream o; - o << "Dispatching client fd " << clientfd() << " to " - << balancer.backend(target_backend).description() - << ", fd " << backendfd() << "\n"; - msg (o.str()); - } + msg ((Mstr("Dispatchign client fd ") + clientfd()) + + (Mstr(" to ") + balancer.backend(target_backend).description()) + + (Mstr(", fd ") + backendfd()) + "\n"); balancer.backend(target_backend).startconnection(); @@ -122,10 +114,7 @@ void TcpDispatcher::execute() { socketclose (clientfd()); socketclose (backendfd()); - if (config.verbose()) { - ostringstream o; - o << "Done dispatching client fd " << backendfd() << " at " - << balancer.backend(target_backend).description() << "\n"; - msg (o.str()); - } + msg ((Mstr("Done dispatching to back end fd ") + backendfd()) + + (Mstr(" at ") + balancer.backend(target_backend).description()) + + "\n"); } diff --git a/xr/tcpdispatcher/handle.cc b/xr/tcpdispatcher/handle.cc @@ -1,12 +1,10 @@ #include "tcpdispatcher" void TcpDispatcher::handle() { - if (config.debug()) { - ostringstream o; - o << "TCP dispatcher: About to shuttle between client fd " - << clientfd() << " and backend fd " << backendfd() << "\n"; - debugmsg (o.str()); - } + + debugmsg (Mstr("TCP dispatcher: About to shuttle between client fd ") + + clientfd() + + (Mstr(" and backend fd ") + backendfd()) + "\n"); while (1) { Fdset readset (config.client_timeout()); @@ -28,11 +26,8 @@ void TcpDispatcher::handle() { timeout = config.client_timeout(); } - if (config.debug()) { - ostringstream o; - o << "Had data on " << sock << ", sending to " << othersock << "\n"; - debugmsg (o.str()); - } + debugmsg (Mstr("Had data on ") + sock + + (Mstr(", sending to ") + othersock) + "\n"); netbuffer.netwrite (othersock, timeout); if (sock == backendfd()) diff --git a/xr/tcpdispatcher/printable.cc b/xr/tcpdispatcher/printable.cc @@ -1,24 +0,0 @@ -#include "tcpdispatcher" - -string TcpDispatcher::printable (char ch) const { - ostringstream o; - - if (isprint(ch) && ch != '\\') { - o << ch; - return (o.str()); - } else if (ch == '\n') - return ("\\n"); - else if (ch == '\r') - return ("\\r"); - else if (ch == '\t') - return ("\\t"); - else { - char buf[10]; - sprintf (buf, "%3.3o", ch & 0xff); - o << "\\" << buf; - return (o.str()); - } - - // Avoid warnings - return ("."); -} diff --git a/xr/tcpdispatcher/readchunk.cc b/xr/tcpdispatcher/readchunk.cc @@ -1,20 +0,0 @@ -#include "tcpdispatcher" - -// obsolete -> replaced by netbuffer - -unsigned TcpDispatcher::readchunk (int src) { - ssize_t nread = read (src, data_buf, config.buffersize()); - if (nread < 0) - throw static_cast<Error>("Read failed on fd ") + src; - - if (config.debug() && nread) { - ostringstream o; - o << "Got " << nread << " bytes from fd " << src << ": "; - for (unsigned i = 0; i < (unsigned)nread; i++) - o << printable(data_buf[i]); - o << "\n"; - debugmsg (o.str()); - } - - return (data_bufsz = nread); -} diff --git a/xr/tcpdispatcher/tcpdispatcher b/xr/tcpdispatcher/tcpdispatcher @@ -38,26 +38,14 @@ public: int backendfd() const { return backend_fd; } void backendfd(int b) { backend_fd = b; } - // obsolete 2 - char const *databuf() const { return data_buf; } - unsigned databufsize() const { return data_bufsz; } - BackendVector const &targetlist() const { return target_list; } void targetlist (BackendVector t) { target_list = t; } unsigned readchunk (int src); private: - // obsolete - string printable (char ch) const; - struct in_addr client_ip; int target_backend, client_fd, backend_fd; - - // obsolete 2 - char *data_buf; - unsigned data_bufsz; - Algorithm *algorithm; BackendVector target_list; Netbuffer netbuffer; diff --git a/xr/tcpdispatcher/tcpdispatcher1.cc b/xr/tcpdispatcher/tcpdispatcher1.cc @@ -2,10 +2,7 @@ TcpDispatcher::TcpDispatcher(int cfd, struct in_addr cip): Thread(), client_ip(cip), target_backend(-1), client_fd(cfd), - backend_fd(-1), data_bufsz(0), target_list(), netbuffer() { - - // Set up a data buffer for network transfers - data_buf = new char[config.buffersize()]; + backend_fd(-1), target_list(), netbuffer() { // Instantiate dispatchmode algorithm switch (config.dispatchmode()) { diff --git a/xr/tcpdispatcher/tcpdispatcher2.cc b/xr/tcpdispatcher/tcpdispatcher2.cc @@ -1,7 +1,6 @@ #include "tcpdispatcher" TcpDispatcher::~TcpDispatcher() { - delete data_buf; delete algorithm; debugmsg ("TCP dispatcher finished\n"); } diff --git a/xr/webinterface/answer.cc b/xr/webinterface/answer.cc @@ -289,5 +289,13 @@ void Webinterface::answer(Httpbuffer req) { return; } + // /backend/NR/up/BOOL + if (parts.size() == 4 && parts[0] == "backend" && parts[2] == "up") { + unsigned ind = backendindex(parts[1]); + balancer.backend(ind).up(str2bool(parts[3], "up")); + answer_status(); + return; + } + throw static_cast<Error>("No action for URI '") + uri + "'"; } diff --git a/xr/webinterface/answerblob.cc b/xr/webinterface/answerblob.cc @@ -10,5 +10,6 @@ void Webinterface::answer_blob (string const &blob) { "Content-Length: " + cl.str() + "\r\n" "\r\n" + blob; - fdwrite (cfd, config.client_timeout(), resp.c_str(), resp.size()); + Netbuffer buf(resp); + buf.netwrite(cfd, config.client_timeout()); } diff --git a/xr/webinterface/answerstatus.cc b/xr/webinterface/answerstatus.cc @@ -55,6 +55,7 @@ void Webinterface::answer_status() { " <weight>" << balancer.backend(i).weight() << "</weight>\n" " <maxconnections>" << balancer.backend(i).maxconn() << "</maxconnections>\n" " <loadavg>" << balancer.backend(i).loadavg() << "</loadavg>\n" + " <up>" << balancer.backend(i).upstr() << "</up>\n" " <live>" << balancer.backend(i).livestr() << "</live>\n" " <available>" << balancer.backend(i).availablestr() << "</available>\n" " <connections>" << balancer.backend(i).connections() << "</connections>\n" diff --git a/xr/webinterface/execute.cc b/xr/webinterface/execute.cc @@ -17,11 +17,8 @@ void Webinterface::execute() { } break; } - - ostringstream o; - o << sfd; - msg ("Web interface started on socket " + o.str() + "\n"); + msg ((Mstr("Web interface started on socket ") + sfd) + "\n"); while (!balancer.terminate()) { try { Fdset fdset(0); @@ -48,12 +45,8 @@ void Webinterface::execute() { "Content-Length: " << m.str().length() << "\r\n" "\r\n" << m.str(); - - try { - fdwrite(cfd, config.client_timeout(), - o.str().c_str(), o.str().length()); - } catch (...) { - } + Netbuffer buf(o.str()); + buf.netwrite(cfd, config.client_timeout()); socketclose(cfd); } } diff --git a/xr/webinterface/serve.cc b/xr/webinterface/serve.cc @@ -1,9 +1,7 @@ #include "webinterface" void Webinterface::serve () { - ostringstream o; - o << cfd; - msg ("Webinterface serving request on client fd " + o.str() + "\n"); + msg ((Mstr("Webinterface serving request on client fd ") + cfd) + "\n"); Httpbuffer clientrequest; clientrequest.netread(cfd, config.client_timeout());