crossroads

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

commit 02de71f3baf64c4f7f21ed7282a10139dd6fdf95
parent 6172bba1dadb972364e98a26703cca4b88a73b68
Author: finwo <finwo@pm.me>
Date:   Sat,  3 Jan 2026 19:31:30 +0100

1.38

Diffstat:
MChangeLog | 25+++++++++++++++++++++++++
MMakefile | 1+
Mdoc/crossroads.html | 484++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mdoc/crossroads.man | 205+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Mdoc/crossroads.pdf | 0
Mdoc/crossroads.yo | 2+-
Mdoc/tips.yo | 1368+------------------------------------------------------------------------------
Adoc/tips/clientip.yo | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/tips/debugging.yo | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/tips/examples.yo | 236+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/tips/externalhandler.yo | 449+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/tips/howselected.yo | 179+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/tips/httpstickiness.yo | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/tips/ipconntrackmax.yo | 35+++++++++++++++++++++++++++++++++++
Adoc/tips/ipfiltering.yo | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/tips/retries.yo | 41+++++++++++++++++++++++++++++++++++++++++
Adoc/tips/tcpstickiness.yo | 22++++++++++++++++++++++
Adoc/tips/throttling.yo | 27+++++++++++++++++++++++++++
Mdoc/using.yo | 34+++++++++++++++++++++++++++++++---
Metc/Makefile.def | 17++++++++++++-----
Metc/svnrev.txt | 2+-
Msrc/Makefile | 49+++++++++++++++++++++++++------------------------
Msrc/allocreporter.c | 2+-
Msrc/ansistamp.c | 2+-
Msrc/backendavailable.c | 2+-
Msrc/backendconnect.c | 117+++++++++++++++++++++++++++++++++++++++-----------------------------------------
Msrc/backendcount.c | 2+-
Msrc/choosebackend.c | 7++++---
Msrc/configtest.c | 2+-
Msrc/copysockets.c | 2+-
Msrc/createcommandlinespace.c | 2+-
Msrc/crossroads.h | 36+++++++++++++++++++-----------------
Msrc/deallocreporter.c | 2+-
Msrc/decrclientcount.c | 45++++++++++++++++++++++++++-------------------
Msrc/error.c | 2+-
Msrc/forktcpservicer.c | 2+-
Msrc/hashpjw.c | 2+-
Msrc/httpcopy.c | 6+++---
Msrc/httperror.c | 2+-
Msrc/httpheaderaddheader.c | 2+-
Msrc/httpheaderappendheader.c | 2+-
Msrc/httpheaderconnectiontype.c | 2+-
Msrc/httpheaderfree.c | 2+-
Msrc/httpheaderhascookie.c | 4++--
Msrc/httpheaderhttpver.c | 2+-
Msrc/httpheadernew.c | 2+-
Msrc/httpheaderread.c | 2+-
Msrc/httpheaderremoveheader.c | 2+-
Msrc/httpheadersetheader.c | 2+-
Msrc/httpheaderval.c | 2+-
Msrc/httpheaderwrite.c | 2+-
Msrc/httpinsertheader.c | 2+-
Msrc/httpserve.c | 4++--
Msrc/httpserversocket.c | 2+-
Msrc/httpwrite.c | 6+++---
Msrc/incrclientcount.c | 2+-
Msrc/initsockaddr.c | 2+-
Msrc/interrupt.c | 100++++++++++++++++++++++++++++++++-----------------------------------------------
Msrc/ipfaddallow.c | 2+-
Msrc/ipfadddeny.c | 2+-
Msrc/ipfallowed.c | 2+-
Msrc/ipfdenied.c | 2+-
Msrc/ipfloadfile.c | 2+-
Msrc/ipfmatch.c | 2+-
Msrc/ipfparse.c | 2+-
Msrc/ishexdigit.c | 2+-
Msrc/isspace.c | 2+-
Msrc/lexer.c | 2+-
Msrc/lockreporter.c | 2+-
Msrc/logactivityany.c | 4++--
Msrc/logactivitycontinuation.c | 2+-
Msrc/logactivityend.c | 2+-
Msrc/logactivitystart.c | 2+-
Msrc/main.c | 13+++++++++----
Msrc/makesocket.c | 14+++++++++++---
Msrc/markactivity.c | 90++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/msg.c | 2+-
Msrc/msgdumpbuf.c | 2+-
Msrc/netbuffer.c | 4++--
Msrc/netbufread.c | 15+++++++--------
Msrc/netcopy.c | 4++--
Msrc/netread.c | 15++++++++++++---
Msrc/netwrite.c | 17++++++++---------
Msrc/parser.c | 228+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/parser.h | 2+-
Msrc/parser.y | 6++++++
Msrc/restart.c | 2+-
Msrc/runservice.c | 112+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/serve.c | 2+-
Msrc/setprogramtitle.c | 2+-
Asrc/showconfig.c | 38++++++++++++++++++++++++++++++++++++++
Msrc/showservices.c | 2+-
Msrc/showstatus.c | 12+++++++++---
Msrc/stagetostring.c | 2+-
Msrc/statetostring.c | 2+-
Msrc/stopdaemon.c | 2+-
Msrc/strcasestr.c | 7++-----
Msrc/strexpandformat.c | 2+-
Msrc/stringtostate.c | 2+-
Msrc/strlcat.c | 5+++--
Msrc/strprintf.c | 2+-
Msrc/strvprintf.c | 2+-
Msrc/sysrun.c | 2+-
Msrc/tcpserve.c | 18+++++++++++++++++-
Msrc/tellservice.c | 2+-
Msrc/thruputlog.c | 9+++++----
Msrc/trafficlog.c | 9+++++----
Msrc/uidassume.c | 2+-
Msrc/uidrestore.c | 2+-
Msrc/unlockreporter.c | 2+-
Msrc/usage.c | 2+-
Msrc/usage.txt | 4+++-
Msrc/vsyslog.c | 4++--
Msrc/wakeuphandler.c | 2+-
Msrc/warning.c | 2+-
Msrc/writelog.c | 2+-
Msrc/xmalloc.c | 2+-
Msrc/xrealloc.c | 2+-
Msrc/xstrcat.c | 2+-
Msrc/xstrcatch.c | 2+-
Msrc/xstrdup.c | 2+-
Mtest/breakingclient | 4++--
Atest/t7.conf | 13+++++++++++++
Atest/t8.conf | 32++++++++++++++++++++++++++++++++
Mtools/c-conf | 66+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
125 files changed, 2668 insertions(+), 2133 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,6 +1,31 @@ ChangeLog for Crossroads ------------------------------------------------------------------------------ +1.38 [KK 2007-04-26] Many changes: + - 'crossroads status' now supports optional service/backend arguments. + - Added specific nullstring initializers to parser.y. + - Added info on ip_conntrack_max to the tips section of the docs + (Thanks, Felix). + - Rewritten the code that timeouts upon network connect (this used + to have jumps which isn't safe). + - Added docs on -t (tabular status report) flag. + - Added code to avoid logging and running on-end hooks when HTTP + mode fails to find a suitable back end. + - Added test/t8.conf which works with breaking-client, to + simulate clients that hang up. + - 'make clean' removes GDB's history files + - Removed usage of non-reentrant functions from signal handler + (interrupt.c) + - Added RETRY_WAIT, small sleep time when retrying connecting to + the same back end + - Added description of retries keyword to the Tips&Tricks section + - Fixed mark_activity() to apply decays only for 'true' + connections, not for wakeup calls + - Split up the tips section of the docs into separate sources. + - Added flag -C to show compile-time settings. + - Sped up make process by scanning c-conf output just once (:= + instead of =, probably GNU Make only, we'll see). + 1.37 [KK 2007-04-17] Intermediate release for bughunts on 64bit Linux. 1.36 [KK 2007-04-16] Fixed small bug in total usage counting. Bugfix diff --git a/Makefile b/Makefile @@ -19,6 +19,7 @@ clean: $(MAKE) -C src clean $(MAKE) -C doc clean find . -type f -name '*~' -exec rm {} \; + find . -type f -name .gdb_history -exec rm {} \; distclean: $(MAKE) -C src distclean diff --git a/doc/crossroads.html b/doc/crossroads.html @@ -1,12 +1,12 @@ <a name="defs.yo"></a><html><head> -<title>Crossroads 1.37</title> +<title>Crossroads 1.38</title> <link rel="stylesheet" type="text/css" href="http://www.e-tunity.com/css/yodl.css"> <link rel="stylesheet" type="text/css" href="http://www.e-tunity.com/css/yodl.css"> <link rev="made" href="mailto:info@e-tunity.com"> </head> <body> <hr> -<h1>Crossroads 1.37</h1> +<h1>Crossroads 1.38</h1> <h2>Karel Kubat</h2> <h2>e-tunity</h2><h2>2005, 2006, ff.</h2> @@ -38,106 +38,109 @@ <dt><h3><a href="#l9">3: Using Crossroads</a></h3></dt> <dl> <dt><a href="#l10">3.1: General Commandline Syntax</a></dt> -<dt><a href="#l11">3.2: Logging-related options</a></dt> -<dt><a href="#l12">3.3: Reloading Configurations</a></dt> +<dt><a href="#l11">3.2: Status Reporting</a></dt> +<dt><a href="#l12">3.3: Logging-related options</a></dt> +<dt><a href="#l13">3.4: Reloading Configurations</a></dt> </dl> -<dt><h3><a href="#l13">4: The configuration</a></h3></dt> +<dt><h3><a href="#l14">4: The configuration</a></h3></dt> <dl> -<dt><a href="#l14">4.1: General language elements</a></dt> +<dt><a href="#l15">4.1: General language elements</a></dt> <dl> -<dt><a href="#l15">4.1.1: Empty lines and comments</a></dt> -<dt><a href="#l16">4.1.2: Keywords, numbers, identifiers, generic strings</a></dt> +<dt><a href="#l16">4.1.1: Empty lines and comments</a></dt> +<dt><a href="#l17">4.1.2: Keywords, numbers, identifiers, generic strings</a></dt> </dl> -<dt><a href="#l17">4.2: Service definitions</a></dt> +<dt><a href="#l18">4.2: Service definitions</a></dt> <dl> -<dt><a href="#l18">4.2.1: type - Defining the service type</a></dt> -<dt><a href="#l19">4.2.2: port - Specifying the listen port</a></dt> -<dt><a href="#l20">4.2.3: bindto - Binding to a specific IP address</a></dt> -<dt><a href="#l21">4.2.4: verbosity - Controlling debug output</a></dt> -<dt><a href="#l22">4.2.5: dispatchmode - How are back ends selected</a></dt> -<dt><a href="#l23">4.2.6: revivinginterval - Back end wakeup calls</a></dt> -<dt><a href="#l24">4.2.7: maxconnections - Limiting concurrent clients at service level</a></dt> -<dt><a href="#l25">4.2.8: backlog - The TCP Back Log size</a></dt> -<dt><a href="#l26">4.2.9: shmkey - Shared Memory Access</a></dt> -<dt><a href="#l27">4.2.10: allow* and deny* - Allowing or denying connections</a></dt> -<dt><a href="#l28">4.2.11: useraccount - Limiting the effective ID of external processes</a></dt> +<dt><a href="#l19">4.2.1: type - Defining the service type</a></dt> +<dt><a href="#l20">4.2.2: port - Specifying the listen port</a></dt> +<dt><a href="#l21">4.2.3: bindto - Binding to a specific IP address</a></dt> +<dt><a href="#l22">4.2.4: verbosity - Controlling debug output</a></dt> +<dt><a href="#l23">4.2.5: dispatchmode - How are back ends selected</a></dt> +<dt><a href="#l24">4.2.6: revivinginterval - Back end wakeup calls</a></dt> +<dt><a href="#l25">4.2.7: maxconnections - Limiting concurrent clients at service level</a></dt> +<dt><a href="#l26">4.2.8: backlog - The TCP Back Log size</a></dt> +<dt><a href="#l27">4.2.9: shmkey - Shared Memory Access</a></dt> +<dt><a href="#l28">4.2.10: allow* and deny* - Allowing or denying connections</a></dt> +<dt><a href="#l29">4.2.11: useraccount - Limiting the effective ID of external processes</a></dt> </dl> -<dt><a href="#l29">4.3: Backend definitions</a></dt> +<dt><a href="#l30">4.3: Backend definitions</a></dt> <dl> -<dt><a href="#l30">4.3.1: server - Specifying the back end address</a></dt> -<dt><a href="#l31">4.3.2: verbosity - Controlling verbosity at the back end level</a></dt> -<dt><a href="#l32">4.3.3: retries - Specifying allowed failures</a></dt> -<dt><a href="#l33">4.3.4: weight - When a back end is more equal than others</a></dt> -<dt><a href="#l34">4.3.5: decay - Levelling out activity of a back end</a></dt> -<dt><a href="#l35">4.3.6: onstart, onend, onfail - Action Hooks</a></dt> -<dt><a href="#l36">4.3.7: trafficlog and throughputlog - Debugging and Performance Aids</a></dt> -<dt><a href="#l37">4.3.8: stickycookie - Back end selection with an HTTP cookie</a></dt> -<dt><a href="#l38">4.3.9: HTTP Header Modification Directives</a></dt> +<dt><a href="#l31">4.3.1: server - Specifying the back end address</a></dt> +<dt><a href="#l32">4.3.2: verbosity - Controlling verbosity at the back end level</a></dt> +<dt><a href="#l33">4.3.3: retries - Specifying allowed failures</a></dt> +<dt><a href="#l34">4.3.4: weight - When a back end is more equal than others</a></dt> +<dt><a href="#l35">4.3.5: decay - Levelling out activity of a back end</a></dt> +<dt><a href="#l36">4.3.6: onstart, onend, onfail - Action Hooks</a></dt> +<dt><a href="#l37">4.3.7: trafficlog and throughputlog - Debugging and Performance Aids</a></dt> +<dt><a href="#l38">4.3.8: stickycookie - Back end selection with an HTTP cookie</a></dt> +<dt><a href="#l39">4.3.9: HTTP Header Modification Directives</a></dt> </dl> </dl> -<dt><h3><a href="#l39">5: Tips, Tricks and Remarks</a></h3></dt> +<dt><h3><a href="#l40">5: Tips, Tricks and Random Remarks</a></h3></dt> <dl> -<dt><a href="#l40">5.1: How back ends are selected in load balancing</a></dt> +<dt><a href="#l41">5.1: How back ends are selected in load balancing</a></dt> <dl> -<dt><a href="#l41">5.1.1: Bysize, byduration or byconnections?</a></dt> -<dt><a href="#l42">5.1.2: Averaging size and duration</a></dt> -<dt><a href="#l43">5.1.3: Specifying decays</a></dt> -<dt><a href="#l44">5.1.4: Adjusting the weights</a></dt> -<dt><a href="#l45">5.1.5: Throttling the number of concurrent connections</a></dt> +<dt><a href="#l42">5.1.1: Bysize, byduration or byconnections?</a></dt> +<dt><a href="#l43">5.1.2: Averaging size and duration</a></dt> +<dt><a href="#l44">5.1.3: Specifying decays</a></dt> +<dt><a href="#l45">5.1.4: Adjusting the weights</a></dt> </dl> -<dt><a href="#l46">5.2: Using an external program to dispatch</a></dt> +<dt><a href="#l46">5.2: Throttling the number of concurrent connections</a></dt> +<dt><a href="#l47">5.3: Using an external program to dispatch</a></dt> <dl> -<dt><a href="#l47">5.2.1: Configuring the external handler</a></dt> -<dt><a href="#l48">5.2.2: Writing the external handler</a></dt> -<dt><a href="#l49">5.2.3: Examples of external handlers</a></dt> +<dt><a href="#l48">5.3.1: Configuring the external handler</a></dt> +<dt><a href="#l49">5.3.2: Writing the external handler</a></dt> +<dt><a href="#l50">5.3.3: Examples of external handlers</a></dt> </dl> -<dt><a href="#l50">5.3: TCP Session Stickiness</a></dt> -<dt><a href="#l51">5.4: HTTP Session Stickiness</a></dt> +<dt><a href="#l51">5.4: TCP Session Stickiness</a></dt> +<dt><a href="#l52">5.5: HTTP Session Stickiness</a></dt> <dl> -<dt><a href="#l52">5.4.1: Don't use stickiness!</a></dt> -<dt><a href="#l53">5.4.2: But if you must..</a></dt> +<dt><a href="#l53">5.5.1: Don't use stickiness!</a></dt> +<dt><a href="#l54">5.5.2: But if you must..</a></dt> </dl> -<dt><a href="#l54">5.5: Passing the client's IP address</a></dt> +<dt><a href="#l55">5.6: Passing the client's IP address</a></dt> <dl> -<dt><a href="#l55">5.5.1: Sample Crossroads configuration</a></dt> -<dt><a href="#l56">5.5.2: Sample Apache configuration</a></dt> +<dt><a href="#l56">5.6.1: Sample Crossroads configuration</a></dt> +<dt><a href="#l57">5.6.2: Sample Apache configuration</a></dt> </dl> -<dt><a href="#l57">5.6: Debugging network traffic</a></dt> -<dt><a href="#l58">5.7: Limiting Access to Crossroads by Client IP Address</a></dt> +<dt><a href="#l58">5.7: Debugging network traffic</a></dt> +<dt><a href="#l59">5.8: IP filtering: Limiting Access by Client IP Address</a></dt> <dl> -<dt><a href="#l59">5.7.1: General Examples</a></dt> -<dt><a href="#l60">5.7.2: Using External Files</a></dt> -<dt><a href="#l61">5.7.3: Mixing Directives</a></dt> +<dt><a href="#l60">5.8.1: General Examples</a></dt> +<dt><a href="#l61">5.8.2: Using External Files</a></dt> +<dt><a href="#l62">5.8.3: Mixing Directives</a></dt> </dl> -<dt><a href="#l62">5.8: Configuration examples</a></dt> +<dt><a href="#l63">5.9: Configuration examples</a></dt> <dl> -<dt><a href="#l63">5.8.1: A load balancer for three webserver back ends</a></dt> -<dt><a href="#l64">5.8.2: An HTTP forwarder when travelling</a></dt> -<dt><a href="#l65">5.8.3: SSH login with enforced idle logout</a></dt> +<dt><a href="#l64">5.9.1: A load balancer for three webserver back ends</a></dt> +<dt><a href="#l65">5.9.2: An HTTP forwarder when travelling</a></dt> +<dt><a href="#l66">5.9.3: SSH login with enforced idle logout</a></dt> </dl> +<dt><a href="#l67">5.10: Linux and ip_conntrack_max</a></dt> +<dt><a href="#l68">5.11: Marking back ends as bad after more than one try</a></dt> </dl> -<dt><h3><a href="#l66">6: Benchmarking</a></h3></dt> +<dt><h3><a href="#l69">6: Benchmarking</a></h3></dt> <dl> -<dt><a href="#l67">6.1: Benchmark 1: Accessing a proxy via crossroads or directly</a></dt> +<dt><a href="#l70">6.1: Benchmark 1: Accessing a proxy via crossroads or directly</a></dt> <dl> -<dt><a href="#l68">6.1.1: Results</a></dt> -<dt><a href="#l69">6.1.2: Discussion</a></dt> +<dt><a href="#l71">6.1.1: Results</a></dt> +<dt><a href="#l72">6.1.2: Discussion</a></dt> </dl> -<dt><a href="#l70">6.2: Benchmark 2: Crossroads versus Linux Virtual Server (LVS)</a></dt> +<dt><a href="#l73">6.2: Benchmark 2: Crossroads versus Linux Virtual Server (LVS)</a></dt> <dl> -<dt><a href="#l71">6.2.1: Environment</a></dt> -<dt><a href="#l72">6.2.2: Tests and results</a></dt> +<dt><a href="#l74">6.2.1: Environment</a></dt> +<dt><a href="#l75">6.2.2: Tests and results</a></dt> </dl> </dl> -<dt><h3><a href="#l73">7: Compiling and Installing</a></h3></dt> +<dt><h3><a href="#l76">7: Compiling and Installing</a></h3></dt> <dl> -<dt><a href="#l74">7.1: Prerequisites</a></dt> -<dt><a href="#l75">7.2: Compiling and installing</a></dt> -<dt><a href="#l76">7.3: Configuring crossroads</a></dt> -<dt><a href="#l77">7.4: A boot script</a></dt> +<dt><a href="#l77">7.1: Prerequisites</a></dt> +<dt><a href="#l78">7.2: Compiling and installing</a></dt> +<dt><a href="#l79">7.3: Configuring crossroads</a></dt> +<dt><a href="#l80">7.4: A boot script</a></dt> <dl> -<dt><a href="#l78">7.4.1: SysV Style Startup</a></dt> -<dt><a href="#l79">7.4.2: BSD Style Startup</a></dt> +<dt><a href="#l81">7.4.1: SysV Style Startup</a></dt> +<dt><a href="#l82">7.4.2: BSD Style Startup</a></dt> </dl> <p><hr><p> @@ -470,10 +473,40 @@ This section shows the most basic usage. As said above, start screen. A good way of quicky viewing the configuration file syntax, or of getting a start for your own configuration <code>/etc/crossroads.conf</code>. -</ul> +</ul> <p> <a name="l11"></a> -<h3>3.2: Logging-related options</h3> +<h3>3.2: Status Reporting</h3> +<p> +The command <code>crossroads status</code> shows a verbose human-readable +report of how Crossroads is doing. When many services are configured, +this can be a somewhat lengthy output. If you're interested in the +overview of only one service, you can use <code>crossroads status</code> +<em>servicename</em>, in which case the report will only be shown for the +stated service. +<p> +Similarly, if you're interested only in the status of a given back end +of a given service, use <code>crossroads service</code> <em>servicename</em> +<em>backendname</em>. +<p> +The flag <code>-t</code> causes the status overview to be abbreviated and +displayed in a parseable format. This flag can be used in automated +scripts that check how Crossroads is doing; e.g., in health checking +scripts. When <code>-t</code> is used, the format of the status reporter is as +follows: +<p> +<ul> + <li> Service health is reported on one line per service. + <li> The first string on the line is the service name. + <li> After this, a series follows of <em>backendname=state</em>, + where the back end name is the configured name of the back + end, and where state is e.g. <code>available</code>, <code>DOWN</code>, + <code>UNAVAILABLE</code>, <code>WAKING</code>. All statuses that cause + Crossroads not to use the back end are in caps. The series is + repeated for all back ends of the given service.</ul> +<p> +<a name="l12"></a> +<h3>3.3: Logging-related options</h3> <p> Two 'flags' of Crossroads are specifically logging-related. This section elaborates on these flags. @@ -515,8 +548,8 @@ That instructs <code>syslogd</code> to send <code>LOG_LOCAL7</code> requests to <li> Finally, monitor <code>/var/log/crossroads.log</code> for Crossroads' messages.</ul> <p> -<a name="l12"></a> -<h3>3.3: Reloading Configurations</h3> +<a name="l13"></a> +<h3>3.4: Reloading Configurations</h3> <p> Crossroads doesn't support the reloading of a configuration while running (such as other programs, e.g. Apache do). There are various @@ -526,7 +559,7 @@ However, external lists of allowed or denied IP addresses can be reloaded by sending a signal -1 (<code>SIGHUP</code>) to Crossroads. See section <a href="crossroads.html#servicedef">4.2</a> for the details. <p> -<a name="l13"></a> +<a name="l14"></a> <h2>4: The configuration</h2> <a name="config"></a>The configuration that crossroads uses is normally stored in the file <code>/etc/crossroads.conf</code>. This location can be overruled using the @@ -535,13 +568,13 @@ command line flag <code>-c</code>. This section explains the syntax of the configuration file, and what all settings do. <p> -<a name="l14"></a> +<a name="l15"></a> <h3>4.1: General language elements</h3> <p> This section describes the general elements of the crossroads configuration language. <p> -<a name="l15"></a> +<a name="l16"></a> <strong>4.1.1: Empty lines and comments</strong> <p> Empty lines are of course allowed in the @@ -559,7 +592,7 @@ best'.&nbsp;(I favor C or C++ comment. My favorite editor <em>emacs</em> can be put in <code>cmode</code> and nicely highlight what's comment and what's not. And as a bonus it will auto-indent the configuration!) <p> -<a name="l16"></a> +<a name="l17"></a> <strong>4.1.2: Keywords, numbers, identifiers, generic strings</strong> <p> In a configuration file, statements are identified by <em>keywords</em>, @@ -594,7 +627,7 @@ Finally, an argument can be a 'boolean' value. Crossroads knows <code>true</code>, <code>yes</code> and <code>on</code> all mean the same and can be used interchangeably; as can the keywords <code>false</code>, <code>no</code> and <code>off</code>. <p> -<a name="l17"></a> +<a name="l18"></a> <h3>4.2: Service definitions</h3> <a name="servicedef"></a> <p> Service definitions are blocks in the configuration file that @@ -618,7 +651,7 @@ identifying names differ. The following list shows possible statements. Each statement must end with a semicolon, except for the <code>backend</code> statement, which has is own block (more on this later). <p> -<a name="conf/type"></a><a name="l18"></a> +<a name="conf/type"></a><a name="l19"></a> <strong>4.2.1: type - Defining the service type</strong> <a name="conftype - Defining the service type"></a> <dl> <p><dt><strong>Description:</strong><dd> The <code>type</code> statement defines how crossroads handles the stated @@ -638,7 +671,7 @@ Unless you really need such special features, use the type <code>any</code> (the <p><dt><strong>Default:</strong><dd> <code>any</code> </dl> <p> -<a name="conf/port"></a><a name="l19"></a> +<a name="conf/port"></a><a name="l20"></a> <strong>4.2.2: port - Specifying the listen port</strong> <a name="confport - Specifying the listen port"></a> <dl> <p><dt><strong>Description:</strong><dd> The <code>port</code> statement defines to which TCP port a service @@ -648,7 +681,7 @@ Unless you really need such special features, use the type <code>any</code> (the <p><dt><strong>Default:</strong><dd> There is no default. This is a required setting. </dl> <p> -<a name="conf/bindto"></a><a name="l20"></a> +<a name="conf/bindto"></a><a name="l21"></a> <strong>4.2.3: bindto - Binding to a specific IP address</strong> <a name="confbindto - Binding to a specific IP address"></a> <dl> <p><dt><strong>Description:</strong><dd> The <code>bindto</code> statement is used in situations where crossroads @@ -662,7 +695,7 @@ Unless you really need such special features, use the type <code>any</code> (the <p><dt><strong>Default:</strong><dd> <code>any</code> </dl> <p> -<a name="conf/verbose"></a><a name="l21"></a> +<a name="conf/verbose"></a><a name="l22"></a> <strong>4.2.4: verbosity - Controlling debug output</strong> <a name="confverbosity - Controlling debug output"></a> <dl> <p><dt><strong>Description:</strong><dd> Verbosity statements come in two forms: <code>verbosity on</code> or @@ -679,7 +712,7 @@ Unless you really need such special features, use the type <code>any</code> (the <p><dt><strong>Default:</strong><dd> <code>off</code> </dl> <p> -<a name="conf/dispatchmode"></a><a name="l22"></a> +<a name="conf/dispatchmode"></a><a name="l23"></a> <strong>4.2.5: dispatchmode - How are back ends selected</strong> <a name="confdispatchmode - How are back ends selected"></a> <dl> <p><dt><strong>Description:</strong><dd> The dispatch mode controls how crossroads selects a back end from @@ -742,7 +775,7 @@ The modifier <code>over</code> <em>connections</em> is optional. (The square custom-made dispatch modes are needed. <p> The dispatch mode that uses an <code>externalhandler</code> is - discussed separately in section <a href="crossroads.html#externalhandler">5.2</a>.</ul> + discussed separately in section <a href="crossroads.html#externalhandler">5.3</a>.</ul> <p> The selection algorithm is only used when clients are serviced that aren't part of a sticky HTTP session. This is the case during: @@ -766,7 +799,7 @@ Your 'right' dispatch mode will depend on the type of service. Given <p><dt><strong>Default:</strong><dd> <code>roundrobin</code> </dl> <p> -<a name="conf/revivinginterval"></a><a name="l23"></a> +<a name="conf/revivinginterval"></a><a name="l24"></a> <strong>4.2.6: revivinginterval - Back end wakeup calls</strong> <a name="confrevivinginterval - Back end wakeup calls"></a> <dl> <p><dt><strong>Description:</strong><dd> A reviving interval definition is needed when crossroads @@ -788,7 +821,7 @@ An example of the definition is <code>revivinginterval 10</code>. When this <p><dt><strong>Default:</strong><dd> 0 (no wakeup calls) </dl> <p> -<a name="conf/maxconnections"></a><a name="l24"></a> +<a name="conf/maxconnections"></a><a name="l25"></a> <strong>4.2.7: maxconnections - Limiting concurrent clients at service level</strong> <a name="confmaxconnections - Limiting concurrent clients at service level"></a> <dl> <p><dt><strong>Description:</strong><dd> The maximum number of connections is specified using @@ -804,7 +837,7 @@ An example of the definition is <code>revivinginterval 10</code>. When this <p><dt><strong>Default:</strong><dd> 0, meaning that all connections will be accepted. </dl> <p> -<a name="conf/backlog"></a><a name="l25"></a> +<a name="conf/backlog"></a><a name="l26"></a> <strong>4.2.8: backlog - The TCP Back Log size</strong> <a name="confbacklog - The TCP Back Log size"></a> <dl> <p><dt><strong>Description:</strong><dd> The TCP back log size is a number that controls how many @@ -820,7 +853,7 @@ An example of the definition is <code>revivinginterval 10</code>. When this value for socket back log size. </dl> <p> -<a name="conf/shmkey"></a><a name="l26"></a> +<a name="conf/shmkey"></a><a name="l27"></a> <strong>4.2.9: shmkey - Shared Memory Access</strong> <a name="confshmkey - Shared Memory Access"></a> <dl> <p><dt><strong>Description:</strong><dd> Different Crossroads @@ -841,7 +874,7 @@ The actual key value doesn't matter much, as long as it's unique own key, based on TCP port and a magic number. </dl> <p> -<a name="conf/allow"></a><a name="l27"></a> +<a name="conf/allow"></a><a name="l28"></a> <strong>4.2.10: allow* and deny* - Allowing or denying connections</strong> <a name="confallow* and deny* - Allowing or denying connections"></a> <dl> <p><dt><strong>Description:</strong><dd> Crossroads can allow or deny @@ -910,7 +943,7 @@ This is probably best explained by a few examples: <p><dt><strong>Default:</strong><dd> In absence of these statements, all client IP's are accepted. </dl> <p> -<a name="conf/useraccount"></a><a name="l28"></a> +<a name="conf/useraccount"></a><a name="l29"></a> <strong>4.2.11: useraccount - Limiting the effective ID of external processes</strong> <a name="confuseraccount - Limiting the effective ID of external processes"></a> <dl> <p><dt><strong>Description:</strong><dd> Using the directive <code>useraccount</code>, the effective user and group @@ -928,7 +961,7 @@ This is probably best explained by a few examples: ID that was in effect when Crossroads was started. </dl> <p> -<a name="l29"></a> +<a name="l30"></a> <h3>4.3: Backend definitions</h3> <p> Inside the service definitions as are described in the previous @@ -964,7 +997,7 @@ Crossroads treats the network traffic as a stream of HTTP messages; i.e., when the service is declared with <code>type http</code>. Incase of <code>type any</code>, the HTTP-specific directives have no effect. <p> -<a name="conf/server.yo"></a><a name="l30"></a> +<a name="conf/server.yo"></a><a name="l31"></a> <strong>4.3.1: server - Specifying the back end address</strong> <a name="confserver - Specifying the back end address"></a> <dl> <p><dt><strong>Description:</strong><dd> Each back end must be identified by the network name @@ -978,7 +1011,7 @@ i.e., when the service is declared with <code>type http</code>. Incase of <p><dt><strong>Default:</strong><dd> There is no default. This is a required setting. </dl> <p> -<a name="conf/verbose-backend.yo"></a><a name="l31"></a> +<a name="conf/verbose-backend.yo"></a><a name="l32"></a> <strong>4.3.2: verbosity - Controlling verbosity at the back end level</strong> <a name="confverbosity - Controlling verbosity at the back end level"></a> <dl> <p><dt><strong>Description:</strong><dd> Similar to <code>service</code> specifications, a @@ -992,7 +1025,7 @@ i.e., when the service is declared with <code>type http</code>. Incase of <p><dt><strong>Default:</strong><dd> <code>off</code> </dl> <p> -<a name="conf/retries.yo"></a><a name="l32"></a> +<a name="conf/retries.yo"></a><a name="l33"></a> <strong>4.3.3: retries - Specifying allowed failures</strong> <a name="confretries - Specifying allowed failures"></a> <dl> <p><dt><strong>Description:</strong><dd> Back ends that are 'flaky' or on a less reliable network can be @@ -1007,7 +1040,7 @@ i.e., when the service is declared with <code>type http</code>. Incase of connection. </dl> <p> -<a name="conf/weight"></a><a name="l33"></a> +<a name="conf/weight"></a><a name="l34"></a> <strong>4.3.4: weight - When a back end is more equal than others</strong> <a name="confweight - When a back end is more equal than others"></a> <dl> <p><dt><strong>Description:</strong><dd> To influence how backends are selected, a backend can specify its @@ -1026,7 +1059,7 @@ The weighing mechanism only applies to the dispatch modes <p><dt><strong>Default:</strong><dd> 1; all back ends have equal weight. </dl> <p> -<a name="conf/decay"></a><a name="l34"></a> +<a name="conf/decay"></a><a name="l35"></a> <strong>4.3.5: decay - Levelling out activity of a back end</strong> <a name="confdecay - Levelling out activity of a back end"></a> <dl> <p><dt><strong>Description:</strong><dd> To make sure that a 'spike' of activity doesn't @@ -1048,7 +1081,7 @@ This means that when a given back end is hit, then its usage data <p><dt><strong>Default:</strong><dd> 0, meaning that no decay is applied to usage statistics. </dl> <p> -<a name="conf/onhooks"></a><a name="l35"></a> +<a name="conf/onhooks"></a><a name="l36"></a> <strong>4.3.6: onstart, onend, onfail - Action Hooks</strong> <a name="confonstart, onend, onfail - Action Hooks"></a> <dl> <p><dt><strong>Description:</strong><dd> The three directives <code>onstart</code>, <code>onend</code> and <code>onfail</code> can be @@ -1100,7 +1133,7 @@ The format is always <code>on</code><em>type</em> <em>command</em>. The <em>comm connection, success or failure of a back end. </dl> <p> -<a name="conf/trafficlog"></a><a name="l36"></a> +<a name="conf/trafficlog"></a><a name="l37"></a> <strong>4.3.7: trafficlog and throughputlog - Debugging and Performance Aids</strong> <a name="conftrafficlog and throughputlog - Debugging and Performance Aids"></a> <dl> <p><dt><strong>Description:</strong><dd> Two directives are available @@ -1120,7 +1153,7 @@ The <code>throughputlog</code> statement writes shorthand transmissions to <p><dt><strong>Default:</strong><dd> none </dl> <p> -<a name="conf/stickycookie"></a><a name="l37"></a> +<a name="conf/stickycookie"></a><a name="l38"></a> <strong>4.3.8: stickycookie - Back end selection with an HTTP cookie</strong> <a name="confstickycookie - Back end selection with an HTTP cookie"></a> <dl> <p><dt><strong>Description:</strong><dd> The directive <code>stickycookie</code> <em>value</em> @@ -1160,7 +1193,7 @@ There are basically to provide such cookies to a browser. First, a <p><dt><strong>Default:</strong><dd> There is no default. </dl> <p> -<a name="conf/addclientheader"></a><a name="l38"></a> +<a name="conf/addclientheader"></a><a name="l39"></a> <strong>4.3.9: HTTP Header Modification Directives</strong> <a name="confHTTP Header Modification Directives"></a> <dl> <p><dt><strong>Description:</strong><dd> Crossroads understands the following @@ -1336,22 +1369,21 @@ service ... { <p><dt><strong>Default:</strong><dd> There is no default. </dl> <p> -<a name="l39"></a> -<h2>5: Tips, Tricks and Remarks</h2> +<a name="l40"></a> +<h2>5: Tips, Tricks and Random Remarks</h2> <a name="tips"></a>The following sections elaborate on the directives as described in section <a href="crossroads.html#config">4</a> to illustrate how crossroads works and to help you achieve the "optimal" balancing configuration. <p> -<a name="l40"></a> -<h3>5.1: How back ends are selected in load balancing</h3><a name="howselected"></a> -<p> -In order to tune your load balancing, you'll need to understand how +<a name="l41"></a> +<h3>5.1: How back ends are selected in load balancing</h3> <a name="howselected"></a> +<a name="tips/howselected"></a>In order to tune your load balancing, you'll need to understand how crossroads computes usage, how weighing works, and so on. In this section we'll focus on the dispatching modes <code>bysize</code>, <code>byduration</code> and <code>byconnections</code> only. The other dispatching types are self-explanatory. <p> -<a name="l41"></a> +<a name="l42"></a> <strong>5.1.1: Bysize, byduration or byconnections?</strong> <p> As stated before, crossroads doesn't know 'what a service does' and @@ -1401,7 +1433,7 @@ E.g., consider a database connection. What's <p> </ul> <p> -<a name="l42"></a> +<a name="l43"></a> <strong>5.1.2: Averaging size and duration</strong> <p> The configuration statement <code>dispatchmode bysize</code> or <code>byduration</code> @@ -1422,7 +1454,7 @@ In contrast, when e.g. <code>over 3</code> is in effect, then a sudden load does show up -- because it highly contributes to the average of three connections. <p> -<a name="l43"></a> +<a name="l44"></a> <strong>5.1.3: Specifying decays</strong> <p> Decays are also only relevant when crossroads computes the 'next best @@ -1476,7 +1508,7 @@ service soap { </pre> <p> -<a name="l44"></a> +<a name="l45"></a> <strong>5.1.4: Adjusting the weights</strong> <p> The back end modifier <code>weight</code> is useful in situations where your @@ -1530,10 +1562,9 @@ both A and B crash). Note also that A's usage data decay much faster than B's and C's: we're assuming that this big server recovers quicker than its smaller siblings. <p> -<a name="l45"></a> -<strong>5.1.5: Throttling the number of concurrent connections</strong> -<p> -If you suspect that your service may occasionally receive 'spikes' of +<a name="l46"></a> +<h3>5.2: Throttling the number of concurrent connections</h3> +<a name="tips/throttling"></a>If you suspect that your service may occasionally receive 'spikes' of activity&nbsp;(which you should always assume), then it might be a good idea to protect your service by specifying a maximum number of concurrent connections. This protection can be specified on two levels: @@ -1560,17 +1591,15 @@ too much, a situation may occur where that back end is about to be hit. A <code>maxconnections</code> statement on the level of that back may then protect it. <p> -<a name="l46"></a> -<h3>5.2: Using an external program to dispatch</h3> -<a name="externalhandler"></a> -<p> -As mentioned before, Crossroads supports several built-in dispatch +<a name="l47"></a> +<h3>5.3: Using an external program to dispatch</h3> <a name="externalhandler"></a> +<a name="tips/externalhandler"></a>As mentioned before, Crossroads supports several built-in dispatch modes. However, you are always free to hook-in your own dispatch mode that determines the next back end using your own specific algorithm. This section explains how to do it. <p> -<a name="l47"></a> -<strong>5.2.1: Configuring the external handler</strong> +<a name="l48"></a> +<strong>5.3.1: Configuring the external handler</strong> <p> First, the <code>dispatchmode</code> statement needs to inform Crossroads that an external program will do the job. The syntax is: <code>dispatchmode @@ -1608,8 +1637,8 @@ Note that the format specifiers such as <code>%b</code> don't make sense in the phase in which an external handler is called, since there is no current back end yet (the job of the handler is to supply one). <p> -<a name="l48"></a> -<strong>5.2.2: Writing the external handler</strong> +<a name="l49"></a> +<strong>5.3.2: Writing the external handler</strong> <p> The external handler is activated using the arguments that are specified in <code>/etc/crossroads.conf</code>. The external handler can do @@ -1617,8 +1646,8 @@ whatever it wants, but ultimately, it must write a back end name on its <em>stdout</em>. Crossroads reads this, and if the back end is available, uses that back end for the connection. <p> -<a name="l49"></a> -<strong>5.2.3: Examples of external handlers</strong> +<a name="l50"></a> +<strong>5.3.3: Examples of external handlers</strong> <p> This section shows some examples of Crossroads configurations vs. external handlers. The sample handlers that are shown here, are @@ -2046,10 +2075,9 @@ if ($action eq 'dispatch') { </pre> <p> -<a name="l50"></a> -<h3>5.3: TCP Session Stickiness</h3> -<p> -If you need to make sure that a client that once gets dispatched to a +<a name="l51"></a> +<h3>5.4: TCP Session Stickiness</h3> +<a name="tips/tcpstickiness"></a>If you need to make sure that a client that once gets dispatched to a given back end keeps re-visiting the back end, then Crossroads offers the dispatch mode <code>byclientip</code>. This mode will only work when each client is seen by Crossroads with its own specific IP address; ie., @@ -2057,7 +2085,7 @@ this method won't work when clients reach Crossroads through a masquerading firewall (in which case all clients would be seen as having the firewall's IP address). <p> -The <code>dispatchmode roundrobin</code> works as follows: +The <code>dispatchmode byclientip</code> works as follows: <p> <ul> <li> The client's IP address is taken in its string @@ -2072,17 +2100,16 @@ If the preferred back end is unavailable, then the action that Crossroads takes is to dispatch as if <code>byconnections</code>: of the available back ends, the one with the least connections is taken. <p> -<a name="l51"></a> -<h3>5.4: HTTP Session Stickiness</h3> -<p> -This section focuses on HTTP session stickiness. This term refers to +<a name="l52"></a> +<h3>5.5: HTTP Session Stickiness</h3> +<a name="tips/httpstickiness"></a>This section focuses on HTTP session stickiness. This term refers to the ability of a balancer to route a conversation between browser and a backend farm with webservers always to the same back end. In other words: once a back end is selected by the balancer, it will remain the back end of choice, even for subsequent connections. <p> -<a name="l52"></a> -<strong>5.4.1: Don't use stickiness!</strong> +<a name="l53"></a> +<strong>5.5.1: Don't use stickiness!</strong> <p> The rule of thumb as far as the balancer is concerned, is: <strong>Do not use HTTP session stickiness unless you really have to.</strong> Enabling @@ -2113,8 +2140,8 @@ that all PHP applications have access to these data. Application servers such as Websphere can be configured to replicate session data between nodes. <p> -<a name="l53"></a> -<strong>5.4.2: But if you must..</strong> +<a name="l54"></a> +<strong>5.5.2: But if you must..</strong> <p> If you really need stickiness, think first whether you might use TCP stickiness (using the client's IP address to dispatch). If you can, @@ -2191,10 +2218,9 @@ Note how the cookie names and values in the directives <code>stickycookie</code> and <code>addclientheader</code> match. That is obviously a prerequisite for stickiness. <p> -<a name="l54"></a> -<h3>5.5: Passing the client's IP address</h3> -<p> -Since Crossroads just shuttles bytes to and fro, meta-information of +<a name="l55"></a> +<h3>5.6: Passing the client's IP address</h3> +<a name="tips/clientip"></a>Since Crossroads just shuttles bytes to and fro, meta-information of network connections is lost. As far as the back ends are concerned, their connections originate at the Crossroads junction. For example, standard Apache access logs will show the IP address of @@ -2219,8 +2245,8 @@ header: <code>X-Real-IP</code>, holding the client's IP address. performance will be hampered -- all passing messages will have to be unpacked and analyzed. <p> -<a name="l55"></a> -<strong>5.5.1: Sample Crossroads configuration</strong> +<a name="l56"></a> +<strong>5.6.1: Sample Crossroads configuration</strong> <p> The below sample configuration shows two HTTP back ends that receive the client's IP address: @@ -2246,8 +2272,8 @@ service www { </pre> <p> -<a name="l56"></a> -<strong>5.5.2: Sample Apache configuration</strong> +<a name="l57"></a> +<strong>5.6.2: Sample Apache configuration</strong> <p> The method by which each back end analyzes the header <code>X-Real-IP</code> will obviously be different per server implementations. However, a @@ -2278,10 +2304,9 @@ LogFormat "%{X-Real-IP}i %l %u %t %D \"%r\" %&gt;s %b" common </pre> <p> -<a name="l57"></a> -<h3>5.6: Debugging network traffic</h3> -<p> -Incase the traffic between +<a name="l58"></a> +<h3>5.7: Debugging network traffic</h3> +<a name="tips/debugging"></a> Incase the traffic between client and backend must be debugged, the statement <code>trafficlog</code> <em>filename</em> can be issued. This causes the traffic to be dumped in hexadecimal @@ -2402,11 +2427,10 @@ Summarizing, the throughput times of a client-back end connection analyze the output and to compute round trip times. Such scripts are not (yet) included in Crossroads. <p> -<a name="l58"></a> -<h3>5.7: Limiting Access to Crossroads by Client IP Address</h3> -<p> <a name="l59"></a> -<strong>5.7.1: General Examples</strong> +<h3>5.8: IP filtering: Limiting Access by Client IP Address</h3> +<a name="tips/ipfiltering"></a><a name="l60"></a> +<strong>5.8.1: General Examples</strong> <p> The directives <code>allowfrom</code>, <code>denyfrom</code>, <code>allowfile</code> and <code>denyfile</code> can be used to instruct Crossroads to specifically allow @@ -2442,8 +2466,8 @@ with 192.168.1. The specifier <code>192.168.1/24</code> states that there are three network bytes (192, 168 and 1), and 24 bits (or 3 bytes) are relevant; so that the fourth network byte doesn't matter. <p> -<a name="l60"></a> -<strong>5.7.2: Using External Files</strong> +<a name="l61"></a> +<strong>5.8.2: Using External Files</strong> <p> The directives <code>allowfile</code> and <code>denyfile</code> allow you to specify IP addresses in external files. The Crossroads configuration states @@ -2474,8 +2498,8 @@ is running, you may edit <code>/tmp/allow.txt</code>, and then issue <code>killa -1 crossroads</code>. The new contents of <code>/tmp/allow.txt</code> will be reloaded. <p> -<a name="l61"></a> -<strong>5.7.3: Mixing Directives</strong> +<a name="l62"></a> +<strong>5.8.3: Mixing Directives</strong> <p> Crossroads allows to mix all directives in one service description. However, some mixes are less meaningful than others. It's @@ -2513,8 +2537,7 @@ denyfrom 192.168.1/24 This will first of all deny access to all IP addresses that start with 192.168.1. So the rule that allows 192.168.1.100 won't ever be effective. The net result will be that access - will be granted to 127.0.0.1, and IP addresses that don't - match 192.168.1/24. + will be granted to 127.0.0.1. <p> <li> Blacklisting or whitelisting can be left out. A list is considered empty when no appropriate directives @@ -2536,20 +2559,17 @@ There is a technical reason for this. Once Crossroads whitelist is cleared (thereby removing the entries 127.0.0.1 and 192.168.1/24), and new entries are reloaded from the file. The net result is that the <code>allowfrom</code> specification - is overruled. + is overruled.</ul> <p> -Crossroads doesn't check for such configurations, which are - syntactially correct, but make no semantic sense.</ul> -<p> -<a name="l62"></a> -<h3>5.8: Configuration examples</h3> -<p> -As a general hint, use <code>crossroads sampleconf</code> to view the most -up-to-date examples of configurations. The description below shows a -few examples too. +Crossroads only performs syntactic checking of the configuration. Some +of the above samples are syntactically correct, but make no semantic +sense: Crossroads doesn't warn for such situations. <p> <a name="l63"></a> -<strong>5.8.1: A load balancer for three webserver back ends</strong> +<h3>5.9: Configuration examples</h3> +<a name="tips/examples"></a> +<a name="l64"></a> +<strong>5.9.1: A load balancer for three webserver back ends</strong> <p> The following configuration example binds crossroads to port 80 of the current server, and distributes the load over three back ends. This @@ -2677,8 +2697,8 @@ service www { </pre> <p> -<a name="l64"></a> -<strong>5.8.2: An HTTP forwarder when travelling</strong> +<a name="l65"></a> +<strong>5.9.2: An HTTP forwarder when travelling</strong> <p> As another example, here's my <code>crossroads.conf</code> that I use on my Unix laptop. The problem that I face is that I need many HTTP proxy @@ -2766,8 +2786,8 @@ and <code>LocalSquid</code> are both active, then <code>crossroads tell httpprox sshtunnel down</code> will 'take down' the back end <code>SshTunnel</code> -- and will automatically cause crossroads to switch to <code>LocalSquid</code>. <p> -<a name="l65"></a> -<strong>5.8.3: SSH login with enforced idle logout</strong> +<a name="l66"></a> +<strong>5.9.3: SSH login with enforced idle logout</strong> <p> The following example shows how crossroads 'throttles' SSH logins. Connections are accepted on port @@ -2792,13 +2812,95 @@ service Ssh { </pre> <p> -<a name="l66"></a> +<a name="l67"></a> +<h3>5.10: Linux and ip_conntrack_max</h3> +<a name="tips/ipconntrackmax"></a>The kernel value of <code>ip_conntrack_max</code> is important for routers and +balancers under Linux. Basically it's the maximum number of tracked +connections. Felix A.W.O. describes the following situation: +<p> +<ul> + <li> Crossroads seems to mark back ends as unavailable, while + in fact nothing is afoot. + <li> This happens under heavy load. + <li> In <code>/var/log/messages</code> one may see the message: + <code>kernel: ip_conntrack: table full, dropping packet</code>.</ul> +<p> +The reason for Crossroad's behavior is that the kernel refuses to +build up a requested network connection. For Crossroads, this looks +just as a non-responding back end. Crossroads therefore marks the back +end as unavailable. +<p> +The solution is as follows: +<p> +<ul> + <li> Try <code>cat /proc/sys/net/ipv4/ip_conntrack_max</code> to see + the current value. + <li> Add something to the shown value (e.g., multiply by two), + and inform + the kernel of the new value, using <code>echo</code> (new-value) <code>&gt; + /proc/sys/net/ipv4/ip_conntrack_max</code> + <li> Make sure that the same step occurs somewhere in your + boot sequence as well, or that the new valueit is stated in a + configuration + file such as <code>/etc/sysctl.conf</code>.</ul> +<p> +The value for <em>new-value</em> is something that you'll have to figure +out yourself. Note however that each count will cause the kernel to +reserve 350 bytes. So if you set <code>ip_conntrack_max</code> to 100.000, then +you're already taking 33.3Mb off the total available memory. +<p> +<a name="l68"></a> +<h3>5.11: Marking back ends as bad after more than one try</h3> +<a name="tips/retries"></a>Crossroads allows you to specify on a per-back end basis how many +retries are needed before a back end is considered unavailable. The +default is just one, meaning that after one failed connection, +Crossroads will mark a back end as unavailable (the back end may be +'revived', if you use <code>revivinginterval</code>). +<p> +Increasing the number is specified using the keyword <code>retries</code>. The +following configuration defines two back ends; the one on the IP +address 5.6.7.8 is somehow 'flaky', and Crossroads should try +connecting 3 times before crossing it off: +<p> +<pre> +service www { + port 80; + backend plugh { + server 1.2.3.4:80; + } + backend xyzzy { + server 5.6.7.8:80; + retries 3; + } +} +</pre> + +<p> +There may be several reasons for increasing the retries number: +<p> +<ul> + <li> The network connections to the server may spuriously + hamper, but such rare errors don't mean that the back end server is + down. +<p> +<li> The back end server is a 'slow starter' and can't handle spikes + very well. E.g., it may be a webserver which starts with only + one daemon; extra capacity is added as network connections + arrive, but adding capacity take a little time.</ul> +<p> +Whatever the reason, the keyword <code>retries</code> might be of help +here. This keyword should however be used carefully: Crossroads will +retry connecting with a small one-second delay in between. A high +<code>retries</code> number means also lots of one-second delays, in which time +a client is kept waiting. +<p> +<a name="l69"></a> <h2>6: Benchmarking</h2> <a name="benchmarking"></a>This section shows how crossroads affects the transmitting of HTML data when used as an intermediate 'station' through which all data travels. <p> -<a name="l67"></a> +<a name="l70"></a> <h3>6.1: Benchmark 1: Accessing a proxy via crossroads or directly</h3> <p> The benchmark was run on a system where the following was varied: @@ -2826,7 +2928,7 @@ service HttpProxy { </pre> <p> -<a name="l68"></a> +<a name="l71"></a> <strong>6.1.1: Results</strong> <p> The results of this test are that crossroads causes a negligible @@ -2849,7 +2951,7 @@ sys 0m0.230s </pre> <p> -<a name="l69"></a> +<a name="l72"></a> <strong>6.1.2: Discussion</strong> <p> The above shown results are quite favorable to crossroads. However, @@ -2881,7 +2983,7 @@ seldom in the real world: back end). Again, this processing time will weigh much heavier than the multiple read/writes.</ul> <p> -<a name="l70"></a> +<a name="l73"></a> <h3>6.2: Benchmark 2: Crossroads versus Linux Virtual Server (LVS)</h3> <p> LVS is a kernel-based balancer that acts like a masquerading @@ -2895,7 +2997,7 @@ LVS isn't aware of downtime of back ends (unless one implements an external heartbeat). Also, crossroads offers more complex balancing than LVS. <p> -<a name="l71"></a> +<a name="l74"></a> <strong>6.2.1: Environment</strong> <p> On the balancer, LVS was run on port 80, its forwarding set up for two @@ -2926,7 +3028,7 @@ service http { </pre> <p> -<a name="l72"></a> +<a name="l75"></a> <strong>6.2.2: Tests and results</strong> <p> In the first test, ports 80 and 81 on the balancer were 'bombed' with @@ -3005,9 +3107,9 @@ are shown in the below table: Again, the results show that crossroads performs just as effectively as LVS, even with large data chunks! <p> -<a name="l73"></a> +<a name="l76"></a> <h2>7: Compiling and Installing</h2> -<a name="compiling"></a><a name="l74"></a> +<a name="compiling"></a><a name="l77"></a> <h3>7.1: Prerequisites</h3> <p> The creation of crossroads requires: @@ -3024,7 +3126,7 @@ The creation of crossroads requires: Basically a Linux or Apple MacOSX box will do nicely. To compile and install crossroads, follow these steps. <p> -<a name="l75"></a> +<a name="l78"></a> <h3>7.2: Compiling and installing</h3> <p> <ul> @@ -3082,7 +3184,7 @@ crossroads, follow these steps. <p> </ul> <p> -<a name="l76"></a> +<a name="l79"></a> <h3>7.3: Configuring crossroads</h3> <p> Now that the binary is available on your system, you need to create a @@ -3131,13 +3233,13 @@ which crossroads daemons are running. Finally, the tailing of <code>/var/log/messages</code> shows what's going on -- especially if you have <code>verbosity true</code> statements in the configuration. <p> -<a name="l77"></a> +<a name="l80"></a> <h3>7.4: A boot script</h3> <p> Finally, you may want to create a boot-time startup script. The exact procedure depends on the used Unix flavor. <p> -<a name="l78"></a> +<a name="l81"></a> <strong>7.4.1: SysV Style Startup</strong> <p> On SysV style systems, there's a startup script directory @@ -3179,7 +3281,7 @@ If your runlevel is 5, then the right <code>cd</code> command is to <code>/etc/rc.d/rc5.d</code>. Alternatively, you can create the symlinks in both runlevel directories.</ul> <p> -<a name="l79"></a> +<a name="l82"></a> <strong>7.4.2: BSD Style Startup</strong> <p> On BSD style systems, daemons are booted directly from <code>/etc/rc</code> and diff --git a/doc/crossroads.man b/doc/crossroads.man @@ -1,6 +1,6 @@ -.TH "Crossroads 1\&.37" "2005, 2006, ff\&." +.TH "Crossroads 1\&.38" "2005, 2006, ff\&." .PP -.SH "Crossroads 1\&.37" +.SH "Crossroads 1\&.38" .SH "Karel Kubat" .SH "e-tunity" .SH "2005, 2006, ff\&." @@ -384,7 +384,40 @@ configuration \f(CW/etc/crossroads\&.conf\fP\&. .PP -.SH "3\&.2: Logging-related options" +.SH "3\&.2: Status Reporting" + +.PP +The command \f(CWcrossroads status\fP shows a verbose human-readable +report of how Crossroads is doing\&. When many services are configured, +this can be a somewhat lengthy output\&. If you\&'re interested in the +overview of only one service, you can use \f(CWcrossroads status\fP +\fIservicename\fP, in which case the report will only be shown for the +stated service\&. +.PP +Similarly, if you\&'re interested only in the status of a given back end +of a given service, use \f(CWcrossroads service\fP \fIservicename\fP +\fIbackendname\fP\&. +.PP +The flag \f(CW-t\fP causes the status overview to be abbreviated and +displayed in a parseable format\&. This flag can be used in automated +scripts that check how Crossroads is doing; e\&.g\&., in health checking +scripts\&. When \f(CW-t\fP is used, the format of the status reporter is as +follows: +.PP +.IP o +Service health is reported on one line per service\&. +.IP o +The first string on the line is the service name\&. +.IP o +After this, a series follows of \fIbackendname=state\fP, +where the back end name is the configured name of the back +end, and where state is e\&.g\&. \f(CWavailable\fP, \f(CWDOWN\fP, +\f(CWUNAVAILABLE\fP, \f(CWWAKING\fP\&. All statuses that cause +Crossroads not to use the back end are in caps\&. The series is +repeated for all back ends of the given service\&. +.PP + +.SH "3\&.3: Logging-related options" .PP Two \&'flags\&' of Crossroads are specifically logging-related\&. This @@ -432,7 +465,7 @@ Finally, monitor \f(CW/var/log/crossroads\&.log\fP for Crossroads\&' messages\&. .PP -.SH "3\&.3: Reloading Configurations" +.SH "3\&.4: Reloading Configurations" .PP Crossroads doesn\&'t support the reloading of a configuration while @@ -1359,7 +1392,7 @@ There is no default\&. .PP -.SH "5: Tips, Tricks and Remarks" +.SH "5: Tips, Tricks and Random Remarks" The following sections elaborate on the directives as described in section ?? to illustrate how crossroads works and to help you @@ -1367,8 +1400,6 @@ achieve the "optimal" balancing configuration\&. .PP .SH "5\&.1: How back ends are selected in load balancing" - -.PP In order to tune your load balancing, you\&'ll need to understand how crossroads computes usage, how weighing works, and so on\&. In this section we\&'ll focus on the dispatching modes \f(CWbysize\fP, \f(CWbyduration\fP @@ -1561,9 +1592,7 @@ than B\&'s and C\&'s: we\&'re assuming that this big server recovers quicker than its smaller siblings\&. .PP -.SH "5\&.1\&.5: Throttling the number of concurrent connections" - -.PP +.SH "5\&.2: Throttling the number of concurrent connections" If you suspect that your service may occasionally receive \&'spikes\&' of activity\e (which you should always assume), then it might be a good idea to protect your service by specifying a maximum number of @@ -1593,16 +1622,14 @@ hit\&. A \f(CWmaxconnections\fP statement on the level of that back may then protect it\&. .PP -.SH "5\&.2: Using an external program to dispatch" - -.PP +.SH "5\&.3: Using an external program to dispatch" As mentioned before, Crossroads supports several built-in dispatch modes\&. However, you are always free to hook-in your own dispatch mode that determines the next back end using your own specific algorithm\&. This section explains how to do it\&. .PP -.SH "5\&.2\&.1: Configuring the external handler" +.SH "5\&.3\&.1: Configuring the external handler" .PP First, the \f(CWdispatchmode\fP statement needs to inform Crossroads that @@ -1652,7 +1679,7 @@ phase in which an external handler is called, since there is no current back end yet (the job of the handler is to supply one)\&. .PP -.SH "5\&.2\&.2: Writing the external handler" +.SH "5\&.3\&.2: Writing the external handler" .PP The external handler is activated using the arguments that are @@ -1662,7 +1689,7 @@ its \fIstdout\fP\&. Crossroads reads this, and if the back end is available, uses that back end for the connection\&. .PP -.SH "5\&.2\&.3: Examples of external handlers" +.SH "5\&.3\&.3: Examples of external handlers" .PP This section shows some examples of Crossroads configurations @@ -2105,9 +2132,7 @@ if ($action eq \&'dispatch\&') { .PP -.SH "5\&.3: TCP Session Stickiness" - -.PP +.SH "5\&.4: TCP Session Stickiness" If you need to make sure that a client that once gets dispatched to a given back end keeps re-visiting the back end, then Crossroads offers the dispatch mode \f(CWbyclientip\fP\&. This mode will only work when each @@ -2116,7 +2141,7 @@ this method won\&'t work when clients reach Crossroads through a masquerading firewall (in which case all clients would be seen as having the firewall\&'s IP address)\&. .PP -The \f(CWdispatchmode roundrobin\fP works as follows: +The \f(CWdispatchmode byclientip\fP works as follows: .PP .IP o The client\&'s IP address is taken in its string @@ -2134,9 +2159,7 @@ Crossroads takes is to dispatch as if \f(CWbyconnections\fP: of the available back ends, the one with the least connections is taken\&. .PP -.SH "5\&.4: HTTP Session Stickiness" - -.PP +.SH "5\&.5: HTTP Session Stickiness" This section focuses on HTTP session stickiness\&. This term refers to the ability of a balancer to route a conversation between browser and a backend farm with webservers always to the same back end\&. In other @@ -2144,7 +2167,7 @@ words: once a back end is selected by the balancer, it will remain the back end of choice, even for subsequent connections\&. .PP -.SH "5\&.4\&.1: Don\&'t use stickiness!" +.SH "5\&.5\&.1: Don\&'t use stickiness!" .PP The rule of thumb as far as the balancer is concerned, is: \fBDo not @@ -2179,7 +2202,7 @@ servers such as Websphere can be configured to replicate session data between nodes\&. .PP -.SH "5\&.4\&.2: But if you must\&.\&." +.SH "5\&.5\&.2: But if you must\&.\&." .PP If you really need stickiness, think first whether you might use TCP @@ -2260,9 +2283,7 @@ Note how the cookie names and values in the directives prerequisite for stickiness\&. .PP -.SH "5\&.5: Passing the client\&'s IP address" - -.PP +.SH "5\&.6: Passing the client\&'s IP address" Since Crossroads just shuttles bytes to and fro, meta-information of network connections is lost\&. As far as the back ends are concerned, their connections originate at the Crossroads junction\&. @@ -2292,7 +2313,7 @@ performance will be hampered -- all passing messages will have to be unpacked and analyzed\&. .PP -.SH "5\&.5\&.1: Sample Crossroads configuration" +.SH "5\&.6\&.1: Sample Crossroads configuration" .PP The below sample configuration shows two HTTP back ends that receive @@ -2320,7 +2341,7 @@ service www { .PP -.SH "5\&.5\&.2: Sample Apache configuration" +.SH "5\&.6\&.2: Sample Apache configuration" .PP The method by which each back end analyzes the header \f(CWX-Real-IP\fP @@ -2353,9 +2374,7 @@ LogFormat "%{X-Real-IP}i %l %u %t %D \e"%r\e" %>s %b" common .PP -.SH "5\&.6: Debugging network traffic" - -.PP +.SH "5\&.7: Debugging network traffic" Incase the traffic between client and backend must be debugged, the statement \f(CWtrafficlog\fP \fIfilename\fP can @@ -2485,11 +2504,10 @@ analyze the output and to compute round trip times\&. Such scripts are not (yet) included in Crossroads\&. .PP -.SH "5\&.7: Limiting Access to Crossroads by Client IP Address" +.SH "5\&.8: IP filtering: Limiting Access by Client IP Address" -.PP -.SH "5\&.7\&.1: General Examples" +.SH "5\&.8\&.1: General Examples" .PP The directives \f(CWallowfrom\fP, \f(CWdenyfrom\fP, \f(CWallowfile\fP and @@ -2527,7 +2545,7 @@ three network bytes (192, 168 and 1), and 24 bits (or 3 bytes) are relevant; so that the fourth network byte doesn\&'t matter\&. .PP -.SH "5\&.7\&.2: Using External Files" +.SH "5\&.8\&.2: Using External Files" .PP The directives \f(CWallowfile\fP and \f(CWdenyfile\fP allow you to specify IP @@ -2561,7 +2579,7 @@ is running, you may edit \f(CW/tmp/allow\&.txt\fP, and then issue \f(CWkillall reloaded\&. .PP -.SH "5\&.7\&.3: Mixing Directives" +.SH "5\&.8\&.3: Mixing Directives" .PP Crossroads allows to mix all directives in one service @@ -2600,8 +2618,7 @@ denyfrom 192\&.168\&.1/24 This will first of all deny access to all IP addresses that start with 192\&.168\&.1\&. So the rule that allows 192\&.168\&.1\&.100 won\&'t ever be effective\&. The net result will be that access -will be granted to 127\&.0\&.0\&.1, and IP addresses that don\&'t -match 192\&.168\&.1/24\&. +will be granted to 127\&.0\&.0\&.1\&. .IP .IP o Blacklisting or whitelisting can be left out\&. @@ -2626,20 +2643,17 @@ whitelist is cleared (thereby removing the entries 127\&.0\&.0\&.1 and 192\&.168\&.1/24), and new entries are reloaded from the file\&. The net result is that the \f(CWallowfrom\fP specification is overruled\&. -.IP -Crossroads doesn\&'t check for such configurations, which are -syntactially correct, but make no semantic sense\&. +.PP +Crossroads only performs syntactic checking of the configuration\&. Some +of the above samples are syntactically correct, but make no semantic +sense: Crossroads doesn\&'t warn for such situations\&. .PP -.SH "5\&.8: Configuration examples" +.SH "5\&.9: Configuration examples" + -.PP -As a general hint, use \f(CWcrossroads sampleconf\fP to view the most -up-to-date examples of configurations\&. The description below shows a -few examples too\&. -.PP -.SH "5\&.8\&.1: A load balancer for three webserver back ends" +.SH "5\&.9\&.1: A load balancer for three webserver back ends" .PP The following configuration example binds crossroads to port 80 of the @@ -2769,7 +2783,7 @@ service www { .PP -.SH "5\&.8\&.2: An HTTP forwarder when travelling" +.SH "5\&.9\&.2: An HTTP forwarder when travelling" .PP As another example, here\&'s my \f(CWcrossroads\&.conf\fP that I use on my @@ -2864,7 +2878,7 @@ sshtunnel down\fP will \&'take down\&' the back end \f(CWSshTunnel\fP -- and will automatically cause crossroads to switch to \f(CWLocalSquid\fP\&. .PP -.SH "5\&.8\&.3: SSH login with enforced idle logout" +.SH "5\&.9\&.3: SSH login with enforced idle logout" .PP The following example shows how crossroads \&'throttles\&' SSH @@ -2891,6 +2905,93 @@ service Ssh { .PP +.SH "5\&.10: Linux and ip_conntrack_max" +The kernel value of \f(CWip_conntrack_max\fP is important for routers and +balancers under Linux\&. Basically it\&'s the maximum number of tracked +connections\&. Felix A\&.W\&.O\&. describes the following situation: +.PP +.IP o +Crossroads seems to mark back ends as unavailable, while +in fact nothing is afoot\&. +.IP o +This happens under heavy load\&. +.IP o +In \f(CW/var/log/messages\fP one may see the message: +\f(CWkernel: ip_conntrack: table full, dropping packet\fP\&. +.PP +The reason for Crossroad\&'s behavior is that the kernel refuses to +build up a requested network connection\&. For Crossroads, this looks +just as a non-responding back end\&. Crossroads therefore marks the back +end as unavailable\&. +.PP +The solution is as follows: +.PP +.IP o +Try \f(CWcat /proc/sys/net/ipv4/ip_conntrack_max\fP to see +the current value\&. +.IP o +Add something to the shown value (e\&.g\&., multiply by two), +and inform +the kernel of the new value, using \f(CWecho\fP (new-value) \f(CW> +/proc/sys/net/ipv4/ip_conntrack_max\fP +.IP o +Make sure that the same step occurs somewhere in your +boot sequence as well, or that the new valueit is stated in a +configuration +file such as \f(CW/etc/sysctl\&.conf\fP\&. +.PP +The value for \fInew-value\fP is something that you\&'ll have to figure +out yourself\&. Note however that each count will cause the kernel to +reserve 350 bytes\&. So if you set \f(CWip_conntrack_max\fP to 100\&.000, then +you\&'re already taking 33\&.3Mb off the total available memory\&. +.PP + +.SH "5\&.11: Marking back ends as bad after more than one try" +Crossroads allows you to specify on a per-back end basis how many +retries are needed before a back end is considered unavailable\&. The +default is just one, meaning that after one failed connection, +Crossroads will mark a back end as unavailable (the back end may be +\&'revived\&', if you use \f(CWrevivinginterval\fP)\&. +.PP +Increasing the number is specified using the keyword \f(CWretries\fP\&. The +following configuration defines two back ends; the one on the IP +address 5\&.6\&.7\&.8 is somehow \&'flaky\&', and Crossroads should try +connecting 3 times before crossing it off: +.PP +.nf +service www { + port 80; + backend plugh { + server 1\&.2\&.3\&.4:80; + } + backend xyzzy { + server 5\&.6\&.7\&.8:80; + retries 3; + } +} +.fi + +.PP +There may be several reasons for increasing the retries number: +.PP +.IP o +The network connections to the server may spuriously +hamper, but such rare errors don\&'t mean that the back end server is +down\&. +.IP +.IP o +The back end server is a \&'slow starter\&' and can\&'t handle spikes +very well\&. E\&.g\&., it may be a webserver which starts with only +one daemon; extra capacity is added as network connections +arrive, but adding capacity take a little time\&. +.PP +Whatever the reason, the keyword \f(CWretries\fP might be of help +here\&. This keyword should however be used carefully: Crossroads will +retry connecting with a small one-second delay in between\&. A high +\f(CWretries\fP number means also lots of one-second delays, in which time +a client is kept waiting\&. +.PP + .SH "6: Benchmarking" This section shows how crossroads affects the transmitting of HTML data when used as an intermediate \&'station\&' diff --git a/doc/crossroads.pdf b/doc/crossroads.pdf Binary files differ. diff --git a/doc/crossroads.yo b/doc/crossroads.yo @@ -27,7 +27,7 @@ includefile(using) sect(The configuration) includefile(config) -sect(Tips, Tricks and Remarks) +sect(Tips, Tricks and Random Remarks) includefile(tips) sect(Benchmarking) diff --git a/doc/tips.yo b/doc/tips.yo @@ -2,1370 +2,36 @@ The following sections elaborate on the directives as described in section ref(config) to illustrate how crossroads works and to help you achieve the "optimal" balancing configuration. -subsect(How back ends are selected in load balancing)label(howselected) +subsect(How back ends are selected in load balancing) label(howselected) +includefile(tips/howselected) -In order to tune your load balancing, you'll need to understand how -crossroads computes usage, how weighing works, and so on. In this -section we'll focus on the dispatching modes tt(bysize), tt(byduration) -and tt(byconnections) only. The other dispatching types are -self-explanatory. +subsect(Throttling the number of concurrent connections) +includefile(tips/throttling) - -subsubsect(Bysize, byduration or byconnections?) - -As stated before, crossroads doesn't know 'what a service does' and -how to judge whether a given back end is very busy or not. You -must therefore give the right hints: - -itemization( - it() In general, a service which is CPU bound, will be more - busy when it takes longer to process a request. The dispatch - mode tt(byduration) is appropriate here. - - it() In contrast, a service which is filesystem bound, will be - more busy when more data are transferred. The dispatch mode - tt(bysize) is apppropriate. - - it() The dispatch mode tt(byduration) can also be used when - network latency is an issue. E.g., if your balancer has back - ends that are geograpically distributed, then tt(byduration) - would be a good way to select best available back ends. - - it() Furthermore it is noteworthy that tt(dispatchmode - byduration) is not usable for interactive processes such as - SSH logins. Idle time of a - login adds to the duration, while causing (almost) no - load. Mode tt(byduration) should only be used for automated - processes that don't wait for user interaction (e.g., SOAP - calls and other HTTP requests). - - it() As a last remark, the dispatching mode tt(byconnections) can - be used if you don't have other clues for load - estimations. - - E.g., consider a database connection. What's - heavier on the back end, time-consuming connections, or connections - where loads of bytes are transferred? Well, that depends. A - tough tt(select) query that joins multiple tables can be very - heavy on the back end, though the response set can be quite - small - and hence the number of - transferred bytes. That would suggest - dispatching by duration. However, tt(byduration) - balancing doesn't respresent the true world, when interactive - connections can occur where users have an idle TCP connection to - the database: - this consumes time, but no bytes (see the SSH login example - above). In this case, the dispatch mode tt(byconnections) may be - your best bet. - - ) - - -subsubsect(Averaging size and duration) - -The configuration statement tt(dispatchmode bysize) or tt(byduration) -allows an optional modifier tt(over) em(number), where the stated -number represents a connection count. When this modifier is present, then -crossroads will use a moving average over the last em(n) connections to -compute duration and size figures. - -In the real world you'll always want this modifier. E.g., consider two -back ends that are running for years now, and one of them is suddenly -overloaded and very busy (it experiences a 'spike' in activity). -When the tt(over) modifier is absent, then -the sudden load will hardly show up in the usage figures -- it will -flatten out due to the large usage figures already stored in the years -of service. - -In contrast, when e.g. tt(over 3) is in effect, then a sudden load -does show up -- because it highly contributes to the average of three -connections. - - -subsubsect(Specifying decays) - -Decays are also only relevant when crossroads computes the 'next best -back end' by size (bytes) or duration (seconds). E.g., imagine two -back ends A and B, both averaged over say 3 connections. - -Now when back end A is suddenly hit by a spike, -its average would go up accordingly. But the back end would never -again be used, unless B also received a similar spike, because A's -'usage data' over its last three connections would forever be larger than -B's data. - -For that reason, you should in real situations probably always -specify a decay, so that the backend selection algorithm recovers from -spikes. Note that the usage data of the back end where a decay is -specified, decay when bf(other) back ends are hit. The decay parameter -is like specifying how fast your body regenerates when someone else -does the work. - -The below configuration illustrates this: - -verb(\ -/* Definition of the service */ -service soap { - /* Local TCP port */ - port 8080; - - /* We'll select back ends by the processing - * duration - */ - dispatchmode byduration over 3; - - /* First back end: */ - backend A { - /* Back end IP address and port */ - server 10.1.1.1:8080; - - /* When this back end is NOT hit because - * the other one was less busy, then the - * usage parameters decay 10% per connection - */ - decay 10; - } - - /* Second back end: */ - backend B { - server 10.1.1.2:8080; - decay 10; - } -}) - -subsubsect(Adjusting the weights) - -The back end modifier tt(weight) is useful in situations where your -back ends differ in respect to performance. E.g,. your back ends may -be geographically distributed, and you know that a given back end is -difficult to reach and often experiences network lag. - -Or you may have -one primary back end, a system with a fast CPU and enough memory, and a -small fall-back back end, with a slow CPU and short on memory. In that -case you know in advance that the second back end should be used only -rarely. Most requests should go to the big server, up to a certain load. - -In such cases you will know in advance that the best performing back ends -should be selected the most often. Here's where the tt(weight) -statement comes in: you can simply increase the weight of the back -ends with the least performance, so that they are selected less -frequently. - -E.g., consider the following configuration: - -verb(\ -service soap { - port 8080; - dispatchmode byduration over 3; - backend A { - server 10.1.1.1:8080; - decay 20; - } - backend B { - server 10.1.1.2:8080; - weight 2; - decay 10; - } - backend C { - server 10.1.1.3:8080; - weight 4; - decay 5; - } -}) - -This will cause crossroads to select back ends by the processing time, -averaging over the last three connections. However, backend B will kick -in only when its usage is half of the usage of A (back end B is -probably only half as fast as A). Backend C will kick in only when its -usage is a quarter of the usage of A, which is half of the usage of B -(back end C is probably very weak, and just a fall-back system incase -both A and B crash). Note also that A's usage data decay much faster -than B's and C's: we're assuming that this big server recovers quicker -than its smaller siblings. - - -subsubsect(Throttling the number of concurrent connections) - -If you suspect that your service may occasionally receive 'spikes' of -activity+footnote(which you should always assume), then it might be a -good idea to protect your service by specifying a maximum number of -concurrent connections. This protection can be specified on two levels: - -description( - dit(On the service level) a statement like tt(maxconnections - 100;) states that the service as a whole will never - service more than 100 concurrent connections. This means that - all your back ends and the crossroads balancer itself - will be protected from being overloaded. - dit(On the back end level) a statement like tt(maxconnections 10;) - states that this particular back end will never have more - than 10 concurrent connections; regardless of the overall - setting on the service level. This means that this - particular back end will be protected from being - overloaded (regardless of what other back ends may - experience).) - -The tt(maxconnections) statement, combined with a back end selection -algorithm, allows very fine granularity. The tt(maxconnections) statement -on the back end level is like a hand brake: even when you specify a -back end algorithm that would protect a given back end from being used -too much, a situation may occur where that back end is about to be -hit. A tt(maxconnections) statement on the level of that back may then -protect it. - - -subsect(Using an external program to dispatch) -label(externalhandler) - -As mentioned before, Crossroads supports several built-in dispatch -modes. However, you are always free to hook-in your own dispatch mode -that determines the next back end using your own specific -algorithm. This section explains how to do it. - -subsubsect(Configuring the external handler) - -First, the tt(dispatchmode) statement needs to inform Crossroads that -an external program will do the job. The syntax is: tt(dispatchmode -externalhandler) em(program arguments). The em(program) must point to -an executable program that will be started by Crossroads. The -specifier em(arguments) can be anything you want; those will be the -arguments to Crossroads. You can however use the following special -format specifiers: - -INCLUDEFILE(formattable) - -Note that the format specifiers such as tt(%b) don't make sense in the -phase in which an external handler is called, since there is no -current back end yet (the job of the handler is to supply one). - -subsubsect(Writing the external handler) - -The external handler is activated using the arguments that are -specified in tt(/etc/crossroads.conf). The external handler can do -whatever it wants, but ultimately, it must write a back end name on -its em(stdout). Crossroads reads this, and if the back end is -available, uses that back end for the connection. - -subsubsect(Examples of external handlers) - -This section shows some examples of Crossroads configurations -vs. external handlers. The sample handlers that are shown here, are -also included in the Crossroads distribution, under the directory -tt(etc/). Also note that the examples shown here are just -quick-and-dirty Perl scripts, meant to illustrate only. Your -applications may need other external handlers, but you can use the -shown scripts as a starting point. - -subsubsubsect(Round-robin dispatching) - -This example is trivial in the sense that round-robin dispatching is -already built into Crossroads, so -that using an external handler for this purpose only slows down -Crossroads. However, it's a good starting example. - -The Crossroads configuration is shown below: - -verb(\ -service test { - port 8001; - verbosity on; - revivinginterval 5; - - dispatchmode externalhandler - /usr/local/src/crossroads/etc/dispatcher-roundrobin - %1b %1a %2b %2a; - - backend testone { - server localhost:3128; - verbosity on; - } - backend testtwo { - server locallhost:3128; - verbosity on; - } -}) - -The relevant tt(dispatchmode) statement invokes the external program -tt(dispatcher-roundrobin) with four arguments: the name of the first -back end (tt(testone)), its availability (0 or 1), the name of the -second back end (tt(testtwo)) and its availability (0 or 1). - -The external handler, which is also included in the Crossroads -distribution, is shown below. It is a Perl script. - -verb(\ -#!/usr/bin/perl - -use strict; - -# Example of a round-robin external dispatcher. This is totally -# superfluous, Crossroads has this on-board; if you use the external -# program for determining round-robin dispatching, then you'll only -# slow things down. This script is just meant as an example. - -# Globals / configuration -# ----------------------- -my $log = '/tmp/exthandler.log'; # Debug log, set to /dev/null to suppress -my $statefile = '/tmp/rr.last'; # Where we keep the last used - -# Logging -# ------- -sub msg { - return if ($log eq '/dev/null' or $log eq ''); - open (my $of, ">>$log") or return; - print $of (scalar(localtime()), ' ', @_); -} - -# Read the last used back end -# --------------------------- -sub readlast() { - my $ret; - - if (open (my $if, $statefile)) { - $ret = <$if>; - chomp ($ret); - close ($if); - msg ("Last used back end: $ret\n"); - return ($ret); - } - msg ("No last-used back end (yet)\n"); - return (undef); -} - -# Write back the last used back end, reply to Crossroads and stop -# --------------------------------------------------------------- -sub reply ($) { - my $last = shift; - - if (open (my $of, ">$statefile")) { - print $of ("$last\n"); - } - print ("$last\n"); - exit (0); -} - -# Main starts here -# ---------------- - -# Collect the cmdline arguments. We expect pairs of backend-name / -# backend-availablility, and we'll store only the available ones. -msg ("Dispatch request received\n"); -my @backend; -for (my $i = 0; $i <= $#ARGV; $i += 2) { - push (@backend, $ARGV[$i]) if ($ARGV[$i + 1]); -} -msg ("Available back ends: @backend\n"); - -# Let's see what the last one is. If none found, then we return the -# first available back end. Otherwise we need to go thru the list of -# back ends, and return the next one in line. -my $last = readlast(); -if ($last eq '') { - msg ("Returning first available back end $backend[0]\n"); - reply ($backend[0]); -} - -# There **was** a last back end. Try to match it in the list, -# then return the next-in-line. -for (my $i = 0; $i < $#backend; $i++) { - if ($last eq $backend[$i]) { - msg ("Returning next back end ", $backend[$i + 1], "\n"); - reply ($backend[$i + 1]); - } -} - -# No luck.. run back to the first one. -msg ("Returning first back end $backend[0]\n"); -reply ($backend[0]);) - -The working of the script is basically as follows: - -itemization( - it() The argument list is scanned. Back ends that are - available are collected in an array tt(@backend). - - it() The script queries a state file tt(/tmp/rr.last). If a - back end name occurs there, then the next back end is looked - up in tt(@backend) and returned to Crossroads. If no last back - is unknown or can't be matched, then the first available back - end (first element of tt(@backend)) is returned to Crossroads. - - it() Informing Crossroads is done via the subroutine - tt(reply()). This code writes the selected back end to file - tt(/tmp/rr.last) (for future usage) and prints the back end - name to em(stdout). - - it() The script logs its actions to a file - tt(/tmp/exthandler.log). This log file can be inspected for - the script's actions.) - - -subsubsubsect(Dispatching by the client IP address) - -The following example shows a useful real-life situation that -illustrates how dispatching by client IP address works. bf(Note that) -as of Crossroads 1.31, tt(dispatchmode byclientip) is implemented -- -so that the below description is somewhat superfluous. The code -snippets however can help you in modelling your own specific dispatch -modes, aided by external helpers. - -The situation is as follows: - -itemization( - it() Crossroads is used as a single-address point to forward - Remote Desktop requests to a farm of Windows systems, where - users can work via remote access; - - it() However, users may stop their session, and when they - re-connect, they expect to be sent to the Windows system that - they had worked on previously; - - it() Client PC's have their distinct IP addresses, which - distinguishes them. - - it() Of four windows systems, two are large servers, and two - are small ones. We'll want to assign large servers to clients - when we have a choice.) - -The requirements resemble session stickiness in HTTP, except that the remote -desktop protocol doesn't support stickiness. This situation is a -perfect example of how an external handler can help: - -itemization( - it() A suitable dispatch mode isn't yet available in - Crossroads, but can be easily coded in an external handler; - - it() The potential delay due to the calling of an external - handler won't even be noticed. This is a network service where - the connection time isn't critical; we'd expect only a few - (albeit lengthy) TCP connections.) - -The approach to the solution of this problem uses several external -program hooks: - -itemization( - it() An external dispatcher handler will be responsible for - suggesting a back end, given a client IP and given the current - timestamp. This handler will consult an internal - administration to see whether the stated IP address should - re-use a back end, or to determine which back end is free for usage. - it() An external hook tt(onstart) will be responsible for - updating the internal administration; i.e., to flag a back end - as 'occupied'. - it() The external hooks tt(onfailure) and tt(onend) will be - responsible for flagging a back end as 'free' again; i.e., for - erasing any previous information that states that the back end - was occupied.) - -The Crossroads configuration is shown below. Only four Windows back -ends are shown. Each back end is configured on a -given IP address, port 3389, and is limited to one concurrent connection -(otherwise a new user might 'steal' a running desktop session). - -verb(\ -service rdp { - port 3389; - revivinginterval 5; - - /* rdp-helper dispatch IP STAMP ... will suggest a back end to use, - * arguments are for all back ends: name, availability, weight */ - dispatchmode externalhandler - /usr/local/src/crossroads/etc/rdp-helper dispatch %r %e - %1b %1a %1w - %2b %2a %2w - %3b %3a %3w - %4b %4a %4w; - - backend win1 { - server 10.1.1.1:3389; - maxconnections 1; - /* rdp-helper start IP STAMP BACKEND will log the actual start - * of a connection; - * rdp-helper end IP will log the ending of a connection */ - onstart /usr/local/src/crossroads/etc/rdp-helper start %r %e %b; - onend /usr/local/src/crossroads/etc/rdp-helper end %r; - onfail /usr/local/src/crossroads/etc/rdp-helper end %r; - } - backend win2 { - server 10.1.1.2:3389; - maxconnections 1; - onstart /usr/local/src/crossroads/etc/rdp-helper start %r %e %b; - onend /usr/local/src/crossroads/etc/rdp-helper end %r; - onfail /usr/local/src/crossroads/etc/rdp-helper end %r; - } - backend win3 { - server 10.1.1.3:3389; - maxconnections 1; - weight 2; - onstart /usr/local/src/crossroads/etc/rdp-helper start %r %e %b; - onend /usr/local/src/crossroads/etc/rdp-helper end %r; - onfail /usr/local/src/crossroads/etc/rdp-helper end %r; - } - backend win4 { - server 10.1.1.4:3389; - maxconnections 1; - weight 3; - onstart /usr/local/src/crossroads/etc/rdp-helper start %r %e %b; - onend /usr/local/src/crossroads/etc/rdp-helper end %r; - onfail /usr/local/src/crossroads/etc/rdp-helper end %r; - } -}) - -Depending on the dispatcher stage, the exernal handler tt(rdp-helper) -is invoked in different ways: - -description( - dit(During dispatching) the helper is called to suggest a back - end. The arguments are an action indicator tt(dispatch), the - client's IP address, the timestamp, and four triplets that - represent back ends: per back end its name, its availability, - and its weight. The purpose of the helper is to tell - Crossroads which back end to use. - - dit(During connection start) the helper will be invoked to - inform it of the start of a connection, given a client IP - address. - - dit(When a connection terminates) the helper will be invoked - to inform it that the connection has ended.) - -Here's the external handler as Perl script. It uses the module -tt(GDBM_File) which most likely will not be part of standard Perl -distributions, but can be added using CPAN. (Alternatively, any other -database module can be used.) - -verb(\ -#!/usr/bin/perl - -use strict; -use GDBM_File; - -# Global variables and configuration -# ---------------------------------- -my $log = '/tmp/exthandler.log'; # Debug log, set to /dev/null to suppress -my $cdb = '/tmp/client.db'; # GDBM database of clients -my %db; # .. and memory representation of it -my $timeout = 24*60*60; # Timeout of a connection in secs - -# Logging -# ------- -sub msg { - return if ($log eq '/dev/null' or $log eq ''); - open (my $of, ">>$log") or return; - print $of (scalar(localtime()), ' ', @_); - close ($of); -} - -# Reply a back end to the caller and stop processing. -# --------------------------------------------------- -sub reply ($) { - my $b = shift; - msg ("Suggesting $b to Crossroads.\n"); - print ("$b\n"); - exit (0); -} - -# Is a value in an array -# ---------------------- -sub inarray { - my $val = shift; - for my $other (@_) { - return (1) if ($other eq $val); - } - return (0); -} - -# A connection is starting -# ------------------------ -sub start { - my ($ip, $stamp, $backend) = @_; - msg ("Logging START of connection for IP $ip on stamp $stamp, ", - "back end $backend\n"); - $db{$ip} = "$backend:$stamp"; -} - -# A connection has ended -# ---------------------- -sub end { - my $ip = shift; - msg ("Logging END of connection for IP $ip\n"); - $db{$ip} = undef; -} - -# Request to determine a back end -# ------------------------------- -sub dispatch { - my $ip = shift; - my $stamp = shift; - - msg ("Request to dispatch IP $ip on stamp $stamp\n"); - - # Read the next arguments. They are triplets of - # backend-name / availability / weight. Store if the back end is - # available. - my (@backends, @weights); - for (my $i = 0; $i < $#_; $i += 3) { - if ($_[$i + 1] != 0) { - push (@backends, $_[$i]); - push (@weights, $_[$i + 2]); - msg ("Candidate back end: $_[$i] with weight ", $_[$i + 2], "\n"); - } - } - - # See if this is a reconnect by a previously seen client IP. We'll - # treat this as a reconnect if the timeout wasn't yet exceeded. - if ($db{$ip} ne '') { - my ($last_backend, $last_stamp) = split (/:/, $db{$ip}); - msg ("IP $ip had last connected on $last_stamp to $last_backend\n"); - if ($stamp < $last_stamp + $timeout) { - msg ("Timeout not yet exceeded, this may be a reconnect\n"); - # We'll allow a reconnect only if the stated last_backend is - # free (sanity check). - if (inarray ($last_backend, @backends)) { - msg ("Last back end $last_backend is available, ", - "letting through\n"); - reply ($last_backend); - } else { - msg ("Last used back end isn't free, suggesting a new one\n"); - } - } else { - msg ("Timeout exceeded, suggesting a new back end\n"); - } - } else { - msg ("Np preveious connection data, suggesting a new back end\n"); - } - - my $bestweight = -1; - my $bestbackend; - for (my $i = 0; $i <= $#weights; $i++) { - if ($bestweight == -1 or $bestweight > $weights[$i]) { - $bestweight = $weights[$i]; - $bestbackend = $backends[$i]; - } - } - - msg ("Best back end: $bestbackend (given weight $bestweight)\n"); - reply ($bestbackend); -} - -# Main starts here -# ---------------- -msg ("Start of run, attaching GDBM database '$cdb'\n"); -tie (%db, 'GDBM_File', $cdb, &GDBM_WRCREAT, 0600); - -# The first argument must be an action 'dispatch', 'start' or 'end'. -# Depending on the action, we do stuff. -my $action = shift (@ARGV); -if ($action eq 'dispatch') { - dispatch (@ARGV); -} elsif ($action eq 'start') { - start (@ARGV); -} elsif ($action eq 'end') { - end (@ARGV); -} else { - print STDERR ("Usage: rdp-helper {dispatch|start|end} args\n"); - exit (1); -}) +subsect(Using an external program to dispatch) label(externalhandler) +includefile(tips/externalhandler) subsect(TCP Session Stickiness) - -If you need to make sure that a client that once gets dispatched to a -given back end keeps re-visiting the back end, then Crossroads offers -the dispatch mode tt(byclientip). This mode will only work when each -client is seen by Crossroads with its own specific IP address; ie., -this method won't work when clients reach Crossroads through a -masquerading firewall (in which case all clients would be seen as -having the firewall's IP address). - -The tt(dispatchmode roundrobin) works as follows: - -itemization( - it() The client's IP address is taken in its string - representation and 'hashed' into a number. - - it() The number is brought back to the number of available - back ends (using a modulo-operation). - - it() The result defines the back end of choice.) - -If the preferred back end is unavailable, then the action that -Crossroads takes is to dispatch as if tt(byconnections): of the -available back ends, the one with the least connections is taken. +includefile(tips/tcpstickiness) subsect(HTTP Session Stickiness) - -This section focuses on HTTP session stickiness. This term refers to -the ability of a balancer to route a conversation between browser and -a backend farm with webservers always to the same back end. In other -words: once a back end is selected by the balancer, it will remain the -back end of choice, even for subsequent connections. - -subsubsect(Don't use stickiness!) - -The rule of thumb as far as the balancer is concerned, is: bf(Do not -use HTTP session stickiness unless you really have to.) Enabling -session stickiness hampers failover, balancing and performance: - -itemization( - it() Failover is hampered because during the session, - the balancer has to assign new connections to the same back - end that was selected at the start of a session. If the back - end suddenly goes 'down', then the session will most likely - crash. (Actually, when a back end becomes unreachable in the - middle of a session, Crossroads will assign a new back end to - that session. This will most likely result in a malfunction - of the underlying application.) - it() Balancing is hampered because at the start of the session, - the balancer has selected the next-best back end. But during - the session, that back end may well become overloaded. The - balancer however must continue to send the requests there. - it() Performance is hampered because crossroads needs to 'unpack' - messages as they are passed to and fro. That's because - crossroads needs to check the HTTP headers in the messages - for persistence cookies.) - -There is a number of measures that you can take to avoid using session -stickiness. E.g., session data can be 'shared' between web back -ends. PHP offers functionality to store session data in a database, so -that all PHP applications have access to these data. Application -servers such as Websphere can be configured to replicate session data -between nodes. - -subsubsect(But if you must..) - -If you really need stickiness, think first whether you might use TCP -stickiness (using the client's IP address to dispatch). If you can, -then this is the preferred method, since Crossroads won't have to -unpack TCP streams. Below is a short configuration example: - -verb(\ -service www { - port 80; - type any; - revivinginterval 15; - dispatchmode byclientip; - - backend one { - server 10.1.1.100:80; - } - - backend two { - server 10.1.1.101:80; - } -}) - - -However, if you bf(must) use HTTP-base session stickiness, then -proceed as follows: - -itemization( - it() At the level of a tt(service) description, set the type to - tt(http). - it() At the level of each back end description, configure the - tt(stickycookie) and a tt(addclientheader) directives.) - -Once crossroads sees that, it will examine each HTTP message that it -shuttles between client and back end: - -itemization( - it() If there is no persistence cookie in the HTTP headers of a - client's request, then the message must be the first one and - a new session should be established. - Crossroads selects an appropriate back - end, sends the message to that back end, catches the reply, - and inserts a tt(Set-Cookie) directive. - it() If there is a persistence cookie in the HTTP headers of a - client's request, then the request is part of an already - established session. Crossroads analyzes the cookie and - forwards the request to the appropriate back end.) - -Below is a short example of a configuration. - -verb(\ -service www { - port 80; - type http; - revivinginterval 15; - dispatchmode byconnections; - - backend one { - server 10.1.1.100:80; - stickycookie XRID=100; - addclientheader "Set-Cookie: XRID=100; Path=/"; - } - - backend two { - server 10.1.1.101:80; - stickycookie XRID=101; - addclientheader "Set-Cookie: XRID=101; Path=/"; - } -}) - -Note how the cookie names and values in the directives -tt(stickycookie) and tt(addclientheader) match. That is obviously a -prerequisite for stickiness. - +includefile(tips/httpstickiness) subsect(Passing the client's IP address) - -Since Crossroads just shuttles bytes to and fro, meta-information of -network connections is lost. As far as the back ends are concerned, -their connections originate at the Crossroads junction. -For example, standard Apache access logs will show the IP address of -Crossroads. - -In order to compensate for this, Crossroads can insert a special -header in HTTP connections, to inform the back end of the original -client's IP address. In order to enable this, the Crossroads -configuration must state the following: - -itemization( - it() The service type must be tt(http), and not tt(any); - it() In the back end definition, the following statement must - occur: nl() - tt(addserverheader "X-Real-IP: %r";) nl() - You are of course free to choose the header name; the here - used tt(X-Real-IP) is a common name for this purpose.) - -After this, HTTP traffic that arrives at the back ends has a new -header: tt(X-Real-IP), holding the client's IP address. -bf(Note that) once the type is set to tt(http), Crossroads' -performance will be hampered -- all passing messages will have to be -unpacked and analyzed. - -subsubsect(Sample Crossroads configuration) - -The below sample configuration shows two HTTP back ends that receive -the client's IP address: - -verb( -service www { - port 80; - type http; - revivinginterval 5; - dispatchmode roundrobin; - - backend one { - server 10.1.1.100:80; - addserverheader "X-Real-IP: %r"; - } - - backend two { - server 10.1.1.200:80; - addserverheader "X-Real-IP: %r"; - } -}) - - -subsubsect(Sample Apache configuration) - -The method by which each back end analyzes the header tt(X-Real-IP) -will obviously be different per server implementations. However, a -common method with the Apache webserver is to log the client's IP -address into the access log. - -Often this is accomplished using the log format tt(custom), defined as -follows: - -verb(\ -LogFormat "%h %l %u %t %D \"%r\" %>s %b" common -CustomLog logs/access_log common) - -The first line defines the format tt(common), with the remote host -specified by tt(%h). The second line sends access information to a log -file tt(logs/access_log), using the previously defined format -tt(common). - -Furtunately, Apache's tt(LogFormat) allows one to log contents of -headers. By replacing the tt(%h) with tt(%{X-Real-IP}i), the desired -information is sent to the log. Therefore, normally you can simply -redefine the tt(common) format to - -verb(\ -LogFormat "%{X-Real-IP}i %l %u %t %D \"%r\" %>s %b" common) - +includefile(tips/clientip) subsect(Debugging network traffic) +includefile(tips/debugging) - Incase the traffic between - client and backend - must be debugged, the statement tt(trafficlog) em(filename) can - be issued. This causes the traffic to be dumped in hexadecimal - format to the stated filename. - - Traffic sent by the client is prefixed by a bf(C), traffic sent by - the back end is prefixed by a bf(B). Below is a sample traffic - dump of a browser trying to get a HTML page. The server replies - that the page was not modified. - - verb(\ -C 0000 47 45 54 20 68 74 74 70 3a 2f 2f 77 77 77 2e 63 GET http://www.c -C 0010 73 2e 68 65 6c 73 69 6e 6b 69 2e 66 69 2f 6c 69 s.helsinki.fi/li -C 0020 6e 75 78 2f 6c 69 6e 75 78 2d 6b 65 72 6e 65 6c nux/linux-kernel -C 0030 2f 32 30 30 31 2d 34 37 2f 30 34 31 37 2e 68 74 /2001-47/0417.ht -C 0040 6d 6c 20 48 54 54 50 2f 31 2e 31 0d 0a 43 6f 6e ml HTTP/1.1..Con -C 0050 6e 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a nection: close.. -. -. etcetera -. -B 0000 48 54 54 50 2f 31 2e 30 20 33 30 34 20 4e 6f 74 HTTP/1.0 304 Not -B 0010 20 4d 6f 64 69 66 69 65 64 0d 0a 44 61 74 65 3a Modified..Date: -B 0020 20 54 75 65 2c 20 31 32 20 4a 75 6c 20 32 30 30 Tue, 12 Jul 200 -B 0030 35 20 30 39 3a 34 39 3a 34 37 20 47 4d 54 0d 0a 5 09:49:47 GMT.. -B 0040 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74 65 Content-Type: te -B 0050 78 74 2f 68 74 6d 6c 3b 20 63 68 61 72 73 65 74 xt/html; charset -. -. etcetera -.) - - Turning on traffic dumps will em(significantly) - slow down crossroads. - - Besides tt(trafficlog), there is also a directive - tt(throughputlog). This directive also takes one argument, a - filename. The file is appended, and the following information is - logged: - - itemization( - it() The process ID of the crossroads image that serves the - TCP connection; - it() The time of the request, in seconds and microseconds - since start of the run; - it() A bf(C) when the request originated at the client, or - bf(B) when the request originated at the back end; - it() The first 100 bytes of the request.) - - As an example, consider the following (the lines are shortened for - brevity and prefixed by line numbers for clarity): - - verb( -1 0000594 0.000001 C GET http://public.e-tunity.com/index.html... -2 0000594 0.173713 B HTTP/1.0 200 OK..Date: Fri, 18 Nov 2005 0... -3 0000594 0.278125 B width="100" bgcolor="#e0e0e0" valign="to... -4 0000595 0.000001 C GET http://public.e-tunity.com/css/style/... -5 0000594 0.944339 B /a></td>.. </tr>.</table>.</td><td class... -6 0000594 0.946356 B smallboxdownl">Download</td>.. <td class... -7 0000594 0.961102 B td><td class="smallboxodd" valign="top"><... -8 0000595 0.698215 B HTTP/1.0 304 Not Modified..Date: Fri, 18 ...) - - This tells us that: - - itemization( - it() Line 1: PID 594 served a request that originated at - the client. The corresponding time is (almost) 0 seconds, - so this is really the start of the run. - it() Line 2: A back end replied 0.17 seconds later, and - 0.28 seconds later, it was still replying (this is the - third line, again a bf(B)-type transmission). - it() Line 4: PID 595 served a request that originated - at the client. Again, the corresponding time is (almost) - 0 seconds, since this is the first conversation part of - this connection. - it() Lines 5 to 7: This is the continuation of line 2. Line 7 - is the last line of the bf(B) series (not visible from - the example, but trust me, it is), so that we may - conclude that it took the back end 0.96 seconds to serve - the file tt(index.html) requested in line 1. - it() Line 8: This is the answer to the client's request of - line 4 (you can tell by the process ID number). - So the back end took 0.68 seconds to confirm that - the stylesheet requested in line 4 wasn't modified.) - - It is also worth while remembering that the start time of a bf(C) - request is the time that crossroads sees the activity. Any latency - between the true client and crossroads is obviously not - included. This is illustrated by the below simple ASCII art: - - verb( -client ---->---->---->--->*crossroads ====>====>====> - \ - back end - / -client ----<----<----<---< crossroads ====<====<====< -) - - This simple picture shows a typical HTTP request that originates - at a client, travels to crossroads, and is relayed via the back - end. The bf(C) entry in a throughput log is the time when - crossroads sees the request, indicated by an asterisk. The bf(B) - entries are the times that it takes the back end to answer, - indicated by tt(===) style lines. Therefore, the true roundtrip - time will be longer than the number of seconds that are logged in - the throughput log: the latency between client and crossroads - isn't included in that measurement. - - Summarizing, the throughput times of a client-back end connection - can be analyzed using the directive tt(throughputlog). In a - real-world analysis, you'd probably want to write up a script to - analyze the output and to compute round trip times. Such scripts - are not (yet) included in Crossroads. - -subsect(Limiting Access to Crossroads by Client IP Address) - -subsubsect(General Examples) - -The directives tt(allowfrom), tt(denyfrom), tt(allowfile) and -tt(denyfile) can be used to instruct Crossroads to specifically allow -access by using a "whitelist" of IP addresses, or to specifically deny -access by using a "blacklist". E.g., the following configuration -allows access to service tt(webproxy) only to em(localhost): - -verb(\ -service webproxy { - port 8000; - allowfrom 127.0.0.1; - backend one { - . - . Back end definitions occur here - . - } - . - . Other back ends or other service directives - . may occur here - . -}) - -In this example there is a "whitelist" having only one entry: IP -address 127.0.0.1, or em(localhost). (Incidentally, the same behaviour -could be accomplished by stating em(bindto 127.0.0.1), in which case -Crossroads would only listen to the local network device.) - -In the same vein, the directive tt(allowfrom 127.0.0.1 192.168.1/24) -would allow access to em(localhost) and to all IP addresses that start -with 192.168.1. The specifier tt(192.168.1/24) states that there are -three network bytes (192, 168 and 1), and 24 bits (or 3 bytes) are -relevant; so that the fourth network byte doesn't matter. - -subsubsect(Using External Files) - -The directives tt(allowfile) and tt(denyfile) allow you to specify IP -addresses in external files. The Crossroads configuration states -e.g. tt(allowfile /tmp/allow.txt), and the IP addresses are then in -tt(/tmp/allow.txt). The format of tt(/tmp/allow.txt) is as follows: - -itemization( - it() The specifications follow again em(p.q.r.s/mask), where - p, q, r and s are network bytes which can be left out on the - right hand side when the mask allows it; - - it() The specifications must be separated by white space - (spaces, tabs or newlines).) - -E.g., the following is a valid example of an external specification -file: - -verb(\ -127.0.0.1 -192.168.1/24 -10/8) - -When external files are in effect, then the signal tt(SIGHUP) (1) -causes Crossroads to reload the external file. E.g., while Crossroads -is running, you may edit tt(/tmp/allow.txt), and then issue tt(killall --1 crossroads). The new contents of tt(/tmp/allow.txt) will be -reloaded. - -subsubsect(Mixing Directives) - -Crossroads allows to mix all directives in one service -description. However, some mixes are less meaningful than others. It's -up to you to take this into account. - -The following rules apply: - -itemization( - it() Blacklisting and whitelisting can be used together. When - combined, the blacklist will always be interpreted - first. E.g., consider the following directives: - - verb(\ -allowfrom 192.168.1/24 -denyfrom 192.168.1.100) - - Given the fact that the deny list is checked first, client - 192.168.1.100 won't be able to access Crossroads. Then the - allow list will be checked, stating that all clients whose IP - address starts with 192.168.1 may connect. The effect will be - that e.g., client 192.168.1.1 may connect, 192.168.1.2 may - connect too, 192.168.1.100 will be blocked, and 10.1.1.1 will - be blocked as well. - - Now consider the following directives: - - verb(\ -allowfrom 192.168.1.100 127.0.0.1 -denyfrom 192.168.1/24) - - This will first of all deny access to all IP addresses that - start with 192.168.1. So the rule that allows 192.168.1.100 - won't ever be effective. The net result will be that access - will be granted to 127.0.0.1, and IP addresses that don't - match 192.168.1/24. - - it() Blacklisting or whitelisting can be left out. - A list is considered empty when no appropriate directives - occur in tt(/etc/crossroads.conf), or when the directive - points to an empty or non-existent external file. - - it() Using tt(*from) and tt(*file) statements is allowed, but - doesn't make sense. E.g., the following configuration sample - is such a case: - - verb(\ -allowfrom 127.0.0.1 192.168.1/24 -allowfile /tmp/allow.txt) - - There is a technical reason for this. Once Crossroads - processes the tt(allowfile) directive, then the whole - whitelist is cleared (thereby removing the entries 127.0.0.1 - and 192.168.1/24), and new entries are reloaded from the - file. The net result is that the tt(allowfrom) specification - is overruled. - - Crossroads doesn't check for such configurations, which are - syntactially correct, but make no semantic sense.) - +subsect(IP filtering: Limiting Access by Client IP Address) +includefile(tips/ipfiltering) subsect(Configuration examples) +includefile(tips/examples) -As a general hint, use tt(crossroads sampleconf) to view the most -up-to-date examples of configurations. The description below shows a -few examples too. - - -subsubsect(A load balancer for three webserver back ends) - -The following configuration example binds crossroads to port 80 of the -current server, and distributes the load over three back ends. This -configuration shows most of the possible settings. - -verb(\ -service www { - /* We don't need session stickyness. */ - type any; - - /* Port on which we'll listen in this service: required. */ - port 8000; - - /* What IP address should this service listen? Default is 'any'. - * Alternatively you can state an explicit IP address, such as - * 127.0.0.1; that would bind the service only to 'localhost'. */ - bindto any; - - /* Verbose reporting or not. Default is off. */ - verbosity on; - - /* Dispatching mode, or: How to select a back end for an incoming - * request. Possible values: - * roundrobin: just the next back end in line - * random: like roundrobin, but at random to make things more - * confusing. Probably only good for testing. - * bysize: The backend that transferred the least nr of bytes - * is the next in line. As a modifier you can say e.g. - * bysize over 10, meaning that the 10 last connections will - * be used to compute the transfer size, instead of all - * transfers. - * byduration: The backend that was active for the shortest time - * is the next in line. As a modifier you can say e.g. - * byduration of 10 to compute over the last 10 connections. - * byconnections: The back end with the least active connections - * is the next ine line. - * byorder: The first available back end is always taken. - */ - dispatchmode byduration over 5; - - /* Interval at which we'll check whether a temporarily unavailable - * backend has woken up. - */ - revivinginterval 5; - - /* TCP backlog of connections. Default is 0 (no backlog, one - * connection may be active). - */ - backlog 5; - - /* For status reporting: a shared memory key. Default is the same - * as the port number, OR-ed by a magic number. - */ - shmkey 8000; - - /* This controls when crossroads should consider a connection as - * finished even when the TCP sockets weren't closed. This is to - * avoid hanging connections that don't do anything. NOTE THAT when - * crossroads cuts off a connection due to timeout exceed, this is - * not marked as a failure, but as a success. Default is 0: no timeout. - */ - connectiontimeout 300; - - /* The max number of allowed client connections. When present, connections - * won't be accepted if the max is about to be exceeded. When - * absent, all connections will be accepted, which might be misused - * for a DOS attack. - */ - maxconnections 300; - - /* Now let's define a couple of back ends. Number 1: */ - backend www_backend_1 { - /* The server and its port, the minimum configuration. */ - server httpserver1; - port 9010; - /* The 'decay' of usage data of this back end. Only relevant - * when the whole service has 'dispatchmode bysize' or - * 'byduration'. The number is a percentage by which the usage - * parameter is decreased upon each connection of an other back - * end. - */ - decay 10; - - /* To see what's happening in /var/log/messages: */ - verbosity on; - } - - /* The second one: */ - backend www_backend_2 { - /* Server and port */ - server httpserver2; - port 9011; - - /* Verbosity of reporting when this back end is active */ - verbosity on; - - /* Decay */ - decay 10; - - /* This back end is twice as weak as the first one */ - weight 2; - - /* Event triggers for system commands upon succesful activation - * and upon failure. - */ - onsuccess echo 'success on backend 2' | mail root; - onfailure echo 'failure on backend 2' | mail root; - } - - /* And yet another one.. this time we will dump the traffic - * to a trace file. Furthermore we don't want more than 10 concurrent - * connections here. Note that there's also a total maxconnections for the - * whole service. - */ - backend www_backend_3 { - server httpserver3; - verbosity on; - port 9000; - verbosity on; - decay 10; - trafficlog /tmp/backend.3.log; - maxconnections 10; - } -}) - -subsubsect(An HTTP forwarder when travelling) - -As another example, here's my tt(crossroads.conf) that I use on my -Unix laptop. The problem that I face is that I need many HTTP proxy -configurations (at home, at customers' sites and so on) but I'm too -lazy to reconfigure browsers all the time. - -Here's how it used to be before crossroads: - -itemization( - it() At home, I would surf through a squid proxy on my local - machine. The browser proxy setting is then - tt(http://localhost:3128). - - it() Sometimes I start up an SSH tunnel to our offices. The - tunnel has a local port 3129, and connects to a squid proxy on - our e-tunity server. Hence, the browser proxy is then - tt(http://localhost:3129). - - it() At a customer's location I need the proxy - tt(http://10.120.34.113:8080), because they have configured it - so. - - it() And in yet other instances, I use a HTTP diagnostic tool - url(Charles)(http://www.xk72.com/charles) - that sits between browser and website and shows me - what's happening. I run charles on my own machine and it - listens to port 8888, behaving like a proxy. The browser - configuration for the proxy is then - tt(http://localhost:8888).) - -Here's how it works with a crossroads configuration: - -itemization( - it() I have configured my browsers to use - tt(http://localhost:8080) as the proxy. For all situations. - - it() I use the following crossroads configuration, and let - crossroads figure out which proxy backend works, and which - doesn't. Note two particularities: - - itemization( - it() The statement tt(dispatchmode byorder). This - makes sure that once crossroads determines which - backend works, it will stick to it. This usage of - crossroads doesn't need to balance over more than one - back end. - - it() The statement tt(bindto 127.0.0.1) makes sure - that requests from other interfaces than loopback - won't get serviced.) - -verb(\ -service HttpProxy { - port 8080; - bindto 127.0.0.1; - verbosity on; - dispatchmode byorder; - revivinginterval 15; - - backend Charles { - server localhost:8888; - verbosity on; - } - - backend CustomerProxy { - server 10.120.34.113:8080; - verbosity on; - } - - backend SshTunnel { - server localhost:3129; - } - - backend LocalSquid { - server localhost:3128; - } -})) - -As a final note, the commandline argument tt(tell) can be used to -influence crossroad's own detection mechanism of back end availability -detection. E.g., if in the above example the back ends tt(SshTunnel) -and tt(LocalSquid) are both active, then tt(crossroads tell httpproxy -sshtunnel down) will 'take down' the back end tt(SshTunnel) -- and -will automatically cause crossroads to switch to tt(LocalSquid). - - -subsubsect(SSH login with enforced idle logout) - -The following example shows how crossroads 'throttles' SSH -logins. Connections are accepted on port -22 (the normal SSH port) and forwarded to the actual SSH daemon -which is running on port 2222. +subsect(Linux and ip_conntrack_max) +includefile(tips/ipconntrackmax) -Note the usage of the -tt(connectiontimeout) directive. This makes sure that users are logged -out after 10 minutes of inactivity. Note also the tt(maxconnections) -setting, this makes sure that no more than 10 concurrent logins occur. +subsect(Marking back ends as bad after more than one try) +includefile(tips/retries) -verb(\ -service Ssh { - port 22; - backlog 5; - maxconnections 10; - connectiontimeout 600; - backend TrueSshDaemon { - server localhost:2222; - } -}) diff --git a/doc/tips/clientip.yo b/doc/tips/clientip.yo @@ -0,0 +1,75 @@ +Since Crossroads just shuttles bytes to and fro, meta-information of +network connections is lost. As far as the back ends are concerned, +their connections originate at the Crossroads junction. +For example, standard Apache access logs will show the IP address of +Crossroads. + +In order to compensate for this, Crossroads can insert a special +header in HTTP connections, to inform the back end of the original +client's IP address. In order to enable this, the Crossroads +configuration must state the following: + +itemization( + it() The service type must be tt(http), and not tt(any); + it() In the back end definition, the following statement must + occur: nl() + tt(addserverheader "X-Real-IP: %r";) nl() + You are of course free to choose the header name; the here + used tt(X-Real-IP) is a common name for this purpose.) + +After this, HTTP traffic that arrives at the back ends has a new +header: tt(X-Real-IP), holding the client's IP address. +bf(Note that) once the type is set to tt(http), Crossroads' +performance will be hampered -- all passing messages will have to be +unpacked and analyzed. + +subsubsect(Sample Crossroads configuration) + +The below sample configuration shows two HTTP back ends that receive +the client's IP address: + +verb( +service www { + port 80; + type http; + revivinginterval 5; + dispatchmode roundrobin; + + backend one { + server 10.1.1.100:80; + addserverheader "X-Real-IP: %r"; + } + + backend two { + server 10.1.1.200:80; + addserverheader "X-Real-IP: %r"; + } +}) + + +subsubsect(Sample Apache configuration) + +The method by which each back end analyzes the header tt(X-Real-IP) +will obviously be different per server implementations. However, a +common method with the Apache webserver is to log the client's IP +address into the access log. + +Often this is accomplished using the log format tt(custom), defined as +follows: + +verb(\ +LogFormat "%h %l %u %t %D \"%r\" %>s %b" common +CustomLog logs/access_log common) + +The first line defines the format tt(common), with the remote host +specified by tt(%h). The second line sends access information to a log +file tt(logs/access_log), using the previously defined format +tt(common). + +Furtunately, Apache's tt(LogFormat) allows one to log contents of +headers. By replacing the tt(%h) with tt(%{X-Real-IP}i), the desired +information is sent to the log. Therefore, normally you can simply +redefine the tt(common) format to + +verb(\ +LogFormat "%{X-Real-IP}i %l %u %t %D \"%r\" %>s %b" common) diff --git a/doc/tips/debugging.yo b/doc/tips/debugging.yo @@ -0,0 +1,112 @@ + Incase the traffic between + client and backend + must be debugged, the statement tt(trafficlog) em(filename) can + be issued. This causes the traffic to be dumped in hexadecimal + format to the stated filename. + + Traffic sent by the client is prefixed by a bf(C), traffic sent by + the back end is prefixed by a bf(B). Below is a sample traffic + dump of a browser trying to get a HTML page. The server replies + that the page was not modified. + + verb(\ +C 0000 47 45 54 20 68 74 74 70 3a 2f 2f 77 77 77 2e 63 GET http://www.c +C 0010 73 2e 68 65 6c 73 69 6e 6b 69 2e 66 69 2f 6c 69 s.helsinki.fi/li +C 0020 6e 75 78 2f 6c 69 6e 75 78 2d 6b 65 72 6e 65 6c nux/linux-kernel +C 0030 2f 32 30 30 31 2d 34 37 2f 30 34 31 37 2e 68 74 /2001-47/0417.ht +C 0040 6d 6c 20 48 54 54 50 2f 31 2e 31 0d 0a 43 6f 6e ml HTTP/1.1..Con +C 0050 6e 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a nection: close.. +. +. etcetera +. +B 0000 48 54 54 50 2f 31 2e 30 20 33 30 34 20 4e 6f 74 HTTP/1.0 304 Not +B 0010 20 4d 6f 64 69 66 69 65 64 0d 0a 44 61 74 65 3a Modified..Date: +B 0020 20 54 75 65 2c 20 31 32 20 4a 75 6c 20 32 30 30 Tue, 12 Jul 200 +B 0030 35 20 30 39 3a 34 39 3a 34 37 20 47 4d 54 0d 0a 5 09:49:47 GMT.. +B 0040 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74 65 Content-Type: te +B 0050 78 74 2f 68 74 6d 6c 3b 20 63 68 61 72 73 65 74 xt/html; charset +. +. etcetera +.) + + Turning on traffic dumps will em(significantly) + slow down crossroads. + + Besides tt(trafficlog), there is also a directive + tt(throughputlog). This directive also takes one argument, a + filename. The file is appended, and the following information is + logged: + + itemization( + it() The process ID of the crossroads image that serves the + TCP connection; + it() The time of the request, in seconds and microseconds + since start of the run; + it() A bf(C) when the request originated at the client, or + bf(B) when the request originated at the back end; + it() The first 100 bytes of the request.) + + As an example, consider the following (the lines are shortened for + brevity and prefixed by line numbers for clarity): + + verb( +1 0000594 0.000001 C GET http://public.e-tunity.com/index.html... +2 0000594 0.173713 B HTTP/1.0 200 OK..Date: Fri, 18 Nov 2005 0... +3 0000594 0.278125 B width="100" bgcolor="#e0e0e0" valign="to... +4 0000595 0.000001 C GET http://public.e-tunity.com/css/style/... +5 0000594 0.944339 B /a></td>.. </tr>.</table>.</td><td class... +6 0000594 0.946356 B smallboxdownl">Download</td>.. <td class... +7 0000594 0.961102 B td><td class="smallboxodd" valign="top"><... +8 0000595 0.698215 B HTTP/1.0 304 Not Modified..Date: Fri, 18 ...) + + This tells us that: + + itemization( + it() Line 1: PID 594 served a request that originated at + the client. The corresponding time is (almost) 0 seconds, + so this is really the start of the run. + it() Line 2: A back end replied 0.17 seconds later, and + 0.28 seconds later, it was still replying (this is the + third line, again a bf(B)-type transmission). + it() Line 4: PID 595 served a request that originated + at the client. Again, the corresponding time is (almost) + 0 seconds, since this is the first conversation part of + this connection. + it() Lines 5 to 7: This is the continuation of line 2. Line 7 + is the last line of the bf(B) series (not visible from + the example, but trust me, it is), so that we may + conclude that it took the back end 0.96 seconds to serve + the file tt(index.html) requested in line 1. + it() Line 8: This is the answer to the client's request of + line 4 (you can tell by the process ID number). + So the back end took 0.68 seconds to confirm that + the stylesheet requested in line 4 wasn't modified.) + + It is also worth while remembering that the start time of a bf(C) + request is the time that crossroads sees the activity. Any latency + between the true client and crossroads is obviously not + included. This is illustrated by the below simple ASCII art: + + verb( +client ---->---->---->--->*crossroads ====>====>====> + \ + back end + / +client ----<----<----<---< crossroads ====<====<====< +) + + This simple picture shows a typical HTTP request that originates + at a client, travels to crossroads, and is relayed via the back + end. The bf(C) entry in a throughput log is the time when + crossroads sees the request, indicated by an asterisk. The bf(B) + entries are the times that it takes the back end to answer, + indicated by tt(===) style lines. Therefore, the true roundtrip + time will be longer than the number of seconds that are logged in + the throughput log: the latency between client and crossroads + isn't included in that measurement. + + Summarizing, the throughput times of a client-back end connection + can be analyzed using the directive tt(throughputlog). In a + real-world analysis, you'd probably want to write up a script to + analyze the output and to compute round trip times. Such scripts + are not (yet) included in Crossroads. diff --git a/doc/tips/examples.yo b/doc/tips/examples.yo @@ -0,0 +1,236 @@ + +subsubsect(A load balancer for three webserver back ends) + +The following configuration example binds crossroads to port 80 of the +current server, and distributes the load over three back ends. This +configuration shows most of the possible settings. + +verb(\ +service www { + /* We don't need session stickyness. */ + type any; + + /* Port on which we'll listen in this service: required. */ + port 8000; + + /* What IP address should this service listen? Default is 'any'. + * Alternatively you can state an explicit IP address, such as + * 127.0.0.1; that would bind the service only to 'localhost'. */ + bindto any; + + /* Verbose reporting or not. Default is off. */ + verbosity on; + + /* Dispatching mode, or: How to select a back end for an incoming + * request. Possible values: + * roundrobin: just the next back end in line + * random: like roundrobin, but at random to make things more + * confusing. Probably only good for testing. + * bysize: The backend that transferred the least nr of bytes + * is the next in line. As a modifier you can say e.g. + * bysize over 10, meaning that the 10 last connections will + * be used to compute the transfer size, instead of all + * transfers. + * byduration: The backend that was active for the shortest time + * is the next in line. As a modifier you can say e.g. + * byduration of 10 to compute over the last 10 connections. + * byconnections: The back end with the least active connections + * is the next ine line. + * byorder: The first available back end is always taken. + */ + dispatchmode byduration over 5; + + /* Interval at which we'll check whether a temporarily unavailable + * backend has woken up. + */ + revivinginterval 5; + + /* TCP backlog of connections. Default is 0 (no backlog, one + * connection may be active). + */ + backlog 5; + + /* For status reporting: a shared memory key. Default is the same + * as the port number, OR-ed by a magic number. + */ + shmkey 8000; + + /* This controls when crossroads should consider a connection as + * finished even when the TCP sockets weren't closed. This is to + * avoid hanging connections that don't do anything. NOTE THAT when + * crossroads cuts off a connection due to timeout exceed, this is + * not marked as a failure, but as a success. Default is 0: no timeout. + */ + connectiontimeout 300; + + /* The max number of allowed client connections. When present, connections + * won't be accepted if the max is about to be exceeded. When + * absent, all connections will be accepted, which might be misused + * for a DOS attack. + */ + maxconnections 300; + + /* Now let's define a couple of back ends. Number 1: */ + backend www_backend_1 { + /* The server and its port, the minimum configuration. */ + server httpserver1; + port 9010; + /* The 'decay' of usage data of this back end. Only relevant + * when the whole service has 'dispatchmode bysize' or + * 'byduration'. The number is a percentage by which the usage + * parameter is decreased upon each connection of an other back + * end. + */ + decay 10; + + /* To see what's happening in /var/log/messages: */ + verbosity on; + } + + /* The second one: */ + backend www_backend_2 { + /* Server and port */ + server httpserver2; + port 9011; + + /* Verbosity of reporting when this back end is active */ + verbosity on; + + /* Decay */ + decay 10; + + /* This back end is twice as weak as the first one */ + weight 2; + + /* Event triggers for system commands upon succesful activation + * and upon failure. + */ + onsuccess echo 'success on backend 2' | mail root; + onfailure echo 'failure on backend 2' | mail root; + } + + /* And yet another one.. this time we will dump the traffic + * to a trace file. Furthermore we don't want more than 10 concurrent + * connections here. Note that there's also a total maxconnections for the + * whole service. + */ + backend www_backend_3 { + server httpserver3; + verbosity on; + port 9000; + verbosity on; + decay 10; + trafficlog /tmp/backend.3.log; + maxconnections 10; + } +}) + +subsubsect(An HTTP forwarder when travelling) + +As another example, here's my tt(crossroads.conf) that I use on my +Unix laptop. The problem that I face is that I need many HTTP proxy +configurations (at home, at customers' sites and so on) but I'm too +lazy to reconfigure browsers all the time. + +Here's how it used to be before crossroads: + +itemization( + it() At home, I would surf through a squid proxy on my local + machine. The browser proxy setting is then + tt(http://localhost:3128). + + it() Sometimes I start up an SSH tunnel to our offices. The + tunnel has a local port 3129, and connects to a squid proxy on + our e-tunity server. Hence, the browser proxy is then + tt(http://localhost:3129). + + it() At a customer's location I need the proxy + tt(http://10.120.34.113:8080), because they have configured it + so. + + it() And in yet other instances, I use a HTTP diagnostic tool + url(Charles)(http://www.xk72.com/charles) + that sits between browser and website and shows me + what's happening. I run charles on my own machine and it + listens to port 8888, behaving like a proxy. The browser + configuration for the proxy is then + tt(http://localhost:8888).) + +Here's how it works with a crossroads configuration: + +itemization( + it() I have configured my browsers to use + tt(http://localhost:8080) as the proxy. For all situations. + + it() I use the following crossroads configuration, and let + crossroads figure out which proxy backend works, and which + doesn't. Note two particularities: + + itemization( + it() The statement tt(dispatchmode byorder). This + makes sure that once crossroads determines which + backend works, it will stick to it. This usage of + crossroads doesn't need to balance over more than one + back end. + + it() The statement tt(bindto 127.0.0.1) makes sure + that requests from other interfaces than loopback + won't get serviced.) + +verb(\ +service HttpProxy { + port 8080; + bindto 127.0.0.1; + verbosity on; + dispatchmode byorder; + revivinginterval 15; + + backend Charles { + server localhost:8888; + verbosity on; + } + + backend CustomerProxy { + server 10.120.34.113:8080; + verbosity on; + } + + backend SshTunnel { + server localhost:3129; + } + + backend LocalSquid { + server localhost:3128; + } +})) + +As a final note, the commandline argument tt(tell) can be used to +influence crossroad's own detection mechanism of back end availability +detection. E.g., if in the above example the back ends tt(SshTunnel) +and tt(LocalSquid) are both active, then tt(crossroads tell httpproxy +sshtunnel down) will 'take down' the back end tt(SshTunnel) -- and +will automatically cause crossroads to switch to tt(LocalSquid). + + +subsubsect(SSH login with enforced idle logout) + +The following example shows how crossroads 'throttles' SSH +logins. Connections are accepted on port +22 (the normal SSH port) and forwarded to the actual SSH daemon +which is running on port 2222. + +Note the usage of the +tt(connectiontimeout) directive. This makes sure that users are logged +out after 10 minutes of inactivity. Note also the tt(maxconnections) +setting, this makes sure that no more than 10 concurrent logins occur. + +verb(\ +service Ssh { + port 22; + backlog 5; + maxconnections 10; + connectiontimeout 600; + backend TrueSshDaemon { + server localhost:2222; + } +}) diff --git a/doc/tips/externalhandler.yo b/doc/tips/externalhandler.yo @@ -0,0 +1,449 @@ +As mentioned before, Crossroads supports several built-in dispatch +modes. However, you are always free to hook-in your own dispatch mode +that determines the next back end using your own specific +algorithm. This section explains how to do it. + +subsubsect(Configuring the external handler) + +First, the tt(dispatchmode) statement needs to inform Crossroads that +an external program will do the job. The syntax is: tt(dispatchmode +externalhandler) em(program arguments). The em(program) must point to +an executable program that will be started by Crossroads. The +specifier em(arguments) can be anything you want; those will be the +arguments to Crossroads. You can however use the following special +format specifiers: + +INCLUDEFILE(formattable) + +Note that the format specifiers such as tt(%b) don't make sense in the +phase in which an external handler is called, since there is no +current back end yet (the job of the handler is to supply one). + +subsubsect(Writing the external handler) + +The external handler is activated using the arguments that are +specified in tt(/etc/crossroads.conf). The external handler can do +whatever it wants, but ultimately, it must write a back end name on +its em(stdout). Crossroads reads this, and if the back end is +available, uses that back end for the connection. + +subsubsect(Examples of external handlers) + +This section shows some examples of Crossroads configurations +vs. external handlers. The sample handlers that are shown here, are +also included in the Crossroads distribution, under the directory +tt(etc/). Also note that the examples shown here are just +quick-and-dirty Perl scripts, meant to illustrate only. Your +applications may need other external handlers, but you can use the +shown scripts as a starting point. + +subsubsubsect(Round-robin dispatching) + +This example is trivial in the sense that round-robin dispatching is +already built into Crossroads, so +that using an external handler for this purpose only slows down +Crossroads. However, it's a good starting example. + +The Crossroads configuration is shown below: + +verb(\ +service test { + port 8001; + verbosity on; + revivinginterval 5; + + dispatchmode externalhandler + /usr/local/src/crossroads/etc/dispatcher-roundrobin + %1b %1a %2b %2a; + + backend testone { + server localhost:3128; + verbosity on; + } + backend testtwo { + server locallhost:3128; + verbosity on; + } +}) + +The relevant tt(dispatchmode) statement invokes the external program +tt(dispatcher-roundrobin) with four arguments: the name of the first +back end (tt(testone)), its availability (0 or 1), the name of the +second back end (tt(testtwo)) and its availability (0 or 1). + +The external handler, which is also included in the Crossroads +distribution, is shown below. It is a Perl script. + +verb(\ +#!/usr/bin/perl + +use strict; + +# Example of a round-robin external dispatcher. This is totally +# superfluous, Crossroads has this on-board; if you use the external +# program for determining round-robin dispatching, then you'll only +# slow things down. This script is just meant as an example. + +# Globals / configuration +# ----------------------- +my $log = '/tmp/exthandler.log'; # Debug log, set to /dev/null to suppress +my $statefile = '/tmp/rr.last'; # Where we keep the last used + +# Logging +# ------- +sub msg { + return if ($log eq '/dev/null' or $log eq ''); + open (my $of, ">>$log") or return; + print $of (scalar(localtime()), ' ', @_); +} + +# Read the last used back end +# --------------------------- +sub readlast() { + my $ret; + + if (open (my $if, $statefile)) { + $ret = <$if>; + chomp ($ret); + close ($if); + msg ("Last used back end: $ret\n"); + return ($ret); + } + msg ("No last-used back end (yet)\n"); + return (undef); +} + +# Write back the last used back end, reply to Crossroads and stop +# --------------------------------------------------------------- +sub reply ($) { + my $last = shift; + + if (open (my $of, ">$statefile")) { + print $of ("$last\n"); + } + print ("$last\n"); + exit (0); +} + +# Main starts here +# ---------------- + +# Collect the cmdline arguments. We expect pairs of backend-name / +# backend-availablility, and we'll store only the available ones. +msg ("Dispatch request received\n"); +my @backend; +for (my $i = 0; $i <= $#ARGV; $i += 2) { + push (@backend, $ARGV[$i]) if ($ARGV[$i + 1]); +} +msg ("Available back ends: @backend\n"); + +# Let's see what the last one is. If none found, then we return the +# first available back end. Otherwise we need to go thru the list of +# back ends, and return the next one in line. +my $last = readlast(); +if ($last eq '') { + msg ("Returning first available back end $backend[0]\n"); + reply ($backend[0]); +} + +# There **was** a last back end. Try to match it in the list, +# then return the next-in-line. +for (my $i = 0; $i < $#backend; $i++) { + if ($last eq $backend[$i]) { + msg ("Returning next back end ", $backend[$i + 1], "\n"); + reply ($backend[$i + 1]); + } +} + +# No luck.. run back to the first one. +msg ("Returning first back end $backend[0]\n"); +reply ($backend[0]);) + +The working of the script is basically as follows: + +itemization( + it() The argument list is scanned. Back ends that are + available are collected in an array tt(@backend). + + it() The script queries a state file tt(/tmp/rr.last). If a + back end name occurs there, then the next back end is looked + up in tt(@backend) and returned to Crossroads. If no last back + is unknown or can't be matched, then the first available back + end (first element of tt(@backend)) is returned to Crossroads. + + it() Informing Crossroads is done via the subroutine + tt(reply()). This code writes the selected back end to file + tt(/tmp/rr.last) (for future usage) and prints the back end + name to em(stdout). + + it() The script logs its actions to a file + tt(/tmp/exthandler.log). This log file can be inspected for + the script's actions.) + + +subsubsubsect(Dispatching by the client IP address) + +The following example shows a useful real-life situation that +illustrates how dispatching by client IP address works. bf(Note that) +as of Crossroads 1.31, tt(dispatchmode byclientip) is implemented -- +so that the below description is somewhat superfluous. The code +snippets however can help you in modelling your own specific dispatch +modes, aided by external helpers. + +The situation is as follows: + +itemization( + it() Crossroads is used as a single-address point to forward + Remote Desktop requests to a farm of Windows systems, where + users can work via remote access; + + it() However, users may stop their session, and when they + re-connect, they expect to be sent to the Windows system that + they had worked on previously; + + it() Client PC's have their distinct IP addresses, which + distinguishes them. + + it() Of four windows systems, two are large servers, and two + are small ones. We'll want to assign large servers to clients + when we have a choice.) + +The requirements resemble session stickiness in HTTP, except that the remote +desktop protocol doesn't support stickiness. This situation is a +perfect example of how an external handler can help: + +itemization( + it() A suitable dispatch mode isn't yet available in + Crossroads, but can be easily coded in an external handler; + + it() The potential delay due to the calling of an external + handler won't even be noticed. This is a network service where + the connection time isn't critical; we'd expect only a few + (albeit lengthy) TCP connections.) + +The approach to the solution of this problem uses several external +program hooks: + +itemization( + it() An external dispatcher handler will be responsible for + suggesting a back end, given a client IP and given the current + timestamp. This handler will consult an internal + administration to see whether the stated IP address should + re-use a back end, or to determine which back end is free for usage. + it() An external hook tt(onstart) will be responsible for + updating the internal administration; i.e., to flag a back end + as 'occupied'. + it() The external hooks tt(onfailure) and tt(onend) will be + responsible for flagging a back end as 'free' again; i.e., for + erasing any previous information that states that the back end + was occupied.) + +The Crossroads configuration is shown below. Only four Windows back +ends are shown. Each back end is configured on a +given IP address, port 3389, and is limited to one concurrent connection +(otherwise a new user might 'steal' a running desktop session). + +verb(\ +service rdp { + port 3389; + revivinginterval 5; + + /* rdp-helper dispatch IP STAMP ... will suggest a back end to use, + * arguments are for all back ends: name, availability, weight */ + dispatchmode externalhandler + /usr/local/src/crossroads/etc/rdp-helper dispatch %r %e + %1b %1a %1w + %2b %2a %2w + %3b %3a %3w + %4b %4a %4w; + + backend win1 { + server 10.1.1.1:3389; + maxconnections 1; + /* rdp-helper start IP STAMP BACKEND will log the actual start + * of a connection; + * rdp-helper end IP will log the ending of a connection */ + onstart /usr/local/src/crossroads/etc/rdp-helper start %r %e %b; + onend /usr/local/src/crossroads/etc/rdp-helper end %r; + onfail /usr/local/src/crossroads/etc/rdp-helper end %r; + } + backend win2 { + server 10.1.1.2:3389; + maxconnections 1; + onstart /usr/local/src/crossroads/etc/rdp-helper start %r %e %b; + onend /usr/local/src/crossroads/etc/rdp-helper end %r; + onfail /usr/local/src/crossroads/etc/rdp-helper end %r; + } + backend win3 { + server 10.1.1.3:3389; + maxconnections 1; + weight 2; + onstart /usr/local/src/crossroads/etc/rdp-helper start %r %e %b; + onend /usr/local/src/crossroads/etc/rdp-helper end %r; + onfail /usr/local/src/crossroads/etc/rdp-helper end %r; + } + backend win4 { + server 10.1.1.4:3389; + maxconnections 1; + weight 3; + onstart /usr/local/src/crossroads/etc/rdp-helper start %r %e %b; + onend /usr/local/src/crossroads/etc/rdp-helper end %r; + onfail /usr/local/src/crossroads/etc/rdp-helper end %r; + } +}) + +Depending on the dispatcher stage, the exernal handler tt(rdp-helper) +is invoked in different ways: + +description( + dit(During dispatching) the helper is called to suggest a back + end. The arguments are an action indicator tt(dispatch), the + client's IP address, the timestamp, and four triplets that + represent back ends: per back end its name, its availability, + and its weight. The purpose of the helper is to tell + Crossroads which back end to use. + + dit(During connection start) the helper will be invoked to + inform it of the start of a connection, given a client IP + address. + + dit(When a connection terminates) the helper will be invoked + to inform it that the connection has ended.) + +Here's the external handler as Perl script. It uses the module +tt(GDBM_File) which most likely will not be part of standard Perl +distributions, but can be added using CPAN. (Alternatively, any other +database module can be used.) + +verb(\ +#!/usr/bin/perl + +use strict; +use GDBM_File; + +# Global variables and configuration +# ---------------------------------- +my $log = '/tmp/exthandler.log'; # Debug log, set to /dev/null to suppress +my $cdb = '/tmp/client.db'; # GDBM database of clients +my %db; # .. and memory representation of it +my $timeout = 24*60*60; # Timeout of a connection in secs + +# Logging +# ------- +sub msg { + return if ($log eq '/dev/null' or $log eq ''); + open (my $of, ">>$log") or return; + print $of (scalar(localtime()), ' ', @_); + close ($of); +} + +# Reply a back end to the caller and stop processing. +# --------------------------------------------------- +sub reply ($) { + my $b = shift; + msg ("Suggesting $b to Crossroads.\n"); + print ("$b\n"); + exit (0); +} + +# Is a value in an array +# ---------------------- +sub inarray { + my $val = shift; + for my $other (@_) { + return (1) if ($other eq $val); + } + return (0); +} + +# A connection is starting +# ------------------------ +sub start { + my ($ip, $stamp, $backend) = @_; + msg ("Logging START of connection for IP $ip on stamp $stamp, ", + "back end $backend\n"); + $db{$ip} = "$backend:$stamp"; +} + +# A connection has ended +# ---------------------- +sub end { + my $ip = shift; + msg ("Logging END of connection for IP $ip\n"); + $db{$ip} = undef; +} + +# Request to determine a back end +# ------------------------------- +sub dispatch { + my $ip = shift; + my $stamp = shift; + + msg ("Request to dispatch IP $ip on stamp $stamp\n"); + + # Read the next arguments. They are triplets of + # backend-name / availability / weight. Store if the back end is + # available. + my (@backends, @weights); + for (my $i = 0; $i < $#_; $i += 3) { + if ($_[$i + 1] != 0) { + push (@backends, $_[$i]); + push (@weights, $_[$i + 2]); + msg ("Candidate back end: $_[$i] with weight ", $_[$i + 2], "\n"); + } + } + + # See if this is a reconnect by a previously seen client IP. We'll + # treat this as a reconnect if the timeout wasn't yet exceeded. + if ($db{$ip} ne '') { + my ($last_backend, $last_stamp) = split (/:/, $db{$ip}); + msg ("IP $ip had last connected on $last_stamp to $last_backend\n"); + if ($stamp < $last_stamp + $timeout) { + msg ("Timeout not yet exceeded, this may be a reconnect\n"); + # We'll allow a reconnect only if the stated last_backend is + # free (sanity check). + if (inarray ($last_backend, @backends)) { + msg ("Last back end $last_backend is available, ", + "letting through\n"); + reply ($last_backend); + } else { + msg ("Last used back end isn't free, suggesting a new one\n"); + } + } else { + msg ("Timeout exceeded, suggesting a new back end\n"); + } + } else { + msg ("Np preveious connection data, suggesting a new back end\n"); + } + + my $bestweight = -1; + my $bestbackend; + for (my $i = 0; $i <= $#weights; $i++) { + if ($bestweight == -1 or $bestweight > $weights[$i]) { + $bestweight = $weights[$i]; + $bestbackend = $backends[$i]; + } + } + + msg ("Best back end: $bestbackend (given weight $bestweight)\n"); + reply ($bestbackend); +} + +# Main starts here +# ---------------- +msg ("Start of run, attaching GDBM database '$cdb'\n"); +tie (%db, 'GDBM_File', $cdb, &GDBM_WRCREAT, 0600); + +# The first argument must be an action 'dispatch', 'start' or 'end'. +# Depending on the action, we do stuff. +my $action = shift (@ARGV); +if ($action eq 'dispatch') { + dispatch (@ARGV); +} elsif ($action eq 'start') { + start (@ARGV); +} elsif ($action eq 'end') { + end (@ARGV); +} else { + print STDERR ("Usage: rdp-helper {dispatch|start|end} args\n"); + exit (1); +}) diff --git a/doc/tips/howselected.yo b/doc/tips/howselected.yo @@ -0,0 +1,179 @@ +In order to tune your load balancing, you'll need to understand how +crossroads computes usage, how weighing works, and so on. In this +section we'll focus on the dispatching modes tt(bysize), tt(byduration) +and tt(byconnections) only. The other dispatching types are +self-explanatory. + + +subsubsect(Bysize, byduration or byconnections?) + +As stated before, crossroads doesn't know 'what a service does' and +how to judge whether a given back end is very busy or not. You +must therefore give the right hints: + +itemization( + it() In general, a service which is CPU bound, will be more + busy when it takes longer to process a request. The dispatch + mode tt(byduration) is appropriate here. + + it() In contrast, a service which is filesystem bound, will be + more busy when more data are transferred. The dispatch mode + tt(bysize) is apppropriate. + + it() The dispatch mode tt(byduration) can also be used when + network latency is an issue. E.g., if your balancer has back + ends that are geograpically distributed, then tt(byduration) + would be a good way to select best available back ends. + + it() Furthermore it is noteworthy that tt(dispatchmode + byduration) is not usable for interactive processes such as + SSH logins. Idle time of a + login adds to the duration, while causing (almost) no + load. Mode tt(byduration) should only be used for automated + processes that don't wait for user interaction (e.g., SOAP + calls and other HTTP requests). + + it() As a last remark, the dispatching mode tt(byconnections) can + be used if you don't have other clues for load + estimations. + + E.g., consider a database connection. What's + heavier on the back end, time-consuming connections, or connections + where loads of bytes are transferred? Well, that depends. A + tough tt(select) query that joins multiple tables can be very + heavy on the back end, though the response set can be quite + small - and hence the number of + transferred bytes. That would suggest + dispatching by duration. However, tt(byduration) + balancing doesn't respresent the true world, when interactive + connections can occur where users have an idle TCP connection to + the database: + this consumes time, but no bytes (see the SSH login example + above). In this case, the dispatch mode tt(byconnections) may be + your best bet. + + ) + + +subsubsect(Averaging size and duration) + +The configuration statement tt(dispatchmode bysize) or tt(byduration) +allows an optional modifier tt(over) em(number), where the stated +number represents a connection count. When this modifier is present, then +crossroads will use a moving average over the last em(n) connections to +compute duration and size figures. + +In the real world you'll always want this modifier. E.g., consider two +back ends that are running for years now, and one of them is suddenly +overloaded and very busy (it experiences a 'spike' in activity). +When the tt(over) modifier is absent, then +the sudden load will hardly show up in the usage figures -- it will +flatten out due to the large usage figures already stored in the years +of service. + +In contrast, when e.g. tt(over 3) is in effect, then a sudden load +does show up -- because it highly contributes to the average of three +connections. + + +subsubsect(Specifying decays) + +Decays are also only relevant when crossroads computes the 'next best +back end' by size (bytes) or duration (seconds). E.g., imagine two +back ends A and B, both averaged over say 3 connections. + +Now when back end A is suddenly hit by a spike, +its average would go up accordingly. But the back end would never +again be used, unless B also received a similar spike, because A's +'usage data' over its last three connections would forever be larger than +B's data. + +For that reason, you should in real situations probably always +specify a decay, so that the backend selection algorithm recovers from +spikes. Note that the usage data of the back end where a decay is +specified, decay when bf(other) back ends are hit. The decay parameter +is like specifying how fast your body regenerates when someone else +does the work. + +The below configuration illustrates this: + +verb(\ +/* Definition of the service */ +service soap { + /* Local TCP port */ + port 8080; + + /* We'll select back ends by the processing + * duration + */ + dispatchmode byduration over 3; + + /* First back end: */ + backend A { + /* Back end IP address and port */ + server 10.1.1.1:8080; + + /* When this back end is NOT hit because + * the other one was less busy, then the + * usage parameters decay 10% per connection + */ + decay 10; + } + + /* Second back end: */ + backend B { + server 10.1.1.2:8080; + decay 10; + } +}) + +subsubsect(Adjusting the weights) + +The back end modifier tt(weight) is useful in situations where your +back ends differ in respect to performance. E.g,. your back ends may +be geographically distributed, and you know that a given back end is +difficult to reach and often experiences network lag. + +Or you may have +one primary back end, a system with a fast CPU and enough memory, and a +small fall-back back end, with a slow CPU and short on memory. In that +case you know in advance that the second back end should be used only +rarely. Most requests should go to the big server, up to a certain load. + +In such cases you will know in advance that the best performing back ends +should be selected the most often. Here's where the tt(weight) +statement comes in: you can simply increase the weight of the back +ends with the least performance, so that they are selected less +frequently. + +E.g., consider the following configuration: + +verb(\ +service soap { + port 8080; + dispatchmode byduration over 3; + backend A { + server 10.1.1.1:8080; + decay 20; + } + backend B { + server 10.1.1.2:8080; + weight 2; + decay 10; + } + backend C { + server 10.1.1.3:8080; + weight 4; + decay 5; + } +}) + +This will cause crossroads to select back ends by the processing time, +averaging over the last three connections. However, backend B will kick +in only when its usage is half of the usage of A (back end B is +probably only half as fast as A). Backend C will kick in only when its +usage is a quarter of the usage of A, which is half of the usage of B +(back end C is probably very weak, and just a fall-back system incase +both A and B crash). Note also that A's usage data decay much faster +than B's and C's: we're assuming that this big server recovers quicker +than its smaller siblings. diff --git a/doc/tips/httpstickiness.yo b/doc/tips/httpstickiness.yo @@ -0,0 +1,110 @@ +This section focuses on HTTP session stickiness. This term refers to +the ability of a balancer to route a conversation between browser and +a backend farm with webservers always to the same back end. In other +words: once a back end is selected by the balancer, it will remain the +back end of choice, even for subsequent connections. + +subsubsect(Don't use stickiness!) + +The rule of thumb as far as the balancer is concerned, is: bf(Do not +use HTTP session stickiness unless you really have to.) Enabling +session stickiness hampers failover, balancing and performance: + +itemization( + it() Failover is hampered because during the session, + the balancer has to assign new connections to the same back + end that was selected at the start of a session. If the back + end suddenly goes 'down', then the session will most likely + crash. (Actually, when a back end becomes unreachable in the + middle of a session, Crossroads will assign a new back end to + that session. This will most likely result in a malfunction + of the underlying application.) + it() Balancing is hampered because at the start of the session, + the balancer has selected the next-best back end. But during + the session, that back end may well become overloaded. The + balancer however must continue to send the requests there. + it() Performance is hampered because crossroads needs to 'unpack' + messages as they are passed to and fro. That's because + crossroads needs to check the HTTP headers in the messages + for persistence cookies.) + +There is a number of measures that you can take to avoid using session +stickiness. E.g., session data can be 'shared' between web back +ends. PHP offers functionality to store session data in a database, so +that all PHP applications have access to these data. Application +servers such as Websphere can be configured to replicate session data +between nodes. + +subsubsect(But if you must..) + +If you really need stickiness, think first whether you might use TCP +stickiness (using the client's IP address to dispatch). If you can, +then this is the preferred method, since Crossroads won't have to +unpack TCP streams. Below is a short configuration example: + +verb(\ +service www { + port 80; + type any; + revivinginterval 15; + dispatchmode byclientip; + + backend one { + server 10.1.1.100:80; + } + + backend two { + server 10.1.1.101:80; + } +}) + + +However, if you bf(must) use HTTP-base session stickiness, then +proceed as follows: + +itemization( + it() At the level of a tt(service) description, set the type to + tt(http). + it() At the level of each back end description, configure the + tt(stickycookie) and a tt(addclientheader) directives.) + +Once crossroads sees that, it will examine each HTTP message that it +shuttles between client and back end: + +itemization( + it() If there is no persistence cookie in the HTTP headers of a + client's request, then the message must be the first one and + a new session should be established. + Crossroads selects an appropriate back + end, sends the message to that back end, catches the reply, + and inserts a tt(Set-Cookie) directive. + it() If there is a persistence cookie in the HTTP headers of a + client's request, then the request is part of an already + established session. Crossroads analyzes the cookie and + forwards the request to the appropriate back end.) + +Below is a short example of a configuration. + +verb(\ +service www { + port 80; + type http; + revivinginterval 15; + dispatchmode byconnections; + + backend one { + server 10.1.1.100:80; + stickycookie XRID=100; + addclientheader "Set-Cookie: XRID=100; Path=/"; + } + + backend two { + server 10.1.1.101:80; + stickycookie XRID=101; + addclientheader "Set-Cookie: XRID=101; Path=/"; + } +}) + +Note how the cookie names and values in the directives +tt(stickycookie) and tt(addclientheader) match. That is obviously a +prerequisite for stickiness. diff --git a/doc/tips/ipconntrackmax.yo b/doc/tips/ipconntrackmax.yo @@ -0,0 +1,35 @@ +The kernel value of tt(ip_conntrack_max) is important for routers and +balancers under Linux. Basically it's the maximum number of tracked +connections. Felix A.W.O. describes the following situation: + +itemization( + it() Crossroads seems to mark back ends as unavailable, while + in fact nothing is afoot. + it() This happens under heavy load. + it() In tt(/var/log/messages) one may see the message: + tt(kernel: ip_conntrack: table full, dropping packet).) + +The reason for Crossroad's behavior is that the kernel refuses to +build up a requested network connection. For Crossroads, this looks +just as a non-responding back end. Crossroads therefore marks the back +end as unavailable. + +The solution is as follows: + +itemization( + it() Try tt(cat /proc/sys/net/ipv4/ip_conntrack_max) to see + the current value. + it() Add something to the shown value (e.g., multiply by two), + and inform + the kernel of the new value, using tt(echo) (new-value) tt(> + /proc/sys/net/ipv4/ip_conntrack_max) + it() Make sure that the same step occurs somewhere in your + boot sequence as well, or that the new valueit is stated in a + configuration + file such as tt(/etc/sysctl.conf).) + +The value for em(new-value) is something that you'll have to figure +out yourself. Note however that each count will cause the kernel to +reserve 350 bytes. So if you set tt(ip_conntrack_max) to 100.000, then +you're already taking 33.3Mb off the total available memory. + diff --git a/doc/tips/ipfiltering.yo b/doc/tips/ipfiltering.yo @@ -0,0 +1,122 @@ +subsubsect(General Examples) + +The directives tt(allowfrom), tt(denyfrom), tt(allowfile) and +tt(denyfile) can be used to instruct Crossroads to specifically allow +access by using a "whitelist" of IP addresses, or to specifically deny +access by using a "blacklist". E.g., the following configuration +allows access to service tt(webproxy) only to em(localhost): + +verb(\ +service webproxy { + port 8000; + allowfrom 127.0.0.1; + backend one { + . + . Back end definitions occur here + . + } + . + . Other back ends or other service directives + . may occur here + . +}) + +In this example there is a "whitelist" having only one entry: IP +address 127.0.0.1, or em(localhost). (Incidentally, the same behaviour +could be accomplished by stating em(bindto 127.0.0.1), in which case +Crossroads would only listen to the local network device.) + +In the same vein, the directive tt(allowfrom 127.0.0.1 192.168.1/24) +would allow access to em(localhost) and to all IP addresses that start +with 192.168.1. The specifier tt(192.168.1/24) states that there are +three network bytes (192, 168 and 1), and 24 bits (or 3 bytes) are +relevant; so that the fourth network byte doesn't matter. + +subsubsect(Using External Files) + +The directives tt(allowfile) and tt(denyfile) allow you to specify IP +addresses in external files. The Crossroads configuration states +e.g. tt(allowfile /tmp/allow.txt), and the IP addresses are then in +tt(/tmp/allow.txt). The format of tt(/tmp/allow.txt) is as follows: + +itemization( + it() The specifications follow again em(p.q.r.s/mask), where + p, q, r and s are network bytes which can be left out on the + right hand side when the mask allows it; + + it() The specifications must be separated by white space + (spaces, tabs or newlines).) + +E.g., the following is a valid example of an external specification +file: + +verb(\ +127.0.0.1 +192.168.1/24 +10/8) + +When external files are in effect, then the signal tt(SIGHUP) (1) +causes Crossroads to reload the external file. E.g., while Crossroads +is running, you may edit tt(/tmp/allow.txt), and then issue tt(killall +-1 crossroads). The new contents of tt(/tmp/allow.txt) will be +reloaded. + +subsubsect(Mixing Directives) + +Crossroads allows to mix all directives in one service +description. However, some mixes are less meaningful than others. It's +up to you to take this into account. + +The following rules apply: + +itemization( + it() Blacklisting and whitelisting can be used together. When + combined, the blacklist will always be interpreted + first. E.g., consider the following directives: + + verb(\ +allowfrom 192.168.1/24 +denyfrom 192.168.1.100) + + Given the fact that the deny list is checked first, client + 192.168.1.100 won't be able to access Crossroads. Then the + allow list will be checked, stating that all clients whose IP + address starts with 192.168.1 may connect. The effect will be + that e.g., client 192.168.1.1 may connect, 192.168.1.2 may + connect too, 192.168.1.100 will be blocked, and 10.1.1.1 will + be blocked as well. + + Now consider the following directives: + + verb(\ +allowfrom 192.168.1.100 127.0.0.1 +denyfrom 192.168.1/24) + + This will first of all deny access to all IP addresses that + start with 192.168.1. So the rule that allows 192.168.1.100 + won't ever be effective. The net result will be that access + will be granted to 127.0.0.1. + + it() Blacklisting or whitelisting can be left out. + A list is considered empty when no appropriate directives + occur in tt(/etc/crossroads.conf), or when the directive + points to an empty or non-existent external file. + + it() Using tt(*from) and tt(*file) statements is allowed, but + doesn't make sense. E.g., the following configuration sample + is such a case: + + verb(\ +allowfrom 127.0.0.1 192.168.1/24 +allowfile /tmp/allow.txt) + + There is a technical reason for this. Once Crossroads + processes the tt(allowfile) directive, then the whole + whitelist is cleared (thereby removing the entries 127.0.0.1 + and 192.168.1/24), and new entries are reloaded from the + file. The net result is that the tt(allowfrom) specification + is overruled.) + +Crossroads only performs syntactic checking of the configuration. Some +of the above samples are syntactically correct, but make no semantic +sense: Crossroads doesn't warn for such situations. diff --git a/doc/tips/retries.yo b/doc/tips/retries.yo @@ -0,0 +1,41 @@ +Crossroads allows you to specify on a per-back end basis how many +retries are needed before a back end is considered unavailable. The +default is just one, meaning that after one failed connection, +Crossroads will mark a back end as unavailable (the back end may be +'revived', if you use tt(revivinginterval)). + +Increasing the number is specified using the keyword tt(retries). The +following configuration defines two back ends; the one on the IP +address 5.6.7.8 is somehow 'flaky', and Crossroads should try +connecting 3 times before crossing it off: + +verb(\ +service www { + port 80; + backend plugh { + server 1.2.3.4:80; + } + backend xyzzy { + server 5.6.7.8:80; + retries 3; + } +}) + +There may be several reasons for increasing the retries number: + +itemization( + it() The network connections to the server may spuriously + hamper, but such rare errors don't mean that the back end server is + down. + + it() The back end server is a 'slow starter' and can't handle spikes + very well. E.g., it may be a webserver which starts with only + one daemon; extra capacity is added as network connections + arrive, but adding capacity take a little time.) + +Whatever the reason, the keyword tt(retries) might be of help +here. This keyword should however be used carefully: Crossroads will +retry connecting with a small one-second delay in between. A high +tt(retries) number means also lots of one-second delays, in which time +a client is kept waiting. + diff --git a/doc/tips/tcpstickiness.yo b/doc/tips/tcpstickiness.yo @@ -0,0 +1,22 @@ +If you need to make sure that a client that once gets dispatched to a +given back end keeps re-visiting the back end, then Crossroads offers +the dispatch mode tt(byclientip). This mode will only work when each +client is seen by Crossroads with its own specific IP address; ie., +this method won't work when clients reach Crossroads through a +masquerading firewall (in which case all clients would be seen as +having the firewall's IP address). + +The tt(dispatchmode byclientip) works as follows: + +itemization( + it() The client's IP address is taken in its string + representation and 'hashed' into a number. + + it() The number is brought back to the number of available + back ends (using a modulo-operation). + + it() The result defines the back end of choice.) + +If the preferred back end is unavailable, then the action that +Crossroads takes is to dispatch as if tt(byconnections): of the +available back ends, the one with the least connections is taken. diff --git a/doc/tips/throttling.yo b/doc/tips/throttling.yo @@ -0,0 +1,27 @@ +If you suspect that your service may occasionally receive 'spikes' of +activity+footnote(which you should always assume), then it might be a +good idea to protect your service by specifying a maximum number of +concurrent connections. This protection can be specified on two levels: + +description( + dit(On the service level) a statement like tt(maxconnections + 100;) states that the service as a whole will never + service more than 100 concurrent connections. This means that + all your back ends and the crossroads balancer itself + will be protected from being overloaded. + dit(On the back end level) a statement like tt(maxconnections 10;) + states that this particular back end will never have more + than 10 concurrent connections; regardless of the overall + setting on the service level. This means that this + particular back end will be protected from being + overloaded (regardless of what other back ends may + experience).) + +The tt(maxconnections) statement, combined with a back end selection +algorithm, allows very fine granularity. The tt(maxconnections) statement +on the back end level is like a hand brake: even when you specify a +back end algorithm that would protect a given back end from being used +too much, a situation may occur where that back end is about to be +hit. A tt(maxconnections) statement on the level of that back may then +protect it. + diff --git a/doc/using.yo b/doc/using.yo @@ -38,7 +38,36 @@ itemization( screen. A good way of quicky viewing the configuration file syntax, or of getting a start for your own configuration tt(/etc/crossroads.conf). -) +) + +subsect(Status Reporting) + +The command tt(crossroads status) shows a verbose human-readable +report of how Crossroads is doing. When many services are configured, +this can be a somewhat lengthy output. If you're interested in the +overview of only one service, you can use tt(crossroads status) +em(servicename), in which case the report will only be shown for the +stated service. + +Similarly, if you're interested only in the status of a given back end +of a given service, use tt(crossroads service) em(servicename) +em(backendname). + +The flag tt(-t) causes the status overview to be abbreviated and +displayed in a parseable format. This flag can be used in automated +scripts that check how Crossroads is doing; e.g., in health checking +scripts. When tt(-t) is used, the format of the status reporter is as +follows: + +itemization( + it() Service health is reported on one line per service. + it() The first string on the line is the service name. + it() After this, a series follows of em(backendname=state), + where the back end name is the configured name of the back + end, and where state is e.g. tt(available), tt(DOWN), + tt(UNAVAILABLE), tt(WAKING). All statuses that cause + Crossroads not to use the back end are in caps. The series is + repeated for all back ends of the given service.) subsect(Logging-related options) @@ -88,4 +117,4 @@ technical reasons for this. However, external lists of allowed or denied IP addresses can be reloaded by sending a signal -1 (tt(SIGHUP)) to Crossroads. See -section ref(servicedef) for the details. -\ No newline at end of file +section ref(servicedef) for the details. diff --git a/etc/Makefile.def b/etc/Makefile.def @@ -1,9 +1,11 @@ -# Definitions for the making of.... -# crossroads. +# Definitions for the making of... Crossroads! +# Tweak the below values to your liking. Just don't uncomment anything; +# if you don't need the setting, set it to zero (for numbers) or to an +# emtpy value (for strings). # Versioning. This defines the overall version ID and must match the topmost # entry in the ChangeLog. -VER = 1.37 +VER = 1.38 # Revision version, auto-detected. REVVER = $(shell ../etc/svnrev ../ChangeLog ../etc/svnrev.txt) @@ -28,6 +30,10 @@ SLEEP_TIME = 10 # (as they should be) then keep this number small. CONNECT_TIMEOUT = 2 +# When retrying connecting to the same back end (config: retries), how +# long should we wait between trying again? +RETRY_WAIT = 1 + # The size of buffers for the copying of data between sockets. TCP_BUFSZ = 10240 @@ -46,6 +52,7 @@ endif # this too, then define as value 1. Otherwise set to zero. SET_PROC_TITLE_BY_ARGV = 1 -# Uncomment if you're on Solaris and don't want to fiddle with -# LD_LIBRARY_PATH or crle (yuk!) +# Set to some meaningful value if you're on Solaris and don't want to +# fiddle with LD_LIBRARY_PATH or crle (yuk!) # EXTRALIBS = -R/usr/ucblib +EXTRALIBS = diff --git a/etc/svnrev.txt b/etc/svnrev.txt @@ -1 +1 @@ -143 +149 diff --git a/src/Makefile b/src/Makefile @@ -14,10 +14,6 @@ $(BINDIR)/crossroads: crossroads cp crossroads $(BINDIR)/ strip $(BINDIR)/crossroads -samplerun: all - -./crossroads -c sample.conf stop - ./crossroads -c sample.conf start - textconv: usage.h proxyerror.h usage.h: usage.txt ../tools/untab usage.txt @@ -32,27 +28,31 @@ lexer.c: lexer.l parser.c: parser.y bison -d -o $@ $< -SRC = $(wildcard *.c) -OBJ = $(patsubst %.c, %.o, $(SRC)) +SRC := $(wildcard *.c) +OBJ := $(patsubst %.c, %.o, $(SRC)) objects: $(OBJ) -CC = $(shell ../tools/c-conf c-compiler) - -DEFS = -DDEFAULT_CONF=\"$(DEFAULT_CONF)\" -DMAX_BACKEND=$(MAX_BACKEND) \ - -DSHM_MASK=$(SHM_MASK) -DSLEEP_TIME=$(SLEEP_TIME) \ - -DCONNECT_TIMEOUT=$(CONNECT_TIMEOUT) -DVER=\"$(VER)/$(REVVER)\" \ - -DSET_PROC_TITLE_BY_ARGV=$(SET_PROC_TITLE_BY_ARGV) \ - -DTCP_BUFSZ=$(TCP_BUFSZ) \ - $(shell ../tools/c-conf ifheader malloc.h HAVE_MALLOC_H) \ - $(shell ../tools/c-conf ifheader stdint.h HAVE_STDINT_H) \ - $(shell ../tools/c-conf libfunction flock HAVE_FLOCK) \ - $(shell ../tools/c-conf libfunction lockf HAVE_LOCKF) \ - $(shell ../tools/c-conf libfunction strlcat HAVE_STRLCAT) \ - $(shell ../tools/c-conf libfunction sranddev HAVE_SRANDDEV) \ - $(shell ../tools/c-conf libfunction vsyslog HAVE_VSYSLOG) \ - $(shell ../tools/c-conf libfunction strcasestr HAVE_STRCASESTR) - -LIBS = $(shell ../tools/c-conf lib ucb nsl pthread socket 2>/dev/null) +CC := $(shell ../tools/c-conf c-compiler) + +LIBS := $(shell ../tools/c-conf lib ucb nsl pthread socket 2>/dev/null) + +# Compiletime defines. Remember to update show_config() when changing +# this list! +DEFS := -DDEFAULT_CONF='"$(DEFAULT_CONF)"' -DMAX_BACKEND=$(MAX_BACKEND) \ + -DSHM_MASK=$(SHM_MASK) -DSLEEP_TIME=$(SLEEP_TIME) \ + -DCONNECT_TIMEOUT=$(CONNECT_TIMEOUT) -DVER='"$(VER)/$(REVVER)"' \ + -DSET_PROC_TITLE_BY_ARGV=$(SET_PROC_TITLE_BY_ARGV) \ + -DTCP_BUFSZ=$(TCP_BUFSZ) -DRETRY_WAIT=$(RETRY_WAIT) \ + -DREVVER='"$(REVVER)"' -DBINDIR='"$(BINDIR)"' \ + -DEXTRALIBS='"$(EXTRALIBS)"' -DLIBS='"$(LIBS)"' \ + $(shell ../tools/c-conf ifheader01 malloc.h HAVE_MALLOC_H) \ + $(shell ../tools/c-conf ifheader01 stdint.h HAVE_STDINT_H) \ + $(shell ../tools/c-conf libfunction01 flock HAVE_FLOCK) \ + $(shell ../tools/c-conf libfunction01 lockf HAVE_LOCKF) \ + $(shell ../tools/c-conf libfunction01 strlcat HAVE_STRLCAT) \ + $(shell ../tools/c-conf libfunction01 sranddev HAVE_SRANDDEV) \ + $(shell ../tools/c-conf libfunction01 vsyslog HAVE_VSYSLOG) \ + $(shell ../tools/c-conf libfunction01 strcasestr HAVE_STRCASESTR) parser.o: parser.c $(CC) $(DEFS) -c -g $< @@ -77,5 +77,5 @@ clean: # Extra deps: usage.o: usage.c usage.h ../etc/Makefile.def main.o: main.c crossroads.h ../etc/Makefile.def -sampleconf.o: sampleconf.c sampleconf.h strexpandformat.o: strexpandformat.c ../etc/Makefile.def +showconfig.o: showconfig.c ../etc/Makefile.def Makefile +\ No newline at end of file diff --git a/src/allocreporter.c b/src/allocreporter.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/ansistamp.c b/src/ansistamp.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/backendavailable.c b/src/backendavailable.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/backendconnect.c b/src/backendconnect.c @@ -1,29 +1,24 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ #include "crossroads.h" -static jmp_buf jmpbuf; -static int timeout; +static int timed_out; static void alarmhandler (int sig) { - alarm(0); - timeout++; - if (program_stage != stage_retrying) - msg ("Service %s: Alarm went off while connecting to back end", - activeservice->name); - longjmp (jmpbuf, 1); + timed_out++; } - int backend_connect () { - int backend_sock; + int sock; struct sockaddr_in servername; + int val = 1; - if ( (backend_sock = socket (PF_INET, SOCK_STREAM, 0)) < 0 ) { + /* Create the socket. */ + if ( (sock = socket (PF_INET, SOCK_STREAM, 0)) < 0 ) { if (program_stage != stage_retrying) { error ("Service %s: failed to create socket " "for backend communication: %s", @@ -35,7 +30,19 @@ int backend_connect () { return (-1); } } + +#ifdef SO_NOSIGPIPE + /* Make sure we don't get SIGPIPE's on it. Not supported on all + * platforms. */ + if (setsockopt (sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val))) { + warning ("Service %s: cannot set backend socket options " + "(nosigpipe): %s", activeservice->name, strerror(errno)); + close (sock); + return (-2); + } +#endif + /* Assign to back end server address. */ if (init_sockaddr (&servername, activeservice->backend[current_backend].server, activeservice->backend[current_backend].port)) { @@ -43,69 +50,59 @@ int backend_connect () { warning ("Service %s: unknown host %s", activeservice->name, activeservice->backend[current_backend].server); + close (sock); mark_activity (0, 0, st_unavailable); - return (-2); + return (-3); } if (program_stage != stage_retrying) - msg ("Service %s: Network socket to %s:%d initialized", + msg ("Service %s: Network socket to %s:%d created", activeservice->name, activeservice->backend[current_backend].server, activeservice->backend[current_backend].port); + /* If retrying, delay a bit */ + if (servicereport->backendstate[current_backend].fail > 0) { + msg ("Service %s: Seen %d retries, waiting a bit", + activeservice->name, + servicereport->backendstate[current_backend].fail); + sleep (RETRY_WAIT); + } + + /* Set up the connect interruption */ signal (SIGALRM, alarmhandler); - timeout = 0; + timed_out = 0; alarm (CONNECT_TIMEOUT); - if (!setjmp (jmpbuf)) { - /* First time around, try connecting */ - if (connect (backend_sock, (struct sockaddr *) &servername, - sizeof(servername)) < 0) { - /* This backend is unusable. - * Either connect() has failed (connection refused) or it got - * interrupted by the SIGALRM - */ - close (backend_sock); - alarm(0); - signal (SIGALRM, SIG_DFL); - - if (timeout) { - if (program_stage != stage_retrying) - warning ("Service %s: server %s:%d not usable" - " due to timeout", - activeservice->name, - activeservice->backend[current_backend].server, - activeservice->backend[current_backend].port); - } else { - if (program_stage != stage_retrying) - warning ("Service %s: server %s:%d: cannot connect: %s", - activeservice->name, - activeservice->backend[current_backend].server, - activeservice->backend[current_backend].port, - strerror(errno)); - } - mark_activity (0, 0, st_unavailable); - return (-3); - } else { - msg ("Service %s: connection to back end %s succeeded", - activeservice->name, - activeservice->backend[current_backend].server); - } - } else { - /* Got here because of longjmp from the signal handler, - * this MUST be a timeout + /* Try connecting */ + if (connect (sock, (struct sockaddr *) &servername, + sizeof(servername)) < 0) { + /* This backend is unusable. + * Either connect() has failed (connection refused) or it got + * interrupted by the SIGALRM, or another signal went off. */ - if (program_stage != stage_retrying) - warning ("Service %s: Server %s not usable due to timeout", - activeservice->name, - activeservice->backend[current_backend].server); - close (backend_sock); + close (sock); alarm(0); signal (SIGALRM, SIG_DFL); + + if (program_stage != stage_retrying) { + if (timed_out) + warning ("Service %s: server %s:%d not usable" + " due to timeout", + activeservice->name, + activeservice->backend[current_backend].server, + activeservice->backend[current_backend].port); + else + warning ("Service %s: server %s:%d: cannot connect: %s", + activeservice->name, + activeservice->backend[current_backend].server, + activeservice->backend[current_backend].port, + strerror(errno)); + } mark_activity (0, 0, st_unavailable); - return (-4); + return (-3); } - alarm(0); signal (SIGALRM, SIG_DFL); - return (backend_sock); + return (sock); } + diff --git a/src/backendcount.c b/src/backendcount.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/choosebackend.c b/src/choosebackend.c @@ -1,8 +1,9 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ + #include "crossroads.h" void choose_backend () { @@ -14,7 +15,7 @@ void choose_backend () { char *exthandler; FILE *f; char buf[80]; -# ifndef HAVE_SRANDDEV +# if HAVE_SRANDDEV == 0 struct timeval tv; # endif @@ -113,7 +114,7 @@ void choose_backend () { case ds_random: /* Re-randomize. */ -# ifdef HAVE_SRANDDEV +# if HAVE_SRANDDEV == 1 sranddev(); msg ("Service %s: randomier seeded with randdev", activeservice->name); # else diff --git a/src/configtest.c b/src/configtest.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/copysockets.c b/src/copysockets.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/createcommandlinespace.c b/src/createcommandlinespace.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/crossroads.h b/src/crossroads.h @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ @@ -10,7 +10,7 @@ #include <errno.h> #include <fcntl.h> #include <netdb.h> -#ifdef HAVE_MALLOC_H +#if HAVE_MALLOC_H == 1 #include <malloc.h> #endif #include <math.h> @@ -20,7 +20,7 @@ #include <stdarg.h> #include <stdio.h> #include <stdlib.h> -#ifdef HAVE_STDINT_H +#if HAVE_STDINT_H == 1 #include <stdint.h> #endif #include <string.h> @@ -256,7 +256,7 @@ typedef struct { /* Numeric state to string map */ EXTERN Service *activeservice; /* target service of a daemon */ EXTERN unsigned char *clbuf; /* client socket input buffer */ -EXTERN unsigned clbufpos, clbufmax; /* .. position & bytes */ +EXTERN int clbufpos, clbufmax; /* .. position & bytes */ EXTERN char *client_ip; /* connected client */ EXTERN char *config_file; /* config to parse */ EXTERN int current_backend; /* of a given service */ @@ -275,12 +275,13 @@ EXTERN int org_argc; /* original argc */ EXTERN char **org_argv; /* and original argv */ EXTERN Programstage program_stage; /* stage of the program */ EXTERN int relevant_sigs[]; /* relevant signals */ +EXTERN int reload_allow_deny; /* flag to reload spec files */ EXTERN int semid; /* semaphore ID */ EXTERN Service *service; /* service descriptions */ EXTERN Servicereport *servicereport; /* reporter in shared mem */ EXTERN int sloppyportbind; /* -s flag present */ EXTERN unsigned char *srbuf; /* server socket input buffer */ -EXTERN unsigned srbufpos, srbufmax; /* .. position & bytes */ +EXTERN int srbufpos, srbufmax; /* .. position & bytes */ EXTERN StateStringMap /* state/string map */ statestringmap[]; /* .. and vv */ EXTERN int tabular_status; /* -t: tabular status overview */ @@ -327,7 +328,7 @@ extern void http_header_write (HttpHeader *m, int sock, CopyDirection dir); extern void http_serve (int clientsock); extern int http_serversocket (HttpHeader *m, int *is_continuation); extern int http_write (int sock, CopyDirection dir, unsigned char const *buf, - unsigned buflen); + int buflen); extern void incr_client_count (void); extern int init_sockaddr (struct sockaddr_in *name, const char *hostname, int port); @@ -351,20 +352,21 @@ extern void mark_activity (double nbytes, double nsec, Backendavail newstate); extern void msg (char const *fmt, ...) __attribute__ ((format (printf, 1, 2))); extern void msgdumpbuf (unsigned char const *buf, int buflen); -extern unsigned net_copy (int clientsock, int serversock, unsigned maxbytes, +extern int net_copy (int clientsock, int serversock, int maxbytes, unsigned char *buf); -extern unsigned net_read (int sock, unsigned maxbytes, unsigned char *buf, - int is_client); -extern unsigned char *net_buffer (CopyDirection dir, unsigned *sz); -extern unsigned char *net_bufread (int sock, unsigned maxbytes, - unsigned *nreadp, int is_client); -extern unsigned net_write (int sock, unsigned char const *buf, unsigned len, - int is_client); +extern int net_read (int sock, int maxbytes, unsigned char *buf, + int is_client); +extern unsigned char *net_buffer (CopyDirection dir, int *sz); +extern unsigned char *net_bufread (int sock, int maxbytes, + int *nreadp, int is_client); +extern int net_write (int sock, unsigned char const *buf, int len, + int is_client); extern int restart (int ac, char **av); extern void runservice (void); extern int serve (int ac, char **av); extern void set_program_title (char const *fmt, ...) __attribute__ ((format (printf, 1, 2))); +extern void show_config (void); extern int show_services (int ac, char **av); extern int show_status (int ac, char **av); extern char *stage_to_string (Programstage stage); @@ -397,16 +399,16 @@ extern char *xstrcatch (char *what, char ch); extern char *xstrdup (char const *what); /* strlcat() if it's missing on this system */ -#ifndef HAVE_STRLCAT +#if HAVE_STRLCAT == 0 extern size_t strlcat (char *dst, char const *src, size_t size); #endif /* vsyslog() if it's missing on this system */ -#ifndef HAVE_VSYSLOG +#if HAVE_VSYSLOG == 0 extern void vsyslog (int fac, char const *fmt, va_list args); #endif /* strcasestr() if it's missing on this system */ -#ifndef HAVE_STRCASESTR +#if HAVE_STRCASESTR == 0 extern char *strcasestr (char const *big, char const *little); #endif diff --git a/src/deallocreporter.c b/src/deallocreporter.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/decrclientcount.c b/src/decrclientcount.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ @@ -13,24 +13,31 @@ void decr_client_count () { if (program_stage != stage_serving) return; - if (servicereport->backendstate[current_backend].nclients > 0) { - lock_reporter(); + lock_reporter(); + + for (i = 0; i < activeservice->nbackend; i++) + totclients += servicereport->backendstate[i].nclients; + servicereport->nclients = totclients; + msg ("Service %s: total active clients now %u", + activeservice->name, totclients); + + /* Warning: Use current_backend as index only if >= 0; it + * may be -1 when still searching for an HTTP back end */ + if (current_backend >= 0 && + servicereport->backendstate[current_backend].nclients > 0) servicereport->backendstate[current_backend].nclients--; - for (i = 0; i < activeservice->nbackend; i++) - totclients += - servicereport->backendstate[i].nclients; - servicereport->nclients = totclients; - msg ("Service %s: total active clients now %u", - activeservice->name, totclients); - unlock_reporter(); - } - msg ("Service %s: extcmd-onend: " - " current_backend = %d, clients = %d, totclients = %d, cmd = %s", - activeservice->name, current_backend, - servicereport->backendstate[current_backend].nclients, - servicereport->nclients, - activeservice->backend[current_backend].onend); + unlock_reporter(); - sysrun (activeservice->backend[current_backend].onend); -} + if (current_backend >= 0) { + msg ("Service %s: extcmd-onend: " + " current_backend = %d, clients = %d, " + "totclients = %d, cmd = %s", + activeservice->name, current_backend, + servicereport->backendstate[current_backend].nclients, + servicereport->nclients, + activeservice->backend[current_backend].onend); + + sysrun (activeservice->backend[current_backend].onend); + } +} diff --git a/src/error.c b/src/error.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/forktcpservicer.c b/src/forktcpservicer.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/hashpjw.c b/src/hashpjw.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/httpcopy.c b/src/httpcopy.c @@ -1,12 +1,12 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ #include "crossroads.h" -static void copy (int src, int dst, int dir, unsigned tot) { - unsigned ncopied = 0, to_copy, bytes; +static void copy (int src, int dst, int dir, int tot) { + int ncopied = 0, to_copy, bytes; unsigned char *buf; while (ncopied < tot) { diff --git a/src/httperror.c b/src/httperror.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/httpheaderaddheader.c b/src/httpheaderaddheader.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/httpheaderappendheader.c b/src/httpheaderappendheader.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/httpheaderconnectiontype.c b/src/httpheaderconnectiontype.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/httpheaderfree.c b/src/httpheaderfree.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/httpheaderhascookie.c b/src/httpheaderhascookie.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ @@ -9,7 +9,7 @@ int http_header_hascookie (HttpHeader *m, char const *cookie) { unsigned char const *val; char *cp, *buf; - if (!cookie) + if (!cookie || !*cookie) return (0); if (! (val = http_header_val (m, "cookie")) ) { msg ("Service %s: no cookies in HTTP message", activeservice->name); diff --git a/src/httpheaderhttpver.c b/src/httpheaderhttpver.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/httpheadernew.c b/src/httpheadernew.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/httpheaderread.c b/src/httpheaderread.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/httpheaderremoveheader.c b/src/httpheaderremoveheader.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/httpheadersetheader.c b/src/httpheadersetheader.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/httpheaderval.c b/src/httpheaderval.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/httpheaderwrite.c b/src/httpheaderwrite.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/httpinsertheader.c b/src/httpinsertheader.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/httpserve.c b/src/httpserve.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ @@ -10,7 +10,7 @@ void http_serve (int clientsock) { HttpHeader *clientreq, *serverresp; int client_persisting, server_persisting; unsigned char *cp; - unsigned size; + int size; /* Fork off a servicer if we're in daemon mode. */ if (fork_tcp_servicer(-1)) diff --git a/src/httpserversocket.c b/src/httpserversocket.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/httpwrite.c b/src/httpwrite.c @@ -1,13 +1,13 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ #include "crossroads.h" int http_write (int sock, CopyDirection dir, unsigned char const *buf, - unsigned buflen) { - unsigned nwritten, totwritten = 0; + int buflen) { + int nwritten, totwritten = 0; while (totwritten < buflen) { nwritten = net_write (sock, buf + totwritten, buflen - totwritten, diff --git a/src/incrclientcount.c b/src/incrclientcount.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/initsockaddr.c b/src/initsockaddr.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/interrupt.c b/src/interrupt.c @@ -1,75 +1,55 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ #include "crossroads.h" -/* Signal handler */ +/* Signal handler. NOTE - don't use non-reentrant functions in code + * that doesn't exit! */ void interrupt (int sig) { - msg ("Caught signal %d", sig); - - /* SIGHUP (1) is handled differently, it will reload the allow- and - * deny files when in waiting mode. In other modes it will be ignored. */ - if (sig == SIGHUP) { - if (program_stage == stage_waiting) { - if (ipf_loadfile (activeservice->allowfile, - &(activeservice->allowchain), - &(activeservice->nallowchain))) - warning ("Bad syntax in allow file"); - if (ipf_loadfile (activeservice->denyfile, - &(activeservice->denychain), - &(activeservice->ndenychain))) - warning ("Bad syntax in deny file"); - } - msg ("Service %s: allow chain has %d entries, " - "deny chain has %d entries", activeservice->name, - activeservice->nallowchain, activeservice->ndenychain); - return; - } + switch (sig) { - /* SIGPIPE(13) is handled differently incase of stage_serving. One - * of the network connections has disappeared, there's no use in - * continuing. */ - if (sig == SIGPIPE && program_stage == stage_serving) { - msg ("Service %s: servicer caught SIGPIPE, stopping now", - activeservice->name); - decr_client_count(); - _exit (0); - } + case SIGHUP: + /* Reload allow/deny files upon next loop */ + reload_allow_deny++; + break; - /* For all other signals: flag that we're signalled, and depending on - * the stage, exit right away or wait 'till the servicer stops. */ - - interrupted++; - - switch (program_stage) { - case stage_waiting: - warning ("Service %s: listener caught signal %d, " - "closing socket %d and exiting", - activeservice->name, sig, listen_sock); - if (shutdown (listen_sock, SHUT_RDWR)) - error ("Service %s: can't shut down server-side socket %d: %s", - activeservice->name, listen_sock, strerror(errno)); - if (close (listen_sock)) - error ("Service %s: can't close socket %d: %s", - activeservice->name, listen_sock, strerror(errno)); - _exit (0); - case stage_serving: - warning ("Service %s: servicer caught signal %d, " - "will exit after servicing my connection", - activeservice->name, sig); + case SIGPIPE: + /* SIGPIPE shouldn't happen, the sockets are set up not to + * generate this. Incase it does: ignore, the next read/write + * will stop. */ break; - case stage_retrying: - warning ("Service %s: wakeup handler caught signal %d, " - "stopping wake ups and exiting", - activeservice->name, sig); - exit (0); + default: - msg ("Caught signal %d in program stage %s, exiting", sig, - stage_to_string (program_stage)); - _exit (0); + interrupted++; + + switch (program_stage) { + case stage_waiting: + warning ("Service %s: listener caught signal %d, " + "closing socket %d and exiting", + activeservice->name, sig, listen_sock); + shutdown (listen_sock, SHUT_RDWR); + close (listen_sock); + exit (0); + break; + + case stage_serving: + /* This will serve the current connection and then stop. */ + break; + + case stage_retrying: + warning ("Service %s: wakeup handler caught signal %d, " + "stopping wake ups and exiting", + activeservice->name, sig); + exit (0); + + default: + msg ("Caught signal %d in program stage %s, exiting", sig, + stage_to_string (program_stage)); + exit (0); + } } } diff --git a/src/ipfaddallow.c b/src/ipfaddallow.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/ipfadddeny.c b/src/ipfadddeny.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/ipfallowed.c b/src/ipfallowed.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/ipfdenied.c b/src/ipfdenied.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/ipfloadfile.c b/src/ipfloadfile.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/ipfmatch.c b/src/ipfmatch.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/ipfparse.c b/src/ipfparse.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/ishexdigit.c b/src/ishexdigit.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/isspace.c b/src/isspace.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/lexer.c b/src/lexer.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/lockreporter.c b/src/lockreporter.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/logactivityany.c b/src/logactivityany.c @@ -1,12 +1,12 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ #include "crossroads.h" void log_activity_any (char const *action) { - if (!log_activity) + if (!log_activity || current_backend < 0) return; if (!logstarted++) openlog ("crossroads", LOG_PID, log_facility); diff --git a/src/logactivitycontinuation.c b/src/logactivitycontinuation.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/logactivityend.c b/src/logactivityend.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/logactivitystart.c b/src/logactivitystart.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/main.c b/src/main.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ @@ -45,8 +45,9 @@ int main (int argc, char **argv) { unsigned i; static Handler handler[] = { /* Argument Nr.args Needconf Handler function */ + /* -1=no check */ { "services", 0, 1, show_services }, - { "status", 0, 1, show_status }, + { "status", -1, 1, show_status }, { "stop", 0, 1, stop_daemon }, { "start", 0, 1, serve }, { "restart", 0, 1, restart }, @@ -60,7 +61,7 @@ int main (int argc, char **argv) { /* Parse options. */ config_file = DEFAULT_CONF; - while ( (opt = getopt (argc, argv, "?c:fhvi:Val:st")) > 0 ) + while ( (opt = getopt (argc, argv, "?c:fhvi:Val:stC")) > 0 ) switch (opt) { case 'a': log_activity++; @@ -110,6 +111,9 @@ int main (int argc, char **argv) { case 't': tabular_status++; break; + case 'C': + show_config(); + exit (0); case 'V': puts (VER); exit (0); @@ -130,7 +134,8 @@ int main (int argc, char **argv) { * scan the configuration (if needed) and GO! */ if (!strcmp (argv[optind], handler[i].arg) && - handler[i].narg == argc - optind - 1) { + (handler[i].narg == -1 || + handler[i].narg == argc - optind - 1)) { if (handler[i].needconf) { msg ("Parsing configuration %s", config_file); if (! (yyin = fopen (config_file, "r")) ) diff --git a/src/makesocket.c b/src/makesocket.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ @@ -17,12 +17,20 @@ int make_socket (int port, char const *ipaddr) { return (-1); } if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) { - warning ("Service %s: cannot set socket options: %s", + warning ("Service %s: cannot set socket options (reuseaddr): %s", activeservice->name, strerror(errno)); close (sock); return (-2); } - +#ifdef SO_NOSIGPIPE + if (setsockopt (sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val))) { + warning ("Service %s: cannot set socket options (nosigpipe): %s", + activeservice->name, strerror(errno)); + close (sock); + return (-2); + } +#endif + /* Give the socket a name. */ name.sin_family = AF_INET; name.sin_port = htons (port); diff --git a/src/markactivity.c b/src/markactivity.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ @@ -32,52 +32,56 @@ void mark_activity (double nbytes, double nsec, } else if (newstate == st_available) servicereport->backendstate[current_backend].fail = 0; - /* Handle the decays of all other back ends */ - for (i = 0; i < activeservice->nbackend; i++) { - if (i != current_backend && activeservice->backend[i].decay) { - if (activeservice->dispatchover) { - servicereport->backendstate[i].avg_nbytes *= - (100 - activeservice->backend[i].decay); - servicereport->backendstate[i].avg_nbytes /= 100; - servicereport->backendstate[i].avg_nsec *= - (100 - activeservice->backend[i].decay); - servicereport->backendstate[i].avg_nsec /= 100; - } else { - servicereport->backendstate[i].nbytes *= - (100 - activeservice->backend[i].decay); - servicereport->backendstate[i].nbytes /= 100; - servicereport->backendstate[i].nsec *= - (100 - activeservice->backend[i].decay); - servicereport->backendstate[i].nsec /= 100; + if (program_stage != stage_retrying) { + /* Handle the decays of all other back ends */ + for (i = 0; i < activeservice->nbackend; i++) { + if (i != current_backend && activeservice->backend[i].decay) { + if (activeservice->dispatchover) { + servicereport->backendstate[i].avg_nbytes *= + (100 - activeservice->backend[i].decay); + servicereport->backendstate[i].avg_nbytes /= 100; + servicereport->backendstate[i].avg_nsec *= + (100 - activeservice->backend[i].decay); + servicereport->backendstate[i].avg_nsec /= 100; + } else { + servicereport->backendstate[i].nbytes *= + (100 - activeservice->backend[i].decay); + servicereport->backendstate[i].nbytes /= 100; + servicereport->backendstate[i].nsec *= + (100 - activeservice->backend[i].decay); + servicereport->backendstate[i].nsec /= 100; + } } } - } - - /* Update average seconds and bytes. */ - if (activeservice->dispatchover) { - multiplier = activeservice->dispatchover - 1; - if (servicereport->backendstate[current_backend].totuses < multiplier) - multiplier = servicereport->backendstate[current_backend].totuses; - dlval = servicereport->backendstate[current_backend].avg_nsec; - dlval *= multiplier; - dlval += nsec; - dlval /= (multiplier + 1); - servicereport->backendstate[current_backend].avg_nsec = dlval; + /* Update average seconds and bytes. */ + if (activeservice->dispatchover) { + multiplier = activeservice->dispatchover - 1; + if (servicereport->backendstate[current_backend].totuses < + multiplier) + multiplier = + servicereport->backendstate[current_backend].totuses; - llval = servicereport->backendstate[current_backend].avg_nbytes; - llval *= multiplier; - llval += nbytes; - llval /= (multiplier + 1); - servicereport->backendstate[current_backend].avg_nbytes = llval; - } + dlval = servicereport->backendstate[current_backend].avg_nsec; + dlval *= multiplier; + dlval += nsec; + dlval /= (multiplier + 1); + servicereport->backendstate[current_backend].avg_nsec = dlval; - /* Update total secs / bytes. */ - servicereport->backendstate[current_backend].nsec += nsec; - servicereport->backendstate[current_backend].nbytes += nbytes; - if (newstate == st_unavailable) - servicereport->backendstate[current_backend].failures++; + llval = servicereport->backendstate[current_backend].avg_nbytes; + llval *= multiplier; + llval += nbytes; + llval /= (multiplier + 1); + servicereport->backendstate[current_backend].avg_nbytes = llval; + } + /* Update total secs / bytes. */ + servicereport->backendstate[current_backend].nsec += nsec; + servicereport->backendstate[current_backend].nbytes += nbytes; + if (newstate == st_unavailable) + servicereport->backendstate[current_backend].failures++; + } + /* Set the state, unless it's already marked for wakeup or brought down. * Do this only for 'final' states, not for intermediate. */ if (servicereport->backendstate[current_backend].avail != st_waking && @@ -91,6 +95,7 @@ void mark_activity (double nbytes, double nsec, "going offline", activeservice->name, current_backend, servicereport->backendstate[current_backend].fail, activeservice->backend[current_backend].retries); + servicereport->backendstate[current_backend].fail = 0; servicereport->backendstate[current_backend].avail = st_unavailable; marked_unavailable++; @@ -98,6 +103,7 @@ void mark_activity (double nbytes, double nsec, servicereport->backendstate[current_backend].totuses++; } else if (newstate != st_intermediate) { /* When applying any other state than intermediate, it's OK */ + servicereport->backendstate[current_backend].fail = 0; servicereport->backendstate[current_backend].avail = newstate; servicereport->backendstate[current_backend].totuses++; } @@ -124,7 +130,7 @@ void mark_activity (double nbytes, double nsec, (servicereport->backendstate[current_backend].avail)); /* Run the onfailure hook if one is specified. */ - if (marked_unavailable) { + if (marked_unavailable && program_stage != stage_retrying) { msg ("Service %s: extcmd-onfail: " " current_backend = %d, clients = %d, totclients = %d, cmd = %s", activeservice->name, current_backend, diff --git a/src/msg.c b/src/msg.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/msgdumpbuf.c b/src/msgdumpbuf.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/netbuffer.c b/src/netbuffer.c @@ -1,12 +1,12 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ #include "crossroads.h" -unsigned char *net_buffer (CopyDirection dir, unsigned *sz) { +unsigned char *net_buffer (CopyDirection dir, int *sz) { if (dir == dir_server_to_client) { if (srbufmax) { *sz = srbufmax - srbufpos; diff --git a/src/netbufread.c b/src/netbufread.c @@ -1,22 +1,21 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ #include "crossroads.h" -unsigned char *net_bufread (int sock, unsigned max, unsigned *nread, +unsigned char *net_bufread (int sock, int max, int *nread, int is_client) { - unsigned char *buf; - unsigned *bufpos, *bufmax, rest; - unsigned char *ret; + unsigned char *buf, *ret; + int *bufpos, *bufmax, rest; /* Make sure we have the buffers. */ if (!clbuf) { clbuf = xmalloc (TCP_BUFSZ); srbuf = xmalloc (TCP_BUFSZ); - clbufmax = srbufmax = 0; + clbufmax = srbufmax = clbufpos = srbufpos = 0; msg ("Service %s: Allocated client and server buffers", activeservice->name); } @@ -34,7 +33,7 @@ unsigned char *net_bufread (int sock, unsigned max, unsigned *nread, /* If buffer is empty, do an actual read */ if (! *bufmax) { *bufmax = net_read (sock, TCP_BUFSZ, buf, is_client); - msg ("Service %s: Got %u bytes from %s", + msg ("Service %s: Got %d bytes from %s", activeservice->name, *bufmax, is_client ? "client" : "server"); *bufpos = 0; } @@ -54,7 +53,7 @@ unsigned char *net_bufread (int sock, unsigned max, unsigned *nread, if (nread) *nread = rest; ret = buf + *bufpos; - *bufmax = 0; + *bufmax = *bufpos = 0; } return (ret); diff --git a/src/netcopy.c b/src/netcopy.c @@ -1,11 +1,11 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ #include "crossroads.h" -unsigned net_copy (int cl, int sr, unsigned max, unsigned char *buf) { +int net_copy (int cl, int sr, int max, unsigned char *buf) { fd_set readset, exset; struct timeval tv, *tvp, tv1, tv2; int nfd; diff --git a/src/netread.c b/src/netread.c @@ -1,12 +1,20 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ #include "crossroads.h" -unsigned net_read (int sock, unsigned max, unsigned char *buf, int is_client) { +// #define DEBUG + +#ifdef DEBUG +#define LOGGIT msg ("back end %d", current_backend) +#else +#define LOGGIT +#endif + +int net_read (int sock, int max, unsigned char *buf, int is_client) { fd_set readset, exset; struct timeval tv, *tvp, tv1, tv2; int nfd; @@ -55,7 +63,8 @@ unsigned net_read (int sock, unsigned max, unsigned char *buf, int is_client) { } /* Do the read. */ - nread = read (sock, buf, max - 1); + nread = read (sock, buf, max); + LOGGIT; if (nread < 1) { decr_client_count(); log_activity_end(); diff --git a/src/netwrite.c b/src/netwrite.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ @@ -14,7 +14,7 @@ /* #define DUMPFILE */ -unsigned net_write (int sock, unsigned char const *buf, unsigned buflen, +int net_write (int sock, unsigned char const *buf, int buflen, int is_client) { int ret, nfd; struct timeval tv, tv1, tv2, *tvp; @@ -65,7 +65,7 @@ unsigned net_write (int sock, unsigned char const *buf, unsigned buflen, decr_client_count(); log_activity_end(); - _exit (0); + exit (0); } if (FD_ISSET (sock, &exset)) { @@ -80,13 +80,12 @@ unsigned net_write (int sock, unsigned char const *buf, unsigned buflen, /* Check for finished / errors */ if (ret < 1) { - warning ("Service %s: sent %d bytes to %s: %s", - activeservice->name, ret, - is_client ? "client" : "server", - strerror(errno)); + msg ("Service %s: failed to send to %s: %s (%d)", + activeservice->name, is_client ? "client" : "server", + strerror(errno), ret); decr_client_count(); log_activity_end (); - _exit (0); + exit (0); } /* Update activity. */ @@ -96,7 +95,7 @@ unsigned net_write (int sock, unsigned char const *buf, unsigned buflen, mark_activity (ret, microsec / 1000000, st_intermediate); /* Signal caller how many bytes were written. */ - return ( (unsigned) ret); + return (ret); } diff --git a/src/parser.c b/src/parser.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ @@ -285,17 +285,17 @@ static const short yyrline[] = { 0, 130, 133, 137, 166, 171, 179, 182, 186, 191, 197, 203, 209, 219, 225, 231, 237, 243, 249, 255, - 261, 267, 273, 279, 286, 451, 463, 475, 484, 491, - 496, 509, 513, 519, 528, 530, 532, 536, 553, 560, - 570, 579, 583, 587, 591, 595, 599, 603, 607, 613, - 625, 634, 646, 658, 670, 682, 694, 706, 711, 715, - 721, 733, 745, 757, 769, 778, 788, 796, 804, 810, - 817, 822, 827, 832, 837, 842, 847, 852, 857, 862, - 867, 872, 877, 882, 887, 892, 897, 902, 907, 914, - 927, 939, 951, 957, 969, 981, 993, 1005, 1017, 1029, - 1038, 1047, 1059, 1068, 1080, 1092, 1104, 1116, 1128, 1140, - 1149, 1154, 1159, 1164, 1169, 1174, 1179, 1184, 1189, 1194, - 1199, 1204, 1209, 1214, 1219, 1224, 1229, 1234 + 261, 267, 273, 279, 286, 457, 469, 481, 490, 497, + 502, 515, 519, 525, 534, 536, 538, 542, 559, 566, + 576, 585, 589, 593, 597, 601, 605, 609, 613, 619, + 631, 640, 652, 664, 676, 688, 700, 712, 717, 721, + 727, 739, 751, 763, 775, 784, 794, 802, 810, 816, + 823, 828, 833, 838, 843, 848, 853, 858, 863, 868, + 873, 878, 883, 888, 893, 898, 903, 908, 913, 920, + 933, 945, 957, 963, 975, 987, 999, 1011, 1023, 1035, + 1044, 1053, 1065, 1074, 1086, 1098, 1110, 1122, 1134, 1146, + 1155, 1160, 1165, 1170, 1175, 1180, 1185, 1190, 1195, 1200, + 1205, 1210, 1215, 1220, 1225, 1230, 1235, 1240 }; #endif @@ -1519,6 +1519,12 @@ case 24: cur_backend.onfail = xstrdup (""); if (! cur_backend.onend) cur_backend.onend = xstrdup (""); + if (! cur_backend.thruputfile) + cur_backend.thruputfile = xstrdup (""); + if (! cur_backend.dumpfile) + cur_backend.dumpfile = xstrdup (""); + if (! cur_backend.stickycookie) + cur_backend.stickycookie = xstrdup (""); /* Add to the list. */ cur_service.backend = xrealloc (cur_service.backend, @@ -1531,7 +1537,7 @@ case 24: ; break;} case 25: -#line 454 "parser.y" +#line 460 "parser.y" { pimsg ("port statement:", lastnr); yyval.n = 1; @@ -1541,7 +1547,7 @@ case 25: ; break;} case 26: -#line 466 "parser.y" +#line 472 "parser.y" { psmsg ("bindto statement:", laststr); yyval.n = 1; @@ -1551,7 +1557,7 @@ case 26: ; break;} case 27: -#line 477 "parser.y" +#line 483 "parser.y" { setlaststr (laststring); free (laststring); @@ -1559,13 +1565,13 @@ case 27: ; break;} case 28: -#line 486 "parser.y" +#line 492 "parser.y" { setlastnr (yytext); ; break;} case 30: -#line 500 "parser.y" +#line 506 "parser.y" { pimsg ("verbosity statement:", lastnr); yyval.n = 1; @@ -1575,25 +1581,25 @@ case 30: ; break;} case 31: -#line 510 "parser.y" +#line 516 "parser.y" { lastnr = 1; ; break;} case 32: -#line 514 "parser.y" +#line 520 "parser.y" { lastnr = 0; ; break;} case 33: -#line 523 "parser.y" +#line 529 "parser.y" { yyval = yyvsp[-2]; ; break;} case 37: -#line 538 "parser.y" +#line 544 "parser.y" { pimsg ("dispatch mode statement:", lastnr); yyval.n = 1; @@ -1609,13 +1615,13 @@ case 37: ; break;} case 38: -#line 555 "parser.y" +#line 561 "parser.y" { setlastovernr (yytext); ; break;} case 39: -#line 561 "parser.y" +#line 567 "parser.y" { psmsg ("external handler:", laststr); if (lastnr != ds_externalhandler) @@ -1625,7 +1631,7 @@ case 39: ; break;} case 40: -#line 572 "parser.y" +#line 578 "parser.y" { yyval.n = 1; yyval.set = xmalloc (sizeof(Confset)); @@ -1633,55 +1639,55 @@ case 40: ; break;} case 41: -#line 580 "parser.y" +#line 586 "parser.y" { lastnr = ds_roundrobin; ; break;} case 42: -#line 584 "parser.y" +#line 590 "parser.y" { lastnr = ds_random; ; break;} case 43: -#line 588 "parser.y" +#line 594 "parser.y" { lastnr = ds_byduration; ; break;} case 44: -#line 592 "parser.y" +#line 598 "parser.y" { lastnr = ds_bysize; ; break;} case 45: -#line 596 "parser.y" +#line 602 "parser.y" { lastnr = ds_byorder; ; break;} case 46: -#line 600 "parser.y" +#line 606 "parser.y" { lastnr = ds_byconnections; ; break;} case 47: -#line 604 "parser.y" +#line 610 "parser.y" { lastnr = ds_externalhandler; ; break;} case 48: -#line 608 "parser.y" +#line 614 "parser.y" { lastnr = ds_byclientip; ; break;} case 49: -#line 616 "parser.y" +#line 622 "parser.y" { pimsg ("user account statement:", laststr); yyval.n = 1; @@ -1691,7 +1697,7 @@ case 49: ; break;} case 50: -#line 627 "parser.y" +#line 633 "parser.y" { setlaststr (laststring); free (laststring); @@ -1699,7 +1705,7 @@ case 50: ; break;} case 51: -#line 637 "parser.y" +#line 643 "parser.y" { pimsg ("reviving interval statement:", lastnr); yyval.n = 1; @@ -1709,7 +1715,7 @@ case 51: ; break;} case 52: -#line 649 "parser.y" +#line 655 "parser.y" { pimsg ("backlog statement:", lastnr); yyval.n = 1; @@ -1719,7 +1725,7 @@ case 52: ; break;} case 53: -#line 661 "parser.y" +#line 667 "parser.y" { pimsg ("shmkey statement:", lastnr); yyval.n = 1; @@ -1729,7 +1735,7 @@ case 53: ; break;} case 54: -#line 673 "parser.y" +#line 679 "parser.y" { pimsg ("connection timeout statement:", lastnr); yyval.n = 1; @@ -1739,7 +1745,7 @@ case 54: ; break;} case 55: -#line 685 "parser.y" +#line 691 "parser.y" { pimsg ("max clients statement (service):", lastnr); yyval.n = 1; @@ -1749,7 +1755,7 @@ case 55: ; break;} case 56: -#line 697 "parser.y" +#line 703 "parser.y" { pimsg ("service type:", lastnr); yyval.n = 1; @@ -1759,19 +1765,19 @@ case 56: ; break;} case 58: -#line 712 "parser.y" +#line 718 "parser.y" { lastnr = type_any; ; break;} case 59: -#line 716 "parser.y" +#line 722 "parser.y" { lastnr = type_http; ; break;} case 60: -#line 724 "parser.y" +#line 730 "parser.y" { psmsg ("allow from: ", laststr); yyval.n = 1; @@ -1781,7 +1787,7 @@ case 60: ; break;} case 61: -#line 736 "parser.y" +#line 742 "parser.y" { psmsg ("allow from: ", laststr); yyval.n = 1; @@ -1791,7 +1797,7 @@ case 61: ; break;} case 62: -#line 748 "parser.y" +#line 754 "parser.y" { psmsg ("allow file: ", laststr); yyval.n = 1; @@ -1801,7 +1807,7 @@ case 62: ; break;} case 63: -#line 760 "parser.y" +#line 766 "parser.y" { psmsg ("allow file: ", laststr); yyval.n = 1; @@ -1811,7 +1817,7 @@ case 63: ; break;} case 64: -#line 771 "parser.y" +#line 777 "parser.y" { setlaststr (laststring); free (laststring); @@ -1819,20 +1825,20 @@ case 64: ; break;} case 65: -#line 783 "parser.y" +#line 789 "parser.y" { yyval = yyvsp[-1]; ; break;} case 66: -#line 790 "parser.y" +#line 796 "parser.y" { psmsg ("backend name:", yytext); cur_backend.name = xstrdup (yytext); ; break;} case 67: -#line 798 "parser.y" +#line 804 "parser.y" { yyvsp[-1].n++; yyvsp[-1].set = xrealloc (yyvsp[-1].set, yyvsp[-1].n * sizeof(Confset)); @@ -1841,152 +1847,152 @@ case 67: ; break;} case 68: -#line 805 "parser.y" +#line 811 "parser.y" { yyval = yyvsp[0]; ; break;} case 69: -#line 812 "parser.y" +#line 818 "parser.y" { yyval = yyvsp[0]; ; break;} case 70: -#line 818 "parser.y" +#line 824 "parser.y" { psmsg ("backend server:", yyvsp[0].set[0].v.sval); yyval = yyvsp[0]; ; break;} case 71: -#line 823 "parser.y" +#line 829 "parser.y" { pimsg ("backend port:", yyvsp[0].set[0].v.ival); yyval = yyvsp[0]; ; break;} case 72: -#line 828 "parser.y" +#line 834 "parser.y" { pimsg ("backend verbosity:", yyvsp[0].set[0].v.ival); yyval = yyvsp[0]; ; break;} case 73: -#line 833 "parser.y" +#line 839 "parser.y" { psmsg ("backend onstart:", yyvsp[0].set[0].v.sval); yyval = yyvsp[0]; ; break;} case 74: -#line 838 "parser.y" +#line 844 "parser.y" { psmsg ("backend onend:", yyvsp[0].set[0].v.sval); yyval = yyvsp[0]; ; break;} case 75: -#line 843 "parser.y" +#line 849 "parser.y" { psmsg ("backend onfail:", yyvsp[0].set[0].v.sval); yyval = yyvsp[0]; ; break;} case 76: -#line 848 "parser.y" +#line 854 "parser.y" { psmsg ("backend trafficlog:", yyvsp[0].set[0].v.sval); yyval = yyvsp[0]; ; break;} case 77: -#line 853 "parser.y" +#line 859 "parser.y" { psmsg ("backend trafficlog:", yyvsp[0].set[0].v.sval); yyval = yyvsp[0]; ; break;} case 78: -#line 858 "parser.y" +#line 864 "parser.y" { pimsg ("backend weight:", yyvsp[0].set[0].v.ival); yyval = yyvsp[0]; ; break;} case 79: -#line 863 "parser.y" +#line 869 "parser.y" { pimsg ("backend decay:", yyvsp[0].set[0].v.ival); yyval = yyvsp[0]; ; break;} case 80: -#line 868 "parser.y" +#line 874 "parser.y" { pimsg ("backend maxconnections:", yyvsp[0].set[0].v.ival); yyval = yyvsp[0]; ; break;} case 81: -#line 873 "parser.y" +#line 879 "parser.y" { psmsg ("backend sticky cookie:", yyvsp[0].set[0].v.sval); yyval = yyvsp[0]; ; break;} case 82: -#line 878 "parser.y" +#line 884 "parser.y" { psmsg ("addclientheader:", yyvsp[0].set[0].v.sval); yyval = yyvsp[0]; ; break;} case 83: -#line 883 "parser.y" +#line 889 "parser.y" { psmsg ("setclientheader:", yyvsp[0].set[0].v.sval); yyval = yyvsp[0]; ; break;} case 84: -#line 888 "parser.y" +#line 894 "parser.y" { psmsg ("appendclientheader:", yyvsp[0].set[0].v.sval); yyval = yyvsp[0]; ; break;} case 85: -#line 893 "parser.y" +#line 899 "parser.y" { psmsg ("addserverheader:", yyvsp[0].set[0].v.sval); yyval = yyvsp[0]; ; break;} case 86: -#line 898 "parser.y" +#line 904 "parser.y" { psmsg ("setserverheader:", yyvsp[0].set[0].v.sval); yyval = yyvsp[0]; ; break;} case 87: -#line 903 "parser.y" +#line 909 "parser.y" { psmsg ("appendserverheader:", yyvsp[0].set[0].v.sval); yyval = yyvsp[0]; ; break;} case 88: -#line 908 "parser.y" +#line 914 "parser.y" { pimsg ("backend retries:", yyvsp[0].set[0].v.ival); yyval = yyvsp[0]; ; break;} case 89: -#line 918 "parser.y" +#line 924 "parser.y" { psmsg ("server statement:", laststr); yyval.n = 1; @@ -1996,7 +2002,7 @@ case 89: ; break;} case 90: -#line 930 "parser.y" +#line 936 "parser.y" { pimsg ("weight statement", lastnr); yyval.n = 1; @@ -2006,7 +2012,7 @@ case 90: ; break;} case 91: -#line 942 "parser.y" +#line 948 "parser.y" { pimsg ("decay statement", lastnr); yyval.n = 1; @@ -2016,13 +2022,13 @@ case 91: ; break;} case 92: -#line 952 "parser.y" +#line 958 "parser.y" { setlaststr (laststring); ; break;} case 93: -#line 960 "parser.y" +#line 966 "parser.y" { pimsg ("retries:", lastnr); yyval.n = 1; @@ -2032,7 +2038,7 @@ case 93: ; break;} case 94: -#line 972 "parser.y" +#line 978 "parser.y" { psmsg ("onstart statement:", laststr); yyval.n = 1; @@ -2042,7 +2048,7 @@ case 94: ; break;} case 95: -#line 984 "parser.y" +#line 990 "parser.y" { psmsg ("onfail statement:", laststr); yyval.n = 1; @@ -2052,7 +2058,7 @@ case 95: ; break;} case 96: -#line 996 "parser.y" +#line 1002 "parser.y" { psmsg ("onend statement:", laststr); yyval.n = 1; @@ -2062,7 +2068,7 @@ case 96: ; break;} case 97: -#line 1008 "parser.y" +#line 1014 "parser.y" { psmsg ("trafficlog statement:", laststr); yyval.n = 1; @@ -2072,7 +2078,7 @@ case 97: ; break;} case 98: -#line 1020 "parser.y" +#line 1026 "parser.y" { psmsg ("throughputlog statement:", laststr); yyval.n = 1; @@ -2082,7 +2088,7 @@ case 98: ; break;} case 99: -#line 1031 "parser.y" +#line 1037 "parser.y" { setlaststr (laststring); free (laststring); @@ -2090,7 +2096,7 @@ case 99: ; break;} case 100: -#line 1040 "parser.y" +#line 1046 "parser.y" { setlaststr (laststring); free (laststring); @@ -2098,7 +2104,7 @@ case 100: ; break;} case 101: -#line 1050 "parser.y" +#line 1056 "parser.y" { psmsg ("insertcookie statement:", laststr); yyval.n = 1; @@ -2108,7 +2114,7 @@ case 101: ; break;} case 102: -#line 1061 "parser.y" +#line 1067 "parser.y" { setlaststr (laststring); free (laststring); @@ -2116,7 +2122,7 @@ case 102: ; break;} case 103: -#line 1071 "parser.y" +#line 1077 "parser.y" { psmsg ("addclientheader statement:", laststr); yyval.n = 1; @@ -2126,7 +2132,7 @@ case 103: ; break;} case 104: -#line 1083 "parser.y" +#line 1089 "parser.y" { psmsg ("setclientheader statement:", laststr); yyval.n = 1; @@ -2136,7 +2142,7 @@ case 104: ; break;} case 105: -#line 1095 "parser.y" +#line 1101 "parser.y" { psmsg ("appendclientheader statement:", laststr); yyval.n = 1; @@ -2146,7 +2152,7 @@ case 105: ; break;} case 106: -#line 1107 "parser.y" +#line 1113 "parser.y" { psmsg ("addserverheader statement:", laststr); yyval.n = 1; @@ -2156,7 +2162,7 @@ case 106: ; break;} case 107: -#line 1119 "parser.y" +#line 1125 "parser.y" { psmsg ("setserverheader statement:", laststr); yyval.n = 1; @@ -2166,7 +2172,7 @@ case 107: ; break;} case 108: -#line 1131 "parser.y" +#line 1137 "parser.y" { psmsg ("appendserverheader statement:", laststr); yyval.n = 1; @@ -2176,7 +2182,7 @@ case 108: ; break;} case 109: -#line 1142 "parser.y" +#line 1148 "parser.y" { setlaststr (laststring); free (laststring); @@ -2184,109 +2190,109 @@ case 109: ; break;} case 110: -#line 1149 "parser.y" +#line 1155 "parser.y" { yyerrmsg = "HTTP header specifier expected"; ; break;} case 111: -#line 1154 "parser.y" +#line 1160 "parser.y" { yyerrmsg = "cookie specifier expected"; ; break;} case 112: -#line 1159 "parser.y" +#line 1165 "parser.y" { yyerrmsg = "number expected"; ; break;} case 113: -#line 1164 "parser.y" +#line 1170 "parser.y" { yyerrmsg = "hostname or IP address expected"; ; break;} case 114: -#line 1169 "parser.y" +#line 1175 "parser.y" { yyerrmsg = "'service' expected"; ; break;} case 115: -#line 1174 "parser.y" +#line 1180 "parser.y" { yyerrmsg = "backend definition statement expected"; ; break;} case 116: -#line 1179 "parser.y" +#line 1185 "parser.y" { yyerrmsg = "service body statement expected"; ; break;} case 117: -#line 1184 "parser.y" +#line 1190 "parser.y" { yyerrmsg = "semicolon (;) expected"; ; break;} case 118: -#line 1189 "parser.y" +#line 1195 "parser.y" { yyerrmsg = "'on' or 'off' expetcted"; ; break;} case 119: -#line 1194 "parser.y" +#line 1200 "parser.y" { yyerrmsg = "dispatch method expected"; ; break;} case 120: -#line 1199 "parser.y" +#line 1205 "parser.y" { yyerrmsg = "command line expected"; ; break;} case 121: -#line 1204 "parser.y" +#line 1210 "parser.y" { yyerrmsg = "file name expected"; ; break;} case 122: -#line 1209 "parser.y" +#line 1215 "parser.y" { yyerrmsg = "service name (identifier) expected"; ; break;} case 123: -#line 1214 "parser.y" +#line 1220 "parser.y" { yyerrmsg = "backend name (identifier) expected"; ; break;} case 124: -#line 1219 "parser.y" +#line 1225 "parser.y" { yyerrmsg = "IP address or 'any' expected"; ; break;} case 125: -#line 1224 "parser.y" +#line 1230 "parser.y" { yyerrmsg = "Service type expected ('any', 'stickyhttp', ...)"; ; break;} case 126: -#line 1229 "parser.y" +#line 1235 "parser.y" { yyerrmsg = "IP filter(s) expected"; ; break;} case 127: -#line 1234 "parser.y" +#line 1240 "parser.y" { yyerrmsg = "username expected"; ; @@ -2524,4 +2530,4 @@ yyreturn: #endif return yyresult; } -#line 1238 "parser.y" +#line 1244 "parser.y" diff --git a/src/parser.h b/src/parser.h @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/parser.y b/src/parser.y @@ -436,6 +436,12 @@ servicebody: cur_backend.onfail = xstrdup (""); if (! cur_backend.onend) cur_backend.onend = xstrdup (""); + if (! cur_backend.thruputfile) + cur_backend.thruputfile = xstrdup (""); + if (! cur_backend.dumpfile) + cur_backend.dumpfile = xstrdup (""); + if (! cur_backend.stickycookie) + cur_backend.stickycookie = xstrdup (""); /* Add to the list. */ cur_service.backend = xrealloc (cur_service.backend, diff --git a/src/restart.c b/src/restart.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/runservice.c b/src/runservice.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ @@ -12,7 +12,7 @@ void runservice () { msg ("Service %s (on port %d): STARTING", activeservice->name, activeservice->port); - + /* Allocate the shared mem segment. */ alloc_reporter(activeservice, 1); @@ -23,7 +23,7 @@ void runservice () { if (ipf_loadfile (activeservice->denyfile, &(activeservice->denychain), &(activeservice->ndenychain))) error ("Error in deny file"); - + /* Go into the background. */ if ( (pid = fork()) < 0 ) { /* Fork failed */ @@ -35,7 +35,7 @@ void runservice () { activeservice->name, pid); return; } - + /* Child branch */ set_program_title ("Service %s: listening", activeservice->name); close (0); @@ -51,10 +51,10 @@ void runservice () { if (setsid() < 0) error ("Service %s: failed to become seesion leader", activeservice->name); - + /* Promote verbosity. */ flag_verbose = activeservice->verbosity; - + /* We've forked for the first time */ program_stage = stage_waiting; @@ -65,54 +65,58 @@ void runservice () { * Of course we only start listening if we have back ends at all... */ while (1) { - if (backend_count()) { - /* Create the socket, bind to port. */ - if ( (listen_sock = make_socket (activeservice->port, - activeservice->bind)) < 0 ) { - if (!sloppyportbind) - error ("Service %s: failed to listen to port %d: %s", - activeservice->name, activeservice->port, - strerror(errno)); - warning ("Service %s: " - "listening socket creation failed.. will retry", - activeservice->name); - - /* We wait here for some time, to let the system regain - * equilibrium. Something's really afoot, so let's not retry - * right away. */ - sleep (SLEEP_TIME); - - continue; - } - msg ("Service %s: server-side network socket: %d", - activeservice->name, listen_sock); - - /* Zero out the stats for first usage. */ - if (first_serving) { - first_serving = 0; - memset (servicereport, 0, sizeof(Servicereport)); - /* Store our pid, so that 'crossroads stop' may kill us. */ - lock_reporter(); - servicereport->pid = getpid(); - unlock_reporter(); - } - - /* Start serving the port! */ - tcpserve (listen_sock); - - /* tcpserve() returned -- must be because this service is out - * of back ends */ - if (shutdown (listen_sock, SHUT_RDWR)) - error ("Service %s: " - "failed to shut down server-side socket %d: %s", - activeservice->name, listen_sock, strerror(errno)); - if (close (listen_sock)) - error ("Service %s: failed to close server-side socket %d: %s", - activeservice->name, listen_sock, strerror(errno)); - + /* We need at least one working back end to operate. */ + if (!backend_count()) { + msg ("Service %s: taking a nap...", activeservice->name); + sleep (SLEEP_TIME); + continue; + } + + /* We have (at least) one back end. Let's run the service. + * Create the socket, bind to port. */ + if ( (listen_sock = make_socket (activeservice->port, + activeservice->bind)) < 0 ) { + if (!sloppyportbind) + error ("Service %s: failed to listen to port %d: %s", + activeservice->name, activeservice->port, + strerror(errno)); + warning ("Service %s: " + "listening socket creation failed.. will retry", + activeservice->name); + + /* We wait here for some time, to let the system regain + * equilibrium. Something's really afoot, so let's not retry + * right away. */ + sleep (SLEEP_TIME); + + continue; } - - msg ("Service %s: taking a nap...", activeservice->name); - sleep (SLEEP_TIME); + + msg ("Service %s: server-side network socket: %d", + activeservice->name, listen_sock); + + /* Zero out the stats for first usage. */ + if (first_serving) { + first_serving = 0; + memset (servicereport, 0, sizeof(Servicereport)); + /* Store our pid, so that 'crossroads stop' may kill us. */ + lock_reporter(); + servicereport->pid = getpid(); + unlock_reporter(); + } + + /* Start serving the port! */ + tcpserve (listen_sock); + + /* tcpserve() returned -- must be because this service is out + * of back ends */ + if (shutdown (listen_sock, SHUT_RDWR)) + warning ("Service %s: " + "failed to shut down server-side socket %d: %s", + activeservice->name, listen_sock, strerror(errno)); + if (close (listen_sock)) + warning ("Service %s: " + "failed to close server-side socket %d: %s", + activeservice->name, listen_sock, strerror(errno)); } } diff --git a/src/serve.c b/src/serve.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/setprogramtitle.c b/src/setprogramtitle.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/showconfig.c b/src/showconfig.c @@ -0,0 +1,38 @@ +/************************************************************************* + * This file is part of Crosroads 1.38, a load balancer and fail over + * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. + * Visit http://crossroads.e-tunity.com for information. + *************************************************************************/ + +#include "crossroads.h" + +#define SHOWDEF(a,b,c) \ + printf ("%-22s %-31s %s \n", b, c, a ? "yes" : "no"); + +void show_config () { + printf ("VER version: %s\n" + "REVVER revision version (REVVER): %s\n" + "DEFAULT_CONF default configuration file: %s\n" + "MAX_BACKEND max nr. of backends in service: %d\n" + "SHM_MASK magic shared memory number: 0x%x\n" + "SLEEP_TIME service inactivy pause %d\n" + "CONNECT_TIMEOUT backend connect timeout %d\n" + "RETRY_WAIT backend retry pause %d\n" + "TCP_BUFSZ network buffer size %d\n" + "BINDIR installation directory %s\n" + "SET_PROC_TITLE_BY_ARGV argv assumed linear array %d\n" + "EXTRALIBS extra library dependencies %s\n" + "LIBS standard library dependencies %s\n" + , + VER, REVVER, DEFAULT_CONF, MAX_BACKEND, SHM_MASK, SLEEP_TIME, + CONNECT_TIMEOUT, RETRY_WAIT, TCP_BUFSZ, BINDIR, + SET_PROC_TITLE_BY_ARGV, EXTRALIBS, LIBS); + SHOWDEF (HAVE_MALLOC_H, "HAVE_MALLOC_H", "<malloc.h> present"); + SHOWDEF (HAVE_STDINT_H, "HAVE_STDINT_H", "<stdint.h> present"); + SHOWDEF (HAVE_FLOCK, "HAVE_FLOCK", "flock() present"); + SHOWDEF (HAVE_LOCKF, "HAVE_LOCKF", "lockf() present"); + SHOWDEF (HAVE_STRLCAT, "HAVE_STRLCAT", "strlcat() present"); + SHOWDEF (HAVE_SRANDDEV, "HAVE_SRANDDEV", "sranddev() present"); + SHOWDEF (HAVE_VSYSLOG, "HAVE_VSYSLOG", "vsyslog() present"); + SHOWDEF (HAVE_STRCASESTR, "HAVE_STRCASESTR", "strcasestr() present"); +} diff --git a/src/showservices.c b/src/showservices.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/showstatus.c b/src/showstatus.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ @@ -53,10 +53,12 @@ static char *bytestr (double nbytes) { } int show_status (int ac, char **av) { - int i, j; + int i, j, services_shown = 0; for (i = 0; i < nservice; i++) { - if (i) + if (ac > 1 && strcmp (service[i].name, av[0])) + continue; + if (services_shown++) putchar ('\n'); alloc_reporter (service + i, 0); msg ("Reporting service %s (pid = %d)", @@ -69,6 +71,8 @@ int show_status (int ac, char **av) { service[i].name, servicereport->nclients, servicereport->last_backend); for (j = 0; j < service[i].nbackend; j++) { + if (ac > 2 && strcmp (service[i].backend[j].name, av[1])) + continue; if (tabular_status) printf ("%s=%s ", service[i].backend[j].name, state_to_string(servicereport->backendstate[j].avail)); @@ -100,6 +104,8 @@ int show_status (int ac, char **av) { error ("Failure releasing reporter memory: %s", strerror(errno)); } + if (tabular_status) + putchar ('\n'); return (1); } diff --git a/src/stagetostring.c b/src/stagetostring.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/statetostring.c b/src/statetostring.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/stopdaemon.c b/src/stopdaemon.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/strcasestr.c b/src/strcasestr.c @@ -1,11 +1,11 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ #include "crossroads.h" -#ifndef HAVE_STRCASESTR +#if HAVE_STRCASESTR == 0 char *strcasestr (char const *big, char const *little) { char *bcopy, *lcopy, *res; @@ -23,6 +23,3 @@ char *strcasestr (char const *big, char const *little) { return (res); } #endif - - - diff --git a/src/strexpandformat.c b/src/strexpandformat.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/stringtostate.c b/src/stringtostate.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/strlcat.c b/src/strlcat.c @@ -1,9 +1,10 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ -#ifndef HAVE_STRLCAT + +#if HAVE_STRLCAT == 0 #include "crossroads.h" diff --git a/src/strprintf.c b/src/strprintf.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/strvprintf.c b/src/strvprintf.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/sysrun.c b/src/sysrun.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/tcpserve.c b/src/tcpserve.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ @@ -44,6 +44,22 @@ void tcpserve (int server_sock) { * (unless something is REALLY wrong). */ while (1) { + /* Reload allow/deny files if requested so due to SIGHUP. */ + if (reload_allow_deny) { + reload_allow_deny = 0; + if (ipf_loadfile (activeservice->allowfile, + &(activeservice->allowchain), + &(activeservice->nallowchain))) + warning ("Bad syntax in allow file"); + if (ipf_loadfile (activeservice->denyfile, + &(activeservice->denychain), + &(activeservice->ndenychain))) + warning ("Bad syntax in deny file"); + msg ("Service %s: allow chain has %d entries, " + "deny chain has %d entries", activeservice->name, + activeservice->nallowchain, activeservice->ndenychain); + } + /* Block until we get a connection. */ FD_ZERO (&set); FD_SET (server_sock, &set); diff --git a/src/tellservice.c b/src/tellservice.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/thruputlog.c b/src/thruputlog.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ @@ -13,7 +13,8 @@ void thruputlog (unsigned char const *buf, int len, CopyDirection dir) { FILE *f; if (current_backend < 0 || - ! activeservice->backend[current_backend].thruputfile) + ! activeservice->backend[current_backend].thruputfile || + ! *activeservice->backend[current_backend].thruputfile) return; /* Initialize timer if necessary. Get current time. */ @@ -38,9 +39,9 @@ void thruputlog (unsigned char const *buf, int len, CopyDirection dir) { return; } -#if defined HAVE_FLOCK +#if HAVE_FLOCK == 1 flock (fileno(f), LOCK_EX); -#elif defined HAVE_LOCKF +#elif HAVE_LOCKF === 1 lockf (fileno(f), F_LOCK, 0); #endif diff --git a/src/trafficlog.c b/src/trafficlog.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ @@ -11,7 +11,8 @@ void trafficlog (unsigned char const *buf, int len, CopyDirection dir) { FILE *f; if (current_backend < 0 || - ! activeservice->backend[current_backend].dumpfile) + ! activeservice->backend[current_backend].dumpfile || + ! *activeservice->backend[current_backend].dumpfile) return; if ( (! (f = fopen (activeservice->backend[current_backend].dumpfile, @@ -24,9 +25,9 @@ void trafficlog (unsigned char const *buf, int len, CopyDirection dir) { return; } -#if defined HAVE_FLOCK +#if HAVE_FLOCK == 1 flock (fileno(f), LOCK_EX); -#elif defined HAVE_LOCKF +#elif HAVE_LOCKF == 1 lockf (fileno(f), F_LOCK, 0); #endif diff --git a/src/uidassume.c b/src/uidassume.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/uidrestore.c b/src/uidrestore.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/unlockreporter.c b/src/unlockreporter.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/usage.c b/src/usage.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/usage.txt b/src/usage.txt @@ -6,7 +6,8 @@ For distributions and updates, visit <http://crossroads.e-tunity.com>. Usage: ** Controlling the daemon: ** crossroads [flags] start: start all services - crossroads [flags] status: show the active services and their status + crossroads [flags] status [service [backend]]: show the services + and their status, optionally of stated service and/or back end crossroads [flags] stop: stop all services crossroads [flags] restart: stop and then start crossroads [flags] tell SERVICE BACKEND STATE: mark the named @@ -19,6 +20,7 @@ Usage: Supported flags: -a: logs starting and finishing activity to syslog + -C: shows compile-time configuration and stops -c CONFIG: Uses the named configuration, instead of the default %s -l FAC: Specifies the openlog(3) facility to use when diff --git a/src/vsyslog.c b/src/vsyslog.c @@ -1,11 +1,11 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ #include "crossroads.h" -#ifndef HAVE_VSYSLOG +#if HAVE_VSYSLOG == 0 void vsyslog (int pri, char const *fmt, va_list args) { char *msg; diff --git a/src/wakeuphandler.c b/src/wakeuphandler.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/warning.c b/src/warning.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/writelog.c b/src/writelog.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/xmalloc.c b/src/xmalloc.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/xrealloc.c b/src/xrealloc.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/xstrcat.c b/src/xstrcat.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/xstrcatch.c b/src/xstrcatch.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/src/xstrdup.c b/src/xstrdup.c @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.37, a load balancer and fail over + * This file is part of Crosroads 1.38, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ diff --git a/test/breakingclient b/test/breakingclient @@ -24,14 +24,14 @@ while (1) { system ("killall -9 wget"); kill ('HUP', $pid); wait(); - my @fls = glob ("/tmp/$$/localhost:8001/~karel/imagepage/img*png"); + my @fls = glob ("/tmp/$$/localhost:10000/~karel/imagepage/img*png"); print (" ", $#fls + 1, " images retrieved\n"); sleep (1); } else { open (my $if, "wget -r -S --http-user=user --http-password=password " . "--no-cache " . - "http://localhost:8001/~karel/imagepage/index.php 2>&1 |") + "http://localhost:10000/~karel/imagepage/index.php 2>&1 |") or die ("Cannot start wget\n"); my $via = ''; while (my $line = <$if>) { diff --git a/test/t7.conf b/test/t7.conf @@ -0,0 +1,13 @@ +service t7 { + port 10000; + type http; + verbosity on; + backend t7a { + server localhost:3128; + verbosity on; + } + backend t7b { + server localhost:3128; + verbosity on; + } +} diff --git a/test/t8.conf b/test/t8.conf @@ -0,0 +1,32 @@ +service test { + port 10000; + type http; + bindto any; + dispatchmode bysize; + connectiontimeout 600; + verbosity on; + + backend a { + server localhost:80; + weight 2; + decay 5; + stickycookie BalancerID=Backend_A; + addclientheader "Set-Cookie: BalancerID=Backend_A; Path=/"; + } + + backend b { + server localhost:80; + weight 2; + decay 5; + stickycookie BalancerID=Backend_B; + addclientheader "Set-Cookie: BalancerID=Backend_B; Path=/"; + } + + backend c { + server localhost:80; + weight 3; + decay 5; + stickycookie BalancerID=Backend_C; + addclientheader "Set-Cookie: BalancerID=Backend_C; Path=/"; + } +} diff --git a/tools/c-conf b/tools/c-conf @@ -4,7 +4,8 @@ use strict; use Getopt::Std; # Globals -my $VER = "1.05"; +my $VER = "1.06"; +# 1.06 [KK 2007-04-27] Added ifheader01 and libfunction01 # 1.05 [KK 2006-09-28] Flag -s (silent) implemented. Usage text updated. # 1.04 [KK 2006-09-05] C-compilers: gcc/g++ get selected first, instead of # cc/c++. Helps HP-UX ports. [Thanks, Bernd Krumboeck.] @@ -51,8 +52,12 @@ Usage: $base [flags] ifheader FILE.H DEFINE Searches for the named header. If found, a compilation flag -DDEFINE is returned, indicating that the header is found. + $base [flags] ifheader01 FILE.H DEFINE Similar to ifheader, but the + returned define is either DEFINE=0 or DEFINE=1 $base [flags] libfunction FUNC DEFINE Creates a small program that tries to use FUNC. If this succeeds, a -DDEFINE=1 flag is returned. + $base [flags] libfunction01 FUNC DEFINE Similar to libfunction, but + the returned define is DEFINE=0 or DEFINE=1 $base [flags] lib NAME [NAME...]: Searches for libNAME.{a,so,...}, returns appropriate -L and -l flags. $base [flags] so-name NAME: Returns filename of a shared-object for NAME, @@ -195,7 +200,7 @@ sub if_header { When found, a define-flag for the C compiler is returned. E.g.: $base ifheader malloc.h HAVE_MALLOC_H (may return -DHAVE_MALLOC_H) Use in a Makefile as in: -CFLAGS = \$(CFLAGS) \$(shell c-conf ifheader malloc.h HAVE_MALLOC_H +CFLAGS = \$(CFLAGS) \$(shell c-conf ifheader malloc.h HAVE_MALLOC_H) Then in a C source as: #ifdef HAVE_MALLOC_H #include <malloc.h> @@ -215,6 +220,32 @@ ENDHELP } } +# Find a header, output define=0 or define=1 +sub if_header01 { + checkhelp <<"ENDHELP"; +'ifheader01' tries to find a header in the 'include' directories. When +found, a define for the C compiler is returned having value 1. When not +found, the value is 0. Use in a Makefile as follows: +CFLAGS = \$(shell c-conf ifheader01 malloc.h HAVE_MALLOC_H) +Then in a C source as: +#if HAVE_MALLOC_H == 1 +#include <malloc.h> +#endif +ENDHELP + + usage() if ($#_ != 1); + my ($h, $def) = @_; + msg ("Looking for '$h'\n"); + foreach my $d (@headerdirs) { + if (-f "$d/$h") { + output ("-D$def=1"); + return; + } + } + output ("-D$def=0"); + return; +} + # Find a header sub header { checkhelp <<"ENDHELP"; @@ -417,6 +448,31 @@ E.g.: $base libfunction printf HAVE_PRINTF $base libfunction foo_bar HAVE_FOOBAR -> (nothing) ENDHELP + + output ("-D$_[1]=1") if (test_libfunction (@_)); +} + +# Check that a libfunction is present, 01-version +sub libfunction01 { + checkhelp <<"ENDHELP"; +'libfunction01' checks whether a library function is present. There are +two arguments: the function to check, and a define to output when the +function is found. When the lib function is found, then the define is +returned with a value 1, else with a value 0. +E.g.: $base libfunction printf HAVE_PRINTF + -> -DHAVE_PRINTF=1 + $base libfunction foo_bar HAVE_FOOBAR + -> -DHAVE_FOOBAR=0 +ENDHELP + + if (test_libfunction (@_)) { + output ("-D$_[1]=1"); + } else { + output ("-D$_[1]=0"); + } +} + +sub test_libfunction { usage() if ($#_ != 1); my ($func, $def) = @_; @@ -443,7 +499,7 @@ ENDHELP my $ret = system ("$cc -o $dst $src >/dev/null 2>&1"); unlink ($src, $dst); - output ("-D$def=1") if ($ret == 0); + return ($ret == 0 ? 1 : 0); } # Main starts here @@ -480,8 +536,12 @@ if ($action eq 'header') { so_name (@ARGV); } elsif ($action eq 'ifheader') { if_header (@ARGV); +} elsif ($action eq 'ifheader01') { + if_header01 (@ARGV); } elsif ($action eq 'libfunction') { libfunction (@ARGV); +} elsif ($action eq 'libfunction01') { + libfunction01 (@ARGV); } else { usage (); }