crossroads

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

commit 2fcfb7de1fd14ee9777829b7f873b55b2bb3b313
parent 82d44c0eef2b7c6a78d7148c77f788f4c45830dd
Author: finwo <finwo@pm.me>
Date:   Sat,  3 Jan 2026 19:03:56 +0100

1.03

Diffstat:
MChangeLog | 33+++++++++++++++++++++++++++++++++
MMakefile | 13+++----------
Mdoc/compiling.yo | 6+++---
Mdoc/crossroads.html | 215+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mdoc/crossroads.man | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Mdoc/crossroads.pdf | 0
Mdoc/impatient.yo | 4++--
Mdoc/using.yo | 45+++++++++++++++++++++++++++++++++++++++++++--
Metc/Makefile.def | 2+-
Metc/Makefile.help | 5+++--
Msrc/Makefile | 6++++--
Asrc/ansistamp.c | 14++++++++++++++
Msrc/choosebackend.c | 106++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/copysockets.c | 10+++++++++-
Msrc/crossroads.h | 24++++++++++++++++++++----
Msrc/httperror.c | 2+-
Msrc/httpread.c | 36+++++++++++++++++++++++-------------
Msrc/httpserve.c | 15+++++++++++----
Msrc/httpserversocket.c | 13+++++++++----
Msrc/lockreporter.c | 12+++++++++---
Asrc/logactivitycontinuation.c | 12++++++++++++
Asrc/logactivityend.c | 12++++++++++++
Asrc/logactivitystart.c | 12++++++++++++
Msrc/main.c | 37++++++++++++++++++++++++++++++++++++-
Msrc/msgdumpbuf.c | 18+++++++++---------
Msrc/parser.y | 1+
Msrc/runservice.c | 2+-
Dsrc/servesockets.c | 11-----------
Msrc/showstatus.c | 60++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Asrc/strlcat.c | 24++++++++++++++++++++++++
Msrc/tcpserve.c | 5+++--
Msrc/unlockreporter.c | 13++++++++++---
Msrc/usage.txt | 4++++
Msrc/writelog.c | 4+---
Msrc/xstrcat.c | 2+-
Mtools/e-ver | 6++++--
36 files changed, 635 insertions(+), 232 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,6 +1,39 @@ ChangeLog for Crossroads ------------------------------------------------------------------------------ +1.03 [KK 2006-06-20] Support for older gcc's (incase strlcat() is + missing; added strlcat.c). + Added -lm to linkage flags for fmod(). + This is a new development version despite the fact that 1.02 + isn't promoted to 'stable'. + [KK 2006-06-22] Changed internal-server-error HTTP + response. Fixed very small bug in weighted random dispatchmode; + the old code wouldn't correctly see similar high weights. + [KK 2006-06-26] Fixed counting of total nr. of connections in + sticky HTTP mode (as shown with 'crossroads status'). + +1.02 [KK 2006-05-11] Next development release. + [KK 2006-05-12] In HTTP mode, the nr of sessions per back end is + stored. Improved status reporting: the nr of sessions is shown + (when type is http), the seconds and bytes are shown in a more + readable format. + [KK 2006-05-13] Fixed weighted random balancing; 1.01 had a bug + that didn't distribute new connections according to the weights + (see choose_backend()). Introduced new make target 'commit'. + [KK 2006-05-19] New flag -a introduced, that logs incoming and + ending activity. See further log_activity_*(). Docs + updated. Cleaned up the source tree (stale sources removed). + [KK 2006-06-07] Introduced -l flag for LOG_LOCAL0 to LOG_LOCAL7 + openlog facility selection. Bugfix in log_activity*() calls. + [KK 2006-06-07] Fixed lock_reporter() / unlock_reporter() so that + running connection (in program_stage == stage_serving) don't + crash during semaphore operations. This actually happens when + there's a running connection and crossroads is stopped on the + commandline. + [KK 2006-06-07] Modified the source to use strlcat/snprintf + instead of strcat/sprintf, to avoid warnings on + e.g. OpenBSD. Enveloped include <stdint.h> with an #ifdef. + 1.01 [KK 2006-05-09] Small codechange in http_serversocket() for GCC < 4.0. (There was accidentally post-3 code which I didn't notice:) [KK 2006-05-10] Improved messaging in choose_backend(), in the diff --git a/Makefile b/Makefile @@ -28,13 +28,5 @@ dist: documentation tools/e-ver ChangeLog $(VER) tools/makedist $(VER) -# This is only for uploads to public.e-tunity.com, to be done by -# me ([KK 2005-09-12]) -UPLOADHOST ?= public.e-tunity.com -upload: dist - upload-scp public.e-tunity.com/data/crossroads \ - ChangeLog doc/*.html doc/*.pdf /tmp/crossroads-$(VER).tar.gz - upload-ssh 'echo $(VER) > public.e-tunity.com/data/crossroads/VERSION' - upload-ssh 'cd public.e-tunity.com/data/crossroads && \ - rm -f crossroads-latest.tar.gz && \ - ln -s crossroads-$(VER).tar.gz crossroads-latest.tar.gz' +commit: clean documentation + svn commit +\ No newline at end of file diff --git a/doc/compiling.yo b/doc/compiling.yo @@ -22,9 +22,9 @@ subsect(Compiling and installing) itemization( it() Obtain the source distribution. It can be found on - lurl(http://public.e-tunity.com). The distribution comes as an - archive tt(crossroads-)em(X.YY)tt(.tar.gz), where em(X.YY) is - a version number. + lurl(http://crossroads.e-tunity.com). The distribution comes as an + archive tt(crossroads-)em(type)tt(.tar.gz), where em(type) is + tt(stable) or tt(devel). it() Unpack the archive in a sources directory using tt(tar xzf crossroads-)em(X.YY)tt(.tar.gz). The contents spill into a diff --git a/doc/crossroads.html b/doc/crossroads.html @@ -1,12 +1,12 @@ <a name="defs.yo"></a><html><head> -<title>Crossroads 1.01</title> +<title>Crossroads 1.03</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.01</h1> +<h1>Crossroads 1.03</h1> <h2>Karel Kubat</h2> <h2>e-tunity</h2><h2>2005, 2006, ff.</h2> @@ -34,60 +34,63 @@ </dl> <dt><h3><a href="#l6">2: Installation for the impatient</a></h3></dt> <dt><h3><a href="#l7">3: Using Crossroads</a></h3></dt> -<dt><h3><a href="#l8">4: The configuration</a></h3></dt> <dl> -<dt><a href="#l9">4.1: General language elements</a></dt> +<dt><a href="#l8">3.1: Logging-related options</a></dt> +</dl> +<dt><h3><a href="#l9">4: The configuration</a></h3></dt> +<dl> +<dt><a href="#l10">4.1: General language elements</a></dt> <dl> -<dt><a href="#l10">4.1.1: Empty lines and comments</a></dt> -<dt><a href="#l11">4.1.2: Keywords, numbers, identifiers, generic strings</a></dt> +<dt><a href="#l11">4.1.1: Empty lines and comments</a></dt> +<dt><a href="#l12">4.1.2: Keywords, numbers, identifiers, generic strings</a></dt> </dl> -<dt><a href="#l12">4.2: Service definitions</a></dt> -<dt><a href="#l13">4.3: Backend definitions</a></dt> +<dt><a href="#l13">4.2: Service definitions</a></dt> +<dt><a href="#l14">4.3: Backend definitions</a></dt> </dl> -<dt><h3><a href="#l14">5: Tips, Tricks and Remarks</a></h3></dt> +<dt><h3><a href="#l15">5: Tips, Tricks and Remarks</a></h3></dt> <dl> -<dt><a href="#l15">5.1: How back ends are selected in load balancing</a></dt> +<dt><a href="#l16">5.1: How back ends are selected in load balancing</a></dt> <dl> -<dt><a href="#l16">5.1.1: Bysize, byduration or byconnections?</a></dt> -<dt><a href="#l17">5.1.2: Averaging size and duration</a></dt> -<dt><a href="#l18">5.1.3: Specifying decays</a></dt> -<dt><a href="#l19">5.1.4: Adjusting the weights</a></dt> -<dt><a href="#l20">5.1.5: Throttling the number of concurrent connections</a></dt> +<dt><a href="#l17">5.1.1: Bysize, byduration or byconnections?</a></dt> +<dt><a href="#l18">5.1.2: Averaging size and duration</a></dt> +<dt><a href="#l19">5.1.3: Specifying decays</a></dt> +<dt><a href="#l20">5.1.4: Adjusting the weights</a></dt> +<dt><a href="#l21">5.1.5: Throttling the number of concurrent connections</a></dt> </dl> -<dt><a href="#l21">5.2: HTTP Session Stickiness</a></dt> +<dt><a href="#l22">5.2: HTTP Session Stickiness</a></dt> <dl> -<dt><a href="#l22">5.2.1: Don't use stickiness!</a></dt> -<dt><a href="#l23">5.2.2: But if you must..</a></dt> +<dt><a href="#l23">5.2.1: Don't use stickiness!</a></dt> +<dt><a href="#l24">5.2.2: But if you must..</a></dt> </dl> -<dt><a href="#l24">5.3: Configuration examples</a></dt> +<dt><a href="#l25">5.3: Configuration examples</a></dt> <dl> -<dt><a href="#l25">5.3.1: A load balancer for three webserver back ends</a></dt> -<dt><a href="#l26">5.3.2: An HTTP forwarder when travelling</a></dt> -<dt><a href="#l27">5.3.3: SSH login with enforced idle logout</a></dt> +<dt><a href="#l26">5.3.1: A load balancer for three webserver back ends</a></dt> +<dt><a href="#l27">5.3.2: An HTTP forwarder when travelling</a></dt> +<dt><a href="#l28">5.3.3: SSH login with enforced idle logout</a></dt> </dl> </dl> -<dt><h3><a href="#l28">6: Benchmarking</a></h3></dt> +<dt><h3><a href="#l29">6: Benchmarking</a></h3></dt> <dl> -<dt><a href="#l29">6.1: Benchmark 1: Accessing a proxy via crossroads or directly</a></dt> +<dt><a href="#l30">6.1: Benchmark 1: Accessing a proxy via crossroads or directly</a></dt> <dl> -<dt><a href="#l30">6.1.1: Results</a></dt> -<dt><a href="#l31">6.1.2: Discussion</a></dt> +<dt><a href="#l31">6.1.1: Results</a></dt> +<dt><a href="#l32">6.1.2: Discussion</a></dt> </dl> -<dt><a href="#l32">6.2: Benchmark 2: Crossroads versus Linux Virtual Server (LVS)</a></dt> +<dt><a href="#l33">6.2: Benchmark 2: Crossroads versus Linux Virtual Server (LVS)</a></dt> <dl> -<dt><a href="#l33">6.2.1: Environment</a></dt> -<dt><a href="#l34">6.2.2: Tests and results</a></dt> +<dt><a href="#l34">6.2.1: Environment</a></dt> +<dt><a href="#l35">6.2.2: Tests and results</a></dt> </dl> </dl> -<dt><h3><a href="#l35">7: Compiling and Installing</a></h3></dt> +<dt><h3><a href="#l36">7: Compiling and Installing</a></h3></dt> <dl> -<dt><a href="#l36">7.1: Prerequisites</a></dt> -<dt><a href="#l37">7.2: Compiling and installing</a></dt> -<dt><a href="#l38">7.3: Configuring crossroads</a></dt> -<dt><a href="#l39">7.4: A boot script</a></dt> +<dt><a href="#l37">7.1: Prerequisites</a></dt> +<dt><a href="#l38">7.2: Compiling and installing</a></dt> +<dt><a href="#l39">7.3: Configuring crossroads</a></dt> +<dt><a href="#l40">7.4: A boot script</a></dt> <dl> -<dt><a href="#l40">7.4.1: SysV Style Startup</a></dt> -<dt><a href="#l41">7.4.2: BSD Style Startup</a></dt> +<dt><a href="#l41">7.4.1: SysV Style Startup</a></dt> +<dt><a href="#l42">7.4.2: BSD Style Startup</a></dt> </dl> <p><hr><p> @@ -127,20 +130,12 @@ also available in <a href="crossroads.pdf">PDF</a> format. As quick reference, here are some important URL's for Crossroads: <p> <ul> - <li> <a href="http://public.e-tunity.com">http://public.e-tunity.com</a> is the site that serves - Crossroads and other packages. You can browse this at leisure + <li> <a href="http:/crossroads.e-tunity.com">http:/crossroads.e-tunity.com</a> is the site that serves + Crossroads. You can browse this at leisure for documentation, sources, and so on. <p> -<li> - <a href="http://public.e-tunity.com/crossroads/crossroads-latest.tar.gz">http://public.e-tunity.com/crossroads/crossroads-latest.tar.gz</a> is - the 'latest' distribution archive. (Older versions aren't - stored. If you really need an old version, contact me at - <a href="mailto:karel@e-tunity.com">karel@e-tunity.com</a>.) -<p> -<li> - <a href="http://public.e-tunity.com/crossroads/crossroads.html">http://public.e-tunity.com/crossroads/crossroads.html</a> is - the documentation in HTML format (this text). Substitute - <em>.pdf</em> for <em>.html</em> to get the documentation in PDF format. +<li> <a href="http://freshmeat.net/projects/crossr">http://freshmeat.net/projects/crossr</a> is the + Freshmeat announcement page. <p> <li> <a href="svn://svn.e-tunity.com/crossroads">svn://svn.e-tunity.com/crossroads</a> is the SVN repository; anonymous reading (fetching) is allowed. In order @@ -286,8 +281,8 @@ for getting crossroads up and running: <li> If you don't have SVN or don't want to use it: <p> <ul> - <li> Obtain the crossroads source archive at <br> - <a href="http://public.e-tunity.com/crossroads/crossroads-latest.tar.gz">http://public.e-tunity.com/crossroads/crossroads-latest.tar.gz</a>. + <li> Obtain the crossroads source archive at + <a href="http://crossroads.e-tunity.com">http://crossroads.e-tunity.com</a>. <p> <li> Change-dir to a 'sources' directory on your system and unpack the archive. @@ -352,9 +347,10 @@ That's off course assuming that you want to balance HTTP on supports a number of flags (e.g., to overrule the location of the configuration file). The actual usage information is always obtained by typing <code>crossroads</code> without any arguments. Crossroads then -displays the allowed arguments. +displays the allowed arguments. <p> -This section shows the basic usage. +This section shows the most basic usage. As said above, start +<code>crossroads</code> without arguments to view the full listing of options. <p> <ul> <li> <code>crossroads start</code> and <code>crossroads stop</code> are typical @@ -387,6 +383,49 @@ This section shows the basic usage. </ul> <p> <a name="l8"></a> +<h3>3.1: Logging-related options</h3> +<p> +Two 'flags' of Crossroads are specifically logging-related. This +section elaborates on these flags. +<p> +First, there's flag <code>-a</code>. When present, the start and end of +activity is logged using statements like +<p> +<center><em>YYYY-MM-DD HH/MM/SS starting http from 61.45.32.189 to 10.1.1.1</em></center> +<p> +Similarly, there are 'ending' statements. Using this flag and +scanning your logs for these statements may be helpful in quickly +determining your system load. +<p> +Second, there's flag <code>-l</code>. This flag selects the 'facility' of +logging and defaults to <code>LOG_DAEMON</code>. You can supply a number +between 0 and 7 to flag <code>-l</code> to select <code>LOG_LOCAL0</code> to +ttt(LOG_LOCAL7). This would separate the Crossroads-related logging +from other streams. Here's a very short guide; please read your Unix +manpages of <code>syslogd</code> for more information. +<p> +<ul> + <li> First edit <code>/etc/syslog.conf</code> and add a line: +<p> +<pre> +local7.* /var/log/crossroads.log +</pre> + +<p> +That instructs <code>syslogd</code> to send <code>LOG_LOCAL7</code> requests to the + logfile <code>/var/log/crossroads.log</code>. +<p> +<li> Next, restart <code>syslogd</code>. On most Unices that's done by + issuing <code>killall -1 syslogd</code>. (As a side-note, I tried this once + on an Bull/AIX system, and the box just shut down. The <code>killall</code> + command killed every process...) +<p> +<li> Now start <code>crossroads</code> with the flag <code>-l7</code>. +<p> +<li> Finally, monitor <code>/var/log/crossroads.log</code> for Crossroads' + messages.</ul> +<p> +<a name="l9"></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 @@ -395,13 +434,13 @@ command line flag <code>-c</code>. This section explains the syntax of the configuration file, and what all settings do. <p> -<a name="l9"></a> +<a name="l10"></a> <h3>4.1: General language elements</h3> <p> This section describes the general elements of the crossroads configuration language. <p> -<a name="l10"></a> +<a name="l11"></a> <strong>4.1.1: Empty lines and comments</strong> <p> Empty lines are of course allowed in the @@ -419,7 +458,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="l11"></a> +<a name="l12"></a> <strong>4.1.2: Keywords, numbers, identifiers, generic strings</strong> <p> In a configuration file, statements are identified by <em>keywords</em>, @@ -454,7 +493,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="l12"></a> +<a name="l13"></a> <h3>4.2: Service definitions</h3> <p> Service definitions are blocks in the configuration file that @@ -677,7 +716,7 @@ is exceeded. <p> </dl> <p> -<a name="l13"></a> +<a name="l14"></a> <h3>4.3: Backend definitions</h3> <p> Inside the service definitions as are described in the previous @@ -984,13 +1023,13 @@ Summarizing, the throughput times of a client-back end connection <p> </dl> <p> -<a name="l14"></a> +<a name="l15"></a> <h2>5: Tips, Tricks and 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="l15"></a> +<a name="l16"></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 @@ -999,7 +1038,7 @@ section we'll focus on the dispatching modes <code>bysize</code>, <code>bydurati and <code>byconnections</code> only. The other dispatching types are self-explanatory. <p> -<a name="l16"></a> +<a name="l17"></a> <strong>5.1.1: Bysize, byduration or byconnections?</strong> <p> As stated before, crossroads doesn't know 'what a service does' and @@ -1049,7 +1088,7 @@ E.g., consider a database connection. What's <p> </ul> <p> -<a name="l17"></a> +<a name="l18"></a> <strong>5.1.2: Averaging size and duration</strong> <p> The configuration statement <code>dispatchmode bysize</code> or <code>byduration</code> @@ -1070,7 +1109,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="l18"></a> +<a name="l19"></a> <strong>5.1.3: Specifying decays</strong> <p> Decays are also only relevant when crossroads computes the 'next best @@ -1124,7 +1163,7 @@ service soap { </pre> <p> -<a name="l19"></a> +<a name="l20"></a> <strong>5.1.4: Adjusting the weights</strong> <p> The back end modifier <code>weight</code> is useful in situations where your @@ -1178,7 +1217,7 @@ 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="l20"></a> +<a name="l21"></a> <strong>5.1.5: Throttling the number of concurrent connections</strong> <p> If you suspect that your service may occasionally receive 'spikes' of @@ -1208,7 +1247,7 @@ 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="l21"></a> +<a name="l22"></a> <h3>5.2: HTTP Session Stickiness</h3> <p> This section focuses on HTTP session stickiness. This term refers to @@ -1217,7 +1256,7 @@ a backend farm 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="l22"></a> +<a name="l23"></a> <strong>5.2.1: Don't use stickiness!</strong> <p> The rule of thumb as far as the balancer is concerned, is: <strong>Do not @@ -1245,7 +1284,7 @@ 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="l23"></a> +<a name="l24"></a> <strong>5.2.2: But if you must..</strong> <p> However, if you <strong>must</strong> use session stickiness, then proceed as @@ -1300,14 +1339,14 @@ Note how the cookie names and values in the directives <code>stickycookie</code> and <code>insertcookie</code> match. That is obviously a prerequisite for stickiness. <p> -<a name="l24"></a> +<a name="l25"></a> <h3>5.3: 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. <p> -<a name="l25"></a> +<a name="l26"></a> <strong>5.3.1: A load balancer for three webserver back ends</strong> <p> The following configuration example binds crossroads to port 80 of the @@ -1436,7 +1475,7 @@ service www { </pre> <p> -<a name="l26"></a> +<a name="l27"></a> <strong>5.3.2: An HTTP forwarder when travelling</strong> <p> As another example, here's my <code>crossroads.conf</code> that I use on my @@ -1525,7 +1564,7 @@ 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="l27"></a> +<a name="l28"></a> <strong>5.3.3: SSH login with enforced idle logout</strong> <p> The following example shows how crossroads 'throttles' SSH @@ -1551,13 +1590,13 @@ service Ssh { </pre> <p> -<a name="l28"></a> +<a name="l29"></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="l29"></a> +<a name="l30"></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: @@ -1585,7 +1624,7 @@ service HttpProxy { </pre> <p> -<a name="l30"></a> +<a name="l31"></a> <strong>6.1.1: Results</strong> <p> The results of this test are that crossroads causes a negligible @@ -1608,7 +1647,7 @@ sys 0m0.230s </pre> <p> -<a name="l31"></a> +<a name="l32"></a> <strong>6.1.2: Discussion</strong> <p> The above shown results are quite favorable to crossroads. However, @@ -1640,7 +1679,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="l32"></a> +<a name="l33"></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 @@ -1654,7 +1693,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="l33"></a> +<a name="l34"></a> <strong>6.2.1: Environment</strong> <p> On the balancer, LVS was run on port 80, its forwarding set up for two @@ -1685,7 +1724,7 @@ service http { </pre> <p> -<a name="l34"></a> +<a name="l35"></a> <strong>6.2.2: Tests and results</strong> <p> In the first test, ports 80 and 81 on the balancer were 'bombed' with @@ -1764,9 +1803,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="l35"></a> +<a name="l36"></a> <h2>7: Compiling and Installing</h2> -<a name="compiling"></a><a name="l36"></a> +<a name="compiling"></a><a name="l37"></a> <h3>7.1: Prerequisites</h3> <p> The creation of crossroads requires: @@ -1786,14 +1825,14 @@ Basically a Linux or Apple MacOSX box will do nicely once you make sure that <code>bison</code> and <code>flex</code> are installed. To compile and install crossroads, follow these steps. <p> -<a name="l37"></a> +<a name="l38"></a> <h3>7.2: Compiling and installing</h3> <p> <ul> <li> Obtain the source distribution. It can be found on - <a href="http://public.e-tunity.com">http://public.e-tunity.com</a>. The distribution comes as an - archive <code>crossroads-</code><em>X.YY</em><code>.tar.gz</code>, where <em>X.YY</em> is - a version number. + <a href="http://crossroads.e-tunity.com">http://crossroads.e-tunity.com</a>. The distribution comes as an + archive <code>crossroads-</code><em>type</em><code>.tar.gz</code>, where <em>type</em> is + <code>stable</code> or <code>devel</code>. <p> <li> Unpack the archive in a sources directory using <code>tar xzf crossroads-</code><em>X.YY</em><code>.tar.gz</code>. The contents spill into a @@ -1844,7 +1883,7 @@ crossroads, follow these steps. <p> </ul> <p> -<a name="l38"></a> +<a name="l39"></a> <h3>7.3: Configuring crossroads</h3> <p> Now that the binary is available on your system, you need to create a @@ -1893,13 +1932,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="l39"></a> +<a name="l40"></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="l40"></a> +<a name="l41"></a> <strong>7.4.1: SysV Style Startup</strong> <p> On SysV style systems, there's a startup script directory @@ -1941,7 +1980,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="l41"></a> +<a name="l42"></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\&.01" "2005, 2006, ff\&." +.TH "Crossroads 1\&.03" "2005, 2006, ff\&." .PP -.SH "Crossroads 1\&.01" +.SH "Crossroads 1\&.03" .SH "Karel Kubat" .SH "e-tunity" .SH "2005, 2006, ff\&." @@ -41,20 +41,13 @@ compile the program from its sources\&. As quick reference, here are some important URL\&'s for Crossroads: .PP .IP o -http://public\&.e-tunity\&.com is the site that serves -Crossroads and other packages\&. You can browse this at leisure +http:/crossroads\&.e-tunity\&.com is the site that serves +Crossroads\&. You can browse this at leisure for documentation, sources, and so on\&. .IP .IP o -http://public\&.e-tunity\&.com/crossroads/crossroads-latest\&.tar\&.gz is -the \&'latest\&' distribution archive\&. (Older versions aren\&'t -stored\&. If you really need an old version, contact me at -karel@e-tunity\&.com\&.) -.IP -.IP o -http://public\&.e-tunity\&.com/crossroads/crossroads\&.html is -the documentation in HTML format (this text)\&. Substitute -\fI\&.pdf\fP for \fI\&.html\fP to get the documentation in PDF format\&. +http://freshmeat\&.net/projects/crossr is the +Freshmeat announcement page\&. .IP .IP o svn://svn\&.e-tunity\&.com/crossroads is the SVN @@ -215,9 +208,8 @@ for getting crossroads up and running: If you don\&'t have SVN or don\&'t want to use it: .IP .IP o -Obtain the crossroads source archive at -.br -http://public\&.e-tunity\&.com/crossroads/crossroads-latest\&.tar\&.gz\&. +Obtain the crossroads source archive at +http://crossroads\&.e-tunity\&.com\&. .IP .IP o Change-dir to a \&'sources\&' directory on your system and @@ -293,9 +285,10 @@ Crossroads is started from the commandline, and highly depends on supports a number of flags (e\&.g\&., to overrule the location of the configuration file)\&. The actual usage information is always obtained by typing \f(CWcrossroads\fP without any arguments\&. Crossroads then -displays the allowed arguments\&. +displays the allowed arguments\&. .PP -This section shows the basic usage\&. +This section shows the most basic usage\&. As said above, start +\f(CWcrossroads\fP without arguments to view the full listing of options\&. .PP .IP o \f(CWcrossroads start\fP and \f(CWcrossroads stop\fP are typical @@ -334,6 +327,54 @@ configuration \f(CW/etc/crossroads\&.conf\fP\&. .PP +.SH "3\&.1: Logging-related options" + +.PP +Two \&'flags\&' of Crossroads are specifically logging-related\&. This +section elaborates on these flags\&. +.PP +First, there\&'s flag \f(CW-a\fP\&. When present, the start and end of +activity is logged using statements like +.PP +\fIYYYY-MM-DD HH/MM/SS starting http from 61\&.45\&.32\&.189 to 10\&.1\&.1\&.1\fP + +.PP +Similarly, there are \&'ending\&' statements\&. Using this flag and +scanning your logs for these statements may be helpful in quickly +determining your system load\&. +.PP +Second, there\&'s flag \f(CW-l\fP\&. This flag selects the \&'facility\&' of +logging and defaults to \f(CWLOG_DAEMON\fP\&. You can supply a number +between 0 and 7 to flag \f(CW-l\fP to select \f(CWLOG_LOCAL0\fP to +ttt(LOG_LOCAL7)\&. This would separate the Crossroads-related logging +from other streams\&. Here\&'s a very short guide; please read your Unix +manpages of \f(CWsyslogd\fP for more information\&. +.PP +.IP o +First edit \f(CW/etc/syslog\&.conf\fP and add a line: +.IP +.nf +local7\&.* /var/log/crossroads\&.log +.fi + +.IP +That instructs \f(CWsyslogd\fP to send \f(CWLOG_LOCAL7\fP requests to the +logfile \f(CW/var/log/crossroads\&.log\fP\&. +.IP +.IP o +Next, restart \f(CWsyslogd\fP\&. On most Unices that\&'s done by +issuing \f(CWkillall -1 syslogd\fP\&. (As a side-note, I tried this once +on an Bull/AIX system, and the box just shut down\&. The \f(CWkillall\fP +command killed every process\&.\&.\&.) +.IP +.IP o +Now start \f(CWcrossroads\fP with the flag \f(CW-l7\fP\&. +.IP +.IP o +Finally, monitor \f(CW/var/log/crossroads\&.log\fP for Crossroads\&' +messages\&. +.PP + .SH "4: The configuration" The configuration that crossroads uses is normally stored in the file \f(CW/etc/crossroads\&.conf\fP\&. This location can be overruled using the @@ -1830,9 +1871,9 @@ crossroads, follow these steps\&. .PP .IP o Obtain the source distribution\&. It can be found on -http://public\&.e-tunity\&.com\&. The distribution comes as an -archive \f(CWcrossroads-\fP\fIX\&.YY\fP\f(CW\&.tar\&.gz\fP, where \fIX\&.YY\fP is -a version number\&. +http://crossroads\&.e-tunity\&.com\&. The distribution comes as an +archive \f(CWcrossroads-\fP\fItype\fP\f(CW\&.tar\&.gz\fP, where \fItype\fP is +\f(CWstable\fP or \f(CWdevel\fP\&. .IP .IP o Unpack the archive in a sources directory using \f(CWtar diff --git a/doc/crossroads.pdf b/doc/crossroads.pdf Binary files differ. diff --git a/doc/impatient.yo b/doc/impatient.yo @@ -7,8 +7,8 @@ itemization( it() If you don't have SVN or don't want to use it: itemization( - it() Obtain the crossroads source archive at nl() - lurl(http://public.e-tunity.com/crossroads/crossroads-latest.tar.gz). + it() Obtain the crossroads source archive at + lurl(http://crossroads.e-tunity.com). it() Change-dir to a 'sources' directory on your system and unpack the archive. diff --git a/doc/using.yo b/doc/using.yo @@ -3,9 +3,10 @@ tt(/etc/crossroads.conf) (the default configuration file). It supports a number of flags (e.g., to overrule the location of the configuration file). The actual usage information is always obtained by typing tt(crossroads) without any arguments. Crossroads then -displays the allowed arguments. +displays the allowed arguments. -This section shows the basic usage. +This section shows the most basic usage. As said above, start +tt(crossroads) without arguments to view the full listing of options. itemization( it() tt(crossroads start) and tt(crossroads stop) are typical @@ -36,3 +37,42 @@ itemization( file syntax, or of getting a start for your own configuration tt(/etc/crossroads.conf). ) + +subsect(Logging-related options) + +Two 'flags' of Crossroads are specifically logging-related. This +section elaborates on these flags. + +First, there's flag tt(-a). When present, the start and end of +activity is logged using statements like + +center(em(YYYY-MM-DD HH/MM/SS starting http from 61.45.32.189 to 10.1.1.1)) + +Similarly, there are 'ending' statements. Using this flag and +scanning your logs for these statements may be helpful in quickly +determining your system load. + +Second, there's flag tt(-l). This flag selects the 'facility' of +logging and defaults to tt(LOG_DAEMON). You can supply a number +between 0 and 7 to flag tt(-l) to select tt(LOG_LOCAL0) to +ttt(LOG_LOCAL7). This would separate the Crossroads-related logging +from other streams. Here's a very short guide; please read your Unix +manpages of tt(syslogd) for more information. + +itemization( + it() First edit tt(/etc/syslog.conf) and add a line: + + verb(local7.* /var/log/crossroads.log) + + That instructs tt(syslogd) to send tt(LOG_LOCAL7) requests to the + logfile tt(/var/log/crossroads.log). + + it() Next, restart tt(syslogd). On most Unices that's done by + issuing tt(killall -1 syslogd). (As a side-note, I tried this once + on an Bull/AIX system, and the box just shut down. The tt(killall) + command killed every process...) + + it() Now start tt(crossroads) with the flag tt(-l7). + + it() Finally, monitor tt(/var/log/crossroads.log) for Crossroads' + messages.) +\ No newline at end of file diff --git a/etc/Makefile.def b/etc/Makefile.def @@ -3,7 +3,7 @@ # Versioning. This defines the overall version ID and must match the topmost # entry in the ChangeLog. -VER = 1.01 +VER = 1.03 # Default config DEFAULT_CONF = /etc/crossroads.conf diff --git a/etc/Makefile.help b/etc/Makefile.help @@ -10,6 +10,7 @@ Make what? Choose: and pdflatex. make clean Cleanup of stale files make distclean Even cleaner still - make dist Creates a distribution (e-tunity only) - make upload Uploads to our public site (e-tunity only) + make dist Creates a distribution as + /tmp/crossroads-VERSION.tar.gz, Yodl etc. required + make commit Creates documentation, cleans up, commits into SVN. ============================================================================ diff --git a/src/Makefile b/src/Makefile @@ -40,8 +40,10 @@ DEFS = -DDEFAULT_CONF=\"$(DEFAULT_CONF)\" -DMAX_BACKEND=$(MAX_BACKEND) \ -DCONNECT_TIMEOUT=$(CONNECT_TIMEOUT) -DVER=\"$(VER)\" \ -DSET_PROC_TITLE_BY_ARGV=$(SET_PROC_TITLE_BY_ARGV) \ $(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 lockf HAVE_LOCKF) \ + $(shell ../tools/c-conf libfunction strlcat HAVE_STRLCAT) LIBS = $(shell ../tools/c-conf lib ucb nsl pthread socket 2>/dev/null) @@ -55,7 +57,7 @@ lexer.o: lexer.c $(CC) $(DEFS) -c -g -Wall $< crossroads: libcrossroads.a - $(CC) $(EXTRALIBS) -g -L. -lcrossroads $(LIBS) -o $@ + $(CC) $(EXTRALIBS) -g -L. -lcrossroads $(LIBS) -o $@ -lm libcrossroads.a: $(OBJ) ar rs libcrossroads.a $(OBJ) diff --git a/src/ansistamp.c b/src/ansistamp.c @@ -0,0 +1,14 @@ +#include "crossroads.h" + +char *ansistamp () { + static char buf[80]; + time_t now; + struct tm *tmp; + + time (&now); + tmp = localtime (&now); + snprintf (buf, sizeof(buf), "%4.4d-%2.2d-%2.2d/%2.2d:%2.2d:%2.2d", + tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + return (buf); +} diff --git a/src/choosebackend.c b/src/choosebackend.c @@ -2,8 +2,8 @@ void choose_backend () { int backends[MAX_BACKEND], nbackends = 0, i, j, k, - target_set = 0, flat_weights = 1, total_weights = 0, - random_weight, *weights, highest_weight = 0; + target_set = 0, flat_weights = 1, weights[MAX_BACKEND], *sel_weights, + tot_weights, lo_val, hi_val, done; unsigned long long values[MAX_BACKEND], nbest; unsigned nclients; struct timeval tv; @@ -79,41 +79,86 @@ void choose_backend () { /* Re-randomize. */ gettimeofday (&tv, 0); srand ((unsigned) tv.tv_usec); - + /* First of all let's see if all the weights are the same. */ + tot_weights = 0; for (i = 0; i < nbackends; i++) { - total_weights += activeservice->backend[backends[i]].weight; values[i] = activeservice->backend[backends[i]].weight; if (activeservice->backend[backends[i]].weight != 1) flat_weights = 0; - if (highest_weight < activeservice->backend[backends[i]].weight) - highest_weight = activeservice->backend[backends[i]].weight; } if (! flat_weights) { /* Non-flat weight random balancing. Determine the chance * to hit a given back end. First we populate the weights array. - * Eg imagine we have 3 back ends with weights 1,2,4. Then the - * weights vector will be: 0,0,0,0,1,1,2 (0/1/2 being the indices - * of the candidate back ends) - */ - weights = xmalloc (total_weights * sizeof(int)); + * Eg imagine we have 4 back ends with weights 1,2,3,4. Then + * ultimately we need to get a selection array of indices: + * 0000111223, meaning that the chance to hit index 0 is 4/10 + * and so on */ + + /* First of all we reverse the values vector, to get 4,3,2,1 */ + done = 0; + while (!done) { + done = 1; + lo_val = 9999999; + hi_val = 0; + /* Find highest/lowest weights in values vector. */ + for (i = 0; i < nbackends; i++) { + if (!values[i]) + continue; + done = 0; + if (lo_val >= values[i]) + lo_val = values[i]; + if (hi_val <= values[i]) + hi_val = values[i]; + } + + if (done) + break; + + /* Stick the values into the duplicate 'weights' array, + but the other way 'round. */ + for (i = 0; i < nbackends; i++) + if (values[i] == lo_val) + weights[i] = hi_val; + else if (values[i] == hi_val) + weights[i] = lo_val; + + for (i = 0; i < nbackends; i++) + if (values[i] == lo_val) { + tot_weights += hi_val; + values[i] = 0; + } else if (values[i] == hi_val) { + tot_weights += lo_val; + values[i] = 0; + } + } + + /* The 'weights' vector is now the reverse of 'values'. + * Create a selection array. */ + sel_weights = xmalloc (tot_weights * sizeof(int)); k = 0; for (i = 0; i < nbackends; i++) - for (j = 0; - j < highest_weight / - activeservice->backend[backends[i]].weight; - j++) - weights[k++] = i; - for (k = 0; k < total_weights; k++) - msg ("random: weights[%d] = %d", k, weights[k]); + for (j = 0; j < weights[i]; j++) { + sel_weights[k] = i; + k++; + } + + /* Debugging: */ + for (k = 0; k < tot_weights; k++) + msg ("random: sel_weight[%d] = %d", k, sel_weights[k]); - random_weight = rand() % total_weights; - current_backend = backends[weights[random_weight]]; + /* Select the next random back end. */ + /* + * i = rand() % tot_weights; + * j = sel_weights[i]; + * k = backends[j]; + * current_backend = k; + * msg ("i=%d j=%d, k=%d", i, j, k); */ + current_backend = backends[sel_weights[rand() % tot_weights]]; servicereport->last_backend = current_backend; - msg ("Chosen backend (weighted random): %d, " - "due to random weight %d (out of %d total)", - current_backend, random_weight, total_weights); + free (sel_weights); + msg ("Chosen backend (weighted random): %d", current_backend); return; } @@ -133,17 +178,18 @@ void choose_backend () { servicereport->backendstate[backends[i]].avg_nbytes) values[i] = servicereport->backendstate[backends[i]].avg_nbytes * - servicereport->backendstate[backends[i]].avg_nbytes * activeservice->backend[backends[i]].weight; else values[i] = servicereport->backendstate[backends[i]].nbytes * activeservice->backend[backends[i]].weight; - msg ("By size weighing: backend %d has value %lu" - " (bytes=%lu, avgbytes=%lu, weight=%d)", - backends[i], values[i], - servicereport->backendstate[backends[i]].nbytes, - servicereport->backendstate[backends[i]].avg_nbytes, - activeservice->backend[backends[i]].weight); + msg ("By size weighing: backend %d has weight %d, value %u" + " (bytes=%u, avgbytes=%u)", + backends[i], + activeservice->backend[backends[i]].weight, + (unsigned) values[i], + (unsigned) servicereport->backendstate[backends[i]].nbytes, + (unsigned) + servicereport->backendstate[backends[i]].avg_nbytes); } /* Get the backend that has transported the least bytes */ for (i = 0; i < nbackends; i++) diff --git a/src/copysockets.c b/src/copysockets.c @@ -1,6 +1,6 @@ #include "crossroads.h" -void copysockets (int clientsock, int serversock) { +void copysockets (int clientsock, int serversock, struct sockaddr_in *client) { int src_fd, dst_fd, nfd; int nread, nwritten, totwritten; unsigned char buf[10240]; @@ -20,6 +20,8 @@ void copysockets (int clientsock, int serversock) { unlock_reporter(); /* Cpio back and forth. */ + log_activity_start (client); + while (1) { FD_ZERO (&readset); FD_SET (clientsock, &readset); @@ -55,6 +57,7 @@ void copysockets (int clientsock, int serversock) { servicereport->nclients--; servicereport->backendstate[current_backend].nclients--; unlock_reporter(); + log_activity_end (client); if (! nfd) { /* This must be caused by a timeout in select(), otherwise @@ -84,6 +87,7 @@ void copysockets (int clientsock, int serversock) { servicereport->nclients--; servicereport->backendstate[current_backend].nclients--; unlock_reporter(); + log_activity_end (client); error ("Exception on client connection"); } if (FD_ISSET(serversock, &exceptset)) { @@ -92,6 +96,7 @@ void copysockets (int clientsock, int serversock) { servicereport->backendstate[current_backend].nclients--; unlock_reporter(); mark_activity (0, 0, st_unavailable); + log_activity_end (client); error ("Exception on backend connection"); } @@ -117,6 +122,7 @@ void copysockets (int clientsock, int serversock) { mark_activity (0, 0, st_available); close (serversock); close (clientsock); + log_activity_end (client); /* In forked mode, we're done. In foreground mode, RTC. */ if (flag_foreground) { @@ -133,6 +139,7 @@ void copysockets (int clientsock, int serversock) { servicereport->nclients--; servicereport->backendstate[current_backend].nclients--; unlock_reporter(); + log_activity_end (client); error ("Read error on connection from %s", src_str); } @@ -155,6 +162,7 @@ void copysockets (int clientsock, int serversock) { servicereport->nclients--; servicereport->backendstate[current_backend].nclients--; unlock_reporter(); + log_activity_end (client); error ("Write error when copying to %s", dst_str); } // msg ("Wrote another %d bytes to %s in this connection", diff --git a/src/crossroads.h b/src/crossroads.h @@ -14,7 +14,9 @@ #include <stdarg.h> #include <stdio.h> #include <stdlib.h> +#ifdef HAVE_STDINT_H #include <stdint.h> +#endif #include <string.h> #include <syslog.h> #include <time.h> @@ -149,6 +151,7 @@ typedef struct { /* Backend state */ unsigned long totuses; /* .. times hit */ unsigned long failures; /* .. times failed */ unsigned long long nbytes; /* .. transferred bytes */ + unsigned long sessions; /* .. # of http sessions */ unsigned long avg_nbytes; /* .. averaged over # connections */ double nsec; /* .. connection durations */ double avg_nsec; /* .. averaged over # connections */ @@ -185,6 +188,9 @@ EXTERN int flag_verbose; /* flag: verbosity */ EXTERN int iflag_present; /* flag: -i present */ EXTERN int interrupted; /* got a signal? */ EXTERN char *laststring; /* semantic lexer value */ +EXTERN int log_activity; /* log activy to syslog? */ +EXTERN int log_facility; /* openlog(3) facility, -l flag */ +EXTERN int logstarted; /* was syslog() called yet? */ EXTERN int nservice; /* # service descriptions */ EXTERN int org_argc; /* original argc */ EXTERN char **org_argv; /* and original argv */ @@ -202,10 +208,12 @@ EXTERN char *yytext; /* lexical buffer */ /* Functions. */ extern void alloc_reporter (Service *active, int first); +extern char *ansistamp (void); extern int backend_available (void); extern int backend_connect (int is_waking); extern void choose_backend (void); -extern void copysockets (int clientsock, int serversock); +extern void copysockets (int clientsock, int serversock, + struct sockaddr_in *client); extern void configtest (int ac, char **av); extern void dealloc_reporter (Service *s); extern void error (char const *fmt, ...); @@ -220,8 +228,9 @@ extern int http_headers_done (unsigned char const *buf); extern int http_09_received (unsigned char const *buf); extern void http_read (int sock, int isclient, unsigned char **bufp, int *buflen); -extern void http_serve (int clientsock); -extern int http_serversocket (unsigned char const *buf); +extern void http_serve (int clientsock, struct sockaddr_in *client); +extern int http_serversocket (unsigned char const *buf, + int *is_continuation); extern void http_set_sticky_cookie (unsigned char **buf, int *buflen); extern int http_write (int sock, unsigned char const *buf, int buflen); extern int init_sockaddr (struct sockaddr_in *name, @@ -229,6 +238,9 @@ extern int init_sockaddr (struct sockaddr_in *name, extern void interrupt (int sig); extern int ishexdigit (char c); extern void lock_reporter (void); +extern void log_activity_start (struct sockaddr_in *client); +extern void log_activity_end (struct sockaddr_in *client); +extern void log_activity_continuation (struct sockaddr_in *client); extern int make_socket (int port, char const *ipaddr); extern void mark_activity (unsigned long long nbytes, double nsec, @@ -239,7 +251,6 @@ extern void restart (int ac, char **av); extern void runservice (void); extern void sample_conf (int ac, char **av); extern void serve (int ac, char **av); -extern void servesockets (int clientsock, int backendsock); extern void set_program_title (char const *fmt, ...); extern void show_services (int ac, char **av); extern void show_status (int ac, char **av); @@ -264,3 +275,8 @@ extern void *xmalloc (unsigned sz); extern void *xrealloc (void *what, unsigned sz); extern char *xstrcat (char *what, char const *rest); extern char *xstrdup (char const *what); + +/* strlcat() if it's missing on this system */ +#ifndef HAVE_STRLCAT +extern size_t strlcat (char *dst, char const *src, size_t size); +#endif diff --git a/src/httperror.c b/src/httperror.c @@ -6,7 +6,7 @@ char *str = "Please try again later.\n"; void http_error (int clientsock) { - char *buf = str_printf ("HTTP/1.x 502 Internal Server Error\r\n" + char *buf = str_printf ("HTTP/1.0 502 Internal Server Error\r\n" "Content-Length: %d\r\n" "\r\n" "%s", diff --git a/src/httpread.c b/src/httpread.c @@ -16,11 +16,12 @@ void http_read (int sock, int isclient, unsigned char **bufp, int *buflen) { /* Promote the verbosity of the backend */ flag_verbose = activeservice->backend[current_backend].verbosity; - /* Get starting time */ + /* Get starting time, update # clients (if this is a backend read) */ gettimeofday (&start_tv, 0); lock_reporter(); servicereport->nclients++; - servicereport->backendstate[current_backend].nclients++; + if (!isclient) + servicereport->backendstate[current_backend].nclients++; unlock_reporter(); while (1) { @@ -42,15 +43,19 @@ void http_read (int sock, int isclient, unsigned char **bufp, int *buflen) { microsec = ( (tv.tv_sec * 1000000 + tv.tv_usec) - (start_tv.tv_sec * 1000000 + start_tv.tv_usec) ); gettimeofday (&start_tv, 0); - mark_activity (0, microsec / 1000000, st_intermediate); - // msg ("Spent another %g microsecs in this connection.", microsec); - + if (!isclient) + mark_activity (0, microsec / 1000000, st_intermediate); + /* msg ("Spent another %g microsecs in this connection.", + microsec); */ + if (nfd < 1) { /* Done, with error */ lock_reporter(); servicereport->nclients--; - servicereport->backendstate[current_backend].nclients--; + if (!isclient) + servicereport->backendstate[current_backend].nclients--; unlock_reporter(); + if (nfd < 0) error ("Failed to wait for HTTP input: %s", strerror(errno)); else @@ -62,9 +67,11 @@ void http_read (int sock, int isclient, unsigned char **bufp, int *buflen) { if (nread < 1) { lock_reporter(); servicereport->nclients--; - servicereport->backendstate[current_backend].nclients--; - unlock_reporter(); - mark_activity (0, 0, st_available); + if (!isclient) + servicereport->backendstate[current_backend].nclients--; + unlock_reporter(); + if (!isclient) + mark_activity (0, 0, st_available); if (nread < 0) warning ("Failed to read HTTP input: %s", strerror(errno)); else @@ -85,7 +92,8 @@ void http_read (int sock, int isclient, unsigned char **bufp, int *buflen) { /* Update the intermediate activity as far as the read bytes * are concerned. Update traffic / thruput logs. */ // msg ("Read %d bytes from socket %d", nread, sock); - mark_activity (nread, 0, st_intermediate); + if (!isclient) + mark_activity (nread, 0, st_intermediate); trafficlog ( (unsigned char *) buf, nread, isclient); thruputlog ( (unsigned char *) buf, nread, isclient); @@ -98,9 +106,11 @@ void http_read (int sock, int isclient, unsigned char **bufp, int *buflen) { if (http_complete (*bufp, *buflen)) { lock_reporter(); servicereport->nclients--; - servicereport->backendstate[current_backend].nclients--; - unlock_reporter(); - mark_activity (0, 0, st_available); + if (!isclient) + servicereport->backendstate[current_backend].nclients--; + unlock_reporter(); + if (!isclient) + mark_activity (0, 0, st_available); msg ("HTTP read: complete message (%d bytes) '%s'", *buflen, *bufp); return; diff --git a/src/httpserve.c b/src/httpserve.c @@ -1,8 +1,8 @@ #include "crossroads.h" -void http_serve (int clientsock) { +void http_serve (int clientsock, struct sockaddr_in *client) { unsigned char *firstbuf, *secondbuf; - int serversock, buflen; + int serversock, buflen, is_continuation; /* Fork off a servicer if we're in daemon mode. */ if (fork_tcp_servicer(-1)) @@ -12,8 +12,15 @@ void http_serve (int clientsock) { http_read (clientsock, 1, &firstbuf, &buflen); /* Determine the back end and send the initial client request. */ - if ( (serversock = http_serversocket (firstbuf)) < 1 ) + if ( (serversock = http_serversocket (firstbuf, &is_continuation)) < 1 ) http_error (clientsock); + + /* Log what's going on. We only log the continuation here, + * because copysockets below will handle the start/end. + */ + if (is_continuation) + log_activity_continuation (client); + if (http_write (serversock, firstbuf, buflen)) { mark_activity (0, 0, st_unavailable); error ("Failed to send data to backend '%s'", @@ -35,7 +42,7 @@ void http_serve (int clientsock) { /* Now we have a client and server socket, possibly with a * session cookie in the chat. Piggyback to & fro. */ - copysockets (clientsock, serversock); + copysockets (clientsock, serversock, client); /* Normal shutdown: TCP traffic done. */ msg ("Normal HTTP stop."); diff --git a/src/httpserversocket.c b/src/httpserversocket.c @@ -1,10 +1,10 @@ #include "crossroads.h" -int http_serversocket (unsigned char const *buf) { +int http_serversocket (unsigned char const *buf, int *is_continuation) { int i, sock; msg ("Searching for back end for HTTP request."); - + /* Try to find a sticky cookie in the request. */ for (i = 0; i < activeservice->nbackend; i++) { if (servicereport->backendstate[i].avail != st_available) @@ -22,8 +22,10 @@ int http_serversocket (unsigned char const *buf) { * If it doesn't succeed, then we'll do a failover to * any other back end. */ current_backend = i; - if ( (sock = backend_connect (0)) >= 0 ) + if ( (sock = backend_connect (0)) >= 0 ) { + *is_continuation = 1; return (sock); + } } } @@ -45,7 +47,10 @@ int http_serversocket (unsigned char const *buf) { } msg ("Trying back end %d for new HTTP connection", current_backend); - if ( (sock = backend_connect (0)) >= 0 ) + if ( (sock = backend_connect (0)) >= 0 ) { + servicereport->backendstate[current_backend].sessions++; + *is_continuation = 0; return (sock); + } } } diff --git a/src/lockreporter.c b/src/lockreporter.c @@ -1,6 +1,7 @@ #include "crossroads.h" void lock_reporter() { + static int warning_issued = 0; struct sembuf buf[] = { { 0, /* semaphore number */ @@ -18,7 +19,12 @@ void lock_reporter() { return; /* msg ("Locking reporter memory"); */ - if (semop (semid, buf, 2) < 0) - error ("Failed to lock reporter memory (stage %s): %s", - stage_to_string (program_stage), strerror(errno)); + if ( (!warning_issued++) && (semop (semid, buf, 2) < 0) ) { + warning ("Failed to lock reporter memory (stage %s): %s", + stage_to_string (program_stage), strerror(errno)); + if (program_stage != stage_serving) + exit (1); + else + warning (".. but continuing serving this TCP connection"); + } } diff --git a/src/logactivitycontinuation.c b/src/logactivitycontinuation.c @@ -0,0 +1,12 @@ +#include "crossroads.h" + +void log_activity_continuation (struct sockaddr_in *client) { + if (!log_activity) + return; + if (!logstarted++) + openlog ("crossroads", LOG_PID, log_facility); + syslog (LOG_NOTICE, "%s continuing %s from %s to %s", + ansistamp(), activeservice->name, + inet_ntoa (client->sin_addr), + activeservice->backend[current_backend].server); +} diff --git a/src/logactivityend.c b/src/logactivityend.c @@ -0,0 +1,12 @@ +#include "crossroads.h" + +void log_activity_end (struct sockaddr_in *client) { + if (!log_activity) + return; + if (!logstarted++) + openlog ("crossroads", LOG_PID, log_facility); + syslog (LOG_NOTICE, "%s ending %s from %s to %s", + ansistamp(), activeservice->name, + inet_ntoa (client->sin_addr), + activeservice->backend[current_backend].server); +} diff --git a/src/logactivitystart.c b/src/logactivitystart.c @@ -0,0 +1,12 @@ +#include "crossroads.h" + +void log_activity_start (struct sockaddr_in *client) { + if (!log_activity) + return; + if (!logstarted++) + openlog ("crossroads", LOG_PID, log_facility); + syslog (LOG_NOTICE, "%s starting %s from %s to %s", + ansistamp(), activeservice->name, + inet_ntoa (client->sin_addr), + activeservice->backend[current_backend].server); +} diff --git a/src/main.c b/src/main.c @@ -4,6 +4,8 @@ /* Explicit initializations. */ +int log_facility = LOG_DAEMON; + char *state_to_string_map [] = { /* backend states as strings */ "available", "UNAVAILABLE", @@ -50,8 +52,11 @@ int main (int argc, char **argv) { /* Parse options. */ config_file = DEFAULT_CONF; - while ( (opt = getopt (argc, argv, "?c:fhvi:u:V")) > 0 ) + while ( (opt = getopt (argc, argv, "?c:fhvi:u:Val:")) > 0 ) switch (opt) { + case 'a': + log_activity++; + break; case 'c': config_file = optarg; break; @@ -64,6 +69,36 @@ int main (int argc, char **argv) { case 'i': iflag_present++; break; + case 'l': + switch (atoi (optarg)) { + case 0: + log_facility = LOG_LOCAL0; + break; + case 1: + log_facility = LOG_LOCAL1; + break; + case 2: + log_facility = LOG_LOCAL2; + break; + case 3: + log_facility = LOG_LOCAL3; + break; + case 4: + log_facility = LOG_LOCAL4; + break; + case 5: + log_facility = LOG_LOCAL5; + break; + case 6: + log_facility = LOG_LOCAL6; + break; + case 7: + log_facility = LOG_LOCAL7; + break; + default: + usage(); + } + break; case 'u': if (! (passwd = getpwnam (optarg)) ) error ("Cannot fetch information for user '%s': %s", diff --git a/src/msgdumpbuf.c b/src/msgdumpbuf.c @@ -12,17 +12,17 @@ void msgdumpbuf (unsigned char const *buf, int buflen) { for (i = 0; i < buflen; i++) { if (! n) - sprintf (hexbuf, "%8.8x ", i); + snprintf (hexbuf, 80, "%8.8x ", i); - sprintf (tmp, " %2.2x", buf[i]); - strcat (hexbuf, tmp); + snprintf (tmp, 5, " %2.2x", buf[i]); + strlcat (hexbuf, tmp, 80); disp[n] = isprint (buf[i]) ? buf[i] : '.'; disp[n + 1] = 0; if (++n == 16) { - strcat (hexbuf, " "); - strcat (hexbuf, disp); + strlcat (hexbuf, " ", 80); + strlcat (hexbuf, disp, 80); msg ("Message hexdump: %s", hexbuf); n = 0; disp[0] = 0; @@ -32,12 +32,12 @@ void msgdumpbuf (unsigned char const *buf, int buflen) { if (n < 16 - 1) { for (j = n; j < 16; j++) - strcat (hexbuf, " "); - strcat (hexbuf, " "); - strcat (hexbuf, disp); + strlcat (hexbuf, " ", 80); + strlcat (hexbuf, " ", 80); + strlcat (hexbuf, disp, 80); msg ("Message hex end: %s", hexbuf); } else msg ("Message hex ends"); } - + diff --git a/src/parser.y b/src/parser.y @@ -499,6 +499,7 @@ typestatement: $$.set[0].cf = cf_typespec; $$.set[0].v.ival = lastnr; } + ; typespec: type_expected diff --git a/src/runservice.c b/src/runservice.c @@ -64,7 +64,7 @@ void runservice () { /* Create the socket, bind to port. */ if ( (listen_sock = make_socket (activeservice->port, activeservice->bind)) < 0 ) { - warning ("Listening socket creation failed.. will retry\n"); + warning ("Listening socket creation failed.. will retry"); /* We wait here for some time, to let the system regain * equilibrium. Something's really afoot, so let's not retry diff --git a/src/servesockets.c b/src/servesockets.c @@ -1,11 +0,0 @@ -#include "crossroads.h" - -void servesockets (int clientsock, int backendsock) { - - /* Fork off a servicer if we're in daemon mode. */ - if (fork_tcp_servicer(current_backend)) - return; - - /* Copy between sockets. */ - copysockets (clientsock, backendsock); -} diff --git a/src/showstatus.c b/src/showstatus.c @@ -1,5 +1,46 @@ #include "crossroads.h" +static char *timestr (double nsec) { + static char *buf; + char *tmp; + + free (buf); + buf = 0; + + if (nsec > 3600) { + buf = str_printf ("%uh", (unsigned) (nsec / 3600)); + nsec = fmod (nsec, 3600); + } + if (nsec > 60) { + tmp = str_printf ("%um", (unsigned) (nsec / 60)); + nsec = fmod (nsec, 60); + buf = xstrcat (buf, tmp); + free (tmp); + } + tmp = str_printf ("%us", (unsigned) nsec); + buf = xstrcat (buf, tmp); + free (tmp); + + return (buf); +} + +static char *bytestr (unsigned long long nbytes) { + static char *buf; + + free (buf); + buf = 0; + + if (nbytes > 1024*1024*1024) + buf = str_printf ("%.2fGb", (double) nbytes / (1024*1024*1024)); + if (nbytes > 1024*1024) + buf = str_printf ("%.2fMb", (double) nbytes / (1024*1024)); + else if (nbytes > 1024) + buf = str_printf ("%.2fKb", (double) nbytes / 1024); + else + buf = str_printf ("%lub", nbytes); + return (buf); +} + void show_status (int ac, char **av) { int i, j; @@ -14,20 +55,23 @@ void show_status (int ac, char **av) { servicereport->last_backend); for (j = 0; j < service[i].nbackend; j++) { printf (" Backend %2d : %s is %s, %u connections\n" - " Stats : %lu failed in %lu connections," - " usage %gs, %llub", + " Stats : %lu failed in %lu connections,", j, service[i].backend[j].name, state_to_string (servicereport->backendstate[j].avail), servicereport->backendstate[j].nclients, servicereport->backendstate[j].failures, - servicereport->backendstate[j].totuses, - servicereport->backendstate[j].nsec, - servicereport->backendstate[j].nbytes); + servicereport->backendstate[j].totuses); + if (service[i].type == type_http) + printf (" %lu sessions,", + servicereport->backendstate[j].sessions); + printf (" usage %s, %s", + timestr (servicereport->backendstate[j].nsec), + bytestr (servicereport->backendstate[j].nbytes)); if (service[i].dispatchover) - printf (" avg %gs, %lub", - servicereport->backendstate[j].avg_nsec, - servicereport->backendstate[j].avg_nbytes); + printf (" avg %s, %s", + timestr(servicereport->backendstate[j].avg_nsec), + bytestr(servicereport->backendstate[j].avg_nbytes)); putchar ('\n'); } diff --git a/src/strlcat.c b/src/strlcat.c @@ -0,0 +1,24 @@ +#ifndef HAVE_STRLCAT + +#include "crossroads.h" + +size_t strlcat (char *dst, char const *src, size_t size) { + size_t bytes = 0; + char *q = dst; + char const *p = src; + char ch; + + while ( bytes < size && *q ) { + q++; + bytes++; + } + while ( (ch = *p++) ) { + if ( bytes < size ) + *q++ = ch; + bytes++; + } + *q = '\0'; + return bytes; +} + +#endif diff --git a/src/tcpserve.c b/src/tcpserve.c @@ -58,7 +58,7 @@ void tcpserve (int server_sock) { /* Incase of a http type service: handle separately. */ if (activeservice->type == type_http) { - http_serve (new); + http_serve (new, &clientname); close (new); continue; } @@ -110,7 +110,8 @@ void tcpserve (int server_sock) { close (backend_sock); break; } - copysockets (new, backend_sock); + + copysockets (new, backend_sock, &clientname); /* If we got here then it's because copysockets() * didn't exit(). Only possible in foreground mode. diff --git a/src/unlockreporter.c b/src/unlockreporter.c @@ -1,6 +1,8 @@ #include "crossroads.h" void unlock_reporter() { + static int warning_issued = 0; + struct sembuf buf = { 0, /* semaphore number */ -1, /* subtract 1 */ @@ -11,7 +13,12 @@ void unlock_reporter() { return; /* msg ("UnLocking reporter memory"); */ - if (semop (semid, &buf, 1) < 0) - error ("Failed to unlock reporter memory (stage %s): %s", - stage_to_string (program_stage), strerror(errno)); + if ( (! warning_issued++) && (semop (semid, &buf, 1) < 0) ) { + warning ("Failed to unlock reporter memory (stage %s): %s", + stage_to_string (program_stage), strerror(errno)); + if (program_stage != stage_serving) + exit (1); + else + warning (".. but continuing serving this TCP connection"); + } } diff --git a/src/usage.txt b/src/usage.txt @@ -19,11 +19,15 @@ Usage: crossroads [flags] sampleconf: display a sample configuration Supported flags: + -a: logs starting and finishing activity to syslog -c CONFIG: Uses the named configuration, instead of the default %s -f: With '(re)start', causes crossroads to stay in the foreground instead of daemonizing. Useful for debugging with -v. No 'status' reporting is possible, no wakeup handlers will run. + -l FAC: Specifies the openlog(3) facility to use when + logging. Default is LOG_DAEMON. Allowed values are 0..7 + for LOG_LOCAL0 to LOG_LOCAL7. -u USER: With '(re)start', causes the daemons to run under the permissions of the stated user. Unused when combined with -f. -v: Enables verbosity upon startup and, when used with -f, in the diff --git a/src/writelog.c b/src/writelog.c @@ -1,9 +1,7 @@ #include "crossroads.h" void writelog (int prio, char const *fmt, va_list args) { - static int logstarted; - if (!logstarted++) - openlog ("crossroads", LOG_PID, LOG_DAEMON); + openlog ("crossroads", LOG_PID, log_facility); vsyslog (prio, fmt, args); } diff --git a/src/xstrcat.c b/src/xstrcat.c @@ -9,6 +9,6 @@ char *xstrcat (char *what, char const *rest) { if (! (what = realloc (what, strlen(what) + strlen(rest) + 1)) ) error ("Out of memory (while adding '%s' to '%s'", rest, what); - strcat (what, rest); + strlcat (what, rest, strlen(what) + strlen(rest) + 1); return (what); } diff --git a/tools/e-ver b/tools/e-ver @@ -14,8 +14,10 @@ my %opts; # Show usage and stop. sub usage () { - system ("e-copyright 'Version ID Checker' $VER"); - die ("Usage: e-ver file(s) VERSION\n", + die ("\n", + "Copyright (c) e-tunity 2000 ff. All rights reserved.\n", + "Contact e-tunity <info\@e-tunity.com> for more info.\n", + "Usage: e-ver file(s) VERSION\n", "The files are checked for ChangeLog-style entries or RPM-style\n", "entries. The stated versions must match VERSION.\n\n"); }