commit 3bb3099779ff845dc1e34c7112bcf08bbef357ff
parent 6b70b8c84664f605bf793999e3bb4633bd67a9d4
Author: finwo <finwo@pm.me>
Date: Sat, 3 Jan 2026 19:09:15 +0100
1.07
Diffstat:
29 files changed, 1651 insertions(+), 1206 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -1,6 +1,11 @@
ChangeLog for Crossroads
------------------------------------------------------------------------------
+1.07 [KK 2006-07-25] Next development (trunk) version. Directive
+ 'insertrealip' implemented. Docs updated. While creating docs,
+ leading tabs are now expanded (needed for PDF documentation).
+ [KK 2006-08-28] 1.07 promoted to next stable version.
+
1.06 [KK 2006-07-25] Small documentation fix. Embedded c-conf upped to
1.03 (protection from endless recursive directory
scans). Optimized http_serve() for short messages (no
diff --git a/doc/Makefile b/doc/Makefile
@@ -1,6 +1,7 @@
include ../etc/Makefile.def
foo:
+ perl ../tools/untab *.yo
yo2html -dVER=$(VER) crossroads
yo2man -dVER=$(VER) crossroads
yo2pdf -dVER=$(VER) crossroads
diff --git a/doc/benchmarking.yo b/doc/benchmarking.yo
@@ -8,13 +8,13 @@ subsect(Benchmark 1: Accessing a proxy via crossroads or directly)
The benchmark was run on a system where the following was varied:
enumeration(
- eit() A website was recursively spidered through a local squid
- proxy. The spidering was repeated 10 times, the total was recorded.
+ eit() A website was recursively spidered through a local squid
+ proxy. The spidering was repeated 10 times, the total was recorded.
- eit() Crossroads was placed in front of the squid proxy, and
- the website was again recursively spidered. Again, the
- spidering was repeated 10 times and the total was recorded.)
-
+ eit() Crossroads was placed in front of the squid proxy, and
+ the website was again recursively spidered. Again, the
+ spidering was repeated 10 times and the total was recorded.)
+
The crossroads configuration of the second alternative is shown below:
verb(\
@@ -68,16 +68,16 @@ This worst case scenario will however (fortunately) occur only very
seldom in the real world:
itemization(
- it() Normally network issues, such as the above mentioned host
- name lookups or throughput restrictions, will add
- significantly to the duration of a request. The 'twice as
- many' read/writes caused by crossroads are then relatively
- irrelevant.
+ it() Normally network issues, such as the above mentioned host
+ name lookups or throughput restrictions, will add
+ significantly to the duration of a request. The 'twice as
+ many' read/writes caused by crossroads are then relatively
+ irrelevant.
- it() Normally a significant amount of time will be spent in a
- back end, due to processing (e.g., when calling a servlet on a
- back end). Again, this processing time will weigh much heavier
- than the multiple read/writes.)
+ it() Normally a significant amount of time will be spent in a
+ back end, due to processing (e.g., when calling a servlet on a
+ back end). Again, this processing time will weigh much heavier
+ than the multiple read/writes.)
subsect(Benchmark 2: Crossroads versus Linux Virtual Server (LVS))
@@ -126,16 +126,16 @@ In the first test, ports 80 and 81 on the balancer were 'bombed' with
following timings where measured:
itemization(
- it() How long it takes to establish a connection;
- it() How long it takes to retrieve the page.)
+ it() How long it takes to establish a connection;
+ it() How long it takes to retrieve the page.)
The results of this test were:
itemization(
- it() On average, each client took 0.12 seconds to connect
- to LVS, and each page was retrieved in 0.14 seconds;
- it() On average, each client took 0.11 seconds to connect to
- crossroads, and each page was retrieved in 0.13 seconds.)
+ it() On average, each client took 0.12 seconds to connect
+ to LVS, and each page was retrieved in 0.14 seconds;
+ it() On average, each client took 0.11 seconds to connect to
+ crossroads, and each page was retrieved in 0.13 seconds.)
In this setup there seems to be no difference between the performance
of LVS and crossroads!
diff --git a/doc/compiling.yo b/doc/compiling.yo
@@ -3,14 +3,14 @@ subsect(Prerequisites)
The creation of crossroads requires:
itemization(
- it() Standard Unix tools, such as tt(sed), tt(awk), tt(Perl)
- (5.00 or better);
+ it() Standard Unix tools, such as tt(sed), tt(awk), tt(Perl)
+ (5.00 or better);
- it() A POSIX-compliant C compiler;
+ it() A POSIX-compliant C compiler;
- it() The grammar generation tools tt(bison) and tt(flex);
+ it() The grammar generation tools tt(bison) and tt(flex);
- it() Support for SYSV IPC, networking and so on.
+ it() Support for SYSV IPC, networking and so on.
)
Basically a Linux or Apple MacOSX box will do nicely once you make
@@ -21,58 +21,58 @@ crossroads, follow these steps.
subsect(Compiling and installing)
itemization(
- it() Obtain the source distribution. It can be found on
- 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
- subdirectory tt(crossroads-)em(X.YY/).
-
- it() Change-dir into the directory.
-
- it() Next, edit tt(etc/Makefile.def) and verify that all
- compilation settings are to your likings. The settings are
- explained in the file. bf(Note that) the default distribution
- of tt(Makefile.def) is suited for Linux or Apple MacOSX
- systems. On other Unices, or on non-Unix systems, you must
- particularly pay attention to tt(SET_PROC_TITLE_BY...). When
- in doubt, comment out all tt(SET_PROC_TITLE...)
- settings. Crossroads will work nevertheless, but it won't show
- nice titles in tt(ps) listings. Also there's a macro
- tt(EXTRA_LIBS) to add linkage flags (an example for a Solaris
- build is included).
-
- it() Now crossroads is ready for compilation. Do a tt(make
- local) followed by tt(make install). The latter step may have
- to be done by the user tt(root) if the tt(BINDIR) setting of
- tt(etc/Makefile.def) points to a root-owned directory.
-
- it() The documentation doesn't install in this process. If you
- want to install the documentation, then proceed as follows:
-
- itemization(
- it() Optionally, tt(cp doc/crossroads.html)
- em(htmldirectory/); where em(htmldirectory) is the destination
- directory for your HTML manuals;
-
- it() Optionally, tt(cp doc/crossroads.pdf)
- em(pdfdirectory/); where em(pdfdirectory) is the
- destination directory for your PDF manuals;
-
- it() Optionally, tt(cp doc/crossroads.man)
- em(manualdirectory)tt(/man1/crossroads.1), where
- em(manualdirectory) is e.g. tt(/usr/man),
- tt(/usr/share), tt(/usr/local/man),
- tt(/usr/local/share). Any possibility is valid, as
- long as em(manualdirectory) has a subdirectory
- tt(man1/);
-
- it() If your manual page system supports compressed
- manual pages, then you can save some space with
- tt(gzip) em(manualdirectory)tt(/man1/crossroads.1).)
-
+ it() Obtain the source distribution. It can be found on
+ 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
+ subdirectory tt(crossroads-)em(X.YY/).
+
+ it() Change-dir into the directory.
+
+ it() Next, edit tt(etc/Makefile.def) and verify that all
+ compilation settings are to your likings. The settings are
+ explained in the file. bf(Note that) the default distribution
+ of tt(Makefile.def) is suited for Linux or Apple MacOSX
+ systems. On other Unices, or on non-Unix systems, you must
+ particularly pay attention to tt(SET_PROC_TITLE_BY...). When
+ in doubt, comment out all tt(SET_PROC_TITLE...)
+ settings. Crossroads will work nevertheless, but it won't show
+ nice titles in tt(ps) listings. Also there's a macro
+ tt(EXTRA_LIBS) to add linkage flags (an example for a Solaris
+ build is included).
+
+ it() Now crossroads is ready for compilation. Do a tt(make
+ local) followed by tt(make install). The latter step may have
+ to be done by the user tt(root) if the tt(BINDIR) setting of
+ tt(etc/Makefile.def) points to a root-owned directory.
+
+ it() The documentation doesn't install in this process. If you
+ want to install the documentation, then proceed as follows:
+
+ itemization(
+ it() Optionally, tt(cp doc/crossroads.html)
+ em(htmldirectory/); where em(htmldirectory) is the destination
+ directory for your HTML manuals;
+
+ it() Optionally, tt(cp doc/crossroads.pdf)
+ em(pdfdirectory/); where em(pdfdirectory) is the
+ destination directory for your PDF manuals;
+
+ it() Optionally, tt(cp doc/crossroads.man)
+ em(manualdirectory)tt(/man1/crossroads.1), where
+ em(manualdirectory) is e.g. tt(/usr/man),
+ tt(/usr/share), tt(/usr/local/man),
+ tt(/usr/local/share). Any possibility is valid, as
+ long as em(manualdirectory) has a subdirectory
+ tt(man1/);
+
+ it() If your manual page system supports compressed
+ manual pages, then you can save some space with
+ tt(gzip) em(manualdirectory)tt(/man1/crossroads.1).)
+
)
@@ -87,31 +87,31 @@ tt(crossroads start). Test the availability of your services and back
ends. Monitor how crossroads is doing with:
itemization(
- it() In one terminal, run the script:
- verb(\
+ it() In one terminal, run the script:
+ verb(\
while [ 1 ] ; do
tput clear
crossroads status
sleep 3
done)
- bf(Note) that depending on your system you might need
- tt(sleep 3s), i.e., with an tt(s) appended.
+ bf(Note) that depending on your system you might need
+ tt(sleep 3s), i.e., with an tt(s) appended.
- it() In another terminal, run:
- verb(\
+ it() In another terminal, run:
+ verb(\
while [ 1 ] ; do
tput clear
ps ax | grep crossroads | grep -v grep
sleep 3
done)
- bf(Note) that depending on your system you might need
- tt(ps -ef) instead of tt(ps ax).
+ bf(Note) that depending on your system you might need
+ tt(ps -ef) instead of tt(ps ax).
- it() In yet another terminal, run tt(tail -f
- /var/log/messages) (supply the appropriate system log file if
- tt(/var/log/messages) doesn't work for you).)
+ it() In yet another terminal, run tt(tail -f
+ /var/log/messages) (supply the appropriate system log file if
+ tt(/var/log/messages) doesn't work for you).)
Now thoroughly test the availability of your back ends through
crossroads. The status display will show an updated view of which back
@@ -135,33 +135,33 @@ inserting scripts into the boot sequence, but
otherwise the steps will resemble the following.
itemization(
- it() Create a script tt(crossroads) in tt(/etc/init.d) similar to the
- following:
+ it() Create a script tt(crossroads) in tt(/etc/init.d) similar to the
+ following:
verb(\
#!/bin/sh
/usr/local/bin/crossroads -v $@)
- The stated directory tt(/usr/local/bin) must correspond with
- the installation path. The flag tt(-v) causes the startup to
- be more 'verbose'. However, once daemonized, the verbosity is
- controlled by the appropriate statements in the configuration.
+ The stated directory tt(/usr/local/bin) must correspond with
+ the installation path. The flag tt(-v) causes the startup to
+ be more 'verbose'. However, once daemonized, the verbosity is
+ controlled by the appropriate statements in the configuration.
- it() Determine your 'runlevel': usually 3 when your system is
- running in text-mode only, or 5 when you are using a graphical
- interface. If your runlevel is 3, then:
+ it() Determine your 'runlevel': usually 3 when your system is
+ running in text-mode only, or 5 when you are using a graphical
+ interface. If your runlevel is 3, then:
verb(\
root> cd /etc/rc.d/rc3.d
root> ln -s /etc/init.d/crossroads S99crossroads
root> ln -s /etc/init.d/crossroads K99crossroads)
- This creates startup (tt(S*)) and stop (tt(K*)) links that
- will be run when the system enters or leaves a given runlevel.
+ This creates startup (tt(S*)) and stop (tt(K*)) links that
+ will be run when the system enters or leaves a given runlevel.
- If your runlevel is 5, then the right tt(cd) command is to
- tt(/etc/rc.d/rc5.d). Alternatively, you can create the
- symlinks in both runlevel directories.)
+ If your runlevel is 5, then the right tt(cd) command is to
+ tt(/etc/rc.d/rc5.d). Alternatively, you can create the
+ symlinks in both runlevel directories.)
subsubsect(BSD Style Startup)
diff --git a/doc/config.yo b/doc/config.yo
@@ -51,12 +51,12 @@ character tt(;). If a string must contain a semicolon, then it must
be enclosed in single or double quotes:
itemization(
- it() tt(This is a string;) is a string that starts at tt(T)
- and ends with tt(g)
- it() tt("This is a string";) is the same, the double quotes
- are not necessary
- it() tt("This is ; a string";) has double quotes to protect
- the inner ;)
+ it() tt(This is a string;) is a string that starts at tt(T)
+ and ends with tt(g)
+ it() tt("This is a string";) is the same, the double quotes
+ are not necessary
+ it() tt("This is ; a string";) has double quotes to protect
+ the inner ;)
Finally, an argument can be a 'boolean' value. Crossroads knows
tt(true), tt(false), tt(yes), tt(no), tt(on), tt(off). The keywords
@@ -89,20 +89,20 @@ startdit()
dit(The type statement) defines how crossroads handles the stated
service. There are currently two types: tt(any) and
-tt(stickyhttp). The type tt(any) means that crossroads doesn't
+tt(http). The type tt(any) means that crossroads doesn't
interpret the contents of a TCP stream, but only distributes streams
-over back ends. The type tt(stickyhttp) means that crossroads has to
-analyze what's in the messages, does magical HTTP cookie tricks, and
-so on -- to ensure that multiple connections are treated as one
-session.
+over back ends. The type tt(http) means that crossroads has to
+analyze what's in the messages, does magical HTTP header tricks, and
+so on -- all to ensure that multiple connections are treated as one
+session, or that the back end is notified of the client's IP address.
-Unless you really need sticky HTTP sessions, use the type tt(any) (the
+Unless you really need such special features, use the type tt(any) (the
default), even for HTTP protocols.
itemization(
- it() Syntax: tt(type) em(typespecifier) tt(;)
- it() Where em(typespecifier) is tt(any) or tt(stickyhttp)
- it() Default: tt(any))
+ it() Syntax: tt(type) em(typespecifier) tt(;)
+ it() Where em(typespecifier) is tt(any) or tt(http)
+ it() Default: tt(any))
dit(The port statement) defines to which TCP port a service
'listens'. E.g. tt(port 8000) says that this service will accept
@@ -120,10 +120,10 @@ serviced. By default, crossroads binds a service to all presently
active IP addresses at the invoking host.
itemization(
- it() Syntax: tt(bindto) em(ip-address) tt(;)
- it() where em(ip-address) is a numeric IP address, such as
- tt(192.168.1.45), or the keyword tt(any)
- it() Default: tt(any))
+ it() Syntax: tt(bindto) em(ip-address) tt(;)
+ it() where em(ip-address) is a numeric IP address, such as
+ tt(192.168.1.45), or the keyword tt(any)
+ it() Default: tt(any))
dit(Verbosity statements) come in two forms: tt(verbosity on) or
tt(verbosity off). When 'on', log messages to tt(/var/log/messages)
@@ -136,7 +136,7 @@ tt(verbosity).
itemization(
it() Syntax: tt(verbosity) em(setting) tt(;)
- it() Or: tt(verbose) em(setting) tt(;)
+ it() Or: tt(verbose) em(setting) tt(;)
it() where em(setting) is tt(true), tt(yes) or tt(on) to turn
verbosity on; or tt(false), tt(no), tt(off) to turn it off.
it() Default: tt(off).)
@@ -157,7 +157,7 @@ itemization(
it() tt(dispatchmode random): Random selection. Probably only
for stress testing, though when used with weights (see below)
- it is a good distributor of new connections too.
+ it is a good distributor of new connections too.
it() tt(dispatchmode bysize [ over) em(connections) tt(]):
The next back end is the one
@@ -177,10 +177,10 @@ itemization(
that served connections for the shortest time. This mechanism
assumes that the longer the connection, the heavier the load.
- it() tt(dispatchmode byconnections): The next back end is the one
- with the least active connections. This mechanism assumes that
- each connection to a back end represents load. It is usable
- for e.g. database connections.
+ it() tt(dispatchmode byconnections): The next back end is the one
+ with the least active connections. This mechanism assumes that
+ each connection to a back end represents load. It is usable
+ for e.g. database connections.
it() tt(dispatchmode byorder): The first back end is selected
every time, unless it's unavailable. In that case the second
@@ -190,12 +190,12 @@ The selection algorithm is only used when clients are serviced that
aren't part of a sticky HTTP session. This is the case during:
itemization(
- it() all client requests of a service type tt(any);
- it() new sessions of a service type tt(stickyhttp).)
+ it() all client requests of a service type tt(any);
+ it() new sessions of a service type tt(http).)
-When tt(stickyhttp) is in effect and a session is underway, then the
+When type tt(http) is in effect and a session is underway, then the
previously used back end is always selected -- regardless of
-dispatching mode.
+dispatching mode.
Your 'right' dispatch mode will depend on the type of service. Given
the fact that crossroads doesn't know (and doesn't care) how to
@@ -209,7 +209,7 @@ happen when:
itemization(
it() The back end cannot be reached (network connection
- fails);
+ fails);
it() The network connection to the back end suddenly dies.)
An example of the definition is tt(revivinginterval 10). When this
@@ -321,7 +321,7 @@ startdit()
itemization(
it() Syntax: tt(server) em(servername) tt(;)
- it() Or: tt(server) em(servername)tt(:)em(port) tt(;)
+ it() Or: tt(server) em(servername)tt(:)em(port) tt(;)
it() There is no default. This is a required setting.)
dit(Port:) When the tt(server) specifier doesn't include a TCP
@@ -332,7 +332,7 @@ startdit()
itemization(
it() Syntax: tt(port) em(number) tt(;)
it() There is no default. The port must be defined either in
- the tt(server) setting or using the tt(port) specifier.)
+ the tt(server) setting or using the tt(port) specifier.)
dit(Verbosity:) Similar to tt(service) specifications, a
tt(backend) can have its own verbosity (tt(on) or tt(off)). When
@@ -340,7 +340,7 @@ startdit()
itemization(
it() Syntax: tt(verbosity) em(setting) tt(;)
- it() Or: tt(verbose) em(setting) tt(;)
+ it() Or: tt(verbose) em(setting) tt(;)
it() where em(setting) is tt(true), tt(yes) or tt(on) to turn
verbosity on; or tt(false), tt(no), tt(off) to turn it off.
it() Default: tt(off).)
@@ -356,10 +356,10 @@ startdit()
overloaded.
itemization(
- it() Syntax: tt(maxconnections) em(number) tt(;)
- it() where em(number) is the maximum number of concurrent
- client connections.
- it() Default: 0, meaning that there is no limit.)
+ it() Syntax: tt(maxconnections) em(number) tt(;)
+ it() where em(number) is the maximum number of concurrent
+ client connections.
+ it() Default: 0, meaning that there is no limit.)
dit(Weight:) To influence how backends are selected by size or by
duration, a backend can specify its 'weight' in the process. The
@@ -375,7 +375,7 @@ startdit()
itemization(
it() Syntax: tt(weight) em(number) tt(;)
- it() Default: 1)
+ it() Default: 1)
dit(Decay:) To make sure that a 'spike' of activity doesn't
influence the perceived load of a back end forever, you may
@@ -397,8 +397,8 @@ startdit()
data when other back ends are hit
it() Default: 0, meaning that no decay is applied to usage statistics.)
- dit(HTTP cookie handling:) When the service type is tt(stickyhttp),
- then backends should define HTTP cookies to identify sessions. There
+ dit(HTTP cookie handling:) When the service type is tt(http),
+ then backends may define HTTP cookies to identify sessions. There
are two directives to accomplish this: tt(stickycookie) and
tt(insertcookie).
@@ -406,8 +406,8 @@ startdit()
HTTP stream when crossroads assigns a back end to a new session.
itemization(
- it() Syntax: tt(insertcookie) em(cookiestring) tt(;)
- it() Default: none)
+ it() Syntax: tt(insertcookie) em(cookiestring) tt(;)
+ it() Default: none)
The directive tt(stickycookie) is used by crossroads to determine
whether a HTTP request is part of an established session. If so, the
@@ -415,8 +415,8 @@ startdit()
considerations.
itemization(
- it() Syntax: tt(stickycookie) em(cookiestring) tt(;)
- it() Default: none)
+ it() Syntax: tt(stickycookie) em(cookiestring) tt(;)
+ it() Default: none)
It should be obvious that the em(cookiestrings) in the two above
directives should match: the cookie that's initially inserted by
@@ -427,7 +427,7 @@ startdit()
verb(\
service www {
port 80;
- type stickyhttp;
+ type http;
backend one {
server 10.0.0.1:80;
stickycookie BalancerID=a;
@@ -442,7 +442,22 @@ service www {
Note also the quoting of the cookiestring in the tt(insertcookie)
directive. Without it, the semicolon in the string would break the
- directive.
+ directive.
+
+ dit(Passing of real IP address:) When the service type is
+ tt(http), the directive tt(insertrealip) can be used to force
+ Crossroads to insert the client's real IP address as an HTTP
+ header. The back end may then inspect the header.
+
+ itemization(
+ it() Syntax: tt(insertrealip) em(setting) tt(;)
+ it() where em(setting) is tt(true), tt(yes) or tt(on) to turn
+ on this feature; or tt(false), tt(no) or tt(off) to turn it
+ off.
+ it() Default: tt(off))
+
+ When turned on, the client's IP address is stored in an HTTP
+ header named tt(XR-Real-IP).
dit(Event triggers:) As special 'hooks' for actions, two triggers
are available: tt(onfailure) and tt(onsuccess). The argument to
@@ -491,7 +506,7 @@ B 0050 78 74 2f 68 74 6d 6c 3b 20 63 68 61 72 73 65 74 xt/html; charset
itemization(
it() Syntax: tt(trafficlog) em(filename) tt(;)
it() There is no default. Without this directive, traffic is
- not logged.)
+ not logged.)
Besides tt(trafficlog), there is also a directive
tt(throughputlog). This directive also takes one argument, a
@@ -499,13 +514,13 @@ B 0050 78 74 2f 68 74 6d 6c 3b 20 63 68 61 72 73 65 74 xt/html; charset
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.)
+ 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):
@@ -523,25 +538,25 @@ B 0050 78 74 2f 68 74 6d 6c 3b 20 63 68 61 72 73 65 74 xt/html; charset
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() 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
@@ -573,9 +588,9 @@ client ----<----<----<---< crossroads ====<====<====<
are not (yet) included in Crossroads.
itemization(
- it() Syntax: tt(throughputlog) em(filename) tt(;)
- it() There is no default. Without this directive, the
- throughput is not logged.)
+ it() Syntax: tt(throughputlog) em(filename) tt(;)
+ it() There is no default. Without this directive, the
+ throughput is not logged.)
enddit()
diff --git a/doc/crossroads.html b/doc/crossroads.html
@@ -1,26 +1,26 @@
<a name="defs.yo"></a><html><head>
-<title>Crossroads 1.05</title>
+<title>Crossroads 1.07</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.05</h1>
+<h1>Crossroads 1.07</h1>
<h2>Karel Kubat</h2>
<h2>e-tunity</h2><h2>2005, 2006, ff.</h2>
<blockquote><em>Crossroads is a load balance and fail over utility for TCP
- based services. It is a daemon program running in user
- space, and features extensive configurability, polling of
- back ends using 'wakeup calls', detailed status reporting,
- 'hooks' for special actions when backend calls fail, and much
- more. Crossroads is service-independent: it is usable for
- HTTP/HTTPS, SSH, SMTP, DNS, etc. In the case of HTTP
- balancing, Crossroads can provide 'session stickiness' for
- back-end processes that need sessions, but aren't
- session-aware of other back-ends.</em></blockquote>
+ based services. It is a daemon program running in user
+ space, and features extensive configurability, polling of
+ back ends using 'wakeup calls', detailed status reporting,
+ 'hooks' for special actions when backend calls fail, and much
+ more. Crossroads is service-independent: it is usable for
+ HTTP/HTTPS, SSH, SMTP, DNS, etc. In the case of HTTP
+ balancing, Crossroads can provide 'session stickiness' for
+ back-end processes that need sessions, but aren't
+ session-aware of other back-ends.</em></blockquote>
<h1>Table of Contents</h1>
<dl>
@@ -62,35 +62,40 @@
<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="#l25">5.3: Configuration examples</a></dt>
+<dt><a href="#l25">5.3: Passing the client's IP address</a></dt>
<dl>
-<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>
+<dt><a href="#l26">5.3.1: Sample Crossroads configuration</a></dt>
+<dt><a href="#l27">5.3.2: Sample Apache configuration</a></dt>
+</dl>
+<dt><a href="#l28">5.4: Configuration examples</a></dt>
+<dl>
+<dt><a href="#l29">5.4.1: A load balancer for three webserver back ends</a></dt>
+<dt><a href="#l30">5.4.2: An HTTP forwarder when travelling</a></dt>
+<dt><a href="#l31">5.4.3: SSH login with enforced idle logout</a></dt>
</dl>
</dl>
-<dt><h3><a href="#l29">6: Benchmarking</a></h3></dt>
+<dt><h3><a href="#l32">6: Benchmarking</a></h3></dt>
<dl>
-<dt><a href="#l30">6.1: Benchmark 1: Accessing a proxy via crossroads or directly</a></dt>
+<dt><a href="#l33">6.1: Benchmark 1: Accessing a proxy via crossroads or directly</a></dt>
<dl>
-<dt><a href="#l31">6.1.1: Results</a></dt>
-<dt><a href="#l32">6.1.2: Discussion</a></dt>
+<dt><a href="#l34">6.1.1: Results</a></dt>
+<dt><a href="#l35">6.1.2: Discussion</a></dt>
</dl>
-<dt><a href="#l33">6.2: Benchmark 2: Crossroads versus Linux Virtual Server (LVS)</a></dt>
+<dt><a href="#l36">6.2: Benchmark 2: Crossroads versus Linux Virtual Server (LVS)</a></dt>
<dl>
-<dt><a href="#l34">6.2.1: Environment</a></dt>
-<dt><a href="#l35">6.2.2: Tests and results</a></dt>
+<dt><a href="#l37">6.2.1: Environment</a></dt>
+<dt><a href="#l38">6.2.2: Tests and results</a></dt>
</dl>
</dl>
-<dt><h3><a href="#l36">7: Compiling and Installing</a></h3></dt>
+<dt><h3><a href="#l39">7: Compiling and Installing</a></h3></dt>
<dl>
-<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>
+<dt><a href="#l40">7.1: Prerequisites</a></dt>
+<dt><a href="#l41">7.2: Compiling and installing</a></dt>
+<dt><a href="#l42">7.3: Configuring crossroads</a></dt>
+<dt><a href="#l43">7.4: A boot script</a></dt>
<dl>
-<dt><a href="#l41">7.4.1: SysV Style Startup</a></dt>
-<dt><a href="#l42">7.4.2: BSD Style Startup</a></dt>
+<dt><a href="#l44">7.4.1: SysV Style Startup</a></dt>
+<dt><a href="#l45">7.4.2: BSD Style Startup</a></dt>
</dl>
<p><hr><p>
@@ -130,17 +135,17 @@ 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:/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.
+ <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://freshmeat.net/projects/crossr">http://freshmeat.net/projects/crossr</a> is the
- Freshmeat announcement page.
+ 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
- to commit changes, <a href="mailto:karel@e-tunity.com">mail me</a> for
- credentials.</ul>
+ repository; anonymous reading (fetching) is allowed. In order
+ to commit changes, <a href="mailto:karel@e-tunity.com">mail me</a> for
+ credentials.</ul>
<p>
<a name="l3"></a>
<h3>1.2: Copyright and Disclaimer</h3>
@@ -171,84 +176,84 @@ more meanings of the terms will exist -- yes, I am aware of that. I'm
using the terms here in a very strict sense.)
<p>
<dl>
- <p><dt><strong>A client</strong><dd> is a process that initiates a network connection
- to get contact with some service.
- <p><dt><strong>A service</strong><dd> or <strong>server process</strong> or <strong>listener</strong>
- is a central application
- that accepts network connections from clients and sevices
- them.
- <p><dt><strong>Back ends</strong><dd> are locations where crossroads looks in
- order to service its clients. Crossroads sits 'in between'
- and does its tricks. Therefore, as far as the back ends
- are concerned, crossroads behaves like a client. As far as
- the true client is concerned, crossroads behaves like the
- service. The communication is however transparent: neither
- client nor back end are aware of the middle position of
- crossroads.
- <p><dt><strong>A connection</strong><dd> is a network conversation between client and service,
- where data are transferred to and fro. As
- far as crossroads is concerned, success means that a
- connection can be established without errors on
- the network level. Crossroads isn't aware of service
- pecularities. E.g., when a webserver answers <code>HTTP/1.0
- 500 Server Error</code> then crossroads will see this as a
- succesful connection, though the user behind a browser may
- think otherwise.
- <p><dt><strong>Back end selection algorithms</strong><dd> are methods by which
- crossroads determines which back end it will talk to
- next. Crossroads has a number of built-in algorithms,
- which may be configured per service.
+ <p><dt><strong>A client</strong><dd> is a process that initiates a network connection
+ to get contact with some service.
+ <p><dt><strong>A service</strong><dd> or <strong>server process</strong> or <strong>listener</strong>
+ is a central application
+ that accepts network connections from clients and sevices
+ them.
+ <p><dt><strong>Back ends</strong><dd> are locations where crossroads looks in
+ order to service its clients. Crossroads sits 'in between'
+ and does its tricks. Therefore, as far as the back ends
+ are concerned, crossroads behaves like a client. As far as
+ the true client is concerned, crossroads behaves like the
+ service. The communication is however transparent: neither
+ client nor back end are aware of the middle position of
+ crossroads.
+ <p><dt><strong>A connection</strong><dd> is a network conversation between client and service,
+ where data are transferred to and fro. As
+ far as crossroads is concerned, success means that a
+ connection can be established without errors on
+ the network level. Crossroads isn't aware of service
+ pecularities. E.g., when a webserver answers <code>HTTP/1.0
+ 500 Server Error</code> then crossroads will see this as a
+ succesful connection, though the user behind a browser may
+ think otherwise.
+ <p><dt><strong>Back end selection algorithms</strong><dd> are methods by which
+ crossroads determines which back end it will talk to
+ next. Crossroads has a number of built-in algorithms,
+ which may be configured per service.
<p><dt><strong>Back end states</strong><dd> are the statusses of each back end that
- is known to crossroads. A back end may be available,
- (temporarily) unavailble or truly down. When a back end is
- temporarily unavailable, then crossroads will periodically
- check whether the back end has come to life yet (that is,
- if configured so).
- <p><dt><strong>A spike</strong><dd> is a sudden increase in activity, leading to
- extra load on a given service. When crossroads is in
- effect and when the spike occurs in one connection,
- then obviously the spike will also appear at one
- of the back ends. However, crossroads will see the spike
- and will make sure that a subsequent request goes to an
- other back end. In contrast, when several connections
- arrive simultaneously and cause a spike, then crossroads
- will be able to distribute the connections over several
- back ends, thereby 'flattening out' the increase.
- <p><dt><strong>Load balancing</strong><dd> means that incoming client requests are
- distributed over more than just one back end (which wouldn't be the
- case if you wouldn't be running crossroads). Enabling load
- balancing is nothing more than duplicating services over
- more than one back end, and having something (in this
- case: crossroads) distribute the requests, so that per
- back end the load doesn't get too high.
- <p><dt><strong>An HTTP session</strong><dd> is a series of separate network connections
- that originate from one browser. E.g., to fill the display
- with text and images, the browser hits a website several times.
- An HTTP session may even span several
- screens. E.g., a website registration dialog may involve 3
- screens that when called from the same browser,
- form a logical group of some sort.
- <p><dt><strong>Session stickiness</strong><dd> means that when a browser starts an
- HTTP dialog, the balancer makes sure that it 'sticks' to
- the same back end (i.e., subsequent requests from the
- browser are forced to go to the same back end, instead of
- being balanced to other ones).
- <p><dt><strong>Back end usage</strong><dd> is measured by crossroads in order to be
- able to determine back end selection. Crossroads stores
- information about the number of active connections, the
- transferred bytes and
- about the connection duration. These numbers can be used to
- estimate which back end is the least used -- and
- therefore, presumably, the best candidate for a new
- request.
- <p><dt><strong>Fail over</strong><dd> is almost always used when load balancing is in
- effect. The distributor of client requests (crossroads of
- course) can also monitor back ends, so that incase a back
- end is 'down', it is no longer accessed.
- <p><dt><strong>Service downtime</strong><dd> normally occurs when a service is
- switched off. Downtime is obviously avoided when fail over
- is in effect: a back end can be taken out of service in a
- controlled manner, without any client noticing it.
+ is known to crossroads. A back end may be available,
+ (temporarily) unavailble or truly down. When a back end is
+ temporarily unavailable, then crossroads will periodically
+ check whether the back end has come to life yet (that is,
+ if configured so).
+ <p><dt><strong>A spike</strong><dd> is a sudden increase in activity, leading to
+ extra load on a given service. When crossroads is in
+ effect and when the spike occurs in one connection,
+ then obviously the spike will also appear at one
+ of the back ends. However, crossroads will see the spike
+ and will make sure that a subsequent request goes to an
+ other back end. In contrast, when several connections
+ arrive simultaneously and cause a spike, then crossroads
+ will be able to distribute the connections over several
+ back ends, thereby 'flattening out' the increase.
+ <p><dt><strong>Load balancing</strong><dd> means that incoming client requests are
+ distributed over more than just one back end (which wouldn't be the
+ case if you wouldn't be running crossroads). Enabling load
+ balancing is nothing more than duplicating services over
+ more than one back end, and having something (in this
+ case: crossroads) distribute the requests, so that per
+ back end the load doesn't get too high.
+ <p><dt><strong>An HTTP session</strong><dd> is a series of separate network connections
+ that originate from one browser. E.g., to fill the display
+ with text and images, the browser hits a website several times.
+ An HTTP session may even span several
+ screens. E.g., a website registration dialog may involve 3
+ screens that when called from the same browser,
+ form a logical group of some sort.
+ <p><dt><strong>Session stickiness</strong><dd> means that when a browser starts an
+ HTTP dialog, the balancer makes sure that it 'sticks' to
+ the same back end (i.e., subsequent requests from the
+ browser are forced to go to the same back end, instead of
+ being balanced to other ones).
+ <p><dt><strong>Back end usage</strong><dd> is measured by crossroads in order to be
+ able to determine back end selection. Crossroads stores
+ information about the number of active connections, the
+ transferred bytes and
+ about the connection duration. These numbers can be used to
+ estimate which back end is the least used -- and
+ therefore, presumably, the best candidate for a new
+ request.
+ <p><dt><strong>Fail over</strong><dd> is almost always used when load balancing is in
+ effect. The distributor of client requests (crossroads of
+ course) can also monitor back ends, so that incase a back
+ end is 'down', it is no longer accessed.
+ <p><dt><strong>Service downtime</strong><dd> normally occurs when a service is
+ switched off. Downtime is obviously avoided when fail over
+ is in effect: a back end can be taken out of service in a
+ controlled manner, without any client noticing it.
</dl>
<p>
<a name="l5"></a>
@@ -258,10 +263,10 @@ As of version 0.26 the syntax of the configuration file has
changed. In particular:
<p>
<ul>
- <li> The keyword <code>maxconnections</code> is now used instead of
- <code>maxclients</code>;
- <li> The keyword <code>connectiontimeout</code> is now used instead of
- <code>sessiontimeout</code>.</ul>
+ <li> The keyword <code>maxconnections</code> is now used instead of
+ <code>maxclients</code>;
+ <li> The keyword <code>connectiontimeout</code> is now used instead of
+ <code>sessiontimeout</code>.</ul>
<p>
Therefore when converting configuration files to the new syntax,
the above keywords must be changed. (The reason for these changes
@@ -281,37 +286,37 @@ 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
- <a href="http://crossroads.e-tunity.com">http://crossroads.e-tunity.com</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.
+ unpack the archive.
<p>
<li> Change-dir into the create directory <code>crossroads/</code>.</ul>
<p>
<li> If you have SVN and want to go for the newest snapshot:
<p>
<ul>
- <li> Get the latest sources and snapshots using SVN from <br>
+ <li> Get the latest sources and snapshots using SVN from <br>
<code>svn://svn.e-tunity.com/crossroads</code>.
<p>
<li> You'll find the newest alpha version under
- <code>crossroads/trunk</code> and the stable versions under
- <code>crossroads/tags</code>,
- e.g. <code>crossroads/tags/release-1.00</code>.
+ <code>crossroads/trunk</code> and the stable versions under
+ <code>crossroads/tags</code>,
+ e.g. <code>crossroads/tags/release-1.00</code>.
<p>
<li> Choose which you want to use: the latest stable
- release, or the bleeding edge alpha? In the former case,
- change-dir to <code>crossroads/tags/release-</code><em>X.YY</em>, where
- <em>X.YY</em> is a release ID. In the latter case, change-dir to
- <code>crossroads/trunk</code>.</ul>
+ release, or the bleeding edge alpha? In the former case,
+ change-dir to <code>crossroads/tags/release-</code><em>X.YY</em>, where
+ <em>X.YY</em> is a release ID. In the latter case, change-dir to
+ <code>crossroads/trunk</code>.</ul>
<p>
<li> Type <code>make install</code>. This installs the crossroads
- binary into <code>/usr/local/bin/</code>. If the compilation doesn't
- work on your system, check <code>etc/Makefile.def</code> for hints.
+ binary into <code>/usr/local/bin/</code>. If the compilation doesn't
+ work on your system, check <code>etc/Makefile.def</code> for hints.
<p>
<li> Create a file <code>/etc/crossroads.conf</code>. In it state
- something like:
+ something like:
<p>
<pre>
service www {
@@ -328,16 +333,16 @@ service www {
<p>
That's off course assuming that you want to balance HTTP on
- port 80 to two back ends at 10.1.1.100 and 10.1.1.101.
+ port 80 to two back ends at 10.1.1.100 and 10.1.1.101.
<p>
<li> Type <code>crossroads start</code>.
<p>
<li> Surf to the machine where crossroads is running. You will
- see the pages served by the back ends 10.1.1.100 or
- 10.1.1.101.
+ see the pages served by the back ends 10.1.1.100 or
+ 10.1.1.101.
<p>
<li> To monitor the status of crossroads, type <code>crossroads
- status</code>.
+ status</code>.
</ul>
<p>
<a name="l7"></a>
@@ -353,33 +358,33 @@ 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
- actions that are run from system startup scripts. The
- meaning is self-explanatory.
- <li> <code>crossroads restart</code> is a combination of the former
- two. Beware that a restart may cause discontinuity in
- service; it is just a shorthand for typing the 'stop' and
- 'start' actions after one another.
- <li> <code>crossroad status</code> reports on each running
- service. Per service, the state of each back end is
- reported.
- <li> <code>crossroads tell</code> <em>service backend state</em> is a
- command line way of telling crossroads that a given back
- end, of a given service, is in a given state. Normally
- crossroads maintains state information itself, but by
- using <code>crossroads tell</code>, a back end can be e.g. taken
- 'off line' for servicing.
- <li> <code>crossroads configtest</code> tells you whether the
- configuration is syntactially correct.
- <li> <code>crossroads services</code> reports on the configured
- services. In contrast to <code>crossroads status</code>, this
- option only shows what's configured -- not what's up and
- running. Therefore, <code>crossroads services</code> doesn't
- report on back end states.
- <li> <code>crossroads sampleconf</code> shows a sample configuration on
- 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>.
+ <li> <code>crossroads start</code> and <code>crossroads stop</code> are typical
+ actions that are run from system startup scripts. The
+ meaning is self-explanatory.
+ <li> <code>crossroads restart</code> is a combination of the former
+ two. Beware that a restart may cause discontinuity in
+ service; it is just a shorthand for typing the 'stop' and
+ 'start' actions after one another.
+ <li> <code>crossroad status</code> reports on each running
+ service. Per service, the state of each back end is
+ reported.
+ <li> <code>crossroads tell</code> <em>service backend state</em> is a
+ command line way of telling crossroads that a given back
+ end, of a given service, is in a given state. Normally
+ crossroads maintains state information itself, but by
+ using <code>crossroads tell</code>, a back end can be e.g. taken
+ 'off line' for servicing.
+ <li> <code>crossroads configtest</code> tells you whether the
+ configuration is syntactially correct.
+ <li> <code>crossroads services</code> reports on the configured
+ services. In contrast to <code>crossroads status</code>, this
+ option only shows what's configured -- not what's up and
+ running. Therefore, <code>crossroads services</code> doesn't
+ report on back end states.
+ <li> <code>crossroads sampleconf</code> shows a sample configuration on
+ 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>
<p>
<a name="l8"></a>
@@ -481,12 +486,12 @@ character <code>;</code>. If a string must contain a semicolon, then it must
be enclosed in single or double quotes:
<p>
<ul>
- <li> <code>This is a string;</code> is a string that starts at <code>T</code>
- and ends with <code>g</code>
- <li> <code>"This is a string";</code> is the same, the double quotes
- are not necessary
- <li> <code>"This is ; a string";</code> has double quotes to protect
- the inner ;</ul>
+ <li> <code>This is a string;</code> is a string that starts at <code>T</code>
+ and ends with <code>g</code>
+ <li> <code>"This is a string";</code> is the same, the double quotes
+ are not necessary
+ <li> <code>"This is ; a string";</code> has double quotes to protect
+ the inner ;</ul>
<p>
Finally, an argument can be a 'boolean' value. Crossroads knows
<code>true</code>, <code>false</code>, <code>yes</code>, <code>no</code>, <code>on</code>, <code>off</code>. The keywords
@@ -521,20 +526,20 @@ statements. Each statement must end with a semicolon, except for the
<p>
<p><dt><strong>The type statement</strong><dd> defines how crossroads handles the stated
service. There are currently two types: <code>any</code> and
-<code>stickyhttp</code>. The type <code>any</code> means that crossroads doesn't
+<code>http</code>. The type <code>any</code> means that crossroads doesn't
interpret the contents of a TCP stream, but only distributes streams
-over back ends. The type <code>stickyhttp</code> means that crossroads has to
-analyze what's in the messages, does magical HTTP cookie tricks, and
-so on -- to ensure that multiple connections are treated as one
-session.
+over back ends. The type <code>http</code> means that crossroads has to
+analyze what's in the messages, does magical HTTP header tricks, and
+so on -- all to ensure that multiple connections are treated as one
+session, or that the back end is notified of the client's IP address.
<p>
-Unless you really need sticky HTTP sessions, use the type <code>any</code> (the
+Unless you really need such special features, use the type <code>any</code> (the
default), even for HTTP protocols.
<p>
<ul>
- <li> Syntax: <code>type</code> <em>typespecifier</em> <code>;</code>
- <li> Where <em>typespecifier</em> is <code>any</code> or <code>stickyhttp</code>
- <li> Default: <code>any</code></ul>
+ <li> Syntax: <code>type</code> <em>typespecifier</em> <code>;</code>
+ <li> Where <em>typespecifier</em> is <code>any</code> or <code>http</code>
+ <li> Default: <code>any</code></ul>
<p>
<p><dt><strong>The port statement</strong><dd> defines to which TCP port a service
'listens'. E.g. <code>port 8000</code> says that this service will accept
@@ -552,10 +557,10 @@ serviced. By default, crossroads binds a service to all presently
active IP addresses at the invoking host.
<p>
<ul>
- <li> Syntax: <code>bindto</code> <em>ip-address</em> <code>;</code>
- <li> where <em>ip-address</em> is a numeric IP address, such as
- <code>192.168.1.45</code>, or the keyword <code>any</code>
- <li> Default: <code>any</code></ul>
+ <li> Syntax: <code>bindto</code> <em>ip-address</em> <code>;</code>
+ <li> where <em>ip-address</em> is a numeric IP address, such as
+ <code>192.168.1.45</code>, or the keyword <code>any</code>
+ <li> Default: <code>any</code></ul>
<p>
<p><dt><strong>Verbosity statements</strong><dd> come in two forms: <code>verbosity on</code> or
<code>verbosity off</code>. When 'on', log messages to <code>/var/log/messages</code>
@@ -568,7 +573,7 @@ priority <code>LOG_INFO</code>. In most (Linux) cases this will mean: output to
<p>
<ul>
<li> Syntax: <code>verbosity</code> <em>setting</em> <code>;</code>
- <li> Or: <code>verbose</code> <em>setting</em> <code>;</code>
+ <li> Or: <code>verbose</code> <em>setting</em> <code>;</code>
<li> where <em>setting</em> is <code>true</code>, <code>yes</code> or <code>on</code> to turn
verbosity on; or <code>false</code>, <code>no</code>, <code>off</code> to turn it off.
<li> Default: <code>off</code>.</ul>
@@ -589,7 +594,7 @@ Roundrobin dispatching is the default method, when no
<p>
<li> <code>dispatchmode random</code>: Random selection. Probably only
for stress testing, though when used with weights (see below)
- it is a good distributor of new connections too.
+ it is a good distributor of new connections too.
<p>
<li> <code>dispatchmode bysize [ over</code> <em>connections</em> <code>]</code>:
The next back end is the one
@@ -610,9 +615,9 @@ The modifier <code>over</code> <em>connections</em> is optional. (The square
assumes that the longer the connection, the heavier the load.
<p>
<li> <code>dispatchmode byconnections</code>: The next back end is the one
- with the least active connections. This mechanism assumes that
- each connection to a back end represents load. It is usable
- for e.g. database connections.
+ with the least active connections. This mechanism assumes that
+ each connection to a back end represents load. It is usable
+ for e.g. database connections.
<p>
<li> <code>dispatchmode byorder</code>: The first back end is selected
every time, unless it's unavailable. In that case the second
@@ -622,12 +627,12 @@ The selection algorithm is only used when clients are serviced that
aren't part of a sticky HTTP session. This is the case during:
<p>
<ul>
- <li> all client requests of a service type <code>any</code>;
- <li> new sessions of a service type <code>stickyhttp</code>.</ul>
+ <li> all client requests of a service type <code>any</code>;
+ <li> new sessions of a service type <code>http</code>.</ul>
<p>
-When <code>stickyhttp</code> is in effect and a session is underway, then the
+When type <code>http</code> is in effect and a session is underway, then the
previously used back end is always selected -- regardless of
-dispatching mode.
+dispatching mode.
<p>
Your 'right' dispatch mode will depend on the type of service. Given
the fact that crossroads doesn't know (and doesn't care) how to
@@ -641,7 +646,7 @@ happen when:
<p>
<ul>
<li> The back end cannot be reached (network connection
- fails);
+ fails);
<li> The network connection to the back end suddenly dies.</ul>
<p>
An example of the definition is <code>revivinginterval 10</code>. When this
@@ -755,7 +760,7 @@ The statements in the backend definition blocks are:
<p>
<ul>
<li> Syntax: <code>server</code> <em>servername</em> <code>;</code>
- <li> Or: <code>server</code> <em>servername</em><code>:</code><em>port</em> <code>;</code>
+ <li> Or: <code>server</code> <em>servername</em><code>:</code><em>port</em> <code>;</code>
<li> There is no default. This is a required setting.</ul>
<p>
<p><dt><strong>Port:</strong><dd> When the <code>server</code> specifier doesn't include a TCP
@@ -766,7 +771,7 @@ The statements in the backend definition blocks are:
<ul>
<li> Syntax: <code>port</code> <em>number</em> <code>;</code>
<li> There is no default. The port must be defined either in
- the <code>server</code> setting or using the <code>port</code> specifier.</ul>
+ the <code>server</code> setting or using the <code>port</code> specifier.</ul>
<p>
<p><dt><strong>Verbosity:</strong><dd> Similar to <code>service</code> specifications, a
<code>backend</code> can have its own verbosity (<code>on</code> or <code>off</code>). When
@@ -774,7 +779,7 @@ The statements in the backend definition blocks are:
<p>
<ul>
<li> Syntax: <code>verbosity</code> <em>setting</em> <code>;</code>
- <li> Or: <code>verbose</code> <em>setting</em> <code>;</code>
+ <li> Or: <code>verbose</code> <em>setting</em> <code>;</code>
<li> where <em>setting</em> is <code>true</code>, <code>yes</code> or <code>on</code> to turn
verbosity on; or <code>false</code>, <code>no</code>, <code>off</code> to turn it off.
<li> Default: <code>off</code>.</ul>
@@ -790,10 +795,10 @@ The difference is that a <code>maxconnections</code> statement at the level of
overloaded.
<p>
<ul>
- <li> Syntax: <code>maxconnections</code> <em>number</em> <code>;</code>
- <li> where <em>number</em> is the maximum number of concurrent
- client connections.
- <li> Default: 0, meaning that there is no limit.</ul>
+ <li> Syntax: <code>maxconnections</code> <em>number</em> <code>;</code>
+ <li> where <em>number</em> is the maximum number of concurrent
+ client connections.
+ <li> Default: 0, meaning that there is no limit.</ul>
<p>
<p><dt><strong>Weight:</strong><dd> To influence how backends are selected by size or by
duration, a backend can specify its 'weight' in the process. The
@@ -809,7 +814,7 @@ The weighing mechanism only applies to the dispatch modes
<p>
<ul>
<li> Syntax: <code>weight</code> <em>number</em> <code>;</code>
- <li> Default: 1</ul>
+ <li> Default: 1</ul>
<p>
<p><dt><strong>Decay:</strong><dd> To make sure that a 'spike' of activity doesn't
influence the perceived load of a back end forever, you may
@@ -831,8 +836,8 @@ This means that when a given back end is hit, then its usage data
data when other back ends are hit
<li> Default: 0, meaning that no decay is applied to usage statistics.</ul>
<p>
-<p><dt><strong>HTTP cookie handling:</strong><dd> When the service type is <code>stickyhttp</code>,
- then backends should define HTTP cookies to identify sessions. There
+<p><dt><strong>HTTP cookie handling:</strong><dd> When the service type is <code>http</code>,
+ then backends may define HTTP cookies to identify sessions. There
are two directives to accomplish this: <code>stickycookie</code> and
<code>insertcookie</code>.
<p>
@@ -840,8 +845,8 @@ The directive <code>insertcookie</code> is used to insert a cookie into the
HTTP stream when crossroads assigns a back end to a new session.
<p>
<ul>
- <li> Syntax: <code>insertcookie</code> <em>cookiestring</em> <code>;</code>
- <li> Default: none</ul>
+ <li> Syntax: <code>insertcookie</code> <em>cookiestring</em> <code>;</code>
+ <li> Default: none</ul>
<p>
The directive <code>stickycookie</code> is used by crossroads to determine
whether a HTTP request is part of an established session. If so, the
@@ -849,8 +854,8 @@ The directive <code>stickycookie</code> is used by crossroads to determine
considerations.
<p>
<ul>
- <li> Syntax: <code>stickycookie</code> <em>cookiestring</em> <code>;</code>
- <li> Default: none</ul>
+ <li> Syntax: <code>stickycookie</code> <em>cookiestring</em> <code>;</code>
+ <li> Default: none</ul>
<p>
It should be obvious that the <em>cookiestrings</em> in the two above
directives should match: the cookie that's initially inserted by
@@ -861,7 +866,7 @@ It should be obvious that the <em>cookiestrings</em> in the two above
<pre>
service www {
port 80;
- type stickyhttp;
+ type http;
backend one {
server 10.0.0.1:80;
stickycookie BalancerID=a;
@@ -878,7 +883,22 @@ service www {
<p>
Note also the quoting of the cookiestring in the <code>insertcookie</code>
directive. Without it, the semicolon in the string would break the
- directive.
+ directive.
+<p>
+<p><dt><strong>Passing of real IP address:</strong><dd> When the service type is
+ <code>http</code>, the directive <code>insertrealip</code> can be used to force
+ Crossroads to insert the client's real IP address as an HTTP
+ header. The back end may then inspect the header.
+<p>
+<ul>
+ <li> Syntax: <code>insertrealip</code> <em>setting</em> <code>;</code>
+ <li> where <em>setting</em> is <code>true</code>, <code>yes</code> or <code>on</code> to turn
+ on this feature; or <code>false</code>, <code>no</code> or <code>off</code> to turn it
+ off.
+ <li> Default: <code>off</code></ul>
+<p>
+When turned on, the client's IP address is stored in an HTTP
+ header named <code>XR-Real-IP</code>.
<p>
<p><dt><strong>Event triggers:</strong><dd> As special 'hooks' for actions, two triggers
are available: <code>onfailure</code> and <code>onsuccess</code>. The argument to
@@ -929,7 +949,7 @@ Turning on traffic dumps will <em>significantly</em>
<ul>
<li> Syntax: <code>trafficlog</code> <em>filename</em> <code>;</code>
<li> There is no default. Without this directive, traffic is
- not logged.</ul>
+ not logged.</ul>
<p>
Besides <code>trafficlog</code>, there is also a directive
<code>throughputlog</code>. This directive also takes one argument, a
@@ -937,13 +957,13 @@ Besides <code>trafficlog</code>, there is also a directive
logged:
<p>
<ul>
- <li> The process ID of the crossroads image that serves the
- TCP connection;
- <li> The time of the request, in seconds and microseconds
- since start of the run;
- <li> A <strong>C</strong> when the request originated at the client, or
- <strong>B</strong> when the request originated at the back end;
- <li> The first 100 bytes of the request.</ul>
+ <li> The process ID of the crossroads image that serves the
+ TCP connection;
+ <li> The time of the request, in seconds and microseconds
+ since start of the run;
+ <li> A <strong>C</strong> when the request originated at the client, or
+ <strong>B</strong> when the request originated at the back end;
+ <li> The first 100 bytes of the request.</ul>
<p>
As an example, consider the following (the lines are shortened for
brevity and prefixed by line numbers for clarity):
@@ -964,25 +984,25 @@ As an example, consider the following (the lines are shortened for
This tells us that:
<p>
<ul>
- <li> 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.
- <li> 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 <strong>B</strong>-type transmission).
- <li> 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.
- <li> Lines 5 to 7: This is the continuation of line 2. Line 7
- is the last line of the <strong>B</strong> 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 <code>index.html</code> requested in line 1.
- <li> 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.</ul>
+ <li> 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.
+ <li> 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 <strong>B</strong>-type transmission).
+ <li> 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.
+ <li> Lines 5 to 7: This is the continuation of line 2. Line 7
+ is the last line of the <strong>B</strong> 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 <code>index.html</code> requested in line 1.
+ <li> 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.</ul>
<p>
It is also worth while remembering that the start time of a <strong>C</strong>
request is the time that crossroads sees the activity. Any latency
@@ -1017,9 +1037,9 @@ Summarizing, the throughput times of a client-back end connection
are not (yet) included in Crossroads.
<p>
<ul>
- <li> Syntax: <code>throughputlog</code> <em>filename</em> <code>;</code>
- <li> There is no default. Without this directive, the
- throughput is not logged.</ul>
+ <li> Syntax: <code>throughputlog</code> <em>filename</em> <code>;</code>
+ <li> There is no default. Without this directive, the
+ throughput is not logged.</ul>
<p>
</dl>
<p>
@@ -1068,23 +1088,23 @@ must therefore give the right hints:
calls and other HTTP requests).
<p>
<li> As a last remark, the dispatching mode <code>byconnections</code> can
- be used if you don't have other clues for load
- estimations.
+ be used if you don't have other clues for load
+ estimations.
<p>
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 <code>select</code> 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, <code>byduration</code>
- 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 <code>byconnections</code> may be
- your best bet.
+ heavier on the back end, time-consuming connections, or connections
+ where loads of bytes are transferred? Well, that depends. A
+ tough <code>select</code> 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, <code>byduration</code>
+ 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 <code>byconnections</code> may be
+ your best bet.
<p>
</ul>
<p>
@@ -1226,18 +1246,18 @@ good idea to protect your service by specifying a maximum number of
concurrent connections. This protection can be specified on two levels:
<p>
<dl>
- <p><dt><strong>On the service level</strong><dd> a statement like <code>maxconnections
- 100;</code> 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.
- <p><dt><strong>On the back end level</strong><dd> a statement like <code>maxconnections 10;</code>
- 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).</dl>
+ <p><dt><strong>On the service level</strong><dd> a statement like <code>maxconnections
+ 100;</code> 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.
+ <p><dt><strong>On the back end level</strong><dd> a statement like <code>maxconnections 10;</code>
+ 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).</dl>
<p>
The <code>maxconnections</code> statement, combined with a back end selection
algorithm, allows very fine granularity. The <code>maxconnections</code> statement
@@ -1266,16 +1286,16 @@ session stickiness hampers failover, balancing and performance:
<ul>
<li> 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 crash.
+ end that was selected at the start of a session. If the back
+ end suddenly goes 'down', then the session will crash.
<li> 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.
+ the session, that back end may well become overloaded. The
+ balancer however must continue to send the requests there.
<li> 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.</ul>
+ crossroads needs to check the HTTP headers in the messages
+ for persistence cookies.</ul>
<p>
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
@@ -1292,7 +1312,7 @@ follows:
<p>
<ul>
<li> At the level of a <code>service</code> description, set the type to
- <code>stickyhttp</code>.
+ <code>http</code>.
<li> At the level of each back end description, configure the
<code>stickycookie</code> and a <code>insertcookie</code> directives.</ul>
<p>
@@ -1302,14 +1322,14 @@ shuttles between client and back end:
<ul>
<li> 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 <code>Set-Cookie</code> directive.
+ 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 <code>Set-Cookie</code> directive.
<li> 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.</ul>
+ established session. Crossroads analyzes the cookie and
+ forwards the request to the appropriate back end.</ul>
<p>
Below is a short example of a configuration.
<p>
@@ -1322,14 +1342,14 @@ service www {
backend one {
server 10.1.1.100:80;
- stickycookie XRID=100;
- insertcookie "XRID=100; Path=/";
+ stickycookie XRID=100;
+ insertcookie "XRID=100; Path=/";
}
backend two {
- server 10.1.1.101:80;
- stickycookie XRID=101;
- insertcookie "XRID=101; Path=/";
+ server 10.1.1.101:80;
+ stickycookie XRID=101;
+ insertcookie "XRID=101; Path=/";
}
}
</pre>
@@ -1337,17 +1357,101 @@ service www {
<p>
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.
+prerequisite for stickiness.
<p>
<a name="l25"></a>
-<h3>5.3: Configuration examples</h3>
+<h3>5.3: Passing the client's IP address</h3>
+<p>
+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.
+<p>
+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:
+<p>
+<ul>
+ <li> The service type must be <code>http</code>, and not <code>any</code>;
+ <li> In the back end definition, a statement <code>insertrealip on;</code>
+ must occur.</ul>
+<p>
+After this, HTTP traffic that arrives at the back ends has a new
+header: <code>XR-Real-IP</code>, holding the client's IP address.
+<strong>Note that</strong> once the type is set to <code>http</code>, Crossroads'
+performance will be hampered -- all passing messages will have to be
+unpacked and analyzed.
+<p>
+<a name="l26"></a>
+<strong>5.3.1: Sample Crossroads configuration</strong>
+<p>
+The below sample configuration shows two HTTP back ends that receive
+the client's IP address:
+<p>
+<pre>
+
+service www {
+ port 80;
+ type http;
+ revivinginterval 5;
+ dispatchmode roundrobin;
+
+ backend one {
+ server 10.1.1.100:80;
+ insertrealip on;
+ }
+
+ backend two {
+ server 10.1.1.200:80;
+ insertrealip on;
+ }
+}
+</pre>
+
+<p>
+<a name="l27"></a>
+<strong>5.3.2: Sample Apache configuration</strong>
+<p>
+The method by which each back end analyzes the header <code>XR-Real-IP</code>
+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.
+<p>
+Often this is accomplished using the log format <code>custom</code>, defined as
+follows:
+<p>
+<pre>
+LogFormat "%h %l %u %t %D \"%r\" %>s %b" common
+CustomLog logs/access_log common
+</pre>
+
+<p>
+The first line defines the format <code>common</code>, with the remote host
+specified by <code>%h</code>. The second line sends access information to a log
+file <code>logs/access_log</code>, using the previously defined format
+<code>common</code>.
+<p>
+Furtunately, Apache's <code>LogFormat</code> allows one to log contents of
+headers. By replacing the <code>%h</code> with <code>%{XR-Real-IP}i</code>, the desired
+information is sent to the log. Therefore, normally you can simply
+redefine the <code>common</code> format to
+<p>
+<pre>
+LogFormat "%{XR-Real-IP}i %l %u %t %D \"%r\" %>s %b" common
+</pre>
+
+<p>
+<a name="l28"></a>
+<h3>5.4: 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="l26"></a>
-<strong>5.3.1: A load balancer for three webserver back ends</strong>
+<a name="l29"></a>
+<strong>5.4.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
@@ -1475,8 +1579,8 @@ service www {
</pre>
<p>
-<a name="l27"></a>
-<strong>5.3.2: An HTTP forwarder when travelling</strong>
+<a name="l30"></a>
+<strong>5.4.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
@@ -1501,7 +1605,7 @@ Here's how it used to be before crossroads:
<p>
<li> And in yet other instances, I use a HTTP diagnostic tool
<a href="http://www.xk72.com/charles">Charles</a>
- that sits between browser and website and shows me
+ 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
@@ -1564,8 +1668,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="l28"></a>
-<strong>5.3.3: SSH login with enforced idle logout</strong>
+<a name="l31"></a>
+<strong>5.4.3: SSH login with enforced idle logout</strong>
<p>
The following example shows how crossroads 'throttles' SSH
logins. Connections are accepted on port
@@ -1590,24 +1694,24 @@ service Ssh {
</pre>
<p>
-<a name="l29"></a>
+<a name="l32"></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="l30"></a>
+<a name="l33"></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:
<p>
<ol>
- <li> A website was recursively spidered through a local squid
- proxy. The spidering was repeated 10 times, the total was recorded.
+ <li> A website was recursively spidered through a local squid
+ proxy. The spidering was repeated 10 times, the total was recorded.
<p>
<li> Crossroads was placed in front of the squid proxy, and
- the website was again recursively spidered. Again, the
- spidering was repeated 10 times and the total was recorded.</ol>
+ the website was again recursively spidered. Again, the
+ spidering was repeated 10 times and the total was recorded.</ol>
<p>
The crossroads configuration of the second alternative is shown below:
<p>
@@ -1624,7 +1728,7 @@ service HttpProxy {
</pre>
<p>
-<a name="l31"></a>
+<a name="l34"></a>
<strong>6.1.1: Results</strong>
<p>
The results of this test are that crossroads causes a negligible
@@ -1647,7 +1751,7 @@ sys 0m0.230s
</pre>
<p>
-<a name="l32"></a>
+<a name="l35"></a>
<strong>6.1.2: Discussion</strong>
<p>
The above shown results are quite favorable to crossroads. However,
@@ -1668,18 +1772,18 @@ This worst case scenario will however (fortunately) occur only very
seldom in the real world:
<p>
<ul>
- <li> Normally network issues, such as the above mentioned host
- name lookups or throughput restrictions, will add
- significantly to the duration of a request. The 'twice as
- many' read/writes caused by crossroads are then relatively
- irrelevant.
+ <li> Normally network issues, such as the above mentioned host
+ name lookups or throughput restrictions, will add
+ significantly to the duration of a request. The 'twice as
+ many' read/writes caused by crossroads are then relatively
+ irrelevant.
<p>
<li> Normally a significant amount of time will be spent in a
- back end, due to processing (e.g., when calling a servlet on a
- back end). Again, this processing time will weigh much heavier
- than the multiple read/writes.</ul>
+ back end, due to processing (e.g., when calling a servlet on a
+ back end). Again, this processing time will weigh much heavier
+ than the multiple read/writes.</ul>
<p>
-<a name="l33"></a>
+<a name="l36"></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
@@ -1693,7 +1797,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="l34"></a>
+<a name="l37"></a>
<strong>6.2.1: Environment</strong>
<p>
On the balancer, LVS was run on port 80, its forwarding set up for two
@@ -1724,7 +1828,7 @@ service http {
</pre>
<p>
-<a name="l35"></a>
+<a name="l38"></a>
<strong>6.2.2: Tests and results</strong>
<p>
In the first test, ports 80 and 81 on the balancer were 'bombed' with
@@ -1732,16 +1836,16 @@ In the first test, ports 80 and 81 on the balancer were 'bombed' with
following timings where measured:
<p>
<ul>
- <li> How long it takes to establish a connection;
- <li> How long it takes to retrieve the page.</ul>
+ <li> How long it takes to establish a connection;
+ <li> How long it takes to retrieve the page.</ul>
<p>
The results of this test were:
<p>
<ul>
- <li> On average, each client took 0.12 seconds to connect
- to LVS, and each page was retrieved in 0.14 seconds;
- <li> On average, each client took 0.11 seconds to connect to
- crossroads, and each page was retrieved in 0.13 seconds.</ul>
+ <li> On average, each client took 0.12 seconds to connect
+ to LVS, and each page was retrieved in 0.14 seconds;
+ <li> On average, each client took 0.11 seconds to connect to
+ crossroads, and each page was retrieved in 0.13 seconds.</ul>
<p>
In this setup there seems to be no difference between the performance
of LVS and crossroads!
@@ -1803,16 +1907,16 @@ 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="l36"></a>
+<a name="l39"></a>
<h2>7: Compiling and Installing</h2>
-<a name="compiling"></a><a name="l37"></a>
+<a name="compiling"></a><a name="l40"></a>
<h3>7.1: Prerequisites</h3>
<p>
The creation of crossroads requires:
<p>
<ul>
- <li> Standard Unix tools, such as <code>sed</code>, <code>awk</code>, <code>Perl</code>
- (5.00 or better);
+ <li> Standard Unix tools, such as <code>sed</code>, <code>awk</code>, <code>Perl</code>
+ (5.00 or better);
<p>
<li> A POSIX-compliant C compiler;
<p>
@@ -1825,65 +1929,65 @@ 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="l38"></a>
+<a name="l41"></a>
<h3>7.2: Compiling and installing</h3>
<p>
<ul>
- <li> Obtain the source distribution. It can be found on
- <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>.
+ <li> Obtain the source distribution. It can be found on
+ <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
- subdirectory <code>crossroads-</code><em>X.YY/</em>.
+ xzf crossroads-</code><em>X.YY</em><code>.tar.gz</code>. The contents spill into a
+ subdirectory <code>crossroads-</code><em>X.YY/</em>.
<p>
<li> Change-dir into the directory.
<p>
<li> Next, edit <code>etc/Makefile.def</code> and verify that all
- compilation settings are to your likings. The settings are
- explained in the file. <strong>Note that</strong> the default distribution
- of <code>Makefile.def</code> is suited for Linux or Apple MacOSX
- systems. On other Unices, or on non-Unix systems, you must
- particularly pay attention to <code>SET_PROC_TITLE_BY...</code>. When
- in doubt, comment out all <code>SET_PROC_TITLE...</code>
- settings. Crossroads will work nevertheless, but it won't show
- nice titles in <code>ps</code> listings. Also there's a macro
- <code>EXTRA_LIBS</code> to add linkage flags (an example for a Solaris
- build is included).
+ compilation settings are to your likings. The settings are
+ explained in the file. <strong>Note that</strong> the default distribution
+ of <code>Makefile.def</code> is suited for Linux or Apple MacOSX
+ systems. On other Unices, or on non-Unix systems, you must
+ particularly pay attention to <code>SET_PROC_TITLE_BY...</code>. When
+ in doubt, comment out all <code>SET_PROC_TITLE...</code>
+ settings. Crossroads will work nevertheless, but it won't show
+ nice titles in <code>ps</code> listings. Also there's a macro
+ <code>EXTRA_LIBS</code> to add linkage flags (an example for a Solaris
+ build is included).
<p>
<li> Now crossroads is ready for compilation. Do a <code>make
- local</code> followed by <code>make install</code>. The latter step may have
- to be done by the user <code>root</code> if the <code>BINDIR</code> setting of
- <code>etc/Makefile.def</code> points to a root-owned directory.
+ local</code> followed by <code>make install</code>. The latter step may have
+ to be done by the user <code>root</code> if the <code>BINDIR</code> setting of
+ <code>etc/Makefile.def</code> points to a root-owned directory.
<p>
<li> The documentation doesn't install in this process. If you
- want to install the documentation, then proceed as follows:
+ want to install the documentation, then proceed as follows:
<p>
<ul>
- <li> Optionally, <code>cp doc/crossroads.html</code>
- <em>htmldirectory/</em>; where <em>htmldirectory</em> is the destination
- directory for your HTML manuals;
+ <li> Optionally, <code>cp doc/crossroads.html</code>
+ <em>htmldirectory/</em>; where <em>htmldirectory</em> is the destination
+ directory for your HTML manuals;
<p>
<li> Optionally, <code>cp doc/crossroads.pdf</code>
- <em>pdfdirectory/</em>; where <em>pdfdirectory</em> is the
- destination directory for your PDF manuals;
+ <em>pdfdirectory/</em>; where <em>pdfdirectory</em> is the
+ destination directory for your PDF manuals;
<p>
<li> Optionally, <code>cp doc/crossroads.man</code>
- <em>manualdirectory</em><code>/man1/crossroads.1</code>, where
- <em>manualdirectory</em> is e.g. <code>/usr/man</code>,
- <code>/usr/share</code>, <code>/usr/local/man</code>,
- <code>/usr/local/share</code>. Any possibility is valid, as
- long as <em>manualdirectory</em> has a subdirectory
- <code>man1/</code>;
+ <em>manualdirectory</em><code>/man1/crossroads.1</code>, where
+ <em>manualdirectory</em> is e.g. <code>/usr/man</code>,
+ <code>/usr/share</code>, <code>/usr/local/man</code>,
+ <code>/usr/local/share</code>. Any possibility is valid, as
+ long as <em>manualdirectory</em> has a subdirectory
+ <code>man1/</code>;
<p>
<li> If your manual page system supports compressed
- manual pages, then you can save some space with
- <code>gzip</code> <em>manualdirectory</em><code>/man1/crossroads.1</code>.</ul>
+ manual pages, then you can save some space with
+ <code>gzip</code> <em>manualdirectory</em><code>/man1/crossroads.1</code>.</ul>
<p>
</ul>
<p>
-<a name="l39"></a>
+<a name="l42"></a>
<h3>7.3: Configuring crossroads</h3>
<p>
Now that the binary is available on your system, you need to create a
@@ -1895,8 +1999,8 @@ Once you have the configuration ready, start crossroads with
ends. Monitor how crossroads is doing with:
<p>
<ul>
- <li> In one terminal, run the script:
- <pre>
+ <li> In one terminal, run the script:
+ <pre>
while [ 1 ] ; do
tput clear
crossroads status
@@ -1906,10 +2010,10 @@ done
<p>
<strong>Note</strong> that depending on your system you might need
- <code>sleep 3s</code>, i.e., with an <code>s</code> appended.
+ <code>sleep 3s</code>, i.e., with an <code>s</code> appended.
<p>
<li> In another terminal, run:
- <pre>
+ <pre>
while [ 1 ] ; do
tput clear
ps ax | grep crossroads | grep -v grep
@@ -1919,11 +2023,11 @@ done
<p>
<strong>Note</strong> that depending on your system you might need
- <code>ps -ef</code> instead of <code>ps ax</code>.
+ <code>ps -ef</code> instead of <code>ps ax</code>.
<p>
<li> In yet another terminal, run <code>tail -f
- /var/log/messages</code> (supply the appropriate system log file if
- <code>/var/log/messages</code> doesn't work for you).</ul>
+ /var/log/messages</code> (supply the appropriate system log file if
+ <code>/var/log/messages</code> doesn't work for you).</ul>
<p>
Now thoroughly test the availability of your back ends through
crossroads. The status display will show an updated view of which back
@@ -1932,13 +2036,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="l40"></a>
+<a name="l43"></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="l41"></a>
+<a name="l44"></a>
<strong>7.4.1: SysV Style Startup</strong>
<p>
On SysV style systems, there's a startup script directory
@@ -1948,8 +2052,8 @@ inserting scripts into the boot sequence, but
otherwise the steps will resemble the following.
<p>
<ul>
- <li> Create a script <code>crossroads</code> in <code>/etc/init.d</code> similar to the
- following:
+ <li> Create a script <code>crossroads</code> in <code>/etc/init.d</code> similar to the
+ following:
<p>
<pre>
#!/bin/sh
@@ -1958,13 +2062,13 @@ otherwise the steps will resemble the following.
<p>
The stated directory <code>/usr/local/bin</code> must correspond with
- the installation path. The flag <code>-v</code> causes the startup to
- be more 'verbose'. However, once daemonized, the verbosity is
- controlled by the appropriate statements in the configuration.
+ the installation path. The flag <code>-v</code> causes the startup to
+ be more 'verbose'. However, once daemonized, the verbosity is
+ controlled by the appropriate statements in the configuration.
<p>
<li> Determine your 'runlevel': usually 3 when your system is
- running in text-mode only, or 5 when you are a graphical
- interface. If your runlevel is 3, then:
+ running in text-mode only, or 5 when you are using a graphical
+ interface. If your runlevel is 3, then:
<p>
<pre>
root> cd /etc/rc.d/rc3.d
@@ -1974,13 +2078,13 @@ root> ln -s /etc/init.d/crossroads K99crossroads
<p>
This creates startup (<code>S*</code>) and stop (<code>K*</code>) links that
- will be run when the system enters or leaves a given runlevel.
+ will be run when the system enters or leaves a given runlevel.
<p>
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>
+ <code>/etc/rc.d/rc5.d</code>. Alternatively, you can create the
+ symlinks in both runlevel directories.</ul>
<p>
-<a name="l42"></a>
+<a name="l45"></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\&.05" "2005, 2006, ff\&."
+.TH "Crossroads 1\&.07" "2005, 2006, ff\&."
.PP
-.SH "Crossroads 1\&.05"
+.SH "Crossroads 1\&.07"
.SH "Karel Kubat"
.SH "e-tunity"
.SH "2005, 2006, ff\&."
@@ -477,20 +477,20 @@ statements\&. Each statement must end with a semicolon, except for the
.IP "The type statement"
defines how crossroads handles the stated
service\&. There are currently two types: \f(CWany\fP and
-\f(CWstickyhttp\fP\&. The type \f(CWany\fP means that crossroads doesn\&'t
+\f(CWhttp\fP\&. The type \f(CWany\fP means that crossroads doesn\&'t
interpret the contents of a TCP stream, but only distributes streams
-over back ends\&. The type \f(CWstickyhttp\fP means that crossroads has to
-analyze what\&'s in the messages, does magical HTTP cookie tricks, and
-so on -- to ensure that multiple connections are treated as one
-session\&.
+over back ends\&. The type \f(CWhttp\fP means that crossroads has to
+analyze what\&'s in the messages, does magical HTTP header tricks, and
+so on -- all to ensure that multiple connections are treated as one
+session, or that the back end is notified of the client\&'s IP address\&.
.IP
-Unless you really need sticky HTTP sessions, use the type \f(CWany\fP (the
+Unless you really need such special features, use the type \f(CWany\fP (the
default), even for HTTP protocols\&.
.IP
.IP o
Syntax: \f(CWtype\fP \fItypespecifier\fP \f(CW;\fP
.IP o
-Where \fItypespecifier\fP is \f(CWany\fP or \f(CWstickyhttp\fP
+Where \fItypespecifier\fP is \f(CWany\fP or \f(CWhttp\fP
.IP o
Default: \f(CWany\fP
.IP
@@ -597,11 +597,11 @@ aren\&'t part of a sticky HTTP session\&. This is the case during:
.IP o
all client requests of a service type \f(CWany\fP;
.IP o
-new sessions of a service type \f(CWstickyhttp\fP\&.
+new sessions of a service type \f(CWhttp\fP\&.
.IP
-When \f(CWstickyhttp\fP is in effect and a session is underway, then the
+When type \f(CWhttp\fP is in effect and a session is underway, then the
previously used back end is always selected -- regardless of
-dispatching mode\&.
+dispatching mode\&.
.IP
Your \&'right\&' dispatch mode will depend on the type of service\&. Given
the fact that crossroads doesn\&'t know (and doesn\&'t care) how to
@@ -831,8 +831,8 @@ data when other back ends are hit
Default: 0, meaning that no decay is applied to usage statistics\&.
.IP
.IP "HTTP cookie handling:"
-When the service type is \f(CWstickyhttp\fP,
-then backends should define HTTP cookies to identify sessions\&. There
+When the service type is \f(CWhttp\fP,
+then backends may define HTTP cookies to identify sessions\&. There
are two directives to accomplish this: \f(CWstickycookie\fP and
\f(CWinsertcookie\fP\&.
.IP
@@ -863,7 +863,7 @@ example:
.nf
service www {
port 80;
- type stickyhttp;
+ type http;
backend one {
server 10\&.0\&.0\&.1:80;
stickycookie BalancerID=a;
@@ -880,7 +880,25 @@ service www {
.IP
Note also the quoting of the cookiestring in the \f(CWinsertcookie\fP
directive\&. Without it, the semicolon in the string would break the
-directive\&.
+directive\&.
+.IP
+.IP "Passing of real IP address:"
+When the service type is
+\f(CWhttp\fP, the directive \f(CWinsertrealip\fP can be used to force
+Crossroads to insert the client\&'s real IP address as an HTTP
+header\&. The back end may then inspect the header\&.
+.IP
+.IP o
+Syntax: \f(CWinsertrealip\fP \fIsetting\fP \f(CW;\fP
+.IP o
+where \fIsetting\fP is \f(CWtrue\fP, \f(CWyes\fP or \f(CWon\fP to turn
+on this feature; or \f(CWfalse\fP, \f(CWno\fP or \f(CWoff\fP to turn it
+off\&.
+.IP o
+Default: \f(CWoff\fP
+.IP
+When turned on, the client\&'s IP address is stored in an HTTP
+header named \f(CWXR-Real-IP\fP\&.
.IP
.IP "Event triggers:"
As special \&'hooks\&' for actions, two triggers
@@ -1319,7 +1337,7 @@ follows:
.PP
.IP o
At the level of a \f(CWservice\fP description, set the type to
-\f(CWstickyhttp\fP\&.
+\f(CWhttp\fP\&.
.IP o
At the level of each back end description, configure the
\f(CWstickycookie\fP and a \f(CWinsertcookie\fP directives\&.
@@ -1351,14 +1369,14 @@ service www {
backend one {
server 10\&.1\&.1\&.100:80;
- stickycookie XRID=100;
- insertcookie "XRID=100; Path=/";
+ stickycookie XRID=100;
+ insertcookie "XRID=100; Path=/";
}
backend two {
- server 10\&.1\&.1\&.101:80;
- stickycookie XRID=101;
- insertcookie "XRID=101; Path=/";
+ server 10\&.1\&.1\&.101:80;
+ stickycookie XRID=101;
+ insertcookie "XRID=101; Path=/";
}
}
.fi
@@ -1366,10 +1384,98 @@ service www {
.PP
Note how the cookie names and values in the directives
\f(CWstickycookie\fP and \f(CWinsertcookie\fP match\&. That is obviously a
-prerequisite for stickiness\&.
+prerequisite for stickiness\&.
+.PP
+
+.SH "5\&.3: Passing the client\&'s IP address"
+
+.PP
+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\&.
+.PP
+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:
+.PP
+.IP o
+The service type must be \f(CWhttp\fP, and not \f(CWany\fP;
+.IP o
+In the back end definition, a statement \f(CWinsertrealip on;\fP
+must occur\&.
+.PP
+After this, HTTP traffic that arrives at the back ends has a new
+header: \f(CWXR-Real-IP\fP, holding the client\&'s IP address\&.
+\fBNote that\fP once the type is set to \f(CWhttp\fP, Crossroads\&'
+performance will be hampered -- all passing messages will have to be
+unpacked and analyzed\&.
+.PP
+
+.SH "5\&.3\&.1: Sample Crossroads configuration"
+
+.PP
+The below sample configuration shows two HTTP back ends that receive
+the client\&'s IP address:
+.PP
+.nf
+
+service www {
+ port 80;
+ type http;
+ revivinginterval 5;
+ dispatchmode roundrobin;
+
+ backend one {
+ server 10\&.1\&.1\&.100:80;
+ insertrealip on;
+ }
+
+ backend two {
+ server 10\&.1\&.1\&.200:80;
+ insertrealip on;
+ }
+}
+.fi
+
+.PP
+
+.SH "5\&.3\&.2: Sample Apache configuration"
+
+.PP
+The method by which each back end analyzes the header \f(CWXR-Real-IP\fP
+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\&.
+.PP
+Often this is accomplished using the log format \f(CWcustom\fP, defined as
+follows:
+.PP
+.nf
+LogFormat "%h %l %u %t %D \e"%r\e" %>s %b" common
+CustomLog logs/access_log common
+.fi
+
+.PP
+The first line defines the format \f(CWcommon\fP, with the remote host
+specified by \f(CW%h\fP\&. The second line sends access information to a log
+file \f(CWlogs/access_log\fP, using the previously defined format
+\f(CWcommon\fP\&.
+.PP
+Furtunately, Apache\&'s \f(CWLogFormat\fP allows one to log contents of
+headers\&. By replacing the \f(CW%h\fP with \f(CW%{XR-Real-IP}i\fP, the desired
+information is sent to the log\&. Therefore, normally you can simply
+redefine the \f(CWcommon\fP format to
+.PP
+.nf
+LogFormat "%{XR-Real-IP}i %l %u %t %D \e"%r\e" %>s %b" common
+.fi
+
.PP
-.SH "5\&.3: Configuration examples"
+.SH "5\&.4: Configuration examples"
.PP
As a general hint, use \f(CWcrossroads sampleconf\fP to view the most
@@ -1377,7 +1483,7 @@ up-to-date examples of configurations\&. The description below shows a
few examples too\&.
.PP
-.SH "5\&.3\&.1: A load balancer for three webserver back ends"
+.SH "5\&.4\&.1: A load balancer for three webserver back ends"
.PP
The following configuration example binds crossroads to port 80 of the
@@ -1507,7 +1613,7 @@ service www {
.PP
-.SH "5\&.3\&.2: An HTTP forwarder when travelling"
+.SH "5\&.4\&.2: An HTTP forwarder when travelling"
.PP
As another example, here\&'s my \f(CWcrossroads\&.conf\fP that I use on my
@@ -1602,7 +1708,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\&.3\&.3: SSH login with enforced idle logout"
+.SH "5\&.4\&.3: SSH login with enforced idle logout"
.PP
The following example shows how crossroads \&'throttles\&' SSH
@@ -2016,7 +2122,7 @@ controlled by the appropriate statements in the configuration\&.
.IP
.IP o
Determine your \&'runlevel\&': usually 3 when your system is
-running in text-mode only, or 5 when you are a graphical
+running in text-mode only, or 5 when you are using a graphical
interface\&. If your runlevel is 3, then:
.IP
.nf
diff --git a/doc/crossroads.pdf b/doc/crossroads.pdf
Binary files differ.
diff --git a/doc/crossroads.yo b/doc/crossroads.yo
@@ -2,15 +2,15 @@ tocclearpage()
titleclearpage()
includefile(defs.yo)
abstract(Crossroads is a load balance and fail over utility for TCP
- based services. It is a daemon program running in user
- space, and features extensive configurability, polling of
- back ends using 'wakeup calls', detailed status reporting,
- 'hooks' for special actions when backend calls fail, and much
- more. Crossroads is service-independent: it is usable for
- HTTP/HTTPS, SSH, SMTP, DNS, etc. In the case of HTTP
- balancing, Crossroads can provide 'session stickiness' for
- back-end processes that need sessions, but aren't
- session-aware of other back-ends.)
+ based services. It is a daemon program running in user
+ space, and features extensive configurability, polling of
+ back ends using 'wakeup calls', detailed status reporting,
+ 'hooks' for special actions when backend calls fail, and much
+ more. Crossroads is service-independent: it is usable for
+ HTTP/HTTPS, SSH, SMTP, DNS, etc. In the case of HTTP
+ balancing, Crossroads can provide 'session stickiness' for
+ back-end processes that need sessions, but aren't
+ session-aware of other back-ends.)
article(Crossroads VER())
(Karel Kubat)
(2005, 2006, ff.)
diff --git a/doc/defs.yo b/doc/defs.yo
@@ -1,7 +1,7 @@
COMMENT(
- Local Yodl Macros
- =================
+ Local Yodl Macros
+ =================
Here's a sample "local config" file that gets installed into
/usr/e/share/yodl. You can use this as an example to cook your
@@ -42,9 +42,9 @@ setfigureext(.png)
sethtmlfigureext(.png)
COMMENT(pngfig (basename-without-extension) (caption) (label)
- A-la figure() but includes the true png. We can do that
- because we use pdflatex.)
-
+ A-la figure() but includes the true png. We can do that
+ because we use pdflatex.)
+
redef(pngfig)(3)(\
whenhtml(figure(ARG1)(ARG2)(ARG3))\
whenlatex(\
@@ -57,14 +57,14 @@ redef(pngfig)(3)(\
latexcommand(\label{)ARG3+latexcommand(})\
latexcommand(\end{figure}))
whenman(verb(
- =====================================================
- Insert figure ARG1 about here
- ARG2
- =====================================================)\
- label(ARG3)))
+ =====================================================
+ Insert figure ARG1 about here
+ ARG2
+ =====================================================)\
+ label(ARG3)))
COMMENT(listing(text)
- A-la verb() but nicely formatted in LaTeX.)
+ A-la verb() but nicely formatted in LaTeX.)
redef(listing)(1)(\
whenhtml(verb(ARG1))\
diff --git a/doc/impatient.yo b/doc/impatient.yo
@@ -4,42 +4,42 @@ for getting crossroads up and running:
itemization(
- it() If you don't have SVN or don't want to use it:
+ it() If you don't have SVN or don't want to use it:
- itemization(
- 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.
+ itemization(
+ 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.
- it() Change-dir into the create directory tt(crossroads/).)
+ it() Change-dir into the create directory tt(crossroads/).)
- it() If you have SVN and want to go for the newest snapshot:
+ it() If you have SVN and want to go for the newest snapshot:
- itemization(
- it() Get the latest sources and snapshots using SVN from nl()
+ itemization(
+ it() Get the latest sources and snapshots using SVN from nl()
tt(svn://svn.e-tunity.com/crossroads).
- it() You'll find the newest alpha version under
- tt(crossroads/trunk) and the stable versions under
- tt(crossroads/tags),
- e.g. tt(crossroads/tags/release-1.00).
+ it() You'll find the newest alpha version under
+ tt(crossroads/trunk) and the stable versions under
+ tt(crossroads/tags),
+ e.g. tt(crossroads/tags/release-1.00).
- it() Choose which you want to use: the latest stable
- release, or the bleeding edge alpha? In the former case,
- change-dir to tt(crossroads/tags/release-)em(X.YY), where
- em(X.YY) is a release ID. In the latter case, change-dir to
- tt(crossroads/trunk).)
+ it() Choose which you want to use: the latest stable
+ release, or the bleeding edge alpha? In the former case,
+ change-dir to tt(crossroads/tags/release-)em(X.YY), where
+ em(X.YY) is a release ID. In the latter case, change-dir to
+ tt(crossroads/trunk).)
- it() Type tt(make install). This installs the crossroads
- binary into tt(/usr/local/bin/). If the compilation doesn't
- work on your system, check tt(etc/Makefile.def) for hints.
+ it() Type tt(make install). This installs the crossroads
+ binary into tt(/usr/local/bin/). If the compilation doesn't
+ work on your system, check tt(etc/Makefile.def) for hints.
- it() Create a file tt(/etc/crossroads.conf). In it state
- something like:
+ it() Create a file tt(/etc/crossroads.conf). In it state
+ something like:
- verb(\
+ verb(\
service www {
port 80;
revivinginterval 15;
@@ -51,15 +51,15 @@ service www {
}
})
- That's off course assuming that you want to balance HTTP on
- port 80 to two back ends at 10.1.1.100 and 10.1.1.101.
+ That's off course assuming that you want to balance HTTP on
+ port 80 to two back ends at 10.1.1.100 and 10.1.1.101.
- it() Type tt(crossroads start).
+ it() Type tt(crossroads start).
- it() Surf to the machine where crossroads is running. You will
- see the pages served by the back ends 10.1.1.100 or
- 10.1.1.101.
+ it() Surf to the machine where crossroads is running. You will
+ see the pages served by the back ends 10.1.1.100 or
+ 10.1.1.101.
- it() To monitor the status of crossroads, type tt(crossroads
- status).
+ it() To monitor the status of crossroads, type tt(crossroads
+ status).
)
diff --git a/doc/intro.yo b/doc/intro.yo
@@ -30,17 +30,17 @@ subsect(Obtaining Crossroads)
As quick reference, here are some important URL's for Crossroads:
itemization(
- it() lurl(http:/crossroads.e-tunity.com) is the site that serves
- Crossroads. You can browse this at leisure
- for documentation, sources, and so on.
+ it() lurl(http:/crossroads.e-tunity.com) is the site that serves
+ Crossroads. You can browse this at leisure
+ for documentation, sources, and so on.
- it() lurl(http://freshmeat.net/projects/crossr) is the
- Freshmeat announcement page.
+ it() lurl(http://freshmeat.net/projects/crossr) is the
+ Freshmeat announcement page.
- it() lurl(svn://svn.e-tunity.com/crossroads) is the SVN
- repository; anonymous reading (fetching) is allowed. In order
- to commit changes, url(mail me)(mailto:karel@e-tunity.com) for
- credentials.)
+ it() lurl(svn://svn.e-tunity.com/crossroads) is the SVN
+ repository; anonymous reading (fetching) is allowed. In order
+ to commit changes, url(mail me)(mailto:karel@e-tunity.com) for
+ credentials.)
subsect(Copyright and Disclaimer)
@@ -70,84 +70,84 @@ more meanings of the terms will exist -- yes, I am aware of that. I'm
using the terms here in a very strict sense.)
description(
- dit(A client) is a process that initiates a network connection
- to get contact with some service.
- dit(A service) or bf(server process) or bf(listener)
- is a central application
- that accepts network connections from clients and sevices
- them.
- dit(Back ends) are locations where crossroads looks in
- order to service its clients. Crossroads sits 'in between'
- and does its tricks. Therefore, as far as the back ends
- are concerned, crossroads behaves like a client. As far as
- the true client is concerned, crossroads behaves like the
- service. The communication is however transparent: neither
- client nor back end are aware of the middle position of
- crossroads.
- dit(A connection) is a network conversation between client and service,
- where data are transferred to and fro. As
- far as crossroads is concerned, success means that a
- connection can be established without errors on
- the network level. Crossroads isn't aware of service
- pecularities. E.g., when a webserver answers tt(HTTP/1.0
- 500 Server Error) then crossroads will see this as a
- succesful connection, though the user behind a browser may
- think otherwise.
- dit(Back end selection algorithms) are methods by which
- crossroads determines which back end it will talk to
- next. Crossroads has a number of built-in algorithms,
- which may be configured per service.
+ dit(A client) is a process that initiates a network connection
+ to get contact with some service.
+ dit(A service) or bf(server process) or bf(listener)
+ is a central application
+ that accepts network connections from clients and sevices
+ them.
+ dit(Back ends) are locations where crossroads looks in
+ order to service its clients. Crossroads sits 'in between'
+ and does its tricks. Therefore, as far as the back ends
+ are concerned, crossroads behaves like a client. As far as
+ the true client is concerned, crossroads behaves like the
+ service. The communication is however transparent: neither
+ client nor back end are aware of the middle position of
+ crossroads.
+ dit(A connection) is a network conversation between client and service,
+ where data are transferred to and fro. As
+ far as crossroads is concerned, success means that a
+ connection can be established without errors on
+ the network level. Crossroads isn't aware of service
+ pecularities. E.g., when a webserver answers tt(HTTP/1.0
+ 500 Server Error) then crossroads will see this as a
+ succesful connection, though the user behind a browser may
+ think otherwise.
+ dit(Back end selection algorithms) are methods by which
+ crossroads determines which back end it will talk to
+ next. Crossroads has a number of built-in algorithms,
+ which may be configured per service.
dit(Back end states) are the statusses of each back end that
- is known to crossroads. A back end may be available,
- (temporarily) unavailble or truly down. When a back end is
- temporarily unavailable, then crossroads will periodically
- check whether the back end has come to life yet (that is,
- if configured so).
- dit(A spike) is a sudden increase in activity, leading to
- extra load on a given service. When crossroads is in
- effect and when the spike occurs in one connection,
- then obviously the spike will also appear at one
- of the back ends. However, crossroads will see the spike
- and will make sure that a subsequent request goes to an
- other back end. In contrast, when several connections
- arrive simultaneously and cause a spike, then crossroads
- will be able to distribute the connections over several
- back ends, thereby 'flattening out' the increase.
- dit(Load balancing) means that incoming client requests are
- distributed over more than just one back end (which wouldn't be the
- case if you wouldn't be running crossroads). Enabling load
- balancing is nothing more than duplicating services over
- more than one back end, and having something (in this
- case: crossroads) distribute the requests, so that per
- back end the load doesn't get too high.
- dit(An HTTP session) is a series of separate network connections
- that originate from one browser. E.g., to fill the display
- with text and images, the browser hits a website several times.
- An HTTP session may even span several
- screens. E.g., a website registration dialog may involve 3
- screens that when called from the same browser,
- form a logical group of some sort.
- dit(Session stickiness) means that when a browser starts an
- HTTP dialog, the balancer makes sure that it 'sticks' to
- the same back end (i.e., subsequent requests from the
- browser are forced to go to the same back end, instead of
- being balanced to other ones).
- dit(Back end usage) is measured by crossroads in order to be
- able to determine back end selection. Crossroads stores
- information about the number of active connections, the
- transferred bytes and
- about the connection duration. These numbers can be used to
- estimate which back end is the least used -- and
- therefore, presumably, the best candidate for a new
- request.
- dit(Fail over) is almost always used when load balancing is in
- effect. The distributor of client requests (crossroads of
- course) can also monitor back ends, so that incase a back
- end is 'down', it is no longer accessed.
- dit(Service downtime) normally occurs when a service is
- switched off. Downtime is obviously avoided when fail over
- is in effect: a back end can be taken out of service in a
- controlled manner, without any client noticing it.
+ is known to crossroads. A back end may be available,
+ (temporarily) unavailble or truly down. When a back end is
+ temporarily unavailable, then crossroads will periodically
+ check whether the back end has come to life yet (that is,
+ if configured so).
+ dit(A spike) is a sudden increase in activity, leading to
+ extra load on a given service. When crossroads is in
+ effect and when the spike occurs in one connection,
+ then obviously the spike will also appear at one
+ of the back ends. However, crossroads will see the spike
+ and will make sure that a subsequent request goes to an
+ other back end. In contrast, when several connections
+ arrive simultaneously and cause a spike, then crossroads
+ will be able to distribute the connections over several
+ back ends, thereby 'flattening out' the increase.
+ dit(Load balancing) means that incoming client requests are
+ distributed over more than just one back end (which wouldn't be the
+ case if you wouldn't be running crossroads). Enabling load
+ balancing is nothing more than duplicating services over
+ more than one back end, and having something (in this
+ case: crossroads) distribute the requests, so that per
+ back end the load doesn't get too high.
+ dit(An HTTP session) is a series of separate network connections
+ that originate from one browser. E.g., to fill the display
+ with text and images, the browser hits a website several times.
+ An HTTP session may even span several
+ screens. E.g., a website registration dialog may involve 3
+ screens that when called from the same browser,
+ form a logical group of some sort.
+ dit(Session stickiness) means that when a browser starts an
+ HTTP dialog, the balancer makes sure that it 'sticks' to
+ the same back end (i.e., subsequent requests from the
+ browser are forced to go to the same back end, instead of
+ being balanced to other ones).
+ dit(Back end usage) is measured by crossroads in order to be
+ able to determine back end selection. Crossroads stores
+ information about the number of active connections, the
+ transferred bytes and
+ about the connection duration. These numbers can be used to
+ estimate which back end is the least used -- and
+ therefore, presumably, the best candidate for a new
+ request.
+ dit(Fail over) is almost always used when load balancing is in
+ effect. The distributor of client requests (crossroads of
+ course) can also monitor back ends, so that incase a back
+ end is 'down', it is no longer accessed.
+ dit(Service downtime) normally occurs when a service is
+ switched off. Downtime is obviously avoided when fail over
+ is in effect: a back end can be taken out of service in a
+ controlled manner, without any client noticing it.
)
subsect(Porting issues for pre-0.26 installations)
@@ -156,10 +156,10 @@ subsect(Porting issues for pre-0.26 installations)
changed. In particular:
itemization(
- it() The keyword tt(maxconnections) is now used instead of
- tt(maxclients);
- it() The keyword tt(connectiontimeout) is now used instead of
- tt(sessiontimeout).)
+ it() The keyword tt(maxconnections) is now used instead of
+ tt(maxclients);
+ it() The keyword tt(connectiontimeout) is now used instead of
+ tt(sessiontimeout).)
Therefore when converting configuration files to the new syntax,
the above keywords must be changed. (The reason for these changes
diff --git a/doc/tips.yo b/doc/tips.yo
@@ -39,26 +39,26 @@ itemization(
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.
-
- )
+ 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)
@@ -193,18 +193,18 @@ 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).)
+ 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
@@ -232,16 +232,16 @@ 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 crash.
+ end that was selected at the start of a session. If the back
+ end suddenly goes 'down', then the session will crash.
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.
+ 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.)
+ 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
@@ -257,7 +257,7 @@ follows:
itemization(
it() At the level of a tt(service) description, set the type to
- tt(stickyhttp).
+ tt(http).
it() At the level of each back end description, configure the
tt(stickycookie) and a tt(insertcookie) directives.)
@@ -267,14 +267,14 @@ 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.
+ 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.)
+ established session. Crossroads analyzes the cookie and
+ forwards the request to the appropriate back end.)
Below is a short example of a configuration.
@@ -287,21 +287,97 @@ service www {
backend one {
server 10.1.1.100:80;
- stickycookie XRID=100;
- insertcookie "XRID=100; Path=/";
+ stickycookie XRID=100;
+ insertcookie "XRID=100; Path=/";
}
backend two {
- server 10.1.1.101:80;
- stickycookie XRID=101;
- insertcookie "XRID=101; Path=/";
+ server 10.1.1.101:80;
+ stickycookie XRID=101;
+ insertcookie "XRID=101; Path=/";
}
})
Note how the cookie names and values in the directives
tt(stickycookie) and tt(insertcookie) match. That is obviously a
-prerequisite for stickiness.
-
+prerequisite for stickiness.
+
+
+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, a statement tt(insertrealip on;)
+ must occur.)
+
+After this, HTTP traffic that arrives at the back ends has a new
+header: tt(XR-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;
+ insertrealip on;
+ }
+
+ backend two {
+ server 10.1.1.200:80;
+ insertrealip on;
+ }
+})
+
+
+subsubsect(Sample Apache configuration)
+
+The method by which each back end analyzes the header tt(XR-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(%{XR-Real-IP}i), the desired
+information is sent to the log. Therefore, normally you can simply
+redefine the tt(common) format to
+
+verb(\
+LogFormat "%{XR-Real-IP}i %l %u %t %D \"%r\" %>s %b" common)
+
subsect(Configuration examples)
@@ -461,7 +537,7 @@ itemization(
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
+ 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
diff --git a/doc/using.yo b/doc/using.yo
@@ -9,33 +9,33 @@ 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
- actions that are run from system startup scripts. The
- meaning is self-explanatory.
- it() tt(crossroads restart) is a combination of the former
- two. Beware that a restart may cause discontinuity in
- service; it is just a shorthand for typing the 'stop' and
- 'start' actions after one another.
- it() tt(crossroad status) reports on each running
- service. Per service, the state of each back end is
- reported.
- it() tt(crossroads tell) em(service backend state) is a
- command line way of telling crossroads that a given back
- end, of a given service, is in a given state. Normally
- crossroads maintains state information itself, but by
- using tt(crossroads tell), a back end can be e.g. taken
- 'off line' for servicing.
- it() tt(crossroads configtest) tells you whether the
- configuration is syntactially correct.
- it() tt(crossroads services) reports on the configured
- services. In contrast to tt(crossroads status), this
- option only shows what's configured -- not what's up and
- running. Therefore, tt(crossroads services) doesn't
- report on back end states.
- it() tt(crossroads sampleconf) shows a sample configuration on
- screen. A good way of quicky viewing the configuration
- file syntax, or of getting a start for your own
- configuration tt(/etc/crossroads.conf).
+ it() tt(crossroads start) and tt(crossroads stop) are typical
+ actions that are run from system startup scripts. The
+ meaning is self-explanatory.
+ it() tt(crossroads restart) is a combination of the former
+ two. Beware that a restart may cause discontinuity in
+ service; it is just a shorthand for typing the 'stop' and
+ 'start' actions after one another.
+ it() tt(crossroad status) reports on each running
+ service. Per service, the state of each back end is
+ reported.
+ it() tt(crossroads tell) em(service backend state) is a
+ command line way of telling crossroads that a given back
+ end, of a given service, is in a given state. Normally
+ crossroads maintains state information itself, but by
+ using tt(crossroads tell), a back end can be e.g. taken
+ 'off line' for servicing.
+ it() tt(crossroads configtest) tells you whether the
+ configuration is syntactially correct.
+ it() tt(crossroads services) reports on the configured
+ services. In contrast to tt(crossroads status), this
+ option only shows what's configured -- not what's up and
+ running. Therefore, tt(crossroads services) doesn't
+ report on back end states.
+ it() tt(crossroads sampleconf) shows a sample configuration on
+ 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(Logging-related options)
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.06
+VER = 1.07
# Default config
DEFAULT_CONF = /etc/crossroads.conf
diff --git a/src/crossroads.h b/src/crossroads.h
@@ -73,6 +73,7 @@ typedef enum { /* Config parsing related */
cf_bindspec,
cf_stickycookiespec,
cf_insertcookiespec,
+ cf_insertrealipspec,
} Conftype;
typedef union { /* Integer of string value */
@@ -118,6 +119,7 @@ typedef struct { /* Backend description */
int maxconnections; /* .. max # of allowed connections */
char *stickycookie; /* .. cookie selector */
char *insertcookie; /* .. cookie ID to insert */
+ int insertrealip; /* .. insert real IP (yes/no) */
} Backend;
typedef struct { /* Service description */
@@ -217,6 +219,7 @@ extern void configtest (int ac, char **av);
extern void dealloc_reporter (Service *s);
extern void error (char const *fmt, ...);
extern int fork_tcp_servicer (int to_backend);
+extern int http_09_received (unsigned char const *buf);
extern unsigned char const *http_beyondheaders (unsigned char const *buf,
int buflen);
extern int http_complete (unsigned char const *buf, int buflen);
@@ -224,12 +227,15 @@ extern void http_error (int clientsock);
extern int http_findcookie (unsigned char const *buf, char const *cookie);
extern char *http_headerval (unsigned char const *buf, char const *label);
extern int http_headers_done (unsigned char const *buf);
-extern int http_09_received (unsigned char const *buf);
+extern void http_insert_header (unsigned char **bufp, int *buflenp,
+ char const *header);
extern void http_read (int sock, int isclient, unsigned char **bufp,
int *buflen);
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_realip_header (unsigned char **buf, int *buflen,
+ struct sockaddr_in *client);
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,
diff --git a/src/httpinsertheader.c b/src/httpinsertheader.c
@@ -0,0 +1,50 @@
+#include "crossroads.h"
+
+void http_insert_header (unsigned char **bufp, int *buflen,
+ char const *header) {
+ unsigned char const *buf, *cp;
+ unsigned char *newbuf;
+ char *instruction;
+ int crseen = 0, atend = 0;
+
+ cp = buf = *bufp;
+ msg ("Pasting header '%s' in '%s'", header, buf);
+ while (1) {
+ if (*cp == '\n')
+ cp++;
+ if (! (cp = (unsigned char const *)
+ strchr ( (char const *) cp, '\n')) ) {
+ msg ("Failed to find end of headers while inserting header");
+ return;
+ }
+ cp++;
+
+ if (*cp == '\r') {
+ crseen++;
+ if (*(cp + 1) == '\n')
+ atend++;
+ } else if (*cp == '\n')
+ atend++;
+
+ if (atend) {
+ instruction = str_printf ("%s%s",
+ header,
+ crseen ? "\r\n" : "\n");
+
+ newbuf = xmalloc (*buflen + strlen(instruction) + 1);
+
+ memcpy (newbuf, buf, cp - buf);
+ memcpy (newbuf + (cp - buf), instruction, strlen(instruction));
+ memcpy (newbuf + (cp - buf) + strlen(instruction),
+ cp, *buflen - (cp - buf));
+
+ msg ("Modified buffer: '%s'", newbuf);
+
+ free (*bufp);
+ *bufp = newbuf;
+ *buflen += strlen(instruction);
+
+ return;
+ }
+ }
+}
diff --git a/src/httpserve.c b/src/httpserve.c
@@ -2,7 +2,7 @@
void http_serve (int clientsock, struct sockaddr_in *client) {
unsigned char *firstbuf, *secondbuf;
- int serversock, buflen, is_continuation;
+ int serversock, buflen, is_continuation, is_ready;
/* Fork off a servicer if we're in daemon mode. */
if (fork_tcp_servicer(-1))
@@ -11,13 +11,19 @@ void http_serve (int clientsock, struct sockaddr_in *client) {
/* Get the initial client request, update logs. */
http_read (clientsock, 1, &firstbuf, &buflen);
- /* Determine the back end and send the initial client request. */
+ /* Determine the back, maybe a fresh one, or a session continuation. */
if ( (serversock = http_serversocket (firstbuf, &is_continuation)) < 1 )
http_error (clientsock);
+ /* Stick in a real-IP header if required. */
+ msg ("pasting - current_backend: %d, insertrealip: %d",
+ current_backend,
+ activeservice->backend[current_backend].insertrealip);
+ if (activeservice->backend[current_backend].insertrealip)
+ http_set_realip_header (&firstbuf, &buflen, client);
+
/* Log what's going on. We only log the continuation here,
- * because copysockets below will handle the start/end.
- */
+ * because copysockets below will handle the start/end. */
if (is_continuation)
log_activity_continuation (client);
@@ -29,23 +35,26 @@ void http_serve (int clientsock, struct sockaddr_in *client) {
free (firstbuf);
/* If we have a sticky cookie to insert:
- * Get the server response, stick in the cookie, send it to the
+ * Get the server response, stick in a session cookie, send it to the
* client. */
+ is_ready = 0;
if (activeservice->backend[current_backend].insertcookie) {
msg ("Getting server response");
http_read (serversock, 0, &secondbuf, &buflen);
http_set_sticky_cookie (&secondbuf, &buflen);
if (http_write (clientsock, secondbuf, buflen))
error ("Failed to send data to client");
+ if (http_complete (secondbuf, buflen)) {
+ mark_activity (0, 0, st_available);
+ is_ready = 1;
+ }
+ free (secondbuf);
}
/* Now we might have to piggyback to and fro -- tho only if the
* HTTP chat wasn't done yet. */
- if (http_complete (secondbuf, buflen))
- mark_activity (0, 0, st_available);
- else
+ if (!is_ready)
copysockets (clientsock, serversock, client);
- free (secondbuf);
/* Normal shutdown: TCP traffic done. */
msg ("Normal HTTP stop.");
diff --git a/src/httpsetrealipheader.c b/src/httpsetrealipheader.c
@@ -0,0 +1,10 @@
+#include "crossroads.h"
+
+void http_set_realip_header (unsigned char **bufp, int *buflenp,
+ struct sockaddr_in *client) {
+ char *header;
+
+ header = str_printf ("XR-Real-IP: %s", inet_ntoa (client->sin_addr));
+ http_insert_header (bufp, buflenp, header);
+ free (header);
+}
diff --git a/src/httpsetstickycookie.c b/src/httpsetstickycookie.c
@@ -1,51 +1,10 @@
#include "crossroads.h"
-void http_set_sticky_cookie (unsigned char **bufp, int *buflen) {
- char
- *cookieval = activeservice->backend[current_backend].insertcookie,
- *instruction;
- unsigned char const *buf, *cp;
- unsigned char *newbuf;
- int crseen = 0, atend = 0;
+void http_set_sticky_cookie (unsigned char **bufp, int *buflenp) {
+ char *header;
- cp = buf = *bufp;
- msg ("Pasting cookie '%s' in '%s'", cookieval, buf);
- while (1) {
- if (*cp == '\n')
- cp++;
- if (! (cp = (unsigned char const *)
- strchr ( (char const *) cp, '\n')) ) {
- msg ("Failed to find end of headers while inserting cookie");
- return;
- }
- cp++;
-
- if (*cp == '\r') {
- crseen++;
- if (*(cp + 1) == '\n')
- atend++;
- } else if (*cp == '\n')
- atend++;
-
- if (atend) {
- instruction = str_printf ("Set-Cookie: %s%s",
- cookieval,
- crseen ? "\r\n" : "\n");
-
- newbuf = xmalloc (*buflen + strlen(instruction) + 1);
-
- memcpy (newbuf, buf, cp - buf);
- memcpy (newbuf + (cp - buf), instruction, strlen(instruction));
- memcpy (newbuf + (cp - buf) + strlen(instruction),
- cp, *buflen - (cp - buf));
-
- msg ("Modified buffer: '%s'", newbuf);
-
- free (*bufp);
- *bufp = newbuf;
- *buflen += strlen(instruction);
-
- return;
- }
- }
+ header = str_printf ("Set-Cookie: %s",
+ activeservice->backend[current_backend].insertcookie);
+ http_insert_header (bufp, buflenp, header);
+ free (header);
}
diff --git a/src/lexer.l b/src/lexer.l
@@ -133,8 +133,15 @@ any {
return (ANY);
}
stickyhttp {
- lmsg ("sticky http");
- return (STICKYHTTP);
+ lmsg ("stickyhttp");
+ warning ("The 'stickyhttp protocol "
+ "is obsolte.\n"
+ "You should change to 'http'.");
+ return (HTTP);
+ }
+http {
+ lmsg ("http");
+ return (HTTP);
}
throughputlog {
lmsg ("throughputlog");
@@ -155,7 +162,7 @@ dumptraffic {
warning ("The 'dumptraffic' statement "
"is obsolete.\n"
"You should change to "
- "'trafficlog'.\n");
+ "'trafficlog'.");
BEGIN (stringstate);
free (laststring);
laststring = 0;
@@ -174,20 +181,24 @@ onfailure {
free (laststring);
laststring = 0;
return (ONFAILURE);
- }
+ }
stickycookie {
lmsg ("stickycookie");
BEGIN (stringstate);
free (laststring);
laststring = 0;
return (STICKYCOOKIE);
- }
+ }
insertcookie {
lmsg ("insertcookie");
BEGIN (stringstate);
free (laststring);
laststring = 0;
return (INSERTCOOKIE);
+ }
+insertrealip {
+ lmsg ("insertrealip");
+ return (INSERTREALIP);
}
on|true|yes {
lmsg ("on");
@@ -227,7 +238,7 @@ off|false|no {
<commentstate>\n {
yylineno++;
}
-<commentstate>. ;
+<commentstate>. ;
<stringstate>\"[^\"]*\" {
llmsg ("string part", yytext);
diff --git a/src/main.c b/src/main.c
@@ -44,7 +44,6 @@ int main (int argc, char **argv) {
{ "tell", 3, 1, tell_service },
{ "configtest", 0, 1, configtest },
};
- struct passwd *passwd;
/* Remember original ac/av/ep */
org_argc = argc;
diff --git a/src/parser.y b/src/parser.y
@@ -79,14 +79,14 @@ static Service cur_service; /* Storage for a handled service */
ON OFF DISPATCHMODE ROUNDROBIN REVIVINGINTERVAL SHMKEY WEIGHT
ONSUCCESS ONFAILURE STRING BACKLOG RANDOM BYDURATION BYSIZE
BYCONNECTIONS CONNECTIONTIMEOUT MAXCONNECTIONS BYORDER TRAFFICLOG
- OVER DECAY BINDTO THROUGHPUTLOG TYPE ANY STICKYHTTP
- STICKYCOOKIE INSERTCOOKIE
+ OVER DECAY BINDTO THROUGHPUTLOG TYPE ANY HTTP
+ STICKYCOOKIE INSERTCOOKIE INSERTREALIP
%%
/* Config file grammar rules */
input:
- element
+ element
input
|
element
@@ -98,26 +98,26 @@ element:
'{'
servicestatements
'}' {
- /* Verify the service description, supply defaults
- * and so on.
- */
- if (!cur_service.port)
- error ("Service %s lacks a port",
- cur_service.name);
- if (!cur_service.nbackend)
- error ("Service %s lacks back ends",
- cur_service.name);
+ /* Verify the service description, supply defaults
+ * and so on.
+ */
+ if (!cur_service.port)
+ error ("Service %s lacks a port",
+ cur_service.name);
+ if (!cur_service.nbackend)
+ error ("Service %s lacks back ends",
+ cur_service.name);
- if (!cur_service.shmkey)
- cur_service.shmkey = cur_service.port | SHM_MASK;
+ if (!cur_service.shmkey)
+ cur_service.shmkey = cur_service.port | SHM_MASK;
- if (!cur_service.bind)
- cur_service.bind = "any";
+ if (!cur_service.bind)
+ cur_service.bind = "any";
- /* Add to the list. */
- service = xrealloc (service, ++nservice * sizeof(Service));
- service[nservice - 1] = cur_service;
- memset (&cur_service, 0, sizeof(Service));
+ /* Add to the list. */
+ service = xrealloc (service, ++nservice * sizeof(Service));
+ service[nservice - 1] = cur_service;
+ memset (&cur_service, 0, sizeof(Service));
}
;
@@ -129,8 +129,8 @@ service:
servicename:
servicename_expected
IDENTIFIER {
- psmsg ("service:", yytext);
- cur_service.name = xstrdup(yytext);
+ psmsg ("service:", yytext);
+ cur_service.name = xstrdup(yytext);
}
;
@@ -148,150 +148,155 @@ servicestatement:
servicebody:
portstatement {
- pimsg ("sevice port:", $1.set[0].v.ival);
- cur_service.port = $1.set[0].v.ival;
- free ($1.set);
+ pimsg ("sevice port:", $1.set[0].v.ival);
+ cur_service.port = $1.set[0].v.ival;
+ free ($1.set);
}
|
bindstatement {
- psmsg ("service binding:", $1.set[0].v.sval);
- cur_service.bind = $1.set[0].v.sval;
- free ($1.set);
+ psmsg ("service binding:", $1.set[0].v.sval);
+ cur_service.bind = $1.set[0].v.sval;
+ free ($1.set);
}
|
verbositystatement {
- pimsg ("service verbosity:", $1.set[0].v.ival);
- cur_service.verbosity = $1.set[0].v.ival;
- free ($1.set);
+ pimsg ("service verbosity:", $1.set[0].v.ival);
+ cur_service.verbosity = $1.set[0].v.ival;
+ free ($1.set);
}
|
dispatchmodestatement {
- pimsg ("service dispatch mode:", $1.set[0].v.ival);
- pimsg ("service dispatch over:", lastovernr);
- cur_service.dispatchtype = $1.set[0].v.ival;
- cur_service.dispatchover = lastovernr;
- free ($1.set);
+ pimsg ("service dispatch mode:", $1.set[0].v.ival);
+ pimsg ("service dispatch over:", lastovernr);
+ cur_service.dispatchtype = $1.set[0].v.ival;
+ cur_service.dispatchover = lastovernr;
+ free ($1.set);
}
|
revivingintervalstatement {
- pimsg ("service revival interval:", $1.set[0].v.ival);
- cur_service.rev_interval = $1.set[0].v.ival;
- free ($1.set);
+ pimsg ("service revival interval:", $1.set[0].v.ival);
+ cur_service.rev_interval = $1.set[0].v.ival;
+ free ($1.set);
}
|
backlogstatement {
- pimsg ("service backlog:", $1.set[0].v.ival);
- cur_service.backlog = $1.set[0].v.ival;
- free ($1.set);
+ pimsg ("service backlog:", $1.set[0].v.ival);
+ cur_service.backlog = $1.set[0].v.ival;
+ free ($1.set);
}
|
shmkeystatement {
- pimsg ("service shmkey:", $1.set[0].v.ival);
- cur_service.shmkey = $1.set[0].v.ival;
- free ($1.set);
+ pimsg ("service shmkey:", $1.set[0].v.ival);
+ cur_service.shmkey = $1.set[0].v.ival;
+ free ($1.set);
}
|
connectiontimeoutstatement {
- pimsg ("connection timout:", $1.set[0].v.ival);
- cur_service.connectiontimeout = $1.set[0].v.ival;
- free ($1.set);
+ pimsg ("connection timout:", $1.set[0].v.ival);
+ cur_service.connectiontimeout = $1.set[0].v.ival;
+ free ($1.set);
}
|
maxconnectionsstatement {
- pimsg ("max clients in service:", $1.set[0].v.ival);
- cur_service.maxconnections = $1.set[0].v.ival;
- free ($1.set);
+ pimsg ("max clients in service:", $1.set[0].v.ival);
+ cur_service.maxconnections = $1.set[0].v.ival;
+ free ($1.set);
}
|
typestatement {
- pimsg ("service type: ", $1.set[0].v.ival);
- cur_service.type = $1.set[0].v.ival;
- free ($1.set);
+ pimsg ("service type: ", $1.set[0].v.ival);
+ cur_service.type = $1.set[0].v.ival;
+ free ($1.set);
}
|
backendblock {
- pimsg ("converting backend statements, count is", $1.n);
- for (i = 0; i < $1.n; i++)
- switch ($1.set[i].cf) {
- case cf_portspec:
- pimsg ("backend block port:", $1.set[i].v.ival);
- cur_backend.port = $1.set[i].v.ival;
- break;
- case cf_serverspec:
- psmsg ("backend block server:", $1.set[i].v.sval);
- cur_backend.server = serverpart ($1.set[i].v.sval);
- cur_backend.port = portpart ($1.set[i].v.sval);
- free ($1.set[i].v.sval);
- break;
- case cf_verbosityspec:
- pimsg ("backend block verbosity:", $1.set[i].v.ival);
- cur_backend.verbosity = $1.set[i].v.ival;
- break;
- case cf_onsuccspec:
- psmsg ("backend block onsuccess:", $1.set[i].v.sval);
- cur_backend.onsuccess = $1.set[i].v.sval;
- break;
- case cf_onfailspec:
- psmsg ("backend block onfailure:", $1.set[i].v.sval);
- cur_backend.onfailure = $1.set[i].v.sval;
- break;
- case cf_dumpspec:
- psmsg ("backend trafficlog:", $1.set[i].v.sval);
- cur_backend.dumpfile = $1.set[i].v.sval;
- break;
- case cf_thruspec:
- psmsg ("backend throughputlog:", $1.set[i].v.sval);
- cur_backend.thruputfile = $1.set[i].v.sval;
- break;
- case cf_weightspec:
- pimsg ("backend weight:", $1.set[i].v.ival);
- cur_backend.weight = $1.set[i].v.ival;
- break;
- case cf_decayspec:
- pimsg ("backend decay:", $1.set[i].v.ival);
- if ($1.set[i].v.ival >= 100)
- error ("Decay specifier %d must be a percentage, "
- "never more than 99",
- $1.set[i].v.ival);
- cur_backend.decay = $1.set[i].v.ival;
- break;
- case cf_maxconnectionsspec:
- pimsg ("backend max clients: ", $1.set[i].v.ival);
- cur_backend.maxconnections = $1.set[i].v.ival;
- break;
- case cf_insertcookiespec:
- psmsg ("backend cookie to insert:",
- $1.set[i].v.sval);
- cur_backend.insertcookie = $1.set[i].v.sval;
- break;
- case cf_stickycookiespec:
- psmsg ("backend sticky cookie:",
- $1.set[i].v.sval);
- cur_backend.stickycookie = $1.set[i].v.sval;
- break;
- default:
- error ("Internal jam, unhandled type %d "
- "in backend specification",
- $1.set[i].cf);
- }
- free ($1.set);
- /* Verify the backend block, supply defaults,
- * And so on.
- */
- if (!cur_service.port)
- error ("Back end %s lacks port",
- cur_service.port);
- if (!cur_backend.weight)
- cur_backend.weight = 1;
-
- /* Add to the list. */
- cur_service.backend = xrealloc (cur_service.backend,
- ++cur_service.nbackend *
- sizeof(Service));
- cur_service.backend[cur_service.nbackend - 1] =
- cur_backend;
- pimsg ("this was backend defintion", cur_service.nbackend);
- memset (&cur_backend, 0, sizeof(cur_backend));
+ pimsg ("converting backend statements, count is", $1.n);
+ for (i = 0; i < $1.n; i++)
+ switch ($1.set[i].cf) {
+ case cf_portspec:
+ pimsg ("backend block port:", $1.set[i].v.ival);
+ cur_backend.port = $1.set[i].v.ival;
+ break;
+ case cf_serverspec:
+ psmsg ("backend block server:", $1.set[i].v.sval);
+ cur_backend.server = serverpart ($1.set[i].v.sval);
+ cur_backend.port = portpart ($1.set[i].v.sval);
+ free ($1.set[i].v.sval);
+ break;
+ case cf_verbosityspec:
+ pimsg ("backend block verbosity:", $1.set[i].v.ival);
+ cur_backend.verbosity = $1.set[i].v.ival;
+ break;
+ case cf_onsuccspec:
+ psmsg ("backend block onsuccess:", $1.set[i].v.sval);
+ cur_backend.onsuccess = $1.set[i].v.sval;
+ break;
+ case cf_onfailspec:
+ psmsg ("backend block onfailure:", $1.set[i].v.sval);
+ cur_backend.onfailure = $1.set[i].v.sval;
+ break;
+ case cf_dumpspec:
+ psmsg ("backend trafficlog:", $1.set[i].v.sval);
+ cur_backend.dumpfile = $1.set[i].v.sval;
+ break;
+ case cf_thruspec:
+ psmsg ("backend throughputlog:", $1.set[i].v.sval);
+ cur_backend.thruputfile = $1.set[i].v.sval;
+ break;
+ case cf_weightspec:
+ pimsg ("backend weight:", $1.set[i].v.ival);
+ cur_backend.weight = $1.set[i].v.ival;
+ break;
+ case cf_decayspec:
+ pimsg ("backend decay:", $1.set[i].v.ival);
+ if ($1.set[i].v.ival >= 100)
+ error ("Decay specifier %d must be a percentage, "
+ "never more than 99",
+ $1.set[i].v.ival);
+ cur_backend.decay = $1.set[i].v.ival;
+ break;
+ case cf_maxconnectionsspec:
+ pimsg ("backend max clients: ", $1.set[i].v.ival);
+ cur_backend.maxconnections = $1.set[i].v.ival;
+ break;
+ case cf_insertrealipspec:
+ pimsg ("backend real IP to insert:",
+ $1.set[i].v.ival);
+ cur_backend.insertrealip = $1.set[i].v.ival;
+ break;
+ case cf_insertcookiespec:
+ psmsg ("backend cookie to insert:",
+ $1.set[i].v.sval);
+ cur_backend.insertcookie = $1.set[i].v.sval;
+ break;
+ case cf_stickycookiespec:
+ psmsg ("backend sticky cookie:",
+ $1.set[i].v.sval);
+ cur_backend.stickycookie = $1.set[i].v.sval;
+ break;
+ default:
+ error ("Internal jam, unhandled type %d "
+ "in backend specification",
+ $1.set[i].cf);
+ }
+ free ($1.set);
+ /* Verify the backend block, supply defaults,
+ * And so on.
+ */
+ if (!cur_service.port)
+ error ("Back end %s lacks port",
+ cur_service.port);
+ if (!cur_backend.weight)
+ cur_backend.weight = 1;
+
+ /* Add to the list. */
+ cur_service.backend = xrealloc (cur_service.backend,
+ ++cur_service.nbackend *
+ sizeof(Service));
+ cur_service.backend[cur_service.nbackend - 1] =
+ cur_backend;
+ pimsg ("this was backend defintion", cur_service.nbackend);
+ memset (&cur_backend, 0, sizeof(cur_backend));
}
;
@@ -299,11 +304,11 @@ portstatement:
PORT
number
semicol {
- pimsg ("port statement:", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_portspec;
- $$.set[0].v.ival = lastnr;
+ pimsg ("port statement:", lastnr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof(Confset));
+ $$.set[0].cf = cf_portspec;
+ $$.set[0].v.ival = lastnr;
}
;
@@ -311,27 +316,27 @@ bindstatement:
BINDTO
ipaddress
semicol {
- psmsg ("bindto statement:", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_bindspec;
- $$.set[0].v.sval = xstrdup(laststr);
+ psmsg ("bindto statement:", laststr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof(Confset));
+ $$.set[0].cf = cf_bindspec;
+ $$.set[0].v.sval = xstrdup(laststr);
}
;
ipaddress:
ipaddress_expected
STRING {
- setlaststr (laststring);
- free (laststring);
- laststring = 0;
+ setlaststr (laststring);
+ free (laststring);
+ laststring = 0;
}
;
number:
number_expected
NUMBER {
- setlastnr (yytext);
+ setlastnr (yytext);
}
;
@@ -345,21 +350,21 @@ verbositystatement:
onoff_expected
onoff
semicol {
- pimsg ("verbosity statement:", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_verbosityspec;
- $$.set[0].v.ival = lastnr;
+ pimsg ("verbosity statement:", lastnr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof(Confset));
+ $$.set[0].cf = cf_verbosityspec;
+ $$.set[0].v.ival = lastnr;
}
;
onoff:
ON {
- lastnr = 1;
+ lastnr = 1;
}
|
OFF {
- lastnr = 0;
+ lastnr = 0;
}
;
@@ -368,17 +373,17 @@ dispatchmodestatement:
dispatchmethod
opt_over
semicol {
- pimsg ("dispatch mode statement:", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_dispatchspec;
- $$.set[0].v.ival = lastnr;
+ pimsg ("dispatch mode statement:", lastnr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof(Confset));
+ $$.set[0].cf = cf_dispatchspec;
+ $$.set[0].v.ival = lastnr;
- if (lastovernr &&
- (lastnr != ds_bysize && lastnr != ds_byduration))
- error ("Service '%s': this dispatch mode "
- "doesn't support 'over <connections>'",
- cur_service.name);
+ if (lastovernr &&
+ (lastnr != ds_bysize && lastnr != ds_byduration))
+ error ("Service '%s': this dispatch mode "
+ "doesn't support 'over <connections>'",
+ cur_service.name);
}
;
@@ -387,14 +392,14 @@ opt_over:
overnumber
|
/* empty */ {
- lastovernr = 0;
+ lastovernr = 0;
}
;
overnumber:
number_expected
NUMBER {
- setlastovernr (yytext);
+ setlastovernr (yytext);
}
;
@@ -405,27 +410,27 @@ dispatchmethod:
dispatchmethodspec:
ROUNDROBIN {
- lastnr = ds_roundrobin;
+ lastnr = ds_roundrobin;
}
|
RANDOM {
- lastnr = ds_random;
+ lastnr = ds_random;
}
|
BYDURATION {
- lastnr = ds_byduration;
+ lastnr = ds_byduration;
}
|
BYSIZE {
- lastnr = ds_bysize;
+ lastnr = ds_bysize;
}
|
BYORDER {
- lastnr = ds_byorder;
+ lastnr = ds_byorder;
}
|
BYCONNECTIONS {
- lastnr = ds_byconnections;
+ lastnr = ds_byconnections;
}
;
@@ -433,11 +438,11 @@ revivingintervalstatement:
REVIVINGINTERVAL
number
semicol {
- pimsg ("reviving interval statement:", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_revivespec;
- $$.set[0].v.ival = lastnr;
+ pimsg ("reviving interval statement:", lastnr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof(Confset));
+ $$.set[0].cf = cf_revivespec;
+ $$.set[0].v.ival = lastnr;
}
;
@@ -445,11 +450,11 @@ backlogstatement:
BACKLOG
number
semicol {
- pimsg ("backlog statement:", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_revivespec;
- $$.set[0].v.ival = lastnr;
+ pimsg ("backlog statement:", lastnr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof(Confset));
+ $$.set[0].cf = cf_revivespec;
+ $$.set[0].v.ival = lastnr;
}
;
@@ -457,11 +462,11 @@ shmkeystatement:
SHMKEY
number
semicol {
- pimsg ("shmkey statement:", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_shmkeyspec;
- $$.set[0].v.ival = lastnr;
+ pimsg ("shmkey statement:", lastnr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof(Confset));
+ $$.set[0].cf = cf_shmkeyspec;
+ $$.set[0].v.ival = lastnr;
}
;
@@ -469,11 +474,11 @@ connectiontimeoutstatement:
CONNECTIONTIMEOUT
number
semicol {
- pimsg ("connection timeout statement:", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_connectiontimeoutspec;
- $$.set[0].v.ival = lastnr;
+ pimsg ("connection timeout statement:", lastnr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof(Confset));
+ $$.set[0].cf = cf_connectiontimeoutspec;
+ $$.set[0].v.ival = lastnr;
}
;
@@ -481,11 +486,11 @@ maxconnectionsstatement:
MAXCONNECTIONS
number
semicol {
- pimsg ("max clients statement (service):", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_maxconnectionsspec;
- $$.set[0].v.ival = lastnr;
+ pimsg ("max clients statement (service):", lastnr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof(Confset));
+ $$.set[0].cf = cf_maxconnectionsspec;
+ $$.set[0].v.ival = lastnr;
}
;
@@ -493,11 +498,11 @@ typestatement:
TYPE
typespec
semicol {
- pimsg ("service type:", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_typespec;
- $$.set[0].v.ival = lastnr;
+ pimsg ("service type:", lastnr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof(Confset));
+ $$.set[0].cf = cf_typespec;
+ $$.set[0].v.ival = lastnr;
}
;
@@ -508,11 +513,11 @@ typespec:
typespecifier:
ANY {
- lastnr = type_any;
+ lastnr = type_any;
}
|
- STICKYHTTP {
- lastnr = type_http;
+ HTTP {
+ lastnr = type_http;
}
;
@@ -522,98 +527,103 @@ backendblock:
'{'
backenddefinitions
'}' {
- $$ = $4;
+ $$ = $4;
}
;
backendname:
backendname_expected
IDENTIFIER {
- psmsg ("backend name:", laststr);
- cur_backend.name = xstrdup (yytext);
+ psmsg ("backend name:", laststr);
+ cur_backend.name = xstrdup (yytext);
}
;
backenddefinitions:
backenddefinitions
backenddefinition {
- $1.n++;
- $1.set = xrealloc ($1.set, $1.n * sizeof(Confset));
- $1.set[$1.n - 1] = $2.set[0];
- $$ = $1;
+ $1.n++;
+ $1.set = xrealloc ($1.set, $1.n * sizeof(Confset));
+ $1.set[$1.n - 1] = $2.set[0];
+ $$ = $1;
}
|
backenddefinition {
- $$ = $1;
+ $$ = $1;
}
;
backenddefinition:
backendstatement_expected
backendstatement {
- $$ = $2;
+ $$ = $2;
}
;
backendstatement:
serverstatement {
- psmsg ("backend server:", $1.set[0].v.sval);
- $$ = $1;
- }
+ psmsg ("backend server:", $1.set[0].v.sval);
+ $$ = $1;
+ }
|
portstatement {
- pimsg ("backend port:", $1.set[0].v.ival);
- $$ = $1;
+ pimsg ("backend port:", $1.set[0].v.ival);
+ $$ = $1;
}
|
verbositystatement {
- pimsg ("backend verbosity:", $1.set[0].v.ival);
- $$ = $1;
+ pimsg ("backend verbosity:", $1.set[0].v.ival);
+ $$ = $1;
}
|
onsuccessstatement {
- psmsg ("backend onsuccess:", $1.set[0].v.sval);
- $$ = $1;
+ psmsg ("backend onsuccess:", $1.set[0].v.sval);
+ $$ = $1;
}
|
onfailurestatement {
- psmsg ("backend onfailure:", $1.set[0].v.sval);
- $$ = $1;
+ psmsg ("backend onfailure:", $1.set[0].v.sval);
+ $$ = $1;
}
|
dumptrafficstatement {
- psmsg ("backend trafficlog:", $1.set[0].v.sval);
- $$ = $1;
+ psmsg ("backend trafficlog:", $1.set[0].v.sval);
+ $$ = $1;
}
|
throughputstatement {
- psmsg ("backend trafficlog:", $1.set[0].v.sval);
- $$ = $1;
+ psmsg ("backend trafficlog:", $1.set[0].v.sval);
+ $$ = $1;
}
|
weightstatement {
- pimsg ("backend weight:", $1.set[0].v.ival);
- $$ = $1;
+ pimsg ("backend weight:", $1.set[0].v.ival);
+ $$ = $1;
}
|
decaystatement {
- pimsg ("backend decay:", $1.set[0].v.ival);
- $$ = $1;
+ pimsg ("backend decay:", $1.set[0].v.ival);
+ $$ = $1;
}
|
maxconnectionsstatement {
- pimsg ("backend maxconnections:", $1.set[0].v.ival);
- $$ = $1;
+ pimsg ("backend maxconnections:", $1.set[0].v.ival);
+ $$ = $1;
}
|
stickycookiestatement {
- psmsg ("backend sticky cookie:", $1.set[0].v.sval);
- $$ = $1;
+ psmsg ("backend sticky cookie:", $1.set[0].v.sval);
+ $$ = $1;
}
|
insertcookiestatement {
- psmsg ("backend cookie insertion:", $1.set[0].v.sval);
- $$ = $1;
+ psmsg ("backend cookie insertion:", $1.set[0].v.sval);
+ $$ = $1;
+ }
+|
+ insertrealipstatement {
+ pimsg ("insert real ip:", $1.set[0].v.ival);
+ $$ = $1;
}
;
@@ -622,11 +632,11 @@ serverstatement:
serveraddress_expected
serveraddress
semicol {
- psmsg ("server statement:", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_serverspec;
- $$.set[0].v.sval = xstrdup (laststr);
+ psmsg ("server statement:", laststr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof (Confset));
+ $$.set[0].cf = cf_serverspec;
+ $$.set[0].v.sval = xstrdup (laststr);
}
;
@@ -634,11 +644,11 @@ weightstatement:
WEIGHT
number
semicol {
- pimsg ("weight statement", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_weightspec;
- $$.set[0].v.ival = lastnr;
+ pimsg ("weight statement", lastnr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof (Confset));
+ $$.set[0].cf = cf_weightspec;
+ $$.set[0].v.ival = lastnr;
}
;
@@ -646,17 +656,17 @@ decaystatement:
DECAY
number
semicol {
- pimsg ("decay statement", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_decayspec;
- $$.set[0].v.ival = lastnr;
+ pimsg ("decay statement", lastnr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof (Confset));
+ $$.set[0].cf = cf_decayspec;
+ $$.set[0].v.ival = lastnr;
}
;
serveraddress:
STRING {
- setlaststr (laststring);
+ setlaststr (laststring);
}
;
@@ -664,11 +674,11 @@ onsuccessstatement:
ONSUCCESS
commandline
semicol {
- psmsg ("onsuccess statement:", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_onsuccspec;
- $$.set[0].v.sval = xstrdup (laststr);
+ psmsg ("onsuccess statement:", laststr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof (Confset));
+ $$.set[0].cf = cf_onsuccspec;
+ $$.set[0].v.sval = xstrdup (laststr);
}
;
@@ -676,11 +686,11 @@ onfailurestatement:
ONFAILURE
commandline
semicol {
- psmsg ("onfailure statement:", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_onfailspec;
- $$.set[0].v.sval = xstrdup (laststr);
+ psmsg ("onfailure statement:", laststr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof (Confset));
+ $$.set[0].cf = cf_onfailspec;
+ $$.set[0].v.sval = xstrdup (laststr);
}
;
@@ -688,11 +698,11 @@ dumptrafficstatement:
TRAFFICLOG
filename
semicol {
- psmsg ("trafficlog statement:", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_dumpspec;
- $$.set[0].v.sval = xstrdup (laststr);
+ psmsg ("trafficlog statement:", laststr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof (Confset));
+ $$.set[0].cf = cf_dumpspec;
+ $$.set[0].v.sval = xstrdup (laststr);
}
;
@@ -700,29 +710,29 @@ throughputstatement:
THROUGHPUTLOG
filename
semicol {
- psmsg ("throughputlog statement:", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_thruspec;
- $$.set[0].v.sval = xstrdup (laststr);
+ psmsg ("throughputlog statement:", laststr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof (Confset));
+ $$.set[0].cf = cf_thruspec;
+ $$.set[0].v.sval = xstrdup (laststr);
}
;
commandline:
commandline_expected
STRING {
- setlaststr (laststring);
- free (laststring);
- laststring = 0;
+ setlaststr (laststring);
+ free (laststring);
+ laststring = 0;
}
;
filename:
filename_expected
STRING {
- setlaststr (laststring);
- free (laststring);
- laststring = 0;
+ setlaststr (laststring);
+ free (laststring);
+ laststring = 0;
}
;
@@ -730,11 +740,11 @@ stickycookiestatement:
STICKYCOOKIE
cookiespecifier
semicol {
- psmsg ("insertcookie statement:", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_stickycookiespec;
- $$.set[0].v.sval = xstrdup (laststr);
+ psmsg ("insertcookie statement:", laststr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof (Confset));
+ $$.set[0].cf = cf_stickycookiespec;
+ $$.set[0].v.sval = xstrdup (laststr);
}
;
@@ -742,14 +752,28 @@ insertcookiestatement:
INSERTCOOKIE
cookiespecifier
semicol {
- psmsg ("insertcookie statement:", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_insertcookiespec;
- $$.set[0].v.sval = xstrdup (laststr);
+ psmsg ("insertcookie statement:", laststr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof (Confset));
+ $$.set[0].cf = cf_insertcookiespec;
+ $$.set[0].v.sval = xstrdup (laststr);
+ }
+;
+
+insertrealipstatement:
+ INSERTREALIP
+ onoff_expected
+ onoff
+ semicol {
+ pimsg ("insert real IP statement: ", lastnr);
+ $$.n = 1;
+ $$.set = xmalloc (sizeof(Confset));
+ $$.set[0].cf = cf_insertrealipspec;
+ $$.set[0].v.ival = lastnr;
}
;
+
cookiespecifier:
cookie_expected
STRING {
@@ -760,76 +784,76 @@ cookiespecifier:
;
cookie_expected: {
- yyerrmsg = "cookie specifier expected";
- }
+ yyerrmsg = "cookie specifier expected";
+}
;
number_expected: {
- yyerrmsg = "number expected";
- }
+ yyerrmsg = "number expected";
+}
;
serveraddress_expected: {
- yyerrmsg = "hostname or IP address expected";
- }
+ yyerrmsg = "hostname or IP address expected";
+}
;
service_expected: {
- yyerrmsg = "'service' expected";
- }
+ yyerrmsg = "'service' expected";
+}
;
backendstatement_expected: {
- yyerrmsg = "backend definition statement expected";
- }
+ yyerrmsg = "backend definition statement expected";
+}
;
servicebody_expected: {
- yyerrmsg = "service body statement expected";
- }
+ yyerrmsg = "service body statement expected";
+}
;
semicol_expected: {
- yyerrmsg = "semicolon (;) expected";
- }
+ yyerrmsg = "semicolon (;) expected";
+}
;
onoff_expected: {
- yyerrmsg = "'on' or 'off' expetcted";
- }
+ yyerrmsg = "'on' or 'off' expetcted";
+}
;
dispatchmethod_expected: {
- yyerrmsg = "dispatch method expected";
- }
+ yyerrmsg = "dispatch method expected";
+}
;
commandline_expected: {
- yyerrmsg = "command line expected";
- }
+ yyerrmsg = "command line expected";
+}
;
filename_expected: {
- yyerrmsg = "file name expected";
- }
+ yyerrmsg = "file name expected";
+}
;
servicename_expected: {
- yyerrmsg = "service name (identifier) expected";
- }
+ yyerrmsg = "service name (identifier) expected";
+}
;
backendname_expected: {
- yyerrmsg = "backend name (identifier) expected";
- }
+ yyerrmsg = "backend name (identifier) expected";
+}
;
ipaddress_expected: {
- yyerrmsg = "IP address or 'any' expected";
- }
+ yyerrmsg = "IP address or 'any' expected";
+}
;
type_expected: {
- yyerrmsg = "Service type expected ('any', 'stickyhttp', ...)";
- }
+ yyerrmsg = "Service type expected ('any', 'stickyhttp', ...)";
+}
;
diff --git a/test/client b/test/client
@@ -14,7 +14,7 @@ ENDUSAGE
my ($host, $port) = @ARGV;
print ("Starting client loop to query $host:$port.. press ^C to stop\n");
-sleep (1);
+select (undef, undef, undef, 0.2);
my %hits = (a => 0, b => 0, c => 0, unknown => 0, errors => 0);
@@ -25,7 +25,7 @@ while (1) {
$err = 1;
while (my $msg = <$if>) {
chomp ($msg);
- # print ("Server says: [$msg]\n");
+ # print ("Server says: [$msg]\n");
if ($msg =~ /HTTP.*200 OK/ or $msg =~ /Hello World/) {
$err = 0;
} elsif ($msg =~ /Backend_A/) {
@@ -51,6 +51,5 @@ while (1) {
}
print ("\n");
- # sleep (1);
select (undef, undef, undef, 0.2);
};
diff --git a/test/server b/test/server
@@ -34,14 +34,19 @@ sub handleconnection () {
}
# Child branch
- select Client;
- $| = 1;
+ while (defined (my $line = <Client>)) {
+ chomp ($line);
+ $line =~ s/\r//;
+ last if ($line eq '');
+ msg ("Client says: [$line]\n");
+ }
+ msg ("Sending response\n");
my $msg = "Hello World!\n";
- print ("HTTP/1.0 200 OK\r\n",
- "Content-length: ", length($msg), "\r\n",
- "\r\n",
- $msg);
+ print Client ("HTTP/1.0 200 OK\r\n",
+ "Content-length: ", length($msg), "\r\n",
+ "\r\n",
+ $msg);
exit (0);
}
diff --git a/test/t1.conf b/test/t1.conf
@@ -1,6 +1,6 @@
service test {
port 10001;
- type stickyhttp;
+ type http;
bindto any;
revivinginterval 5;
dispatchmode bysize;
diff --git a/test/t2.conf b/test/t2.conf
@@ -1,6 +1,6 @@
service test {
port 10001;
- type stickyhttp;
+ type http;
bindto any;
revivinginterval 5;
dispatchmode random;
diff --git a/test/t4.conf b/test/t4.conf
@@ -0,0 +1,35 @@
+service test {
+ port 10001;
+ type http;
+ revivinginterval 5;
+ dispatchmode roundrobin;
+ connectiontimeout 600;
+ verbosity on;
+
+ backend a {
+ server localhost;
+ port 10000;
+ verbosity on;
+ stickycookie BalancerID=Backend_A;
+ insertcookie "BalancerID=Backend_A; Path=/";
+ insertrealip on;
+ }
+
+ backend b {
+ server localhost;
+ port 10000;
+ verbosity on;
+ stickycookie BalancerID=Backend_B;
+ insertcookie "BalancerID=Backend_B; Path=/";
+ insertrealip on;
+ }
+
+ backend c {
+ server localhost;
+ port 10000;
+ verbosity on;
+ stickycookie BalancerID=Backend_C;
+ insertcookie "BalancerID=Backend_C; Path=/";
+ insertrealip on;
+ }
+}
diff --git a/tools/untab b/tools/untab
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+
+use strict;
+
+die ("Usage: untab file [file...]\n") if ($#ARGV == -1);
+
+for my $in (@ARGV) {
+ my $out = "$in.new";
+ open (my $fin, $in) or die ("Can't read $in: $!\n");
+ open (my $fout, ">$out") or die ("Can't write $out: $!\n");
+
+ my $changed = 0;
+ while (defined (my $line = <$fin>)) {
+ while ($line =~ /^\t/) {
+ $line =~ s/^\t/ /;
+ $changed++;
+ }
+ print $fout ($line);
+ }
+
+ close ($fin);
+ close ($fout);
+
+ if (!$changed) {
+ unlink ($out) or die ("Can't unlink $out: $!\n");
+ } else {
+ print ("Untabbed $in ($changed times)\n");
+ unlink ($in) or die ("Can't unlink $in: $!\n");
+ rename ($out, $in) or die ("Can't rename $out to $in: $!\n");
+ }
+}