commit 999c56944a289bbfecfa925fa0fc096a1dc26d75
parent e8d1a84a54b585712b2b5f2a80655f4920229ff7
Author: finwo <finwo@pm.me>
Date: Sat, 3 Jan 2026 19:34:52 +0100
2.00
Diffstat:
415 files changed, 3962 insertions(+), 30282 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -1,696 +1 @@
-
-ChangeLog for Crossroads
-------------------------------------------------------------------------------
-
-1.81 [KK 2008-06-26]
- - Memory leaks debugging
-
-1.80 [KK 2008-05-19]
- - "Read from <client/server> timed out" is now only an error when
- it concerns the server. When it concerns the client, it's only a
- verbose message.
- - In http_copy(): Copy-thru mode from server to client is NOT
- entered when the server sent a HTTP/1.x 3xx response. HTTP 300
- responses are not assumed to have a body.
-
-1.79 [KK 2008-04-01]
- - Changed 'make' in '$(MAKE)' in all Makefiles to support 'gmake'
- invocations.
- - Added debugging to config_write() (Solaris problems)
- - Changed limits_msg() to avoid RLIMIT_MEMLOCK, RLIMIT_NPROC,
- RLIMIT_RSS on systems that don't have these (Solaris problems)
- - Rewrote Messaging functions msg(), error(), warning() to
- autosupply the service name.
- - The configuration file is now searched relative to the program,
- then as /etc/crossroads.conf. So if eg. the program is
- /opt/crossroads/bin/crossroads, then the config may be
- /opt/crossroads/etc/crossroads.conf.
-
-1.78 [KK 2008-03-14]
- - Limits of running service are shown when verbosity is on.
- - Fixed "no child processes" error when doing system() calls
- under Linux. The signal handler for SIGCHLD must apparently be
- off (see src/lib/sysrun.c). Also fixed for popen() calls (see
- src/lib/choosebackend.c).
-
-1.77 [KK 2008-03-07]
- - Next development version. Introduced %l for last-connect timing.
-
-1.76 [KK 2008-01-31]
- - Parser again made stricter: a backend's maxconnections is not allowed
- when the service's dispatch type is an external handler.
- - Porting issues for gcc 4.0.2 (default at MacOSX Leopard) solved.
-
-1.75 [KK 2008-01-25]
- - Changed chunked transfer copying in HTTP mode. The trailing
- \r\n, following a zero-bytes chunk, also gets handled in
- http_copy(). Before it was left for handling in a next loop.
- - Bugfix in the parser, regarding handling of external dispatcher
- definitions.
- - Change in the way Crossroads handles responses from external
- dispatchers: when no back ends are available, XR will sleep for
- a short time. Better handling of incorrect responses.
- - Irritating svn messages during build phase suppressed.
-
-1.74 [KK 2008-01-22]
- - Bugfix in HTTP header scanning.
- - strnstr() added for systems that lack it
- - Warning stanza enhanced when select() fails during network writes,
- back end names are displayed
-
-1.73 [KK 2008-01-17]
- - Upon service startup the initial configuration is logged (if
- verbose is on).
- - Flag -P added for parser/lexer verbosity (debugging only).
- <stringstate> rewritten. String-state lexer strips trailing
- spaces in stringstate mode.
- - Backend-level directive "httptiminglog" implemented.
- - "througputlog" logging will also include the # of bytes.
-
-1.72 [KK 2008-01-14]
- - Lexical analyzer changed: whitespace leading up to strings (eg.
- external handler specifiiers) are skipped.
- - Porting issues with Intel Macs solved.
- - Upped c-conf to 1.11 (compatible with MacOSX's extensions
- MacPorts and with Fink).
- - External dispatchers are called even when NO back ends are
- available. Previously asking an external dispatcher would only
- occur when one or more back ends was up. Furthermore,
- Crossroads will always accept the dispatcher's suggestion, even
- when that back end was previously unavailable.
-
-1.71 [KK 2008-01-12]
- - Bugfix in 1.70 related to HTTP body copy-thru mode.
-
-1.70 [KK 2008-01-11]
- - Bugfix in 1.69 (yeah that was fast)..
-
-1.69 [KK 2008-01-11]
- - The HTTP header processing was rewritten to work with octet
- chunks. Previously TCP buffers would be processed byte by byte
- to match headers. Hopefully this will speed up HTTP processing.
-
-1.68 [KK 2008-01-10]
- - "crossroads status" now also reports the PID of each service
- listener process (in both plain text and XML). Thanks Felix Ostmann
- for suggesting.
-
-1.67 [KK 2008-01-09]
- - In the case of an external dispatcher: the dispatcher will be
- called even when there is only one backend available. The
- dispatcher may have side-actions to perform. Thanks Nicolas
- Prochazka for suggesting this. EXPERIMENTAL VERSION - use 1.65
- until this code has proven stable.
-
-1.66 [KK 2008-01-09]
- - Forking of a servicer moved 'forward', before dispatching
- phase. That way external dispatchers won't slow down the
- listener. Thanks, Nicolas Prochazka, for suggesting this.
- This version is EXPERIMENTAL ONLY - use 1.65 until this code
- has proven stable. Incidentally, this makes the system load
- lower as well...
-
-1.65 [KK 2008-01-08]
- - Bugfix in parsing of -B option (TCP buffer size)
-
-1.64 [KK 2007-12-27]
- - Bugfix in "dispatchmode byclientip"
- - Added testing utility test/hashtest
- - The parser is stricter. HTTP-related directives are now only
- allowed when 'type http' is given.
-
-1.63 [KK 2007-12-10]
- - Cosmetic change to usage text.
- - Flag -p implemented.
- - Commandline functions (start/stop) etc now in properly named
- §sources.
- [KK 2007-12-14] Promoted to Stable.
-
-1.62 [KK 2007-10-03]
- - Extended format specifiers with %g. In time-related modifiers
- like %g, %t, %T, the optional number is an offset into the
- future (so %3600t is now + 1h). Thanks Gunnar S. for pointing
- this out.
-
-1.61 [KK 2007-10-02]
- - Added messaging to allowfrom/denyfrom rule handling. Bugfixes
- in the parsing and handling of allow/deny rules. Thanks Chris
- G. for pointing this out to me.
-
-1.60 [KK 2007-08-29]
- - upped c-conf to 1.10
- - Support for __progname_full in systems that have it, see setproctitle()
-
-1.59 [KK 2007-08-22]
- - 1.58 Stable
-
-1.58 [KK 2007-08-21]
- - Bugfix in the handling of "bindto any". Thanks, Simon M. for
- pointing it out.
-
-1.57 [KK 2007-08-20]
- - Next development release.
-
-1.56 [KK 2007-08-20]
- - This is basically only version 1.55 marked STABLE.
-
-1.55 [KK 2007-08-16]
- - Changed error handling of the finding of duplicate ports. Same
- ports in different service statements are now an error only if
- one or both services don't list a bindto address (or if the two
- listed bindto addresses are the same). Thanks, Rodd Johnson,
- for finding this bug.
-
-1.54 [KK 2007-07-30]
- - Changed copyright to GPL V3.
-
-1.53 [KK 2007-07-29]
- - Misc small changes, thanks Simon Matter for all suggestions,
- fixes and diffs! Changes include: ps fix for Linux systems in
- crossroads-mgr, 'use POSIX' fix in Perl, C code fix for for
- older gcc's.
- - crossroads-mgr now supports a flag '-a address' to specify a
- listening address (also suggested by Simon).
-
-1.52 [KK 2007-07-12]
- - Added list of keywords to the docs
- - Removed Log4Perl dependency in crossroads-mgr (easier for distro's)
-
-1.51 [KK 2007-07-10]
- - Removed global MAX_BACKEND setting. The number of back ends per
- service is now totally dynamic - derived from the
- configuration.
- - Added counts of available back ends, unavailable back ends and
- so on to "crossroads -x status". The web interface
- crossroads-mgr now picks this up.
- - Documentation updated. Small fixes.
-
-1.50 [KK 2007-07-08]
- - Back end states can be initially set using the "state"
- directive. Command "crossroads tell" now requires keyword
- "state" for setting the state.
- - Introduced actual_server and actual_port in SHM block for back
- end addresses. Introduced define FQDN_LENGTH. Back end addresses
- can be set using "crossroads tell".
- - Web front end crossroads-mgr can now redefine a back end address.
-
-1.49 [KK 2007-07-04]
- - Next development cycle version.
-
-1.48 [KK 2007-07-04]
- - Added strupr() for systems that lack it.
- - Version tagged STABLE.
-
-1.47 [KK 2007-06-27]
- - Added "externalhandler" to "revivinginterval"
- - Added "checkinterval"
- - Last connect time per back end gets stored
-
-1.46 [KK 2007-06-25]
- - Flag -X added (for xslt reference embedding)
- - "crossroads tell {service} {backend} {state}": state can be
- numeric
- - Added crossroads-mgr, updated all docs, etc..
- - Fixed "make distclean"
-
-1.45 [KK 2007-06-12]
- - Configuration option 'headerinspection {deep|shallow}'
- implemented. Documentation updated. Several other documentation fixes.
- - New make target 'dbginstall', installs gdb-able versions into
- /usr/local/bin
- - Upped c-conf to 1.09: /usr/lib64 is in the library search path
- (thanks Joern F. for pointing this one out).
- - Added setproctitle() for non-BSD-ish systems. Previous
- set_program_title() is obsolete (it woundn't save the envp).
- - Flag -B <bufsize> introduced, making the TCP buffer size
- variable. Previous constant TCP_BUFSZ is now DEFAULT_TCP_BUFSZ,
- which is now 5k instead of 10k.
-
-1.44 [KK 2007-06-12]
- - Small bugfix in -b flag handling (useful during debugging only).
-
-1.43 [KK 2007-05-22]
- - Changed the way that shmkeys are computed; the old way would
- cause more collisions.
- - Implemented DNS caching. By default 20 gethostbyname() results
- can be cached, with a ttl of 1 hour per entry; though the ttl
- has a default of 0 (no caching). Flag -d can overrule the TTL.
- - Fixed makefile dependency for crossroads-daemon.
- - Upped c-conf to 1.08.
- - Reorganized docs. Key variables (author, maintainer, ...) are
- passed from the Makefile.
- - Added a small test run to the making: test/t*conf should parse
- OK, test/bad*conf should fail. These tests are auto-run on
- 'make local'.
- - Added #include to the grammar. Shell-style #-comments are no
- longer allowed. Added #define to the grammar.
-
-1.42 [KK 2007-05-21]
- - Fixed small portability issue for gcc 4.0.3 (library dependency
- with libm.a)
- - Added etc/svncheck to verify that SVN holds all files, before
- making a distro.
-
-1.41 [KK 2007-05-18]
- - Included c-conf 1.07 (caching provisions - way faster build)
- - Fixed deliverable, version 1.40 lacked files (DISTRO WAS BROKEN)
-
-1.40 [KK 2007-05-16]
- - Added flag -m to control shared memory access mode.
- - Implemented flag -x for XML report of status.
- - Added tips sections on health check scripting and on XSLT's.
- - Cosmetic code changes.
- - The daemon 'sec' is now in in a separate crossroads-daemon
- binary. Configuration parsing, usage info etc. not included, so
- that the sec daemon has a smaller footprint.
-
-1.39 [KK 2007-05-06]
- - This is the next development release (1.38 promoted to stable).
- - Fixed tcp_serve() to only warn when accept() fails (this used
- to be fatal).
-
-1.38 [KK 2007-04-26] Many changes:
- - 'crossroads status' now supports optional service/backend arguments.
- - Added specific nullstring initializers to parser.y.
- - Added info on ip_conntrack_max to the tips section of the docs
- (Thanks, Felix).
- - Rewritten the code that timeouts upon network connect (this used
- to have jumps which isn't safe).
- - Added docs on -t (tabular status report) flag.
- - Added code to avoid logging and running on-end hooks when HTTP
- mode fails to find a suitable back end.
- - Added test/t8.conf which works with breaking-client, to
- simulate clients that hang up.
- - 'make clean' removes GDB's history files
- - Removed usage of non-reentrant functions from signal handler
- (interrupt.c)
- - Added RETRY_WAIT, small sleep time when retrying connecting to
- the same back end
- - Added description of retries keyword to the Tips&Tricks section
- - Fixed mark_activity() to apply decays only for 'true'
- connections, not for wakeup calls
- - Split up the tips section of the docs into separate sources.
- - Added flag -C to show compile-time settings.
- - Sped up make process by scanning c-conf output just once (:=
- instead of =, probably GNU Make only, we'll see).
-
-1.37 [KK 2007-04-17] Intermediate release for bughunts on 64bit Linux.
-
-1.36 [KK 2007-04-16] Fixed small bug in total usage counting. Bugfix
- in resetting temporary failure counts of back ends (while waiting
- for retries to expire). Added __attribute__ compiler macro to
- functions such as msg(), warning() -- and fixed format conversion issues.
-
-1.35 [KK 2007-04-16] Added 'retries' keyword to back end definitions.
-
-1.34 [KK 2007-04-03] Added SVN revision number to the overall version
- ID, so that tracking historical versions becomes easier. Added
- flag -t which causes tabular display in 'crossroads status'
- (useful for automated parsing, e.g. for heartbeat scripts).
- [KK 2007-04-06] Increased max # of back ends per service to
- 20. (In the future this should be a dynamic value - but it'll
- take code changes; so for now, I'm taking 20.)
-
-1.33 [KK 2007-04-02] Added hashpjw.c to the repository - I had
- forgotten that in 1.32 (so, 1.32 is broken..).
-
-1.32 [KK 2007-03-30] Change net_read() and net_copy(): Read exceptions
- on the client network socket don't issue error or warning
- messages; clients are notorious for just dropping dead. Logging
- this just clogs up the syslog. These situations are only logged
- when verbosity is on.
-
-1.31 [KK 2007-03-21] Changed messaging from error to warning when a
- TCP write fails towards the server. The fact that the server
- hangs up, can be actually intended -- Crossroads can't make
- assumptions about it. Marked 1.30 as stable, 1.31 is the next
- development release.
-
-1.30 [KK 2007-03-20] Signed/unsigned fix in net_read() (return value <
- 0 would get evaluated badly when taken as unsigned). Changed
- state/string handling, so that "up" is a synonym for "available"
- (eg. in "crossroads tell {myservice} {mybackend} up"). Fixed up
- sources so that compilation with -pedantic is OK. Added flag -W
- to warn against loads of things, mainly signed/unsigned comparisons.
-
-1.29 [KK 2007-02-25] Small code changes in error/msg/warning, no
- action when no format string.
- [KK 2007-03-07] fork_tcp_servicer() won't abort upon fork
- failure, just warn. This avoids fatal stops when the process
- table is full.
-
-1.28 [KK 2007-02-15] Added small dependencies to src/Makefile. Added
- debugging code to http_header_add(). The signal handler (see
- interrupt.c) will exit immediately upon SIGPIPE when in serving
- mode. There is no need to wait for the current request to finish,
- when one of the network pipes has gone. Change exiting to _exit()
- instead of exit() to avoid cleanup code execution. Misc small
- changes in http mode.
-
-1.27 [KK 2007-02-14] Verbosity gets set correctly in HTTP type
- services.
-
-1.26 [KK 2007-02-13] Backends that are unavailable are skipped in the
- determination of targets during sticky HTTP sessions. This used
- to be: only backends that are available are candidate. Difference
- is that backends that are now marked down, can still be selected
- -- so that sticky HTTP sessions get a chance to continue.
-
-1.25 [KK 2007-01-26] Next development release.
-
-1.24 [KK 2007-01-26] This is identical to version 1.23, tagged Stable.
-
-1.23 [KK 2007-01-04] Removed "sampleconf" program option. There are
- too many config options to have all the sample text in the
- binary. Other small fixes.
-
-1.22 [KK 2006-12-21] Implemented username directive.
- [KK 2006-12-22] Fixed counting of total sessions.
-
-1.21 [KK 2006-12-11] Implemented externalhandler as dispatch mode.
- Added a few sample handlers, updated the docs. NOTE: The external
- dispatcher handlers are ALPHA CODE at this time.
- [KK 2006-12-13] Changed the 'configuration' section of the
- docs. Directives are now in their own subsection, so that they
- have their own TOC entry.
- [KK 2006-12-14] Changed the 'onsuccess' directive to
- 'onstart'. Implemented 'onend'. Commands that are run via these
- hooks, plus via 'onfailure', get expanded. Added format expanders
- '%n' (connections of a back end) and '%w' (weights of a back
- end). Thanks Bernd Krumboeck for loads of suggestions, code,
- diffs and testing!
- [KK 2006-12-19] Compilation fixes, thanks again Bernd.
-
-1.20 [KK 2006-12-06] Updated connection handler in HTTP requests to
- show the right title (which backend is being served). Fixed bug
- in client connection counting. Fixed status reporter to show an
- 's' after the display of seconds.
- [KK 2006-12-08] Fixed status reporter to use suffix Tb (tera) or
- Gb (giga) for large bytecounts.
-
-1.19 [KK 2006-12-04] Implemented IP filtering (configuration:
- allowfrom/allowfile, denyfrom/denyfile). Updated docs. Recoded
- filtering so that the order is "deny,allow" (a-la Apache). More
- messaging in "dispatchmode roundrobin".
-
-1.18 [KK 2006-11-29] Next development version. Fixed net_copy() to
- correctly decrement the client connection count (thanks Bernd
- Krumboeck for the fix!). Small document fix.
- [KK 2006-12-01] http_header_connectiontype() will now correctly
- understand Connection-Type: TE, close (ie. when the "close" is
- part of a larger setting).
-
-1.17 [KK 2006-11-28] Next development version.
- [KK 2006-11-29] Removed debugging stuff which by mistake slipped
- into 1.16 stable. Shipping this 1.17 as next-stable (instead of
- the previous 1.16, which is theoretically unnecessarily slow).
-
-1.16 [KK 2006-11-01] New development version. Usage text updated to
- point to http://crossroads.e-tunity.com. Flag -s
- implemented. Small bugfix in 'restart' action.
- [KK 2006-11-28] Promoted to next stable version.
-
-1.15 [KK 2006-10-23] Speedup in the handling of chunked HTTP message
- transfer. Furthermore, chunked messages are treated as
- single-shot actions (see RFC2616, liberally explained by yours
- truly).
- [KK 2006-11-01] Bison- and flex-generated files are no longer
- removed in 'make clean'. This helps folks who want to build
- Crossroads but don't have these tools.
- Version 1.15 marked as 'stable'.
-
-1.14 [KK 2006-10-19] Bugfix in chunked transfer encoding (yeah I
- know.. yet again.. hopefully the last time). This was a
- particularly nasty one.
-
-1.13 [KK 2006-09-26] Next development release.
- [KK 2006-10-03] Porting issues for Solaris 9: localtime() issues
- fixed, cp/strip used instead of install -s, ctype.h macro's avoided.
-
-1.12 [KK 2006-09-13] Small changes in wakeup handler. Timeout handling
- in HTTP service processing slightly changed.
- [KK 2006-09-15] Added checks whether both client and server want
- persisting HTTP connections (see http_serve()). Header
- Proxy-Connection: close is inserted if the connections should get
- closed. Rewrote network to- and fro- copying: net_copy() now
- replaces net_read() + net_write().
- [KK 2006-09-26] Promoted to STABLE.
-
-1.11 [KK 2006-09-12] HTTP type services now analyze not only the first
- request/response pair to apply header magic; Subsequent pairs are
- also analyzed.
-
-1.10 [KK 2006-09-11] Small speedup in header reading. Commandline
- option "restart" will now act as "start" if no Crossroads is
- found running. Rewrote chunked transfer-encoding transmission in
- HTTP type services. Messaging now shows the type of message with
- a prefix: ERROR, WARNING or INFO.
-
-1.09 [KK 2006-09-05] Small changes for HP-UX port. Crossroads should
- now compile on HP-UX 11.23 / ia64. (Thanks, Bernd Krumboeck):
- - gcc selected if both gcc and cc are present (c-conf 1.04)
- - conditional compilation of vsyslog() function
- [KK 2006-09-06] Neater support of streamed HTTP transfer
- (eg. video); data is sent instantly to the client.
-
-1.08 [KK 2006-08-28] Next development (trunk) version.
- [KK 2006-08-29] Implemented net_read() / net_write() so that
- socket reads and writes are centralized, with their logging and
- error handling. HTTP transfer buffers are now 'unsigned
- char'. Shell script test/runtest added to drive sanity checks.
- [KK 2006-08-31] Rewrote HTTPP message parsing (http_msg_*()).
- Added directives 6 header modification directives. Lots of code
- cleanups. The HTTP 502 error text (proxy error) is now in a
- separate text file. Byte and second counts of 'crossroads status'
- are now correctly displayed. Documentation updated.
-
-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
- piggybacking is necessary after the initial chat). Flag -u (user
- switch) removed; user switching won't work given privileged TCP
- ports, shared memory access and semaphores all mixed together (or
- in other words: I'm too lazy right now to make this work
- elegantly.)
- Version 1.06 promoted to the next stable.
-
-1.05 [KK 2006-07-12] Restarting heavily sped up, plus it won't affect
- creation of new listener sockets. Messaging improved, the
- affected service is reported. Flag -f (foreground mode) removed;
- this debugging option is no longer useful given the complexity of
- it all. Added socket shutdowns to interrupt handler
- (interrupt.c). Fixed up shared memory free ups.
- THIS VERSION SHOULD MAKE "CROSSROADS RESTART" WORK WELL!
-
-1.04 [KK 2006-06-26] Next development version.
- [KK 2006-07-03] Fixed http_read(); the # of historic
- connections ('totuses') would be counted double in sticky HTTP
- mode.
- [KK 2006-07-04] Added call to sranddev() to make weighted random
- dispatching more conforming to the weights (HAVE_SRANDDEV defined
- in the Makefile when sranddev() is available).
-
-1.03 [KK 2006-06-20] Support for older gcc's (incase strlcat() is
- missing; added strlcat.c).
- Added -lm to linkage flags for fmod().
- This is a new development version despite the fact that 1.02
- isn't promoted to 'stable'.
- [KK 2006-06-22] Changed internal-server-error HTTP
- response. Fixed very small bug in weighted random dispatchmode;
- the old code wouldn't correctly see similar high weights.
- [KK 2006-06-26] Fixed counting of total nr. of connections in
- sticky HTTP mode (as shown with 'crossroads status').
- This version is tagged as 'stable'.
-
-1.02 [KK 2006-05-11] Next development release.
- [KK 2006-05-12] In HTTP mode, the nr of sessions per back end is
- stored. Improved status reporting: the nr of sessions is shown
- (when type is http), the seconds and bytes are shown in a more
- readable format.
- [KK 2006-05-13] Fixed weighted random balancing; 1.01 had a bug
- that didn't distribute new connections according to the weights
- (see choose_backend()). Introduced new make target 'commit'.
- [KK 2006-05-19] New flag -a introduced, that logs incoming and
- ending activity. See further log_activity_*(). Docs
- updated. Cleaned up the source tree (stale sources removed).
- [KK 2006-06-07] Introduced -l flag for LOG_LOCAL0 to LOG_LOCAL7
- openlog facility selection. Bugfix in log_activity*() calls.
- [KK 2006-06-07] Fixed lock_reporter() / unlock_reporter() so that
- running connection (in program_stage == stage_serving) don't
- crash during semaphore operations. This actually happens when
- there's a running connection and crossroads is stopped on the
- commandline.
- [KK 2006-06-07] Modified the source to use strlcat/snprintf
- instead of strcat/sprintf, to avoid warnings on
- e.g. OpenBSD. Enveloped include <stdint.h> with an #ifdef.
-
-1.01 [KK 2006-05-09] Small codechange in http_serversocket() for GCC <
- 4.0. (There was accidentally post-3 code which I didn't notice:)
- [KK 2006-05-10] Improved messaging in choose_backend(), in the
- case of round robin balancing. Implemented weighted balancing with
- "dispatchmode random".
- [KK 2006-05-11] Updated the docs regarding the new primary site
- http://crossroads.e-tunity.com. Promoted 1.01 to the next stable
- release, versioned 1.02 as the next development release.
-
-1.00 [KK 2006-05-05] This version is identical to 0.33, except that
- crossroads will now be hosted in a publicly accessible SVN
- repository at svn://svn.e-tunity.com/crossroads.
-
-0.33 [KK 2006-05-05] Fixed small bug in http_findcookie() concerning
- routing cookies matching.
-
-0.32 [KK 2006-05-02] Fixed set_program_title() to have a separate
- argv[0] argument, so that 'killall' e.a. match 'crossroads'.
-
-0.31 [KK 2006-04-06] Slight change of functionality in
- http_serversocket(). Fail over implemented for existing HTTP
- sessions. Furthermore: small code optimizations.
-
-0.30 [KK 2006-03-17] Optimization in http_serversocket() routine.
-
-0.29 [KK 2006-03-14]
- - Small bugfix in chunked transfer handling (added: ishexdigit())
-
-0.28 [KK 2006-03-13]
- - Chunked transfer handling improved.
- - Flag -V implemented.
-
-0.27 [KK 2006-03-10]
- - Small changes in HTTP handling (better support for proxies as
- back ends).
- - Verbosity of HTTP handling somewhat throttled.
-
-0.26 [KK 2006-02-27]
- - Backend definitions now support HOSTNAME:PORT in a 'server'
- specifier.
- - Status overview compressed to fewer lines.
- - Documentation updated and refined.
- - Service types introduced, defaulting to 'any'.
- - New service 'stickyhttp'. New directives 'stickycookie' and
- 'insertcookie' to make HTTP sessions.. well.. stick.
- - Old keywords 'sessiontimeout' and 'bysessions' renamed to
- 'connectiontimeout' and 'byconnections'.
-
-0.25 [KK 2006-02-08] Program stages are displayed as strings in
- debug/error messages (see stagetostring.c).
-
-0.24 [KK 2006-01-20] Fixed display of high-ascii chars in the dumplog.
-
-0.23 [KK 2006-01-03] Fixed potential race condition when creating
- network sockets over and over. Now a short sleeptime is inserted
- between the retries, so that e.g. new file descriptors become
- available. Fixed potential fd leak.
-
-0.22 [KK 2005-12-12] Portability issues fixed for Solaris builds
- (thanks, Lasse Osterild, for pointing this out and fixing
- it). Version ID added to the docs.
-
-0.21 [KK 2005-12-07] Implemented the 'configtest' command line
- argument. Configuration file parsing improved (no more
- shift/reduce conflicts, better error checks). Docs updated.
-
-0.20 [KK 2005-12-06] Changes in the dispatching machine. Added a
- "dispatchmode bysessions", which selects the back end with the
- least active clients (adjusted for weights). All durations are
- now logged with millisecond accuracy, the "dispatchmode
- byduration" uses this. (All this due to Ray Pittigher's requests
- to load-balance MySQL RDBMS back ends ;-)
-
-0.19 [KK 2005-11-29] Cosmetic fix of debug messages. Typo fix in the
- documentation (thanks, Marc Uebel for pointing this one out).
- Fixed the status updater: updates now occur DURING sessions, not
- just at the closing. That makes balancing by duration or by size
- more precise.
-
-0.18 [KK 2005-11-28] Fixed #ifdef/#if clausing of
- SET_PROC_TITLE_BY_ARGV. (Thanks to Ray Pittigher for pointing
- this out, Linux on Redhat AS4 was too critical to grok this code.)
-
-0.17 [KK 2005-11-23] Maintenance-related release. Messages are now logged with
- priority LOG_NOTICE (which ensures debug-information on default
- Mac OSX). When the creation of a listening socket fails,
- crossroads will retry after X sleep-seconds (this prevents 'port
- steals'). Stability of the wakeup handler improved.
-
-0.16 [KK 2005-11-18] Documentation updated for the throughputlog statement.
-
-0.15 [KK 2005-11-17] Bugfix in time calculation of thruputlog().
-
-0.14 [KK 2005-11-16] Statement 'dumptraffic' renamed to 'trafficlog'.
- Implemented the 'throughputlog' statement.
-
-0.13 [KK 2005-11-09] Implemented support for either flock(), lockf()
- or none of the above; whichever is available. Added #defines for
- flock()-related calls and for others, incase your Unix lacks them
- (thanks to Patrick Debois & Jan Vanhaecht, a Solaris port
- effort). Added linkage flags for the libs: ucb, nsl, pthread,
- socket (thanks also to Patrick Debois & Jan Vanhaecht). Added a
- maxclients statement at the level of back end definitions (thanks
- to Martin Lonkwitz for suggesting this).
-
-0.12 [KK 2005-11-03] Minor documentation update.
-
-0.11 [KK 2005-10-28] Docs updated. Makefiles somewhat cleaned
- up. Fixed a 'make install' related issue (thanks go to Johnatan
- Cua or pointing this one out).
-
-0.10 [KK 2005-10-26] Minor bugfix. The nr. of sessions in the report
- would not get decreased upon timeout of a session (thanks go to
- Martin Lonkwitz for pointing this one out).
-
-0.09 [KK 2005-10-18] Warnings of backend connections are avoided in
- the wakeup handler. This prevents too much messaging in the
- system log. Implemented commandline action 'restart'. Docs updated.
-
-0.08 [KK 2005-10-13] Minor build changes; port to Mac OSX Darwin.
-
-0.07 [KK 2005-09-15] Small change of verbose messages. Verbose
- messages now go to stderr (instead of stdout). Added shmctl()
- calls to make sure that we're the rightful owner of the shared
- memory segment. Fixed checking of the return value of shmat()
- for 64bit systems [Thanks, Ray Pittigher, for helping me find
- this bug].
-
-0.06 [KK 2005-09-14] Improved error messaging during the parsing of
- the configuration. The onfailure or onsuccess triggers now also
- run during an initial connect; this used to be only during
- interrupted sessions. Improved the handling of new connections
- when no back ends are available: in that case, the client's
- connection gets denied (instead of accepted and closed).
- Increased the default sleep time (pause when no back ends are
- available) to 10 secs; edit etc/Makefile.def if you want to
- change this. Implemented the statement 'bindto ip-address' in
- service configurations; this can be used in situations where
- crossroads must only listen to a specific IP address.
-
-0.05 [KK 2005-09-12] Changed the wakeup handler to generate less
- messages to syslog. Hearing that a back end still hasn't woken up
- is not very relevant.
- Moved release from alpha to beta.
-
-0.04 [KK 2005-07-18] Added manual page. Internal: update of project to
- svn (instead of CVS). Implemented flag -u to set the effective
- uid of running services. More documentation updates.
-
-0.03 [KK 2005-07-15] Fixed potential race condition in mark_activity()
- to set back end states. Implemented set_program_title() so that
- 'ps ax | grep crossroads' shows what's going on. Change in
- show_status(), the output is more condensed. Implemented "over N"
- in dispatchmode, and "weight N" in backend
- configurations. Rewrote the backend selection algorithm. Then of
- course lots of changes in the docs.
-
-0.02 [KK 2005-07-11] Maintenance stuff: fixed minor things in the
- docs, updated timeout message in backend_connect(), fixed minor bug in
- wakeup_handler(), 'tell' argument now matches services and back
- ends without regard to casing. More maintenance in the 'upload'
- target: a crossroads-latest.tar.gz is created to facilitate easy
- downloads from public.e-tunity.com.
-
-0.01 [KK 2005-07-06] First release, alpha.
+2.00 [KK 2008-08-07] Release of 2.00.
diff --git a/Makefile b/Makefile
@@ -1,66 +1,55 @@
-# Central Makefile for crossroads
-# -------------------------------
+# Top-level Makefile for XR
+# -------------------------
-BASE = $(shell sh -c pwd)
-include etc/Makefile.def
+VER = 2.00
+BINDIR = /usr/sbin
+TAR = /tmp/crossroads-$(VER).tar.gz
+AUTHOR = Karel Kubat <karel@kubat.nl>
+MAINTAINER = Karel Kubat <karel@kubat.nl>
foo:
- @cat etc/Makefile.help
-
-compile-only:
- BASE=$(BASE) $(MAKE) -C src
-
-local: compile-only
- BASE=$(BASE) $(MAKE) -C test
-
-local-pg:
- BASE=$(BASE) PG=-pg G=-g $(MAKE) -C src
- BASE=$(BASE) $(MAKE) -C test
-
-local-g:
- BASE=$(BASE) G=-g $(MAKE) -C src
- BASE=$(BASE) $(MAKE) -C test
-
-local-alf:
- BASE=$(BASE) G=-g ALF=-DALF $(MAKE) -C src
+ @echo
+ @echo 'Choose:'
+ @echo ' make local - local program construction'
+ @echo ' make install - installation to $(BINDIR)'
+ @echo ' make clean - removal after local/install'
+ @echo ' make tar - pack sources in an archive'
+ @echo ' make commit - commit to repository (maintainer only)'
+ @echo
+
+local:
+ mkdir -p xr/build
+ xr/etc/gettools /usr/local/bin xr/etc c-conf e-ver
+ xr/etc/e-ver ChangeLog $(VER)
+ AUTHOR='$(AUTHOR)' MAINTAINER='$(MAINTAINER)' VER='$(VER)'\
+ $(MAKE) -C xr
install: local
- BASE=$(BASE) $(MAKE) -C src install
- BASE=$(BASE) $(MAKE) -C doc install
-
-dbginstall: local-g
- BASE=$(BASE) G=-g $(MAKE) -C src dbginstall
- BASE=$(BASE) $(MAKE) -C doc install
-
-pginstall: local-pg
- BASE=$(BASE) PG=-pg G=-g $(MAKE) -C src dbginstall
- BASE=$(BASE) $(MAKE) -C doc install
-
-documentation:
- BASE=$(BASE) $(MAKE) -C doc
+ mkdir -p $(BINDIR)
+ AUTHOR='$(AUTHOR)' MAINTAINER='$(MAINTAINER)' \
+ VER='$(VER)' BINDIR=$(BINDIR) $(MAKE) -C xr install
+ @echo
+ @echo ' The balancer program xr is now installed to $(BINDIR).'
+ @echo ' Consider configuring xrctl/xrctl and copying it to $(BINDIR) too.'
+ @echo ' The helper xrctl is not installed automatically.'
+ @echo ' Have fun with Crossroads $(VER)!'
+ @echo ' -- $(MAINTAINER)'
+ @echo
clean:
- find $(BASE) -type f -name '*~' -exec rm {} \;
- find $(BASE) -type f -name .gdb_history -exec rm {} \;
- find $(BASE) -type f -name gmon.out -exec rm {} \;
- BASE=$(BASE) $(MAKE) -C doc clean
- BASE=$(BASE) $(MAKE) -C test clean
- BASE=$(BASE) $(MAKE) -C src clean
-
-distclean:
- BASE=$(BASE) $(MAKE) -C doc distclean
- BASE=$(BASE) $(MAKE) -C src distclean
-
-dist: documentation
- $(BASE)/tools/e-ver ChangeLog $(VER)
- $(BASE)/tools/makedist $(VER)
-
-commit: clean headers documentation local
- BASE=$(BASE) $(MAKE) clean
- BASE=$(BASE) etc/svncheck
+ rm -rf xr/build/*
+
+tar:
+ rm -rf $(TAR) /tmp/crossroads-$(VER)
+ cd ..; cp -r crossroads /tmp/crossroads-$(VER)
+ cd /tmp; tar czf $(TAR) \
+ --exclude .git --exclude crossroads-$(VER)/xr/build \
+ crossroads-$(VER)
+ @echo
+ @echo 'Sources now tarred into $(TAR)'
+
+commit: local clean
+ test `svn status | grep '^\?' | wc -l` -eq 0 || \
+ (echo 'SVN not fully up to date' && exit 1)
svn commit
- svn commit -m 'Revision number update' $(BASE)/etc/svnrev.txt
-
-headers:
- $(BASE)/tools/patch-header $(BASE)/etc/hdr.template $(VER) \
- src/*/*.c src/*.h
+
+\ No newline at end of file
diff --git a/doc/Makefile b/doc/Makefile
@@ -1,40 +0,0 @@
-include ../etc/Makefile.def
-
-YODLINC = -I.:/usr/local/share/yodl:/usr/share/yodl:$(BASE)/doc/main
-
-foo: defs main/keywords.yo
- find main -type f -name '*.yo' -exec ../tools/untab {} \;
- cd man && yo2man crossroads
- mv man/crossroads.man crossroads.1
- cd man && yo2man crossroads-mgr
- mv man/crossroads-mgr.man crossroads-mgr.1
- cd man && yo2man $(YODLINC) crossroads.conf
- mv man/crossroads.conf.man crossroads.conf.7
- cd main && yo2pdf crossroads
- mv main/crossroads.pdf .
- rm -f main/*.aux main/*.latex main/*.log main/*.toc
- cd main && yo2html crossroads
- mv main/*.html .
-
-main/keywords.yo: $(BASE)/src/lib/parser.y
- $(BASE)/tools/getkeywords < $< > $@
-
-defs:
- echo 'redef(VER)(1)($(VER))' > crossroads-defs.yo
- echo 'redef(YEARS)(1)($(YEARS))' >> crossroads-defs.yo
- echo 'redef(AUTHORNAME)(1)($(AUTHORNAME))' >> crossroads-defs.yo
- echo 'redef(DNSCACHETTL)(1)($(DNS_CACHETTL))' >> crossroads-defs.yo
- echo 'redef(MAINTAINERNAME)(1)($(MAINTAINERNAME))' \
- >> crossroads-defs.yo
- echo 'redef(MAINTAINEREMAIL)(1)($(MAINTAINEREMAIL))' \
- >> crossroads-defs.yo
-
-install:
- $(BASE)/tools/installdoc $(PREFIX) crossroads.1 crossroads-mgr.1 \
- crossroads.conf.7
-
-clean:
- rm -f crossroads-defs.yo *.man
-
-distclean: clean
- rm -f *.html *.pdf *.1 *.7
diff --git a/doc/crossroads-mgr.1 b/doc/crossroads-mgr.1
@@ -1,120 +0,0 @@
-.SH "e-tunity"
-.TH "crossroads-mgr" "1" "2005-2008" "crossroads" ""
-.SH "NAME"
-crossroads-mgr \- Web interface for Crossroads
-.PP
-.SH "SYNOPSIS"
-.IP o
-\fBcrossroads-mgr\fP \fI[flags]\fP \fBstart\fP \fIport\fP: starts
-the web interface server
-.IP o
-\fBcrossroads-mgr\fP \fBstop\fP: stops the server
-.IP o
-\fBcrossroads-mgr\fP \fBstatus\fP: shows whether the server
-is running
-.PP
-.SH "DESCRIPTION"
-
-.PP
-\fBcrossroads-mgr\fP is a self-contained web server, written in
-Perl, providing a web interface to control Crossroads\&. The web
-interface allows one to:
-.PP
-.IP o
-View the states of back ends, and their usage;
-.IP o
-Set the states of back ends (e\&.g\&., to take a back end out
-of service)\&.
-.PP
-The web interface cannot be used to fully configure Crossroads (e\&.g\&., to
-add new back ends)\&. This must be done via the configuration file
-\fBcrossroads\&.conf\fP\&. Note furthermore that \fBcrossroads status\fP and
-\fBcrossroads tell\fP are commandline tools that achieve the same
-functionality as \fBcrossroads-mgr\fP\&.
-.PP
-.SH "OPTIONS"
-
-.PP
-\fBcrossroads-mgr\fP recognizes the following flags:
-.PP
-.IP o
-\fB-a ADDRESS\fP: Specifies the address to which the
-manager binds\&. E\&.g\&., one may specify \fB-a 127\&.0\&.0\&.1\fP, after
-which only requests originating from localhost will be served\&.
-.IP
-.IP o
-\fB-b UN:PW\fP: Viewing the status is protected using
-simple basic authentication, requiring username \fBUN\fP and
-password \fBPW\fP\&.
-.IP
-For example one may specify: \fB-b user:secret\fP, after which
-visitors to the web interface are prompted for a username and
-password\&.
-.IP
-Instead of the username, a colon, and a password, the special
-word \fBPROMPT\fP may be used (in caps)\&. In this case,
-\fBcrossroads-mgr\fP prompts for the entry of a username and a
-password\&. Using \fBPROMPT\fP will have the effect that the
-username and password are not shown in a process listing\&.
-.IP
-.IP o
-\fB-B UN:PW\fP: Setting the status of a back end is
-protected using simple basic authentication, with username
-\fBUN\fP and password \fBPW\fP\&. The special word \fBPROMPT\fP may be
-used\&.
-.IP
-.IP o
-\fB-f\fP: \fBcrossroads-mgr\fP stays in the foreground
-instead of daemonizing\&. Useful for debugging\&.
-.IP
-.IP o
-\fB-l FILE\fP: Verbose activity (when \fB-v\fP is given) is
-written to the stated file\&. Useful for debugging\&. Also, error
-messages are written to the file\&. The default is
-\fB/tmp/crossroads-mgr\&.log\fP\&. Note that file logging is not
-used in \&'foreground\&' mode (flag \fB-f\fP; in that case all
-logging goes to terminal)\&.
-.IP
-.IP o
-\fB-v\fP: Verbosity is increased\&.
-.IP
-.IP o
-\fB-x CMD\fP: This specifies how \fBcrossroads-mgr\fP should
-invoke \fBcrossroads\fP\&. The default is just \fBcrossroads\fP\&. An
-example is: \fB/usr/local/bin/crossroads -c
-/alternative/configuration\fP which overrules the default
-configuration file name\&. Note that once \fB-x\fP is given,
-\fBcrossroads-mgr\fP will no longer search along the PATH\&. When
-using \fB-x\fP, the full access path to \fBcrossroads\fP must be
-specified\&.
-.IP
-.IP o
-\fB-X XSLT\fP: Causes \fBcrossroads-mgr\fP to send the
-specified XSLT file, instead of the built-in\&. Useful for
-debugging\&.
-.PP
-.SH "BUGS"
-
-.PP
-.IP o
-Basic authentication headers are logged when \fB-v\fP
-is active\&. Make sure that the log file is not in a
-world-readable place, or turn off \fB-v\fP\&.
-.IP
-.IP o
-When using basic authentication in the form \fB-b
-UN:PW\fP and \fB-B UN:PW\fP, the required credentials are
-visible in the process overview list\&. Use \fBPROMPT\fP to
-hide these\&.
-.IP
-.IP o
-\fBcrossroads-mgr stop\fP and \fBcrossroads-mgr status\fP
-use the process list to see which daemons are active\&. If
-you start more than one daemon, then \fBcrossroads-mgr
-stop\fP will stop all of them\&.
-.PP
-.SH "AUTHOR"
-.IP o
-Author: Karel Kubat
-.IP o
- Maintainer: Karel Kubat karel@kubat\&.nl
diff --git a/doc/crossroads.1 b/doc/crossroads.1
@@ -1,149 +0,0 @@
-.SH "e-tunity"
-.TH "crossroads" "1" "2005-2008" "crossroads" ""
-.SH "NAME"
-crossroads \- Load balancer and fail over utility
-.PP
-.SH "SYNOPSIS"
-.IP o
-\fBcrossroads\fP \fI[flags]\fP \fBstart\fP: starts Crossroads
-.IP o
-\fBcrossroads\fP \fI[flags]\fP \fBstop\fP: stops Crossroads
-.IP o
-\fBcrossroads\fP \fI[flags]\fP \fBrestart\fP: restarts Crossroads
-.IP o
-\fBcrossroads\fP \fI[flags]\fP \fBconfigtest\fP: verifies
-configuration
-.IP o
-\fBcrossroads\fP \fI[flags]\fP \fBservices\fP: shows configured
-services
-.IP o
-\fBcrossroads\fP \fI[flags]\fP \fBtell\fP \fIservice\fP
-\fIbackend\fP \fBstate\fP \fInewstate\fP: sets a back end state
-.IP o
-\fBcrossroads\fP \fI[flags]\fP \fBtell\fP \fIservice\fP
-\fIbackend\fP \fBserver\fP \fIhostname:port\fP: redefines the
-address of a back end
-.PP
-.SH "DESCRIPTION"
-
-.PP
-\fBcrossroads\fP is the main control program of Crossroads, a
-balancing and fail over utility\&. The Crossroads utility consists
-of two binaries: \fBcrossroads\fP and \fBcrossroads-daemon\fP\&. The
-latter is controlled by the front end \fBcrossroads\fP\&.
-.PP
-Recognized states in \fBcrossroads tell\fP are:
-.PP
-.IP o
-\fBavailable\fP or \fBup\fP when a backend is working;
-.IP o
-\fBunavailable\fP when a back end is temporarily down, but
-can be woken up;
-.IP o
-\fBdown\fP when a back end is permanently down (e\&.g\&., for
-maintenance)\&. Crossroads itself will never activate a
-backend in this state\&.
-.IP o
-\fBwaking\fP when the live status of a back end is being checked\&.
-.PP
-.SH "OPTIONS"
-
-.PP
-Crossroads recognizes the following flags:
-.PP
-.IP o
-\fB-a\fP: Logs start and end times of activity to
-\fIsyslog\fP\&.
-.IP
-.IP o
-\fB-b\fP: Writes a binary representation of the
-configuration to \fIstdout\fP\&. For debugging only\&.
-.IP
-.IP o
-\fB-B\fP \fIsize\fP: Sets the size of network buffers\&. Larger
-buffers will mean a less number of \f(CWread()\fP or
-\f(CWwrite()\fP operations, but a larger memory
-footprint\&. Usually the default value will do fine\&.
-.IP
-.IP o
-\fB-C\fP: Writes the compile time configuration to
-\fIstdout\fP and stops\&. Useful when submitting bug reports\&.
-.IP
-.IP o
-\fB-c\fP \fIconfig\fP: Uses \fIconfig\fP as the configuration
-file\&. The default is \fB/some/path/etc/crossroads\&.conf\fP
-or \fB/etc/crossroads\&.conf\fP\&. The first alternative
-applies when Crossroads is installed as
-\fB/some/path/bin/crossroads\fP; in that case, Crossroads
-tries to find its configuration by trying an \&'etc\&'
-diretory \&'near\&' its own path\&.
-.IP
-.IP o
-\fB-d\fP \fIsec\fP: Sets the DNS cache time-to-live to
-\fIsec\fP seconds\&. Value 0 suppresses DNS entry
-caching\&. The default is \fB0\fP\&.
-.IP
-.IP o
-\fB-l\fP \fIfacility\fP: Specifies the openlog (3) facility,
-default is \fBLOG_DAEMON\fP\&. Values can be 0 to 7, meaning
-\fBLOG_LOCAL0\fP to \fBLOG_LOCAL9\fP\&.
-.IP
-.IP o
-\fB-m\fP \fIpermissions\fP: Specifies shared memory
-permissions, default is \fB0644\fP\&.
-.IP
-.IP o
-\fB-s\fP: Requests \&'sloppy\&' binding to TCP ports\&. When a
-port is busy, Crossroads will retry periodically to get
-it\&. Default is to stop when a listening port cannot be
-obtained\&.
-.IP
-.IP o
-\fB-t\fP: Output of \fBcrossroads status\fP is shown as a
-tabular view, in one or more lines of:
-.IP
-\fIservice\fP \fIbackend=state\fP \fI[backend=state\&.\&.\&.]\fP
-.IP
-.IP o
-\fB-x\fP: Output of \fBcrossroads status\fP is shown as an
-XML document\&.
-.IP
-.IP o
-\fB-v\fP: Initial actions of Crossroads are more
-\&'verbose\&'\&. (Once daemonized, the verbosity is controlled
-using \fBverbosity\fP statements in the configuration\&.)
-.IP
-.IP o
-\fB-V\fP: Shows the version ID and stops\&.
-.IP
-.IP o
-\fB-?\fP: Shows an overview of the usage\&.
-.PP
-.SH "FILES"
-\fBcrossroads\&.conf\fP, the default configuration file
-.PP
-.SH "SEE ALSO"
-.IP o
-crossroads\&.conf (7)
-.IP o
-The full Crossroads documentation in html or pdf format,
-distributed with the sources\&.
-.PP
-.SH "BUGS"
-Crossroads is of course bug free (haha)\&. When submitting bugs to
-the maintainer\&. please always include the following information:
-.PP
-.IP o
-The configuration file that Crossroads uses;
-.IP o
-The compile-time configuration, which is the output of
-\fBcrossroads -C\fP;
-.IP o
-A good description of the bug, and of the conditions
-under which it occurs\&.
-.PP
-.SH "AUTHOR"
-.IP o
-Author: Karel Kubat
-.IP o
- Maintainer: Karel Kubat karel@kubat\&.nl
diff --git a/doc/crossroads.conf.7 b/doc/crossroads.conf.7
@@ -1,1360 +0,0 @@
-.SH "e-tunity"
-.TH "crossroads\&.conf" "7" "2005-2008" "crossroads" ""
-.SH "NAME"
-crossroads\&.conf \- Crossroads configuration
-.PP
-.SH "SYNOPSIS"
-This manpage describes the configuration of
-Crossroads, usually the file \fBcrossroads\&.conf\fP\&. This file is often
-located in an \&'etc\&' directory near the path where Crossroads is
-installed\&. E\&.g\&., when Crossroads is installed as
-\fB/usr/local/bin/crossroads\fP, then the configuration file can be
-\f(CW/usr/local/etc/crossroads\&.conf\fP\&. Alternatively the configuration
-can always be put in \fB/etc/crossroads\&.conf\fP\&. Crossroads can however
-be started with a flag \fB-c\fP to specify an entirely different name\&.\&.
-.PP
-.SH "DESCRIPTION"
-
-
-
-The configuration that crossroads uses is normally stored in the file
-\f(CWcrossroads\&.conf\fP, either in an \&'etc\&' directory near the binary, or
-in \f(CW/etc/\fP\&. See section ?? for details\&.
-.PP
-The name of the configuration file can be overruled using the
-command line flag \f(CW-c\fP\&.
-.PP
-This section explains the syntax of the configuration file, and what
-all settings do\&.
-.PP
-.SH "General language elements"
-
-.PP
-This section describes the general elements of the crossroads
-configuration language\&.
-.PP
-\fBEmpty lines, indentation and comments\fP
-.PP
-Empty lines are of course allowed in the configuration\&. Also,
-indentation is irrelevant as far as processing is concerned, but is
-loosely inspired on a C-like style\&. So the following two examples are
-identical as far as Crossroads is concerned (thought the first one
-will be typically more readable):
-.PP
-.nf
-/* Example one */
-options {
- tcpbuffersize 10240;
- logactivity on;
-}
-
-/* Example two */
-options {tcpbuffersize 10240
-;logactivity on;}
-.fi
-
-.PP
-Crossroads recognizes the following comment formats:
-.PP
-.IP o
-C-style, between \f(CW/*\fP and \f(CW*/\fP,
-.IP o
-C++-style, starting with \f(CW//\fP and ending with the end
-of the text line\&.
-.PP
-Simply choose your favorite editor and use the comment that \&'looks
-best\&'\&.\e (I favor C or C++ comment\&. My favorite editor \fIemacs\fP
-can be put in \f(CWcmode\fP and nicely highlight what\&'s comment and what\&'s
-not\&. And as a bonus it will auto-indent the configuration!)
-.PP
-\fBPreprocessor directives\fP
-.PP
-Similar to \fBC\fP or \fBC++\fP, the Crossroads grammar knows \f(CW#include\fP
-and \f(CW#define\fP\&. Both directives must start at the first column of the
-line (ie\&., the \f(CW#\fP sign must occur at the leftmost line
-position)\&.
-.PP
-.IP o
-\f(CW#include\fP \f(CW"\fP\fIfilename\fP\f(CW"\fP includes the stated file
-name at the place of the statement\&.
-.IP o
-\f(CW#define\fP \fISYMBOL\fP \fIDEFINITION\fP defines \fISYMBOL\fP
-as placeholder for \fIDEFINITION\fP\&.
-.PP
-For example, one may use the configuration:
-.PP
-.nf
-#define SERVICEPORT 80
-service web {
- port SERVICEPORT;
- \&.
- \&. /* More statements follow here */
- \&.
-}
-.fi
-
-.PP
-The \f(CWport\fP statement is then read as \f(CWport 80\fP\&.
-.PP
-The statement \f(CW#define\fP can also be very nicely used when trying out
-Crossroads configurations\&. Crossroads has a statement \f(CWverbosity\fP
-\f(CWtrue\fP that causes debugging information to be logged\&. Once a
-configuration has proven to work, you\&'ll most likely want
-\f(CWverbosity\fP \f(CWfalse\fP so that overhead due to logging is
-avoided\&. This can be easily implemented using \f(CW#define\fP:
-.PP
-.nf
-/* Set DEBUG to true or false;
- * true is for testing purposes,
- * false is for production */
-#define DEBUG true
-
-service web {
- verbosity DEBUG;
- \&.
- \&. /* More statements follow here */
- \&.
-}
-.fi
-
-.PP
-\fBKeywords, numbers, identifiers, generic strings\fP
-.PP
-In a configuration file, statements are identified by \fIkeywords\fP,
-which are reserved words\&. The list of the keywords of the Crossroads
-grammar is:
-\f(CWservice\fP
-\f(CWport\fP
-\f(CWverbosity\fP
-\f(CWmaxconnections\fP
-\f(CWtype\fP
-\f(CWany\fP
-\f(CWhttp\fP
-\f(CWbackend\fP
-\f(CWserver\fP
-\f(CWbindto\fP
-\f(CWconnectiontimeout\fP
-\f(CWon\fP
-\f(CWoff\fP
-\f(CWdispatchmode\fP
-\f(CWroundrobin\fP
-\f(CWrandom\fP
-\f(CWbyduration\fP
-\f(CWbysize\fP
-\f(CWbyconnections\fP
-\f(CWbyorder\fP
-\f(CWbyclientip\fP
-\f(CWover\fP
-\f(CWdecay\fP
-\f(CWrevivinginterval\fP
-\f(CWcheckinterval\fP
-\f(CWretries\fP
-\f(CWshmkey\fP
-\f(CWweight\fP
-\f(CWonstart\fP
-\f(CWonfail\fP
-\f(CWbacklog\fP
-\f(CWthroughputlog\fP
-\f(CWtrafficlog\fP
-\f(CWhttptiminglog\fP
-\f(CWstickycookie\fP
-\f(CWaddclientheader\fP
-\f(CWsetclientheader\fP
-\f(CWappendclientheader\fP
-\f(CWaddserverheader\fP
-\f(CWsetserverheader\fP
-\f(CWappendserverheader\fP
-\f(CWallowfrom\fP
-\f(CWdenyfrom\fP
-\f(CWallowfile\fP
-\f(CWdenyfile\fP
-\f(CWexternalhandler\fP
-\f(CWuseraccount\fP
-\f(CWonend\fP
-\f(CWheaderinspection\fP
-\f(CWdeep\fP
-\f(CWshallow\fP
-\f(CWstate\fP
-\f(CWavailable\fP
-\f(CWunavailable\fP
-\f(CWdown\fP
-\f(CWoptions\fP
-\f(CWlogactivity\fP
-\f(CWtcpbuffersize\fP
-\f(CWdnscachettl\fP
-\f(CWlogfacility\fP
-\f(CWshmpermissions\fP
-\f(CWsloppyportbind\fP
-\f(CWleaveprocesstitle\fP
-.PP
-Many keywords require an \fIidentifier\fP as the argument\&. E\&.g, a
-service has a unique name, which must start with a letter or
-underscore, followed by zero or more letters, underscores, or
-digits\&. E\&.g\&., in the statement \f(CWservice myservice\fP, the keyword is
-\f(CWservice\fP and the identifier is \f(CWmyservice\fP\&.
-.PP
-Other keywords require a numeric argument\&. Crossroads knows only
-non-negative integer numbers, as in \f(CWport 8000\fP\&. Here, \f(CWport\fP is
-the keyword and \f(CW8000\fP is the number\&. Octal numbers are specified by
-prefixing a zero; e\&.g\&., \f(CW0644\fP is an octal number\&.
-.PP
-Yet other keywords require \&'generic strings\&', such as hostname
-specifications or system commands\&. Such generic strings contain any
-characters (including white space) up to the terminating statement
-character \f(CW;\fP\&. If a string must contain a semicolon, then it must
-be enclosed in single or double quotes:
-.PP
-.IP o
-\f(CWThis is a string;\fP is a string that starts at \f(CWT\fP
-and ends with \f(CWg\fP
-.IP o
-\f(CW"This is a string";\fP is the same, the double quotes
-are not necessary
-.IP o
-\f(CW"This is ; a string";\fP has double quotes to protect
-the inner ;
-.PP
-Finally, an argument can be a \&'boolean\&' value\&. Crossroads knows
-\f(CWtrue\fP, \f(CWfalse\fP, \f(CWyes\fP, \f(CWno\fP, \f(CWon\fP, \f(CWoff\fP\&. The keywords
-\f(CWtrue\fP, \f(CWyes\fP and \f(CWon\fP all mean the same and can be used
-interchangeably; as can the keywords \f(CWfalse\fP, \f(CWno\fP and \f(CWoff\fP\&.
-.PP
-.SH "Daemon options"
-
-.PP
-Crossroads supports an optional block that defines run options for the
-daemon process\&. These options can be also be specified on the command line
-using flags\&.
-.PP
-The syntax of the options block is:
-.PP
-.nf
-options {
- \&.
- \&. option statements (see below)
- \&.
-}
-.fi
-
-.PP
-In the curly-brace block the following option statements can occur:
-.PP
-.IP o
-\f(CWlogactivity on;\fP or \f(CWoff\fP Turns activity logging on
-or off\&. This is also controlled using the flag \f(CW-a\fP\&. The
-default is not to log network activity\&.
-.IP
-.IP o
-\f(CWtcpbuffersize\fP \fInumber\fP \f(CW;\fP This defines the size
-of network buffers\&. The default is 5120 bytes\&. This is also
-controlled using the flag \f(CW-B\fP\&.
-.IP
-.IP o
-\f(CWdnscachettl\fP \fInumber\fP \f(CW;\fP This controls the
-time-to-live of cached DNS entries, in seconds\&. Value zero
-means no caching and is the default\&. This is also controlled
-using the flag \f(CW-d\fP\&.
-.IP
-.IP o
-\f(CWlogfacility\fP \fInumber\fP \f(CW;\fP This controls the
-logging facility\&. Values 0 to 7 select \f(CWLOG_LOCAL0\fP to
-\f(CWLOG_LOCAL7\fP\&. Any other value selects \f(CWLOG_DAEMON\fP, which
-is also the default\&. This is also controlled using the flag \f(CW-l\fP\&.
-.IP
-.IP o
-\f(CWshmpermissions\fP \f(CWnumber\fP \f(CW;\fP This defines the
-permissions (for user, group and other) of the shared memory
-block\&. The number is most often specified as an octal value,
-e\&.g\&. \f(CW0644\fP, which is also the default\&. This is also
-controlled using the flag \f(CW-m\fP\&.
-.IP
-.IP o
-\f(CWsloppyportbind on;\fP or \f(CWoff\fP Turns on \&'sloppy\&' port
-binding of the listener\&. When \f(CWon\fP, Crossroads will not
-treat port-busy conditions as fatal, but will wait and retry\&.
-The default is \f(CWoff\fP\&. This is also controlled using flag
-\f(CW-s\fP\&.
-.IP
-.IP o
-\f(CWleaveprocesstitle\fP \f(CWon;\fP or \f(CWoff\fP When \f(CWon\fP, the
-process title of Crossroads is not modified, so that \f(CWps\fP
-will show \f(CWcrossroads-daemon\fP\&. The default is \f(CWoff\fP:
-Crosroads will modify its process name into something like
-\fIcrossroads - Sevice web: listening\fP or \fIcrossroads -
-Service web: serving\fP\&.
-.PP
-.SH "Service definitions"
-
-.PP
-Service definitions are blocks in the configuration file that
-state what is for each service\&. A service definition starts with
-\f(CWservice\fP, followed by a unique identifier, and by statements in
-\f(CW{\fP and \f(CW}\fP\&. For example:
-.PP
-.nf
-// Definition of service \&'www\&':
-service www {
- \&.\&.\&.
- \&.\&.\&. // statements that define the
- \&.\&.\&. // service named \&'www\&'
- \&.\&.\&.
-}
-.fi
-
-.PP
-The configuration file can contain many service blocks, as long as the
-identifying names differ\&. The following list shows possible
-statements\&. Each statement must end with a semicolon, except for the
-\f(CWbackend\fP statement, which has is own block (more on this later)\&.
-.PP
-\fBport - Specifying the listen port\fP
-.IP "Description:"
-The \f(CWport\fP statement defines to which TCP port a service
-\&'listens\&'\&. E\&.g\&. \f(CWport 8000\fP says that this service will accept
-connections on port 8000\&.
-.IP
-Multiple services in one configuration cannot use the same port
-number, unless they both bind to specific (and different) IP
-addresses\&. See also the \f(CWbindto\fP statement\&.
-.IP "Syntax:"
-\f(CWport\fP \fInumber\fP
-.IP "Default:"
-There is no default\&. This is a required setting\&.
-
-.PP
-\fBtype - Defining the service type\fP
-.IP "Description:"
-The \f(CWtype\fP statement defines how crossroads handles the stated
-service\&. There are currently two types: \f(CWany\fP and
-\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(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 such special features, use the type \f(CWany\fP (the
-default), even for HTTP protocols\&.
-.IP "Syntax:"
-\f(CWtype\fP \fIspecifier\fP, where \fIspecifier\fP is \f(CWany\fP or
-\f(CWhttp\fP
-.IP "Default:"
-\f(CWany\fP
-
-.PP
-\fBheaderinspection - are all HTTP headers inspected\fP
-.IP "Description:"
-The \f(CWheaderinspection\fP directive defines whether Crossroads
-must inspect all HTTP headers that are seen on one TCP connection, or
-only the first ones\&. There are two possible values for this directive:
-\f(CWdeep\fP and \f(CWshallow\fP\&. In \f(CWdeep\fP mode, all information that is
-seen on the TCP link is monitored
-and parsed, and all HTTP header blocks are analyzed and subject to
-directives such as \f(CWaddclientheader\fP\&. In \f(CWshallow\fP mode, only the
-first header block that the server sends, and the first header block
-that forms the server\&'s answer, are analyzed\&.
-.IP "Syntax:"
-\f(CWheaderinspection\fP \fIspecifier\fP, where \fIspecifier\fP is
-\f(CWdeep\fP or \f(CWshallow\fP
-.IP "Default:"
-\f(CWdeep\fP
-
-.PP
-\fBbindto - Binding to a specific IP address\fP
-.IP "Description:"
-The \f(CWbindto\fP statement is used in situations where crossroads
-should only listen to the stated port at a given IP address\&. E\&.g\&.,
-\f(CWbindto 127\&.0\&.0\&.1\fP causes crossroads to \&'bind\&' the service only to
-the local IP address\&. Network connections from other hosts won\&'t be
-serviced\&. By default, crossroads binds a service to all presently
-active IP addresses at the invoking host\&.
-.IP "Syntax:"
-\f(CWbindto\fP \fIaddress\fP, where \fIaddress\fP is a numeric IP
-address, such as 127\&.0\&.0\&.1, or the keyword \f(CWany\fP\&.
-.IP "Default:"
-\f(CWany\fP
-
-.PP
-\fBverbosity - Controlling debug output\fP
-.IP "Description:"
-Verbosity statements come in two forms: \f(CWverbosity on\fP or
-\f(CWverbosity off\fP\&. When \&'on\&', log messages to \f(CW/var/log/messages\fP
-are generated that show what\&'s going on\&.\e (Actually, the
-messages go to \f(CWsyslog(3)\fP, using facility \f(CWLOG_DAEMON\fP and
-priority \f(CWLOG_INFO\fP\&. In most (Linux) cases this will mean: output to
-\f(CW/var/log/messages\fP\&. On Mac OSX the messages go to
-\f(CW/var/log/system\&.log\fP\&.) The keyword \f(CWverbose\fP is an alias for
-\f(CWverbosity\fP\&.
-.IP "Syntax:"
-\f(CWverbosity\fP \fIsetting\fP or \f(CWverbose\fP \fIsetting\fP, where
-\fIsetting\fP is \f(CWtrue\fP, \f(CWyes\fP or \f(CWon\fP to turn
-verbosity on; or \f(CWfalse\fP, \f(CWno\fP, \f(CWoff\fP to turn it off\&.
-.IP "Default:"
-\f(CWoff\fP
-
-.PP
-\fBdispatchmode - How are back ends selected\fP
-.IP "Description:"
- The dispatch mode controls how crossroads selects a back end from
- a list of active back ends\&. The below text shows the bare
- syntax\&. See section ?? for a textual explanation\&.
-.IP
-The settings can be:
-.IP
-.IP o
-\f(CWdispatchmode roundrobin\fP: Simply the \&'next in line\&' is
-chosen\&. E\&.g, when 3 back ends are active, then the usage
-series is 1, 2, 3, 1, 2, 3, and so on\&.
-.IP
-Roundrobin dispatching is the default method, when no
-\f(CWdispatchmode\fP statement occurs\&.
-.IP
-.IP o
-\f(CWdispatchmode random\fP: Random selection\&. Probably only
-for stress testing, though when used with weights (see below)
-it is a good distributor of new connections too\&.
-.IP
-.IP o
-\f(CWdispatchmode bysize [ over\fP \fIconnections\fP \f(CW]\fP:
-The next back end is the one
-that has transferred the least number of bytes\&. This
-selection mechanism assumes that the more bytes, the heavier
-the load\&.
-.IP
-The modifier \f(CWover\fP \fIconnections\fP is optional\&. (The square
-brackets shown above are not part of the statement but
-indicate optionality\&.) When given,
-the load is computed as an average of the last stated number of
-connections\&. When this modifier is absent, then the load is
-computed over all connections since startup\&.
-.IP
-.IP o
-\f(CWdispatchmode byduration [ over\fP \fIconnections\fP \f(CW]\fP:
-The next back end is the one
-that served connections for the shortest time\&. This mechanism
-assumes that the longer the connection, the heavier the load\&.
-.IP
-.IP o
-\f(CWdispatchmode byconnections\fP: 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\&.
-.IP
-.IP o
-\f(CWdispatchmode byorder\fP: The first back end is selected
-every time, unless it\&'s unavailable\&. In that case the second
-is taken, and so on\&.
-.IP
-.IP o
-\f(CWdispatchmode byclientip\fP: The client\&'s IP address is
-\&'hashed\&' into a number, which is used to pick a back end\&. The
-same client IP address will therefore always be dispatched to
-the same back end\&. When the back end of choice is down,
-\f(CWdispatchmode byconnections\fP is used\&.
-.IP
-.IP o
-\f(CWdispatchmode externalhandler\fP \fIprogram arguments\fP:
-This is a special mode, where an external program is delegated
-the responsibility to say which back end should be used
-next\&. In this case, Crossroads will call the external program,
-and this will of course be slower than one of the \&'built-in\&'
-dispatch modes\&. However, this is the ultimate escape when
-custom-made dispatch modes are needed\&.
-.IP
-The dispatch mode that uses an \f(CWexternalhandler\fP is
- discussed separately in section ??\&.
-.IP
-The selection algorithm is only used when clients are serviced that
-aren\&'t part of a sticky HTTP session\&. This is the case during:
-.IP
-.IP o
-all client requests of a service type \f(CWany\fP;
-.IP o
-new sessions of a service type \f(CWhttp\fP\&.
-.IP
-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\&.
-.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
-estimate load from a network traffic stream, you have to choose an
-appropriate dispatch mode to optimize load balancing\&. In most cases,
-\f(CWroundrobin\fP or \f(CWbyconnections\fP will do the job just fine\&.
-.IP "Syntax:"
-\f(CWdispatchmode\fP \fImode\fP (see above for the modes), optionally
-followed by \f(CWover\fP \fInumber\fP, or when the \fImode\fP is
-\f(CWexternalhandler\fP, followed by \fIprogram\fP\&.
-.IP "Default:"
-\f(CWroundrobin\fP
-
-.PP
-\fBrevivinginterval - Back end wakeup calls\fP
-.IP "Description:"
-A reviving interval definition is used when Crossroads
-determines that a back end is temporarily unavailable\&. This will
-happen when:
-.IP
-.IP o
-The back end cannot be reached (network connection
-fails);
-.IP o
-The network connection to the back end suddenly dies\&.
-.IP
-Once a reviving interval is set, Crossroads will periodically
-check the unavailable back end(s) to see whether they have woken up\&.
-.IP
-An example of the definition is \f(CWrevivinginterval 10\fP\&. When this
-reviving interval is given, crossroads will check each 10 seconds
-whether unavailable back ends have woken up yet\&.
-.IP "Syntax:"
-.IP o
-\f(CWrevivinginterval\fP \fInumber\fP;
-.IP o
- \f(CWrevivinginterval\fP \fInumber\fP \f(CWexternalhandler\fP
- \fIprogram arguments\fP;
- The first form connects to a back end server\&. If the connection
- succeeds, then the back end is considered available\&. The second
- form activates an external program (see section
- ?? for a description)\&. The back end is marked
-available if the program\&'s exit status is zero\&.
-.IP "Default:"
-0 (no wakeup calls)
-
-.PP
-\fBcheckinterval - Periodic back end checks\fP
-.IP "Description:"
-When a check interval is stated, Crossroads will periodically
-probe back ends to determine whether available back ends are
-still there, and to see whether unavailable back ends have woken
-up yet\&.
-.IP
-An example is \f(CWcheckinterval 10\fP\&. When this is stated,
-Crossroads will probe all back ends each 10 seconds\&.
-.IP "Syntax:"
-.IP o
-\f(CWcheckinterval\fP \fInumber\fP;
-.IP o
-\f(CWcheckinterval\fP \fInumber\fP \f(CWexternalhandler\fP
-\fIprogram arguments\fP;
-The first form checks bhy connecting to the back end server\&.
-If the connection succeeds, then the back end is considered
-available; otherwise the back end is considered unavailable\&.
-.IP
-The second form activates an external program (see section
- ?? for a description)\&. The back end is considered
-available if the program\&'s exit status is zero; otherwise it is
-considered unavailable\&.
-.IP "Default:"
-0 (no periodic checks)
-
-.PP
-\fBmaxconnections - Limiting concurrent clients at service level\fP
-.IP "Description:"
-The maximum number of connections is specified using
-\f(CWmaxconnections\fP\&. There is one argument; the number of concurrent
-established connections that may be active within one service\&.
-.IP
-\&'Throttling\&' the number of connections is a way of preventing Denial of
-Service (DOS) attacks\&. Without a limit, numerous network connections
-may spawn so many server instances, that the service ultimately breaks
-down and becomes unavailable\&.
-.IP
-Note that \f(CWmaxconnections\fP is also allowed in a backend
-description block, in which case it limits the number of TCP
-connections to that particular back end\&.
-.IP "Syntax:"
-\f(CWmaxconnections\fP \fInumber\fP, where the number specifies the
-maximum of concurrent connections to the service\&.
-.IP "Default:"
-0, meaning that all connections will be accepted\&.
-
-.PP
-\fBbacklog - The TCP Back Log size\fP
-.IP "Description:"
-The TCP back log size is a number that controls how many
-\&'waiting\&' network connections may be queued, before a client simply
-cannot connect\&. The syntax is e\&.g\&. \f(CWbacklog 5\fP to cause crossroads
-to have 5 waiting connections for 1 active connection\&.
-The backlog queue shouldn\&'t be too
-high, or clients will experience timeouts before they can actually
-connect\&. The queue shouldn\&'t be too small either, because clients
-would be simply rejected\&. Your mileage may vary\&.
-.IP "Syntax:"
-\f(CWbacklog\fP \fInumber\fP
-.IP "Default:"
-0, which takes the operating system\&'s default
-value for socket back log size\&.
-
-.PP
-\fBshmkey - Shared Memory Access\fP
-.IP "Description:"
-Different Crossroads
-invocations must \&'know\&' of each others activity\&. E\&.g, \f(CWcrossroad
-status\fP must be able to get to the actual state information of all
-running services\&. This is internally implemented through shared
-memory, which is reserved using a key\&.
-.IP
-Normally crossroads will supply a shared memory key, based on the
-service name\&. In situations where this conflicts with existing
-keys (of other programs, having their own keys), you may supply a
-chosen value\&.
-.IP
-The actual key value doesn\&'t matter much, as long as it\&'s unique
-and as long as each invocation of crossroads uses it\&.
-.IP "Syntax:"
-\f(CWshmkey\fP \fInumber\fP
-.IP "Default:"
-0, which means that crossroads will \&'guess\&' its
-own key, based on the service name\&.
-
-.PP
-\fBallow* and deny* - Allowing or denying connections\fP
-.IP "Description:"
-Crossroads can allow or deny
-connections based on the IP address of a client\&. There are four
-directives that are relevant: \f(CWallowfrom\fP, \f(CWallowfile\fP,
-\f(CWdenyfrom\fP and \f(CWdenyfile\fP\&.
-.IP
-When using \f(CWallowfrom\fP and
-\f(CWdenyfrom\fP then the IP addresses to allow or deny connections are
-stated in the configuration\&. When using \f(CWallowfile\fP and
-\f(CWdenyfile\fP the allow or deny connections are stated in a
-separate file\&.
-.IP
-When \f(CWallow*\fP directives are used, then all connections are denied
-unless they match the stated allowed IP\&'s\&. When \f(CWdeny*\fP directives
-are used, then all connections are allowed unless they match the
-stated disallowed IP\&'s\&. When denying and allowing is both used,
-then the Crossroads checks the deny list first\&.
-.IP
-The statements \f(CWallowfrom\fP and \f(CWdenyfrom\fP are followed by a
-list of filter specifications\&. The statements \f(CWallowfile\fP and
-\f(CWdenyfile\fP are followed by a filename; Crossroads will read
-filter specifications from those external files\&. In both cases,
-Crossroads obtains filter specifications and places them in its
-lists of allowed or denied IP addresses\&. The difference between
-specifying filters in the configuration file or in external
-files, is that Crossroads will reload the external files when it
-receives signal 1 (\f(CWSIGHUP\fP), as in \f(CWkillall -1 crossroads\fP\&.
-.IP
-The filter specifications must obey the following syntax: they
-are series of space-separated strings, consisting of up to
-four numbers ranging from 0 to 255 and separated by a decimal
-sign\&. Optionally a slash follows, with a bitmask which is also a
-decimal number\&. For example, \f(CW127\&.0\&.0/24 10/8 192\&.168\&.2\&.1\fP is a
-setting that consists of three specifiers\&.
-.IP
-This is probably best explained by a few examples:
-.IP
-.IP o
-\f(CWallowfrom 10/8;\fP will allow connections from
-\f(CW10\&.*\&.*\&.*\fP (a full Class A network)\&. The mask \f(CW/8\fP means
-that the first 8 bits of the number (ie\&., only the \f(CW10\fP) are
-significant\&. On the last 3 positions of the IP address, all
-numbers are allowed\&. Given this directive, client connections
-from e\&.g\&. 10\&.1\&.1\&.1 and 10\&.2\&.3\&.4 will be allowed\&.
-.IP
-.IP o
-\f(CWallowfrom 10\&.3/16;\fP will allow all IP addresses that
-start with \f(CW10\&.3\fP\&. The first 16 bits (i\&.e\&., the first 2
-numbers) are significant, the rest doesn\&'t matter\&.
-.IP
-.IP o
-\f(CWallowfrom 10\&.3\&.1/16;\fP is the same as above\&. The third
-byte of the IP address is superfluous because the netmask
-specifies that only the first 16 bits (2 numbers) are taken
-into account\&.
-.IP
-.IP o
-\f(CWallowfrom 10\&.3\&.1\&.15;\fP allows traffic from only the
-specified IP address\&. There is no bitmask; all four numbers
-are relevant\&.
-.IP
-.IP o
-\f(CWallowfrom 10\&.3\&.1\&.15 10\&.2/16;\fP allows traffic from one
-IP address \f(CW10\&.3\&.1\&.15\fP or from a complete Class B network
-\f(CW10\&.2\&.*\&.*\fP
-.IP
-.IP o
-\f(CWallowfile /tmp/myfile\&.txt;\fP in combination with a file
-\f(CW/tmp/myfile\&.txt\fP, with the contents \f(CW10\&.3\&.1\&.15 10\&.2/16\fP,
-is the same as above\&.
-.IP
-When using ttt(allowfrom) and \f(CWdenyfrom\fP, separate specifiers
-can be stated in one statement (separated by whitespace), or the
-whole statement can be repeated\&. E\&.g\&., the following two
-alternatives have the same effect:
-.IP
-.nf
-/* Alternative 1: */
-allowfrom 10/8 192\&.168\&.1/24;
-
-/* Alternative 2: */
-allowfrom 10/8;
-allowfrom 192\&.168\&.1\&.24;
-.fi
-.IP "Syntax:"
-.IP o
-\f(CWallowfrom\fP \fIfilter-specificication(s)\fP
-.IP o
-\f(CWdenyfrom\fP \fIfilter-specificication(s)\fP
-.IP o
-\f(CWallowfile\fP \fIfilename\fP
-.IP o
-\f(CWdenyfile\fP \fIfilename\fP
-.IP "Default:"
-In absence of these statements, all client IP\&'s are accepted\&.
-
-.PP
-\fBuseraccount - Limiting the effective ID of external processes\fP
-.IP "Description:"
-Using the directive \f(CWuseraccount\fP, the effective user and group
-ID can be restricted\&. This comes into effect when Crossroads runs
-external commands, such as:
-.IP o
-Hooks for \f(CWonstart\fP, \f(CWonend\fP or \f(CWonfail\fP;
-.IP o
-External dispatchers, when \f(CWdispatchmode
-externalhandler\fP is in effect\&.
-Once a user name for external commands is specified, Crossroads
-assumes the associated user ID and group ID before running those
-commands\&.
-.IP "Syntax:"
-\f(CWuseraccount\fP \fIusername\fP
-.IP "Default:"
-None; when unspecified, external commands are run with the
-ID that was in effect when Crossroads was started\&.
-
-.PP
-.SH "Backend definitions"
-
-.PP
-Inside the service definitions as are described in the previous
-section, \fIbackend definitions\fP must also occur\&. Backend definitions
-are started by the keyword \f(CWbackend\fP, followed by an identifier
-(the back end name) , and statements inside \f(CW{\fP and \f(CW}\fP:
-.PP
-.nf
-service myservice {
- \&.\&.\&.
- \&.\&.\&. // statements that define the
- \&.\&.\&. // service named \&'myservice\&'
- \&.\&.\&.
-
- backend mybackend {
- \&.\&.\&.
- \&.\&.\&. // statements that define the
- \&.\&.\&. // backend named \&'mybackend\&'
- \&.\&.\&.
- }
-}
-.fi
-
-.PP
-Each service definition must have at least one backend
-definition\&. There may be more (and probably will, if you want
-balancing and fail over) as long as the backend names differ\&.
-The statements in the backend definition blocks are described in the
-following sections\&.
-.PP
-Some directives (\f(CWstickycookie\fP etc\&.) only have effect when
-Crossroads treats the network traffic as a stream of HTTP messages;
-i\&.e\&., when the service is declared with \f(CWtype http\fP\&. Incase of
-\f(CWtype any\fP, the HTTP-specific directives have no effect\&.
-.PP
-\fBserver - Specifying the back end address\fP
-.IP "Description:"
-Each back end must be identified by the network name
-(server name) where it is located\&. For example: \f(CWserver
-10\&.1\&.1\&.23\fP, or \f(CWserver web\&.mydomain\&.org\fP\&. A TCP port specifier
-can follow the server name, as in \f(CWserver
-web\&.mydomain\&.org:80\fP\&. \fBNote that\fP resolved host names can be
-cached by Crossroads\&. (The DNS cache timeout can be
-controlled using the invocation flag \f(CW-d\fP\&.)
-.IP "Syntax:"
-.IP o
-\f(CWserver\fP \fIservername\fP, where \fIservername\fP is a
-network name or IP address\&. In this case a separate \f(CWport\fP
-statement must be used to define the TCP port;
-.IP o
-\f(CWserver\fP \fIservername:port\fP
-.IP "Default:"
-There is no default\&. This is a required setting\&.
-
-.PP
-\fBport - Specifying a back end port\fP
-.IP "Description:"
-Back ends must be known by their host name and a port\&. Both can
-be simultaneously specified in a \f(CWserver\fP statement\&. When the
-\f(CWserver\fP statement specifies a host name only, then a \f(CWport\fP
-statement must be used to specify the port\&.
-.IP "Syntax:"
-\f(CWport\fP \fInumber\fP
-.IP "Default:"
-There is no default for the port\&. It must be specified either
-using \f(CWserver\fP or using \f(CWport\fP\&.
-
-.PP
-\fBverbosity - Controlling verbosity at the back end level\fP
-.IP "Description:"
-Similar to \f(CWservice\fP specifications, a
-\f(CWbackend\fP can have its own verbosity (\f(CWon\fP or \f(CWoff\fP)\&. When
-\f(CWon\fP, traffic to and fro this back end is reported\&.
-.IP "Syntax:"
-.IP o
-\f(CWverbosity\fP \fIsetting\fP, or
-.IP o
-\f(CWverbose\fP \fIsetting\fP, where \fIsetting\fP is \f(CWtrue\fP,
-\f(CWyes\fP or \f(CWon\fP, or \f(CWfalse\fP, \f(CWno\fP, \f(CWoff\fP to turn it
-off\&.
-.IP "Default:"
-\f(CWoff\fP
-
-.PP
-\fBretries - Specifying allowed failures\fP
-.IP "Description:"
-Back ends that are \&'flaky\&' or on a less reliable network can be
-marked as unavailable after not just one failure, but after
-e\&.g\&. three\&. You can use this configuration if you suspect that
-spurious errors cause otherwise \&'good\&' back ends to be marked as
-unavailable, while they in fact still could be used\&.
-.IP "Syntax:"
-\f(CWretries\fP \fInumber\fP; where \fInumber\fP is the threshold of bad
-connections\&. Once exceeded, Crossroads will mark a back end as
-unavailable\&.
-.IP "Default:"
-1; a back end is assumed to be unavailable after the first bad
-connection\&.
-
-.PP
-\fBmaxconnections - Limiting the connections to a back end\fP
-.IP "Description:"
-The directive \f(CWmaxconnections\fP limits the number of allowed
-connections to this client\&.
-Note that this directive can also occur on the level of a service
-block, in which case it limits the overall number of connections\&.
-.IP
-\fBFuthermore note\fP that this directive cannot be used when an external
-dispatcher is in effect\&. In such cases, the external dispatcher has
-full control over backend selection\&.
-.IP "Syntax:"
-\f(CWmaxconnections\fP \fInumber\fP \f(CW;\fP
-.IP "Default:"
-0; meaning no limit
-
-.PP
-\fBweight - When a back end is more equal than others\fP
-.IP "Description:"
-To influence how backends are selected, a backend can specify its
-\&'weight\&' in the process\&. The higher the weight, the less likely a
-back end will be chosen\&. The default is 1\&.
-.IP
-The weighing mechanism only applies to the dispatch modes
-\f(CWrandom\fP, \f(CWbyconnections\fP, \f(CWbysize\fP and \f(CWbyduration\fP\&.
-The weight is in fact a penalty factor\&. E\&.g\&., if backend A has
-\f(CWweight 2\fP and backend B has \f(CWweight 1\fP, then backend B will
-be selected all the time, until its usage parameter is twice as
-large as the parameter of A\&. Think of it as a \&'sluggishness\&'
-statement\&.
-.IP "Syntax:"
-\f(CWweight\fP \fInumber\fP; the higher the number, the more \&'sluggish\&'
-a back end is
-.IP "Default:"
-1; all back ends have equal weight\&.
-
-.PP
-\fBdecay - Levelling out activity of a back end\fP
-.IP "Description:"
-To make sure that a \&'spike\&' of activity doesn\&'t
-influence the perceived load of a back end forever, you may
-specify a certain decay\&. E\&.g, the statement \f(CWdecay 10\fP makes
-sure that the load that crossroads computes for this back end (be
-it in seconds or in bytes) is decreased by 10% each time that
-\fBan other\fP back end is hit\&. Decays are not applied to the count
-of concurrent connections\&.
-.IP
-This means that when a given back end is hit, then its usage data
-of the transferred bytes and the connection duration are updated
-using the actual number of bytes and actual duration\&. However,
-when a different back end is hit, then the usage data are
-decreased by the specified decay\&.
-.IP "Syntax:"
-\f(CWdecay\fP \fInumber\fP, where \fInumber\fP is a percentage that
-decreases the back end usage data when other back ends are
-hit\&.
-.IP "Default:"
-0, meaning that no decay is applied to usage statistics\&.
-
-.PP
-\fBstate - Setting an initial back end state\fP
-.IP "Description:"
-Using the \f(CWstate\fP directive a back end can be \&'primed\&' with an
-initial state\&. The keyword \f(CWstate\fP can be followed by
-\f(CWavailable\fP, \f(CWunavailable\fP or \f(CWdown\fP\&. Back ends marked
-\f(CWunavailable\fP are excluded as candidates, but are checked when
-a \f(CWrevivinginterval\fP or a \f(CWcheckinterval\fP is used\&. Back ends
-marked \f(CWdown\fP are excluded and never re-checked\&.
-.IP "Syntax:"
-.IP o
-\f(CWstate\fP \fIspecifier\fP \f(CW;\fP
-.IP o
-where \fIspecifier\fP is one of \f(CWavailable\fP,
-\f(CWunavailable\fP or \f(CWdown\fP
-.IP "Default:"
-\f(CWavailable\fP, meaning that a back end is a candidate for
-initial dispatching\&.
-
-.PP
-\fBonstart, onend, onfail - Action Hooks\fP
-.IP "Description:"
-The three directives \f(CWonstart\fP, \f(CWonend\fP and \f(CWonfail\fP can be
-specified to start system commands (external programs) when a
-connection to a back end starts, fails or ends:
-.IP o
-\f(CWonstart\fP commands will be run when Crossroads
-successfully connects to a back end, and starts servicing;
-.IP o
-\f(CWonend\fP commands will be run when a (previously
-established) connection stops;
-.IP o
-\f(CWonfail\fP commands will be run when Crossroads tries to
-contact a back end to serve a client, but the back end can\&'t
-be reached\&.
-.IP
-The format is always \f(CWon\fP\fItype\fP \fIcommand\fP\&. The \fIcommand\fP
-is an external program, optionally followed by arguments\&. The
-command is expanded according to the following table:
-.IP
-.IP o
-\f(CW%a\fP is the availability of the current back end, when
-a current back end is established\&. \f(CW%1a\fP is the
-availability of the first back end (0 when unavailable, 1 if
-available); \f(CW%2a\fP is the availability of the second back
-end, and so on\&.
-.IP
-.IP o
-\f(CW%b\fP is the name of the current back end, when one is
-established\&. \f(CW%1b\fP is the name of the first back end,
-\f(CW%2b\fP of the second back end, and so on\&.
-.IP
-.IP o
-\f(CW%e\fP is the count of seconds since start of epoch
-(January 1st 1970 GMT)\&. \f(CW%60e\fP is the count since start of
-epoch plus 60, so this is a 1 minute offset into the future\&.
-.IP
-.IP o
-\f(CW%g\fP is a "GMT-string" representation of the current
-time, in the format \fImonthname, day year hh:mm:ss\fP\&. This
-format is used in e\&.g\&. cookie expiry\&. \f(CW%600g\fP is the same
-representation but of a moment 600 seconds in the future (10
-minutes)\&.
-.IP
-.IP o
-\f(CW%h\fP is the host name of the current back end\&. \f(CW%1h\fP
-is the host name of the first back end, \f(CW%2h\fP of the second
-back end, and so on\&.
-.IP
-.IP o
-\f(CW%l\fP is the duration of the last successful connection
-in seconds, concerning the current back end\&. \f(CW%1l\fP is the
-duration of the connection to back end one, and so on\&. Note
-that \f(CW%l\fP refers only to the last successful connections\&.
-Unsuccessful connection attempts to back ends do not change
-the value\&.
-.IP
-.IP o
-\f(CW%p\fP is the TCP port of the current back end\&. \f(CW%1p\fP
-is the TCP port of the first back end, \f(CW%2p\fP of the second
-back end, and so on\&.
-.IP
-.IP o
-\f(CW%P\fP is the process ID of the Crossroads handler that
-handled this request\&. For debugging only\&.
-.IP
-.IP o
-\f(CW%r\fP is the IP address of the connecting client\&.
-.IP
-.IP o
-\f(CW%s\fP is the name of the current service that the client
-connected to\&.
-.IP
-.IP o
-\f(CW%t\fP is the current local time in ANSI format, in
-\fIYYYY-MM-DD/hhh:mm:ss\fP\&. \f(CW%1800s\fP is an ANSI stamp of a
-moment 1800 seconds in the future (half an hour)\&.
-.IP
-.IP o
-\f(CW%T\fP is the current GMT time in ANSI format\&. \f(CW%10T\fP
-offsets this 10 seconds into the future\&.
-.IP
-.IP o
-\f(CW%v\fP is the Crossroads version\&.
-.IP
-.IP o
-\f(CW%w\fP is the weight factor of the current back
-end\&. \f(CW%1w\fP is the weight factor of the first back end, etc\&.\&.
-.IP
-.IP o
-Any other chararacter following a \f(CW%\fP sign is taken
-literally; e\&.g\&. \f(CW%z\fP is just a z\&.
-.IP
-.IP "Syntax:"
-The syntax of the commands is as follows\&.
-.IP
-.IP o
-\f(CWonstart\fP \fIcommandline\fP
-.IP o
-\f(CWonend\fP \fIcommandline\fP
-.IP o
-\f(CWonfail\fP \fIcommandline\fP
-.IP o
-\f(CWonsuccess\fP \fIcommandline\fP
-.IP "Default:"
-There is no default\&. Normally no external programs are run upon
-connection, success or failure of a back end\&.
-
-.PP
-\fBtrafficlog and throughputlog - Debugging and Performance Aids\fP
-.IP "Description:"
-Two directives are available
-to log network traffic to files\&. They are \f(CWtrafficlog\fP and
-\f(CWthroughputlog\fP\&.
-.IP
-The \f(CWtrafficlog\fP statement causes all traffic to be logged in
-hexadecimal format\&. Each line is prefixed by \f(CWB\fP or \f(CWC\fP,
-depending on whether the information was received from the back
-end or from the client\&.
-.IP
-The \f(CWthroughputlog\fP statement writes shorthand transmissions to
-its log, accompanied by timings and the number of bytes each
-transmission was able to read or write in one chunk\&.
-.IP "Syntax:"
-The syntax is:
-.IP
-.IP o
-\f(CWtrafficlog\fP \fIfilename\fP \f(CW;\fP
-.IP o
-\f(CWthroughputlog\fP \fIfilename\fP \f(CW;\fP
-.IP "Default:"
-none
-
-.PP
-\fBhttptiminglog - Timing debugging in HTTP mode\fP
-.IP "Description:"
-The directive \f(CWhttptiminglog\fP turns on logging of HTTP mode
-timing\&. There must be one argument, the filename where the timings
-are written to\&. Turning on this option will slow down processing,
-but may be helpful in finding out where delays are caused\&.
-.IP "Syntax:"
-The syntax is:
-.IP
-.IP o
-\f(CWhttptiminglog\fP \fIfilename\fP \f(CW;\fP
-.IP o
-Where \fIfilename\fP is the output file, e\&.g\&.
-\f(CW/tmp/timings\&.log\fP
-.IP "Default:"
-none
-
-.PP
-\fBstickycookie - Back end selection with an HTTP cookie\fP
-.IP "Description:"
-The directive \f(CWstickycookie\fP \fIvalue\fP
-causes Crossroads to unpack clients\&' requests, to check for
-\fIvalue\fP in the cookies\&. When found, the message is routed to the
-back end having the appropriate \f(CWstickycookie\fP directive\&.
-.IP
-E\&.g\&., consider the following configuration:
-.IP
-.nf
-service \&.\&.\&. {
- \&.\&.\&.
- backend one {
- \&.\&.\&.
- stickycookie "BalancerID=first";
- }
- backend two {
- \&.\&.\&.
- stickycookie "BalancerID=second";
- }
-}
-.fi
-
-.IP
-When clients\&' messages contain cookies named \f(CWBalancerID\fP with
-the value \f(CWfirst\fP, then such messages are routed to backend
-\f(CWone\fP\&. When the value is \f(CWsecond\fP then they are routed to the
-backend \f(CWtwo\fP\&.
-.IP
-There are basically to provide such cookies to a browser\&. First, a
-back end can insert such a cookie into the HTTP response\&. E\&.g\&.,
-the webserver of back end \f(CWone\fP might insert a cookie named
-\f(CWBalancerID\fP, having value \f(CWfirst\fP\&.
-Second, Crossroads can insert such cookies using a carefully
-crafted directive \f(CWaddclientheader\fP\&.
-.IP "Syntax:"
-\f(CWstickycookie\fP \fIcookievalue\fP
-.IP "Default:"
-There is no default\&.
-
-.PP
-\fBHTTP Header Modification Directives\fP
-.IP "Description:"
-Crossroads understands the following
-header modification directives: \f(CWaddclientheader\fP,
-\f(CWappendclientheader\fP, \f(CWsetclientheader\fP, \f(CWaddserverheader\fP,
-\f(CWappendserverheader\fP, \f(CWsetserverheader\fP\&.
-.IP
-The directive names always consist of
-\fIAction\fP\fIDestination\fP\f(CWheader\fP, where:
-.IP
-.IP o
-The action is \f(CWadd\fP, \f(CWappend\fP or \f(CWinsert\fP\&.
-.IP
-.IP o
-Action \f(CWadd\fP adds a header, even when headers with
-the same name already are present in an HTTP
-message\&. Adding headers is useful for e\&.g\&. \f(CWSet-Cookie\fP
-headers; a message may contain several of such headers\&.
-.IP
-.IP o
-Action \f(CWappend\fP adds a header if it isn\&'t present
-yet in an HTTP message\&. If such a header is already
-present, then the value is appended to the pre-existing
-header\&. This is useful for e\&.g\&. \f(CWVia\fP headers\&. Imagine
-an HTTP message with a header \f(CWVia: someproxy\fP\&. Then the
-directive \f(CWappendclientheader "Via: crossroads"\fP will
-rewrite the header to \f(CWVia: someproxy; crossroads\fP\&.
-.IP
-.IP o
-Action \f(CWset\fP overwrites headers with the same
-name; or adds a new header if no pre-existing is found\&.
-This is useful for e\&.g\&. \f(CWHost\fP headers\&.
-.IP
-.IP o
-The destination is one of \f(CWclient\fP or \f(CWserver\fP\&. When
-the destination is \f(CWserver\fP, then Crossroads will apply such
-directives to HTTP messages that originate from the browser
-and are being forwarded to back ends\&. When the destination is
-\f(CWclient\fP, then Crossroads will apply such directives to
-backend responses that are shuttled to the browser\&.
-.IP
-The format of the directives is e\&.g\&. \f(CWaddclientheader
-"X-Processed-By: Crossroads"\fP\&. The directives expect one
-argument; a string, consisting of a header name, a colon, and a
-header value\&. As usual, the directive must end with a semicolon\&.
-.IP
-The header value may contain one of the following formatting
-directives:
-.IP
-.IP o
-\f(CW%a\fP is the availability of the current back end, when
-a current back end is established\&. \f(CW%1a\fP is the
-availability of the first back end (0 when unavailable, 1 if
-available); \f(CW%2a\fP is the availability of the second back
-end, and so on\&.
-.IP
-.IP o
-\f(CW%b\fP is the name of the current back end, when one is
-established\&. \f(CW%1b\fP is the name of the first back end,
-\f(CW%2b\fP of the second back end, and so on\&.
-.IP
-.IP o
-\f(CW%e\fP is the count of seconds since start of epoch
-(January 1st 1970 GMT)\&. \f(CW%60e\fP is the count since start of
-epoch plus 60, so this is a 1 minute offset into the future\&.
-.IP
-.IP o
-\f(CW%g\fP is a "GMT-string" representation of the current
-time, in the format \fImonthname, day year hh:mm:ss\fP\&. This
-format is used in e\&.g\&. cookie expiry\&. \f(CW%600g\fP is the same
-representation but of a moment 600 seconds in the future (10
-minutes)\&.
-.IP
-.IP o
-\f(CW%h\fP is the host name of the current back end\&. \f(CW%1h\fP
-is the host name of the first back end, \f(CW%2h\fP of the second
-back end, and so on\&.
-.IP
-.IP o
-\f(CW%l\fP is the duration of the last successful connection
-in seconds, concerning the current back end\&. \f(CW%1l\fP is the
-duration of the connection to back end one, and so on\&. Note
-that \f(CW%l\fP refers only to the last successful connections\&.
-Unsuccessful connection attempts to back ends do not change
-the value\&.
-.IP
-.IP o
-\f(CW%p\fP is the TCP port of the current back end\&. \f(CW%1p\fP
-is the TCP port of the first back end, \f(CW%2p\fP of the second
-back end, and so on\&.
-.IP
-.IP o
-\f(CW%P\fP is the process ID of the Crossroads handler that
-handled this request\&. For debugging only\&.
-.IP
-.IP o
-\f(CW%r\fP is the IP address of the connecting client\&.
-.IP
-.IP o
-\f(CW%s\fP is the name of the current service that the client
-connected to\&.
-.IP
-.IP o
-\f(CW%t\fP is the current local time in ANSI format, in
-\fIYYYY-MM-DD/hhh:mm:ss\fP\&. \f(CW%1800s\fP is an ANSI stamp of a
-moment 1800 seconds in the future (half an hour)\&.
-.IP
-.IP o
-\f(CW%T\fP is the current GMT time in ANSI format\&. \f(CW%10T\fP
-offsets this 10 seconds into the future\&.
-.IP
-.IP o
-\f(CW%v\fP is the Crossroads version\&.
-.IP
-.IP o
-\f(CW%w\fP is the weight factor of the current back
-end\&. \f(CW%1w\fP is the weight factor of the first back end, etc\&.\&.
-.IP
-.IP o
-Any other chararacter following a \f(CW%\fP sign is taken
-literally; e\&.g\&. \f(CW%z\fP is just a z\&.
-.IP
-The following examples show common uses of header modifications\&.
-.IP
-.IP "Enforcing session stickiness:"
-By combining
-\f(CWstickycookie\fP and \f(CWaddclientheader\fP, HTTP session
-stickiness is enforced\&. Consider the following configuration:
-.IP
-.nf
-service \&.\&.\&. {
- \&.\&.\&.
- backend one {
- \&.\&.\&.
- addclientheader "Set-Cookie: BalancerID=first; path=/";
- stickycookie "BalancerID=first";
- }
- backend two {
- \&.\&.\&.
- addclientheader "Set-Cookie: BalancerID=second; path=/";
- stickycookie "BalancerID=second";
- }
-}
-.fi
-
-.IP
-The first request of an HTTP session is balanced to either
-backend \f(CWone\fP or \f(CWtwo\fP\&. The server response is enriched
-using \f(CWaddclientheader\fP with an appropriate cookie\&. A
-subsequent request from the same browser now has that cookie
-in place; and is therefore sent to the same back end where the
-its predecessors went\&.
-.IP
-The header which is sent to the client to inject a cookie, can
-furthermore be expanded to specify a timeout:
-.IP
-.nf
-addclientheader "Set-Cookie: BalancerID=second; path=/; expires=%1800g";
-.fi
-
-.IP
-The format specifier \f(CW%1800g\fP outputs a GMT-string date 1800
-seconds in the future (half an hour from now)\&.
-.IP
-.IP "Hiding the server software version:"
-Many servers
-(e\&.g\&. Apache) advertize their version, as in \f(CWServer: Apache
-1\&.27\fP\&. This potentially provides information to attackers\&. The
-following configuration hides such information:
-.IP
-.nf
-service \&.\&.\&. {
- \&.\&.\&.
- backend one {
- \&.\&.\&.
- setclientheader "Server: WWW-Server";
- }
-}
-.fi
-
-.IP
-.IP "Informing the server of the clients\&' IP address:"
-Since
-Crossroads sits \&'in the middle\&' between a client and a back
-end, the back end perceives Crossroads as its client\&. The
-following sends the true clients\&' IP address to the server, in
-a header \f(CWX-Real-IP\fP:
-.IP
-.nf
-service \&.\&.\&. {
- \&.\&.\&.
- backend one {
- \&.\&.\&.
- setserverheader "X-Real-IP: %r";
- }
-}
-.fi
-
-.IP
-.IP "Keep-Alive Downgrading:"
-The directives
-\f(CWsetclientheader\fP and \f(CWsetserverheader\fP also play a key
-role in downgrading Keep-Alive connections to
-\&'single-shot\&'\&. E\&.g\&., the following configuration makes sure
-that no Keep-Alive connections occur\&.
-.IP
-.nf
-service \&.\&.\&. {
- \&.\&.\&.
- backend one {
- \&.\&.\&.
- setserverheader "Connection: close";
- setclientheader "Connection: close";
- }
-}
-.fi
-.IP "Syntax:"
-.IP o
-\f(CWaddclientheader\fP \fIHeadername: headervalue\fP to add a
-header in the traffic towards the client, even when another
-header \fIHeadername\fP exists;
-.IP o
-\f(CWappendclientheader\fP \fIHeadername: headervalue\fP to
-append \fIheadervalue\fP to an existing header \fIHeadername\fP
-in the traffic towards the client,
-or to add the whole header alltogether;
-.IP o
-\f(CWsetclientheader\fP \fIHeadername: headervalue\fP to
-overwrite an existing header in the traffic towards the
-client, or to add such a header;
-.IP o
-\f(CWaddserverheader\fP \fIHeadername: headervalue\fP to add a
-header in the traffic towards the server, even when another
-header \fIHeadername\fP exists;
-.IP o
-\f(CWappendserverheader\fP \fIHeadername: headervalue\fP to
-append \fIheadervalue\fP to an existing header \fIHeadername\fP
-in the traffic towards the server,
-or to add the whole header alltogether;
-.IP o
-\f(CWsetserverheader\fP \fIHeadername: headervalue\fP to
-overwrite an existing header in the traffic towards the
-server, or to add such a header\&.
-.IP "Default:"
-There is no default\&.
-
-.PP
-.SH "SEE ALSO"
-.IP o
-crossroads (1)
-.IP o
-The full Crossroads documentation, in pdf and html
-format, distributed with the sources\&.
-.PP
-.SH "AUTHOR"
-
- Crossroads is written by Karel Kubat and is maintained by
- Karel Kubat (karel@kubat\&.nl)\&.
diff --git a/doc/crossroads.html b/doc/crossroads.html
@@ -1,4562 +0,0 @@
-<a name="../crossroads-defs"></a><a name="defs"></a><html><head>
-<title>Crossroads 1.81</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.81</h1>
-<h2>Karel Kubat <br>
- Maintained by Karel Kubat (karel@kubat.nl)</h2>
-
-<h2>e-tunity</h2><h2>2005-2008, 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 modify HTTP headers, e.g. to
- provide 'session stickiness' for back end processes that need
- sessions, but aren't session-aware of other
- back ends. Crossroads is configured via a file and accessible
- via a web interface.</em></blockquote>
-
-<h1>Table of Contents</h1>
-<dl>
-<dl>
-<dt><h3><a href="#l1">1: Introduction</a></h3></dt>
-<dl>
-<dt><a href="#l2">1.1: Obtaining Crossroads</a></dt>
-<dt><a href="#l3">1.2: Reporting bugs</a></dt>
-<dt><a href="#l4">1.3: Copyright and Disclaimer</a></dt>
-<dt><a href="#l5">1.4: Terminology</a></dt>
-<dt><a href="#l6">1.5: Porting Issues</a></dt>
-<dl>
-<dt><a href="#l7">1.5.1: Porting issues for pre-1.80 installations</a></dt>
-<dt><a href="#l8">1.5.2: Porting issues for pre-1.63 installations</a></dt>
-<dt><a href="#l9">1.5.3: Porting issues for pre-1.50 installations</a></dt>
-<dt><a href="#l10">1.5.4: Porting issues for pre-1.43 installations</a></dt>
-<dt><a href="#l11">1.5.5: Porting issues for pre-1.21 installations</a></dt>
-<dt><a href="#l12">1.5.6: Porting issues for pre-0.26 installations</a></dt>
-<dt><a href="#l13">1.5.7: Porting issues for pre-1.08 installations</a></dt>
-</dl>
-</dl>
-<dt><h3><a href="#l14">2: Installation for the impatient</a></h3></dt>
-<dt><h3><a href="#l15">3: Using Crossroads</a></h3></dt>
-<dl>
-<dt><a href="#l16">3.1: The Balancer: crossroads</a></dt>
-<dl>
-<dt><a href="#l17">3.1.1: General Commandline Syntax</a></dt>
-<dt><a href="#l18">3.1.2: Status Reporting from the Command Line</a></dt>
-<dt><a href="#l19">3.1.3: Logging-related options</a></dt>
-<dt><a href="#l20">3.1.4: Reloading Configurations</a></dt>
-</dl>
-<dt><a href="#l21">3.2: The Web Frontend: crossroads-mgr</a></dt>
-</dl>
-<dt><h3><a href="#l22">4: The configuration</a></h3></dt>
-<dl>
-<dt><a href="#l23">4.1: General language elements</a></dt>
-<dl>
-<dt><a href="#l24">4.1.1: Empty lines, indentation and comments</a></dt>
-<dt><a href="#l25">4.1.2: Preprocessor directives</a></dt>
-<dt><a href="#l26">4.1.3: Keywords, numbers, identifiers, generic strings</a></dt>
-</dl>
-<dt><a href="#l27">4.2: Daemon options</a></dt>
-<dt><a href="#l28">4.3: Service definitions</a></dt>
-<dl>
-<dt><a href="#l29">4.3.1: port - Specifying the listen port</a></dt>
-<dt><a href="#l30">4.3.2: type - Defining the service type</a></dt>
-<dt><a href="#l31">4.3.3: headerinspection - are all HTTP headers inspected</a></dt>
-<dt><a href="#l32">4.3.4: bindto - Binding to a specific IP address</a></dt>
-<dt><a href="#l33">4.3.5: verbosity - Controlling debug output</a></dt>
-<dt><a href="#l34">4.3.6: dispatchmode - How are back ends selected</a></dt>
-<dt><a href="#l35">4.3.7: revivinginterval - Back end wakeup calls</a></dt>
-<dt><a href="#l36">4.3.8: checkinterval - Periodic back end checks</a></dt>
-<dt><a href="#l37">4.3.9: maxconnections - Limiting concurrent clients at service level</a></dt>
-<dt><a href="#l38">4.3.10: backlog - The TCP Back Log size</a></dt>
-<dt><a href="#l39">4.3.11: shmkey - Shared Memory Access</a></dt>
-<dt><a href="#l40">4.3.12: allow* and deny* - Allowing or denying connections</a></dt>
-<dt><a href="#l41">4.3.13: useraccount - Limiting the effective ID of external processes</a></dt>
-</dl>
-<dt><a href="#l42">4.4: Backend definitions</a></dt>
-<dl>
-<dt><a href="#l43">4.4.1: server - Specifying the back end address</a></dt>
-<dt><a href="#l44">4.4.2: port - Specifying a back end port</a></dt>
-<dt><a href="#l45">4.4.3: verbosity - Controlling verbosity at the back end level</a></dt>
-<dt><a href="#l46">4.4.4: retries - Specifying allowed failures</a></dt>
-<dt><a href="#l47">4.4.5: maxconnections - Limiting the connections to a back end</a></dt>
-<dt><a href="#l48">4.4.6: weight - When a back end is more equal than others</a></dt>
-<dt><a href="#l49">4.4.7: decay - Levelling out activity of a back end</a></dt>
-<dt><a href="#l50">4.4.8: state - Setting an initial back end state</a></dt>
-<dt><a href="#l51">4.4.9: onstart, onend, onfail - Action Hooks</a></dt>
-<dt><a href="#l52">4.4.10: trafficlog and throughputlog - Debugging and Performance Aids</a></dt>
-<dt><a href="#l53">4.4.11: httptiminglog - Timing debugging in HTTP mode</a></dt>
-<dt><a href="#l54">4.4.12: stickycookie - Back end selection with an HTTP cookie</a></dt>
-<dt><a href="#l55">4.4.13: HTTP Header Modification Directives</a></dt>
-</dl>
-</dl>
-<dt><h3><a href="#l56">5: Tips, Tricks and Random Remarks</a></h3></dt>
-<dl>
-<dt><a href="#l57">5.1: Configuration examples</a></dt>
-<dl>
-<dt><a href="#l58">5.1.1: A load balancer for three webserver back ends</a></dt>
-<dt><a href="#l59">5.1.2: An HTTP forwarder when travelling</a></dt>
-<dt><a href="#l60">5.1.3: SSH login with enforced idle logout</a></dt>
-</dl>
-<dt><a href="#l61">5.2: How back ends are selected in load balancing</a></dt>
-<dl>
-<dt><a href="#l62">5.2.1: Bysize, byduration or byconnections?</a></dt>
-<dt><a href="#l63">5.2.2: Averaging size and duration</a></dt>
-<dt><a href="#l64">5.2.3: Specifying decays</a></dt>
-<dt><a href="#l65">5.2.4: Adjusting the weights</a></dt>
-</dl>
-<dt><a href="#l66">5.3: Periodic probes and wake up calls</a></dt>
-<dl>
-<dt><a href="#l67">5.3.1: Syntax</a></dt>
-<dt><a href="#l68">5.3.2: Security Considerations</a></dt>
-<dt><a href="#l69">5.3.3: An example</a></dt>
-</dl>
-<dt><a href="#l70">5.4: Throttling the number of concurrent connections</a></dt>
-<dt><a href="#l71">5.5: TCP Session Stickiness</a></dt>
-<dt><a href="#l72">5.6: HTTP Session Stickiness</a></dt>
-<dl>
-<dt><a href="#l73">5.6.1: Don't use stickiness!</a></dt>
-<dt><a href="#l74">5.6.2: But if you must..</a></dt>
-</dl>
-<dt><a href="#l75">5.7: Passing the client's IP address</a></dt>
-<dl>
-<dt><a href="#l76">5.7.1: Sample Crossroads configuration</a></dt>
-<dt><a href="#l77">5.7.2: Sample Apache configuration</a></dt>
-</dl>
-<dt><a href="#l78">5.8: Deep or shallow HTTP header inspection</a></dt>
-<dt><a href="#l79">5.9: Debugging network traffic</a></dt>
-<dt><a href="#l80">5.10: IP filtering: Limiting Access by Client IP Address</a></dt>
-<dl>
-<dt><a href="#l81">5.10.1: General Examples</a></dt>
-<dt><a href="#l82">5.10.2: Using External Files</a></dt>
-<dt><a href="#l83">5.10.3: Mixing Directives</a></dt>
-</dl>
-<dt><a href="#l84">5.11: Using an external program to dispatch</a></dt>
-<dl>
-<dt><a href="#l85">5.11.1: Configuring the external handler</a></dt>
-<dt><a href="#l86">5.11.2: Writing the external handler</a></dt>
-<dt><a href="#l87">5.11.3: Examples of external handlers</a></dt>
-</dl>
-<dt><a href="#l88">5.12: Linux and ip_conntrack_max</a></dt>
-<dt><a href="#l89">5.13: Marking back ends as bad after more than one try</a></dt>
-<dt><a href="#l90">5.14: Using the Web Interface crossroads-mgr</a></dt>
-<dl>
-<dt><a href="#l91">5.14.1: Starting crossroads-mgr</a></dt>
-</dl>
-<dt><a href="#l92">5.15: Rendering Crossroads' status in a web page</a></dt>
-<dt><a href="#l93">5.16: Crossroads and DNS caching</a></dt>
-<dt><a href="#l94">5.17: Managing a Pool of Virtual Back Ends</a></dt>
-</dl>
-<dt><h3><a href="#l95">6: Benchmarking</a></h3></dt>
-<dl>
-<dt><a href="#l96">6.1: Benchmark 1: Accessing a proxy via crossroads or directly</a></dt>
-<dl>
-<dt><a href="#l97">6.1.1: Results</a></dt>
-<dt><a href="#l98">6.1.2: Discussion</a></dt>
-</dl>
-<dt><a href="#l99">6.2: Benchmark 2: Crossroads versus Linux Virtual Server (LVS)</a></dt>
-<dl>
-<dt><a href="#l100">6.2.1: Environment</a></dt>
-<dt><a href="#l101">6.2.2: Tests and results</a></dt>
-</dl>
-</dl>
-<dt><h3><a href="#l102">7: Compiling and Installing</a></h3></dt>
-<dl>
-<dt><a href="#l103">7.1: Prerequisites</a></dt>
-<dt><a href="#l104">7.2: Compiling and installing</a></dt>
-<dt><a href="#l105">7.3: Configuring crossroads</a></dt>
-<dt><a href="#l106">7.4: A boot script</a></dt>
-<dl>
-<dt><a href="#l107">7.4.1: SysV Style Startup</a></dt>
-<dt><a href="#l108">7.4.2: BSD Style Startup</a></dt>
-<dt><a href="#l109">7.4.3: Linux-related</a></dt>
-</dl>
-
-<p><hr><p>
-<p>
-<a name="l1"></a>
-<h2>1: Introduction</h2>
-<a name="intro"></a>Crossroads is a daemon that basically accepts TCP connections at
-preconfigured ports, and given a list of 'back ends' distributes each
-incoming connection to one of the back ends, so that a client request
-is served. Additionally, crossroads maintains an internal
-administration of the back end connectivity: if a back end isn't
-usable, then the client request is handled using another back
-end. Crossroads will then periodically check whether a previously not
-usable back end has come to life yet. Also, crossroads can select back
-ends by estimating the load, so that balancing is achieved.
-<p>
-Using this approach, crossroads serves as load balancer and fail over
-utility. Crossroads will very likely not be as reliable as hardware
-based balancers, since it always will require a server to run on. This
-server, in turn, may become a new Single Point of Failure (SPOS).
-However, in situations where cost efficiency is an issue, crossroads
-may be a good choice. Furthermore, crossroads can be deployed in
-situations where a hardware based balancing already exists and
-augmenting service reliability is needed. Or, crossroads may be run
-off a diskless system, which again improves reliability of the
-underlying hardware.
-<p>
-This document describes how to use crossroads, how to configure it in
-order to increase the reliability of your systems, and how to compile
-the program from its sources. This document is also available
-in <a href="crossroads.pdf">PDF</a> format.
-<p>
-<a name="l2"></a>
-<h3>1.1: Obtaining Crossroads</h3>
-<p>
-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.
-<p>
-<li> <a href="http://freshmeat.net/projects/crossr">http://freshmeat.net/projects/crossr</a> is the
- Freshmeat announcement page.
-<p>
-<li> <a href="svn://svn.e-tunity.com/crossroads">svn://svn.e-tunity.com/crossroads</a> is the SVN
- repository; anonymous reading (fetching) is allowed. In order
- to commit changes, mail the author or maintainer for credentials.</ul>
-<p>
-<a name="l3"></a>
-<h3>1.2: Reporting bugs</h3>
-<p>
-Crossroads was thoroughly tested and proven to work. However, on
-particular Unices with particular needs and network particularities,
-bugs may occur.
-<p>
-In such cases you can contact the maintainer to ask for
-assistance. Visit the site <a href="http://crossroads.e-tunity.com">http://crossroads.e-tunity.com</a> for contact information. In questions
-or bug reports, always include the following:
-<p>
-<ul>
- <li> A description of the bug: when does it occur, what are
- the circumstances, what is the expected behavior, what is the
- observed behavior.
-<p>
-<li> The Crossroads configuration in the file <code>crossroads.conf</code>
-<p>
-<li> The version of Crossroads and all compile-time settings,
- obtained via <code>crossroads -C</code>.</ul>
-<p>
-<a name="l4"></a>
-<h3>1.3: Copyright and Disclaimer</h3>
-<p>
-Crossroads is distributed as-is, without assumptions of fitness or
-usability. You are free to use crossroads to your liking. It's free,
-and as with everything that's free: there's also no
-warranty. Crossroads is distibuted under the GNU General Public
-Licence, version 3. See <a href="http://crossroads.e-tunity.com">http://crossroads.e-tunity.com</a> for more
-information.
-<p>
-You are allowed to make modifications to the source code of
-crossroads, and you are allowed to (re)distribute crossroads, as long
-as you include this text, all sources, and if applicable: all your
-modifications, with each distribution.
-<p>
-While you are allowed to make any and all changes to the sources, I
-would appreciate hearing about them. If the changes concern new
-functionality or bugfixes, then I'll include them in a next release,
-stating full credits. If you want to seriously contribute (to which
-you are heartily encouraged), then mail me and I'll get you access to
-the Crossroads SVN repository, so that you can update and commit as
-you like.
-<p>
-<a name="l5"></a>
-<h3>1.4: Terminology</h3>
-<p>
-Throughout this document, the following terms are used: (Many
-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>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>Headers</strong><dd> or <strong>header lines</strong> are specific parts of an HTTP
- message. Crossroads has directives to add or modify
- headers that are part of the request that a browser sends
- to server, or those that are part of the server.
- <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="l6"></a>
-<h3>1.5: Porting Issues</h3>
-<p>
-This section lists some caveats when converting Crossroads
-configurations to new versions. Given the changes of the syntax of the
-configuration file of Crossroads, existing configuration files may
-need to be made suitable for new versions.
-<p>
-<a name="l7"></a>
-<strong>1.5.1: Porting issues for pre-1.80 installations</strong>
-<p>
-Please be aware that as of version 1.80, the Crossroads
- configuration file may be located in an 'etc' directory along the
- path where Crossroads was started. E.g., if the Crossroads binary
- is <code>/usr/local/bin/crossroads</code>, then Crossroads will read the
- configuration file <code>/usr/local/etc/crossroads.conf</code> before
- defaulting to <code>/etc/crossroads.conf</code>. When installing
- configurations to such 'etc' directories along the path, be sure
- to remove stale configuration files. Crossroads will only parse
- one primary configuration file.
-<p>
-<a name="l8"></a>
-<strong>1.5.2: Porting issues for pre-1.63 installations</strong>
-<p>
-The parser of Crossroads 1.63 has become even
- stricter. HTTP-related commands, such as <code>addclientheader</code>, may
- only occur when the service type is <code>http</code>.
-<p>
-Previously such directives were allowed, albeit they would be
- ineffective.
-<p>
-<a name="l9"></a>
-<strong>1.5.3: Porting issues for pre-1.50 installations</strong>
-<p>
-As of version 1.50, the command <code>crossroads tell</code> has been
- changed. To set a state, the command must be used as follows:
-<p>
-<center><code>crossroads</code> <code>tell</code> <em>service</em> <em>backend</em> <code>state</code>
- <em>newstate</em></center>
-<p>
-The keyword <code>state</code> was added. This is because <code>crossroads
- tell</code> can also set a new server address; in that case the keyword
- <code>server</code> is required. If you have automatic health checkers or
- the like that change the back end states, please modify the
- commands to suit this.
-<p>
-<a name="l10"></a>
-<strong>1.5.4: Porting issues for pre-1.43 installations</strong>
-<p>
-As of version 1.43, the shared memory key calculations are based
- on a different algorithm. This key is e.g. necessary when starting
- and stopping Crossroads; in both actions, the key must be computed
- in the same way.
-<p>
-Therefore, when upgrading Crossroads, make sure that you stop a
- running Crossroads daemon using the same binary that started
- it. After this, install a new binary, and start the daemon using
- the new binary.
-<p>
-(Incidentally, this is always a good idea, but especially so when
- the 'old' binary is pre-1.43 and the 'new' one is post-1.43.)
-<p>
-Furthermore, shell-style comment is no longer supported as of
- 1.43. The reason is that 1.43 introduces the hash mark as a
- preprocessor token (in <code>#include</code>, <code>#define</code>). Therefore, if
- your configuration files use shell-style comment, please convert
- this to <strong>C</strong> or <strong>C++</strong> style.
-<p>
-<a name="l11"></a>
-<strong>1.5.5: Porting issues for pre-1.21 installations</strong>
-<p>
-As of version 1.21, the event-hook directives <code>onsuccess</code> and
- <code>onfailure</code> no longer exists.
-<p>
-<ul>
- <li> Please replace <code>onsuccess</code> by <code>onstart</code>;
- <li> Please replace <code>onfailure</code> bu <code>onfail</code>;
- <li> Note that there is a new hook <code>onend</code>.</ul>
-<p>
-The commands that are run via <code>onstart</code>, <code>onend</code> or <code>onfail</code>
- are subject to format expansion; e.g., <code>%1w</code> is expanded to the
- weight of the first back end, etc.. See section <a href="crossroads.html#config">4</a> for details.
-<p>
-<a name="l12"></a>
-<strong>1.5.6: Porting issues for pre-0.26 installations</strong>
-<p>
-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>
-<p>
-Therefore when converting configuration files to the new syntax,
- the above keywords must be changed. (The reason for these changes
- is that 0.26 introduces <em>sticky HTTP sessions</em> that span
- multiple TCP connections, and the term
- <em>session</em> is used strictly in that sense -- and no longer for a
- TCP connection.)
-<p>
-<a name="l13"></a>
-<strong>1.5.7: Porting issues for pre-1.08 installations</strong>
-<p>
-As of version 1.08, the following directives no longer are
- supported:
-<p>
-<ul>
- <li> <code>insertstickycookie</code> was replaced by the more generic
- directive <code>addclientheader</code>. E.g., instead of <br>
- <code>insertstickycookie "XRID=100; Path=/";</code> <br>
- the syntax is now <br>
- <code>addclientheader "Set-Cookie: XRID=100; Path=/";</code>
-<p>
-<li> <code>insertrealip</code> was replaced by the more generic
- directive <code>setserverheader</code>. E.g., instead of <br>
- <code>insertrealip on;</code> <br>
- the syntax is now <br>
- <code>setserverheader "XR-Real-IP: %r";</code> <br>
- This incidentally also makes it possible to change the header
- name (here: <code>XR-Real-IP</code>).</ul>
-<p>
-<a name="l14"></a>
-<h2>2: Installation for the impatient</h2>
-<a name="impatient"></a>
-For the impatient, here's the very-quick-but-very-superficial recipy
-for getting Crossroads up and running:
-<p>
-<ul>
-<p>
-<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>.
-<p>
-<li> Change-dir to a 'sources' directory on your system and
- 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>
-<p>
-<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>.
-<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>
-<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.
-<p>
-<li> Create a configuration file as e.g.
- <code>/etc/crossroads.conf</code>. (Other locations are permitted. See
- section <a href="crossroads.html#configuring">7.3</a> for details.) In it state something
- like:
-<p>
-<pre>
-service www {
- port 80;
- revivinginterval 15;
- backend one {
- server 10.1.1.100:80;
- }
- backend two {
- server 10.1.1.101:80;
- }
-}
-</pre>
-
-<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.
-<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.
-<p>
-<li> To monitor the status of Crossroads from the command
- line, type <code>crossroads status</code>.
-<p>
-<li> If you want to monitor Crossroads via a web front end,
- start the manager: type <code>crossroads-mgr start 1000</code>. Next
- point your browser to the machine where Crossroads is
- running, port 1000.
-</ul>
-<p>
-<a name="l15"></a>
-<h2>3: Using Crossroads</h2>
-<a name="using"></a><a name="l16"></a>
-<h3>3.1: The Balancer: crossroads</h3>
-<p>
-The Crossroads balancer is started from the commandline, and highly
-depends on the configuration file <code>crossroads.conf</code> (the default
-configuration file). It supports a number of flags (e.g., to overrule
-the location of the configuration file). The actual usage information
-is always obtained by typing <code>crossroads</code> without any arguments.
-Crossroads then displays the allowed arguments.
-<p>
-The installation (see section <a href="crossroads.html#installation">7</a>) installs also a
-second program called <code>crossroads-daemon</code>. This program is not meant
-to be started from the command line; it is administered through the
-front end <code>crossroads</code>.
-<p>
-<a name="l17"></a>
-<strong>3.1.1: General Commandline Syntax</strong>
-<p>
-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. The reason is that in
- the split second where the listener is stopped and a new one
- is not yet started, a new network connection won't be
- accepted. Running connections are however not hindered by a
- restart.
- <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</em> <code>state</code>
- <em>newstate</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 tel</code> <em>service backend</em> <code>server</code>
- <em>hostname:port</em> redefines the back end address of a
- running back end.
- <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.
-</ul>
-<p>
-<a name="l18"></a>
-<strong>3.1.2: Status Reporting from the Command Line</strong>
-<p>
-The command <code>crossroads status</code> shows a verbose human-readable
-report of how Crossroads is doing. When many services are configured,
-this can be a somewhat lengthy output. If you're interested in the
-overview of only one service, you can use <code>crossroads status</code>
-<em>servicename</em>, in which case the report will only be shown for the
-stated service.
-<p>
-Similarly, if you're interested only in the status of a given back end
-of a given service, use <code>crossroads service</code> <em>servicename</em>
-<em>backendname</em>.
-<p>
-The flag <code>-t</code> causes the status overview to be abbreviated and
-displayed in a parseable format. This flag can be used in automated
-scripts that check how Crossroads is doing; e.g., in health checking
-scripts. When <code>-t</code> is used, the format of the status reporter is as
-follows:
-<p>
-<ul>
- <li> Service health is reported on one line per service.
- <li> The first string on the line is the service name.
- <li> After this, a series follows of <em>backendname=state</em>,
- where the back end name is the configured name of the back
- end, and where state is e.g. <code>available</code>, <code>down</code>,
- <code>unavailable</code>, <code>waking</code>. The statuses may occur in caps.
- The series is repeated for all back ends of the given service.</ul>
-<p>
-The flag <code>-x</code> causes the overview to be presented as an XML
-document. This can be handy if you want to further automate the
-control over Crossroads, or if you want to show the status via the
-web. (See section <a href="crossroads.html#xmlstatus">5.15</a> for more information.)
-<p>
-The status reporter shows the number of running connections per back
-end, and the total of connections of the entire service. Due to
-technical reasons the total count can be one off. (There is a
-technical reason for this: the total counter gets updated at a
-different rate than separate back end counts. This may be fixed in a
-future release.)
-<p>
-<a name="l19"></a>
-<strong>3.1.3: Logging-related options</strong>
-<p>
-Two 'flags' of Crossroads are specifically logging-related. This
-section elaborates on these flags.
-<p>
-First, there's flag <code>-a</code>. When present, the start and end of
-activity is logged using statements like
-<p>
-<center><em>YYYY-MM-DD HH/MM/SS starting http from 61.45.32.189 to 10.1.1.1</em></center>
-<p>
-Similarly, there are 'ending' statements. Using this flag and
-scanning your logs for these statements may be helpful in quickly
-determining your system load.
-<p>
-Second, there's flag <code>-l</code>. This flag selects the 'facility' of
-logging and defaults to <code>LOG_DAEMON</code>. You can supply a number
-between 0 and 7 to flag <code>-l</code> to select <code>LOG_LOCAL0</code> to
-<code>LOG_LOCAL7</code>. This would separate the Crossroads-related logging
-from other streams. Here's a very short guide; please read your Unix
-manpages of <code>syslogd</code> for more information.
-<p>
-<ul>
- <li> First edit <code>/etc/syslog.conf</code> and add a line:
-<p>
-<pre>
-local7.* /var/log/crossroads.log
-</pre>
-
-<p>
-That instructs <code>syslogd</code> to send <code>LOG_LOCAL7</code> requests to the
- logfile <code>/var/log/crossroads.log</code>.
-<p>
-<li> Next, restart <code>syslogd</code>. On most Unices that's done by
- issuing <code>killall -1 syslogd</code>. (As a side-note, I tried this once
- on an Bull/AIX system, and the box just shut down. The <code>killall</code>
- command killed every process...)
-<p>
-<li> Now start <code>crossroads</code> with the flag <code>-l7</code>.
-<p>
-<li> Finally, monitor <code>/var/log/crossroads.log</code> for Crossroads'
- messages.</ul>
-<p>
-<a name="l20"></a>
-<strong>3.1.4: Reloading Configurations</strong>
-<p>
-Crossroads doesn't support the reloading of a configuration while
-running (such as other programs, e.g. Apache do). There are various
-technical reasons for this.
-<p>
-However, external lists of allowed or denied IP addresses can be
-reloaded by sending a signal -1 (<code>SIGHUP</code>) to Crossroads. See
-section <a href="crossroads.html#servicedef">4.3</a> for the details.
-<p>
-<a name="l21"></a>
-<h3>3.2: The Web Frontend: crossroads-mgr</h3>
-<p>
-A web front end for Crossroads is <code>crossroads-mgr</code>. Type
-<code>crossroads-mgr</code> without arguments to see the usage.
-<p>
-Normally the web interface is started like:
-<p>
-<center><code>crossroads-mgr start 1000</code></center>
-<p>
-where 1000 is a free TCP port. Note that <code>crossroads-mgr</code> must be
-started on the system where the balancer <code>crossroads</code> itself is
-running.
-<p>
-There are lots of other options that can be used with
-<code>crossroads-mgr</code>, see section <a href="crossroads.html#tips/webinterface">5.14</a>.
-<p>
-
-
-<a name="l22"></a>
-<h2>4: The configuration</h2>
-<a name="config"></a>The configuration that crossroads uses is normally stored in the file
-<code>crossroads.conf</code>, either in an 'etc' directory near the binary, or
-in <code>/etc/</code>. See section <a href="crossroads.html#configuring">7.3</a> for details.
-<p>
-The name of the configuration file can be overruled using the
-command line flag <code>-c</code>.
-<p>
-This section explains the syntax of the configuration file, and what
-all settings do.
-<p>
-<a name="l23"></a>
-<h3>4.1: General language elements</h3>
-<p>
-This section describes the general elements of the crossroads
-configuration language.
-<p>
-<a name="l24"></a>
-<strong>4.1.1: Empty lines, indentation and comments</strong>
-<p>
-Empty lines are of course allowed in the configuration. Also,
-indentation is irrelevant as far as processing is concerned, but is
-loosely inspired on a C-like style. So the following two examples are
-identical as far as Crossroads is concerned (thought the first one
-will be typically more readable):
-<p>
-<pre>
-/* Example one */
-options {
- tcpbuffersize 10240;
- logactivity on;
-}
-
-/* Example two */
-options {tcpbuffersize 10240
-;logactivity on;}
-</pre>
-
-<p>
-Crossroads recognizes the following comment formats:
-<p>
-<ul>
- <li> C-style, between <code>/*</code> and <code>*/</code>,
- <li> C++-style, starting with <code>//</code> and ending with the end
- of the text line.</ul>
-<p>
-Simply choose your favorite editor and use the comment that 'looks
-best'. (I favor C or C++ comment. My favorite editor <em>emacs</em>
-can be put in <code>cmode</code> and nicely highlight what's comment and what's
-not. And as a bonus it will auto-indent the configuration!)
-<p>
-<a name="l25"></a>
-<strong>4.1.2: Preprocessor directives</strong>
-<p>
-Similar to <strong>C</strong> or <strong>C++</strong>, the Crossroads grammar knows <code>#include</code>
-and <code>#define</code>. Both directives must start at the first column of the
-line (ie., the <code>#</code> sign must occur at the leftmost line
-position).
-<p>
-<ul>
- <li> <code>#include</code> <code>"</code><em>filename</em><code>"</code> includes the stated file
- name at the place of the statement.
- <li> <code>#define</code> <em>SYMBOL</em> <em>DEFINITION</em> defines <em>SYMBOL</em>
- as placeholder for <em>DEFINITION</em>.</ul>
-<p>
-For example, one may use the configuration:
-<p>
-<pre>
-#define SERVICEPORT 80
-service web {
- port SERVICEPORT;
- .
- . /* More statements follow here */
- .
-}
-</pre>
-
-<p>
-The <code>port</code> statement is then read as <code>port 80</code>.
-<p>
-The statement <code>#define</code> can also be very nicely used when trying out
-Crossroads configurations. Crossroads has a statement <code>verbosity</code>
-<code>true</code> that causes debugging information to be logged. Once a
-configuration has proven to work, you'll most likely want
-<code>verbosity</code> <code>false</code> so that overhead due to logging is
-avoided. This can be easily implemented using <code>#define</code>:
-<p>
-<pre>
-/* Set DEBUG to true or false;
- * true is for testing purposes,
- * false is for production */
-#define DEBUG true
-
-service web {
- verbosity DEBUG;
- .
- . /* More statements follow here */
- .
-}
-</pre>
-
-<p>
-<a name="l26"></a>
-<strong>4.1.3: Keywords, numbers, identifiers, generic strings</strong>
-<p>
-In a configuration file, statements are identified by <em>keywords</em>,
-which are reserved words. The list of the keywords of the Crossroads
-grammar is:
-<a name="keywords.yo"></a><code>service</code>
-<code>port</code>
-<code>verbosity</code>
-<code>maxconnections</code>
-<code>type</code>
-<code>any</code>
-<code>http</code>
-<code>backend</code>
-<code>server</code>
-<code>bindto</code>
-<code>connectiontimeout</code>
-<code>on</code>
-<code>off</code>
-<code>dispatchmode</code>
-<code>roundrobin</code>
-<code>random</code>
-<code>byduration</code>
-<code>bysize</code>
-<code>byconnections</code>
-<code>byorder</code>
-<code>byclientip</code>
-<code>over</code>
-<code>decay</code>
-<code>revivinginterval</code>
-<code>checkinterval</code>
-<code>retries</code>
-<code>shmkey</code>
-<code>weight</code>
-<code>onstart</code>
-<code>onfail</code>
-<code>backlog</code>
-<code>throughputlog</code>
-<code>trafficlog</code>
-<code>httptiminglog</code>
-<code>stickycookie</code>
-<code>addclientheader</code>
-<code>setclientheader</code>
-<code>appendclientheader</code>
-<code>addserverheader</code>
-<code>setserverheader</code>
-<code>appendserverheader</code>
-<code>allowfrom</code>
-<code>denyfrom</code>
-<code>allowfile</code>
-<code>denyfile</code>
-<code>externalhandler</code>
-<code>useraccount</code>
-<code>onend</code>
-<code>headerinspection</code>
-<code>deep</code>
-<code>shallow</code>
-<code>state</code>
-<code>available</code>
-<code>unavailable</code>
-<code>down</code>
-<code>options</code>
-<code>logactivity</code>
-<code>tcpbuffersize</code>
-<code>dnscachettl</code>
-<code>logfacility</code>
-<code>shmpermissions</code>
-<code>sloppyportbind</code>
-<code>leaveprocesstitle</code>
-<p>
-Many keywords require an <em>identifier</em> as the argument. E.g, a
-service has a unique name, which must start with a letter or
-underscore, followed by zero or more letters, underscores, or
-digits. E.g., in the statement <code>service myservice</code>, the keyword is
-<code>service</code> and the identifier is <code>myservice</code>.
-<p>
-Other keywords require a numeric argument. Crossroads knows only
-non-negative integer numbers, as in <code>port 8000</code>. Here, <code>port</code> is
-the keyword and <code>8000</code> is the number. Octal numbers are specified by
-prefixing a zero; e.g., <code>0644</code> is an octal number.
-<p>
-Yet other keywords require 'generic strings', such as hostname
-specifications or system commands. Such generic strings contain any
-characters (including white space) up to the terminating statement
-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>
-<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
-<code>true</code>, <code>yes</code> and <code>on</code> all mean the same and can be used
-interchangeably; as can the keywords <code>false</code>, <code>no</code> and <code>off</code>.
-<p>
-<a name="l27"></a>
-<h3>4.2: Daemon options</h3><a name="daemonoptions"></a>
-<p>
-Crossroads supports an optional block that defines run options for the
-daemon process. These options can be also be specified on the command line
-using flags.
-<p>
-The syntax of the options block is:
-<p>
-<pre>
-options {
- .
- . option statements (see below)
- .
-}
-</pre>
-
-<p>
-In the curly-brace block the following option statements can occur:
-<p>
-<ul>
- <li> <code>logactivity on;</code> or <code>off</code> Turns activity logging on
- or off. This is also controlled using the flag <code>-a</code>. The
- default is not to log network activity.
-<p>
-<li> <code>tcpbuffersize</code> <em>number</em> <code>;</code> This defines the size
- of network buffers. The default is 5120 bytes. This is also
- controlled using the flag <code>-B</code>.
-<p>
-<li> <code>dnscachettl</code> <em>number</em> <code>;</code> This controls the
- time-to-live of cached DNS entries, in seconds. Value zero
- means no caching and is the default. This is also controlled
- using the flag <code>-d</code>.
-<p>
-<li> <code>logfacility</code> <em>number</em> <code>;</code> This controls the
- logging facility. Values 0 to 7 select <code>LOG_LOCAL0</code> to
- <code>LOG_LOCAL7</code>. Any other value selects <code>LOG_DAEMON</code>, which
- is also the default. This is also controlled using the flag <code>-l</code>.
-<p>
-<li> <code>shmpermissions</code> <code>number</code> <code>;</code> This defines the
- permissions (for user, group and other) of the shared memory
- block. The number is most often specified as an octal value,
- e.g. <code>0644</code>, which is also the default. This is also
- controlled using the flag <code>-m</code>.
-<p>
-<li> <code>sloppyportbind on;</code> or <code>off</code> Turns on 'sloppy' port
- binding of the listener. When <code>on</code>, Crossroads will not
- treat port-busy conditions as fatal, but will wait and retry.
- The default is <code>off</code>. This is also controlled using flag
- <code>-s</code>.
-<p>
-<li> <code>leaveprocesstitle</code> <code>on;</code> or <code>off</code> When <code>on</code>, the
- process title of Crossroads is not modified, so that <code>ps</code>
- will show <code>crossroads-daemon</code>. The default is <code>off</code>:
- Crosroads will modify its process name into something like
- <em>crossroads - Sevice web: listening</em> or <em>crossroads -
- Service web: serving</em>.</ul>
-<p>
-<a name="l28"></a>
-<h3>4.3: Service definitions</h3> <a name="servicedef"></a>
-<p>
-Service definitions are blocks in the configuration file that
-state what is for each service. A service definition starts with
-<code>service</code>, followed by a unique identifier, and by statements in
-<code>{</code> and <code>}</code>. For example:
-<p>
-<pre>
-// Definition of service 'www':
-service www {
- ...
- ... // statements that define the
- ... // service named 'www'
- ...
-}
-</pre>
-
-<p>
-The configuration file can contain many service blocks, as long as the
-identifying names differ. The following list shows possible
-statements. Each statement must end with a semicolon, except for the
-<code>backend</code> statement, which has is own block (more on this later).
-<p>
-<a name="conf/port"></a><a name="l29"></a>
-<strong>4.3.1: port - Specifying the listen port</strong> <a name="confport - Specifying the listen port"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> The <code>port</code> statement defines to which TCP port a service
- 'listens'. E.g. <code>port 8000</code> says that this service will accept
- connections on port 8000.
-<p>
-Multiple services in one configuration cannot use the same port
- number, unless they both bind to specific (and different) IP
- addresses. See also the <code>bindto</code> statement.
- <p><dt><strong>Syntax:</strong><dd> <code>port</code> <em>number</em>
- <p><dt><strong>Default:</strong><dd> There is no default. This is a required setting.
- </dl>
-<p>
-<a name="conf/type"></a><a name="l30"></a>
-<strong>4.3.2: type - Defining the service type</strong> <a name="conftype - Defining the service type"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> The <code>type</code> statement defines how crossroads handles the stated
- service. There are currently two types: <code>any</code> and
- <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>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 such special features, use the type <code>any</code> (the
- default), even for HTTP protocols.
- <p><dt><strong>Syntax:</strong><dd> <code>type</code> <em>specifier</em>, where <em>specifier</em> is <code>any</code> or
- <code>http</code>
- <p><dt><strong>Default:</strong><dd> <code>any</code>
- </dl>
-<p>
-<a name="conf/headerinspection"></a><a name="l31"></a>
-<strong>4.3.3: headerinspection - are all HTTP headers inspected</strong> <a name="confheaderinspection - are all HTTP headers inspected"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> The <code>headerinspection</code> directive defines whether Crossroads
-must inspect all HTTP headers that are seen on one TCP connection, or
-only the first ones. There are two possible values for this directive:
-<code>deep</code> and <code>shallow</code>. In <code>deep</code> mode, all information that is
-seen on the TCP link is monitored
-and parsed, and all HTTP header blocks are analyzed and subject to
-directives such as <code>addclientheader</code>. In <code>shallow</code> mode, only the
-first header block that the server sends, and the first header block
-that forms the server's answer, are analyzed.
- <p><dt><strong>Syntax:</strong><dd> <code>headerinspection</code> <em>specifier</em>, where <em>specifier</em> is
-<code>deep</code> or <code>shallow</code>
- <p><dt><strong>Default:</strong><dd> <code>deep</code>
- </dl>
-<p>
-<a name="conf/bindto"></a><a name="l32"></a>
-<strong>4.3.4: bindto - Binding to a specific IP address</strong> <a name="confbindto - Binding to a specific IP address"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> The <code>bindto</code> statement is used in situations where crossroads
- should only listen to the stated port at a given IP address. E.g.,
- <code>bindto 127.0.0.1</code> causes crossroads to 'bind' the service only to
- the local IP address. Network connections from other hosts won't be
- serviced. By default, crossroads binds a service to all presently
- active IP addresses at the invoking host.
- <p><dt><strong>Syntax:</strong><dd> <code>bindto</code> <em>address</em>, where <em>address</em> is a numeric IP
- address, such as 127.0.0.1, or the keyword <code>any</code>.
- <p><dt><strong>Default:</strong><dd> <code>any</code>
- </dl>
-<p>
-<a name="conf/verbose"></a><a name="l33"></a>
-<strong>4.3.5: verbosity - Controlling debug output</strong> <a name="confverbosity - Controlling debug output"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> Verbosity statements come in two forms: <code>verbosity on</code> or
- <code>verbosity off</code>. When 'on', log messages to <code>/var/log/messages</code>
- are generated that show what's going on. (Actually, the
- messages go to <code>syslog(3)</code>, using facility <code>LOG_DAEMON</code> and
- priority <code>LOG_INFO</code>. In most (Linux) cases this will mean: output to
- <code>/var/log/messages</code>. On Mac OSX the messages go to
- <code>/var/log/system.log</code>.) The keyword <code>verbose</code> is an alias for
- <code>verbosity</code>.
- <p><dt><strong>Syntax:</strong><dd> <code>verbosity</code> <em>setting</em> or <code>verbose</code> <em>setting</em>, 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.
- <p><dt><strong>Default:</strong><dd> <code>off</code>
- </dl>
-<p>
-<a name="conf/dispatchmode"></a><a name="l34"></a>
-<strong>4.3.6: dispatchmode - How are back ends selected</strong> <a name="confdispatchmode - How are back ends selected"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> The dispatch mode controls how crossroads selects a back end from
- a list of active back ends. The below text shows the bare
- syntax. See section <a href="crossroads.html#howselected">5.2</a> for a textual explanation.
-<p>
-The settings can be:
-<p>
-<ul>
- <li> <code>dispatchmode roundrobin</code>: Simply the 'next in line' is
- chosen. E.g, when 3 back ends are active, then the usage
- series is 1, 2, 3, 1, 2, 3, and so on.
-<p>
-Roundrobin dispatching is the default method, when no
- <code>dispatchmode</code> statement occurs.
-<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.
-<p>
-<li> <code>dispatchmode bysize [ over</code> <em>connections</em> <code>]</code>:
- The next back end is the one
- that has transferred the least number of bytes. This
- selection mechanism assumes that the more bytes, the heavier
- the load.
-<p>
-The modifier <code>over</code> <em>connections</em> is optional. (The square
- brackets shown above are not part of the statement but
- indicate optionality.) When given,
- the load is computed as an average of the last stated number of
- connections. When this modifier is absent, then the load is
- computed over all connections since startup.
-<p>
-<li> <code>dispatchmode byduration [ over</code> <em>connections</em> <code>]</code>:
- The next back end is the one
- that served connections for the shortest time. This mechanism
- 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.
-<p>
-<li> <code>dispatchmode byorder</code>: The first back end is selected
- every time, unless it's unavailable. In that case the second
- is taken, and so on.
-<p>
-<li> <code>dispatchmode byclientip</code>: The client's IP address is
- 'hashed' into a number, which is used to pick a back end. The
- same client IP address will therefore always be dispatched to
- the same back end. When the back end of choice is down,
- <code>dispatchmode byconnections</code> is used.
-<p>
-<li> <code>dispatchmode externalhandler</code> <em>program arguments</em>:
- This is a special mode, where an external program is delegated
- the responsibility to say which back end should be used
- next. In this case, Crossroads will call the external program,
- and this will of course be slower than one of the 'built-in'
- dispatch modes. However, this is the ultimate escape when
- custom-made dispatch modes are needed.
-<p>
-The dispatch mode that uses an <code>externalhandler</code> is
- discussed separately in section <a href="crossroads.html#externalhandler">5.11</a>.</ul>
-<p>
-The selection algorithm is only used when clients are serviced that
- aren't part of a sticky HTTP session. This is the case during:
-<p>
-<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 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.
-<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
- estimate load from a network traffic stream, you have to choose an
- appropriate dispatch mode to optimize load balancing. In most cases,
- <code>roundrobin</code> or <code>byconnections</code> will do the job just fine.
- <p><dt><strong>Syntax:</strong><dd> <code>dispatchmode</code> <em>mode</em> (see above for the modes), optionally
- followed by <code>over</code> <em>number</em>, or when the <em>mode</em> is
- <code>externalhandler</code>, followed by <em>program</em>.
- <p><dt><strong>Default:</strong><dd> <code>roundrobin</code>
- </dl>
-<p>
-<a name="conf/revivinginterval"></a><a name="l35"></a>
-<strong>4.3.7: revivinginterval - Back end wakeup calls</strong> <a name="confrevivinginterval - Back end wakeup calls"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> A reviving interval definition is used when Crossroads
- determines that a back end is temporarily unavailable. This will
- happen when:
-<p>
-<ul>
- <li> The back end cannot be reached (network connection
- fails);
- <li> The network connection to the back end suddenly dies.</ul>
-<p>
-Once a reviving interval is set, Crossroads will periodically
- check the unavailable back end(s) to see whether they have woken up.
-<p>
-An example of the definition is <code>revivinginterval 10</code>. When this
- reviving interval is given, crossroads will check each 10 seconds
- whether unavailable back ends have woken up yet.
- <p><dt><strong>Syntax:</strong><dd> <ul>
- <li> <code>revivinginterval</code> <em>number</em>;
- <li> <code>revivinginterval</code> <em>number</em> <code>externalhandler</code>
- <em>program arguments</em>;</ul>
- The first form connects to a back end server. If the connection
- succeeds, then the back end is considered available. The second
- form activates an external program (see section
- <a href="crossroads.html#tips/periodic">5.3</a> for a description). The back end is marked
- available if the program's exit status is zero.
- <p><dt><strong>Default:</strong><dd> 0 (no wakeup calls)
- </dl>
-<p>
-<a name="conf/checkinterval"></a><a name="l36"></a>
-<strong>4.3.8: checkinterval - Periodic back end checks</strong> <a name="confcheckinterval - Periodic back end checks"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> When a check interval is stated, Crossroads will periodically
- probe back ends to determine whether available back ends are
- still there, and to see whether unavailable back ends have woken
- up yet.
-<p>
-An example is <code>checkinterval 10</code>. When this is stated,
- Crossroads will probe all back ends each 10 seconds.
- <p><dt><strong>Syntax:</strong><dd> <ul>
- <li> <code>checkinterval</code> <em>number</em>;
- <li> <code>checkinterval</code> <em>number</em> <code>externalhandler</code>
- <em>program arguments</em>;</ul>
- The first form checks bhy connecting to the back end server.
- If the connection succeeds, then the back end is considered
- available; otherwise the back end is considered unavailable.
-<p>
-The second form activates an external program (see section
- <a href="crossroads.html#tips/periodic">5.3</a> for a description). The back end is considered
- available if the program's exit status is zero; otherwise it is
- considered unavailable.
- <p><dt><strong>Default:</strong><dd> 0 (no periodic checks)
- </dl>
-<p>
-<a name="conf/maxconnections"></a><a name="l37"></a>
-<strong>4.3.9: maxconnections - Limiting concurrent clients at service level</strong> <a name="confmaxconnections - Limiting concurrent clients at service level"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> The maximum number of connections is specified using
- <code>maxconnections</code>. There is one argument; the number of concurrent
- established connections that may be active within one service.
-<p>
-'Throttling' the number of connections is a way of preventing Denial of
- Service (DOS) attacks. Without a limit, numerous network connections
- may spawn so many server instances, that the service ultimately breaks
- down and becomes unavailable.
-<p>
-Note that <code>maxconnections</code> is also allowed in a backend
- description block, in which case it limits the number of TCP
- connections to that particular back end.
- <p><dt><strong>Syntax:</strong><dd> <code>maxconnections</code> <em>number</em>, where the number specifies the
- maximum of concurrent connections to the service.
- <p><dt><strong>Default:</strong><dd> 0, meaning that all connections will be accepted.
- </dl>
-<p>
-<a name="conf/backlog"></a><a name="l38"></a>
-<strong>4.3.10: backlog - The TCP Back Log size</strong> <a name="confbacklog - The TCP Back Log size"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> The TCP back log size is a number that controls how many
- 'waiting' network connections may be queued, before a client simply
- cannot connect. The syntax is e.g. <code>backlog 5</code> to cause crossroads
- to have 5 waiting connections for 1 active connection.
- The backlog queue shouldn't be too
- high, or clients will experience timeouts before they can actually
- connect. The queue shouldn't be too small either, because clients
- would be simply rejected. Your mileage may vary.
- <p><dt><strong>Syntax:</strong><dd> <code>backlog</code> <em>number</em>
- <p><dt><strong>Default:</strong><dd> 0, which takes the operating system's default
- value for socket back log size.
- </dl>
-<p>
-<a name="conf/shmkey"></a><a name="l39"></a>
-<strong>4.3.11: shmkey - Shared Memory Access</strong> <a name="confshmkey - Shared Memory Access"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> Different Crossroads
- invocations must 'know' of each others activity. E.g, <code>crossroad
- status</code> must be able to get to the actual state information of all
- running services. This is internally implemented through shared
- memory, which is reserved using a key.
-<p>
-Normally crossroads will supply a shared memory key, based on the
- service name. In situations where this conflicts with existing
- keys (of other programs, having their own keys), you may supply a
- chosen value.
-<p>
-The actual key value doesn't matter much, as long as it's unique
- and as long as each invocation of crossroads uses it.
- <p><dt><strong>Syntax:</strong><dd> <code>shmkey</code> <em>number</em>
- <p><dt><strong>Default:</strong><dd> 0, which means that crossroads will 'guess' its
- own key, based on the service name.
- </dl>
-<p>
-<a name="conf/allow"></a><a name="l40"></a>
-<strong>4.3.12: allow* and deny* - Allowing or denying connections</strong> <a name="confallow* and deny* - Allowing or denying connections"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> Crossroads can allow or deny
- connections based on the IP address of a client. There are four
- directives that are relevant: <code>allowfrom</code>, <code>allowfile</code>,
- <code>denyfrom</code> and <code>denyfile</code>.
-<p>
-When using <code>allowfrom</code> and
- <code>denyfrom</code> then the IP addresses to allow or deny connections are
- stated in the configuration. When using <code>allowfile</code> and
- <code>denyfile</code> the allow or deny connections are stated in a
- separate file.
-<p>
-When <code>allow*</code> directives are used, then all connections are denied
- unless they match the stated allowed IP's. When <code>deny*</code> directives
- are used, then all connections are allowed unless they match the
- stated disallowed IP's. When denying and allowing is both used,
- then the Crossroads checks the deny list first.
-<p>
-The statements <code>allowfrom</code> and <code>denyfrom</code> are followed by a
- list of filter specifications. The statements <code>allowfile</code> and
- <code>denyfile</code> are followed by a filename; Crossroads will read
- filter specifications from those external files. In both cases,
- Crossroads obtains filter specifications and places them in its
- lists of allowed or denied IP addresses. The difference between
- specifying filters in the configuration file or in external
- files, is that Crossroads will reload the external files when it
- receives signal 1 (<code>SIGHUP</code>), as in <code>killall -1 crossroads</code>.
-<p>
-The filter specifications must obey the following syntax: they
- are series of space-separated strings, consisting of up to
- four numbers ranging from 0 to 255 and separated by a decimal
- sign. Optionally a slash follows, with a bitmask which is also a
- decimal number. For example, <code>127.0.0/24 10/8 192.168.2.1</code> is a
- setting that consists of three specifiers.
-<p>
-This is probably best explained by a few examples:
-<p>
-<ul>
- <li> <code>allowfrom 10/8;</code> will allow connections from
- <code>10.*.*.*</code> (a full Class A network). The mask <code>/8</code> means
- that the first 8 bits of the number (ie., only the <code>10</code>) are
- significant. On the last 3 positions of the IP address, all
- numbers are allowed. Given this directive, client connections
- from e.g. 10.1.1.1 and 10.2.3.4 will be allowed.
-<p>
-<li> <code>allowfrom 10.3/16;</code> will allow all IP addresses that
- start with <code>10.3</code>. The first 16 bits (i.e., the first 2
- numbers) are significant, the rest doesn't matter.
-<p>
-<li> <code>allowfrom 10.3.1/16;</code> is the same as above. The third
- byte of the IP address is superfluous because the netmask
- specifies that only the first 16 bits (2 numbers) are taken
- into account.
-<p>
-<li> <code>allowfrom 10.3.1.15;</code> allows traffic from only the
- specified IP address. There is no bitmask; all four numbers
- are relevant.
-<p>
-<li> <code>allowfrom 10.3.1.15 10.2/16;</code> allows traffic from one
- IP address <code>10.3.1.15</code> or from a complete Class B network
- <code>10.2.*.*</code>
-<p>
-<li> <code>allowfile /tmp/myfile.txt;</code> in combination with a file
- <code>/tmp/myfile.txt</code>, with the contents <code>10.3.1.15 10.2/16</code>,
- is the same as above.</ul>
-<p>
-When using ttt(allowfrom) and <code>denyfrom</code>, separate specifiers
- can be stated in one statement (separated by whitespace), or the
- whole statement can be repeated. E.g., the following two
- alternatives have the same effect:
-<p>
-<pre>
-/* Alternative 1: */
-allowfrom 10/8 192.168.1/24;
-
-/* Alternative 2: */
-allowfrom 10/8;
-allowfrom 192.168.1.24;
-</pre>
-
- <p><dt><strong>Syntax:</strong><dd> <ul>
- <li> <code>allowfrom</code> <em>filter-specificication(s)</em>
- <li> <code>denyfrom</code> <em>filter-specificication(s)</em>
- <li> <code>allowfile</code> <em>filename</em>
- <li> <code>denyfile</code> <em>filename</em></ul>
- <p><dt><strong>Default:</strong><dd> In absence of these statements, all client IP's are accepted.
- </dl>
-<p>
-<a name="conf/useraccount"></a><a name="l41"></a>
-<strong>4.3.13: useraccount - Limiting the effective ID of external processes</strong> <a name="confuseraccount - Limiting the effective ID of external processes"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> Using the directive <code>useraccount</code>, the effective user and group
- ID can be restricted. This comes into effect when Crossroads runs
- external commands, such as:
- <ul>
- <li> Hooks for <code>onstart</code>, <code>onend</code> or <code>onfail</code>;
- <li> External dispatchers, when <code>dispatchmode
- externalhandler</code> is in effect.</ul>
- Once a user name for external commands is specified, Crossroads
- assumes the associated user ID and group ID before running those
- commands.
- <p><dt><strong>Syntax:</strong><dd> <code>useraccount</code> <em>username</em>
- <p><dt><strong>Default:</strong><dd> None; when unspecified, external commands are run with the
- ID that was in effect when Crossroads was started.
- </dl>
-<p>
-<a name="l42"></a>
-<h3>4.4: Backend definitions</h3>
-<p>
-Inside the service definitions as are described in the previous
-section, <em>backend definitions</em> must also occur. Backend definitions
-are started by the keyword <code>backend</code>, followed by an identifier
-(the back end name) , and statements inside <code>{</code> and <code>}</code>:
-<p>
-<pre>
-service myservice {
- ...
- ... // statements that define the
- ... // service named 'myservice'
- ...
-
- backend mybackend {
- ...
- ... // statements that define the
- ... // backend named 'mybackend'
- ...
- }
-}
-</pre>
-
-<p>
-Each service definition must have at least one backend
-definition. There may be more (and probably will, if you want
-balancing and fail over) as long as the backend names differ.
-The statements in the backend definition blocks are described in the
-following sections.
-<p>
-Some directives (<code>stickycookie</code> etc.) only have effect when
-Crossroads treats the network traffic as a stream of HTTP messages;
-i.e., when the service is declared with <code>type http</code>. Incase of
-<code>type any</code>, the HTTP-specific directives have no effect.
-<p>
-<a name="conf/server.yo"></a><a name="l43"></a>
-<strong>4.4.1: server - Specifying the back end address</strong> <a name="confserver - Specifying the back end address"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> Each back end must be identified by the network name
- (server name) where it is located. For example: <code>server
- 10.1.1.23</code>, or <code>server web.mydomain.org</code>. A TCP port specifier
- can follow the server name, as in <code>server
- web.mydomain.org:80</code>. <strong>Note that</strong> resolved host names can be
- cached by Crossroads. (The DNS cache timeout can be
- controlled using the invocation flag <code>-d</code>.)
- <p><dt><strong>Syntax:</strong><dd> <ul>
- <li> <code>server</code> <em>servername</em>, where <em>servername</em> is a
- network name or IP address. In this case a separate <code>port</code>
- statement must be used to define the TCP port;
- <li> <code>server</code> <em>servername:port</em></ul>
- <p><dt><strong>Default:</strong><dd> There is no default. This is a required setting.
- </dl>
-<p>
-<a name="conf/backendport.yo"></a><a name="l44"></a>
-<strong>4.4.2: port - Specifying a back end port</strong> <a name="confport - Specifying a back end port"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> Back ends must be known by their host name and a port. Both can
- be simultaneously specified in a <code>server</code> statement. When the
- <code>server</code> statement specifies a host name only, then a <code>port</code>
- statement must be used to specify the port.
- <p><dt><strong>Syntax:</strong><dd> <code>port</code> <em>number</em>
- <p><dt><strong>Default:</strong><dd> There is no default for the port. It must be specified either
- using <code>server</code> or using <code>port</code>.
- </dl>
-<p>
-<a name="conf/verbose-backend.yo"></a><a name="l45"></a>
-<strong>4.4.3: verbosity - Controlling verbosity at the back end level</strong> <a name="confverbosity - Controlling verbosity at the back end level"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> Similar to <code>service</code> specifications, a
- <code>backend</code> can have its own verbosity (<code>on</code> or <code>off</code>). When
- <code>on</code>, traffic to and fro this back end is reported.
- <p><dt><strong>Syntax:</strong><dd> <ul>
- <li> <code>verbosity</code> <em>setting</em>, or
- <li> <code>verbose</code> <em>setting</em>, where <em>setting</em> is <code>true</code>,
- <code>yes</code> or <code>on</code>, or <code>false</code>, <code>no</code>, <code>off</code> to turn it
- off.</ul>
- <p><dt><strong>Default:</strong><dd> <code>off</code>
- </dl>
-<p>
-<a name="conf/retries.yo"></a><a name="l46"></a>
-<strong>4.4.4: retries - Specifying allowed failures</strong> <a name="confretries - Specifying allowed failures"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> Back ends that are 'flaky' or on a less reliable network can be
- marked as unavailable after not just one failure, but after
- e.g. three. You can use this configuration if you suspect that
- spurious errors cause otherwise 'good' back ends to be marked as
- unavailable, while they in fact still could be used.
- <p><dt><strong>Syntax:</strong><dd> <code>retries</code> <em>number</em>; where <em>number</em> is the threshold of bad
- connections. Once exceeded, Crossroads will mark a back end as
- unavailable.
- <p><dt><strong>Default:</strong><dd> 1; a back end is assumed to be unavailable after the first bad
- connection.
- </dl>
-<p>
-<a name="conf/maxcon-client.yo"></a><a name="l47"></a>
-<strong>4.4.5: maxconnections - Limiting the connections to a back end</strong> <a name="confmaxconnections - Limiting the connections to a back end"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> The directive <code>maxconnections</code> limits the number of allowed
- connections to this client.
- Note that this directive can also occur on the level of a service
- block, in which case it limits the overall number of connections.
-<p>
-<strong>Futhermore note</strong> that this directive cannot be used when an external
- dispatcher is in effect. In such cases, the external dispatcher has
- full control over backend selection.
- <p><dt><strong>Syntax:</strong><dd> <code>maxconnections</code> <em>number</em> <code>;</code>
- <p><dt><strong>Default:</strong><dd> 0; meaning no limit
- </dl>
-<p>
-<a name="conf/weight"></a><a name="l48"></a>
-<strong>4.4.6: weight - When a back end is more equal than others</strong> <a name="confweight - When a back end is more equal than others"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> To influence how backends are selected, a backend can specify its
- 'weight' in the process. The higher the weight, the less likely a
- back end will be chosen. The default is 1.
-<p>
-The weighing mechanism only applies to the dispatch modes
- <code>random</code>, <code>byconnections</code>, <code>bysize</code> and <code>byduration</code>.
- The weight is in fact a penalty factor. E.g., if backend A has
- <code>weight 2</code> and backend B has <code>weight 1</code>, then backend B will
- be selected all the time, until its usage parameter is twice as
- large as the parameter of A. Think of it as a 'sluggishness'
- statement.
- <p><dt><strong>Syntax:</strong><dd> <code>weight</code> <em>number</em>; the higher the number, the more 'sluggish'
- a back end is
- <p><dt><strong>Default:</strong><dd> 1; all back ends have equal weight.
- </dl>
-<p>
-<a name="conf/decay"></a><a name="l49"></a>
-<strong>4.4.7: decay - Levelling out activity of a back end</strong> <a name="confdecay - Levelling out activity of a back end"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> To make sure that a 'spike' of activity doesn't
- influence the perceived load of a back end forever, you may
- specify a certain decay. E.g, the statement <code>decay 10</code> makes
- sure that the load that crossroads computes for this back end (be
- it in seconds or in bytes) is decreased by 10% each time that
- <strong>an other</strong> back end is hit. Decays are not applied to the count
- of concurrent connections.
-<p>
-This means that when a given back end is hit, then its usage data
- of the transferred bytes and the connection duration are updated
- using the actual number of bytes and actual duration. However,
- when a different back end is hit, then the usage data are
- decreased by the specified decay.
- <p><dt><strong>Syntax:</strong><dd> <code>decay</code> <em>number</em>, where <em>number</em> is a percentage that
- decreases the back end usage data when other back ends are
- hit.
- <p><dt><strong>Default:</strong><dd> 0, meaning that no decay is applied to usage statistics.
- </dl>
-<p>
-<a name="conf/state"></a><a name="l50"></a>
-<strong>4.4.8: state - Setting an initial back end state</strong> <a name="confstate - Setting an initial back end state"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> Using the <code>state</code> directive a back end can be 'primed' with an
- initial state. The keyword <code>state</code> can be followed by
- <code>available</code>, <code>unavailable</code> or <code>down</code>. Back ends marked
- <code>unavailable</code> are excluded as candidates, but are checked when
- a <code>revivinginterval</code> or a <code>checkinterval</code> is used. Back ends
- marked <code>down</code> are excluded and never re-checked.
- <p><dt><strong>Syntax:</strong><dd> <ul>
- <li> <code>state</code> <em>specifier</em> <code>;</code>
- <li> where <em>specifier</em> is one of <code>available</code>,
- <code>unavailable</code> or <code>down</code></ul>
- <p><dt><strong>Default:</strong><dd> <code>available</code>, meaning that a back end is a candidate for
- initial dispatching.
- </dl>
-<p>
-<a name="conf/onhooks"></a><a name="l51"></a>
-<strong>4.4.9: onstart, onend, onfail - Action Hooks</strong> <a name="confonstart, onend, onfail - Action Hooks"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> The three directives <code>onstart</code>, <code>onend</code> and <code>onfail</code> can be
- specified to start system commands (external programs) when a
- connection to a back end starts, fails or ends:
- <ul>
- <li> <code>onstart</code> commands will be run when Crossroads
- successfully connects to a back end, and starts servicing;
- <li> <code>onend</code> commands will be run when a (previously
- established) connection stops;
- <li> <code>onfail</code> commands will be run when Crossroads tries to
- contact a back end to serve a client, but the back end can't
- be reached.</ul>
-<p>
-The format is always <code>on</code><em>type</em> <em>command</em>. The <em>command</em>
- is an external program, optionally followed by arguments. The
- command is expanded according to the following table:
-<p>
-<ul>
-<p>
-<li> <code>%a</code> is the availability of the current back end, when
- a current back end is established. <code>%1a</code> is the
- availability of the first back end (0 when unavailable, 1 if
- available); <code>%2a</code> is the availability of the second back
- end, and so on.
-<p>
-<li> <code>%b</code> is the name of the current back end, when one is
- established. <code>%1b</code> is the name of the first back end,
- <code>%2b</code> of the second back end, and so on.
-<p>
-<li> <code>%e</code> is the count of seconds since start of epoch
- (January 1st 1970 GMT). <code>%60e</code> is the count since start of
- epoch plus 60, so this is a 1 minute offset into the future.
-<p>
-<li> <code>%g</code> is a "GMT-string" representation of the current
- time, in the format <em>monthname, day year hh:mm:ss</em>. This
- format is used in e.g. cookie expiry. <code>%600g</code> is the same
- representation but of a moment 600 seconds in the future (10
- minutes).
-<p>
-<li> <code>%h</code> is the host name of the current back end. <code>%1h</code>
- is the host name of the first back end, <code>%2h</code> of the second
- back end, and so on.
-<p>
-<li> <code>%l</code> is the duration of the last successful connection
- in seconds, concerning the current back end. <code>%1l</code> is the
- duration of the connection to back end one, and so on. Note
- that <code>%l</code> refers only to the last successful connections.
- Unsuccessful connection attempts to back ends do not change
- the value.
-<p>
-<li> <code>%p</code> is the TCP port of the current back end. <code>%1p</code>
- is the TCP port of the first back end, <code>%2p</code> of the second
- back end, and so on.
-<p>
-<li> <code>%P</code> is the process ID of the Crossroads handler that
- handled this request. For debugging only.
-<p>
-<li> <code>%r</code> is the IP address of the connecting client.
-<p>
-<li> <code>%s</code> is the name of the current service that the client
- connected to.
-<p>
-<li> <code>%t</code> is the current local time in ANSI format, in
- <em>YYYY-MM-DD/hhh:mm:ss</em>. <code>%1800s</code> is an ANSI stamp of a
- moment 1800 seconds in the future (half an hour).
-<p>
-<li> <code>%T</code> is the current GMT time in ANSI format. <code>%10T</code>
- offsets this 10 seconds into the future.
-<p>
-<li> <code>%v</code> is the Crossroads version.
-<p>
-<li> <code>%w</code> is the weight factor of the current back
- end. <code>%1w</code> is the weight factor of the first back end, etc..
-<p>
-<li> Any other chararacter following a <code>%</code> sign is taken
- literally; e.g. <code>%z</code> is just a z.</ul>
-<p>
-<p><dt><strong>Syntax:</strong><dd> The syntax of the commands is as follows.
-<p>
-<ul>
- <li> <code>onstart</code> <em>commandline</em>
- <li> <code>onend</code> <em>commandline</em>
- <li> <code>onfail</code> <em>commandline</em>
- <li> <code>onsuccess</code> <em>commandline</em></ul>
- <p><dt><strong>Default:</strong><dd> There is no default. Normally no external programs are run upon
- connection, success or failure of a back end.
- </dl>
-<p>
-<a name="conf/trafficlog"></a><a name="l52"></a>
-<strong>4.4.10: trafficlog and throughputlog - Debugging and Performance Aids</strong> <a name="conftrafficlog and throughputlog - Debugging and Performance Aids"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> Two directives are available
- to log network traffic to files. They are <code>trafficlog</code> and
- <code>throughputlog</code>.
-<p>
-The <code>trafficlog</code> statement causes all traffic to be logged in
- hexadecimal format. Each line is prefixed by <code>B</code> or <code>C</code>,
- depending on whether the information was received from the back
- end or from the client.
-<p>
-The <code>throughputlog</code> statement writes shorthand transmissions to
- its log, accompanied by timings and the number of bytes each
- transmission was able to read or write in one chunk.
- <p><dt><strong>Syntax:</strong><dd> The syntax is:
-<p>
-<ul>
- <li> <code>trafficlog</code> <em>filename</em> <code>;</code>
- <li> <code>throughputlog</code> <em>filename</em> <code>;</code></ul>
- <p><dt><strong>Default:</strong><dd> none
- </dl>
-<p>
-<a name="conf/httptiminglog"></a><a name="l53"></a>
-<strong>4.4.11: httptiminglog - Timing debugging in HTTP mode</strong> <a name="confhttptiminglog - Timing debugging in HTTP mode"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> The directive <code>httptiminglog</code> turns on logging of HTTP mode
- timing. There must be one argument, the filename where the timings
- are written to. Turning on this option will slow down processing,
- but may be helpful in finding out where delays are caused.
- <p><dt><strong>Syntax:</strong><dd> The syntax is:
-<p>
-<ul>
- <li> <code>httptiminglog</code> <em>filename</em> <code>;</code>
- <li> Where <em>filename</em> is the output file, e.g.
- <code>/tmp/timings.log</code></ul>
- <p><dt><strong>Default:</strong><dd> none
- </dl>
-<p>
-<a name="conf/stickycookie"></a><a name="l54"></a>
-<strong>4.4.12: stickycookie - Back end selection with an HTTP cookie</strong> <a name="confstickycookie - Back end selection with an HTTP cookie"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> The directive <code>stickycookie</code> <em>value</em>
- causes Crossroads to unpack clients' requests, to check for
- <em>value</em> in the cookies. When found, the message is routed to the
- back end having the appropriate <code>stickycookie</code> directive.
-<p>
-E.g., consider the following configuration:
-<p>
-<pre>
-service ... {
- ...
- backend one {
- ...
- stickycookie "BalancerID=first";
- }
- backend two {
- ...
- stickycookie "BalancerID=second";
- }
-}
-</pre>
-
-<p>
-When clients' messages contain cookies named <code>BalancerID</code> with
- the value <code>first</code>, then such messages are routed to backend
- <code>one</code>. When the value is <code>second</code> then they are routed to the
- backend <code>two</code>.
-<p>
-There are basically to provide such cookies to a browser. First, a
- back end can insert such a cookie into the HTTP response. E.g.,
- the webserver of back end <code>one</code> might insert a cookie named
- <code>BalancerID</code>, having value <code>first</code>.
- Second, Crossroads can insert such cookies using a carefully
- crafted directive <code>addclientheader</code>.
- <p><dt><strong>Syntax:</strong><dd> <code>stickycookie</code> <em>cookievalue</em>
- <p><dt><strong>Default:</strong><dd> There is no default.
- </dl>
-<p>
-<a name="conf/addclientheader"></a><a name="l55"></a>
-<strong>4.4.13: HTTP Header Modification Directives</strong> <a name="confHTTP Header Modification Directives"></a>
- <dl>
- <p><dt><strong>Description:</strong><dd> Crossroads understands the following
- header modification directives: <code>addclientheader</code>,
- <code>appendclientheader</code>, <code>setclientheader</code>, <code>addserverheader</code>,
- <code>appendserverheader</code>, <code>setserverheader</code>.
-<p>
-The directive names always consist of
- <em>Action</em><em>Destination</em><code>header</code>, where:
-<p>
-<ul>
- <li> The action is <code>add</code>, <code>append</code> or <code>insert</code>.
-<p>
-<ul>
- <li> Action <code>add</code> adds a header, even when headers with
- the same name already are present in an HTTP
- message. Adding headers is useful for e.g. <code>Set-Cookie</code>
- headers; a message may contain several of such headers.
-<p>
-<li> Action <code>append</code> adds a header if it isn't present
- yet in an HTTP message. If such a header is already
- present, then the value is appended to the pre-existing
- header. This is useful for e.g. <code>Via</code> headers. Imagine
- an HTTP message with a header <code>Via: someproxy</code>. Then the
- directive <code>appendclientheader "Via: crossroads"</code> will
- rewrite the header to <code>Via: someproxy; crossroads</code>.
-<p>
-<li> Action <code>set</code> overwrites headers with the same
- name; or adds a new header if no pre-existing is found.
- This is useful for e.g. <code>Host</code> headers.</ul>
-<p>
-<li> The destination is one of <code>client</code> or <code>server</code>. When
- the destination is <code>server</code>, then Crossroads will apply such
- directives to HTTP messages that originate from the browser
- and are being forwarded to back ends. When the destination is
- <code>client</code>, then Crossroads will apply such directives to
- backend responses that are shuttled to the browser.</ul>
-<p>
-The format of the directives is e.g. <code>addclientheader
- "X-Processed-By: Crossroads"</code>. The directives expect one
- argument; a string, consisting of a header name, a colon, and a
- header value. As usual, the directive must end with a semicolon.
-<p>
-The header value may contain one of the following formatting
- directives:
-<p>
-<ul>
-<p>
-<li> <code>%a</code> is the availability of the current back end, when
- a current back end is established. <code>%1a</code> is the
- availability of the first back end (0 when unavailable, 1 if
- available); <code>%2a</code> is the availability of the second back
- end, and so on.
-<p>
-<li> <code>%b</code> is the name of the current back end, when one is
- established. <code>%1b</code> is the name of the first back end,
- <code>%2b</code> of the second back end, and so on.
-<p>
-<li> <code>%e</code> is the count of seconds since start of epoch
- (January 1st 1970 GMT). <code>%60e</code> is the count since start of
- epoch plus 60, so this is a 1 minute offset into the future.
-<p>
-<li> <code>%g</code> is a "GMT-string" representation of the current
- time, in the format <em>monthname, day year hh:mm:ss</em>. This
- format is used in e.g. cookie expiry. <code>%600g</code> is the same
- representation but of a moment 600 seconds in the future (10
- minutes).
-<p>
-<li> <code>%h</code> is the host name of the current back end. <code>%1h</code>
- is the host name of the first back end, <code>%2h</code> of the second
- back end, and so on.
-<p>
-<li> <code>%l</code> is the duration of the last successful connection
- in seconds, concerning the current back end. <code>%1l</code> is the
- duration of the connection to back end one, and so on. Note
- that <code>%l</code> refers only to the last successful connections.
- Unsuccessful connection attempts to back ends do not change
- the value.
-<p>
-<li> <code>%p</code> is the TCP port of the current back end. <code>%1p</code>
- is the TCP port of the first back end, <code>%2p</code> of the second
- back end, and so on.
-<p>
-<li> <code>%P</code> is the process ID of the Crossroads handler that
- handled this request. For debugging only.
-<p>
-<li> <code>%r</code> is the IP address of the connecting client.
-<p>
-<li> <code>%s</code> is the name of the current service that the client
- connected to.
-<p>
-<li> <code>%t</code> is the current local time in ANSI format, in
- <em>YYYY-MM-DD/hhh:mm:ss</em>. <code>%1800s</code> is an ANSI stamp of a
- moment 1800 seconds in the future (half an hour).
-<p>
-<li> <code>%T</code> is the current GMT time in ANSI format. <code>%10T</code>
- offsets this 10 seconds into the future.
-<p>
-<li> <code>%v</code> is the Crossroads version.
-<p>
-<li> <code>%w</code> is the weight factor of the current back
- end. <code>%1w</code> is the weight factor of the first back end, etc..
-<p>
-<li> Any other chararacter following a <code>%</code> sign is taken
- literally; e.g. <code>%z</code> is just a z.</ul>
-<p>
-The following examples show common uses of header modifications.
-<p>
-<dl>
- <p><dt><strong>Enforcing session stickiness:</strong><dd> By combining
- <code>stickycookie</code> and <code>addclientheader</code>, HTTP session
- stickiness is enforced. Consider the following configuration:
-<p>
-<pre>
-service ... {
- ...
- backend one {
- ...
- addclientheader "Set-Cookie: BalancerID=first; path=/";
- stickycookie "BalancerID=first";
- }
- backend two {
- ...
- addclientheader "Set-Cookie: BalancerID=second; path=/";
- stickycookie "BalancerID=second";
- }
-}
-</pre>
-
-<p>
-The first request of an HTTP session is balanced to either
- backend <code>one</code> or <code>two</code>. The server response is enriched
- using <code>addclientheader</code> with an appropriate cookie. A
- subsequent request from the same browser now has that cookie
- in place; and is therefore sent to the same back end where the
- its predecessors went.
-<p>
-The header which is sent to the client to inject a cookie, can
- furthermore be expanded to specify a timeout:
-<p>
-<pre>
-addclientheader "Set-Cookie: BalancerID=second; path=/; expires=%1800g";
-</pre>
-
-<p>
-The format specifier <code>%1800g</code> outputs a GMT-string date 1800
- seconds in the future (half an hour from now).
-<p>
-<p><dt><strong>Hiding the server software version:</strong><dd> Many servers
- (e.g. Apache) advertize their version, as in <code>Server: Apache
- 1.27</code>. This potentially provides information to attackers. The
- following configuration hides such information:
-<p>
-<pre>
-service ... {
- ...
- backend one {
- ...
- setclientheader "Server: WWW-Server";
- }
-}
-</pre>
-
-<p>
-<p><dt><strong>Informing the server of the clients' IP address:</strong><dd> Since
- Crossroads sits 'in the middle' between a client and a back
- end, the back end perceives Crossroads as its client. The
- following sends the true clients' IP address to the server, in
- a header <code>X-Real-IP</code>:
-<p>
-<pre>
-service ... {
- ...
- backend one {
- ...
- setserverheader "X-Real-IP: %r";
- }
-}
-</pre>
-
-<p>
-<p><dt><strong>Keep-Alive Downgrading:</strong><dd> The directives
- <code>setclientheader</code> and <code>setserverheader</code> also play a key
- role in downgrading Keep-Alive connections to
- 'single-shot'. E.g., the following configuration makes sure
- that no Keep-Alive connections occur.
-<p>
-<pre>
-service ... {
- ...
- backend one {
- ...
- setserverheader "Connection: close";
- setclientheader "Connection: close";
- }
-}
-</pre>
-</dl>
- <p><dt><strong>Syntax:</strong><dd> <ul>
- <li> <code>addclientheader</code> <em>Headername: headervalue</em> to add a
- header in the traffic towards the client, even when another
- header <em>Headername</em> exists;
- <li> <code>appendclientheader</code> <em>Headername: headervalue</em> to
- append <em>headervalue</em> to an existing header <em>Headername</em>
- in the traffic towards the client,
- or to add the whole header alltogether;
- <li> <code>setclientheader</code> <em>Headername: headervalue</em> to
- overwrite an existing header in the traffic towards the
- client, or to add such a header;
- <li> <code>addserverheader</code> <em>Headername: headervalue</em> to add a
- header in the traffic towards the server, even when another
- header <em>Headername</em> exists;
- <li> <code>appendserverheader</code> <em>Headername: headervalue</em> to
- append <em>headervalue</em> to an existing header <em>Headername</em>
- in the traffic towards the server,
- or to add the whole header alltogether;
- <li> <code>setserverheader</code> <em>Headername: headervalue</em> to
- overwrite an existing header in the traffic towards the
- server, or to add such a header.</ul>
- <p><dt><strong>Default:</strong><dd> There is no default.
- </dl>
-<p>
-<a name="l56"></a>
-<h2>5: Tips, Tricks and Random Remarks</h2>
-<a name="tips"></a>The following sections elaborate on the directives as described in
-section <a href="crossroads.html#config">4</a> to illustrate how crossroads works and to help you
-achieve the "optimal" balancing configuration.
-<p>
-<a name="l57"></a>
-<h3>5.1: Configuration examples</h3>
-<a name="tips/examples"></a>
-<a name="l58"></a>
-<strong>5.1.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
-configuration shows most of the possible settings.
-<p>
-<pre>
-service www {
- /* We don't need session stickyness. */
- type any;
-
- /* Port on which we'll listen in this service: required. */
- port 8000;
-
- /* What IP address should this service listen? Default is 'any'.
- * Alternatively you can state an explicit IP address, such as
- * 127.0.0.1; that would bind the service only to 'localhost'. */
- bindto any;
-
- /* Verbose reporting or not. Default is off. */
- verbosity on;
-
- /* Dispatching mode, or: How to select a back end for an incoming
- * request. Possible values:
- * roundrobin: just the next back end in line
- * random: like roundrobin, but at random to make things more
- * confusing. Probably only good for testing.
- * bysize: The backend that transferred the least nr of bytes
- * is the next in line. As a modifier you can say e.g.
- * bysize over 10, meaning that the 10 last connections will
- * be used to compute the transfer size, instead of all
- * transfers.
- * byduration: The backend that was active for the shortest time
- * is the next in line. As a modifier you can say e.g.
- * byduration of 10 to compute over the last 10 connections.
- * byconnections: The back end with the least active connections
- * is the next ine line.
- * byorder: The first available back end is always taken.
- */
- dispatchmode byduration over 5;
-
- /* Interval at which we'll check whether a temporarily unavailable
- * backend has woken up.
- */
- revivinginterval 5;
-
- /* TCP backlog of connections. Default is 0 (no backlog, one
- * connection may be active).
- */
- backlog 5;
-
- /* For status reporting: a shared memory key. Default is the same
- * as the port number, OR-ed by a magic number.
- */
- shmkey 8000;
-
- /* This controls when crossroads should consider a connection as
- * finished even when the TCP sockets weren't closed. This is to
- * avoid hanging connections that don't do anything. NOTE THAT when
- * crossroads cuts off a connection due to timeout exceed, this is
- * not marked as a failure, but as a success. Default is 0: no timeout.
- */
- connectiontimeout 300;
-
- /* The max number of allowed client connections. When present, connections
- * won't be accepted if the max is about to be exceeded. When
- * absent, all connections will be accepted, which might be misused
- * for a DOS attack.
- */
- maxconnections 300;
-
- /* Now let's define a couple of back ends. Number 1: */
- backend www_backend_1 {
- /* The server and its port, the minimum configuration. */
- server httpserver1;
- port 9010;
- /* The 'decay' of usage data of this back end. Only relevant
- * when the whole service has 'dispatchmode bysize' or
- * 'byduration'. The number is a percentage by which the usage
- * parameter is decreased upon each connection of an other back
- * end.
- */
- decay 10;
-
- /* To see what's happening in /var/log/messages: */
- verbosity on;
- }
-
- /* The second one: */
- backend www_backend_2 {
- /* Server and port */
- server httpserver2;
- port 9011;
-
- /* Verbosity of reporting when this back end is active */
- verbosity on;
-
- /* Decay */
- decay 10;
-
- /* This back end is twice as weak as the first one */
- weight 2;
-
- /* Event triggers for system commands upon succesful activation
- * and upon failure.
- */
- onsuccess echo 'success on backend 2' | mail root;
- onfailure echo 'failure on backend 2' | mail root;
- }
-
- /* And yet another one.. this time we will dump the traffic
- * to a trace file. Furthermore we don't want more than 10 concurrent
- * connections here. Note that there's also a total maxconnections for the
- * whole service.
- */
- backend www_backend_3 {
- server httpserver3;
- verbosity on;
- port 9000;
- verbosity on;
- decay 10;
- trafficlog /tmp/backend.3.log;
- maxconnections 10;
- }
-}
-</pre>
-
-<p>
-<a name="l59"></a>
-<strong>5.1.2: An HTTP forwarder when travelling</strong>
-<p>
-As another example, here's my configuration <code>crossroads.conf</code> that I
-use on my Unix laptop. The problem that I face is that I need many
-HTTP proxy configurations (at home, at customers' sites and so on) but
-I'm too lazy to reconfigure browsers all the time.
-<p>
-Here's how it used to be before crossroads:
-<p>
-<ul>
- <li> At home, I would surf through a squid proxy on my local
- machine. The browser proxy setting is then
- <code>http://localhost:3128</code>.
-<p>
-<li> Sometimes I start up an SSH tunnel to our offices. The
- tunnel has a local port 3129, and connects to a squid proxy on
- our e-tunity server. Hence, the browser proxy is then
- <code>http://localhost:3129</code>.
-<p>
-<li> At a customer's location I need the proxy
- <code>http://10.120.34.113:8080</code>, because they have configured it
- so.
-<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
- 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
- <code>http://localhost:8888</code>.</ul>
-<p>
-Here's how it works with a crossroads configuration:
-<p>
-<ul>
- <li> I have configured my browsers to use
- <code>http://localhost:8080</code> as the proxy. For all situations.
-<p>
-<li> I use the following crossroads configuration, and let
- crossroads figure out which proxy backend works, and which
- doesn't. Note two particularities:
-<p>
-<ul>
- <li> The statement <code>dispatchmode byorder</code>. This
- makes sure that once crossroads determines which
- backend works, it will stick to it. This usage of
- crossroads doesn't need to balance over more than one
- back end.
-<p>
-<li> The statement <code>bindto 127.0.0.1</code> makes sure
- that requests from other interfaces than loopback
- won't get serviced.</ul>
-<p>
-<pre>
-service HttpProxy {
- port 8080;
- bindto 127.0.0.1;
- verbosity on;
- dispatchmode byorder;
- revivinginterval 15;
-
- backend Charles {
- server localhost:8888;
- verbosity on;
- }
-
- backend CustomerProxy {
- server 10.120.34.113:8080;
- verbosity on;
- }
-
- backend SshTunnel {
- server localhost:3129;
- }
-
- backend LocalSquid {
- server localhost:3128;
- }
-}
-</pre>
-</ul>
-<p>
-As a final note, the commandline argument <code>tell</code> can be used to
-influence crossroad's own detection mechanism of back end availability
-detection. E.g., if in the above example the back ends <code>SshTunnel</code>
-and <code>LocalSquid</code> are both active, then <code>crossroads tell httpproxy
-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="l60"></a>
-<strong>5.1.3: SSH login with enforced idle logout</strong>
-<p>
-The following example shows how crossroads 'throttles' SSH
-logins. Connections are accepted on port
-22 (the normal SSH port) and forwarded to the actual SSH daemon
-which is running on port 2222.
-<p>
-Note the usage of the
-<code>connectiontimeout</code> directive. This makes sure that users are logged
-out after 10 minutes of inactivity. Note also the <code>maxconnections</code>
-setting, this makes sure that no more than 10 concurrent logins occur.
-<p>
-<pre>
-service Ssh {
- port 22;
- backlog 5;
- maxconnections 10;
- connectiontimeout 600;
- backend TrueSshDaemon {
- server localhost:2222;
- }
-}
-</pre>
-
-<p>
-<a name="l61"></a>
-<h3>5.2: How back ends are selected in load balancing</h3> <a name="howselected"></a>
-<a name="tips/howselected"></a>In order to tune your load balancing, you'll need to understand how
-crossroads computes usage, how weighing works, and so on. In this
-section we'll focus on the dispatching modes <code>bysize</code>, <code>byduration</code>
-and <code>byconnections</code> only. The other dispatching types are
-self-explanatory.
-<p>
-<a name="l62"></a>
-<strong>5.2.1: Bysize, byduration or byconnections?</strong>
-<p>
-As stated before, crossroads doesn't know 'what a service does' and
-how to judge whether a given back end is very busy or not. You
-must therefore give the right hints:
-<p>
-<ul>
- <li> In general, a service which is CPU bound, will be more
- busy when it takes longer to process a request. The dispatch
- mode <code>byduration</code> is appropriate here.
-<p>
-<li> In contrast, a service which is filesystem bound, will be
- more busy when more data are transferred. The dispatch mode
- <code>bysize</code> is apppropriate.
-<p>
-<li> The dispatch mode <code>byduration</code> can also be used when
- network latency is an issue. E.g., if your balancer has back
- ends that are geograpically distributed, then <code>byduration</code>
- would be a good way to select best available back ends.
-<p>
-<li> Furthermore it is noteworthy that <code>dispatchmode
- byduration</code> is not usable for interactive processes such as
- SSH logins. Idle time of a
- login adds to the duration, while causing (almost) no
- load. Mode <code>byduration</code> should only be used for automated
- processes that don't wait for user interaction (e.g., SOAP
- 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.
-<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.
-<p>
-</ul>
-<p>
-<a name="l63"></a>
-<strong>5.2.2: Averaging size and duration</strong>
-<p>
-The configuration statement <code>dispatchmode bysize</code> or <code>byduration</code>
-allows an optional modifier <code>over</code> <em>number</em>, where the stated
-number represents a connection count. When this modifier is present, then
-crossroads will use a moving average over the last <em>n</em> connections to
-compute duration and size figures.
-<p>
-In the real world you'll always want this modifier. E.g., consider two
-back ends that are running for years now, and one of them is suddenly
-overloaded and very busy (it experiences a 'spike' in activity).
-When the <code>over</code> modifier is absent, then
-the sudden load will hardly show up in the usage figures -- it will
-flatten out due to the large usage figures already stored in the years
-of service.
-<p>
-In contrast, when e.g. <code>over 3</code> is in effect, then a sudden load
-does show up -- because it highly contributes to the average of three
-connections.
-<p>
-<a name="l64"></a>
-<strong>5.2.3: Specifying decays</strong>
-<p>
-Decays are also only relevant when crossroads computes the 'next best
-back end' by size (bytes) or duration (seconds). E.g., imagine two
-back ends A and B, both averaged over say 3 connections.
-<p>
-Now when back end A is suddenly hit by a spike,
-its average would go up accordingly. But the back end would never
-again be used, unless B also received a similar spike, because A's
-'usage data' over its last three connections would forever be larger than
-B's data.
-<p>
-For that reason, you should in real situations probably always
-specify a decay, so that the backend selection algorithm recovers from
-spikes. Note that the usage data of the back end where a decay is
-specified, decay when <strong>other</strong> back ends are hit. The decay parameter
-is like specifying how fast your body regenerates when someone else
-does the work.
-<p>
-The below configuration illustrates this:
-<p>
-<pre>
-/* Definition of the service */
-service soap {
- /* Local TCP port */
- port 8080;
-
- /* We'll select back ends by the processing
- * duration
- */
- dispatchmode byduration over 3;
-
- /* First back end: */
- backend A {
- /* Back end IP address and port */
- server 10.1.1.1:8080;
-
- /* When this back end is NOT hit because
- * the other one was less busy, then the
- * usage parameters decay 10% per connection
- */
- decay 10;
- }
-
- /* Second back end: */
- backend B {
- server 10.1.1.2:8080;
- decay 10;
- }
-}
-</pre>
-
-<p>
-<a name="l65"></a>
-<strong>5.2.4: Adjusting the weights</strong>
-<p>
-The back end modifier <code>weight</code> is useful in situations where your
-back ends differ in respect to performance. E.g,. your back ends may
-be geographically distributed, and you know that a given back end is
-difficult to reach and often experiences network lag.
-<p>
-Or you may have
-one primary back end, a system with a fast CPU and enough memory, and a
-small fall-back back end, with a slow CPU and short on memory. In that
-case you know in advance that the second back end should be used only
-rarely. Most requests should go to the big server, up to a certain load.
-<p>
-In such cases you will know in advance that the best performing back ends
-should be selected the most often. Here's where the <code>weight</code>
-statement comes in: you can simply increase the weight of the back
-ends with the least performance, so that they are selected less
-frequently.
-<p>
-E.g., consider the following configuration:
-<p>
-<pre>
-service soap {
- port 8080;
- dispatchmode byduration over 3;
- backend A {
- server 10.1.1.1:8080;
- decay 20;
- }
- backend B {
- server 10.1.1.2:8080;
- weight 2;
- decay 10;
- }
- backend C {
- server 10.1.1.3:8080;
- weight 4;
- decay 5;
- }
-}
-</pre>
-
-<p>
-This will cause crossroads to select back ends by the processing time,
-averaging over the last three connections. However, backend B will kick
-in only when its usage is half of the usage of A (back end B is
-probably only half as fast as A). Backend C will kick in only when its
-usage is a quarter of the usage of A, which is half of the usage of B
-(back end C is probably very weak, and just a fall-back system incase
-both A and B crash). Note also that A's usage data decay much faster
-than B's and C's: we're assuming that this big server recovers quicker
-than its smaller siblings.
-<p>
-<a name="l66"></a>
-<h3>5.3: Periodic probes and wake up calls</h3>
-<a name="tips/periodic"></a>Crossroads has two methods of periodic back end verifications:
-<p>
-<ul>
-<p>
-<li> The first method only checks unavailable back ends. It is
- configured using the directive <code>revivinginterval</code>.
- The way <code>revivinginterval</code> works is as follows:
-<p>
-<ol>
- <li> Crossroads determines that a back end is
- unavailable. This happens when a new network connection to
- the back end fails, or when an existing connection
- suddenly dies.
-<p>
-<li> The back end is the periodically checked to see
- if it has woken up yet.</ol>
-<p>
-<li> The second method periodically checks all back ends,
- available ones and unavailable ones. This is configured using
- <code>checkinterval</code>. During each check, back ends can be marked
- as available or as unavailable.</ul>
-<p>
-<a name="l67"></a>
-<strong>5.3.1: Syntax</strong>
-<p>
-The syntax of both verifications is:
-<p>
-<center><em>method</em><code>interval</code> <em>seconds</em> <code>[</code> <code>externalhandler</code>
-<em>program</em> <em>arguments</em> <code>]</code></center>
-<p>
-In this syntax, the method is <code>reviving</code> or <code>check</code>. The seconds
-specifier defines the delay between consecutive checks.
-<p>
-When no specification <code>externalhandler</code> <em>program</em> <em>arguments</em> is
-given, then Crossroads runs the verification by trying to connect to
-the back end. A simple successful connection suffices to cause
-Crossroads to consider the back end available. However, when the
-<code>externalhandler</code> specifier is given, then Crossroads runs the
-specified external program. This program must exit with status 0 to
-inform Crossroads that the back end is available. All other exit
-statuses will mark the back end as unavailable.
-<p>
-The <em>arguments</em> are expanded according to the following table:
-<p>
-<ul>
-<p>
-<li> <code>%a</code> is the availability of the current back end, when
- a current back end is established. <code>%1a</code> is the
- availability of the first back end (0 when unavailable, 1 if
- available); <code>%2a</code> is the availability of the second back
- end, and so on.
-<p>
-<li> <code>%b</code> is the name of the current back end, when one is
- established. <code>%1b</code> is the name of the first back end,
- <code>%2b</code> of the second back end, and so on.
-<p>
-<li> <code>%e</code> is the count of seconds since start of epoch
- (January 1st 1970 GMT). <code>%60e</code> is the count since start of
- epoch plus 60, so this is a 1 minute offset into the future.
-<p>
-<li> <code>%g</code> is a "GMT-string" representation of the current
- time, in the format <em>monthname, day year hh:mm:ss</em>. This
- format is used in e.g. cookie expiry. <code>%600g</code> is the same
- representation but of a moment 600 seconds in the future (10
- minutes).
-<p>
-<li> <code>%h</code> is the host name of the current back end. <code>%1h</code>
- is the host name of the first back end, <code>%2h</code> of the second
- back end, and so on.
-<p>
-<li> <code>%l</code> is the duration of the last successful connection
- in seconds, concerning the current back end. <code>%1l</code> is the
- duration of the connection to back end one, and so on. Note
- that <code>%l</code> refers only to the last successful connections.
- Unsuccessful connection attempts to back ends do not change
- the value.
-<p>
-<li> <code>%p</code> is the TCP port of the current back end. <code>%1p</code>
- is the TCP port of the first back end, <code>%2p</code> of the second
- back end, and so on.
-<p>
-<li> <code>%P</code> is the process ID of the Crossroads handler that
- handled this request. For debugging only.
-<p>
-<li> <code>%r</code> is the IP address of the connecting client.
-<p>
-<li> <code>%s</code> is the name of the current service that the client
- connected to.
-<p>
-<li> <code>%t</code> is the current local time in ANSI format, in
- <em>YYYY-MM-DD/hhh:mm:ss</em>. <code>%1800s</code> is an ANSI stamp of a
- moment 1800 seconds in the future (half an hour).
-<p>
-<li> <code>%T</code> is the current GMT time in ANSI format. <code>%10T</code>
- offsets this 10 seconds into the future.
-<p>
-<li> <code>%v</code> is the Crossroads version.
-<p>
-<li> <code>%w</code> is the weight factor of the current back
- end. <code>%1w</code> is the weight factor of the first back end, etc..
-<p>
-<li> Any other chararacter following a <code>%</code> sign is taken
- literally; e.g. <code>%z</code> is just a z.</ul>
-<p>
-<a name="l68"></a>
-<strong>5.3.2: Security Considerations</strong>
-<p>
-When <code>externalhandler</code> is in effect, Crossroads spawns an external
-process. For security reasons, you may want to run this process under
-a restricted user account.
-<p>
-The directive <code>useraccount</code> can be used to accomplish this.
-<p>
-<a name="l69"></a>
-<strong>5.3.3: An example</strong>
-<p>
-The following configuration balances SMTP requests to two back
-ends. The connectivity is checked by retrieving output from each back
-end. The back end is available when the standard greeting of a mail
-server is seen; this greeting must contain the word SMTP. During each
-check the probe is terminated by sending <code>quit</code>.
-<p>
-<pre>
-/* Use either DEBUG on or off */
-#define DEBUG off
-
-/* SMTP balancer */
-service smtp {
- /* Standard stuff */
- port 25;
- verbosity DEBUG;
- /* Check back ends every 30 seconds. User 'nobody'
- * will run the external handler. */
- useraccount nobody;
- checkinterval 30
- externalhandler "echo quit | netcat -w1 %h %p | grep SMTP";
-
- /* Two back ends to handle mail traffic. */
- backend mailone {
- server smtp1.local.network:25;
- verbosity DEBUG;
- }
- backend second {
- server smtp2.local.network:25;
- verbosity DEBUG;
- }
-}
-</pre>
-
-<p>
-<a name="l70"></a>
-<h3>5.4: Throttling the number of concurrent connections</h3>
-<a name="tips/throttling"></a>If you suspect that your service may occasionally receive 'spikes' of
-activity (which you should always assume), then it might be a
-good idea to protect your service by specifying a maximum number of
-concurrent connections. This protection can be specified on two levels:
-<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>
-The <code>maxconnections</code> statement, combined with a back end selection
-algorithm, allows very fine granularity. The <code>maxconnections</code> statement
-on the back end level is like a hand brake: even when you specify a
-back end algorithm that would protect a given back end from being used
-too much, a situation may occur where that back end is about to be
-hit. A <code>maxconnections</code> statement on the level of that back may then
-protect it.
-<p>
-<a name="l71"></a>
-<h3>5.5: TCP Session Stickiness</h3>
-<a name="tips/tcpstickiness"></a>If you need to make sure that a client that once gets dispatched to a
-given back end keeps re-visiting the back end, then Crossroads offers
-the dispatch mode <code>byclientip</code>. This mode will only work when each
-client is seen by Crossroads with its own specific IP address; ie.,
-this method won't work when clients reach Crossroads through a
-masquerading firewall (in which case all clients would be seen as
-having the firewall's IP address).
-<p>
-The <code>dispatchmode byclientip</code> works as follows:
-<p>
-<ul>
- <li> The client's IP address is taken in its string
- representation and 'hashed' into a number.
-<p>
-<li> The number is brought back to the number of available
- back ends (using a modulo-operation).
-<p>
-<li> The result defines the back end of choice.</ul>
-<p>
-If the preferred back end is unavailable, then the action that
-Crossroads takes is to dispatch as if <code>byconnections</code>: of the
-available back ends, the one with the least connections is taken.
-<p>
-<a name="l72"></a>
-<h3>5.6: HTTP Session Stickiness</h3>
-<a name="tips/httpstickiness"></a>This section focuses on HTTP session stickiness. This term refers to
-the ability of a balancer to route a conversation between browser and
-a backend farm with webservers always to the same back end. In other
-words: once a back end is selected by the balancer, it will remain the
-back end of choice, even for subsequent connections.
-<p>
-<a name="l73"></a>
-<strong>5.6.1: Don't use stickiness!</strong>
-<p>
-The rule of thumb as far as the balancer is concerned, is: <strong>Do not
-use HTTP session stickiness unless you really have to.</strong> Enabling
-session stickiness hampers failover, balancing and performance:
-<p>
-<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 most likely
- crash. (Actually, when a back end becomes unreachable in the
- middle of a session, Crossroads will assign a new back end to
- that session. This will most likely result in a malfunction
- of the underlying application.)
- <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.
- <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>
-<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
-ends. PHP offers functionality to store session data in a database, so
-that all PHP applications have access to these data. Application
-servers such as Websphere can be configured to replicate session data
-between nodes.
-<p>
-<a name="l74"></a>
-<strong>5.6.2: But if you must..</strong>
-<p>
-If you really need stickiness, think first whether you might use TCP
-stickiness (using the client's IP address to dispatch). If you can,
-then this is the preferred method, since Crossroads won't have to
-unpack TCP streams. Below is a short configuration example:
-<p>
-<pre>
-service www {
- port 80;
- type any;
- revivinginterval 15;
- dispatchmode byclientip;
-
- backend one {
- server 10.1.1.100:80;
- }
-
- backend two {
- server 10.1.1.101:80;
- }
-}
-</pre>
-
-<p>
-However, if you <strong>must</strong> use HTTP-base session stickiness, then
-proceed as follows:
-<p>
-<ul>
- <li> At the level of a <code>service</code> description, set the type to
- <code>http</code>.
- <li> Furthermore, set the <code>headerinspection</code> to <code>shallow</code>
- (unless of course you also want to modify other HTTP headers,
- see section <a href="crossroads.html#tips/deeporshallow">5.8</a>).
- <li> At the level of each back end description, configure the
- <code>stickycookie</code> and a <code>addclientheader</code> directives.</ul>
-<p>
-Once crossroads sees that, it will examine each HTTP message that it
-shuttles between client and back end:
-<p>
-<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.
- <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>
-<p>
-Below is a short example of a configuration.
-<p>
-<pre>
-service www {
- port 80;
- type http;
- headerinspection shallow;
- revivinginterval 15;
- dispatchmode byconnections;
-
- backend one {
- server 10.1.1.100:80;
- stickycookie XRID=100;
- addclientheader "Set-Cookie: XRID=100; Path=/";
- /* or: XRID=100; Path=/; Expires=%600g
- * This would make the session cookie expire in 600 sec (10 mins)
- */
- }
-
- backend two {
- server 10.1.1.101:80;
- stickycookie XRID=101;
- addclientheader "Set-Cookie: XRID=101; Path=/";
- }
-}
-</pre>
-
-<p>
-Note how the cookie names and values in the directives
-<code>stickycookie</code> and <code>addclientheader</code> match. That is obviously a
-prerequisite for stickiness.
-<p>
-<a name="l75"></a>
-<h3>5.7: Passing the client's IP address</h3>
-<a name="tips/clientip"></a>Since Crossroads just shuttles bytes to and fro, meta-information of
-network connections is lost. As far as the back ends are concerned,
-their connections originate at the Crossroads junction.
-For example, standard Apache access logs will show the IP address of
-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> Make sure that the <code>headerinspection</code> is <code>deep</code> (or that
- there is no <code>headerinspection</code> statement, since <code>deep</code> is
- the default, see section <a href="crossroads.html#tips/deeporshallow">5.8</a>);
- <li> In the back end definition, the following statement must
- occur: <br>
- <code>addserverheader "X-Real-IP: %r";</code> <br>
- You are of course free to choose the header name; the here
- used <code>X-Real-IP</code> is a common name for this purpose.</ul>
-<p>
-After this, HTTP traffic that arrives at the back ends has a new
-header: <code>X-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="l76"></a>
-<strong>5.7.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;
- addserverheader "X-Real-IP: %r";
- }
-
- backend two {
- server 10.1.1.200:80;
- addserverheader "X-Real-IP: %r";
- }
-}
-</pre>
-
-<p>
-<a name="l77"></a>
-<strong>5.7.2: Sample Apache configuration</strong>
-<p>
-The method by which each back end analyzes the header <code>X-Real-IP</code>
-will obviously be different per server implementations. However, a
-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>%{X-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 "%{X-Real-IP}i %l %u %t %D \"%r\" %>s %b" common
-</pre>
-
-<p>
-<a name="l78"></a>
-<h3>5.8: Deep or shallow HTTP header inspection</h3>
-<a name="tips/deeporshallow"></a>The service-level directive <code>headerinspection</code> defines which HTTP
-headers Crossroads will analyze. Often, several HTTP requests and
-responses will be served over one network
-link. Browsers and servers will try to keep a TCP link open so that it
-may be re-used; this is a measure to increase efficiency and to shorten load
-times of pages. E.g., a typical HTML page
-will require a style sheet and a few images - and these can be
-retrieved over the same link that originally served the HTML page.
-<p>
-Re-using the TCP link occurs more often than not. It is the default in
-HTTP/1.1 (unless <code>Connection: close</code> is specified as one of the HTTP
-headers). The older HTTP protocol, HTTP/1.0, by default passes just
-one request and response over a TCP link, after which the link is
-closed (unless <code>Connection: keep-alive</code> is specified as one of the
-HTTP headers).
-<p>
-If you define your service as <code>type http</code>, then by default
-Crossroads will inspect all HTTP headers that it sees: not only the
-first browser request and server answer, but also subsequent requests
-and answers that travel over the same link. This is called 'deep
-inspection mode', in which Crossroads applies
-directives such as <code>addclientheader</code> to all header
-blocks. Inspecting the full TCP stream to catch header blocks can be
-resource consuming. You can optionally make Crossroads's resource
-consumption 'lighter' by instructing it to inspect only the first
-HTTP header block, and to simply pass-through over all subsequent information
-(which might well include next header blocks of a re-used TCP
-connection) This is done using the directive <code>headerinspection</code>:
-<p>
-<pre>
-service web {
- type http;
- headerinspection shallow;
- backend a { .... }
- backend b { .... }
-}
-</pre>
-
-<p>
-The situations where <code>shallow</code> mode can be used, depends on what you
-need to do:
-<p>
-<ul>
- <li> <code>shallow</code> mode can be used when the inspection and
- modification of the first HTTP header block suffices. For example,
- HTTP session stickiness is a good example:
-<p>
-<pre>
-service web {
- type http;
- headerinspection shallow;
- backend a {
- server 10.1.1.1:80;
- stickycookie "BalancerID=1";
- addclientheader "Set-Cookie: BalancerID=1";
- }
- .
- . other back ends are defined here
- .
-}
-</pre>
-
-<p>
-In this case, Crossroads will inspect only the first header block that
- the client sends for the presence of a cookie <code>BalancerID</code>. If the
- cookie has value 1, then the request will be routed to back end
- <code>a</code>. Similarly, Crossroads will inspect only the first header block
- that the server sends, and will inject a <code>Set-Cookie</code>
- instruction.
-<p>
-In this example, deep mode is not necessary because Crossroads
- will use the first header that the client sends to route the
- information to a given back end.
- If more than one HTTP transactions follow over
- the same TCP link, then by definition the link will go to the
- same back end - even without inspecting all HTTP headers that
- follow the first ones.
-<p>
-<li> <code>deep</code> mode is necessary in situations where all header
- blocks must be inspected and modified. E.g., if you want to hide your
- HTTP server identification, you might use:
-<p>
-<pre>
-service web {
- type http;
- headerinspection deep;
- backend a {
- server 10.1.1.1:80;
- setclientheader "Server: MyWebServer";
- }
- .
- . other back ends are defined here
- .
-}
-</pre>
-
-<p>
-Here, all HTTP header blocks that come from the server will be parsed,
- and <code>Server</code> headers will be overwritten.
- In a similar vein, if you want to pass the client's IP address, you
- will also need deep mode.
-<p>
-In these examples, <code>shallow</code> mode is not usable, because the
- outbound header modifications should apply to all headers of a
- given series. Imagine that one would use <code>shallow</code> mode
- here: then, in a series of 5 HTTP transactions that pass over
- the same TCP link, only the first transaction would hide the
- HTTP server signature. All subsequent transactions would still
- show the HTTP server signature to the world.</ul>
-<p>
-<a name="l79"></a>
-<h3>5.9: Debugging network traffic</h3>
-<a name="tips/debugging"></a> Incase the traffic between client and backend must be debugged,
- the statement <code>trafficlog</code> <em>filename</em> can be issued. This
- causes the traffic to be dumped in hexadecimal format to the
- stated filename.
-<p>
-Traffic sent by the client is prefixed by a <strong>C</strong>, traffic sent by
- the back end is prefixed by a <strong>B</strong>. Below is a sample traffic
- dump of a browser trying to get a HTML page. The server replies
- that the page was not modified.
-<p>
-<pre>
-C 0000 47 45 54 20 68 74 74 70 3a 2f 2f 77 77 77 2e 63 GET http://www.c
-C 0010 73 2e 68 65 6c 73 69 6e 6b 69 2e 66 69 2f 6c 69 s.helsinki.fi/li
-C 0020 6e 75 78 2f 6c 69 6e 75 78 2d 6b 65 72 6e 65 6c nux/linux-kernel
-C 0030 2f 32 30 30 31 2d 34 37 2f 30 34 31 37 2e 68 74 /2001-47/0417.ht
-C 0040 6d 6c 20 48 54 54 50 2f 31 2e 31 0d 0a 43 6f 6e ml HTTP/1.1..Con
-C 0050 6e 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a nection: close..
-.
-. etcetera
-.
-B 0000 48 54 54 50 2f 31 2e 30 20 33 30 34 20 4e 6f 74 HTTP/1.0 304 Not
-B 0010 20 4d 6f 64 69 66 69 65 64 0d 0a 44 61 74 65 3a Modified..Date:
-B 0020 20 54 75 65 2c 20 31 32 20 4a 75 6c 20 32 30 30 Tue, 12 Jul 200
-B 0030 35 20 30 39 3a 34 39 3a 34 37 20 47 4d 54 0d 0a 5 09:49:47 GMT..
-B 0040 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74 65 Content-Type: te
-B 0050 78 74 2f 68 74 6d 6c 3b 20 63 68 61 72 73 65 74 xt/html; charset
-.
-. etcetera
-.
-</pre>
-
-<p>
-Turning on traffic dumps will <em>significantly</em> slow down
- crossroads.
-<p>
-Besides <code>trafficlog</code>, there is also a directive
- <code>throughputlog</code>. This directive also takes one argument, a
- filename. The file is appended, and the following information is
- 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>
-<p>
-As an example, consider the following (the lines are shortened for
- brevity and prefixed by line numbers for clarity):
-<p>
-<pre>
-
-1 0027566 0.000000 C 462 GET http://public.e-tunity.com/ ...
-2 0027566 0.052974 B 394 HTTP/1.1 200 OK..Via: 1.1 tinyp ...
-3 0027566 0.053413 B 1073 <html>.. <head>.. <titl ...
-4 0027566 0.053589 B 1448 1> </td>.. </tr>.. </table ...
-5 0027566 0.065679 B 725 for more. info.... <li> To ...
-</pre>
-
-<p>
-This tells us that:
-<p>
-<ul>
- <li> Line 1: PID 27566 served a request that originated at the
- client (C). The corresponding timing is 0 seconds, which means
- that this is the start of the run. The request was 462 bytes
- long and started with <code>GET http://public...</code>
-<p>
-<li> Line 2: 0.052974 seconds later, the backend (B) replied
- with <code>HTTP/1.1 200 OK</code>.
-<p>
-<li> Lines 3, 4 and 5: The backend (B) proceeded by sending
- chunks.</ul>
-<p>
-The buffer sizes (462, 394 and so on) also tell us that the
- network sends relatively small chunks. In this case we might save
- some processing memory by setting the TCP buffer size to say 2K,
- instead of the default 5K. In this situation, most of the default
- 5K buffers will be unused. Setting the TCP buffer size to 2K can be done
- using the flag <code>-B 2048</code> or by using the statement
- <code>tcpbuffersize</code> <code>2048;</code> in an <code>options</code> block of the configuration.
-<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
- between the true client and crossroads is obviously not
- included. This is illustrated by the below simple ASCII art:
-<p>
-<pre>
-
-client ---->---->---->--->*crossroads ====>====>====>
- \
- back end
- /
-client ----<----<----<---< crossroads ====<====<====<
-
-</pre>
-
-<p>
-This simple picture shows a typical request that originates
- at a client, travels to crossroads, and is relayed via the back
- end. The <strong>C</strong> entry in a throughput log is the time when
- crossroads sees the request, indicated by an asterisk. The <strong>B</strong>
- entries are the times that it takes the back end to answer,
- indicated by <code>===</code> style lines. Therefore, the true roundtrip
- time will be longer than the number of seconds that are logged in
- the throughput log: the latency between client and crossroads
- isn't included in that measurement.
-<p>
-Summarizing, the throughput times and buffer sizes of a
- client-back end connection can be analyzed using the directive
- <code>throughputlog</code>. In a real-world analysis, you'd probably want
- to write up a script to analyze the output and to compute round
- trip times. Such scripts are not (yet) included in Crossroads.
-<p>
-<a name="l80"></a>
-<h3>5.10: IP filtering: Limiting Access by Client IP Address</h3>
-<a name="tips/ipfiltering"></a><a name="l81"></a>
-<strong>5.10.1: General Examples</strong>
-<p>
-The directives <code>allowfrom</code>, <code>denyfrom</code>, <code>allowfile</code> and
-<code>denyfile</code> can be used to instruct Crossroads to specifically allow
-access by using a "whitelist" of IP addresses, or to specifically deny
-access by using a "blacklist". E.g., the following configuration
-allows access to service <code>webproxy</code> only to <em>localhost</em>:
-<p>
-<pre>
-service webproxy {
- port 8000;
- allowfrom 127.0.0.1;
- backend one {
- .
- . Back end definitions occur here
- .
- }
- .
- . Other back ends or other service directives
- . may occur here
- .
-}
-</pre>
-
-<p>
-In this example there is a "whitelist" having only one entry: IP
-address 127.0.0.1, or <em>localhost</em>. (Incidentally, the same behaviour
-could be accomplished by stating <em>bindto 127.0.0.1</em>, in which case
-Crossroads would only listen to the local network device.)
-<p>
-In the same vein, the directive <code>allowfrom 127.0.0.1 192.168.1/24</code>
-would allow access to <em>localhost</em> and to all IP addresses that start
-with 192.168.1. The specifier <code>192.168.1/24</code> states that there are
-three network bytes (192, 168 and 1), and 24 bits (or 3 bytes) are
-relevant; so that the fourth network byte doesn't matter.
-<p>
-<a name="l82"></a>
-<strong>5.10.2: Using External Files</strong>
-<p>
-The directives <code>allowfile</code> and <code>denyfile</code> allow you to specify IP
-addresses in external files. The Crossroads configuration states
-e.g. <code>allowfile /tmp/allow.txt</code>, and the IP addresses are then in
-<code>/tmp/allow.txt</code>. The format of <code>/tmp/allow.txt</code> is as follows:
-<p>
-<ul>
- <li> The specifications follow again <em>p.q.r.s/mask</em>, where
- p, q, r and s are network bytes which can be left out on the
- right hand side when the mask allows it;
-<p>
-<li> The specifications must be separated by white space
- (spaces, tabs or newlines).</ul>
-<p>
-E.g., the following is a valid example of an external specification
-file:
-<p>
-<pre>
-127.0.0.1
-192.168.1/24
-10/8
-</pre>
-
-<p>
-When external files are in effect, then the signal <code>SIGHUP</code> (1)
-causes Crossroads to reload the external file. E.g., while Crossroads
-is running, you may edit <code>/tmp/allow.txt</code>, and then issue <code>killall
--1 crossroads</code>. The new contents of <code>/tmp/allow.txt</code> will be
-reloaded.
-<p>
-<a name="l83"></a>
-<strong>5.10.3: Mixing Directives</strong>
-<p>
-Crossroads allows to mix all directives in one service
-description. However, some mixes are less meaningful than others. It's
-up to you to take this into account.
-<p>
-The following rules apply:
-<p>
-<ul>
- <li> Blacklisting and whitelisting can be used together. When
- combined, the blacklist will always be interpreted
- first. E.g., consider the following directives:
-<p>
-<pre>
-allowfrom 192.168.1/24
-denyfrom 192.168.1.100
-</pre>
-
-<p>
-Given the fact that the deny list is checked first, client
- 192.168.1.100 won't be able to access Crossroads. Then the
- allow list will be checked, stating that all clients whose IP
- address starts with 192.168.1 may connect. The effect will be
- that e.g., client 192.168.1.1 may connect, 192.168.1.2 may
- connect too, 192.168.1.100 will be blocked, and 10.1.1.1 will
- be blocked as well.
-<p>
-Now consider the following directives:
-<p>
-<pre>
-allowfrom 192.168.1.100 127.0.0.1
-denyfrom 192.168.1/24
-</pre>
-
-<p>
-This will first of all deny access to all IP addresses that
- start with 192.168.1. So the rule that allows 192.168.1.100
- won't ever be effective. The net result will be that access
- will be granted to 127.0.0.1.
-<p>
-<li> Blacklisting or whitelisting can be left out. A list is
- considered empty when no appropriate directives occur in the
- configuration file <code>crossroads.conf</code>, or when the directive
- points to an empty or non-existent external file.
-<p>
-<li> Using <code>*from</code> and <code>*file</code> statements is allowed, but
- doesn't make sense. E.g., the following configuration sample
- is such a case:
-<p>
-<pre>
-allowfrom 127.0.0.1 192.168.1/24
-allowfile /tmp/allow.txt
-</pre>
-
-<p>
-There is a technical reason for this. Once Crossroads
- processes the <code>allowfile</code> directive, then the whole
- whitelist is cleared (thereby removing the entries 127.0.0.1
- and 192.168.1/24), and new entries are reloaded from the
- file. The net result is that the <code>allowfrom</code> specification
- is overruled.</ul>
-<p>
-Crossroads only performs syntactic checking of the configuration. Some
-of the above samples are syntactically correct, but make no semantic
-sense: Crossroads doesn't warn for such situations.
-<p>
-<a name="l84"></a>
-<h3>5.11: Using an external program to dispatch</h3> <a name="externalhandler"></a>
-<a name="tips/externalhandler"></a>As mentioned before, Crossroads supports several built-in dispatch
-modes. However, you are always free to hook-in your own dispatch mode
-that determines the next back end using your own specific
-algorithm. This section explains how to do it.
-<p>
-<a name="l85"></a>
-<strong>5.11.1: Configuring the external handler</strong>
-<p>
-First, the <code>dispatchmode</code> statement needs to inform Crossroads that
-an external program will do the job. The syntax is: <code>dispatchmode
-externalhandler</code> <em>program arguments</em>. The <em>program</em> must point to
-an executable program that will be started by Crossroads. The
-specifier <em>arguments</em> can be anything you want; those will be the
-arguments to your dispatch helper. You use the following special
-format specifiers in the argument list:
-<p>
-<ul>
-<p>
-<li> <code>%a</code> is the availability of the current back end, when
- a current back end is established. <code>%1a</code> is the
- availability of the first back end (0 when unavailable, 1 if
- available); <code>%2a</code> is the availability of the second back
- end, and so on.
-<p>
-<li> <code>%b</code> is the name of the current back end, when one is
- established. <code>%1b</code> is the name of the first back end,
- <code>%2b</code> of the second back end, and so on.
-<p>
-<li> <code>%e</code> is the count of seconds since start of epoch
- (January 1st 1970 GMT). <code>%60e</code> is the count since start of
- epoch plus 60, so this is a 1 minute offset into the future.
-<p>
-<li> <code>%g</code> is a "GMT-string" representation of the current
- time, in the format <em>monthname, day year hh:mm:ss</em>. This
- format is used in e.g. cookie expiry. <code>%600g</code> is the same
- representation but of a moment 600 seconds in the future (10
- minutes).
-<p>
-<li> <code>%h</code> is the host name of the current back end. <code>%1h</code>
- is the host name of the first back end, <code>%2h</code> of the second
- back end, and so on.
-<p>
-<li> <code>%l</code> is the duration of the last successful connection
- in seconds, concerning the current back end. <code>%1l</code> is the
- duration of the connection to back end one, and so on. Note
- that <code>%l</code> refers only to the last successful connections.
- Unsuccessful connection attempts to back ends do not change
- the value.
-<p>
-<li> <code>%p</code> is the TCP port of the current back end. <code>%1p</code>
- is the TCP port of the first back end, <code>%2p</code> of the second
- back end, and so on.
-<p>
-<li> <code>%P</code> is the process ID of the Crossroads handler that
- handled this request. For debugging only.
-<p>
-<li> <code>%r</code> is the IP address of the connecting client.
-<p>
-<li> <code>%s</code> is the name of the current service that the client
- connected to.
-<p>
-<li> <code>%t</code> is the current local time in ANSI format, in
- <em>YYYY-MM-DD/hhh:mm:ss</em>. <code>%1800s</code> is an ANSI stamp of a
- moment 1800 seconds in the future (half an hour).
-<p>
-<li> <code>%T</code> is the current GMT time in ANSI format. <code>%10T</code>
- offsets this 10 seconds into the future.
-<p>
-<li> <code>%v</code> is the Crossroads version.
-<p>
-<li> <code>%w</code> is the weight factor of the current back
- end. <code>%1w</code> is the weight factor of the first back end, etc..
-<p>
-<li> Any other chararacter following a <code>%</code> sign is taken
- literally; e.g. <code>%z</code> is just a z.</ul>
-<p>
-Note that the format specifiers such as <code>%b</code> don't make sense in the
-phase in which an external handler is called, since there is no
-current back end yet (the job of the handler is to supply one, so at
-the time of calling, <code>%b</code> is undefined).
-<p>
-<a name="l86"></a>
-<strong>5.11.2: Writing the external handler</strong>
-<p>
-The external handler is activated using the arguments that are
-specified in the configuration file. The external handler can do
-whatever it wants, but ultimately, it must write a back end name on
-its <em>stdout</em>. Crossroads reads this, and if the back end is
-available, uses that back end for the connection.
-<p>
-<a name="l87"></a>
-<strong>5.11.3: Examples of external handlers</strong>
-<p>
-This section shows some examples of Crossroads configurations
-vs. external handlers. The sample handlers that are shown here, are
-also included in the Crossroads distribution, under the directory
-<code>etc/</code>. Also note that the examples shown here are just
-quick-and-dirty Perl scripts, meant to illustrate only. Your
-applications may need other external handlers, but you can use the
-shown scripts as a starting point.
-<p>
-<p><strong>Round-robin dispatching</strong><br>
-<p>
-This example is trivial in the sense that round-robin dispatching is
-already built into Crossroads, so
-that using an external handler for this purpose only slows down
-Crossroads. However, it's a good starting example.
-<p>
-The Crossroads configuration is shown below:
-<p>
-<pre>
-service test {
- port 8001;
- verbosity on;
- revivinginterval 5;
-
- dispatchmode externalhandler
- /usr/local/src/crossroads/etc/dispatcher-roundrobin
- %1b %1a %2b %2a;
-
- backend testone {
- server localhost:3128;
- verbosity on;
- }
- backend testtwo {
- server locallhost:3128;
- verbosity on;
- }
-}
-</pre>
-
-<p>
-The relevant <code>dispatchmode</code> statement invokes the external program
-<code>dispatcher-roundrobin</code> with four arguments: the name of the first
-back end (<code>testone</code>), its availability (0 or 1), the name of the
-second back end (<code>testtwo</code>) and its availability (0 or 1).
-<p>
-The external handler, which is also included in the Crossroads
-distribution, is shown below. It is a Perl script.
-<p>
-<pre>
-#!/usr/bin/perl
-
-use strict;
-
-# Example of a round-robin external dispatcher. This is totally
-# superfluous, Crossroads has this on-board; if you use the external
-# program for determining round-robin dispatching, then you'll only
-# slow things down. This script is just meant as an example.
-
-# Globals / configuration
-# -----------------------
-my $log = '/tmp/exthandler.log'; # Debug log, set to /dev/null to suppress
-my $statefile = '/tmp/rr.last'; # Where we keep the last used
-
-# Logging
-# -------
-sub msg {
- return if ($log eq '/dev/null' or $log eq '');
- open (my $of, ">>$log") or return;
- print $of (scalar(localtime()), ' ', @_);
-}
-
-# Read the last used back end
-# ---------------------------
-sub readlast() {
- my $ret;
-
- if (open (my $if, $statefile)) {
- $ret = <$if>;
- chomp ($ret);
- close ($if);
- msg ("Last used back end: $ret\n");
- return ($ret);
- }
- msg ("No last-used back end (yet)\n");
- return (undef);
-}
-
-# Write back the last used back end, reply to Crossroads and stop
-# ---------------------------------------------------------------
-sub reply ($) {
- my $last = shift;
-
- if (open (my $of, ">$statefile")) {
- print $of ("$last\n");
- }
- print ("$last\n");
- exit (0);
-}
-
-# Main starts here
-# ----------------
-
-# Collect the cmdline arguments. We expect pairs of backend-name /
-# backend-availablility, and we'll store only the available ones.
-msg ("Dispatch request received\n");
-my @backend;
-for (my $i = 0; $i <= $#ARGV; $i += 2) {
- push (@backend, $ARGV[$i]) if ($ARGV[$i + 1]);
-}
-msg ("Available back ends: @backend\n");
-
-# Let's see what the last one is. If none found, then we return the
-# first available back end. Otherwise we need to go thru the list of
-# back ends, and return the next one in line.
-my $last = readlast();
-if ($last eq '') {
- msg ("Returning first available back end $backend[0]\n");
- reply ($backend[0]);
-}
-
-# There **was** a last back end. Try to match it in the list,
-# then return the next-in-line.
-for (my $i = 0; $i < $#backend; $i++) {
- if ($last eq $backend[$i]) {
- msg ("Returning next back end ", $backend[$i + 1], "\n");
- reply ($backend[$i + 1]);
- }
-}
-
-# No luck.. run back to the first one.
-msg ("Returning first back end $backend[0]\n");
-reply ($backend[0]);
-</pre>
-
-<p>
-The working of the script is basically as follows:
-<p>
-<ul>
- <li> The argument list is scanned. Back ends that are
- available are collected in an array <code>@backend</code>.
-<p>
-<li> The script queries a state file <code>/tmp/rr.last</code>. If a
- back end name occurs there, then the next back end is looked
- up in <code>@backend</code> and returned to Crossroads. If no last back
- is unknown or can't be matched, then the first available back
- end (first element of <code>@backend</code>) is returned to Crossroads.
-<p>
-<li> Informing Crossroads is done via the subroutine
- <code>reply()</code>. This code writes the selected back end to file
- <code>/tmp/rr.last</code> (for future usage) and prints the back end
- name to <em>stdout</em>.
-<p>
-<li> The script logs its actions to a file
- <code>/tmp/exthandler.log</code>. This log file can be inspected for
- the script's actions.</ul>
-<p>
-<p><strong>Dispatching by the client IP address</strong><br>
-<p>
-The following example shows a useful real-life situation that
-illustrates how dispatching by client IP address works. <strong>Note that</strong>
-as of Crossroads 1.31, <code>dispatchmode byclientip</code> is implemented --
-so that the below description is somewhat superfluous. The code
-snippets however can help you in modelling your own specific dispatch
-modes, aided by external helpers. (Incidentally, the <code>dispatchmode</code>
-<code>byclientip</code> was modeled after the shown script. The functionality
-proved so useful that it was embedded into Crossroads.)
-<p>
-Our hypothetical dispatching situation is as follows:
-<p>
-<ul>
- <li> Crossroads is used as a single-address point to forward
- Remote Desktop requests to a farm of Windows systems, where
- users can work via remote access;
-<p>
-<li> However, users may stop their session, and when they
- re-connect, they expect to be sent to the Windows system that
- they had worked on previously;
-<p>
-<li> Client PC's have their distinct IP addresses, which
- distinguish them.
-<p>
-<li> Of four windows systems, two are large servers, and two
- are small ones. We'll want to assign large servers to clients
- when we have a choice.</ul>
-<p>
-The requirements resemble session stickiness in HTTP, except that the remote
-desktop protocol doesn't support stickiness. This situation is a
-perfect example of how an external handler can help:
-the potential delay due to the calling of an external
-handler won't even be noticed. Remote Desktop is a network service where
-the connection time isn't critical; users won't notice a slightly
-larger connection time due to the fact that Crossroads invokes an
-external program. We expect only a few (albeit lengthy) TCP connections.
-<p>
-The approach to the solution of this problem uses several external
-program hooks:
-<p>
-<ul>
- <li> An external dispatcher handler will be responsible for
- suggesting a back end, given a client IP and given the current
- timestamp. This handler will consult an internal
- administration to see whether the stated IP address should
- re-use a back end, or to determine which back end is free for usage.
- <li> An external hook <code>onstart</code> will be responsible for
- updating the internal administration; i.e., to flag a back end
- as 'occupied'.
- <li> The external hooks <code>onfailure</code> and <code>onend</code> will be
- responsible for flagging a back end as 'free' again; i.e., for
- erasing any previous information that states that the back end
- was occupied.</ul>
-<p>
-The Crossroads configuration is shown below. Only four Windows back
-ends are shown. Each back end is configured on a
-given IP address, port 3389, and is limited to one concurrent connection
-(otherwise a new user might 'steal' a running desktop session).
-<p>
-<pre>
-service rdp {
- port 3389;
- revivinginterval 5;
-
- /* rdp-helper dispatch IP STAMP ... will suggest a back end to use,
- * arguments are for all back ends: name, availability, weight */
- dispatchmode externalhandler
- /usr/local/src/crossroads/etc/rdp-helper dispatch %r %e
- %1b %1a %1w
- %2b %2a %2w
- %3b %3a %3w
- %4b %4a %4w;
-
- backend win1 {
- server 10.1.1.1:3389;
- maxconnections 1;
- /* rdp-helper start IP STAMP BACKEND will log the actual start
- * of a connection;
- * rdp-helper end IP will log the ending of a connection */
- onstart /usr/local/src/crossroads/etc/rdp-helper start %r %e %b;
- onend /usr/local/src/crossroads/etc/rdp-helper end %r;
- onfail /usr/local/src/crossroads/etc/rdp-helper end %r;
- }
- backend win2 {
- server 10.1.1.2:3389;
- maxconnections 1;
- onstart /usr/local/src/crossroads/etc/rdp-helper start %r %e %b;
- onend /usr/local/src/crossroads/etc/rdp-helper end %r;
- onfail /usr/local/src/crossroads/etc/rdp-helper end %r;
- }
- backend win3 {
- server 10.1.1.3:3389;
- maxconnections 1;
- weight 2;
- onstart /usr/local/src/crossroads/etc/rdp-helper start %r %e %b;
- onend /usr/local/src/crossroads/etc/rdp-helper end %r;
- onfail /usr/local/src/crossroads/etc/rdp-helper end %r;
- }
- backend win4 {
- server 10.1.1.4:3389;
- maxconnections 1;
- weight 3;
- onstart /usr/local/src/crossroads/etc/rdp-helper start %r %e %b;
- onend /usr/local/src/crossroads/etc/rdp-helper end %r;
- onfail /usr/local/src/crossroads/etc/rdp-helper end %r;
- }
-}
-</pre>
-
-<p>
-Depending on the dispatcher stage, the exernal handler <code>rdp-helper</code>
-is invoked in different ways:
-<p>
-<dl>
- <p><dt><strong>During dispatching</strong><dd> the helper is called to suggest a back
- end. The arguments are an action indicator <code>dispatch</code>, the
- client's IP address, the timestamp, and four triplets that
- represent back ends: per back end its name, its availability,
- and its weight. The purpose of the helper is to tell
- Crossroads which back end to use.
-<p>
-<p><dt><strong>During connection start</strong><dd> the helper will be invoked to
- inform it of the start of a connection, given a client IP
- address.
-<p>
-<p><dt><strong>When a connection terminates</strong><dd> the helper will be invoked
- to inform it that the connection has ended.</dl>
-<p>
-Here's the external handler as Perl script. It uses the module
-<code>GDBM_File</code> which most likely will not be part of standard Perl
-distributions, but can be added using CPAN. (Alternatively, any other
-database module can be used.)
-<p>
-<pre>
-#!/usr/bin/perl
-
-use strict;
-use GDBM_File;
-
-# Global variables and configuration
-# ----------------------------------
-my $log = '/tmp/exthandler.log'; # Debug log, set to /dev/null to suppress
-my $cdb = '/tmp/client.db'; # GDBM database of clients
-my %db; # .. and memory representation of it
-my $timeout = 24*60*60; # Timeout of a connection in secs
-
-# Logging
-# -------
-sub msg {
- return if ($log eq '/dev/null' or $log eq '');
- open (my $of, ">>$log") or return;
- print $of (scalar(localtime()), ' ', @_);
- close ($of);
-}
-
-# Reply a back end to the caller and stop processing.
-# ---------------------------------------------------
-sub reply ($) {
- my $b = shift;
- msg ("Suggesting $b to Crossroads.\n");
- print ("$b\n");
- exit (0);
-}
-
-# Is a value in an array
-# ----------------------
-sub inarray {
- my $val = shift;
- for my $other (@_) {
- return (1) if ($other eq $val);
- }
- return (0);
-}
-
-# A connection is starting
-# ------------------------
-sub start {
- my ($ip, $stamp, $backend) = @_;
- msg ("Logging START of connection for IP $ip on stamp $stamp, ",
- "back end $backend\n");
- $db{$ip} = "$backend:$stamp";
-}
-
-# A connection has ended
-# ----------------------
-sub end {
- my $ip = shift;
- msg ("Logging END of connection for IP $ip\n");
- $db{$ip} = undef;
-}
-
-# Request to determine a back end
-# -------------------------------
-sub dispatch {
- my $ip = shift;
- my $stamp = shift;
-
- msg ("Request to dispatch IP $ip on stamp $stamp\n");
-
- # Read the next arguments. They are triplets of
- # backend-name / availability / weight. Store if the back end is
- # available.
- my (@backends, @weights);
- for (my $i = 0; $i < $#_; $i += 3) {
- if ($_[$i + 1] != 0) {
- push (@backends, $_[$i]);
- push (@weights, $_[$i + 2]);
- msg ("Candidate back end: $_[$i] with weight ", $_[$i + 2], "\n");
- }
- }
-
- # See if this is a reconnect by a previously seen client IP. We'll
- # treat this as a reconnect if the timeout wasn't yet exceeded.
- if ($db{$ip} ne '') {
- my ($last_backend, $last_stamp) = split (/:/, $db{$ip});
- msg ("IP $ip had last connected on $last_stamp to $last_backend\n");
- if ($stamp < $last_stamp + $timeout) {
- msg ("Timeout not yet exceeded, this may be a reconnect\n");
- # We'll allow a reconnect only if the stated last_backend is
- # free (sanity check).
- if (inarray ($last_backend, @backends)) {
- msg ("Last back end $last_backend is available, ",
- "letting through\n");
- reply ($last_backend);
- } else {
- msg ("Last used back end isn't free, suggesting a new one\n");
- }
- } else {
- msg ("Timeout exceeded, suggesting a new back end\n");
- }
- } else {
- msg ("Np preveious connection data, suggesting a new back end\n");
- }
-
- my $bestweight = -1;
- my $bestbackend;
- for (my $i = 0; $i <= $#weights; $i++) {
- if ($bestweight == -1 or $bestweight > $weights[$i]) {
- $bestweight = $weights[$i];
- $bestbackend = $backends[$i];
- }
- }
-
- msg ("Best back end: $bestbackend (given weight $bestweight)\n");
- reply ($bestbackend);
-}
-
-# Main starts here
-# ----------------
-msg ("Start of run, attaching GDBM database '$cdb'\n");
-tie (%db, 'GDBM_File', $cdb, &GDBM_WRCREAT, 0600);
-
-# The first argument must be an action 'dispatch', 'start' or 'end'.
-# Depending on the action, we do stuff.
-my $action = shift (@ARGV);
-if ($action eq 'dispatch') {
- dispatch (@ARGV);
-} elsif ($action eq 'start') {
- start (@ARGV);
-} elsif ($action eq 'end') {
- end (@ARGV);
-} else {
- print STDERR ("Usage: rdp-helper {dispatch|start|end} args\n");
- exit (1);
-}
-</pre>
-
-<p>
-<a name="l88"></a>
-<h3>5.12: Linux and ip_conntrack_max</h3>
-<a name="tips/ipconntrackmax"></a>The kernel value of <code>ip_conntrack_max</code> is important for routers and
-balancers under Linux. Basically it's the maximum number of tracked
-connections. Felix A.W.O. describes the following situation:
-<p>
-<ul>
- <li> Crossroads seems to mark back ends as unavailable, while
- in fact nothing is afoot.
- <li> This happens under heavy load.
- <li> In <code>/var/log/messages</code> one may see the message:
- <code>kernel: ip_conntrack: table full, dropping packet</code>.</ul>
-<p>
-The reason for Crossroad's behavior is that the kernel refuses to
-build up a requested network connection. For Crossroads, this looks
-just as a non-responding back end. Crossroads therefore marks the back
-end as unavailable.
-<p>
-The solution is as follows:
-<p>
-<ul>
- <li> Try <code>cat /proc/sys/net/ipv4/ip_conntrack_max</code> to see
- the current value.
- <li> Add something to the shown value (e.g., multiply by two),
- and inform
- the kernel of the new value, using <code>echo</code> <em>new-value</em> <code>>
- /proc/sys/net/ipv4/ip_conntrack_max</code>
- <li> Make sure that the same step occurs somewhere in your
- boot sequence as well, or that the new value is stated in a
- configuration file such as <code>/etc/sysctl.conf</code>.</ul>
-<p>
-The value for <em>new-value</em> is something that you'll have to figure
-out yourself. Note however that each count will cause the kernel to
-reserve 350 bytes. So if you set <code>ip_conntrack_max</code> to 100.000, then
-you're already taking 33.3Mb off the total available memory.
-<p>
-<a name="l89"></a>
-<h3>5.13: Marking back ends as bad after more than one try</h3>
-<a name="tips/retries"></a>Crossroads allows you to specify on a per-back end basis how many
-retries are needed before a back end is considered unavailable. The
-default is just one, meaning that after one failed connection,
-Crossroads will mark a back end as unavailable (the back end may be
-'revived', if you use <code>revivinginterval</code> or <code>checkinterval</code>).
-<p>
-Increasing the number is specified using the keyword <code>retries</code>. The
-following configuration defines two back ends; the one on the IP
-address 5.6.7.8 is somehow 'flaky', and Crossroads should try
-connecting 3 times before crossing it off:
-<p>
-<pre>
-service www {
- port 80;
- backend plugh {
- server 1.2.3.4:80;
- }
- backend xyzzy {
- server 5.6.7.8:80;
- retries 3;
- }
-}
-</pre>
-
-<p>
-There may be several reasons for increasing the retries number:
-<p>
-<ul>
- <li> The network connections to the server may spuriously
- hamper, but such rare errors don't mean that the back end server is
- down.
-<p>
-<li> The back end server is a 'slow starter' and can't handle spikes
- very well. E.g., it may be a webserver which starts with only
- one daemon; extra capacity is added as network connections
- arrive, but adding capacity take a little time.</ul>
-<p>
-Whatever the reason, the keyword <code>retries</code> might be of help
-here. This keyword should however be used carefully: Crossroads will
-retry connecting with a small one-second delay in between. A high
-<code>retries</code> number means also lots of one-second delays, in which time
-a client is kept waiting.
-<p>
-<a name="l90"></a>
-<h3>5.14: Using the Web Interface crossroads-mgr</h3>
-<a name="tips/webinterface"></a>The mini-webserver <code>crossroads-mgr</code> provides an intuitive web
-interface to the state of Crossroads. Once started, an administrator
-may view the state of the balancer, and may influence the state of all
-back ends.
-<p>
-As an example, a procedure is described here where a given back end is
-gracefully taken out of service. Below is a sample Crossroads
-configuration, which distributes requests over three back ends:
-<p>
-<pre>
-service www {
- port 80;
- type http;
- backend one {
- server 10.1.1.1:80;
- stickycookie "BalancerID=one";
- addclientheader "Set-Cookie: BalancerID=one";
- }
- backend two {
- server 10.1.1.1:80;
- stickycookie "BalancerID=two";
- addclientheader "Set-Cookie: BalancerID=two";
- }
- backend three {
- server 10.1.1.1:80;
- stickycookie "BalancerID=three";
- addclientheader "Set-Cookie: BalancerID=three";
- }
-}
-</pre>
-
-<p>
-In order to take a given back end gracefully offline (say back end
-<code>two</code>), either of the following procedures can be followed:
-<p>
-<ol>
- <li> Back end <code>two</code> is taken down via the commandline, using
- <code>crossroads tell www two down</code>. Next we wait for say one hour to
- let existing sessions die out. After that, the back end can be turned
- off.
-<p>
-<li> Back end <code>two</code> is taken down via the web interface, by
- switching the status from <code>available</code> to <code>down</code>. Next we wait
- for say one our, and turn off the back end.</ol>
-<p>
-The web interface doesn't offer extra functionality over the command
-line tools; but all information is available at one glance, and
-accessible without a shell access to the balancer.
-<p>
-<a name="l91"></a>
-<strong>5.14.1: Starting crossroads-mgr</strong>
-<p>
-The basic command to start <code>crossroads-mgr</code> is
-<p>
-<center><code>crossroads-mgr start</code> <em>portnumber</em></center>
-<p>
-where the port number specifies to which TCP port the manager will
-listen. There is however one important security aspect that needs
-attention. Unless specified otherwise, anyone who points their browser
-to the balancer and the given port, can view back end states and even
-change them. This may be a too lax policy.
-<p>
-The web interface daemon has two methods to limit access: a listening
-address can be specified via the command line, and basic
-authentication (username / password protection) can be turned on.
-<p>
-Specifying a listening address is done using the flag <code>-a</code>. E.g.,
-after
-<p>
-<center><code>crossroads-mgr -a 127.0.0.1 start 10000</code></center>
-<p>
-the manager is started to listen to port 10000, but only on the
-address 127.0.0.1 which is localhost. Requests from other addresses
-will not be served.
-<p>
-Enforcing basic authentication is turned on using two command line
-flags:
-<p>
-<ul>
- <li> Flag <code>-b</code> turns on basic authentication to view the status.
- <li> Flag <code>-B</code> turns on basic authentication to change back end
- states.</ul>
-<p>
-Both flags must be followed by the required credentials. The most
-simple way to state the credentials, is to postfix the flag with the
-required user name, a colon, and the required password. E.g.,
-<code>-Buser:secret</code> says that anyone who tries to change back end
-states, must supply the user name <code>user</code> and the password
-<code>secret</code>.
-<p>
-In this example the full invocation would be e.g.:
-<p>
-<center><code>crossroads-mgr -Buser:secret start 1000</code></center>
-<p>
-The disadvantage is here that the credentials are visible for anyone
-who has shell access to the balancer. A process overview, generated
-with say <code>ps ax | grep crossroads-mgr</code>, would show the required
-username and password. In order to avoid such a leak,
-<code>crossroads-mgr</code> can be started as follows:
-<p>
-<center><code>crossroads-mgr -BPROMPT start 1000</code></center>
-<p>
-The 'magic' word <code>PROMPT</code> instructs <code>crossroads-mgr</code> to read the
-username and password from <em>stdin</em>. The invocation can be further
-scripted, using something like:
-<p>
-<center><code>echo user:secret | crossroads-mgr -BPROMPT start 1000</code></center>
-<p>
-The same trick can be used with the flag <code>-b</code>. When both flags are
-present, and both 'magic' words <code>PROMPT</code> occur, then
-<code>crossroads-mgr</code> will first ask for the credentials of the 'viewer',
-and next for the credentials of the 'modifier' (even when flag <code>-B</code>
-is stated first). So the following example starts <code>crossroads-mgr</code>
-and requires the user name <code>viewer</code>, with password <code>showme</code> to view the
-status, and it requires the user name <code>modifier</code>, with password
-<code>changeit</code> to change states:
-<p>
-<pre>
-echo -e 'viewer:showme\nmodifier:changeit' |
- crossroads-mgr -bPROMPT -BPROMPT start 1000
-</pre>
-
-<p>
-<a name="l92"></a>
-<h3>5.15: Rendering Crossroads' status in a web page</h3> <a name="xmlstatus"></a>
-<a name="tips/rendering"></a>The Crossroads flag <code>-x</code> causes the status output to be generated as
-an XML document. This format can be nicely used to render the output
-as an HTML page.
-<p>
-E.g., the following sample shows how Crossroads reports its status in
-XML format (the actual XML structure that Crossroads outputs may be
-different from this example, depending on the version):
-<p>
-<pre>
-<?xml version="1.0" encoding="UTF-8"?>
-<status>
- <service id="1" name="smtp">
- <connections>1</connections>
- <lastbackend>0</lastbackend>
- <backend id="0" name="first">
- <availability id="0">available</availability>
- <clients>0</clients>
- <failures>0</failures>
- <connections>2</connections>
- <duration sec="0.559882">0.56s</duration>
- <throughput bytes="3564">3.48Kb</throughput>
- </backend>
- <backend id="1" name="second">
- <availability id="0">available</availability>
- <clients>0</clients>
- <failures>0</failures>
- <connections>2</connections>
- <duration sec="23.7636">23.76s</duration>
- <throughput bytes="9055">8.84Kb</throughput>
- </backend>
- </service>
-</status>
-</pre>
-
-<p>
-A custom-made XSLT transformation stylesheet can be used to convert
-this to any output format - and also to HTML. Such a style sheet is
-included in the Crossroads distribution as
-<code>etc/xml-status-to-html.xslt</code>. The sheet is lengthy, and is
-therefore not included in this document. (You're welcome to modify it
-to suit your specific needs. If you have cool tips, send them along to
-me and I'll include them in the next distribution!)
-<p>
-If you want to show this output in a webpage which is generated on
-demand by a webserver, then you might run into the following
-problem. The status reporter (<code>crossroads -x status</code>)
- must be able to access the shared memory segment of the running
-Crossroads instance. By default, the shared memory is protected for
-the user that started Crossroads, which will often not be the user who
-runs the webserver. Under the auspices of the webserver user,
-<code>crossroads status</code> might abort with a message: "ERROR: Cannot get
-shared memory for service <em>name</em>, key <em>number</em>: Permission denied."
-<p>
-The solution for this problem is to make the shared memory access
-somewhat more liberal. There are basically two options:
-<p>
-<ul>
- <li> Start Crossroads with the flag <code>-m 0666</code>, which makes
- the shared memory segment available to all. The octal number
- 0666 works just like a file permission setting under
- Unix. Now, any user can run <code>crossroads status</code>.
-<p>
-<li> If you want to make the access to Crossroads' shared
- memory somewhat stricter, then make the user who starts
- Crossroads and the user who runs the webserver member of a new
- Unix group. Start Crossroads with the flag <code>-m 0664</code>. Now,
- users belonging to the same group as the Crossroads starter
- can run <code>crossroads status</code>.</ul>
-<p>
-<a name="l93"></a>
-<h3>5.16: Crossroads and DNS caching</h3>
-<a name="tips/dnscaching"></a>
-The option <code>-d</code> allows you to control Crossroads' built in DNS
-caching mechanism. Most often you will not need to use this:
-DNS lookups in Crossroads occur only to find back ends; and back ends
-are usually 'near' to the balancer.
-<p>
-You might want or need to use DNS caching if:
-<p>
-<ul>
- <li> Back end servers are specified as hostnames, and not as
- IP addresses;
- <li> DNS resolving of those host names is perceptibly slow.</ul>
-<p>
-You can test DNS resolving from the command line using e.g. the
-commands <code>nslookup</code> and <code>host</code>.
-<p>
-If DNS resolving is an issue, then you can specify the flag <code>-d</code>
-<em>nsec</em> on the command line while invoking Crossroads. This instructs
-Crossroads to use its DNS cache to store results. Each result is
-stored for up to <em>nsec</em> seconds - after that, a new request for the
-back end will lead to a new DNS lookup.
-<p>
-<a name="l94"></a>
-<h3>5.17: Managing a Pool of Virtual Back Ends</h3>
-<a name="tips/virtual"></a>Crossroads can be used as a central dispatcher for computing on
-demand. E.g., imagine a situation where a web service exists on one or
-two servers, with the option of adding new servers in case of a high
-load. The "other" servers, besides the first two ones, are a virtual
-pool - the pool size and the IP addresses may not be known in advance.
-<p>
-The following Crossroads' features are used in this example:
-<p>
-<ul>
-<p>
-<li> The back ends of Crossroads can have an initial state. For
- the two real servers which are already present this would be
- <code>up</code> (the default). For the non-present ones this would be
- <code>down</code>: Crossroads excludes back ends that are down from the set
- of candidate workers, and does not check their presence using
- <code>revivalinterval</code> or <code>checkinterval</code>.
-<p>
-<li> The back ends must be configured to have a server address and
- port, but this can be later reconfigured runtime. E.g., the
- virtual pool servers would be initially configured on
- <code>localhost:80</code>, and later the addresses would be filled in.</ul>
-<p>
-A sample Crossroads configuration is shown below. It defines 20 back
-ends: two are always present, and 18 are in the virtual pool.
-<p>
-<pre>
-service vpool {
- port 80;
- revivinginterval 3;
- dispatchmode byconnections;
-
- /* The two back ends that are always present: */
- backend real_01 { server 10.1.1.1:80; }
- backend real_02 { server 10.1.1.2:80; }
-
- /* The virtual pool: */
- backend virt_01 { server localhost:80; state down; }
- backend virt_02 { server localhost:80; state down; }
- backend virt_03 { server localhost:80; state down; }
- backend virt_04 { server localhost:80; state down; }
- backend virt_05 { server localhost:80; state down; }
- backend virt_06 { server localhost:80; state down; }
- backend virt_07 { server localhost:80; state down; }
- backend virt_08 { server localhost:80; state down; }
- backend virt_09 { server localhost:80; state down; }
- backend virt_10 { server localhost:80; state down; }
- backend virt_11 { server localhost:80; state down; }
- backend virt_12 { server localhost:80; state down; }
- backend virt_13 { server localhost:80; state down; }
- backend virt_14 { server localhost:80; state down; }
- backend virt_15 { server localhost:80; state down; }
- backend virt_16 { server localhost:80; state down; }
- backend virt_17 { server localhost:80; state down; }
- backend virt_18 { server localhost:80; state down; }
-
-}
-</pre>
-
-<p>
-New back ends can be enabled using <code>crossroads tell</code>. E.g., to
-enable back end <code>virt_01</code> on IP address 10.100.1.1:80, the commands
-are:
-<p>
-<pre>
-crossroads tell vpool virt_01 server 10.100.1.1:80
- crossroads tell vpool virt_01 up
-</pre>
-
-<p>
-To disable a back end, its state is reset to <code>down</code>. The IP address
-doesn't even have to be erased:
-<p>
-<pre>
-crossroads tell vpool virt_01 down
-</pre>
-
-<p>
-A script to monitor the total number of connections, and to add a back
-end or to remove one, is left to the reader. The output of
-<code>crossroads -x status</code> can be very helpful here: it reports on the
-states of all back ends, their connections, the total number of
-available or down back ends, etc..
-<p>
-<a name="l95"></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="l96"></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.
-<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>
-<p>
-The crossroads configuration of the second alternative is shown below:
-<p>
-<pre>
-service HttpProxy {
- port 8080;
- verbosity on;
- backend LocalSquid {
- server 127.0.0.1;
- port 3128;
- verbosity on;
- }
-}
-</pre>
-
-<p>
-<a name="l97"></a>
-<strong>6.1.1: Results</strong>
-<p>
-The results of this test are that crossroads causes a negligible
-delay, if it is statistically relevant at all. Without crossroads, the
-timing results are:
-<p>
-<pre>
-real 0m8.146s
-user 0m0.130s
-sys 0m0.253s
-</pre>
-
-<p>
-When using crossroads as a middle station, the results are:
-<p>
-<pre>
-real 0m9.481s
-user 0m0.141s
-sys 0m0.230s
-</pre>
-
-<p>
-<a name="l98"></a>
-<strong>6.1.2: Discussion</strong>
-<p>
-The above shown results are quite favorable to crossroads. However,
-one should know that situations will exist where crossroads leans
-towards the 'worst case' scenario, causing up to 50%
-delay.
-<p>
-E.g., imagine a test where a <code>wget</code> command retrieves a
-HTML document from an Apache server on <code>localhost</code>. Now we have
-(almost) no overhead due to network throttling, hostname lookups and
-so on. When this test would be run either with or without crossroads
-in between, then theoretically, crossroads would cause a much larger
-delay, because it has to read from the server, and then write the same
-information to <code>wget</code>. Each read/write occurs twice when crossroads
-sits in between.
-<p>
-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.
-<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>
-<p>
-<a name="l99"></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
-firewall: TCP packets that arrive at the balancer are sent to one of
-the configured back ends. LVS has the advantage over crossroads that
-there is no stop-and-go in the transmission; in contrast, crossroads
-needs to send data via an internal buffer. Crossroads has the
-advantage that it offers instantaneous failover because it tries to
-contact the back end for upon each new TCP connection; in contrast,
-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="l100"></a>
-<strong>6.2.1: Environment</strong>
-<p>
-On the balancer, LVS was run on port 80, its forwarding set up for two
-equally weighted back ends, using <code>ipvsadm</code>:
-<p>
-<pre>
-ipvsadm -a -t 192.168.1.250:http -r 10.1.1.100:http -m -w 1
-ipvsadm -a -t 192.168.1.250:http -r 10.1.1.101:http -m -w 1
-</pre>
-
-<p>
-Crossroads was run on port 81. The configuration file is shown below:
-<p>
-<pre>
-service http {
- port 81;
- dispatchmode roundrobin;
- revivinginterval 5;
- backend one {
- server 10.1.1.100;
- port 80;
- }
- backend two {
- server 10.1.1.101;
- port 80;
- }
-}
-</pre>
-
-<p>
-<a name="l101"></a>
-<strong>6.2.2: Tests and results</strong>
-<p>
-In the first test, ports 80 and 81 on the balancer were 'bombed' with
-50 concurrent clients, each requesting a small page 50 times. The
-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>
-<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>
-<p>
-In this setup there seems to be no difference between the performance
-of LVS and crossroads!
-<p>
-In a second test, the size of the retrieved page was varied from 2.000
-to 2.000.000 bytes. This test was taken to see whether crossroads would
-show performance degradation when transferring larger amounts of data.
-<p>
-For each page size, 30 concurrent clients were started, that retrieved
-the page 50 times. Again, the connect times and processing times where
-recorded.
-<p>
-The results of the total time (connect time + retrieval time)
-are shown in the below table:
-<p>
-<table>
-
- <td colspan=3><hr></td>
-
-
-<tr>
-
- <td> <strong>Bytes</strong></td> <td> <strong>LVS timing</strong></td> <td> <strong>Crossroads timing</strong></td>
-
-</tr>
-
-
-<tr>
-
- <td> 2000</td> <td> 0.130741688</td> <td> 0.12739582</td>
-
-</tr>
-
-
-<tr>
-
- <td> 20000</td> <td> 0.490916224</td> <td> 0.50376901</td>
-
-</tr>
-
-
-<tr>
-
- <td> 200000</td> <td> 3.799440328</td> <td> 4.33125273</td>
-
-</tr>
-
-
-<tr>
-
- <td> 2000000</td> <td> 45.25090855</td> <td> 45.9600728</td>
-
-</tr>
-
- <td colspan=3><hr></td>
-
-</table>
-<p>
-Again, the results show that crossroads performs just as effectively
-as LVS, even with large data chunks!
-<p>
-<a name="l102"></a>
-<h2>7: Compiling and Installing</h2> <a name="installation"></a>
-<a name="compiling"></a><a name="l103"></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>;
-<p>
-<li> Perl (5.00 or better). The web interface
- <code>crossroads-mgr</code> requires specific modules;
-<p>
-<li> A POSIX-compliant C compiler;
-<p>
-<li> Support for SYSV IPC, networking and so on.
-</ul>
-<p>
-Basically a Linux or Apple MacOSX box will do nicely. To compile and install
-crossroads, follow these steps.
-<p>
-<a name="l104"></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>.
-<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>.
-<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, set the <code>SET_PROC_TITLE...</code>
- settings to 0. 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.
-<p>
-<li> The manual pages on the basic usage of Crossroads and on
- the layout of the configuration file are installed as
- well, if a suitable <code>man/</code> directory is present under the
- installation prefix directory. If these pages are not
- installed, then you can always copy <code>doc/crossroads.1</code> to a
- suitable <code>man/man1/</code> directory, and
- <code>doc/crossroads.conf.7</code> to a suitable <code>man/man7/</code>
- directory. After this, <code>man crossroads</code> and <code>man
- crossroads.conf</code> would show the appropriate manual pages.
-<p>
-<li> The full documentation doesn't install in this process. If you
- 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;
-<p>
-<li> Optionally, <code>cp doc/crossroads.pdf</code>
- <em>pdfdirectory/</em>; where <em>pdfdirectory</em> is the
- destination directory for your PDF manuals.</ul>
-<p>
-<li> In order to use the web interface <code>crossroads-mgr</code>,
- make sure that the following Perl modules are available:
- <code>HTTP::Daemon</code>, <code>Getopt::Std</code>,
- <code>MIME::Base64</code>. When in doubt, start the commandline tool
- <code>cpan</code> and enter <code>install HTTP::Daemon</code>, which will
- install the named module if necessary. You can repeat this for
- all listed modules.
-<p>
-</ul>
-<p>
-<a name="l105"></a>
-<h3>7.3: Configuring crossroads</h3><a name="configuring"></a>
-<p>
-Now that the binary is available on your system, you need to create a
-configuration <code>crossroads.conf</code>. Use this manual to get started. You
-can locate the configuration file in any of the following locations on
-your file system:
-<p>
-<ul>
- <li> Along an 'etc' directory that matches the path where
- Crossroads is installed. E.g, when the Crossroads binary is
- <code>/usr/local/bin/crossroads</code>, then the configuration can be
- put in <code>/usr/local/etc/crossroads.conf</code>. Alternatively, if
- you install Crossroads in <code>/opt/crossroads/bin/</code>, then you
- can install the configuration into <code>/opt/crossroads/etc/</code>.
-<p>
-<li> As the file <code>/etc/crossroads.conf</code>. When Crossroads
- fails to locate a configuration file near its path, it tries
- this name.</ul>
-<p>
-Once you have the configuration ready, start crossroads with
-<code>crossroads start</code>. Test the availability of your services and back
-ends. Monitor how crossroads is doing with:
-<p>
-<ul>
- <li> In one terminal, run the script:
- <pre>
-while [ 1 ] ; do
- tput clear
- crossroads status
- sleep 3
-done
-</pre>
-
-<p>
-<strong>Note</strong> that depending on your system you might need
- <code>sleep 3s</code>, i.e., with an <code>s</code> appended.
-<p>
-<li> In another terminal, run:
- <pre>
-while [ 1 ] ; do
- tput clear
- ps ax | grep crossroads | grep -v grep
- sleep 3
-done
-</pre>
-
-<p>
-<strong>Note</strong> that depending on your system you might need
- <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>
-<p>
-Now thoroughly test the availability of your back ends through
-crossroads. The status display will show an updated view of which back
-ends are selected and how busy they are. The process list will show
-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="l106"></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="l107"></a>
-<strong>7.4.1: SysV Style Startup</strong>
-<p>
-On SysV style systems, there's a startup script directory
-<code>/etc/init.d</code> where bootscripts for all utilities are located.
-You may have the <code>chkconfig</code> utility to automate the task of
-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:
-<p>
-<pre>
-#!/bin/sh
-/usr/local/bin/crossroads -v $1
-/usr/local/bin/crossroads-mgr $1 1000
-</pre>
-
-<p>
-<code>init</code> will supply the right value for <code>$1</code>: "start"
- during startup, and "stop" during shutdown. Note that
- the stated directory <code>/usr/local/bin</code> must correspond with
- the installation path.
-<p>
-In the first line, The flag <code>-v</code> causes the startup to be
- more 'verbose'. However, once daemonized, the verbosity of
- Crossroads is controlled by the appropriate statements in the
- configuration.
-<p>
-The second line starts the web interface <code>crossorads-mgr</code> on
- TCP port 1000. Access to the web interface is free for all;
- add your own flags <code>-b</code> or <code>-B</code> to enforce basic
- authentication (see the manual page of <code>crossroads-mgr</code> and
- section <a href="crossroads.html#tips/webinterface">5.14</a>).
-<p>
-<li> 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:
-<p>
-<pre>
-root> cd /etc/rc.d/rc3.d
-root> ln -s /etc/init.d/crossroads S99crossroads
-root> ln -s /etc/init.d/crossroads K99crossroads
-</pre>
-
-<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.
-<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>
-<p>
-<a name="l108"></a>
-<strong>7.4.2: BSD Style Startup</strong>
-<p>
-On BSD style systems, daemons are booted directly from <code>/etc/rc</code> and
-related scripts. Incase you have a file <code>/etc/rc.local</code>, edit it,
-and add the statement:
-<p>
-<pre>
-/usr/local/bin/crossroads start
-/usr/local/bin/crossroads-mgr start 1000
-</pre>
-
-<p>
-If your BSD system lacks <code>/etc/rc.local</code>, then you may need to start
-Crossroads from <code>/etc/rc</code>. Your mileage may vary.
-<p>
-<a name="l109"></a>
-<strong>7.4.3: Linux-related</strong>
-<p>
-When using Crossroads on Linux, the following may be relevant:
-<p>
-<ul>
-<p>
-<li> Crossroads supports flag <code>-p</code>, which causes Crossroads not
- to modify the process name. In the absence of the flag, Crossroads
- alters its process name to something like <code>crossroads</code> <code>-</code>
- <code>Service</code> <em>myservice:</em> <code>listening</code>.
-<p>
-Flag <code>-p</code> may be handy if you want to suppress this
- behavior. The process name is then <code>crossroads-daemon</code>. Some
- boot scripts use the <code>/proc</code> filesystem to find PID's by
- filename; in those cases, flag <code>-p</code> can be used.
-<p>
-</ul>
-<p>
-</body>
-</html>
diff --git a/doc/crossroads.pdf b/doc/crossroads.pdf
Binary files differ.
diff --git a/doc/fig/cluster.graffle b/doc/fig/cluster.graffle
@@ -0,0 +1,631 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>ActiveLayerIndex</key>
+ <integer>0</integer>
+ <key>AutoAdjust</key>
+ <true/>
+ <key>CanvasColor</key>
+ <dict>
+ <key>w</key>
+ <string>1</string>
+ </dict>
+ <key>CanvasOrigin</key>
+ <string>{0, 0}</string>
+ <key>CanvasScale</key>
+ <real>1</real>
+ <key>ColumnAlign</key>
+ <integer>1</integer>
+ <key>ColumnSpacing</key>
+ <real>36</real>
+ <key>CreationDate</key>
+ <string>2008-07-15 11:11:27 +0200</string>
+ <key>Creator</key>
+ <string>Karel Kubat</string>
+ <key>DisplayScale</key>
+ <string>1 cm = 1 cm</string>
+ <key>GraphDocumentVersion</key>
+ <integer>5</integer>
+ <key>GraphicsList</key>
+ <array>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>30</integer>
+ <key>Points</key>
+ <array>
+ <string>{288.594, 104.284}</string>
+ <string>{367.5, 102.219}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>27</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>27</integer>
+ </dict>
+ <key>ID</key>
+ <integer>29</integer>
+ <key>Points</key>
+ <array>
+ <string>{116.479, 138.195}</string>
+ <string>{154.614, 126.669}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>9</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>27</integer>
+ </dict>
+ <key>ID</key>
+ <integer>28</integer>
+ <key>Points</key>
+ <array>
+ <string>{116.486, 80.1664}</string>
+ <string>{153.816, 89.2202}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>8</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{147, 61}, {152, 90}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>27</integer>
+ <key>Shape</key>
+ <string>Cloud</string>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>7</integer>
+ </dict>
+ <key>ID</key>
+ <integer>26</integer>
+ <key>Points</key>
+ <array>
+ <string>{421.842, 114.609}</string>
+ <string>{454.158, 130.391}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>4</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>6</integer>
+ </dict>
+ <key>ID</key>
+ <integer>25</integer>
+ <key>Points</key>
+ <array>
+ <string>{422.5, 101.5}</string>
+ <string>{453.5, 101.5}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>4</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>5</integer>
+ </dict>
+ <key>ID</key>
+ <integer>24</integer>
+ <key>Points</key>
+ <array>
+ <string>{421.842, 88.3909}</string>
+ <string>{454.158, 72.6091}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>4</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{62, 131}, {54, 31}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>9</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>CornerRadius</key>
+ <real>5</real>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf330
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf0 Client}</string>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{62, 58}, {54, 31}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>8</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>CornerRadius</key>
+ <real>5</real>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf330
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf0 Client}</string>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{454, 128}, {54, 31}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>7</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>CornerRadius</key>
+ <real>5</real>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf330
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf0 B3}</string>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{454, 86}, {54, 31}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>6</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>CornerRadius</key>
+ <real>5</real>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf330
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf0 B2}</string>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{454, 44}, {54, 31}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>5</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>CornerRadius</key>
+ <real>5</real>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf330
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf0 B1}</string>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{368, 86}, {54, 31}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>4</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>CornerRadius</key>
+ <real>5</real>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf330
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf0 XR}</string>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{355, 35}, {166, 133}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>3</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>CornerRadius</key>
+ <real>5</real>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf330
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf0 Cluster\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+}</string>
+ </dict>
+ </dict>
+ </array>
+ <key>GridInfo</key>
+ <dict/>
+ <key>GuidesLocked</key>
+ <string>NO</string>
+ <key>GuidesVisible</key>
+ <string>YES</string>
+ <key>HPages</key>
+ <integer>1</integer>
+ <key>ImageCounter</key>
+ <integer>1</integer>
+ <key>IsPalette</key>
+ <string>NO</string>
+ <key>KeepToScale</key>
+ <false/>
+ <key>Layers</key>
+ <array>
+ <dict>
+ <key>Lock</key>
+ <string>NO</string>
+ <key>Name</key>
+ <string>Layer 1</string>
+ <key>Print</key>
+ <string>YES</string>
+ <key>View</key>
+ <string>YES</string>
+ </dict>
+ </array>
+ <key>LayoutInfo</key>
+ <dict>
+ <key>LayoutTarget</key>
+ <integer>3</integer>
+ </dict>
+ <key>LinksVisible</key>
+ <string>NO</string>
+ <key>MagnetsVisible</key>
+ <string>NO</string>
+ <key>MasterSheet</key>
+ <string>Master 1</string>
+ <key>MasterSheets</key>
+ <array>
+ <dict>
+ <key>ActiveLayerIndex</key>
+ <integer>0</integer>
+ <key>AutoAdjust</key>
+ <true/>
+ <key>CanvasColor</key>
+ <dict>
+ <key>w</key>
+ <string>1</string>
+ </dict>
+ <key>CanvasOrigin</key>
+ <string>{0, 0}</string>
+ <key>CanvasScale</key>
+ <real>1</real>
+ <key>ColumnAlign</key>
+ <integer>1</integer>
+ <key>ColumnSpacing</key>
+ <real>36</real>
+ <key>DisplayScale</key>
+ <string>1 cm = 1 cm</string>
+ <key>GraphicsList</key>
+ <array/>
+ <key>GridInfo</key>
+ <dict/>
+ <key>HPages</key>
+ <integer>1</integer>
+ <key>IsPalette</key>
+ <string>NO</string>
+ <key>KeepToScale</key>
+ <false/>
+ <key>Layers</key>
+ <array>
+ <dict>
+ <key>Lock</key>
+ <string>NO</string>
+ <key>Name</key>
+ <string>Layer 1</string>
+ <key>Print</key>
+ <string>YES</string>
+ <key>View</key>
+ <string>YES</string>
+ </dict>
+ </array>
+ <key>LayoutInfo</key>
+ <dict>
+ <key>LayoutTarget</key>
+ <integer>3</integer>
+ </dict>
+ <key>Orientation</key>
+ <integer>2</integer>
+ <key>OutlineStyle</key>
+ <string>Basic</string>
+ <key>RowAlign</key>
+ <integer>1</integer>
+ <key>RowSpacing</key>
+ <real>36</real>
+ <key>SheetTitle</key>
+ <string>Master 1</string>
+ <key>UniqueID</key>
+ <integer>1</integer>
+ <key>VPages</key>
+ <integer>1</integer>
+ </dict>
+ </array>
+ <key>ModificationDate</key>
+ <string>2008-07-15 11:15:13 +0200</string>
+ <key>Modifier</key>
+ <string>Karel Kubat</string>
+ <key>NotesVisible</key>
+ <string>NO</string>
+ <key>Orientation</key>
+ <integer>2</integer>
+ <key>OriginVisible</key>
+ <string>NO</string>
+ <key>OutlineStyle</key>
+ <string>Basic</string>
+ <key>PageBreaks</key>
+ <string>YES</string>
+ <key>PrintInfo</key>
+ <dict>
+ <key>NSBottomMargin</key>
+ <array>
+ <string>coded</string>
+ <string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFklwCG</string>
+ </array>
+ <key>NSLeftMargin</key>
+ <array>
+ <string>coded</string>
+ <string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFklwCG</string>
+ </array>
+ <key>NSPaperName</key>
+ <array>
+ <string>string</string>
+ <string>A4</string>
+ </array>
+ <key>NSPaperSize</key>
+ <array>
+ <string>size</string>
+ <string>{595.2, 841.8}</string>
+ </array>
+ <key>NSRightMargin</key>
+ <array>
+ <string>coded</string>
+ <string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFklwCG</string>
+ </array>
+ <key>NSTopMargin</key>
+ <array>
+ <string>coded</string>
+ <string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFklwCG</string>
+ </array>
+ </dict>
+ <key>ReadOnly</key>
+ <string>NO</string>
+ <key>RowAlign</key>
+ <integer>1</integer>
+ <key>RowSpacing</key>
+ <real>36</real>
+ <key>SheetTitle</key>
+ <string>Canvas 1</string>
+ <key>SmartAlignmentGuidesActive</key>
+ <string>YES</string>
+ <key>SmartDistanceGuidesActive</key>
+ <string>YES</string>
+ <key>UniqueID</key>
+ <integer>1</integer>
+ <key>UseEntirePage</key>
+ <true/>
+ <key>VPages</key>
+ <integer>1</integer>
+ <key>WindowInfo</key>
+ <dict>
+ <key>CurrentSheet</key>
+ <string>0</string>
+ <key>DrawerOpen</key>
+ <false/>
+ <key>DrawerTab</key>
+ <string>Outline</string>
+ <key>DrawerWidth</key>
+ <real>209</real>
+ <key>FitInWindow</key>
+ <false/>
+ <key>Frame</key>
+ <string>{{537, 57}, {593, 939}}</string>
+ <key>ShowRuler</key>
+ <false/>
+ <key>ShowStatusBar</key>
+ <true/>
+ <key>VisibleRegion</key>
+ <string>{{0, 0}, {578, 825}}</string>
+ <key>Zoom</key>
+ <string>1</string>
+ </dict>
+</dict>
+</plist>
diff --git a/doc/main/benchmarking.yo b/doc/main/benchmarking.yo
@@ -1,170 +0,0 @@
-This section shows how crossroads affects the
-transmitting of HTML data when used as an intermediate 'station'
-through which all data travels.
-
-
-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() 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(\
-service HttpProxy {
- port 8080;
- verbosity on;
- backend LocalSquid {
- server 127.0.0.1;
- port 3128;
- verbosity on;
- }
-})
-
-
-subsubsect(Results)
-
-The results of this test are that crossroads causes a negligible
-delay, if it is statistically relevant at all. Without crossroads, the
-timing results are:
-
-verb(\
-real 0m8.146s
-user 0m0.130s
-sys 0m0.253s)
-
-When using crossroads as a middle station, the results are:
-
-verb(\
-real 0m9.481s
-user 0m0.141s
-sys 0m0.230s)
-
-
-subsubsect(Discussion)
-
-The above shown results are quite favorable to crossroads. However,
-one should know that situations will exist where crossroads leans
-towards the 'worst case' scenario, causing up to 50%
-delay.
-
-E.g., imagine a test where a tt(wget) command retrieves a
-HTML document from an Apache server on tt(localhost). Now we have
-(almost) no overhead due to network throttling, hostname lookups and
-so on. When this test would be run either with or without crossroads
-in between, then theoretically, crossroads would cause a much larger
-delay, because it has to read from the server, and then write the same
-information to tt(wget). Each read/write occurs twice when crossroads
-sits in between.
-
-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 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))
-
-LVS is a kernel-based balancer that acts like a masquerading
-firewall: TCP packets that arrive at the balancer are sent to one of
-the configured back ends. LVS has the advantage over crossroads that
-there is no stop-and-go in the transmission; in contrast, crossroads
-needs to send data via an internal buffer. Crossroads has the
-advantage that it offers instantaneous failover because it tries to
-contact the back end for upon each new TCP connection; in contrast,
-LVS isn't aware of downtime of back ends (unless one implements an
-external heartbeat). Also, crossroads offers more complex balancing
-than LVS.
-
-subsubsect(Environment)
-
-On the balancer, LVS was run on port 80, its forwarding set up for two
-equally weighted back ends, using tt(ipvsadm):
-
-verb(\
-ipvsadm -a -t 192.168.1.250:http -r 10.1.1.100:http -m -w 1
-ipvsadm -a -t 192.168.1.250:http -r 10.1.1.101:http -m -w 1)
-
-Crossroads was run on port 81. The configuration file is shown below:
-
-verb(\
-service http {
- port 81;
- dispatchmode roundrobin;
- revivinginterval 5;
- backend one {
- server 10.1.1.100;
- port 80;
- }
- backend two {
- server 10.1.1.101;
- port 80;
- }
-})
-
-subsubsect(Tests and results)
-
-In the first test, ports 80 and 81 on the balancer were 'bombed' with
-50 concurrent clients, each requesting a small page 50 times. The
-following timings where measured:
-
-itemization(
- 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.)
-
-In this setup there seems to be no difference between the performance
-of LVS and crossroads!
-
-In a second test, the size of the retrieved page was varied from 2.000
-to 2.000.000 bytes. This test was taken to see whether crossroads would
-show performance degradation when transferring larger amounts of data.
-
-For each page size, 30 concurrent clients were started, that retrieved
-the page 50 times. Again, the connect times and processing times where
-recorded.
-
-The results of the total time (connect time + retrieval time)
-are shown in the below table:
-
-table(3)(rrr)(
- rowline()
- row(
- cell(bf(Bytes)) cell(bf(LVS timing)) cell(bf(Crossroads timing)))
- row(
- cell(2000) cell(0.130741688) cell(0.12739582))
- row(
- cell(20000) cell(0.490916224) cell(0.50376901))
- row(
- cell(200000) cell(3.799440328) cell(4.33125273))
- row(
- cell(2000000) cell(45.25090855) cell(45.9600728))
- rowline())
-
-Again, the results show that crossroads performs just as effectively
-as LVS, even with large data chunks!
-
-\ No newline at end of file
diff --git a/doc/main/compiling.yo b/doc/main/compiling.yo
@@ -1,226 +0,0 @@
-subsect(Prerequisites)
-
-The creation of crossroads requires:
-
-itemization(
- it() Standard Unix tools, such as tt(sed), tt(awk);
-
- it() Perl (5.00 or better). The web interface
- tt(crossroads-mgr) requires specific modules;
-
- it() A POSIX-compliant C compiler;
-
- it() Support for SYSV IPC, networking and so on.
-)
-
-Basically a Linux or Apple MacOSX box will do nicely. To compile and install
-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, set the tt(SET_PROC_TITLE...)
- settings to 0. 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 manual pages on the basic usage of Crossroads and on
- the layout of the configuration file are installed as
- well, if a suitable tt(man/) directory is present under the
- installation prefix directory. If these pages are not
- installed, then you can always copy tt(doc/crossroads.1) to a
- suitable tt(man/man1/) directory, and
- tt(doc/crossroads.conf.7) to a suitable tt(man/man7/)
- directory. After this, tt(man crossroads) and tt(man
- crossroads.conf) would show the appropriate manual pages.
-
- it() The full 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() In order to use the web interface tt(crossroads-mgr),
- make sure that the following Perl modules are available:
- tt(HTTP::Daemon), tt(Getopt::Std),
- tt(MIME::Base64). When in doubt, start the commandline tool
- tt(cpan) and enter tt(install HTTP::Daemon), which will
- install the named module if necessary. You can repeat this for
- all listed modules.
-
-)
-
-
-subsect(Configuring crossroads)label(configuring)
-
-Now that the binary is available on your system, you need to create a
-configuration tt(crossroads.conf). Use this manual to get started. You
-can locate the configuration file in any of the following locations on
-your file system:
-
-itemization(
- it() Along an 'etc' directory that matches the path where
- Crossroads is installed. E.g, when the Crossroads binary is
- tt(/usr/local/bin/crossroads), then the configuration can be
- put in tt(/usr/local/etc/crossroads.conf). Alternatively, if
- you install Crossroads in tt(/opt/crossroads/bin/), then you
- can install the configuration into tt(/opt/crossroads/etc/).
-
- it() As the file tt(/etc/crossroads.conf). When Crossroads
- fails to locate a configuration file near its path, it tries
- this name.)
-
-Once you have the configuration ready, start crossroads with
-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(\
-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.
-
- 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).
-
- 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
-ends are selected and how busy they are. The process list will show
-which crossroads daemons are running. Finally, the tailing of
-tt(/var/log/messages) shows what's going on -- especially if you have
-tt(verbosity true) statements in the configuration.
-
-
-subsect(A boot script)
-
-Finally, you may want to create a boot-time startup script. The exact
-procedure depends on the used Unix flavor.
-
-subsubsect(SysV Style Startup)
-
-On SysV style systems, there's a startup script directory
-tt(/etc/init.d) where bootscripts for all utilities are located.
-You may have the tt(chkconfig) utility to automate the task of
-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:
-
-verb(\
-#!/bin/sh
-/usr/local/bin/crossroads -v $1
-/usr/local/bin/crossroads-mgr $1 1000)
-
- tt(init) will supply the right value for tt($1): "start"
- during startup, and "stop" during shutdown. Note that
- the stated directory tt(/usr/local/bin) must correspond with
- the installation path.
-
- In the first line, The flag tt(-v) causes the startup to be
- more 'verbose'. However, once daemonized, the verbosity of
- Crossroads is controlled by the appropriate statements in the
- configuration.
-
- The second line starts the web interface tt(crossorads-mgr) on
- TCP port 1000. Access to the web interface is free for all;
- add your own flags tt(-b) or tt(-B) to enforce basic
- authentication (see the manual page of tt(crossroads-mgr) and
- section ref(tips/webinterface)).
-
- 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.
-
- 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)
-
-On BSD style systems, daemons are booted directly from tt(/etc/rc) and
-related scripts. Incase you have a file tt(/etc/rc.local), edit it,
-and add the statement:
-
-verb(\
-/usr/local/bin/crossroads start
-/usr/local/bin/crossroads-mgr start 1000)
-
-If your BSD system lacks tt(/etc/rc.local), then you may need to start
-Crossroads from tt(/etc/rc). Your mileage may vary.
-
-
-subsubsect(Linux-related)
-
-When using Crossroads on Linux, the following may be relevant:
-
-itemization(
-
- it() Crossroads supports flag tt(-p), which causes Crossroads not
- to modify the process name. In the absence of the flag, Crossroads
- alters its process name to something like tt(crossroads) tt(-)
- tt(Service) em(myservice:) tt(listening).
-
- Flag tt(-p) may be handy if you want to suppress this
- behavior. The process name is then tt(crossroads-daemon). Some
- boot scripts use the tt(/proc) filesystem to find PID's by
- filename; in those cases, flag tt(-p) can be used.
-
-)
diff --git a/doc/main/conf/addclientheader.yo b/doc/main/conf/addclientheader.yo
@@ -1,151 +0,0 @@
-conf(HTTP Header Modification Directives)
- (Crossroads understands the following
- header modification directives: tt(addclientheader),
- tt(appendclientheader), tt(setclientheader), tt(addserverheader),
- tt(appendserverheader), tt(setserverheader).
-
- The directive names always consist of
- em(Action)em(Destination)tt(header), where:
-
- itemization(
- it() The action is tt(add), tt(append) or tt(insert).
-
- itemization(
- it() Action tt(add) adds a header, even when headers with
- the same name already are present in an HTTP
- message. Adding headers is useful for e.g. tt(Set-Cookie)
- headers; a message may contain several of such headers.
-
- it() Action tt(append) adds a header if it isn't present
- yet in an HTTP message. If such a header is already
- present, then the value is appended to the pre-existing
- header. This is useful for e.g. tt(Via) headers. Imagine
- an HTTP message with a header tt(Via: someproxy). Then the
- directive tt(appendclientheader "Via: crossroads") will
- rewrite the header to tt(Via: someproxy; crossroads).
-
- it() Action tt(set) overwrites headers with the same
- name; or adds a new header if no pre-existing is found.
- This is useful for e.g. tt(Host) headers.)
-
- it() The destination is one of tt(client) or tt(server). When
- the destination is tt(server), then Crossroads will apply such
- directives to HTTP messages that originate from the browser
- and are being forwarded to back ends. When the destination is
- tt(client), then Crossroads will apply such directives to
- backend responses that are shuttled to the browser.)
-
- The format of the directives is e.g. tt(addclientheader
- "X-Processed-By: Crossroads"). The directives expect one
- argument; a string, consisting of a header name, a colon, and a
- header value. As usual, the directive must end with a semicolon.
-
- The header value may contain one of the following formatting
- directives:
-
- INCLUDEFILE(formattable.yo)
-
- The following examples show common uses of header modifications.
-
- description(
- dit(Enforcing session stickiness:) By combining
- tt(stickycookie) and tt(addclientheader), HTTP session
- stickiness is enforced. Consider the following configuration:
-
- verb(\
-service ... {
- ...
- backend one {
- ...
- addclientheader "Set-Cookie: BalancerID=first; path=/";
- stickycookie "BalancerID=first";
- }
- backend two {
- ...
- addclientheader "Set-Cookie: BalancerID=second; path=/";
- stickycookie "BalancerID=second";
- }
-})
-
- The first request of an HTTP session is balanced to either
- backend tt(one) or tt(two). The server response is enriched
- using tt(addclientheader) with an appropriate cookie. A
- subsequent request from the same browser now has that cookie
- in place; and is therefore sent to the same back end where the
- its predecessors went.
-
- The header which is sent to the client to inject a cookie, can
- furthermore be expanded to specify a timeout:
-
- verb(\
-addclientheader "Set-Cookie: BalancerID=second; path=/; expires=%1800g";)
-
- The format specifier tt(%1800g) outputs a GMT-string date 1800
- seconds in the future (half an hour from now).
-
- dit(Hiding the server software version:) Many servers
- (e.g. Apache) advertize their version, as in tt(Server: Apache
- 1.27). This potentially provides information to attackers. The
- following configuration hides such information:
-
- verb(\
-service ... {
- ...
- backend one {
- ...
- setclientheader "Server: WWW-Server";
- }
-})
-
- dit(Informing the server of the clients' IP address:) Since
- Crossroads sits 'in the middle' between a client and a back
- end, the back end perceives Crossroads as its client. The
- following sends the true clients' IP address to the server, in
- a header tt(X-Real-IP):
-
- verb(\
-service ... {
- ...
- backend one {
- ...
- setserverheader "X-Real-IP: %r";
- }
-})
-
- dit(Keep-Alive Downgrading:) The directives
- tt(setclientheader) and tt(setserverheader) also play a key
- role in downgrading Keep-Alive connections to
- 'single-shot'. E.g., the following configuration makes sure
- that no Keep-Alive connections occur.
-
- verb(\
-service ... {
- ...
- backend one {
- ...
- setserverheader "Connection: close";
- setclientheader "Connection: close";
- }
-})))
- (itemization(
- it() tt(addclientheader) em(Headername: headervalue) to add a
- header in the traffic towards the client, even when another
- header em(Headername) exists;
- it() tt(appendclientheader) em(Headername: headervalue) to
- append em(headervalue) to an existing header em(Headername)
- in the traffic towards the client,
- or to add the whole header alltogether;
- it() tt(setclientheader) em(Headername: headervalue) to
- overwrite an existing header in the traffic towards the
- client, or to add such a header;
- it() tt(addserverheader) em(Headername: headervalue) to add a
- header in the traffic towards the server, even when another
- header em(Headername) exists;
- it() tt(appendserverheader) em(Headername: headervalue) to
- append em(headervalue) to an existing header em(Headername)
- in the traffic towards the server,
- or to add the whole header alltogether;
- it() tt(setserverheader) em(Headername: headervalue) to
- overwrite an existing header in the traffic towards the
- server, or to add such a header.))
- (There is no default.)
diff --git a/doc/main/conf/allow.yo b/doc/main/conf/allow.yo
@@ -1,84 +0,0 @@
-conf(allow* and deny* - Allowing or denying connections)
- (Crossroads can allow or deny
- connections based on the IP address of a client. There are four
- directives that are relevant: tt(allowfrom), tt(allowfile),
- tt(denyfrom) and tt(denyfile).
-
- When using tt(allowfrom) and
- tt(denyfrom) then the IP addresses to allow or deny connections are
- stated in the configuration. When using tt(allowfile) and
- tt(denyfile) the allow or deny connections are stated in a
- separate file.
-
- When tt(allow*) directives are used, then all connections are denied
- unless they match the stated allowed IP's. When tt(deny*) directives
- are used, then all connections are allowed unless they match the
- stated disallowed IP's. When denying and allowing is both used,
- then the Crossroads checks the deny list first.
-
- The statements tt(allowfrom) and tt(denyfrom) are followed by a
- list of filter specifications. The statements tt(allowfile) and
- tt(denyfile) are followed by a filename; Crossroads will read
- filter specifications from those external files. In both cases,
- Crossroads obtains filter specifications and places them in its
- lists of allowed or denied IP addresses. The difference between
- specifying filters in the configuration file or in external
- files, is that Crossroads will reload the external files when it
- receives signal 1 (tt(SIGHUP)), as in tt(killall -1 crossroads).
-
- The filter specifications must obey the following syntax: they
- are series of space-separated strings, consisting of up to
- four numbers ranging from 0 to 255 and separated by a decimal
- sign. Optionally a slash follows, with a bitmask which is also a
- decimal number. For example, tt(127.0.0/24 10/8 192.168.2.1) is a
- setting that consists of three specifiers.
-
- This is probably best explained by a few examples:
-
- itemization(
- it() tt(allowfrom 10/8;) will allow connections from
- tt(10.*.*.*) (a full Class A network). The mask tt(/8) means
- that the first 8 bits of the number (ie., only the tt(10)) are
- significant. On the last 3 positions of the IP address, all
- numbers are allowed. Given this directive, client connections
- from e.g. 10.1.1.1 and 10.2.3.4 will be allowed.
-
- it() tt(allowfrom 10.3/16;) will allow all IP addresses that
- start with tt(10.3). The first 16 bits (i.e., the first 2
- numbers) are significant, the rest doesn't matter.
-
- it() tt(allowfrom 10.3.1/16;) is the same as above. The third
- byte of the IP address is superfluous because the netmask
- specifies that only the first 16 bits (2 numbers) are taken
- into account.
-
- it() tt(allowfrom 10.3.1.15;) allows traffic from only the
- specified IP address. There is no bitmask; all four numbers
- are relevant.
-
- it() tt(allowfrom 10.3.1.15 10.2/16;) allows traffic from one
- IP address tt(10.3.1.15) or from a complete Class B network
- tt(10.2.*.*)
-
- it() tt(allowfile /tmp/myfile.txt;) in combination with a file
- tt(/tmp/myfile.txt), with the contents tt(10.3.1.15 10.2/16),
- is the same as above.)
-
- When using ttt(allowfrom) and tt(denyfrom), separate specifiers
- can be stated in one statement (separated by whitespace), or the
- whole statement can be repeated. E.g., the following two
- alternatives have the same effect:
-
- verb(\
-/* Alternative 1: */
-allowfrom 10/8 192.168.1/24;
-
-/* Alternative 2: */
-allowfrom 10/8;
-allowfrom 192.168.1.24;))
- (itemization(
- it() tt(allowfrom) em(filter-specificication(s))
- it() tt(denyfrom) em(filter-specificication(s))
- it() tt(allowfile) em(filename)
- it() tt(denyfile) em(filename)))
- (In absence of these statements, all client IP's are accepted.)
diff --git a/doc/main/conf/backendport.yo b/doc/main/conf/backendport.yo
@@ -1,8 +0,0 @@
-conf(port - Specifying a back end port)
- (Back ends must be known by their host name and a port. Both can
- be simultaneously specified in a tt(server) statement. When the
- tt(server) statement specifies a host name only, then a tt(port)
- statement must be used to specify the port.)
- (tt(port) em(number))
- (There is no default for the port. It must be specified either
- using tt(server) or using tt(port).)
diff --git a/doc/main/conf/backlog.yo b/doc/main/conf/backlog.yo
@@ -1,12 +0,0 @@
-conf(backlog - The TCP Back Log size)
- (The TCP back log size is a number that controls how many
- 'waiting' network connections may be queued, before a client simply
- cannot connect. The syntax is e.g. tt(backlog 5) to cause crossroads
- to have 5 waiting connections for 1 active connection.
- The backlog queue shouldn't be too
- high, or clients will experience timeouts before they can actually
- connect. The queue shouldn't be too small either, because clients
- would be simply rejected. Your mileage may vary.)
- (tt(backlog) em(number))
- (0, which takes the operating system's default
- value for socket back log size.)
diff --git a/doc/main/conf/bindto.yo b/doc/main/conf/bindto.yo
@@ -1,11 +0,0 @@
-conf(bindto - Binding to a specific IP address)
- (The tt(bindto) statement is used in situations where crossroads
- should only listen to the stated port at a given IP address. E.g.,
- tt(bindto 127.0.0.1) causes crossroads to 'bind' the service only to
- the local IP address. Network connections from other hosts won't be
- serviced. By default, crossroads binds a service to all presently
- active IP addresses at the invoking host.)
- (tt(bindto) em(address), where em(address) is a numeric IP
- address, such as 127.0.0.1, or the keyword tt(any).)
- (tt(any))
-
-\ No newline at end of file
diff --git a/doc/main/conf/checkinterval.yo b/doc/main/conf/checkinterval.yo
@@ -1,22 +0,0 @@
-conf(checkinterval - Periodic back end checks)
- (When a check interval is stated, Crossroads will periodically
- probe back ends to determine whether available back ends are
- still there, and to see whether unavailable back ends have woken
- up yet.
-
- An example is tt(checkinterval 10). When this is stated,
- Crossroads will probe all back ends each 10 seconds.)
- (itemization(
- it() tt(checkinterval) em(number);
- it() tt(checkinterval) em(number) tt(externalhandler)
- em(program arguments);)
- The first form checks bhy connecting to the back end server.
- If the connection succeeds, then the back end is considered
- available; otherwise the back end is considered unavailable.
-
- The second form activates an external program (see section
- ref(tips/periodic) for a description). The back end is considered
- available if the program's exit status is zero; otherwise it is
- considered unavailable.)
- (0 (no periodic checks))
-
diff --git a/doc/main/conf/connectiontimeout.yo b/doc/main/conf/connectiontimeout.yo
@@ -1,11 +0,0 @@
-conf(connectiontimeout - Specifying client time outs)
- (Sometimes, clients simply won't close a network
- connection which leads to unnecessary resource usage. To avoid this,
- one might state e.g. tt(connectiontimeout 300). This instructs
- crossroads to consider a connection where nothing has happened for
- 300 seconds as
- 'finished'. Crossroads will terminate the connection when this timeout
- is exceeded.)
- (tt(connectiontimeout) em(number), where em(number) specifies the
- timeout in seconds.)
- (0, meaning that crossroads will not cut connections.)
diff --git a/doc/main/conf/decay.yo b/doc/main/conf/decay.yo
@@ -1,18 +0,0 @@
-conf(decay - Levelling out activity of a back end)
- (To make sure that a 'spike' of activity doesn't
- influence the perceived load of a back end forever, you may
- specify a certain decay. E.g, the statement tt(decay 10) makes
- sure that the load that crossroads computes for this back end (be
- it in seconds or in bytes) is decreased by 10% each time that
- bf(an other) back end is hit. Decays are not applied to the count
- of concurrent connections.
-
- This means that when a given back end is hit, then its usage data
- of the transferred bytes and the connection duration are updated
- using the actual number of bytes and actual duration. However,
- when a different back end is hit, then the usage data are
- decreased by the specified decay. )
- (tt(decay) em(number), where em(number) is a percentage that
- decreases the back end usage data when other back ends are
- hit.)
- (0, meaning that no decay is applied to usage statistics.)
diff --git a/doc/main/conf/dispatchmode.yo b/doc/main/conf/dispatchmode.yo
@@ -1,84 +0,0 @@
-conf(dispatchmode - How are back ends selected)
- (The dispatch mode controls how crossroads selects a back end from
- a list of active back ends. The below text shows the bare
- syntax. See section ref(howselected) for a textual explanation.
-
- The settings can be:
-
- itemization(
- it() tt(dispatchmode roundrobin): Simply the 'next in line' is
- chosen. E.g, when 3 back ends are active, then the usage
- series is 1, 2, 3, 1, 2, 3, and so on.
-
- Roundrobin dispatching is the default method, when no
- tt(dispatchmode) statement occurs.
-
- 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() tt(dispatchmode bysize [ over) em(connections) tt(]):
- The next back end is the one
- that has transferred the least number of bytes. This
- selection mechanism assumes that the more bytes, the heavier
- the load.
-
- The modifier tt(over) em(connections) is optional. (The square
- brackets shown above are not part of the statement but
- indicate optionality.) When given,
- the load is computed as an average of the last stated number of
- connections. When this modifier is absent, then the load is
- computed over all connections since startup.
-
- it() tt(dispatchmode byduration [ over) em(connections) tt(]):
- The next back end is the one
- 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 byorder): The first back end is selected
- every time, unless it's unavailable. In that case the second
- is taken, and so on.
-
- it() tt(dispatchmode byclientip): The client's IP address is
- 'hashed' into a number, which is used to pick a back end. The
- same client IP address will therefore always be dispatched to
- the same back end. When the back end of choice is down,
- tt(dispatchmode byconnections) is used.
-
- it() tt(dispatchmode externalhandler) em(program arguments):
- This is a special mode, where an external program is delegated
- the responsibility to say which back end should be used
- next. In this case, Crossroads will call the external program,
- and this will of course be slower than one of the 'built-in'
- dispatch modes. However, this is the ultimate escape when
- custom-made dispatch modes are needed.
-
- The dispatch mode that uses an tt(externalhandler) is
- discussed separately in section ref(externalhandler).)
-
- 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(http).)
-
- 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.
-
- 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
- estimate load from a network traffic stream, you have to choose an
- appropriate dispatch mode to optimize load balancing. In most cases,
- tt(roundrobin) or tt(byconnections) will do the job just fine.)
- (tt(dispatchmode) em(mode) (see above for the modes), optionally
- followed by tt(over) em(number), or when the em(mode) is
- tt(externalhandler), followed by em(program).)
- (tt(roundrobin))
-
diff --git a/doc/main/conf/headerinspection.yo b/doc/main/conf/headerinspection.yo
@@ -1,13 +0,0 @@
-conf(headerinspection - are all HTTP headers inspected)
- (The tt(headerinspection) directive defines whether Crossroads
-must inspect all HTTP headers that are seen on one TCP connection, or
-only the first ones. There are two possible values for this directive:
-tt(deep) and tt(shallow). In tt(deep) mode, all information that is
-seen on the TCP link is monitored
-and parsed, and all HTTP header blocks are analyzed and subject to
-directives such as tt(addclientheader). In tt(shallow) mode, only the
-first header block that the server sends, and the first header block
-that forms the server's answer, are analyzed.)
- (tt(headerinspection) em(specifier), where em(specifier) is
-tt(deep) or tt(shallow))
- (tt(deep))
diff --git a/doc/main/conf/httptiminglog.yo b/doc/main/conf/httptiminglog.yo
@@ -1,12 +0,0 @@
-conf(httptiminglog - Timing debugging in HTTP mode)
- (The directive tt(httptiminglog) turns on logging of HTTP mode
- timing. There must be one argument, the filename where the timings
- are written to. Turning on this option will slow down processing,
- but may be helpful in finding out where delays are caused.)
- (The syntax is:
-
- itemization(
- it() tt(httptiminglog) em(filename) tt(;)
- it() Where em(filename) is the output file, e.g.
- tt(/tmp/timings.log)))
- (none)
diff --git a/doc/main/conf/maxcon-client.yo b/doc/main/conf/maxcon-client.yo
@@ -1,13 +0,0 @@
-conf(maxconnections - Limiting the connections to a back end)
- (The directive tt(maxconnections) limits the number of allowed
- connections to this client.
- Note that this directive can also occur on the level of a service
- block, in which case it limits the overall number of connections.
-
- bf(Futhermore note) that this directive cannot be used when an external
- dispatcher is in effect. In such cases, the external dispatcher has
- full control over backend selection.)
- (tt(maxconnections) em(number) tt(;))
- (0; meaning no limit)
-
-
diff --git a/doc/main/conf/maxconnections.yo b/doc/main/conf/maxconnections.yo
@@ -1,16 +0,0 @@
-conf(maxconnections - Limiting concurrent clients at service level)
- (The maximum number of connections is specified using
- tt(maxconnections). There is one argument; the number of concurrent
- established connections that may be active within one service.
-
- 'Throttling' the number of connections is a way of preventing Denial of
- Service (DOS) attacks. Without a limit, numerous network connections
- may spawn so many server instances, that the service ultimately breaks
- down and becomes unavailable.
-
- Note that tt(maxconnections) is also allowed in a backend
- description block, in which case it limits the number of TCP
- connections to that particular back end.)
- (tt(maxconnections) em(number), where the number specifies the
- maximum of concurrent connections to the service.)
- (0, meaning that all connections will be accepted.)
diff --git a/doc/main/conf/onfailure.yo b/doc/main/conf/onfailure.yo
@@ -1,10 +0,0 @@
-conf(onfailure and onsuccess - Action Hooks)
- (As special 'hooks' for actions, two triggers
- are available: tt(onfailure) and tt(onsuccess). The argument to
- the triggers is a system command that is executed when a connection
- with the back end either fails or succeeds.)
- (itemization(
- it() tt(onfailure) em(commandline)
- it() tt(onsuccess) em(commandline)))
- (There is no default. Normally no external programs are run upon
- success or failure of a back end.)
diff --git a/doc/main/conf/onhooks.yo b/doc/main/conf/onhooks.yo
@@ -1,27 +0,0 @@
-conf(onstart, onend, onfail - Action Hooks)
- (The three directives tt(onstart), tt(onend) and tt(onfail) can be
- specified to start system commands (external programs) when a
- connection to a back end starts, fails or ends:
- itemization(
- it() tt(onstart) commands will be run when Crossroads
- successfully connects to a back end, and starts servicing;
- it() tt(onend) commands will be run when a (previously
- established) connection stops;
- it() tt(onfail) commands will be run when Crossroads tries to
- contact a back end to serve a client, but the back end can't
- be reached.)
-
- The format is always tt(on)em(type) em(command). The em(command)
- is an external program, optionally followed by arguments. The
- command is expanded according to the following table:
-
- INCLUDEFILE(formattable))
- (The syntax of the commands is as follows.
-
- itemization(
- it() tt(onstart) em(commandline)
- it() tt(onend) em(commandline)
- it() tt(onfail) em(commandline)
- it() tt(onsuccess) em(commandline)))
- (There is no default. Normally no external programs are run upon
- connection, success or failure of a back end.)
diff --git a/doc/main/conf/port.yo b/doc/main/conf/port.yo
@@ -1,11 +0,0 @@
-conf(port - Specifying the listen port)
- (The tt(port) statement defines to which TCP port a service
- 'listens'. E.g. tt(port 8000) says that this service will accept
- connections on port 8000.
-
- Multiple services in one configuration cannot use the same port
- number, unless they both bind to specific (and different) IP
- addresses. See also the tt(bindto) statement.)
- (tt(port) em(number))
- (There is no default. This is a required setting.)
-
diff --git a/doc/main/conf/retries.yo b/doc/main/conf/retries.yo
@@ -1,11 +0,0 @@
-conf(retries - Specifying allowed failures)
- (Back ends that are 'flaky' or on a less reliable network can be
- marked as unavailable after not just one failure, but after
- e.g. three. You can use this configuration if you suspect that
- spurious errors cause otherwise 'good' back ends to be marked as
- unavailable, while they in fact still could be used.)
- (tt(retries) em(number); where em(number) is the threshold of bad
- connections. Once exceeded, Crossroads will mark a back end as
- unavailable.)
- (1; a back end is assumed to be unavailable after the first bad
- connection.)
diff --git a/doc/main/conf/revivinginterval.yo b/doc/main/conf/revivinginterval.yo
@@ -1,26 +0,0 @@
-conf(revivinginterval - Back end wakeup calls)
- (A reviving interval definition is used when Crossroads
- determines that a back end is temporarily unavailable. This will
- happen when:
-
- itemization(
- it() The back end cannot be reached (network connection
- fails);
- it() The network connection to the back end suddenly dies.)
-
- Once a reviving interval is set, Crossroads will periodically
- check the unavailable back end(s) to see whether they have woken up.
-
- An example of the definition is tt(revivinginterval 10). When this
- reviving interval is given, crossroads will check each 10 seconds
- whether unavailable back ends have woken up yet.)
- (itemization(
- it() tt(revivinginterval) em(number);
- it() tt(revivinginterval) em(number) tt(externalhandler)
- em(program arguments);)
- The first form connects to a back end server. If the connection
- succeeds, then the back end is considered available. The second
- form activates an external program (see section
- ref(tips/periodic) for a description). The back end is marked
- available if the program's exit status is zero.)
- (0 (no wakeup calls))
diff --git a/doc/main/conf/server.yo b/doc/main/conf/server.yo
@@ -1,14 +0,0 @@
-conf(server - Specifying the back end address)
- (Each back end must be identified by the network name
- (server name) where it is located. For example: tt(server
- 10.1.1.23), or tt(server web.mydomain.org). A TCP port specifier
- can follow the server name, as in tt(server
- web.mydomain.org:80). bf(Note that) resolved host names can be
- cached by Crossroads. (The DNS cache timeout can be
- controlled using the invocation flag tt(-d).))
- (itemization(
- it() tt(server) em(servername), where em(servername) is a
- network name or IP address. In this case a separate tt(port)
- statement must be used to define the TCP port;
- it() tt(server) em(servername:port)))
- (There is no default. This is a required setting.)
diff --git a/doc/main/conf/shmkey.yo b/doc/main/conf/shmkey.yo
@@ -1,18 +0,0 @@
-conf(shmkey - Shared Memory Access)
- (Different Crossroads
- invocations must 'know' of each others activity. E.g, tt(crossroad
- status) must be able to get to the actual state information of all
- running services. This is internally implemented through shared
- memory, which is reserved using a key.
-
- Normally crossroads will supply a shared memory key, based on the
- service name. In situations where this conflicts with existing
- keys (of other programs, having their own keys), you may supply a
- chosen value.
-
- The actual key value doesn't matter much, as long as it's unique
- and as long as each invocation of crossroads uses it.)
- (tt(shmkey) em(number))
- (0, which means that crossroads will 'guess' its
- own key, based on the service name.)
-
diff --git a/doc/main/conf/state.yo b/doc/main/conf/state.yo
@@ -1,13 +0,0 @@
-conf(state - Setting an initial back end state)
- (Using the tt(state) directive a back end can be 'primed' with an
- initial state. The keyword tt(state) can be followed by
- tt(available), tt(unavailable) or tt(down). Back ends marked
- tt(unavailable) are excluded as candidates, but are checked when
- a tt(revivinginterval) or a tt(checkinterval) is used. Back ends
- marked tt(down) are excluded and never re-checked.)
- (itemization(
- it() tt(state) em(specifier) tt(;)
- it() where em(specifier) is one of tt(available),
- tt(unavailable) or tt(down)))
- (tt(available), meaning that a back end is a candidate for
- initial dispatching.)
diff --git a/doc/main/conf/stickycookie.yo b/doc/main/conf/stickycookie.yo
@@ -1,35 +0,0 @@
-conf(stickycookie - Back end selection with an HTTP cookie)
- (The directive tt(stickycookie) em(value)
- causes Crossroads to unpack clients' requests, to check for
- em(value) in the cookies. When found, the message is routed to the
- back end having the appropriate tt(stickycookie) directive.
-
- E.g., consider the following configuration:
-
- verb(\
-service ... {
- ...
- backend one {
- ...
- stickycookie "BalancerID=first";
- }
- backend two {
- ...
- stickycookie "BalancerID=second";
- }
-})
-
- When clients' messages contain cookies named tt(BalancerID) with
- the value tt(first), then such messages are routed to backend
- tt(one). When the value is tt(second) then they are routed to the
- backend tt(two).
-
- There are basically to provide such cookies to a browser. First, a
- back end can insert such a cookie into the HTTP response. E.g.,
- the webserver of back end tt(one) might insert a cookie named
- tt(BalancerID), having value tt(first).
- Second, Crossroads can insert such cookies using a carefully
- crafted directive tt(addclientheader).)
- (tt(stickycookie) em(cookievalue))
- (There is no default.)
-
diff --git a/doc/main/conf/trafficlog.yo b/doc/main/conf/trafficlog.yo
@@ -1,20 +0,0 @@
-conf(trafficlog and throughputlog - Debugging and Performance Aids)
- (Two directives are available
- to log network traffic to files. They are tt(trafficlog) and
- tt(throughputlog).
-
- The tt(trafficlog) statement causes all traffic to be logged in
- hexadecimal format. Each line is prefixed by tt(B) or tt(C),
- depending on whether the information was received from the back
- end or from the client.
-
- The tt(throughputlog) statement writes shorthand transmissions to
- its log, accompanied by timings and the number of bytes each
- transmission was able to read or write in one chunk.)
- (The syntax is:
-
- itemization(
- it() tt(trafficlog) em(filename) tt(;)
- it() tt(throughputlog) em(filename) tt(;)))
- (none)
-
diff --git a/doc/main/conf/type.yo b/doc/main/conf/type.yo
@@ -1,18 +0,0 @@
-conf(type - Defining the service type)
- (The tt(type) statement defines how crossroads handles the stated
- service. There are currently two types: tt(any) and
- 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(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 such special features, use the type tt(any) (the
- default), even for HTTP protocols.)
- (tt(type) em(specifier), where em(specifier) is tt(any) or
- tt(http))
- (tt(any))
-
-
diff --git a/doc/main/conf/useraccount.yo b/doc/main/conf/useraccount.yo
@@ -1,14 +0,0 @@
-conf(useraccount - Limiting the effective ID of external processes)
- (Using the directive tt(useraccount), the effective user and group
- ID can be restricted. This comes into effect when Crossroads runs
- external commands, such as:
- itemization(
- it() Hooks for tt(onstart), tt(onend) or tt(onfail);
- it() External dispatchers, when tt(dispatchmode
- externalhandler) is in effect.)
- Once a user name for external commands is specified, Crossroads
- assumes the associated user ID and group ID before running those
- commands.)
- (tt(useraccount) em(username))
- (None; when unspecified, external commands are run with the
- ID that was in effect when Crossroads was started.)
-\ No newline at end of file
diff --git a/doc/main/conf/verbose-backend.yo b/doc/main/conf/verbose-backend.yo
@@ -1,10 +0,0 @@
-conf(verbosity - Controlling verbosity at the back end level)
- (Similar to tt(service) specifications, a
- tt(backend) can have its own verbosity (tt(on) or tt(off)). When
- tt(on), traffic to and fro this back end is reported.)
- (itemization(
- it() tt(verbosity) em(setting), or
- it() tt(verbose) em(setting), where em(setting) is tt(true),
- tt(yes) or tt(on), or tt(false), tt(no), tt(off) to turn it
- off.))
- (tt(off))
diff --git a/doc/main/conf/verbose.yo b/doc/main/conf/verbose.yo
@@ -1,14 +0,0 @@
-conf(verbosity - Controlling debug output)
- (Verbosity statements come in two forms: tt(verbosity on) or
- tt(verbosity off). When 'on', log messages to tt(/var/log/messages)
- are generated that show what's going on.footnote(Actually, the
- messages go to tt(syslog(3)), using facility tt(LOG_DAEMON) and
- priority tt(LOG_INFO). In most (Linux) cases this will mean: output to
- tt(/var/log/messages). On Mac OSX the messages go to
- tt(/var/log/system.log).) The keyword tt(verbose) is an alias for
- tt(verbosity).)
- (tt(verbosity) em(setting) or tt(verbose) em(setting), 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.)
- (tt(off))
-
-\ No newline at end of file
diff --git a/doc/main/conf/weight.yo b/doc/main/conf/weight.yo
@@ -1,15 +0,0 @@
-conf(weight - When a back end is more equal than others)
- (To influence how backends are selected, a backend can specify its
- 'weight' in the process. The higher the weight, the less likely a
- back end will be chosen. The default is 1.
-
- The weighing mechanism only applies to the dispatch modes
- tt(random), tt(byconnections), tt(bysize) and tt(byduration).
- The weight is in fact a penalty factor. E.g., if backend A has
- tt(weight 2) and backend B has tt(weight 1), then backend B will
- be selected all the time, until its usage parameter is twice as
- large as the parameter of A. Think of it as a 'sluggishness'
- statement.)
- (tt(weight) em(number); the higher the number, the more 'sluggish'
- a back end is)
- (1; all back ends have equal weight.)
diff --git a/doc/main/config.yo b/doc/main/config.yo
@@ -1,278 +0,0 @@
-The configuration that crossroads uses is normally stored in the file
-tt(crossroads.conf), either in an 'etc' directory near the binary, or
-in tt(/etc/). See section ref(configuring) for details.
-
-The name of the configuration file can be overruled using the
-command line flag tt(-c).
-
-This section explains the syntax of the configuration file, and what
-all settings do.
-
-confsect(General language elements)
-
-This section describes the general elements of the crossroads
-configuration language.
-
-
-confsubsect(Empty lines, indentation and comments)
-
-Empty lines are of course allowed in the configuration. Also,
-indentation is irrelevant as far as processing is concerned, but is
-loosely inspired on a C-like style. So the following two examples are
-identical as far as Crossroads is concerned (thought the first one
-will be typically more readable):
-
-verb(/* Example one */
-options {
- tcpbuffersize 10240;
- logactivity on;
-}
-
-/* Example two */
-options {tcpbuffersize 10240
-;logactivity on;})
-
-Crossroads recognizes the following comment formats:
-
-itemization(
- it() C-style, between tt(/*) and tt(*/),
- it() C++-style, starting with tt(//) and ending with the end
- of the text line.)
-
-Simply choose your favorite editor and use the comment that 'looks
-best'.footnote(I favor C or C++ comment. My favorite editor em(emacs)
-can be put in tt(cmode) and nicely highlight what's comment and what's
-not. And as a bonus it will auto-indent the configuration!)
-
-
-confsubsect(Preprocessor directives)
-
-Similar to bf(C) or bf(C++), the Crossroads grammar knows tt(#include)
-and tt(#define). Both directives must start at the first column of the
-line (ie., the tt(#) sign must occur at the leftmost line
-position).
-
-itemization(
- it() tt(#include) tt(")em(filename)tt(") includes the stated file
- name at the place of the statement.
- it() tt(#define) em(SYMBOL) em(DEFINITION) defines em(SYMBOL)
- as placeholder for em(DEFINITION).)
-
-For example, one may use the configuration:
-
-verb(\
-#define SERVICEPORT 80
-service web {
- port SERVICEPORT;
- .
- . /* More statements follow here */
- .
-})
-
-The tt(port) statement is then read as tt(port 80).
-
-The statement tt(#define) can also be very nicely used when trying out
-Crossroads configurations. Crossroads has a statement tt(verbosity)
-tt(true) that causes debugging information to be logged. Once a
-configuration has proven to work, you'll most likely want
-tt(verbosity) tt(false) so that overhead due to logging is
-avoided. This can be easily implemented using tt(#define):
-
-verb(\
-/* Set DEBUG to true or false;
- * true is for testing purposes,
- * false is for production */
-#define DEBUG true
-
-service web {
- verbosity DEBUG;
- .
- . /* More statements follow here */
- .
-})
-
-
-confsubsect(Keywords, numbers, identifiers, generic strings)
-
-In a configuration file, statements are identified by em(keywords),
-which are reserved words. The list of the keywords of the Crossroads
-grammar is:
-includefile(keywords.yo)
-
-Many keywords require an em(identifier) as the argument. E.g, a
-service has a unique name, which must start with a letter or
-underscore, followed by zero or more letters, underscores, or
-digits. E.g., in the statement tt(service myservice), the keyword is
-tt(service) and the identifier is tt(myservice).
-
-Other keywords require a numeric argument. Crossroads knows only
-non-negative integer numbers, as in tt(port 8000). Here, tt(port) is
-the keyword and tt(8000) is the number. Octal numbers are specified by
-prefixing a zero; e.g., tt(0644) is an octal number.
-
-Yet other keywords require 'generic strings', such as hostname
-specifications or system commands. Such generic strings contain any
-characters (including white space) up to the terminating statement
-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 ;)
-
-Finally, an argument can be a 'boolean' value. Crossroads knows
-tt(true), tt(false), tt(yes), tt(no), tt(on), tt(off). The keywords
-tt(true), tt(yes) and tt(on) all mean the same and can be used
-interchangeably; as can the keywords tt(false), tt(no) and tt(off).
-
-
-confsect(Daemon options)label(daemonoptions)
-
-Crossroads supports an optional block that defines run options for the
-daemon process. These options can be also be specified on the command line
-using flags.
-
-The syntax of the options block is:
-
-verb(options {
- .
- . option statements (see below)
- .
-})
-
-In the curly-brace block the following option statements can occur:
-
-itemization(
- it() tt(logactivity on;) or tt(off) Turns activity logging on
- or off. This is also controlled using the flag tt(-a). The
- default is not to log network activity.
-
- it() tt(tcpbuffersize) em(number) tt(;) This defines the size
- of network buffers. The default is 5120 bytes. This is also
- controlled using the flag tt(-B).
-
- it() tt(dnscachettl) em(number) tt(;) This controls the
- time-to-live of cached DNS entries, in seconds. Value zero
- means no caching and is the default. This is also controlled
- using the flag tt(-d).
-
- it() tt(logfacility) em(number) tt(;) This controls the
- logging facility. Values 0 to 7 select tt(LOG_LOCAL0) to
- tt(LOG_LOCAL7). Any other value selects tt(LOG_DAEMON), which
- is also the default. This is also controlled using the flag tt(-l).
-
- it() tt(shmpermissions) tt(number) tt(;) This defines the
- permissions (for user, group and other) of the shared memory
- block. The number is most often specified as an octal value,
- e.g. tt(0644), which is also the default. This is also
- controlled using the flag tt(-m).
-
- it() tt(sloppyportbind on;) or tt(off) Turns on 'sloppy' port
- binding of the listener. When tt(on), Crossroads will not
- treat port-busy conditions as fatal, but will wait and retry.
- The default is tt(off). This is also controlled using flag
- tt(-s).
-
- it() tt(leaveprocesstitle) tt(on;) or tt(off) When tt(on), the
- process title of Crossroads is not modified, so that tt(ps)
- will show tt(crossroads-daemon). The default is tt(off):
- Crosroads will modify its process name into something like
- em(crossroads - Sevice web: listening) or em(crossroads -
- Service web: serving).)
-
-
-confsect(Service definitions) label(servicedef)
-
-Service definitions are blocks in the configuration file that
-state what is for each service. A service definition starts with
-tt(service), followed by a unique identifier, and by statements in
-tt({) and tt(}). For example:
-
-verb(\
-// Definition of service 'www':
-service www {
- ...
- ... // statements that define the
- ... // service named 'www'
- ...
-})
-
-The configuration file can contain many service blocks, as long as the
-identifying names differ. The following list shows possible
-statements. Each statement must end with a semicolon, except for the
-tt(backend) statement, which has is own block (more on this later).
-
-redef(conf)(4)(\
- confsubsect(ARG1) label(confARG1)
- startdit()
- dit(Description:) ARG2
- dit(Syntax:) ARG3
- dit(Default:) ARG4
- enddit())
-
-
-includefile(conf/port)
-includefile(conf/type)
-includefile(conf/headerinspection)
-includefile(conf/bindto)
-includefile(conf/verbose)
-includefile(conf/dispatchmode)
-includefile(conf/revivinginterval)
-includefile(conf/checkinterval)
-includefile(conf/maxconnections)
-includefile(conf/backlog)
-includefile(conf/shmkey)
-includefile(conf/allow)
-includefile(conf/useraccount)
-
-
-confsect(Backend definitions)
-
-Inside the service definitions as are described in the previous
-section, em(backend definitions) must also occur. Backend definitions
-are started by the keyword tt(backend), followed by an identifier
-(the back end name) , and statements inside tt({) and tt(}):
-
-verb(\
-service myservice {
- ...
- ... // statements that define the
- ... // service named 'myservice'
- ...
-
- backend mybackend {
- ...
- ... // statements that define the
- ... // backend named 'mybackend'
- ...
- }
-})
-
-Each service definition must have at least one backend
-definition. There may be more (and probably will, if you want
-balancing and fail over) as long as the backend names differ.
-The statements in the backend definition blocks are described in the
-following sections.
-
-Some directives (tt(stickycookie) etc.) only have effect when
-Crossroads treats the network traffic as a stream of HTTP messages;
-i.e., when the service is declared with tt(type http). Incase of
-tt(type any), the HTTP-specific directives have no effect.
-
-includefile(conf/server.yo)
-includefile(conf/backendport.yo)
-includefile(conf/verbose-backend.yo)
-includefile(conf/retries.yo)
-includefile(conf/maxcon-client.yo)
-includefile(conf/weight)
-includefile(conf/decay)
-includefile(conf/state)
-includefile(conf/onhooks)
-includefile(conf/trafficlog)
-includefile(conf/httptiminglog)
-includefile(conf/stickycookie)
-includefile(conf/addclientheader)
diff --git a/doc/main/crossroads.yo b/doc/main/crossroads.yo
@@ -1,44 +0,0 @@
-includefile(../crossroads-defs)
-tocclearpage()
-titleclearpage()
-includefile(defs)
-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 modify HTTP headers, e.g. to
- provide 'session stickiness' for back end processes that need
- sessions, but aren't session-aware of other
- back ends. Crossroads is configured via a file and accessible
- via a web interface.)
-article(Crossroads VER())
- (AUTHORNAME() nl()
- Maintained by MAINTAINERNAME() (MAINTAINEREMAIL()))
- (YEARS(), ff.)
-
-sect(Introduction)
-includefile(intro)
-
-sect(Installation for the impatient)
-includefile(impatient)
-
-sect(Using Crossroads)
-includefile(using)
-
-redef(confsect)(1)(subsect(ARG1))
-redef(confsubsect)(1)(subsubsect(ARG1))
-sect(The configuration)
-includefile(config)
-
-sect(Tips, Tricks and Random Remarks)
-includefile(tips)
-
-sect(Benchmarking)
-includefile(benchmarking)
-
-sect(Compiling and Installing) label(installation)
-includefile(compiling)
-
diff --git a/doc/main/defs.yo b/doc/main/defs.yo
@@ -1,84 +0,0 @@
-COMMENT(
-
- 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
-own. E.g., you'll want to a use different affiliation, mailto, and so
-on.
-
-Also, the shown latexlayoutcmds() probably won't be what you like to
-see... Good luck!
--- [KK 2004-11-17]
-
-)
-
-COMMENT(General document modifiers)
-htmlstylesheet(http://www.e-tunity.com/css/yodl.css)
-affiliation(e-tunity)
-mailto(info@e-tunity.com)
-latexlayoutcmds(
- \usepackage{a4wide}
- \usepackage{fancyhdr}
- \usepackage{graphicx}
- \usepackage{moreverb}
- \usepackage{palatino}
- \setlength{\textheight}{21cm}
- \setlength{\parindent}{0pt}
- \setlength{\parskip}{1ex plus 0.5ex minus 0.2ex}
- \renewcommand{\headrulewidth}{.6pt}
- \renewcommand{\footrulewidth}{.6pt}
- \fancypagestyle{plain}{
- \fancyhf{}
- \fancyhead[LE,RO]{}
- \fancyhead[LO]{\small\slshape \leftmark}
- \fancyhead[RE]{\small\slshape \rightmark}
- \fancyfoot[LE,RO]{\small\thepage}
- %\fancyfoot[RE,LO]{\small\textbf{e-tunity}}
- }
- \AtBeginDocument{\pagestyle{plain}})
-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.)
-
-redef(pngfig)(3)(\
- whenhtml(figure(ARG1)(ARG2)(ARG3))\
- whenlatex(\
- latexcommand(\begin{figure}[htbp])\
- latexcommand(\centerline{)\
- latexcommand(\includegraphics[scale=.5]{)\
- ARG1.png+\
- latexcommand(}})\
- latexcommand(\caption{\small )ARG2+latexcommand(})\
- latexcommand(\label{)ARG3+latexcommand(})\
- latexcommand(\end{figure}))
- whenman(verb(
- =====================================================
- Insert figure ARG1 about here
- ARG2
- =====================================================)\
- label(ARG3)))
-
-COMMENT(listing(text)
- A-la verb() but nicely formatted in LaTeX.)
-
-redef(listing)(1)(\
- whenhtml(verb(ARG1))\
- whenlatex(\
- PUSHCHARTABLE()
- latexcommand(\begin{listing}{1})\
- XXnl()\
- NOEXPAND(ARG1)\
- XXnl()\
- latexcommand(\end{listing})
- POPCHARTABLE())\
- whenman(\
- XXroffcmd(.nf)()()()\
- INTERNALINDEX(verb on)\
- NOEXPAND(ARG1)\
- INTERNALINDEX(verb off)\
- XXroffcmd(.fi)()()()))
diff --git a/doc/main/formattable.yo b/doc/main/formattable.yo
@@ -1,59 +0,0 @@
-itemization(
-
- it() tt(%a) is the availability of the current back end, when
- a current back end is established. tt(%1a) is the
- availability of the first back end (0 when unavailable, 1 if
- available); tt(%2a) is the availability of the second back
- end, and so on.
-
- it() tt(%b) is the name of the current back end, when one is
- established. tt(%1b) is the name of the first back end,
- tt(%2b) of the second back end, and so on.
-
- it() tt(%e) is the count of seconds since start of epoch
- (January 1st 1970 GMT). tt(%60e) is the count since start of
- epoch plus 60, so this is a 1 minute offset into the future.
-
- it() tt(%g) is a "GMT-string" representation of the current
- time, in the format em(monthname, day year hh:mm:ss). This
- format is used in e.g. cookie expiry. tt(%600g) is the same
- representation but of a moment 600 seconds in the future (10
- minutes).
-
- it() tt(%h) is the host name of the current back end. tt(%1h)
- is the host name of the first back end, tt(%2h) of the second
- back end, and so on.
-
- it() tt(%l) is the duration of the last successful connection
- in seconds, concerning the current back end. tt(%1l) is the
- duration of the connection to back end one, and so on. Note
- that tt(%l) refers only to the last successful connections.
- Unsuccessful connection attempts to back ends do not change
- the value.
-
- it() tt(%p) is the TCP port of the current back end. tt(%1p)
- is the TCP port of the first back end, tt(%2p) of the second
- back end, and so on.
-
- it() tt(%P) is the process ID of the Crossroads handler that
- handled this request. For debugging only.
-
- it() tt(%r) is the IP address of the connecting client.
-
- it() tt(%s) is the name of the current service that the client
- connected to.
-
- it() tt(%t) is the current local time in ANSI format, in
- em(YYYY-MM-DD/hhh:mm:ss). tt(%1800s) is an ANSI stamp of a
- moment 1800 seconds in the future (half an hour).
-
- it() tt(%T) is the current GMT time in ANSI format. tt(%10T)
- offsets this 10 seconds into the future.
-
- it() tt(%v) is the Crossroads version.
-
- it() tt(%w) is the weight factor of the current back
- end. tt(%1w) is the weight factor of the first back end, etc..
-
- it() Any other chararacter following a tt(%) sign is taken
- literally; e.g. tt(%z) is just a z.)
diff --git a/doc/main/impatient.yo b/doc/main/impatient.yo
@@ -1,73 +0,0 @@
-
-For the impatient, here's the very-quick-but-very-superficial recipy
-for getting Crossroads up and running:
-
-itemization(
-
- 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.
-
- it() Change-dir into the create directory tt(crossroads/).)
-
- 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()
- 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() 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() Create a configuration file as e.g.
- tt(/etc/crossroads.conf). (Other locations are permitted. See
- section ref(configuring) for details.) In it state something
- like:
-
- verb(\
-service www {
- port 80;
- revivinginterval 15;
- backend one {
- server 10.1.1.100:80;
- }
- backend two {
- server 10.1.1.101:80;
- }
-})
-
- 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() 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 from the command
- line, type tt(crossroads status).
-
- it() If you want to monitor Crossroads via a web front end,
- start the manager: type tt(crossroads-mgr start 1000). Next
- point your browser to the machine where Crossroads is
- running, port 1000.
-)
diff --git a/doc/main/intro.yo b/doc/main/intro.yo
@@ -1,294 +0,0 @@
-Crossroads is a daemon that basically accepts TCP connections at
-preconfigured ports, and given a list of 'back ends' distributes each
-incoming connection to one of the back ends, so that a client request
-is served. Additionally, crossroads maintains an internal
-administration of the back end connectivity: if a back end isn't
-usable, then the client request is handled using another back
-end. Crossroads will then periodically check whether a previously not
-usable back end has come to life yet. Also, crossroads can select back
-ends by estimating the load, so that balancing is achieved.
-
-Using this approach, crossroads serves as load balancer and fail over
-utility. Crossroads will very likely not be as reliable as hardware
-based balancers, since it always will require a server to run on. This
-server, in turn, may become a new Single Point of Failure (SPOS).
-However, in situations where cost efficiency is an issue, crossroads
-may be a good choice. Furthermore, crossroads can be deployed in
-situations where a hardware based balancing already exists and
-augmenting service reliability is needed. Or, crossroads may be run
-off a diskless system, which again improves reliability of the
-underlying hardware.
-
-This document describes how to use crossroads, how to configure it in
-order to increase the reliability of your systems, and how to compile
-the program from its sources. whenhtml(This document is also available
-in url(PDF)(crossroads.pdf) format.)
-
-
-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://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, mail the author or maintainer for credentials.)
-
-
-subsect(Reporting bugs)
-
-Crossroads was thoroughly tested and proven to work. However, on
-particular Unices with particular needs and network particularities,
-bugs may occur.
-
-In such cases you can contact the maintainer to ask for
-assistance. Visit the site url(http://crossroads.e-tunity.com)
-(http://crossroads.e-tunity.com) for contact information. In questions
-or bug reports, always include the following:
-
-itemization(
- it() A description of the bug: when does it occur, what are
- the circumstances, what is the expected behavior, what is the
- observed behavior.
-
- it() The Crossroads configuration in the file tt(crossroads.conf)
-
- it() The version of Crossroads and all compile-time settings,
- obtained via tt(crossroads -C).)
-
-
-subsect(Copyright and Disclaimer)
-
-Crossroads is distributed as-is, without assumptions of fitness or
-usability. You are free to use crossroads to your liking. It's free,
-and as with everything that's free: there's also no
-warranty. Crossroads is distibuted under the GNU General Public
-Licence, version 3. See lurl(http://crossroads.e-tunity.com) for more
-information.
-
-You are allowed to make modifications to the source code of
-crossroads, and you are allowed to (re)distribute crossroads, as long
-as you include this text, all sources, and if applicable: all your
-modifications, with each distribution.
-
-While you are allowed to make any and all changes to the sources, I
-would appreciate hearing about them. If the changes concern new
-functionality or bugfixes, then I'll include them in a next release,
-stating full credits. If you want to seriously contribute (to which
-you are heartily encouraged), then mail me and I'll get you access to
-the Crossroads SVN repository, so that you can update and commit as
-you like.
-
-subsect(Terminology)
-
-Throughout this document, the following terms are used: footnote(Many
-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(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(Headers) or bf(header lines) are specific parts of an HTTP
- message. Crossroads has directives to add or modify
- headers that are part of the request that a browser sends
- to server, or those that are part of the server.
- 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)
-
-This section lists some caveats when converting Crossroads
-configurations to new versions. Given the changes of the syntax of the
-configuration file of Crossroads, existing configuration files may
-need to be made suitable for new versions.
-
-subsubsect(Porting issues for pre-1.80 installations)
-
- Please be aware that as of version 1.80, the Crossroads
- configuration file may be located in an 'etc' directory along the
- path where Crossroads was started. E.g., if the Crossroads binary
- is tt(/usr/local/bin/crossroads), then Crossroads will read the
- configuration file tt(/usr/local/etc/crossroads.conf) before
- defaulting to tt(/etc/crossroads.conf). When installing
- configurations to such 'etc' directories along the path, be sure
- to remove stale configuration files. Crossroads will only parse
- one primary configuration file.
-
-subsubsect(Porting issues for pre-1.63 installations)
-
- The parser of Crossroads 1.63 has become even
- stricter. HTTP-related commands, such as tt(addclientheader), may
- only occur when the service type is tt(http).
-
- Previously such directives were allowed, albeit they would be
- ineffective.
-
-subsubsect(Porting issues for pre-1.50 installations)
-
- As of version 1.50, the command tt(crossroads tell) has been
- changed. To set a state, the command must be used as follows:
-
- center(tt(crossroads) tt(tell) em(service) em(backend) tt(state)
- em(newstate))
-
- The keyword tt(state) was added. This is because tt(crossroads
- tell) can also set a new server address; in that case the keyword
- tt(server) is required. If you have automatic health checkers or
- the like that change the back end states, please modify the
- commands to suit this.
-
-subsubsect(Porting issues for pre-1.43 installations)
-
- As of version 1.43, the shared memory key calculations are based
- on a different algorithm. This key is e.g. necessary when starting
- and stopping Crossroads; in both actions, the key must be computed
- in the same way.
-
- Therefore, when upgrading Crossroads, make sure that you stop a
- running Crossroads daemon using the same binary that started
- it. After this, install a new binary, and start the daemon using
- the new binary.
-
- (Incidentally, this is always a good idea, but especially so when
- the 'old' binary is pre-1.43 and the 'new' one is post-1.43.)
-
- Furthermore, shell-style comment is no longer supported as of
- 1.43. The reason is that 1.43 introduces the hash mark as a
- preprocessor token (in tt(#include), tt(#define)). Therefore, if
- your configuration files use shell-style comment, please convert
- this to bf(C) or bf(C++) style.
-
-subsubsect(Porting issues for pre-1.21 installations)
-
- As of version 1.21, the event-hook directives tt(onsuccess) and
- tt(onfailure) no longer exists.
-
- itemization(
- it() Please replace tt(onsuccess) by tt(onstart);
- it() Please replace tt(onfailure) bu tt(onfail);
- it() Note that there is a new hook tt(onend).)
-
- The commands that are run via tt(onstart), tt(onend) or tt(onfail)
- are subject to format expansion; e.g., tt(%1w) is expanded to the
- weight of the first back end, etc.. See section ref(config) for details.
-
-subsubsect(Porting issues for pre-0.26 installations)
-
- As of version 0.26 the syntax of the configuration file has
- 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).)
-
- Therefore when converting configuration files to the new syntax,
- the above keywords must be changed. (The reason for these changes
- is that 0.26 introduces em(sticky HTTP sessions) that span
- multiple TCP connections, and the term
- em(session) is used strictly in that sense -- and no longer for a
- TCP connection.)
-
-subsubsect(Porting issues for pre-1.08 installations)
-
- As of version 1.08, the following directives no longer are
- supported:
-
- itemization(
- it() tt(insertstickycookie) was replaced by the more generic
- directive tt(addclientheader). E.g., instead of nl()
- tt(insertstickycookie "XRID=100; Path=/";) nl()
- the syntax is now nl()
- tt(addclientheader "Set-Cookie: XRID=100; Path=/";)
-
- it() tt(insertrealip) was replaced by the more generic
- directive tt(setserverheader). E.g., instead of nl()
- tt(insertrealip on;) nl()
- the syntax is now nl()
- tt(setserverheader "XR-Real-IP: %r";) nl()
- This incidentally also makes it possible to change the header
- name (here: tt(XR-Real-IP)).)
-
diff --git a/doc/main/keywords.yo b/doc/main/keywords.yo
@@ -1,63 +0,0 @@
-tt(service)
-tt(port)
-tt(verbosity)
-tt(maxconnections)
-tt(type)
-tt(any)
-tt(http)
-tt(backend)
-tt(server)
-tt(bindto)
-tt(connectiontimeout)
-tt(on)
-tt(off)
-tt(dispatchmode)
-tt(roundrobin)
-tt(random)
-tt(byduration)
-tt(bysize)
-tt(byconnections)
-tt(byorder)
-tt(byclientip)
-tt(over)
-tt(decay)
-tt(revivinginterval)
-tt(checkinterval)
-tt(retries)
-tt(shmkey)
-tt(weight)
-tt(onstart)
-tt(onfail)
-tt(backlog)
-tt(throughputlog)
-tt(trafficlog)
-tt(httptiminglog)
-tt(stickycookie)
-tt(addclientheader)
-tt(setclientheader)
-tt(appendclientheader)
-tt(addserverheader)
-tt(setserverheader)
-tt(appendserverheader)
-tt(allowfrom)
-tt(denyfrom)
-tt(allowfile)
-tt(denyfile)
-tt(externalhandler)
-tt(useraccount)
-tt(onend)
-tt(headerinspection)
-tt(deep)
-tt(shallow)
-tt(state)
-tt(available)
-tt(unavailable)
-tt(down)
-tt(options)
-tt(logactivity)
-tt(tcpbuffersize)
-tt(dnscachettl)
-tt(logfacility)
-tt(shmpermissions)
-tt(sloppyportbind)
-tt(leaveprocesstitle)
diff --git a/doc/main/tips.yo b/doc/main/tips.yo
@@ -1,54 +0,0 @@
-The following sections elaborate on the directives as described in
-section ref(config) to illustrate how crossroads works and to help you
-achieve the "optimal" balancing configuration.
-
-subsect(Configuration examples)
-includefile(tips/examples)
-
-subsect(How back ends are selected in load balancing) label(howselected)
-includefile(tips/howselected)
-
-subsect(Periodic probes and wake up calls)
-includefile(tips/periodic)
-
-subsect(Throttling the number of concurrent connections)
-includefile(tips/throttling)
-
-subsect(TCP Session Stickiness)
-includefile(tips/tcpstickiness)
-
-subsect(HTTP Session Stickiness)
-includefile(tips/httpstickiness)
-
-subsect(Passing the client's IP address)
-includefile(tips/clientip)
-
-subsect(Deep or shallow HTTP header inspection)
-includefile(tips/deeporshallow)
-
-subsect(Debugging network traffic)
-includefile(tips/debugging)
-
-subsect(IP filtering: Limiting Access by Client IP Address)
-includefile(tips/ipfiltering)
-
-subsect(Using an external program to dispatch) label(externalhandler)
-includefile(tips/externalhandler)
-
-subsect(Linux and ip_conntrack_max)
-includefile(tips/ipconntrackmax)
-
-subsect(Marking back ends as bad after more than one try)
-includefile(tips/retries)
-
-subsect(Using the Web Interface crossroads-mgr)
-includefile(tips/webinterface)
-
-subsect(Rendering Crossroads' status in a web page) label(xmlstatus)
-includefile(tips/rendering)
-
-subsect(Crossroads and DNS caching)
-includefile(tips/dnscaching)
-
-subsect(Managing a Pool of Virtual Back Ends)
-includefile(tips/virtual)
diff --git a/doc/main/tips/clientip.yo b/doc/main/tips/clientip.yo
@@ -1,78 +0,0 @@
-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() Make sure that the tt(headerinspection) is tt(deep) (or that
- there is no tt(headerinspection) statement, since tt(deep) is
- the default, see section ref(tips/deeporshallow));
- it() In the back end definition, the following statement must
- occur: nl()
- tt(addserverheader "X-Real-IP: %r";) nl()
- You are of course free to choose the header name; the here
- used tt(X-Real-IP) is a common name for this purpose.)
-
-After this, HTTP traffic that arrives at the back ends has a new
-header: tt(X-Real-IP), holding the client's IP address.
-bf(Note that) once the type is set to tt(http), Crossroads'
-performance will be hampered -- all passing messages will have to be
-unpacked and analyzed.
-
-subsubsect(Sample Crossroads configuration)
-
-The below sample configuration shows two HTTP back ends that receive
-the client's IP address:
-
-verb(
-service www {
- port 80;
- type http;
- revivinginterval 5;
- dispatchmode roundrobin;
-
- backend one {
- server 10.1.1.100:80;
- addserverheader "X-Real-IP: %r";
- }
-
- backend two {
- server 10.1.1.200:80;
- addserverheader "X-Real-IP: %r";
- }
-})
-
-
-subsubsect(Sample Apache configuration)
-
-The method by which each back end analyzes the header tt(X-Real-IP)
-will obviously be different per server implementations. However, a
-common method with the Apache webserver is to log the client's IP
-address into the access log.
-
-Often this is accomplished using the log format tt(custom), defined as
-follows:
-
-verb(\
-LogFormat "%h %l %u %t %D \"%r\" %>s %b" common
-CustomLog logs/access_log common)
-
-The first line defines the format tt(common), with the remote host
-specified by tt(%h). The second line sends access information to a log
-file tt(logs/access_log), using the previously defined format
-tt(common).
-
-Furtunately, Apache's tt(LogFormat) allows one to log contents of
-headers. By replacing the tt(%h) with tt(%{X-Real-IP}i), the desired
-information is sent to the log. Therefore, normally you can simply
-redefine the tt(common) format to
-
-verb(\
-LogFormat "%{X-Real-IP}i %l %u %t %D \"%r\" %>s %b" common)
diff --git a/doc/main/tips/debugging.yo b/doc/main/tips/debugging.yo
@@ -1,107 +0,0 @@
- Incase the traffic between client and backend must be debugged,
- the statement tt(trafficlog) em(filename) can be issued. This
- causes the traffic to be dumped in hexadecimal format to the
- stated filename.
-
- Traffic sent by the client is prefixed by a bf(C), traffic sent by
- the back end is prefixed by a bf(B). Below is a sample traffic
- dump of a browser trying to get a HTML page. The server replies
- that the page was not modified.
-
- verb(\
-C 0000 47 45 54 20 68 74 74 70 3a 2f 2f 77 77 77 2e 63 GET http://www.c
-C 0010 73 2e 68 65 6c 73 69 6e 6b 69 2e 66 69 2f 6c 69 s.helsinki.fi/li
-C 0020 6e 75 78 2f 6c 69 6e 75 78 2d 6b 65 72 6e 65 6c nux/linux-kernel
-C 0030 2f 32 30 30 31 2d 34 37 2f 30 34 31 37 2e 68 74 /2001-47/0417.ht
-C 0040 6d 6c 20 48 54 54 50 2f 31 2e 31 0d 0a 43 6f 6e ml HTTP/1.1..Con
-C 0050 6e 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a nection: close..
-.
-. etcetera
-.
-B 0000 48 54 54 50 2f 31 2e 30 20 33 30 34 20 4e 6f 74 HTTP/1.0 304 Not
-B 0010 20 4d 6f 64 69 66 69 65 64 0d 0a 44 61 74 65 3a Modified..Date:
-B 0020 20 54 75 65 2c 20 31 32 20 4a 75 6c 20 32 30 30 Tue, 12 Jul 200
-B 0030 35 20 30 39 3a 34 39 3a 34 37 20 47 4d 54 0d 0a 5 09:49:47 GMT..
-B 0040 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74 65 Content-Type: te
-B 0050 78 74 2f 68 74 6d 6c 3b 20 63 68 61 72 73 65 74 xt/html; charset
-.
-. etcetera
-.)
-
- Turning on traffic dumps will em(significantly) slow down
- crossroads.
-
- Besides tt(trafficlog), there is also a directive
- tt(throughputlog). This directive also takes one argument, a
- filename. The file is appended, and the following information is
- logged:
-
- itemization(
- it() The process ID of the crossroads image that serves the
- TCP connection;
- it() The time of the request, in seconds and microseconds
- since start of the run;
- it() A bf(C) when the request originated at the client, or
- bf(B) when the request originated at the back end;
- it() The first 100 bytes of the request.)
-
- As an example, consider the following (the lines are shortened for
- brevity and prefixed by line numbers for clarity):
-
- verb(
-1 0027566 0.000000 C 462 GET http://public.e-tunity.com/ ...
-2 0027566 0.052974 B 394 HTTP/1.1 200 OK..Via: 1.1 tinyp ...
-3 0027566 0.053413 B 1073 <html>.. <head>.. <titl ...
-4 0027566 0.053589 B 1448 1> </td>.. </tr>.. </table ...
-5 0027566 0.065679 B 725 for more. info.... <li> To ...)
-
- This tells us that:
-
- itemization(
- it() Line 1: PID 27566 served a request that originated at the
- client (C). The corresponding timing is 0 seconds, which means
- that this is the start of the run. The request was 462 bytes
- long and started with tt(GET http://public...)
-
- it() Line 2: 0.052974 seconds later, the backend (B) replied
- with tt(HTTP/1.1 200 OK).
-
- it() Lines 3, 4 and 5: The backend (B) proceeded by sending
- chunks.)
-
- The buffer sizes (462, 394 and so on) also tell us that the
- network sends relatively small chunks. In this case we might save
- some processing memory by setting the TCP buffer size to say 2K,
- instead of the default 5K. In this situation, most of the default
- 5K buffers will be unused. Setting the TCP buffer size to 2K can be done
- using the flag tt(-B 2048) or by using the statement
- tt(tcpbuffersize) tt(2048;) in an tt(options) block of the configuration.
-
- It is also worth while remembering that the start time of a bf(C)
- request is the time that crossroads sees the activity. Any latency
- between the true client and crossroads is obviously not
- included. This is illustrated by the below simple ASCII art:
-
- verb(
-client ---->---->---->--->*crossroads ====>====>====>
- \
- back end
- /
-client ----<----<----<---< crossroads ====<====<====<
-)
-
- This simple picture shows a typical request that originates
- at a client, travels to crossroads, and is relayed via the back
- end. The bf(C) entry in a throughput log is the time when
- crossroads sees the request, indicated by an asterisk. The bf(B)
- entries are the times that it takes the back end to answer,
- indicated by tt(===) style lines. Therefore, the true roundtrip
- time will be longer than the number of seconds that are logged in
- the throughput log: the latency between client and crossroads
- isn't included in that measurement.
-
- Summarizing, the throughput times and buffer sizes of a
- client-back end connection can be analyzed using the directive
- tt(throughputlog). In a real-world analysis, you'd probably want
- to write up a script to analyze the output and to compute round
- trip times. Such scripts are not (yet) included in Crossroads.
diff --git a/doc/main/tips/deeporshallow.yo b/doc/main/tips/deeporshallow.yo
@@ -1,103 +0,0 @@
-The service-level directive tt(headerinspection) defines which HTTP
-headers Crossroads will analyze. Often, several HTTP requests and
-responses will be served over one network
-link. Browsers and servers will try to keep a TCP link open so that it
-may be re-used; this is a measure to increase efficiency and to shorten load
-times of pages. E.g., a typical HTML page
-will require a style sheet and a few images - and these can be
-retrieved over the same link that originally served the HTML page.
-
-Re-using the TCP link occurs more often than not. It is the default in
-HTTP/1.1 (unless tt(Connection: close) is specified as one of the HTTP
-headers). The older HTTP protocol, HTTP/1.0, by default passes just
-one request and response over a TCP link, after which the link is
-closed (unless tt(Connection: keep-alive) is specified as one of the
-HTTP headers).
-
-If you define your service as tt(type http), then by default
-Crossroads will inspect all HTTP headers that it sees: not only the
-first browser request and server answer, but also subsequent requests
-and answers that travel over the same link. This is called 'deep
-inspection mode', in which Crossroads applies
-directives such as tt(addclientheader) to all header
-blocks. Inspecting the full TCP stream to catch header blocks can be
-resource consuming. You can optionally make Crossroads's resource
-consumption 'lighter' by instructing it to inspect only the first
-HTTP header block, and to simply pass-through over all subsequent information
-(which might well include next header blocks of a re-used TCP
-connection) This is done using the directive tt(headerinspection):
-
-verb(\
-service web {
- type http;
- headerinspection shallow;
- backend a { .... }
- backend b { .... }
-})
-
-The situations where tt(shallow) mode can be used, depends on what you
-need to do:
-
-itemization(
- it() tt(shallow) mode can be used when the inspection and
- modification of the first HTTP header block suffices. For example,
- HTTP session stickiness is a good example:
-
-verb(\
-service web {
- type http;
- headerinspection shallow;
- backend a {
- server 10.1.1.1:80;
- stickycookie "BalancerID=1";
- addclientheader "Set-Cookie: BalancerID=1";
- }
- .
- . other back ends are defined here
- .
-})
-
- In this case, Crossroads will inspect only the first header block that
- the client sends for the presence of a cookie tt(BalancerID). If the
- cookie has value 1, then the request will be routed to back end
- tt(a). Similarly, Crossroads will inspect only the first header block
- that the server sends, and will inject a tt(Set-Cookie)
- instruction.
-
- In this example, deep mode is not necessary because Crossroads
- will use the first header that the client sends to route the
- information to a given back end.
- If more than one HTTP transactions follow over
- the same TCP link, then by definition the link will go to the
- same back end - even without inspecting all HTTP headers that
- follow the first ones.
-
- it() tt(deep) mode is necessary in situations where all header
- blocks must be inspected and modified. E.g., if you want to hide your
- HTTP server identification, you might use:
-
-verb(\
-service web {
- type http;
- headerinspection deep;
- backend a {
- server 10.1.1.1:80;
- setclientheader "Server: MyWebServer";
- }
- .
- . other back ends are defined here
- .
-})
-
- Here, all HTTP header blocks that come from the server will be parsed,
- and tt(Server) headers will be overwritten.
- In a similar vein, if you want to pass the client's IP address, you
- will also need deep mode.
-
- In these examples, tt(shallow) mode is not usable, because the
- outbound header modifications should apply to all headers of a
- given series. Imagine that one would use tt(shallow) mode
- here: then, in a series of 5 HTTP transactions that pass over
- the same TCP link, only the first transaction would hide the
- HTTP server signature. All subsequent transactions would still
- show the HTTP server signature to the world.)
diff --git a/doc/main/tips/dnscaching.yo b/doc/main/tips/dnscaching.yo
@@ -1,21 +0,0 @@
-
-The option tt(-d) allows you to control Crossroads' built in DNS
-caching mechanism. Most often you will not need to use this:
-DNS lookups in Crossroads occur only to find back ends; and back ends
-are usually 'near' to the balancer.
-
-You might want or need to use DNS caching if:
-
-itemization(
- it() Back end servers are specified as hostnames, and not as
- IP addresses;
- it() DNS resolving of those host names is perceptibly slow.)
-
-You can test DNS resolving from the command line using e.g. the
-commands tt(nslookup) and tt(host).
-
-If DNS resolving is an issue, then you can specify the flag tt(-d)
-em(nsec) on the command line while invoking Crossroads. This instructs
-Crossroads to use its DNS cache to store results. Each result is
-stored for up to em(nsec) seconds - after that, a new request for the
-back end will lead to a new DNS lookup.
diff --git a/doc/main/tips/examples.yo b/doc/main/tips/examples.yo
@@ -1,236 +0,0 @@
-
-subsubsect(A load balancer for three webserver back ends)
-
-The following configuration example binds crossroads to port 80 of the
-current server, and distributes the load over three back ends. This
-configuration shows most of the possible settings.
-
-verb(\
-service www {
- /* We don't need session stickyness. */
- type any;
-
- /* Port on which we'll listen in this service: required. */
- port 8000;
-
- /* What IP address should this service listen? Default is 'any'.
- * Alternatively you can state an explicit IP address, such as
- * 127.0.0.1; that would bind the service only to 'localhost'. */
- bindto any;
-
- /* Verbose reporting or not. Default is off. */
- verbosity on;
-
- /* Dispatching mode, or: How to select a back end for an incoming
- * request. Possible values:
- * roundrobin: just the next back end in line
- * random: like roundrobin, but at random to make things more
- * confusing. Probably only good for testing.
- * bysize: The backend that transferred the least nr of bytes
- * is the next in line. As a modifier you can say e.g.
- * bysize over 10, meaning that the 10 last connections will
- * be used to compute the transfer size, instead of all
- * transfers.
- * byduration: The backend that was active for the shortest time
- * is the next in line. As a modifier you can say e.g.
- * byduration of 10 to compute over the last 10 connections.
- * byconnections: The back end with the least active connections
- * is the next ine line.
- * byorder: The first available back end is always taken.
- */
- dispatchmode byduration over 5;
-
- /* Interval at which we'll check whether a temporarily unavailable
- * backend has woken up.
- */
- revivinginterval 5;
-
- /* TCP backlog of connections. Default is 0 (no backlog, one
- * connection may be active).
- */
- backlog 5;
-
- /* For status reporting: a shared memory key. Default is the same
- * as the port number, OR-ed by a magic number.
- */
- shmkey 8000;
-
- /* This controls when crossroads should consider a connection as
- * finished even when the TCP sockets weren't closed. This is to
- * avoid hanging connections that don't do anything. NOTE THAT when
- * crossroads cuts off a connection due to timeout exceed, this is
- * not marked as a failure, but as a success. Default is 0: no timeout.
- */
- connectiontimeout 300;
-
- /* The max number of allowed client connections. When present, connections
- * won't be accepted if the max is about to be exceeded. When
- * absent, all connections will be accepted, which might be misused
- * for a DOS attack.
- */
- maxconnections 300;
-
- /* Now let's define a couple of back ends. Number 1: */
- backend www_backend_1 {
- /* The server and its port, the minimum configuration. */
- server httpserver1;
- port 9010;
- /* The 'decay' of usage data of this back end. Only relevant
- * when the whole service has 'dispatchmode bysize' or
- * 'byduration'. The number is a percentage by which the usage
- * parameter is decreased upon each connection of an other back
- * end.
- */
- decay 10;
-
- /* To see what's happening in /var/log/messages: */
- verbosity on;
- }
-
- /* The second one: */
- backend www_backend_2 {
- /* Server and port */
- server httpserver2;
- port 9011;
-
- /* Verbosity of reporting when this back end is active */
- verbosity on;
-
- /* Decay */
- decay 10;
-
- /* This back end is twice as weak as the first one */
- weight 2;
-
- /* Event triggers for system commands upon succesful activation
- * and upon failure.
- */
- onsuccess echo 'success on backend 2' | mail root;
- onfailure echo 'failure on backend 2' | mail root;
- }
-
- /* And yet another one.. this time we will dump the traffic
- * to a trace file. Furthermore we don't want more than 10 concurrent
- * connections here. Note that there's also a total maxconnections for the
- * whole service.
- */
- backend www_backend_3 {
- server httpserver3;
- verbosity on;
- port 9000;
- verbosity on;
- decay 10;
- trafficlog /tmp/backend.3.log;
- maxconnections 10;
- }
-})
-
-subsubsect(An HTTP forwarder when travelling)
-
-As another example, here's my configuration tt(crossroads.conf) that I
-use on my Unix laptop. The problem that I face is that I need many
-HTTP proxy configurations (at home, at customers' sites and so on) but
-I'm too lazy to reconfigure browsers all the time.
-
-Here's how it used to be before crossroads:
-
-itemization(
- it() At home, I would surf through a squid proxy on my local
- machine. The browser proxy setting is then
- tt(http://localhost:3128).
-
- it() Sometimes I start up an SSH tunnel to our offices. The
- tunnel has a local port 3129, and connects to a squid proxy on
- our e-tunity server. Hence, the browser proxy is then
- tt(http://localhost:3129).
-
- it() At a customer's location I need the proxy
- tt(http://10.120.34.113:8080), because they have configured it
- so.
-
- it() And in yet other instances, I use a HTTP diagnostic tool
- url(Charles)(http://www.xk72.com/charles)
- that sits between browser and website and shows me
- what's happening. I run charles on my own machine and it
- listens to port 8888, behaving like a proxy. The browser
- configuration for the proxy is then
- tt(http://localhost:8888).)
-
-Here's how it works with a crossroads configuration:
-
-itemization(
- it() I have configured my browsers to use
- tt(http://localhost:8080) as the proxy. For all situations.
-
- it() I use the following crossroads configuration, and let
- crossroads figure out which proxy backend works, and which
- doesn't. Note two particularities:
-
- itemization(
- it() The statement tt(dispatchmode byorder). This
- makes sure that once crossroads determines which
- backend works, it will stick to it. This usage of
- crossroads doesn't need to balance over more than one
- back end.
-
- it() The statement tt(bindto 127.0.0.1) makes sure
- that requests from other interfaces than loopback
- won't get serviced.)
-
-verb(\
-service HttpProxy {
- port 8080;
- bindto 127.0.0.1;
- verbosity on;
- dispatchmode byorder;
- revivinginterval 15;
-
- backend Charles {
- server localhost:8888;
- verbosity on;
- }
-
- backend CustomerProxy {
- server 10.120.34.113:8080;
- verbosity on;
- }
-
- backend SshTunnel {
- server localhost:3129;
- }
-
- backend LocalSquid {
- server localhost:3128;
- }
-}))
-
-As a final note, the commandline argument tt(tell) can be used to
-influence crossroad's own detection mechanism of back end availability
-detection. E.g., if in the above example the back ends tt(SshTunnel)
-and tt(LocalSquid) are both active, then tt(crossroads tell httpproxy
-sshtunnel down) will 'take down' the back end tt(SshTunnel) -- and
-will automatically cause crossroads to switch to tt(LocalSquid).
-
-
-subsubsect(SSH login with enforced idle logout)
-
-The following example shows how crossroads 'throttles' SSH
-logins. Connections are accepted on port
-22 (the normal SSH port) and forwarded to the actual SSH daemon
-which is running on port 2222.
-
-Note the usage of the
-tt(connectiontimeout) directive. This makes sure that users are logged
-out after 10 minutes of inactivity. Note also the tt(maxconnections)
-setting, this makes sure that no more than 10 concurrent logins occur.
-
-verb(\
-service Ssh {
- port 22;
- backlog 5;
- maxconnections 10;
- connectiontimeout 600;
- backend TrueSshDaemon {
- server localhost:2222;
- }
-})
diff --git a/doc/main/tips/externalhandler.yo b/doc/main/tips/externalhandler.yo
@@ -1,448 +0,0 @@
-As mentioned before, Crossroads supports several built-in dispatch
-modes. However, you are always free to hook-in your own dispatch mode
-that determines the next back end using your own specific
-algorithm. This section explains how to do it.
-
-subsubsect(Configuring the external handler)
-
-First, the tt(dispatchmode) statement needs to inform Crossroads that
-an external program will do the job. The syntax is: tt(dispatchmode
-externalhandler) em(program arguments). The em(program) must point to
-an executable program that will be started by Crossroads. The
-specifier em(arguments) can be anything you want; those will be the
-arguments to your dispatch helper. You use the following special
-format specifiers in the argument list:
-
-INCLUDEFILE(formattable)
-
-Note that the format specifiers such as tt(%b) don't make sense in the
-phase in which an external handler is called, since there is no
-current back end yet (the job of the handler is to supply one, so at
-the time of calling, tt(%b) is undefined).
-
-subsubsect(Writing the external handler)
-
-The external handler is activated using the arguments that are
-specified in the configuration file. The external handler can do
-whatever it wants, but ultimately, it must write a back end name on
-its em(stdout). Crossroads reads this, and if the back end is
-available, uses that back end for the connection.
-
-subsubsect(Examples of external handlers)
-
-This section shows some examples of Crossroads configurations
-vs. external handlers. The sample handlers that are shown here, are
-also included in the Crossroads distribution, under the directory
-tt(etc/). Also note that the examples shown here are just
-quick-and-dirty Perl scripts, meant to illustrate only. Your
-applications may need other external handlers, but you can use the
-shown scripts as a starting point.
-
-subsubsubsect(Round-robin dispatching)
-
-This example is trivial in the sense that round-robin dispatching is
-already built into Crossroads, so
-that using an external handler for this purpose only slows down
-Crossroads. However, it's a good starting example.
-
-The Crossroads configuration is shown below:
-
-verb(\
-service test {
- port 8001;
- verbosity on;
- revivinginterval 5;
-
- dispatchmode externalhandler
- /usr/local/src/crossroads/etc/dispatcher-roundrobin
- %1b %1a %2b %2a;
-
- backend testone {
- server localhost:3128;
- verbosity on;
- }
- backend testtwo {
- server locallhost:3128;
- verbosity on;
- }
-})
-
-The relevant tt(dispatchmode) statement invokes the external program
-tt(dispatcher-roundrobin) with four arguments: the name of the first
-back end (tt(testone)), its availability (0 or 1), the name of the
-second back end (tt(testtwo)) and its availability (0 or 1).
-
-The external handler, which is also included in the Crossroads
-distribution, is shown below. It is a Perl script.
-
-verb(\
-#!/usr/bin/perl
-
-use strict;
-
-# Example of a round-robin external dispatcher. This is totally
-# superfluous, Crossroads has this on-board; if you use the external
-# program for determining round-robin dispatching, then you'll only
-# slow things down. This script is just meant as an example.
-
-# Globals / configuration
-# -----------------------
-my $log = '/tmp/exthandler.log'; # Debug log, set to /dev/null to suppress
-my $statefile = '/tmp/rr.last'; # Where we keep the last used
-
-# Logging
-# -------
-sub msg {
- return if ($log eq '/dev/null' or $log eq '');
- open (my $of, ">>$log") or return;
- print $of (scalar(localtime()), ' ', @_);
-}
-
-# Read the last used back end
-# ---------------------------
-sub readlast() {
- my $ret;
-
- if (open (my $if, $statefile)) {
- $ret = <$if>;
- chomp ($ret);
- close ($if);
- msg ("Last used back end: $ret\n");
- return ($ret);
- }
- msg ("No last-used back end (yet)\n");
- return (undef);
-}
-
-# Write back the last used back end, reply to Crossroads and stop
-# ---------------------------------------------------------------
-sub reply ($) {
- my $last = shift;
-
- if (open (my $of, ">$statefile")) {
- print $of ("$last\n");
- }
- print ("$last\n");
- exit (0);
-}
-
-# Main starts here
-# ----------------
-
-# Collect the cmdline arguments. We expect pairs of backend-name /
-# backend-availablility, and we'll store only the available ones.
-msg ("Dispatch request received\n");
-my @backend;
-for (my $i = 0; $i <= $#ARGV; $i += 2) {
- push (@backend, $ARGV[$i]) if ($ARGV[$i + 1]);
-}
-msg ("Available back ends: @backend\n");
-
-# Let's see what the last one is. If none found, then we return the
-# first available back end. Otherwise we need to go thru the list of
-# back ends, and return the next one in line.
-my $last = readlast();
-if ($last eq '') {
- msg ("Returning first available back end $backend[0]\n");
- reply ($backend[0]);
-}
-
-# There **was** a last back end. Try to match it in the list,
-# then return the next-in-line.
-for (my $i = 0; $i < $#backend; $i++) {
- if ($last eq $backend[$i]) {
- msg ("Returning next back end ", $backend[$i + 1], "\n");
- reply ($backend[$i + 1]);
- }
-}
-
-# No luck.. run back to the first one.
-msg ("Returning first back end $backend[0]\n");
-reply ($backend[0]);)
-
-The working of the script is basically as follows:
-
-itemization(
- it() The argument list is scanned. Back ends that are
- available are collected in an array tt(@backend).
-
- it() The script queries a state file tt(/tmp/rr.last). If a
- back end name occurs there, then the next back end is looked
- up in tt(@backend) and returned to Crossroads. If no last back
- is unknown or can't be matched, then the first available back
- end (first element of tt(@backend)) is returned to Crossroads.
-
- it() Informing Crossroads is done via the subroutine
- tt(reply()). This code writes the selected back end to file
- tt(/tmp/rr.last) (for future usage) and prints the back end
- name to em(stdout).
-
- it() The script logs its actions to a file
- tt(/tmp/exthandler.log). This log file can be inspected for
- the script's actions.)
-
-
-subsubsubsect(Dispatching by the client IP address)
-
-The following example shows a useful real-life situation that
-illustrates how dispatching by client IP address works. bf(Note that)
-as of Crossroads 1.31, tt(dispatchmode byclientip) is implemented --
-so that the below description is somewhat superfluous. The code
-snippets however can help you in modelling your own specific dispatch
-modes, aided by external helpers. (Incidentally, the tt(dispatchmode)
-tt(byclientip) was modeled after the shown script. The functionality
-proved so useful that it was embedded into Crossroads.)
-
-Our hypothetical dispatching situation is as follows:
-
-itemization(
- it() Crossroads is used as a single-address point to forward
- Remote Desktop requests to a farm of Windows systems, where
- users can work via remote access;
-
- it() However, users may stop their session, and when they
- re-connect, they expect to be sent to the Windows system that
- they had worked on previously;
-
- it() Client PC's have their distinct IP addresses, which
- distinguish them.
-
- it() Of four windows systems, two are large servers, and two
- are small ones. We'll want to assign large servers to clients
- when we have a choice.)
-
-The requirements resemble session stickiness in HTTP, except that the remote
-desktop protocol doesn't support stickiness. This situation is a
-perfect example of how an external handler can help:
-the potential delay due to the calling of an external
-handler won't even be noticed. Remote Desktop is a network service where
-the connection time isn't critical; users won't notice a slightly
-larger connection time due to the fact that Crossroads invokes an
-external program. We expect only a few (albeit lengthy) TCP connections.
-
-The approach to the solution of this problem uses several external
-program hooks:
-
-itemization(
- it() An external dispatcher handler will be responsible for
- suggesting a back end, given a client IP and given the current
- timestamp. This handler will consult an internal
- administration to see whether the stated IP address should
- re-use a back end, or to determine which back end is free for usage.
- it() An external hook tt(onstart) will be responsible for
- updating the internal administration; i.e., to flag a back end
- as 'occupied'.
- it() The external hooks tt(onfailure) and tt(onend) will be
- responsible for flagging a back end as 'free' again; i.e., for
- erasing any previous information that states that the back end
- was occupied.)
-
-The Crossroads configuration is shown below. Only four Windows back
-ends are shown. Each back end is configured on a
-given IP address, port 3389, and is limited to one concurrent connection
-(otherwise a new user might 'steal' a running desktop session).
-
-verb(\
-service rdp {
- port 3389;
- revivinginterval 5;
-
- /* rdp-helper dispatch IP STAMP ... will suggest a back end to use,
- * arguments are for all back ends: name, availability, weight */
- dispatchmode externalhandler
- /usr/local/src/crossroads/etc/rdp-helper dispatch %r %e
- %1b %1a %1w
- %2b %2a %2w
- %3b %3a %3w
- %4b %4a %4w;
-
- backend win1 {
- server 10.1.1.1:3389;
- maxconnections 1;
- /* rdp-helper start IP STAMP BACKEND will log the actual start
- * of a connection;
- * rdp-helper end IP will log the ending of a connection */
- onstart /usr/local/src/crossroads/etc/rdp-helper start %r %e %b;
- onend /usr/local/src/crossroads/etc/rdp-helper end %r;
- onfail /usr/local/src/crossroads/etc/rdp-helper end %r;
- }
- backend win2 {
- server 10.1.1.2:3389;
- maxconnections 1;
- onstart /usr/local/src/crossroads/etc/rdp-helper start %r %e %b;
- onend /usr/local/src/crossroads/etc/rdp-helper end %r;
- onfail /usr/local/src/crossroads/etc/rdp-helper end %r;
- }
- backend win3 {
- server 10.1.1.3:3389;
- maxconnections 1;
- weight 2;
- onstart /usr/local/src/crossroads/etc/rdp-helper start %r %e %b;
- onend /usr/local/src/crossroads/etc/rdp-helper end %r;
- onfail /usr/local/src/crossroads/etc/rdp-helper end %r;
- }
- backend win4 {
- server 10.1.1.4:3389;
- maxconnections 1;
- weight 3;
- onstart /usr/local/src/crossroads/etc/rdp-helper start %r %e %b;
- onend /usr/local/src/crossroads/etc/rdp-helper end %r;
- onfail /usr/local/src/crossroads/etc/rdp-helper end %r;
- }
-})
-
-Depending on the dispatcher stage, the exernal handler tt(rdp-helper)
-is invoked in different ways:
-
-description(
- dit(During dispatching) the helper is called to suggest a back
- end. The arguments are an action indicator tt(dispatch), the
- client's IP address, the timestamp, and four triplets that
- represent back ends: per back end its name, its availability,
- and its weight. The purpose of the helper is to tell
- Crossroads which back end to use.
-
- dit(During connection start) the helper will be invoked to
- inform it of the start of a connection, given a client IP
- address.
-
- dit(When a connection terminates) the helper will be invoked
- to inform it that the connection has ended.)
-
-Here's the external handler as Perl script. It uses the module
-tt(GDBM_File) which most likely will not be part of standard Perl
-distributions, but can be added using CPAN. (Alternatively, any other
-database module can be used.)
-
-verb(\
-#!/usr/bin/perl
-
-use strict;
-use GDBM_File;
-
-# Global variables and configuration
-# ----------------------------------
-my $log = '/tmp/exthandler.log'; # Debug log, set to /dev/null to suppress
-my $cdb = '/tmp/client.db'; # GDBM database of clients
-my %db; # .. and memory representation of it
-my $timeout = 24*60*60; # Timeout of a connection in secs
-
-# Logging
-# -------
-sub msg {
- return if ($log eq '/dev/null' or $log eq '');
- open (my $of, ">>$log") or return;
- print $of (scalar(localtime()), ' ', @_);
- close ($of);
-}
-
-# Reply a back end to the caller and stop processing.
-# ---------------------------------------------------
-sub reply ($) {
- my $b = shift;
- msg ("Suggesting $b to Crossroads.\n");
- print ("$b\n");
- exit (0);
-}
-
-# Is a value in an array
-# ----------------------
-sub inarray {
- my $val = shift;
- for my $other (@_) {
- return (1) if ($other eq $val);
- }
- return (0);
-}
-
-# A connection is starting
-# ------------------------
-sub start {
- my ($ip, $stamp, $backend) = @_;
- msg ("Logging START of connection for IP $ip on stamp $stamp, ",
- "back end $backend\n");
- $db{$ip} = "$backend:$stamp";
-}
-
-# A connection has ended
-# ----------------------
-sub end {
- my $ip = shift;
- msg ("Logging END of connection for IP $ip\n");
- $db{$ip} = undef;
-}
-
-# Request to determine a back end
-# -------------------------------
-sub dispatch {
- my $ip = shift;
- my $stamp = shift;
-
- msg ("Request to dispatch IP $ip on stamp $stamp\n");
-
- # Read the next arguments. They are triplets of
- # backend-name / availability / weight. Store if the back end is
- # available.
- my (@backends, @weights);
- for (my $i = 0; $i < $#_; $i += 3) {
- if ($_[$i + 1] != 0) {
- push (@backends, $_[$i]);
- push (@weights, $_[$i + 2]);
- msg ("Candidate back end: $_[$i] with weight ", $_[$i + 2], "\n");
- }
- }
-
- # See if this is a reconnect by a previously seen client IP. We'll
- # treat this as a reconnect if the timeout wasn't yet exceeded.
- if ($db{$ip} ne '') {
- my ($last_backend, $last_stamp) = split (/:/, $db{$ip});
- msg ("IP $ip had last connected on $last_stamp to $last_backend\n");
- if ($stamp < $last_stamp + $timeout) {
- msg ("Timeout not yet exceeded, this may be a reconnect\n");
- # We'll allow a reconnect only if the stated last_backend is
- # free (sanity check).
- if (inarray ($last_backend, @backends)) {
- msg ("Last back end $last_backend is available, ",
- "letting through\n");
- reply ($last_backend);
- } else {
- msg ("Last used back end isn't free, suggesting a new one\n");
- }
- } else {
- msg ("Timeout exceeded, suggesting a new back end\n");
- }
- } else {
- msg ("Np preveious connection data, suggesting a new back end\n");
- }
-
- my $bestweight = -1;
- my $bestbackend;
- for (my $i = 0; $i <= $#weights; $i++) {
- if ($bestweight == -1 or $bestweight > $weights[$i]) {
- $bestweight = $weights[$i];
- $bestbackend = $backends[$i];
- }
- }
-
- msg ("Best back end: $bestbackend (given weight $bestweight)\n");
- reply ($bestbackend);
-}
-
-# Main starts here
-# ----------------
-msg ("Start of run, attaching GDBM database '$cdb'\n");
-tie (%db, 'GDBM_File', $cdb, &GDBM_WRCREAT, 0600);
-
-# The first argument must be an action 'dispatch', 'start' or 'end'.
-# Depending on the action, we do stuff.
-my $action = shift (@ARGV);
-if ($action eq 'dispatch') {
- dispatch (@ARGV);
-} elsif ($action eq 'start') {
- start (@ARGV);
-} elsif ($action eq 'end') {
- end (@ARGV);
-} else {
- print STDERR ("Usage: rdp-helper {dispatch|start|end} args\n");
- exit (1);
-})
diff --git a/doc/main/tips/howselected.yo b/doc/main/tips/howselected.yo
@@ -1,179 +0,0 @@
-In order to tune your load balancing, you'll need to understand how
-crossroads computes usage, how weighing works, and so on. In this
-section we'll focus on the dispatching modes tt(bysize), tt(byduration)
-and tt(byconnections) only. The other dispatching types are
-self-explanatory.
-
-
-subsubsect(Bysize, byduration or byconnections?)
-
-As stated before, crossroads doesn't know 'what a service does' and
-how to judge whether a given back end is very busy or not. You
-must therefore give the right hints:
-
-itemization(
- it() In general, a service which is CPU bound, will be more
- busy when it takes longer to process a request. The dispatch
- mode tt(byduration) is appropriate here.
-
- it() In contrast, a service which is filesystem bound, will be
- more busy when more data are transferred. The dispatch mode
- tt(bysize) is apppropriate.
-
- it() The dispatch mode tt(byduration) can also be used when
- network latency is an issue. E.g., if your balancer has back
- ends that are geograpically distributed, then tt(byduration)
- would be a good way to select best available back ends.
-
- it() Furthermore it is noteworthy that tt(dispatchmode
- byduration) is not usable for interactive processes such as
- SSH logins. Idle time of a
- login adds to the duration, while causing (almost) no
- load. Mode tt(byduration) should only be used for automated
- processes that don't wait for user interaction (e.g., SOAP
- calls and other HTTP requests).
-
- it() As a last remark, the dispatching mode tt(byconnections) can
- be used if you don't have other clues for load
- estimations.
-
- E.g., consider a database connection. What's
- heavier on the back end, time-consuming connections, or connections
- where loads of bytes are transferred? Well, that depends. A
- tough tt(select) query that joins multiple tables can be very
- heavy on the back end, though the response set can be quite
- small - and hence the number of
- transferred bytes. That would suggest
- dispatching by duration. However, tt(byduration)
- balancing doesn't respresent the true world, when interactive
- connections can occur where users have an idle TCP connection to
- the database:
- this consumes time, but no bytes (see the SSH login example
- above). In this case, the dispatch mode tt(byconnections) may be
- your best bet.
-
- )
-
-
-subsubsect(Averaging size and duration)
-
-The configuration statement tt(dispatchmode bysize) or tt(byduration)
-allows an optional modifier tt(over) em(number), where the stated
-number represents a connection count. When this modifier is present, then
-crossroads will use a moving average over the last em(n) connections to
-compute duration and size figures.
-
-In the real world you'll always want this modifier. E.g., consider two
-back ends that are running for years now, and one of them is suddenly
-overloaded and very busy (it experiences a 'spike' in activity).
-When the tt(over) modifier is absent, then
-the sudden load will hardly show up in the usage figures -- it will
-flatten out due to the large usage figures already stored in the years
-of service.
-
-In contrast, when e.g. tt(over 3) is in effect, then a sudden load
-does show up -- because it highly contributes to the average of three
-connections.
-
-
-subsubsect(Specifying decays)
-
-Decays are also only relevant when crossroads computes the 'next best
-back end' by size (bytes) or duration (seconds). E.g., imagine two
-back ends A and B, both averaged over say 3 connections.
-
-Now when back end A is suddenly hit by a spike,
-its average would go up accordingly. But the back end would never
-again be used, unless B also received a similar spike, because A's
-'usage data' over its last three connections would forever be larger than
-B's data.
-
-For that reason, you should in real situations probably always
-specify a decay, so that the backend selection algorithm recovers from
-spikes. Note that the usage data of the back end where a decay is
-specified, decay when bf(other) back ends are hit. The decay parameter
-is like specifying how fast your body regenerates when someone else
-does the work.
-
-The below configuration illustrates this:
-
-verb(\
-/* Definition of the service */
-service soap {
- /* Local TCP port */
- port 8080;
-
- /* We'll select back ends by the processing
- * duration
- */
- dispatchmode byduration over 3;
-
- /* First back end: */
- backend A {
- /* Back end IP address and port */
- server 10.1.1.1:8080;
-
- /* When this back end is NOT hit because
- * the other one was less busy, then the
- * usage parameters decay 10% per connection
- */
- decay 10;
- }
-
- /* Second back end: */
- backend B {
- server 10.1.1.2:8080;
- decay 10;
- }
-})
-
-subsubsect(Adjusting the weights)
-
-The back end modifier tt(weight) is useful in situations where your
-back ends differ in respect to performance. E.g,. your back ends may
-be geographically distributed, and you know that a given back end is
-difficult to reach and often experiences network lag.
-
-Or you may have
-one primary back end, a system with a fast CPU and enough memory, and a
-small fall-back back end, with a slow CPU and short on memory. In that
-case you know in advance that the second back end should be used only
-rarely. Most requests should go to the big server, up to a certain load.
-
-In such cases you will know in advance that the best performing back ends
-should be selected the most often. Here's where the tt(weight)
-statement comes in: you can simply increase the weight of the back
-ends with the least performance, so that they are selected less
-frequently.
-
-E.g., consider the following configuration:
-
-verb(\
-service soap {
- port 8080;
- dispatchmode byduration over 3;
- backend A {
- server 10.1.1.1:8080;
- decay 20;
- }
- backend B {
- server 10.1.1.2:8080;
- weight 2;
- decay 10;
- }
- backend C {
- server 10.1.1.3:8080;
- weight 4;
- decay 5;
- }
-})
-
-This will cause crossroads to select back ends by the processing time,
-averaging over the last three connections. However, backend B will kick
-in only when its usage is half of the usage of A (back end B is
-probably only half as fast as A). Backend C will kick in only when its
-usage is a quarter of the usage of A, which is half of the usage of B
-(back end C is probably very weak, and just a fall-back system incase
-both A and B crash). Note also that A's usage data decay much faster
-than B's and C's: we're assuming that this big server recovers quicker
-than its smaller siblings.
diff --git a/doc/main/tips/httpstickiness.yo b/doc/main/tips/httpstickiness.yo
@@ -1,118 +0,0 @@
-This section focuses on HTTP session stickiness. This term refers to
-the ability of a balancer to route a conversation between browser and
-a backend farm with webservers always to the same back end. In other
-words: once a back end is selected by the balancer, it will remain the
-back end of choice, even for subsequent connections.
-
-subsubsect(Don't use stickiness!)
-
-The rule of thumb as far as the balancer is concerned, is: bf(Do not
-use HTTP session stickiness unless you really have to.) Enabling
-session stickiness hampers failover, balancing and performance:
-
-itemization(
- it() Failover is hampered because during the session,
- the balancer has to assign new connections to the same back
- end that was selected at the start of a session. If the back
- end suddenly goes 'down', then the session will most likely
- crash. (Actually, when a back end becomes unreachable in the
- middle of a session, Crossroads will assign a new back end to
- that session. This will most likely result in a malfunction
- of the underlying application.)
- it() Balancing is hampered because at the start of the session,
- the balancer has selected the next-best back end. But during
- the session, that back end may well become overloaded. The
- balancer however must continue to send the requests there.
- it() Performance is hampered because crossroads needs to 'unpack'
- messages as they are passed to and fro. That's because
- crossroads needs to check the HTTP headers in the messages
- for persistence cookies.)
-
-There is a number of measures that you can take to avoid using session
-stickiness. E.g., session data can be 'shared' between web back
-ends. PHP offers functionality to store session data in a database, so
-that all PHP applications have access to these data. Application
-servers such as Websphere can be configured to replicate session data
-between nodes.
-
-subsubsect(But if you must..)
-
-If you really need stickiness, think first whether you might use TCP
-stickiness (using the client's IP address to dispatch). If you can,
-then this is the preferred method, since Crossroads won't have to
-unpack TCP streams. Below is a short configuration example:
-
-verb(\
-service www {
- port 80;
- type any;
- revivinginterval 15;
- dispatchmode byclientip;
-
- backend one {
- server 10.1.1.100:80;
- }
-
- backend two {
- server 10.1.1.101:80;
- }
-})
-
-
-However, if you bf(must) use HTTP-base session stickiness, then
-proceed as follows:
-
-itemization(
- it() At the level of a tt(service) description, set the type to
- tt(http).
- it() Furthermore, set the tt(headerinspection) to tt(shallow)
- (unless of course you also want to modify other HTTP headers,
- see section ref(tips/deeporshallow)).
- it() At the level of each back end description, configure the
- tt(stickycookie) and a tt(addclientheader) directives.)
-
-Once crossroads sees that, it will examine each HTTP message that it
-shuttles between client and back end:
-
-itemization(
- it() If there is no persistence cookie in the HTTP headers of a
- client's request, then the message must be the first one and
- a new session should be established.
- Crossroads selects an appropriate back
- end, sends the message to that back end, catches the reply,
- and inserts a tt(Set-Cookie) directive.
- it() If there is a persistence cookie in the HTTP headers of a
- client's request, then the request is part of an already
- established session. Crossroads analyzes the cookie and
- forwards the request to the appropriate back end.)
-
-Below is a short example of a configuration.
-
-verb(\
-service www {
- port 80;
- type http;
- headerinspection shallow;
- revivinginterval 15;
- dispatchmode byconnections;
-
- backend one {
- server 10.1.1.100:80;
- stickycookie XRID=100;
- addclientheader "Set-Cookie: XRID=100; Path=/";
- /* or: XRID=100; Path=/; Expires=%600g
- * This would make the session cookie expire in 600 sec (10 mins)
- */
- }
-
- backend two {
- server 10.1.1.101:80;
- stickycookie XRID=101;
- addclientheader "Set-Cookie: XRID=101; Path=/";
- }
-})
-
-Note how the cookie names and values in the directives
-tt(stickycookie) and tt(addclientheader) match. That is obviously a
-prerequisite for stickiness.
-
diff --git a/doc/main/tips/ipconntrackmax.yo b/doc/main/tips/ipconntrackmax.yo
@@ -1,34 +0,0 @@
-The kernel value of tt(ip_conntrack_max) is important for routers and
-balancers under Linux. Basically it's the maximum number of tracked
-connections. Felix A.W.O. describes the following situation:
-
-itemization(
- it() Crossroads seems to mark back ends as unavailable, while
- in fact nothing is afoot.
- it() This happens under heavy load.
- it() In tt(/var/log/messages) one may see the message:
- tt(kernel: ip_conntrack: table full, dropping packet).)
-
-The reason for Crossroad's behavior is that the kernel refuses to
-build up a requested network connection. For Crossroads, this looks
-just as a non-responding back end. Crossroads therefore marks the back
-end as unavailable.
-
-The solution is as follows:
-
-itemization(
- it() Try tt(cat /proc/sys/net/ipv4/ip_conntrack_max) to see
- the current value.
- it() Add something to the shown value (e.g., multiply by two),
- and inform
- the kernel of the new value, using tt(echo) em(new-value) tt(>
- /proc/sys/net/ipv4/ip_conntrack_max)
- it() Make sure that the same step occurs somewhere in your
- boot sequence as well, or that the new value is stated in a
- configuration file such as tt(/etc/sysctl.conf).)
-
-The value for em(new-value) is something that you'll have to figure
-out yourself. Note however that each count will cause the kernel to
-reserve 350 bytes. So if you set tt(ip_conntrack_max) to 100.000, then
-you're already taking 33.3Mb off the total available memory.
-
diff --git a/doc/main/tips/ipfiltering.yo b/doc/main/tips/ipfiltering.yo
@@ -1,122 +0,0 @@
-subsubsect(General Examples)
-
-The directives tt(allowfrom), tt(denyfrom), tt(allowfile) and
-tt(denyfile) can be used to instruct Crossroads to specifically allow
-access by using a "whitelist" of IP addresses, or to specifically deny
-access by using a "blacklist". E.g., the following configuration
-allows access to service tt(webproxy) only to em(localhost):
-
-verb(\
-service webproxy {
- port 8000;
- allowfrom 127.0.0.1;
- backend one {
- .
- . Back end definitions occur here
- .
- }
- .
- . Other back ends or other service directives
- . may occur here
- .
-})
-
-In this example there is a "whitelist" having only one entry: IP
-address 127.0.0.1, or em(localhost). (Incidentally, the same behaviour
-could be accomplished by stating em(bindto 127.0.0.1), in which case
-Crossroads would only listen to the local network device.)
-
-In the same vein, the directive tt(allowfrom 127.0.0.1 192.168.1/24)
-would allow access to em(localhost) and to all IP addresses that start
-with 192.168.1. The specifier tt(192.168.1/24) states that there are
-three network bytes (192, 168 and 1), and 24 bits (or 3 bytes) are
-relevant; so that the fourth network byte doesn't matter.
-
-subsubsect(Using External Files)
-
-The directives tt(allowfile) and tt(denyfile) allow you to specify IP
-addresses in external files. The Crossroads configuration states
-e.g. tt(allowfile /tmp/allow.txt), and the IP addresses are then in
-tt(/tmp/allow.txt). The format of tt(/tmp/allow.txt) is as follows:
-
-itemization(
- it() The specifications follow again em(p.q.r.s/mask), where
- p, q, r and s are network bytes which can be left out on the
- right hand side when the mask allows it;
-
- it() The specifications must be separated by white space
- (spaces, tabs or newlines).)
-
-E.g., the following is a valid example of an external specification
-file:
-
-verb(\
-127.0.0.1
-192.168.1/24
-10/8)
-
-When external files are in effect, then the signal tt(SIGHUP) (1)
-causes Crossroads to reload the external file. E.g., while Crossroads
-is running, you may edit tt(/tmp/allow.txt), and then issue tt(killall
--1 crossroads). The new contents of tt(/tmp/allow.txt) will be
-reloaded.
-
-subsubsect(Mixing Directives)
-
-Crossroads allows to mix all directives in one service
-description. However, some mixes are less meaningful than others. It's
-up to you to take this into account.
-
-The following rules apply:
-
-itemization(
- it() Blacklisting and whitelisting can be used together. When
- combined, the blacklist will always be interpreted
- first. E.g., consider the following directives:
-
- verb(\
-allowfrom 192.168.1/24
-denyfrom 192.168.1.100)
-
- Given the fact that the deny list is checked first, client
- 192.168.1.100 won't be able to access Crossroads. Then the
- allow list will be checked, stating that all clients whose IP
- address starts with 192.168.1 may connect. The effect will be
- that e.g., client 192.168.1.1 may connect, 192.168.1.2 may
- connect too, 192.168.1.100 will be blocked, and 10.1.1.1 will
- be blocked as well.
-
- Now consider the following directives:
-
- verb(\
-allowfrom 192.168.1.100 127.0.0.1
-denyfrom 192.168.1/24)
-
- This will first of all deny access to all IP addresses that
- start with 192.168.1. So the rule that allows 192.168.1.100
- won't ever be effective. The net result will be that access
- will be granted to 127.0.0.1.
-
- it() Blacklisting or whitelisting can be left out. A list is
- considered empty when no appropriate directives occur in the
- configuration file tt(crossroads.conf), or when the directive
- points to an empty or non-existent external file.
-
- it() Using tt(*from) and tt(*file) statements is allowed, but
- doesn't make sense. E.g., the following configuration sample
- is such a case:
-
- verb(\
-allowfrom 127.0.0.1 192.168.1/24
-allowfile /tmp/allow.txt)
-
- There is a technical reason for this. Once Crossroads
- processes the tt(allowfile) directive, then the whole
- whitelist is cleared (thereby removing the entries 127.0.0.1
- and 192.168.1/24), and new entries are reloaded from the
- file. The net result is that the tt(allowfrom) specification
- is overruled.)
-
-Crossroads only performs syntactic checking of the configuration. Some
-of the above samples are syntactically correct, but make no semantic
-sense: Crossroads doesn't warn for such situations.
diff --git a/doc/main/tips/periodic.yo b/doc/main/tips/periodic.yo
@@ -1,89 +0,0 @@
-Crossroads has two methods of periodic back end verifications:
-
-itemization(
-
- it() The first method only checks unavailable back ends. It is
- configured using the directive tt(revivinginterval).
- The way tt(revivinginterval) works is as follows:
-
- enumeration(
- eit() Crossroads determines that a back end is
- unavailable. This happens when a new network connection to
- the back end fails, or when an existing connection
- suddenly dies.
-
- eit() The back end is the periodically checked to see
- if it has woken up yet.)
-
- it() The second method periodically checks all back ends,
- available ones and unavailable ones. This is configured using
- tt(checkinterval). During each check, back ends can be marked
- as available or as unavailable.)
-
-
-subsubsect(Syntax)
-
-The syntax of both verifications is:
-
-center(em(method)tt(interval) em(seconds) tt([) tt(externalhandler)
-em(program) em(arguments) tt(]))
-
-In this syntax, the method is tt(reviving) or tt(check). The seconds
-specifier defines the delay between consecutive checks.
-
-When no specification tt(externalhandler) em(program) em(arguments) is
-given, then Crossroads runs the verification by trying to connect to
-the back end. A simple successful connection suffices to cause
-Crossroads to consider the back end available. However, when the
-tt(externalhandler) specifier is given, then Crossroads runs the
-specified external program. This program must exit with status 0 to
-inform Crossroads that the back end is available. All other exit
-statuses will mark the back end as unavailable.
-
-The em(arguments) are expanded according to the following table:
-
-INCLUDEFILE(formattable)
-
-
-subsubsect(Security Considerations)
-
-When tt(externalhandler) is in effect, Crossroads spawns an external
-process. For security reasons, you may want to run this process under
-a restricted user account.
-
-The directive tt(useraccount) can be used to accomplish this.
-
-
-subsubsect(An example)
-
-The following configuration balances SMTP requests to two back
-ends. The connectivity is checked by retrieving output from each back
-end. The back end is available when the standard greeting of a mail
-server is seen; this greeting must contain the word SMTP. During each
-check the probe is terminated by sending tt(quit).
-
-verb(\
-/* Use either DEBUG on or off */
-#define DEBUG off
-
-/* SMTP balancer */
-service smtp {
- /* Standard stuff */
- port 25;
- verbosity DEBUG;
- /* Check back ends every 30 seconds. User 'nobody'
- * will run the external handler. */
- useraccount nobody;
- checkinterval 30
- externalhandler "echo quit | netcat -w1 %h %p | grep SMTP";
-
- /* Two back ends to handle mail traffic. */
- backend mailone {
- server smtp1.local.network:25;
- verbosity DEBUG;
- }
- backend second {
- server smtp2.local.network:25;
- verbosity DEBUG;
- }
-})
diff --git a/doc/main/tips/rendering.yo b/doc/main/tips/rendering.yo
@@ -1,66 +0,0 @@
-The Crossroads flag tt(-x) causes the status output to be generated as
-an XML document. This format can be nicely used to render the output
-as an HTML page.
-
-E.g., the following sample shows how Crossroads reports its status in
-XML format (the actual XML structure that Crossroads outputs may be
-different from this example, depending on the version):
-
-verb(\
-<?xml version="1.0" encoding="UTF-8"?>
-<status>
- <service id="1" name="smtp">
- <connections>1</connections>
- <lastbackend>0</lastbackend>
- <backend id="0" name="first">
- <availability id="0">available</availability>
- <clients>0</clients>
- <failures>0</failures>
- <connections>2</connections>
- <duration sec="0.559882">0.56s</duration>
- <throughput bytes="3564">3.48Kb</throughput>
- </backend>
- <backend id="1" name="second">
- <availability id="0">available</availability>
- <clients>0</clients>
- <failures>0</failures>
- <connections>2</connections>
- <duration sec="23.7636">23.76s</duration>
- <throughput bytes="9055">8.84Kb</throughput>
- </backend>
- </service>
-</status>)
-
-A custom-made XSLT transformation stylesheet can be used to convert
-this to any output format - and also to HTML. Such a style sheet is
-included in the Crossroads distribution as
-tt(etc/xml-status-to-html.xslt). The sheet is lengthy, and is
-therefore not included in this document. (You're welcome to modify it
-to suit your specific needs. If you have cool tips, send them along to
-me and I'll include them in the next distribution!)
-
-If you want to show this output in a webpage which is generated on
-demand by a webserver, then you might run into the following
-problem. The status reporter (tt(crossroads -x status))
- must be able to access the shared memory segment of the running
-Crossroads instance. By default, the shared memory is protected for
-the user that started Crossroads, which will often not be the user who
-runs the webserver. Under the auspices of the webserver user,
-tt(crossroads status) might abort with a message: "ERROR: Cannot get
-shared memory for service em(name), key em(number): Permission denied."
-
-The solution for this problem is to make the shared memory access
-somewhat more liberal. There are basically two options:
-
-itemization(
- it() Start Crossroads with the flag tt(-m 0666), which makes
- the shared memory segment available to all. The octal number
- 0666 works just like a file permission setting under
- Unix. Now, any user can run tt(crossroads status).
-
- it() If you want to make the access to Crossroads' shared
- memory somewhat stricter, then make the user who starts
- Crossroads and the user who runs the webserver member of a new
- Unix group. Start Crossroads with the flag tt(-m 0664). Now,
- users belonging to the same group as the Crossroads starter
- can run tt(crossroads status).)
diff --git a/doc/main/tips/retries.yo b/doc/main/tips/retries.yo
@@ -1,41 +0,0 @@
-Crossroads allows you to specify on a per-back end basis how many
-retries are needed before a back end is considered unavailable. The
-default is just one, meaning that after one failed connection,
-Crossroads will mark a back end as unavailable (the back end may be
-'revived', if you use tt(revivinginterval) or tt(checkinterval)).
-
-Increasing the number is specified using the keyword tt(retries). The
-following configuration defines two back ends; the one on the IP
-address 5.6.7.8 is somehow 'flaky', and Crossroads should try
-connecting 3 times before crossing it off:
-
-verb(\
-service www {
- port 80;
- backend plugh {
- server 1.2.3.4:80;
- }
- backend xyzzy {
- server 5.6.7.8:80;
- retries 3;
- }
-})
-
-There may be several reasons for increasing the retries number:
-
-itemization(
- it() The network connections to the server may spuriously
- hamper, but such rare errors don't mean that the back end server is
- down.
-
- it() The back end server is a 'slow starter' and can't handle spikes
- very well. E.g., it may be a webserver which starts with only
- one daemon; extra capacity is added as network connections
- arrive, but adding capacity take a little time.)
-
-Whatever the reason, the keyword tt(retries) might be of help
-here. This keyword should however be used carefully: Crossroads will
-retry connecting with a small one-second delay in between. A high
-tt(retries) number means also lots of one-second delays, in which time
-a client is kept waiting.
-
diff --git a/doc/main/tips/tcpstickiness.yo b/doc/main/tips/tcpstickiness.yo
@@ -1,22 +0,0 @@
-If you need to make sure that a client that once gets dispatched to a
-given back end keeps re-visiting the back end, then Crossroads offers
-the dispatch mode tt(byclientip). This mode will only work when each
-client is seen by Crossroads with its own specific IP address; ie.,
-this method won't work when clients reach Crossroads through a
-masquerading firewall (in which case all clients would be seen as
-having the firewall's IP address).
-
-The tt(dispatchmode byclientip) works as follows:
-
-itemization(
- it() The client's IP address is taken in its string
- representation and 'hashed' into a number.
-
- it() The number is brought back to the number of available
- back ends (using a modulo-operation).
-
- it() The result defines the back end of choice.)
-
-If the preferred back end is unavailable, then the action that
-Crossroads takes is to dispatch as if tt(byconnections): of the
-available back ends, the one with the least connections is taken.
diff --git a/doc/main/tips/throttling.yo b/doc/main/tips/throttling.yo
@@ -1,27 +0,0 @@
-If you suspect that your service may occasionally receive 'spikes' of
-activity+footnote(which you should always assume), then it might be a
-good idea to protect your service by specifying a maximum number of
-concurrent connections. This protection can be specified on two levels:
-
-description(
- dit(On the service level) a statement like tt(maxconnections
- 100;) states that the service as a whole will never
- service more than 100 concurrent connections. This means that
- all your back ends and the crossroads balancer itself
- will be protected from being overloaded.
- dit(On the back end level) a statement like tt(maxconnections 10;)
- states that this particular back end will never have more
- than 10 concurrent connections; regardless of the overall
- setting on the service level. This means that this
- particular back end will be protected from being
- overloaded (regardless of what other back ends may
- experience).)
-
-The tt(maxconnections) statement, combined with a back end selection
-algorithm, allows very fine granularity. The tt(maxconnections) statement
-on the back end level is like a hand brake: even when you specify a
-back end algorithm that would protect a given back end from being used
-too much, a situation may occur where that back end is about to be
-hit. A tt(maxconnections) statement on the level of that back may then
-protect it.
-
diff --git a/doc/main/tips/virtual.yo b/doc/main/tips/virtual.yo
@@ -1,77 +0,0 @@
-Crossroads can be used as a central dispatcher for computing on
-demand. E.g., imagine a situation where a web service exists on one or
-two servers, with the option of adding new servers in case of a high
-load. The "other" servers, besides the first two ones, are a virtual
-pool - the pool size and the IP addresses may not be known in advance.
-
-The following Crossroads' features are used in this example:
-
-itemization(
-
- it() The back ends of Crossroads can have an initial state. For
- the two real servers which are already present this would be
- tt(up) (the default). For the non-present ones this would be
- tt(down): Crossroads excludes back ends that are down from the set
- of candidate workers, and does not check their presence using
- tt(revivalinterval) or tt(checkinterval).
-
- it() The back ends must be configured to have a server address and
- port, but this can be later reconfigured runtime. E.g., the
- virtual pool servers would be initially configured on
- tt(localhost:80), and later the addresses would be filled in.)
-
-A sample Crossroads configuration is shown below. It defines 20 back
-ends: two are always present, and 18 are in the virtual pool.
-
-verb(\
-service vpool {
- port 80;
- revivinginterval 3;
- dispatchmode byconnections;
-
- /* The two back ends that are always present: */
- backend real_01 { server 10.1.1.1:80; }
- backend real_02 { server 10.1.1.2:80; }
-
- /* The virtual pool: */
- backend virt_01 { server localhost:80; state down; }
- backend virt_02 { server localhost:80; state down; }
- backend virt_03 { server localhost:80; state down; }
- backend virt_04 { server localhost:80; state down; }
- backend virt_05 { server localhost:80; state down; }
- backend virt_06 { server localhost:80; state down; }
- backend virt_07 { server localhost:80; state down; }
- backend virt_08 { server localhost:80; state down; }
- backend virt_09 { server localhost:80; state down; }
- backend virt_10 { server localhost:80; state down; }
- backend virt_11 { server localhost:80; state down; }
- backend virt_12 { server localhost:80; state down; }
- backend virt_13 { server localhost:80; state down; }
- backend virt_14 { server localhost:80; state down; }
- backend virt_15 { server localhost:80; state down; }
- backend virt_16 { server localhost:80; state down; }
- backend virt_17 { server localhost:80; state down; }
- backend virt_18 { server localhost:80; state down; }
-
-})
-
-New back ends can be enabled using tt(crossroads tell). E.g., to
-enable back end tt(virt_01) on IP address 10.100.1.1:80, the commands
-are:
-
-verb(\
- crossroads tell vpool virt_01 server 10.100.1.1:80
- crossroads tell vpool virt_01 up)
-
-To disable a back end, its state is reset to tt(down). The IP address
-doesn't even have to be erased:
-
-verb(\
- crossroads tell vpool virt_01 down)
-
-A script to monitor the total number of connections, and to add a back
-end or to remove one, is left to the reader. The output of
-tt(crossroads -x status) can be very helpful here: it reports on the
-states of all back ends, their connections, the total number of
-available or down back ends, etc..
-
diff --git a/doc/main/tips/webinterface.yo b/doc/main/tips/webinterface.yo
@@ -1,118 +0,0 @@
-The mini-webserver tt(crossroads-mgr) provides an intuitive web
-interface to the state of Crossroads. Once started, an administrator
-may view the state of the balancer, and may influence the state of all
-back ends.
-
-As an example, a procedure is described here where a given back end is
-gracefully taken out of service. Below is a sample Crossroads
-configuration, which distributes requests over three back ends:
-
-verb(\
-service www {
- port 80;
- type http;
- backend one {
- server 10.1.1.1:80;
- stickycookie "BalancerID=one";
- addclientheader "Set-Cookie: BalancerID=one";
- }
- backend two {
- server 10.1.1.1:80;
- stickycookie "BalancerID=two";
- addclientheader "Set-Cookie: BalancerID=two";
- }
- backend three {
- server 10.1.1.1:80;
- stickycookie "BalancerID=three";
- addclientheader "Set-Cookie: BalancerID=three";
- }
-})
-
-In order to take a given back end gracefully offline (say back end
-tt(two)), either of the following procedures can be followed:
-
-enumeration(
- eit() Back end tt(two) is taken down via the commandline, using
- tt(crossroads tell www two down). Next we wait for say one hour to
- let existing sessions die out. After that, the back end can be turned
- off.
-
- eit() Back end tt(two) is taken down via the web interface, by
- switching the status from tt(available) to tt(down). Next we wait
- for say one our, and turn off the back end.)
-
-The web interface doesn't offer extra functionality over the command
-line tools; but all information is available at one glance, and
-accessible without a shell access to the balancer.
-
-
-subsubsect(Starting crossroads-mgr)
-
-The basic command to start tt(crossroads-mgr) is
-
-center(tt(crossroads-mgr start) em(portnumber))
-
-where the port number specifies to which TCP port the manager will
-listen. There is however one important security aspect that needs
-attention. Unless specified otherwise, anyone who points their browser
-to the balancer and the given port, can view back end states and even
-change them. This may be a too lax policy.
-
-The web interface daemon has two methods to limit access: a listening
-address can be specified via the command line, and basic
-authentication (username / password protection) can be turned on.
-
-Specifying a listening address is done using the flag tt(-a). E.g.,
-after
-
-center(tt(crossroads-mgr -a 127.0.0.1 start 10000))
-
-the manager is started to listen to port 10000, but only on the
-address 127.0.0.1 which is localhost. Requests from other addresses
-will not be served.
-
-Enforcing basic authentication is turned on using two command line
-flags:
-
-itemization(
- it() Flag tt(-b) turns on basic authentication to view the status.
- it() Flag tt(-B) turns on basic authentication to change back end
- states.)
-
-Both flags must be followed by the required credentials. The most
-simple way to state the credentials, is to postfix the flag with the
-required user name, a colon, and the required password. E.g.,
-tt(-Buser:secret) says that anyone who tries to change back end
-states, must supply the user name tt(user) and the password
-tt(secret).
-
-In this example the full invocation would be e.g.:
-
-center(tt(crossroads-mgr -Buser:secret start 1000))
-
-The disadvantage is here that the credentials are visible for anyone
-who has shell access to the balancer. A process overview, generated
-with say tt(ps ax | grep crossroads-mgr), would show the required
-username and password. In order to avoid such a leak,
-tt(crossroads-mgr) can be started as follows:
-
-center(tt(crossroads-mgr -BPROMPT start 1000))
-
-The 'magic' word tt(PROMPT) instructs tt(crossroads-mgr) to read the
-username and password from em(stdin). The invocation can be further
-scripted, using something like:
-
-center(tt(echo user:secret | crossroads-mgr -BPROMPT start 1000))
-
-The same trick can be used with the flag tt(-b). When both flags are
-present, and both 'magic' words tt(PROMPT) occur, then
-tt(crossroads-mgr) will first ask for the credentials of the 'viewer',
-and next for the credentials of the 'modifier' (even when flag tt(-B)
-is stated first). So the following example starts tt(crossroads-mgr)
-and requires the user name tt(viewer), with password tt(showme) to view the
-status, and it requires the user name tt(modifier), with password
-tt(changeit) to change states:
-
-verb(\
-echo -e 'viewer:showme\nmodifier:changeit' |
- crossroads-mgr -bPROMPT -BPROMPT start 1000)
diff --git a/doc/main/using.yo b/doc/main/using.yo
@@ -1,161 +0,0 @@
-subsect(The Balancer: crossroads)
-
-The Crossroads balancer is started from the commandline, and highly
-depends on the configuration file tt(crossroads.conf) (the default
-configuration file). It supports a number of flags (e.g., to overrule
-the location of the configuration file). The actual usage information
-is always obtained by typing tt(crossroads) without any arguments.
-Crossroads then displays the allowed arguments.
-
-The installation (see section ref(installation)) installs also a
-second program called tt(crossroads-daemon). This program is not meant
-to be started from the command line; it is administered through the
-front end tt(crossroads).
-
-subsubsect(General Commandline Syntax)
-
-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. The reason is that in
- the split second where the listener is stopped and a new one
- is not yet started, a new network connection won't be
- accepted. Running connections are however not hindered by a
- restart.
- 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) tt(state)
- em(newstate) 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 tel) em(service backend) tt(server)
- em(hostname:port) redefines the back end address of a
- running back end.
- 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.
-)
-
-subsubsect(Status Reporting from the Command Line)
-
-The command tt(crossroads status) shows a verbose human-readable
-report of how Crossroads is doing. When many services are configured,
-this can be a somewhat lengthy output. If you're interested in the
-overview of only one service, you can use tt(crossroads status)
-em(servicename), in which case the report will only be shown for the
-stated service.
-
-Similarly, if you're interested only in the status of a given back end
-of a given service, use tt(crossroads service) em(servicename)
-em(backendname).
-
-The flag tt(-t) causes the status overview to be abbreviated and
-displayed in a parseable format. This flag can be used in automated
-scripts that check how Crossroads is doing; e.g., in health checking
-scripts. When tt(-t) is used, the format of the status reporter is as
-follows:
-
-itemization(
- it() Service health is reported on one line per service.
- it() The first string on the line is the service name.
- it() After this, a series follows of em(backendname=state),
- where the back end name is the configured name of the back
- end, and where state is e.g. tt(available), tt(down),
- tt(unavailable), tt(waking). The statuses may occur in caps.
- The series is repeated for all back ends of the given service.)
-
-The flag tt(-x) causes the overview to be presented as an XML
-document. This can be handy if you want to further automate the
-control over Crossroads, or if you want to show the status via the
-web. (See section ref(xmlstatus) for more information.)
-
-The status reporter shows the number of running connections per back
-end, and the total of connections of the entire service. Due to
-technical reasons the total count can be one off. (There is a
-technical reason for this: the total counter gets updated at a
-different rate than separate back end counts. This may be fixed in a
-future release.)
-
-
-subsubsect(Logging-related options)
-
-Two 'flags' of Crossroads are specifically logging-related. This
-section elaborates on these flags.
-
-First, there's flag tt(-a). When present, the start and end of
-activity is logged using statements like
-
-center(em(YYYY-MM-DD HH/MM/SS starting http from 61.45.32.189 to 10.1.1.1))
-
-Similarly, there are 'ending' statements. Using this flag and
-scanning your logs for these statements may be helpful in quickly
-determining your system load.
-
-Second, there's flag tt(-l). This flag selects the 'facility' of
-logging and defaults to tt(LOG_DAEMON). You can supply a number
-between 0 and 7 to flag tt(-l) to select tt(LOG_LOCAL0) to
-tt(LOG_LOCAL7). This would separate the Crossroads-related logging
-from other streams. Here's a very short guide; please read your Unix
-manpages of tt(syslogd) for more information.
-
-itemization(
- it() First edit tt(/etc/syslog.conf) and add a line:
-
- verb(local7.* /var/log/crossroads.log)
-
- That instructs tt(syslogd) to send tt(LOG_LOCAL7) requests to the
- logfile tt(/var/log/crossroads.log).
-
- it() Next, restart tt(syslogd). On most Unices that's done by
- issuing tt(killall -1 syslogd). (As a side-note, I tried this once
- on an Bull/AIX system, and the box just shut down. The tt(killall)
- command killed every process...)
-
- it() Now start tt(crossroads) with the flag tt(-l7).
-
- it() Finally, monitor tt(/var/log/crossroads.log) for Crossroads'
- messages.)
-
-
-subsubsect(Reloading Configurations)
-
-Crossroads doesn't support the reloading of a configuration while
-running (such as other programs, e.g. Apache do). There are various
-technical reasons for this.
-
-However, external lists of allowed or denied IP addresses can be
-reloaded by sending a signal -1 (tt(SIGHUP)) to Crossroads. See
-section ref(servicedef) for the details.
-
-
-subsect(The Web Frontend: crossroads-mgr)
-
-A web front end for Crossroads is tt(crossroads-mgr). Type
-tt(crossroads-mgr) without arguments to see the usage.
-
-Normally the web interface is started like:
-
-center(tt(crossroads-mgr start 1000))
-
-where 1000 is a free TCP port. Note that tt(crossroads-mgr) must be
-started on the system where the balancer tt(crossroads) itself is
-running.
-
-There are lots of other options that can be used with
-tt(crossroads-mgr), see section ref(tips/webinterface).
-
diff --git a/doc/man/crossroads-mgr.yo b/doc/man/crossroads-mgr.yo
@@ -1,106 +0,0 @@
-includefile(../crossroads-defs)
-manpage(crossroads-mgr)(1)(YEARS())(crossroads)()
-manpagename(crossroads-mgr)(Web interface for Crossroads)
-
-manpagesynopsis()
- itemization(
- it() bf(crossroads-mgr) em([flags]) bf(start) em(port): starts
- the web interface server
- it() bf(crossroads-mgr) bf(stop): stops the server
- it() bf(crossroads-mgr) bf(status): shows whether the server
- is running)
-
-manpagedescription()
-
- bf(crossroads-mgr) is a self-contained web server, written in
- Perl, providing a web interface to control Crossroads. The web
- interface allows one to:
-
- itemization(
- it() View the states of back ends, and their usage;
- it() Set the states of back ends (e.g., to take a back end out
- of service).)
-
- The web interface cannot be used to fully configure Crossroads (e.g., to
- add new back ends). This must be done via the configuration file
- bf(crossroads.conf). Note furthermore that bf(crossroads status) and
- bf(crossroads tell) are commandline tools that achieve the same
- functionality as bf(crossroads-mgr).
-
-manpageoptions()
-
- bf(crossroads-mgr) recognizes the following flags:
-
- itemization(
-
- it() bf(-a ADDRESS): Specifies the address to which the
- manager binds. E.g., one may specify bf(-a 127.0.0.1), after
- which only requests originating from localhost will be served.
-
- it() bf(-b UN:PW): Viewing the status is protected using
- simple basic authentication, requiring username bf(UN) and
- password bf(PW).
-
- For example one may specify: bf(-b user:secret), after which
- visitors to the web interface are prompted for a username and
- password.
-
- Instead of the username, a colon, and a password, the special
- word bf(PROMPT) may be used (in caps). In this case,
- bf(crossroads-mgr) prompts for the entry of a username and a
- password. Using bf(PROMPT) will have the effect that the
- username and password are not shown in a process listing.
-
- it() bf(-B UN:PW): Setting the status of a back end is
- protected using simple basic authentication, with username
- bf(UN) and password bf(PW). The special word bf(PROMPT) may be
- used.
-
- it() bf(-f): bf(crossroads-mgr) stays in the foreground
- instead of daemonizing. Useful for debugging.
-
- it() bf(-l FILE): Verbose activity (when bf(-v) is given) is
- written to the stated file. Useful for debugging. Also, error
- messages are written to the file. The default is
- bf(/tmp/crossroads-mgr.log). Note that file logging is not
- used in 'foreground' mode (flag bf(-f); in that case all
- logging goes to terminal).
-
- it() bf(-v): Verbosity is increased.
-
- it() bf(-x CMD): This specifies how bf(crossroads-mgr) should
- invoke bf(crossroads). The default is just bf(crossroads). An
- example is: bf(/usr/local/bin/crossroads -c
- /alternative/configuration) which overrules the default
- configuration file name. Note that once bf(-x) is given,
- bf(crossroads-mgr) will no longer search along the PATH. When
- using bf(-x), the full access path to bf(crossroads) must be
- specified.
-
- it() bf(-X XSLT): Causes bf(crossroads-mgr) to send the
- specified XSLT file, instead of the built-in. Useful for
- debugging.)
-
-
-manpagebugs()
-
- itemization(
-
- it() Basic authentication headers are logged when bf(-v)
- is active. Make sure that the log file is not in a
- world-readable place, or turn off bf(-v).
-
- it() When using basic authentication in the form bf(-b
- UN:PW) and bf(-B UN:PW), the required credentials are
- visible in the process overview list. Use bf(PROMPT) to
- hide these.
-
- it() bf(crossroads-mgr stop) and bf(crossroads-mgr status)
- use the process list to see which daemons are active. If
- you start more than one daemon, then bf(crossroads-mgr
- stop) will stop all of them.)
-
-manpageauthor()
- itemization(
- it() Author: AUTHORNAME()
- it() Maintainer: MAINTAINERNAME() MAINTAINEREMAIL())
diff --git a/doc/man/crossroads.conf.yo b/doc/man/crossroads.conf.yo
@@ -1,29 +0,0 @@
-includefile(../crossroads-defs)
-
-manpage(crossroads.conf)(7)(YEARS())(crossroads)()
-manpagename(crossroads.conf)(Crossroads configuration)
-
-manpagesynopsis()
-This manpage describes the configuration of
-Crossroads, usually the file bf(crossroads.conf). This file is often
-located in an 'etc' directory near the path where Crossroads is
-installed. E.g., when Crossroads is installed as
-bf(/usr/local/bin/crossroads), then the configuration file can be
-tt(/usr/local/etc/crossroads.conf). Alternatively the configuration
-can always be put in bf(/etc/crossroads.conf). Crossroads can however
-be started with a flag bf(-c) to specify an entirely different name..
-
-manpagedescription()
-redef(confsect)(1)(manpagesection(ARG1))
-redef(confsubsect)(1)(bf(ARG1))
-includefile(../main/config)
-
-manpageseealso()
- itemization(
- it() crossroads (1)
- it() The full Crossroads documentation, in pdf and html
- format, distributed with the sources.)
-
-manpageauthor()
- Crossroads is written by AUTHORNAME() and is maintained by
- MAINTAINERNAME() (MAINTAINEREMAIL()).
diff --git a/doc/man/crossroads.yo b/doc/man/crossroads.yo
@@ -1,120 +0,0 @@
-includefile(../crossroads-defs)
-manpage(crossroads)(1)(YEARS())(crossroads)()
-manpagename(crossroads)(Load balancer and fail over utility)
-
-manpagesynopsis()
- itemization(
- it() bf(crossroads) em([flags]) bf(start): starts Crossroads
- it() bf(crossroads) em([flags]) bf(stop): stops Crossroads
- it() bf(crossroads) em([flags]) bf(restart): restarts Crossroads
- it() bf(crossroads) em([flags]) bf(configtest): verifies
- configuration
- it() bf(crossroads) em([flags]) bf(services): shows configured
- services
- it() bf(crossroads) em([flags]) bf(tell) em(service)
- em(backend) bf(state) em(newstate): sets a back end state
- it() bf(crossroads) em([flags]) bf(tell) em(service)
- em(backend) bf(server) em(hostname:port): redefines the
- address of a back end)
-
-manpagedescription()
-
- bf(crossroads) is the main control program of Crossroads, a
- balancing and fail over utility. The Crossroads utility consists
- of two binaries: bf(crossroads) and bf(crossroads-daemon). The
- latter is controlled by the front end bf(crossroads).
-
- Recognized states in bf(crossroads tell) are:
-
- itemization(
- it() bf(available) or bf(up) when a backend is working;
- it() bf(unavailable) when a back end is temporarily down, but
- can be woken up;
- it() bf(down) when a back end is permanently down (e.g., for
- maintenance). Crossroads itself will never activate a
- backend in this state.
- it() bf(waking) when the live status of a back end is being checked.)
-
-manpageoptions()
-
- Crossroads recognizes the following flags:
-
- itemization(
- it() bf(-a): Logs start and end times of activity to
- em(syslog).
-
- it() bf(-b): Writes a binary representation of the
- configuration to em(stdout). For debugging only.
-
- it() bf(-B) em(size): Sets the size of network buffers. Larger
- buffers will mean a less number of tt(read()) or
- tt(write()) operations, but a larger memory
- footprint. Usually the default value will do fine.
-
- it() bf(-C): Writes the compile time configuration to
- em(stdout) and stops. Useful when submitting bug reports.
-
- it() bf(-c) em(config): Uses em(config) as the configuration
- file. The default is bf(/some/path/etc/crossroads.conf)
- or bf(/etc/crossroads.conf). The first alternative
- applies when Crossroads is installed as
- bf(/some/path/bin/crossroads); in that case, Crossroads
- tries to find its configuration by trying an 'etc'
- diretory 'near' its own path.
-
- it() bf(-d) em(sec): Sets the DNS cache time-to-live to
- em(sec) seconds. Value 0 suppresses DNS entry
- caching. The default is bf(DNSCACHETTL()).
-
- it() bf(-l) em(facility): Specifies the openlog (3) facility,
- default is bf(LOG_DAEMON). Values can be 0 to 7, meaning
- bf(LOG_LOCAL0) to bf(LOG_LOCAL9).
-
- it() bf(-m) em(permissions): Specifies shared memory
- permissions, default is bf(0644).
-
- it() bf(-s): Requests 'sloppy' binding to TCP ports. When a
- port is busy, Crossroads will retry periodically to get
- it. Default is to stop when a listening port cannot be
- obtained.
-
- it() bf(-t): Output of bf(crossroads status) is shown as a
- tabular view, in one or more lines of:
-
- em(service) em(backend=state) em([backend=state...])
-
- it() bf(-x): Output of bf(crossroads status) is shown as an
- XML document.
-
- it() bf(-v): Initial actions of Crossroads are more
- 'verbose'. (Once daemonized, the verbosity is controlled
- using bf(verbosity) statements in the configuration.)
-
- it() bf(-V): Shows the version ID and stops.
-
- it() bf(-?): Shows an overview of the usage.)
-
-manpagefiles()
- bf(crossroads.conf), the default configuration file
-
-manpageseealso()
- itemization(
- it() crossroads.conf (7)
- it() The full Crossroads documentation in html or pdf format,
- distributed with the sources.)
-
-manpagebugs()
- Crossroads is of course bug free (haha). When submitting bugs to
- the maintainer. please always include the following information:
-
- itemization(
- it() The configuration file that Crossroads uses;
- it() The compile-time configuration, which is the output of
- bf(crossroads -C);
- it() A good description of the bug, and of the conditions
- under which it occurs.)
-
-manpageauthor()
- itemization(
- it() Author: AUTHORNAME()
- it() Maintainer: MAINTAINERNAME() MAINTAINEREMAIL())
diff --git a/doc/xr.odt b/doc/xr.odt
Binary files differ.
diff --git a/doc/xr.pdf b/doc/xr.pdf
Binary files differ.
diff --git a/etc/Makefile.conf b/etc/Makefile.conf
@@ -1,44 +0,0 @@
-# The used C compiler.
-CC := $(shell $(BASE)/tools/c-conf -vc $(BASE)/src/c-conf.cache c-compiler)
-
-# Link time libraries.
-LIBS := $(shell $(BASE)/tools/c-conf -vc $(BASE)/src/c-conf.cache lib \
- ucb nsl pthread socket m alf 2>/dev/null)
-
-# Compiletime defines. Remember to update show_config() when changing
-# this list!
-DEFS := -DSLEEP_TIME=$(SLEEP_TIME) -DDNS_CACHESIZE=$(DNS_CACHESIZE) \
- -DDNS_CACHETTL=$(DNS_CACHETTL) -DDEF_MAX=$(DEF_MAX) \
- -DCONNECT_TIMEOUT=$(CONNECT_TIMEOUT) -DVER='"$(VER)/$(REVVER)"' \
- -DSET_PROC_TITLE_BY_ARGV=$(SET_PROC_TITLE_BY_ARGV) \
- -DDEFAULT_TCP_BUFSZ=$(DEFAULT_TCP_BUFSZ) -DRETRY_WAIT=$(RETRY_WAIT) \
- -DREVVER='"$(REVVER)"' -DBINDIR='"$(BINDIR)"' \
- -DPREFIX='"$(PREFIX)"' -DYEARS='"$(YEARS)"' \
- -DEXTRALIBS='"$(EXTRALIBS)"' -DLIBS='"$(LIBS)"' \
- -DAUTHORNAME='"$(AUTHORNAME)"' -DMAINTAINERNAME='"$(MAINTAINERNAME)"' \
- -DMAINTAINEREMAIL='"$(MAINTAINEREMAIL)"' -DFQDN_LENGTH=$(FQDN_LENGTH) \
- -DDEFAULT_SPT_BUFSIZE=$(DEFAULT_SPT_BUFSIZE) \
- $(shell $(BASE)/tools/c-conf -vc $(BASE)/src/c-conf.cache \
- ifheader01 malloc.h HAVE_MALLOC_H) \
- $(shell $(BASE)/tools/c-conf -vc $(BASE)/src/c-conf.cache \
- ifheader01 stdint.h HAVE_STDINT_H) \
- $(shell $(BASE)/tools/c-conf -vc $(BASE)/src/c-conf.cache \
- libfunction01 flock HAVE_FLOCK) \
- $(shell $(BASE)/tools/c-conf -vc $(BASE)/src/c-conf.cache \
- libfunction01 lockf HAVE_LOCKF) \
- $(shell $(BASE)/tools/c-conf -vc $(BASE)/src/c-conf.cache \
- libfunction01 strlcat HAVE_STRLCAT) \
- $(shell $(BASE)/tools/c-conf -vc $(BASE)/src/c-conf.cache \
- libfunction01 sranddev HAVE_SRANDDEV) \
- $(shell $(BASE)/tools/c-conf -vc $(BASE)/src/c-conf.cache \
- libfunction01 vsyslog HAVE_VSYSLOG) \
- $(shell $(BASE)/tools/c-conf -vc $(BASE)/src/c-conf.cache \
- libfunction01 strcasestr HAVE_STRCASESTR) \
- $(shell $(BASE)/tools/c-conf -vc $(BASE)/src/c-conf.cache \
- libfunction01 setproctitle HAVE_SETPROCTITLE) \
- $(shell $(BASE)/tools/c-conf -vc $(BASE)/src/c-conf.cache \
- libfunction01 strupr HAVE_STRUPR) \
- $(shell $(BASE)/tools/c-conf -vc $(BASE)/src/c-conf.cache \
- libfunction01 strnstr HAVE_STRNSTR) \
- $(shell $(BASE)/tools/c-conf -vc $(BASE)/src/c-conf.cache \
- libvariable01 __progname_full HAVE_PROGNAME_FULL)
diff --git a/etc/Makefile.def b/etc/Makefile.def
@@ -1,78 +0,0 @@
-# Definitions for the making of... Crossroads!
-# --------------------------------------------
-# Tweak the below values to your liking. Just don't uncomment anything;
-# if you don't need the setting, set it to zero (for numbers) or to an
-# emtpy value (for strings).
-
-# Versioning. This defines the overall version ID and must match the topmost
-# entry in the ChangeLog.
-VER = 1.81
-
-# Years that Crossroads has been 'round.
-YEARS = 2005-2008
-
-# Author and maintainer
-AUTHORNAME = Karel Kubat
-MAINTAINERNAME = Karel Kubat
-MAINTAINEREMAIL = karel@kubat.nl
-
-# Revision version, auto-detected.
-REVVER = $(shell $(BASE)/etc/svnrev $(BASE)/ChangeLog $(BASE)/etc/svnrev.txt)
-
-# The length of a fully qualified domain name. See RFC2181.
-FQDN_LENGTH = 256
-
-# Sleep time (sec). When we detect that there are too many clients, or
-# no back ends, then we'll wait during this period.
-SLEEP_TIME = 10
-
-# How long before an attempt to connect to a back end fails (secs)?
-# This is NOT the sessiontimeout specifier of the config file; it affects
-# trying to connect to a back end. If your back ends are nearby
-# (as they should be) then keep this number small.
-CONNECT_TIMEOUT = 2
-
-# When retrying connecting to the same back end (config: retries), how
-# long should we wait between trying again?
-RETRY_WAIT = 1
-
-# The default size of buffers for the copying of data between sockets.
-# Can be overruled using the flag -B.
-DEFAULT_TCP_BUFSZ = 5120
-
-# The max size of the DNS cache (nr of entries). Crossroads will cache
-# gethostbyname() results until the max nr is exceeded; then the latest hits
-# will be killed off.
-DNS_CACHESIZE = 20
-
-# The max age of a DNS cache entry, before it is considered obsolete.
-# Value is in seconds; so e.g. 900 is 15 minutes, 3600 is 1 hour.
-# Value 0 suppresses DNS caching. This can always be overruled using the
-# flag -d.
-DNS_CACHETTL = 0
-
-# The number of #define expansions before Crossroads thinks it's a
-# circular definition. Also the max nr of #defines that's allowed in one file.
-DEF_MAX = 1000
-
-# Prefix directory for the install processs.
-PREFIX = /usr/local
-
-# Installation directory for the binaries.
-BINDIR = $(PREFIX)/bin
-
-# Default size of a commandline buffer. This is used in juggling the
-# process name. If your headers define SPT_BUFSIZE then that will be used
-# instead.
-DEFAULT_SPT_BUFSIZE = 2048
-
-# If you're on Linux, then one can set the program title for 'ps' output
-# by modifying argv directly. If you're on Linux or if your system supports
-# this too, then define as value 1. Otherwise set to zero. If your system
-# has setproctitle(3) then that will be used instead.
-SET_PROC_TITLE_BY_ARGV = 1
-
-# Set to some meaningful value if you're on Solaris and don't want to
-# fiddle with LD_LIBRARY_PATH or crle (yuk!)
-# EXTRALIBS = -R/usr/ucblib
-EXTRALIBS =
diff --git a/etc/Makefile.help b/etc/Makefile.help
@@ -1,37 +0,0 @@
-============================================================================
- The Making Of.... Crossroads.
-============================================================================
-
-Make what? Choose:
-
-** Local Construction **
- make compile-only Local program construction (src/crossroads/crossroads
- and src/crossroads-daemon/crossroads-daemon)
- make local Local program construction and unit tests
- make local-g Like 'make local' but wigh 'gdb' symbols
- make local-pg Like 'make local-g' but with 'gprof' profiling
- make local-alf Like 'make local' but with allocation leak finder
- (requires 'alf', for debugging only)
- make documentation Creates documentation under doc/. Requires Yodl
- and pdflatex.
-
-** Installing **
- make install Locally built programs are installed, and the
- manpages are installed, see etc/Makefile.def for
- the destination location.
- NOTE: Don't use 'make local-pg' and 'make install'
- in production environments!
- make dbginstall Debug-able programs are installed (for testing only)
- make pginstall Debug-able and profile-able programs are installed
- (for testing/profiling only)
-
-** Maintenance **
- make clean Cleanup of stale files
- make distclean Even cleaner still
- make dist Creates a distribution as
- /tmp/crossroads-VERSION.tar.gz, Yodl etc. required
- make commit Creates documentation, cleans up, commits into SVN.
-
-(If your GNU make is called 'gmake', just type with 'gmake <whatever>'.)
-
-============================================================================
diff --git a/etc/dispatcher-roundrobin b/etc/dispatcher-roundrobin
@@ -1,84 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-
-# Example of a round-robin external dispatcher. This is totally
-# superfluous, Crossroads has this on-board; if you use the external
-# program for determining round-robin dispatching, then you'll only
-# slow things down. This script is just meant as an example.
-
-# Globals / configuration
-# -----------------------
-my $log = '/tmp/exthandler.log'; # Debug log, set to /dev/null to suppress
-my $statefile = '/tmp/rr.last'; # Where we keep the last used
-
-# Logging
-# -------
-sub msg {
- return if ($log eq '/dev/null' or $log eq '');
- open (my $of, ">>$log") or return;
- print $of (scalar(localtime()), ' ', @_);
-}
-
-# Read the last used back end
-# ---------------------------
-sub readlast() {
- my $ret;
-
- if (open (my $if, $statefile)) {
- $ret = <$if>;
- chomp ($ret);
- close ($if);
- msg ("Last used back end: $ret\n");
- return ($ret);
- }
- msg ("No last-used back end (yet)\n");
- return (undef);
-}
-
-# Write back the last used back end, reply to Crossroads and stop
-# ---------------------------------------------------------------
-sub reply ($) {
- my $last = shift;
-
- if (open (my $of, ">$statefile")) {
- print $of ("$last\n");
- }
- print ("$last\n");
- exit (0);
-}
-
-# Main starts here
-# ----------------
-
-# Collect the cmdline arguments. We expect pairs of backend-name /
-# backend-availablility, and we'll store only the available ones.
-msg ("Dispatch request received\n");
-my @backend;
-for (my $i = 0; $i <= $#ARGV; $i += 2) {
- push (@backend, $ARGV[$i]) if ($ARGV[$i + 1]);
-}
-msg ("Available back ends: @backend\n");
-
-# Let's see what the last one is. If none found, then we return the
-# first available back end. Otherwise we need to go thru the list of
-# back ends, and return the next one in line.
-my $last = readlast();
-if ($last eq '') {
- msg ("Returning first available back end $backend[0]\n");
- reply ($backend[0]);
-}
-
-# There **was** a last back end. Try to match it in the list,
-# then return the next-in-line.
-for (my $i = 0; $i < $#backend; $i++) {
- if ($last eq $backend[$i]) {
- msg ("Returning next back end ", $backend[$i + 1], "\n");
- reply ($backend[$i + 1]);
- }
-}
-
-# No luck.. run back to the first one.
-msg ("Returning first back end $backend[0]\n");
-reply ($backend[0]);
-
diff --git a/etc/hdr.template b/etc/hdr.template
@@ -1,5 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads __VER__, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
diff --git a/etc/healthcheck b/etc/healthcheck
@@ -1,63 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use LWP::UserAgent;
-
-# Show usage and stop
-sub usage () {
- die <<"ENDUSAGE";
-
-Usage: healthcheck URL SERVICE BACKEND
-
-Performs a health check of the stated url and if necessary flips the
-state of the stated back end between 'available' and 'unavailable'.
-Back ends that are 'down' are not affected.
-
-ENDUSAGE
-}
-
-# Test an URL. Return whether it's a success.
-sub testurl() {
- my $ua = LWP::UserAgent->new();
- my $req = HTTP::Request->new(GET => $ARGV[0]);
- my $res = $ua->request($req);
-
- if ($res->is_success()) {
- print ("URL $ARGV[0] indicates success\n");
- return (1);
- } else {
- print ("URL $ARGV[0] indicates failure\n");
- return (0);
- }
-}
-
-# Main starts here
-usage() unless ($#ARGV == 2);
-
-# Get the current state of the back end
-open (my $if, "crossroads -t status '$ARGV[1]' '$ARGV[2]' |")
- or die ("Cannot run 'crossroads status'\n");
-my $status = <$if>;
-close ($if) or die ("'crossroads status' terminated with error\n");
-chomp ($status);
-$status =~ s{.*=}{};
-$status =~ s{\s+}{};
-
-print ("Back end $ARGV[2] has status $status\n");
-if ($status eq 'UNAVAILABLE') {
- if (testurl()) {
- print ("Back end $ARGV[2] is now available\n");
- system ("crossroads tell $ARGV[1] $ARGV[2] available")
- and die ("'crossroads tell' terminated with error\n");
- }
-} elsif ($status eq 'available') {
- if (!testurl()) {
- print ("Back end $ARGV[2] is is now UNAVAILABLE\n");
- system ("crossroads tell $ARGV[1] $ARGV[2] UNAVAILABLE")
- and die ("'crossroads tell' terminated with error\n");
- }
-} else {
- print ("No action given status '$status'\n");
-}
-
-
diff --git a/etc/rdp-helper b/etc/rdp-helper
@@ -1,140 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use GDBM_File;
-
-# Global variables and configuration
-# ----------------------------------
-my $log = '/tmp/exthandler.log'; # Debug log, set to /dev/null to suppress
-my $cdb = '/tmp/client.db'; # GDBM database of clients
-my %db; # .. and memory representation of it
-my $timeout = 24*60*60; # Timeout of a connection in secs
-
-# Logging
-# -------
-sub msg {
- return if ($log eq '/dev/null' or $log eq '');
- open (my $of, ">>$log") or return;
- print $of (scalar(localtime()), ' ', @_);
- close ($of);
-}
-
-# Reply a back end to the caller and stop processing.
-# ---------------------------------------------------
-sub reply ($) {
- my $b = shift;
- msg ("Suggesting $b to Crossroads.\n");
- print ("$b\n");
- exit (0);
-}
-
-# Is a value in an array
-# ----------------------
-sub inarray {
- my $val = shift;
- for my $other (@_) {
- return (1) if ($other eq $val);
- }
- return (0);
-}
-
-# A connection is starting
-# ------------------------
-sub start {
- my ($ip, $stamp, $backend) = @_;
- msg ("Logging START of connection for IP $ip on stamp $stamp, ",
- "back end $backend\n");
- $db{$ip} = "$backend:$stamp";
-}
-
-# A connection has ended
-# ----------------------
-sub end {
- my $ip = shift;
- msg ("Logging END of connection for IP $ip\n");
- $db{$ip} = undef;
-}
-
-# A back end has failed
-# ---------------------
-sub fail {
- my $backend = shift;
- msg ("Back end $backend failed, thanks for notifying me\n");
-}
-
-# Request to determine a back end
-# -------------------------------
-sub dispatch {
- my $ip = shift;
- my $stamp = shift;
-
- msg ("Request to dispatch IP $ip on stamp $stamp\n");
-
- # Read the next arguments. They are triplets of
- # backend-name / availability / weight. Store if the back end is
- # available.
- my (@backends, @weights);
- for (my $i = 0; $i < $#_; $i += 3) {
- if ($_[$i + 1] != 0) {
- push (@backends, $_[$i]);
- push (@weights, $_[$i + 2]);
- msg ("Candidate back end: $_[$i] with weight ", $_[$i + 2], "\n");
- }
- }
-
- # See if this is a reconnect by a previously seen client IP. We'll
- # treat this as a reconnect if the timeout wasn't yet exceeded.
- if ($db{$ip} ne '') {
- my ($last_backend, $last_stamp) = split (/:/, $db{$ip});
- msg ("IP $ip had last connected on $last_stamp to $last_backend\n");
- if ($stamp < $last_stamp + $timeout) {
- msg ("Timeout not yet exceeded, this may be a reconnect\n");
- # We'll allow a reconnect only if the stated last_backend is
- # free (sanity check).
- if (inarray ($last_backend, @backends)) {
- msg ("Last back end $last_backend is available, ",
- "letting through\n");
- reply ($last_backend);
- } else {
- msg ("Last used back end isn't free, suggesting a new one\n");
- }
- } else {
- msg ("Timeout exceeded, suggesting a new back end\n");
- }
- } else {
- msg ("Np preveious connection data, suggesting a new back end\n");
- }
-
- my $bestweight = -1;
- my $bestbackend;
- for (my $i = 0; $i <= $#weights; $i++) {
- if ($bestweight == -1 or $bestweight > $weights[$i]) {
- $bestweight = $weights[$i];
- $bestbackend = $backends[$i];
- }
- }
-
- msg ("Best back end: $bestbackend (given weight $bestweight)\n");
- reply ($bestbackend);
-}
-
-# Main starts here
-# ----------------
-msg ("Start of run, attaching GDBM database '$cdb'\n");
-tie (%db, 'GDBM_File', $cdb, &GDBM_WRCREAT, 0600);
-
-# The first argument must be an action 'dispatch', 'start' or 'end'.
-# Depending on the action, we do stuff.
-my $action = shift (@ARGV);
-if ($action eq 'dispatch') {
- dispatch (@ARGV);
-} elsif ($action eq 'start') {
- start (@ARGV);
-} elsif ($action eq 'end') {
- end (@ARGV);
-} elsif ($action eq 'fail') {
- fail (@ARGV);
-} else {
- print STDERR ("Usage: rdp-helper {dispatch|start|end|fail} args\n");
- exit (1);
-}
diff --git a/etc/svncheck b/etc/svncheck
@@ -1,21 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-
-my $startdir = $ENV{BASE}
- or die ("BASE not set.\n",
- "You should only run this from the top level level Makefile!\n");
-chdir ($startdir)
- or die ("Start dir '$startdir' not available!\n");
-
-open (my $if, "svn status |")
- or die ("Cannot run 'svn status'\n");
-my $unknowns = 0;
-while (my $line = <$if>) {
- if ($line =~ /^\?/) {
- print STDERR ("ERROR - unknown: $line");
- $unknowns++;
- }
-}
-die ("ERROR - $unknowns unknown files, svn not up to date?\n")
- if ($unknowns);
diff --git a/etc/svnrev b/etc/svnrev
@@ -1,42 +0,0 @@
-#!/usr/bin/perl
-use strict;
-
-die ("Usage: svnrev REFERENCEFILE STATEFILE\n",
- "The revision number of the reference file is retrieved and shown.\n",
- "The state file is updated.\n")
- if ($#ARGV != 1);
-
-die ("No such file $ARGV[0]\n")
- unless (-f $ARGV[0]);
-
-my $revno;
-
-# Can we slurp in "svn info"?
-if (open (my $if, "svn info $ARGV[0] 2>&1 |")) {
- while (defined (my $line = <$if>)) {
- chomp ($line);
- next unless ($line =~ /Last Changed Rev:/);
- $line =~ s/Last Changed Rev: //;
- $revno = $line;
- }
- close ($if);
-
- if ($revno ne '') {
- open (my $of, ">$ARGV[1]")
- or die ("Cannot write $ARGV[2]: $!\n");
- print $of ("$revno\n");
- close ($of);
- }
-}
-
-# If we failed to retrieve the rev no, get it from the state file.
-if ($revno eq '') {
- open (my $if, $ARGV[1])
- or die ("Cannot read $ARGV[1]: $!\n");
- $revno = <$if>;
- chomp ($revno);
- close ($if);
-}
-
-# Finally.. display it
-print ("$revno\n");
diff --git a/etc/svnrev.txt b/etc/svnrev.txt
@@ -1 +0,0 @@
-233
diff --git a/etc/xml-status-short.xslt b/etc/xml-status-short.xslt
@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xsl:stylesheet version="1.0"
- xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
-
-<xsl:template match="/">
- <html>
- <head>
- <title>Crossroads Status Overview</title>
- </head>
- <body>
- <h1>Crossroads Status Overview</h1>
- <xsl:apply-templates/>
- </body>
- </html>
-</xsl:template>
-
-<xsl:template match="/status">
- <table>
- <xsl:apply-templates/>
- </table>
-</xsl:template>
-
-<xsl:template match="/status/service">
- <tr>
- <td> <b> Service <xsl:value-of select="@name"/> </b> </td>
- <td align="right"> <xsl:value-of select="connections"/> </td>
- <td> connections </td>
- </tr>
- <xsl:apply-templates/>
- <tr> </tr>
-</xsl:template>
-
-<xsl:template match="/status/service/backend">
- <tr>
- <td> </td>
- <td> Backend </td>
- <td> <b> <xsl:value-of select="@name"/> </b> </td>
- <td>
- is <xsl:value-of select="availability"/>
- </td>
- <td> </td>
- </tr>
- <tr>
- <td> </td>
- <td> </td>
- <td> Clients: </td>
- <td>
- total <xsl:value-of select="connections"/>,
- <xsl:value-of select="failures"/> failures
- </td>
- </tr>
- <tr>
- <td> </td>
- <td> </td>
- <td> Usage: </td>
- <td>
- <xsl:value-of select="throughput"/> in
- <xsl:value-of select="duration"/>,
- <xsl:value-of select="clients"/> active connections
- </td>
- </tr>
- <xsl:apply-templates/>
-</xsl:template>
-
-<xsl:template match="*"/>
-
-</xsl:stylesheet>
diff --git a/etc/xml-status-to-html.xslt b/etc/xml-status-to-html.xslt
@@ -1,131 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xsl:stylesheet version="1.0"
- xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
-
-<!-- Sample XSLT stylesheet to convert "crossroads -x status"
- into HTML. This is only a VERY BASIC example, you would
- want to add a CSS, or to display information in a different
- way. Good luck! - Karel <karel@e-tunity.com> -->
-
-<xsl:template match="/">
- <html>
- <head>
- <title>Crossroads Status Overview</title>
- </head>
- <body>
- <h1>Crossroads Status Overview</h1>
- <xsl:apply-templates/>
- </body>
- </html>
-</xsl:template>
-
-<xsl:template match="/status">
- <table>
- <xsl:apply-templates/>
- </table>
-</xsl:template>
-
-<xsl:template match="/status/service">
- <tr>
- <td> <b> Service <xsl:value-of select="@name"/> </b> </td>
- <td> </td>
- <td> </td>
- <td> </td>
- </tr>
- <xsl:apply-templates/>
-</xsl:template>
-
-<xsl:template match="/status/service/connections">
- <tr>
- <td> </td>
- <td> Connections: </td>
- <td> </td>
- <td> <xsl:value-of select="."/> </td>
- </tr>
-</xsl:template>
-
-<xsl:template match="/status/service/lastbackend">
- <tr>
- <td> </td>
- <td> Last back end: </td>
- <td> </td>
- <td> <xsl:value-of select="."/> </td>
- </tr>
-</xsl:template>
-
-<xsl:template match="/status/service/backend">
- <tr>
- <td> </td>
- <td> <b> Backend <xsl:value-of select="@name"/> </b> </td>
- <td> </td>
- <td> </td>
- </tr>
- <xsl:apply-templates/>
-</xsl:template>
-
-<xsl:template match="/status/service/backend/availability">
- <tr>
- <td> </td>
- <td> </td>
- <td> Availability: </td>
- <td> <xsl:value-of select="."/> </td>
- </tr>
-</xsl:template>
-
-<xsl:template match="/status/service/backend/clients">
- <tr>
- <td> </td>
- <td> </td>
- <td> Connections: </td>
- <td> <xsl:value-of select="."/> </td>
- </tr>
-</xsl:template>
-
-<xsl:template match="/status/service/backend/connections">
- <tr>
- <td> </td>
- <td> </td>
- <td> Total successes: </td>
- <td> <xsl:value-of select="."/> </td>
- </tr>
-</xsl:template>
-
-<xsl:template match="/status/service/backend/failures">
- <tr>
- <td> </td>
- <td> </td>
- <td> Total failures: </td>
- <td> <xsl:value-of select="."/> </td>
- </tr>
-</xsl:template>
-
-<xsl:template match="/status/service/backend/duration">
- <tr>
- <td> </td>
- <td> </td>
- <td> Duration: </td>
- <td> <xsl:value-of select="."/> </td>
- </tr>
-</xsl:template>
-
-<xsl:template match="/status/service/backend/throughput">
- <tr>
- <td> </td>
- <td> </td>
- <td> Throughput: </td>
- <td> <xsl:value-of select="."/> </td>
- </tr>
-</xsl:template>
-
-<xsl:template match="/status/service/backend/sessions">
- <tr>
- <td> </td>
- <td> </td>
- <td> Sessions: </td>
- <td> <xsl:value-of select="."/> </td>
- </tr>
-</xsl:template>
-
-<xsl:template match="*"/>
-
-</xsl:stylesheet>
diff --git a/src/Makefile b/src/Makefile
@@ -1,45 +0,0 @@
-include ../etc/Makefile.def
-
-DIRS = lib crossroads crossroads-daemon crossroads-mgr
-
-all: prep
- for d in ${DIRS}; do \
- echo "Making all in $$d"; \
- echo BASE=$(BASE) PG=$(PG) G=$(G) $(MAKE) -C $$d all; \
- BASE=$(BASE) PG=$(PG) G=$(G) ALF=$(ALF) \
- $(MAKE) -C $$d all || exit 1; \
- done
-
-install: prep
- for d in ${DIRS}; do \
- echo "Making install in $$d"; \
- echo BASE=$(BASE) PG=$(PG) G=$(G) $(MAKE) -C $$d install; \
- BASE=$(BASE) $(MAKE) -C $$d install || exit 1; \
- done
-
-dbginstall: prep
- for d in ${DIRS}; do \
- echo "Making dbginstall in $$d"; \
- echo BASE=$(BASE) PG=$(PG) G=$(G) $(MAKE) -C $$d dbginstall; \
- BASE=$(BASE) $(MAKE) -C $$d dbginstall || exit 1; \
- done
-
-clean:
- for d in ${DIRS}; do \
- echo "Making clean in $$d"; \
- echo BASE=$(BASE) $(MAKE) -C $$d clean; \
- BASE=$(BASE) $(MAKE) -C $$d clean || exit 1; \
- done
- rm -f c-conf.cache
-
-distclean:
- for d in ${DIRS}; do \
- echo "Making distclean in $$d"; \
- echo BASE=$(BASE) $(MAKE) -C $$d distclean; \
- BASE=$(BASE) $(MAKE) -C $$d distclean || exit 1; \
- done
- rm -f c-conf.cache
-
-prep:
- ../tools/gettools e-ver e-txt2c c-conf
- ../tools/e-ver ../ChangeLog $(VER)
diff --git a/src/crossroads-daemon/Makefile b/src/crossroads-daemon/Makefile
@@ -1,28 +0,0 @@
-include $(BASE)/etc/Makefile.def
-include $(BASE)/etc/Makefile.conf
-
-BIN = crossroads-daemon
-all:
- BASE=$(BASE) $(MAKE) $(BIN)
-
-dbginstall: all $(BINDIR)/$(BIN)
-
-install: all $(BINDIR)/$(BIN)
- strip $(BINDIR)/$(BIN)
-
-distclean: clean
-clean:
- rm -f *.o $(BIN)
-
-$(BINDIR)/$(BIN): $(BIN)
- cp $(BIN) $(BINDIR)/$(BIN)
-
-main.o: main.c
- $(CC) -c -g -W -Wall $(DEFS) $(PG) main.c
-
-$(BIN): main.o ../lib/libcrossroads.a
- $(CC) $(PG) -o $(BIN) main.o -L$(BASE)/src/lib -lcrossroads \
- $(LIBS) $(EXTRALIBS)
-
-# Extra deps:
-main.o: main.c $(BASE)/src/crossroads.h $(BASE)/etc/Makefile.def
diff --git a/src/crossroads-daemon/main.c b/src/crossroads-daemon/main.c
@@ -1,61 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-int main (int argc, char **argv) {
- int i;
-
- /* Remember original ac/av/ep */
- org_argc = argc;
- org_argv = argv;
-
- /* Inherit program options and configuration */
- options_read (0);
- config_read (0);
-
- /* Convert the log facility number into a syslog constant. */
- switch (opt.log_facility) {
- case 0:
- opt.log_facility = LOG_LOCAL0;
- break;
- case 1:
- opt.log_facility = LOG_LOCAL1;
- break;
- case 2:
- opt.log_facility = LOG_LOCAL2;
- break;
- case 3:
- opt.log_facility = LOG_LOCAL3;
- break;
- case 4:
- opt.log_facility = LOG_LOCAL4;
- break;
- case 5:
- opt.log_facility = LOG_LOCAL5;
- break;
- case 6:
- opt.log_facility = LOG_LOCAL6;
- break;
- case 7:
- opt.log_facility = LOG_LOCAL7;
- break;
- default:
- opt.log_facility = LOG_DAEMON;
- break;
- }
-
- /* We're the daemon executable. We know what to do -- serve. */
- msg ("Starting services");
- for (i = 0; i < nservice; i++) {
- /* Start the service. */
- activeservice = service + i;
- runservice ();
- }
-
- /* All done. */
- return (0);
-}
diff --git a/src/crossroads-mgr/Makefile b/src/crossroads-mgr/Makefile
@@ -1,19 +0,0 @@
-include $(BASE)/etc/Makefile.def
-
-all: crossroads-mgr
-crossroads-mgr: crossroads-mgr.in Makefile $(BASE)/tools/patch-mgr \
- crossroads-mgr.xslt $(BASE)/etc/Makefile.def \
- crossroads-mgr.usage
- $(BASE)/tools/patch-mgr $(VER)/$(REVVER) \
- crossroads-mgr.xslt crossroads-mgr.usage < $< > $@
- chmod +x $@
-
-dbginstall: install
-install: $(BINDIR)/crossroads-mgr
-$(BINDIR)/crossroads-mgr: crossroads-mgr
- cp crossroads-mgr $(BINDIR)/crossroads-mgr
- chmod +x $(BINDIR)/crossroads-mgr
-
-distclean: clean
-clean:
- rm -f crossroads-mgr
diff --git a/src/crossroads-mgr/crossroads-mgr.in b/src/crossroads-mgr/crossroads-mgr.in
@@ -1,460 +0,0 @@
-#!/usr/bin/perl
-
-__WARNING__
-
-use strict;
-use HTTP::Daemon;
-use Getopt::Std;
-use POSIX qw(:sys_wait_h setsid);
-use MIME::Base64;
-
-# The built in XSLT.
-my $builtin_xslt = <<'END_XSLT';
-__XSLT__
-END_XSLT
-
-# The version ID
-my $VER = "__VER__";
-
-# Main starts here
-my $prog;
-$prog = Program->new();
-my $daemon = Daemon->new ();
-$daemon->start ($prog->port()); # doesn't return
-
-
-# All program-related functions
-{
- package Program;
- use strict;
-
- # Instantiate program handler. Parse the commandline.
- sub new {
- my $proto = shift;
- my $self = {};
- my %opts;
-
- # Get the commandline options.
- ::getopts ('vfl:x:X:b:B:a:', \%opts) or usage();
-
- # Act according to argument; 'start' is handled here.
- if ($ARGV[0] eq 'stop') {
- stop();
- exit (0);
- } elsif ($ARGV[0] eq 'status' and $#ARGV == 0) {
- status();
- exit (0);
- } elsif ($ARGV[0] ne 'start' or $#ARGV != 1) {
- usage();
- exit (0);
- }
-
- # ARGV[0] was 'start' and there is one more argument $ARGV[1], port
- $self->{port} = sprintf ("%d", $ARGV[1]);
- $self->{verbose} = $opts{v} ? 1 : 0;
- $self->{foreground} = $opts{f} ? 1 : 0;
- $self->{isdaemon} = 0;
- $self->{xsltfile} = $opts{X} if ($opts{X});
- $self->{address} = $opts{a} if ($opts{a});
- if ($opts{b}) {
- if ($opts{b} eq 'PROMPT') {
- print ("Enter username:password for status authentication: ")
- if (-t STDIN);
- $opts{b} = <STDIN>;
- chomp ($opts{b});
- }
- $self->{statuscred} = ::encode_base64($opts{b});
- chomp ($self->{statuscred});
- }
- if ($opts{B}) {
- if ($opts{B} eq 'PROMPT') {
- print ("Enter username:password for updating authentication: ")
- if (-t STDIN);
- $opts{B} = <STDIN>;
- chomp ($opts{B});
- }
- $self->{setcred} = ::encode_base64($opts{B});
- chomp ($self->{setcred});
- }
- if ($opts{x}) {
- $self->{call} = $opts{x};
- } else {
- $self->{call} = '';
- for my $p (split /:/, $ENV{PATH}) {
- if (-x "$p/crossroads") {
- $self->{call} = "$p/crossroads";
- last;
- }
- }
- die ("Failed to locate crossroads program on PATH\n")
- if ($self->{call} eq '');
- }
- die ("Argument $ARGV[0] is not a port number\n") unless ($self->{port});
- $self->{logfile} = "/tmp/crossroads-mgr.log";
- $self->{logfile} = $opts{l} if ($opts{l});
-
- bless ($self, $proto);
- return ($self);
- }
-
- # Return the necessary un/pw for status viewing, in Base64 encoding
- sub authstatus {
- return ($_[0]->{statuscred});
- }
-
- # Return the necessary un/pw for status setting, in Base64 encoding
- sub authset {
- return ($_[0]->{setcred});
- }
-
- # Show usage and stop.
- sub usage {
- die <<"ENDUSAGE";
-
-__USAGE__
-
-ENDUSAGE
- }
-
- # Stop the daemon. NOTE: Class-less, called from the constructor.
- sub stop {
- my @pids = pids()
- or die ("crossroads-mgr is not running\n");
- kill (2, @pids);
- }
-
- # Report on the status. NOTE: Class-less, called from the constructor.
- sub status {
- my @pids;
- if (@pids = pids()) {
- print ("crossroads-mgr is running (pids @pids)\n");
- } else {
- print ("crossroads-mgr is NOT running\n");
- }
- }
-
- # Return the PID's where the manager is running. NOTE: Class-less.
- sub pids {
- my %ps = (Darwin => 'ps ax',
- linux => 'ps ax',
- Linux => 'ps ax',
- SunOS => 'ps -eo \'pid args\'');
- my $uname = `uname`;
- chomp ($uname);
- die ("Failed to get uname of this system\n") if ($uname eq '');
- die ("No 'ps' command configured for uname '$uname'\n")
- unless ($ps{$uname});
- open (my $if, "$ps{$uname} |")
- or die ("Failed to start '$ps{$uname}'\n");
- my @ret;
- while (my $line = <$if>) {
- next unless ($line =~ /perl/ and $line =~ /crossroads-mgr/);
- my $pid = sprintf ("%d", $line);
- next if ($pid == $$);
- push (@ret, $pid);
- }
- return (@ret);
- }
-
- # Get or set the listening port.
- sub port {
- $_[0]->{port} = $_[1] if ($_[1]);
- return ($_[0]->{port});
- }
-
- # Get or set the listening address.
- sub address {
- $_[0]->{address} = $_[1] if ($_[1]);
- return ($_[0]->{address});
- }
-
- # Issue an error
- sub error {
- my $self = shift;
- if (! $self->{isdaemon}) {
- die (@_, "\n");
- } else {
- $self->sendlog ('ERROR', @_);
- die (@_);
- }
- }
-
- # Return a Crossroads command
- sub call {
- my $self = shift;
- my $ret = $self->{call};
- for my $a (@_) {
- $ret .= " $a";
- }
- $ret .= " 2>&1";
- $self->msg ("External call: [$ret]");
- return ($ret);
- }
-
- # Log a verbose message.
- sub msg {
- my $self = shift;
- return unless ($self->{verbose});
- if (! $self->{isdaemon}) {
- print (@_, "\n");
- } else {
- $self->sendlog ('DEBUG', @_);
- }
- }
-
- # Log a line
- sub sendlog {
- my $self = shift;
- my $type = shift;
- open (my $of, '>>' . $self->{logfile}) or return;
- print $of (scalar (localtime()), ' ', $type, ' ', @_, "\n");
- }
-
- # Get/set verbosity
- sub verbose {
- $_[0]->{verbose} = $_[1] if ($_[1]);
- return ($_[0]->{verbose});
- }
-
- # Get/set foreground mode
- sub foreground {
- $_[0]->{foreground} = $_[1] if ($_[1]);
- return ($_[0]->{foreground});
- }
-
- # Daemonize
- sub daemonize {
- my $self = shift;
- return if ($self->{foreground});
- if (my $pid = fork()) {
- $self->msg ("Daemon is running as pid $pid");
- sleep (2);
- exit (0);
- }
- $self->msg ("Daemonizing.");
- $self->{isdaemon} = 1;
- open (STDIN, "/dev/null")
- or $self->error ("Cannot read /dev/null: $!");
- open (STDOUT, ">/dev/null")
- or $self->error ("Cannot write /dev/null: $!");
- open (STDERR, ">&STDOUT")
- or $self->error ("Cannot dup stdout: $!");
- }
-
- # The XSLT stylesheet
- sub xslt {
- my $self = shift;
- if (! $self->{xsltfile}) {
- $self->msg ("Returning built-in XSLT");
- return ($builtin_xslt);
- } else {
- $self->msg ("Returning contents of ", $self->{xsltfile},
- " as XSLT");
- open (my $if, $self->{xsltfile})
- or die ("Cannot read ", $self->{xsltfile}, ": $!");
- my $ret = '';
- while (my $line = <$if>) {
- $ret .= $line;
- }
- return ($ret);
- }
- }
-}
-
-# Daemon-related stuff
-{
- package Daemon;
- use strict;
-
- # Instantiate a daemon and start serving.
- sub new {
- my $proto = shift;
- my $self = {};
- $self->{request} = '';
- $self->{conn} = '';
- bless ($self, $proto);
- $prog->msg ("HTTP daemon instantiated.");
- return ($self);
- }
-
- sub start {
- my ($self, $port) = @_;
- $prog->msg ("Starting HTTP daemon on port $port");
- my $daemon = HTTP::Daemon->new (LocalPort => $port,
- LocalAddr => $prog->address(),
- ReuseAddr => 1)
- or $prog->error ("Failed to start HTTP daemon. ",
- "Maybe the address is in use?");
- $SIG{CHLD} = \&reaper;
- $prog->daemonize();
- $prog->msg ("Open for business");
- while (1) {
- my ($conn, $peer) = $daemon->accept() or next;
- $prog->msg ("Accepted new connection, spawning handler");
- next if (my $pid = fork());
- $prog->msg ("Handler spawned as pid $$");
- my $req = Request->new();
- eval { $req->serve ($conn); };
- $conn->send_error (500, $@) if ($@);
- exit (0);
- }
- }
-
- # Reaper of stopped child processes. NOTE: Class-less!
- sub reaper {
- my $child;
- while (($child = waitpid (-1, 'WNOHANG')) > 0){
- $prog->msg ("Child process $child stopped with status $?");
- }
- $SIG{CHLD} = \&reaper;
- }
-}
-
-# Request related stuff
-{
- package Request;
- use strict;
-
- sub new {
- my $proto = shift;
- my $self = {};
- bless ($self, $proto);
- return ($self);
- }
-
- # Serve a request.
- sub serve {
- my ($self, $conn) = @_;
-
- # Receive the request.
- $self->receive ($conn);
- }
-
- # Check authentication.
- sub checkauth {
- my ($self, $required, $desc) = @_;
- return (1) if ($required eq '');
- my $h = $self->{request}->header ('Authorization')
- or return ($self->prompt_auth($desc));
- $h =~ s/^\s*Basic\s*//i;
- if ($h eq $required) {
- $prog->msg ("Required authentication '$required' matched");
- return (1);
- }
- $prog->msg ("Required authentication '$required' does not ",
- "match passed '$h'");
- return ($self->prompt_auth($desc));
- }
-
- # Prompt for authentication
- sub prompt_auth {
- my ($self, $desc) = @_;
- $prog->msg ("Prompting for authentication ($desc)");
- my $r = HTTP::Response->new (401, 'Authentication Required');
- $r->header ('WWW-Authenticate' =>
- "Basic realm=\"Crossroads Load Balancer: $desc\"");
- $self->{conn}->send_response ($r);
- return (undef);
- }
-
- # Receive client's request.
- sub receive {
- my ($self, $conn) = @_;
- $self->{conn} = $conn;
- $self->{request} = $conn->get_request()
- or die ("Failed to receive request");
- die ("Bad request, only GET supported")
- if ($self->{request}->method() ne 'GET');
- my $uri = $self->{request}->uri();
- $prog->msg ("Requested URI: ", $uri);
-
- # Take action depending on the URI.
- if ($uri eq '/') {
- $self->act_status ();
- } elsif ($uri eq '/xslt') {
- $self->act_xslt ();
- } elsif ($uri =~ m{^/set/}) {
- $self->act_set($uri);
- } else {
- die ("No action on URI ", $uri, "\n");
- }
- }
-
- # Status setter
- sub act_set {
- my ($self, $uri) = @_;
-
- # The uri is /set/{service}/{backend}/state/{numericalstate} or
- # /set/{service}/{backend}/server/{hostname}/{port}
- # Get the variables, and run crossroads tell.
- $self->checkauth ($prog->authset(), "Status Modification")
- or return;
- my (undef, undef, $service, $backend, $action) = split (/\//, $uri);
- my ($nr, $hostname, $port, $if);
- if ($action eq 'state') {
- (undef, undef, undef, undef, undef, $nr) = split (/\//, $uri);
- $prog->msg ("Setting service $service, backend $backend ",
- "to state $nr");
- open ($if, $prog->call ("tell $service $backend state $nr") . '|')
- or die ("Cannot start crossroads\n");
- } elsif ($action eq 'server') {
- (undef, undef, undef, undef, undef, $hostname, $port) =
- split (/\//, $uri);
- $prog->msg ("Setting service $service, backend $backend ",
- "to address $hostname:$port");
- open ($if, $prog->call ("tell $service $backend " .
- "server $hostname:$port") . '|')
- or die ("Cannot start crossroads\n");
- } else {
- die ("Action '$action' not supported in 'set'\n");
- }
-
- my $resp = '';
- while (<$if>) {
- $resp .= $_;
- }
- close ($if);
- die ("Failed to modify runtime environment: $resp\n")
- if ($resp ne '');
-
- # Runtime environment is updated. Redirect to the overview page.
- $prog->msg ("Redirecting to status overview page");
- my $r = HTTP::Response->new (302, 'Moved Temporarily');
- $r->header ('Location' => '/');
- $r->header ('Cache-Control' => 'no-cache');
- $self->{conn}->send_response ($r);
- }
-
- # Status overview actor
- sub act_status {
- my $self = shift;
-
- $prog->msg ("Serving status overview page");
- $self->checkauth ($prog->authstatus(), "Status Retrieval")
- or return;
- open (my $if, $prog->call ('-x -Xxslt status') . '|')
- or die ("Failed to run status retrieval");
- my $buf = '';
- while (my $line = <$if>) {
- $buf .= $line;
- }
-
- my $r = HTTP::Response->new (200, 'OK');
- $r->header ('Content-Type' => 'text/xml');
- $r->header ('Cache-Control' => 'no-cache');
- $r->content ($buf);
- $self->{conn}->send_response ($r);
- }
-
- # XSLT server
- sub act_xslt {
- my $self = shift;
-
- $prog->msg ("Serving XSLT");
- my $r = HTTP::Response->new (200, 'OK');
- $r->header ('Content-Type' => 'text/xml');
- $r->header ('Cache-Control' => 'no-cache');
- $r->content ($prog->xslt());
- $self->{conn}->send_response ($r);
- }
-}
diff --git a/src/crossroads-mgr/crossroads-mgr.usage b/src/crossroads-mgr/crossroads-mgr.usage
@@ -1,25 +0,0 @@
-This is crossroads-mgr V$VER, a web interface for Crossroads.
-Usage: crossroads-mgr [flags] start PORT (starts on tcp port)
- or: crossroads-msg stop (stops the manager)
- or: crossroads-msg status (shows if it's running)
-
-Controls a mini-webserver to monitor Crossroads.
-Supported flags during 'start' are:
- -a ADDR States the binding address for the monitor. Default is to listen
- to all addresses.
- -b UN:PW Viewing the Crossroads status will be protected using basic
- authentication, UN is the username, PW is the password.
- Use PROMPT to be prompted for the username/password.
- -B UN:PW Modifying back end states will be protected using authentication,
- use PROMPT to be prompted for the username/password.
- -f crossroads-mgr stays in the foreground instead of daemonizing
- (for debugging).
- -l FILE States the log file of the daemon, default is
- /tmp/crossroads-mgr.log.
- -v Verbosity is increased, either to the log file or to stdout
- (in -f mode).
- -x CMD States how crossroads should be invoked, default is 'crossroads'.
- Set to e.g. '/opt/xr/bin/crossroads -c /opt/xr/conf/xr.conf' if
- your Crossroads is in an atypical location and if we should not use
- configuration /etc/crossroads.conf.
- -X XSLT Serves XSLT file, instead of built-in xslt.
diff --git a/src/crossroads-mgr/crossroads-mgr.xslt b/src/crossroads-mgr/crossroads-mgr.xslt
@@ -1,212 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xsl:stylesheet version="1.0"
- xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
-<xsl:output method="html"/>
-
-<xsl:template match="/">
- <html>
- <head>
- <title>Crossroads Status Overview</title>
- <script type="text/javascript">
- function setstate (target, index) {
- document.location = '/set/' + target + '/state/' + index;
- }
- function setaddress (target) {
- var hostname = document.getElementById (target + '/hostname').value;
- var port = document.getElementById (target + '/port').value;
- document.location = '/set/' + target + '/server/' +
- hostname + '/' + port;
- }
- </script>
- <style type="text/css">
- h1 {
- font-family: Verdana,Helvetica;
- font-size: 12pt;
- color: blue;
- }
- body {
- font-family: Verdana,Helvetica;
- font-size: 8pt;
- }
- td {
- font-family: Verdana,Helvetica;
- font-size: 10pt;
- }
- .service { background-color: #ffff33; }
- .backend { background-color: #ffff99; }
- .info { font-size: 8pt; }
- .footer { color: gray; }
- </style>
- </head>
- <body>
- <h1>Crossroads Status Overview</h1>
- <hr/>
- <form>
- <xsl:apply-templates/>
- </form>
- <hr/>
- <div class="footer">
- <i>
- Generated by Crossroads __VER__.
- Visit
- <a href="http://crossroads.e-tunity.com">
- http://crossroads.e-tunity.com
- </a>
- for documentation and downloads. <br/>
- </i>
- </div>
- </body>
- </html>
-</xsl:template>
-
-<xsl:template match="/status">
- <table width="100%">
- <xsl:apply-templates/>
- </table>
-</xsl:template>
-
-<xsl:template match="/status/service">
- <tr>
- <td class="service" valign="top">
- <b> Service <xsl:value-of select="@name"/> </b>
- </td>
- <td class="service" colspan="3">
- <table>
- <tr>
- <td class="service">Total connections:</td>
- <td class="service"><xsl:value-of select="connections"/></td>
- </tr>
- <xsl:if test="backends_available > 0">
- <tr>
- <td class="service">Available back ends:</td>
- <td class="service"><xsl:value-of select="backends_available"/></td>
- </tr>
- </xsl:if>
- <xsl:if test="backends_unavailable > 0">
- <tr>
- <td class="service">Unvailable back ends:</td>
- <td class="service"><xsl:value-of select="backends_unavailable"/></td>
- </tr>
- </xsl:if>
- <xsl:if test="backends_down > 0">
- <tr>
- <td class="service">Down back ends:</td>
- <td class="service"><xsl:value-of select="backends_down"/></td>
- </tr>
- </xsl:if>
- <xsl:if test="backends_waking > 0">
- <tr>
- <td class="service">Waking back ends:</td>
- <td class="service"><xsl:value-of select="backends_waking"/></td>
- </tr>
- </xsl:if>
- <tr>
- <td class="service">Listener process PID:</td>
- <td class="service"><xsl:value-of select="pid"/></td>
- </tr>
- </table>
- </td>
- </tr>
- <xsl:apply-templates/>
- <tr> </tr>
-</xsl:template>
-
-<xsl:template match="/status/service/backend">
- <tr>
- <td width="15%"> </td>
- <td class="backend" width="15%"> Back end </td>
- <td class="backend" width="15%"> <b> <xsl:value-of select="@name"/> </b> </td>
- <td class="backend">
- <select onchange="setstate('{../@name}/{@name}', this.selectedIndex);">
- <xsl:choose>
- <xsl:when test="availability/@id = 0">
- <option value="available" selected="1">available</option>
- </xsl:when>
- <xsl:otherwise>
- <option value="available">available</option>
- </xsl:otherwise>
- </xsl:choose>
- <xsl:choose>
- <xsl:when test="availability/@id = 1">
- <option value="unavailable" selected="1">unavailable</option>
- </xsl:when>
- <xsl:otherwise>
- <option value="unavailable">unavailable</option>
- </xsl:otherwise>
- </xsl:choose>
- <xsl:choose>
- <xsl:when test="availability/@id = 2">
- <option value="down" selected="1">down</option>
- </xsl:when>
- <xsl:otherwise>
- <option value="down">down</option>
- </xsl:otherwise>
- </xsl:choose>
- <xsl:choose>
- <xsl:when test="availability/@id = 3">
- <option value="waking" selected="1">waking</option>
- </xsl:when>
- <xsl:otherwise>
- <option value="waking">waking</option>
- </xsl:otherwise>
- </xsl:choose>
- <xsl:choose>
- <xsl:when test="availability/@id = 4">
- <option value="intermediate" selected="1">intermediate</option>
- </xsl:when>
- <xsl:otherwise>
- <option value="intermediate">intermediate</option>
- </xsl:otherwise>
- </xsl:choose>
- <xsl:choose>
- <xsl:when test="availability/@id = 5">
- <option value="unknown" selected="1">unknown</option>
- </xsl:when>
- <xsl:otherwise>
- <option value="unknown">unknown</option>
- </xsl:otherwise>
- </xsl:choose>
- </select>
- </td>
- </tr>
- <tr>
- <td class="info"/>
- <td class="info"/>
- <td class="info"> Address: </td>
- <td class="info">
- <input name="{../@name}/{@name}/hostname" type="text" class="info"
- id="{../@name}/{@name}/hostname" value="{server}" maxlength="255"/>
- :
- <input name="{../@name}/{@name}/port" type="text" value="{port}"
- id="{../@name}/{@name}/port" size="7" class="info"/>
- <input type="button" class="info" value="Set"
- onclick="setaddress('{../@name}/{@name}');"/>
- </td>
- </tr>
- <tr>
- <td class="info"/>
- <td class="info"/>
- <td class="info"> Connections: </td>
- <td class="info">
- Total <xsl:value-of select="connections"/>
- (<xsl:value-of select="failures"/> failures,
- <xsl:value-of select="clients"/> active)
- </td>
- </tr>
- <tr>
- <td class="info"/>
- <td class="info"/>
- <td class="info"> Usage: </td>
- <td class="info">
- Throughput
- <b><xsl:value-of select="throughput"/></b> in
- <b><xsl:value-of select="duration"/></b>,
- <b><xsl:value-of select="lastaccess"/></b> ago
- </td>
- </tr>
- <xsl:apply-templates/>
-</xsl:template>
-
-<xsl:template match="*"/>
-
-</xsl:stylesheet>
diff --git a/src/crossroads.h b/src/crossroads.h
@@ -1,534 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-/* Actually used commandline size. */
-#ifndef SPT_BUFSIZE
-#define SPT_BUFSIZE DEFAULT_SPT_BUFSIZE
-#endif
-
-/* Includes. */
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <netdb.h>
-#if HAVE_MALLOC_H == 1
-#include <malloc.h>
-#endif
-#include <math.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#if HAVE_STDINT_H == 1
-#include <stdint.h>
-#endif
-#include <string.h>
-#include <syslog.h>
-#include <time.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <sys/file.h>
-#include <sys/ipc.h>
-#include <sys/resource.h>
-#include <sys/sem.h>
-#include <sys/shm.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <sys/times.h>
-#include <sys/types.h>
-
-/* Allocation leak finding (requires 'alf' package) */
-#ifdef ALF
-#include <alf.h>
-#endif
-
-/* flock() macros, incase they aren't present on your system. */
-#ifndef LOCK_SH
-#define LOCK_SH 1
-#endif
-#ifndef LOCK_EX
-#define LOCK_EX 2
-#endif
-#ifndef LOCK_NB
-#define LOCK_NB 4
-#endif
-#ifndef LOCK_UN
-#define LOCK_UN 8
-#endif
-
-/* inet_addr() macros, incase they aren't present on your system. */
-#ifndef INADDR_NONE
-#define INADDR_NONE ((unsigned long) -1)
-#endif
-
-/* Types. */
-
-/* NOTE: Adapt optionsread.c and data.c and parser.y when changing!
- * -------------------------------------------------------------- */
-typedef struct { /* Operating options in daemon */
- int log_activity; /* -a: log TCP timings? */
- unsigned tcp_bufsz; /* -B: TCP buffer size */
- int dns_cachettl; /* -d: DNS cache timeout */
- int log_facility; /* -l: logging facility */
- int shmperm; /* -m: SHM permissions */
- int sloppyportbind; /* -s: sloppy port bindings? */
- int leave_proctitle; /* -p: leave process title? */
- int log_http_activity; /* -h: log HTTP activity? */
-} Options;
-
-typedef struct { /* Symbol table for #define */
- char *symbol;
- char *redef;
-} Symtab;
-
-typedef struct { /* Bison/Flex state given files */
- char *name;
- FILE *file;
- int lineno;
- char *buf;
-} ParserState;
-
-typedef enum { /* Config parsing related */
- cf_portspec,
- cf_backlogspec,
- cf_verbosityspec,
- cf_backendspec,
- cf_serverspec,
- cf_dispatchspec,
- cf_revivespec,
- cf_checkspec,
- cf_shmkeyspec,
- cf_weightspec,
- cf_decayspec,
- cf_onstartspec,
- cf_onfailspec,
- cf_onendspec,
- cf_connectiontimeoutspec,
- cf_maxconnectionsspec,
- cf_typespec,
- cf_inspectionspec,
- cf_dumpspec,
- cf_thruspec,
- cf_httptimingspec,
- cf_bindspec,
- cf_stickycookiespec,
- cf_setclientheaderspec,
- cf_addclientheaderspec,
- cf_appendclientheaderspec,
- cf_setserverheaderspec,
- cf_addserverheaderspec,
- cf_appendserverheaderspec,
- cf_allowfromspec,
- cf_denyfromspec,
- cf_allowfilespec,
- cf_denyfilespec,
- cf_useraccountspec,
- cf_retriesspec,
- cf_statespec,
-} Conftype;
-
-typedef union { /* Integer of string value */
- int ival; /* passed around by the parser */
- char *sval;
-} IntOrString;
-
-typedef struct {
- Conftype cf;
- IntOrString v;
-} Confset;
-
-typedef struct {
- int n;
- Confset *set;
-} Confsets;
-
-typedef enum { /* Dispatching types */
- ds_roundrobin,
- ds_random,
- ds_bysize,
- ds_byduration,
- ds_byorder,
- ds_byconnections,
- ds_byclientip,
- ds_externalhandler
-} Dispatchtype;
-
-typedef enum { /* Service types */
- type_any,
- type_http
-} Servicetype;
-
-typedef enum { /* Backend availability */
- st_available, /* .. all OK */
- st_unavailable, /* .. temporarily unavailable */
- st_down, /* .. permanently unavailable */
- st_waking, /* .. scheduled for wake up */
- st_intermediate, /* .. bogus, for mark_activity() */
- st_unknown /* .. no idea (terminator) */
-} Backendavail;
-#define NR_OF_STATES 6 /* Make sure this matches the above */
- /* possible states! */
-
-typedef struct { /* Backend description */
- char *name; /* .. back end identifier */
- int initial_port; /* .. TCP port */
- char *initial_server; /* .. server name */
- int verbosity; /* .. debugging on/off */
- int weight; /* .. weight in backend selection */
- int decay; /* .. decay in % */
- char *onstart; /* .. system() on success */
- char *onfail; /* .. or on failure */
- char *onend; /* .. or on ending */
- char *dumpfile; /* .. traffic dump file */
- char *thruputfile; /* .. traffic throughput file */
- char *timinglog; /* .. HTTP timings log */
- unsigned maxconnections; /* .. max # of allowed connections */
- char *stickycookie; /* .. cookie selector */
- int retries; /* .. # retries before unavailable */
- char **addclientheader; /* .. client hdrs to ADD */
- int naddclientheader; /* .. table size */
- char **setclientheader; /* .. client hdrs to SET */
- int nsetclientheader; /* .. table size */
- char **appendclientheader; /* .. client hdrs to APPEND */
- int nappendclientheader; /* .. table size */
- char **addserverheader; /* .. server hdrs to ADD */
- int naddserverheader; /* .. table size */
- char **setserverheader; /* .. server hdrs to SET */
- int nsetserverheader; /* .. table size */
- char **appendserverheader; /* .. server hdrs to APPEND */
- int nappendserverheader; /* .. table size */
- Backendavail initial_avail; /* .. initial back end state */
-} Backend;
-
-typedef struct { /* Filtering information: */
- unsigned ip; /* .. IP address (or part of it) */
- unsigned mask; /* .. netmask */
-} IpFilter;
-
-typedef enum { /* HTTP header inspection mode */
- ins_deep, /* .. inspect all headers */
- ins_shallow, /* .. inspect only first */
-} HttpInspection;
-
-/* The configuration in internal representation. When changing, remember
- * to change config_write() and config_read() and config_msg()! */
-typedef struct { /* Service description */
- /* Basic stuff */
- char *name; /* .. service name */
- char *bind; /* .. address to bind to */
- unsigned port; /* .. listening port */
- unsigned verbosity; /* .. message generation */
- Dispatchtype dispatchtype; /* .. backend selection method */
- unsigned dispatchover; /* .. selection over # connections */
- char *dispatchext; /* .. external handler */
- unsigned rev_interval; /* .. dead backend revival interval */
- unsigned check_interval; /* .. backend recheck interval */
- char *check_cmd; /* .. rechecking command */
- unsigned backlog; /* .. # pending TCP connections */
- unsigned shmkey; /* .. key for SysV IPC */
- unsigned connectiontimeout; /* .. # secs for timeout handling */
- unsigned maxconnections; /* .. max # of allowed connections */
- Servicetype type; /* .. type of the service */
- HttpInspection inspection; /* .. header inspection mode */
- char *allowfile; /* .. file with allowed IP filters */
- char *denyfile; /* .. and denied */
- int uid; /* .. UID to assume for system() */
- int gid; /* .. GID to assume for system() */
- /* Deny chain */
- int ndenychain; /* .. size of chain */
- IpFilter *denychain; /* .. chain of denied IP's */
- /* Allow chain */
- int nallowchain; /* .. size of chain */
- IpFilter *allowchain; /* .. chain of allowed IP's */
- /* Back ends */
- int nbackend; /* .. size of backend array */
- Backend *backend; /* .. the back ends */
-} Service;
-
-typedef struct { /* Backend state */
- Backendavail actual_avail; /* .. availability */
- unsigned long totuses; /* .. times hit */
- unsigned long failures; /* .. times failed */
- double nbytes; /* .. transferred bytes */
- unsigned long sessions; /* .. # of http sessions */
- unsigned long avg_nbytes; /* .. averaged over # connections */
- double nsec; /* .. connection durations */
- double avg_nsec; /* .. averaged over # connections */
- unsigned nclients; /* .. active clients */
- unsigned fail; /* .. failures so far */
- unsigned laststamp; /* .. last usage */
- int actual_port; /* .. currently used port */
- char actual_server[FQDN_LENGTH]; /* .. currently used server */
- double last_con_sec; /* .. last connect duration */
-} Backendstate;
-
-typedef struct { /* Service reporting (shmem) */
- int pid; /* .. PID of service daemon */
- int rev_pid; /* .. PID of revival handler */
- unsigned nclients; /* .. active clients */
- int last_backend; /* .. last used back end */
- Backendstate /* .. states of the back ends */
- backendstate[1]; /* .. actual shmem array will be >1 */
-} Servicereport;
-
-typedef enum { /* Stage of the program: */
- stage_main, /* .. commandline */
- stage_waiting, /* .. waiting for connections */
- stage_serving, /* .. servicing a connection */
- stage_retrying /* .. waking up a backend */
-} Programstage; /* Update stagetostring.c when */
- /* modifying! */
-
-typedef struct { /* An HTTP Message */
- char **header; /* Headers table, excluding first */
- int nheader; /* Headers table size */
-} HttpHeader;
-
-typedef enum { /* Time representation format */
- tm_localtime, /* .. local */
- tm_gmtime /* .. UTC */
-} TmType;
-
-typedef enum { /* TCP copying direction */
- dir_client_to_server,
- dir_server_to_client
-} CopyDirection;
-
-typedef enum { /* HTTP version */
- con_unknown,
- con_keepalive,
- con_close
-} HttpConnectionType;
-
-typedef struct { /* Numeric state to string map */
- Backendavail av;
- char *nm;
-} StateStringMap;
-
-typedef struct { /* DNS cache related */
- char *hostname; /* resolved name */
- struct in_addr hostaddr; /* resolved host info entry */
- time_t stamp; /* date of cache entry */
-} DnsCache;
-
-/* Globals. */
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-EXTERN Service *activeservice; /* target service of a daemon */
-EXTERN unsigned char *clbuf; /* client socket input buffer */
-EXTERN int clbufpos, clbufmax; /* .. position & bytes */
-EXTERN char *client_ip; /* connected client */
-EXTERN unsigned client_ip_nr; /* .. and in reversed octets form */
-EXTERN char *config_file; /* config to parse */
-EXTERN int current_backend; /* of a given service */
-EXTERN int daemonized; /* are we forked off yet */
-EXTERN DnsCache dnscache[]; /* DNS cache */
-EXTERN int dns_cachettl; /* TTL of DNS cache entries */
-EXTERN int flag_verbose; /* flag: verbosity */
-EXTERN int gid_org, gid_set; /* original gid, flag: changed? */
-EXTERN int interrupted; /* got a signal? */
-EXTERN char *laststring; /* semantic lexer value */
-EXTERN int listen_sock; /* servicer listening socket */
-EXTERN int logstarted; /* was syslog() called yet? */
-EXTERN int nservice; /* # service descriptions */
-EXTERN Options opt; /* processing options */
-EXTERN int org_argc; /* original argc */
-EXTERN char **org_argv; /* and original argv */
-EXTERN int parser_debug; /* lexer/parser debugging */
-EXTERN ParserState *parserstate; /* parser state */
-EXTERN int nparserstate; /* size of array */
-EXTERN char *program_name; /* fully expanded argv[0] */
-EXTERN Programstage program_stage; /* stage of the program */
-EXTERN int relevant_sigs[]; /* relevant signals */
-EXTERN int reload_allow_deny; /* flag to reload spec files */
-EXTERN int semid; /* semaphore ID */
-EXTERN Service *service; /* service descriptions */
-EXTERN Servicereport *servicereport; /* reporter in shared mem */
-EXTERN unsigned char *srbuf; /* server socket input buffer */
-EXTERN int srbufpos, srbufmax; /* .. position & bytes */
-EXTERN StateStringMap /* state/string map */
- statestringmap[]; /* .. and vv */
-EXTERN Symtab *symtab; /* symbol table of #defines */
-EXTERN int nsymtab; /* table size */
-EXTERN int tabular_status; /* -t: tabular status overview */
-EXTERN int uid_org, uid_set; /* original uid, flag: changed? */
-EXTERN int xml_status; /* -x: XML status overview */
-EXTERN char *xml_xslt; /* -X: XSLT refrence for XML output */
-EXTERN FILE *yyin; /* config file handle */
-EXTERN int yylineno; /* input line number */
-EXTERN char *yyerrmsg; /* parsing error msg */
-EXTERN char *yytext; /* lexical buffer */
-
-/* Functions. To suppress the __attribute__ macro (if you're on a
- * non-gcc compiler), uncomment the following. */
-// #undef __attribute__
-// #define __attribute(x)
-extern void alloc_reporter (Service *active, int first);
-extern char *ansistamp (TmType t, int offset);
-extern int backend_available (int target);
-extern int backend_count(void);
-extern int backend_connect (void);
-extern void check_service (Service s);
-extern void choose_backend (void);
-extern int cmd_restart (int ac, char **av);
-extern int cmd_services (int ac, char **av);
-extern int cmd_status (int ac, char **av);
-extern int cmd_start (int ac, char **av);
-extern int cmd_stop (int ac, char **av);
-extern int cmd_tell (int ac, char **av);
-extern int cmd_configtest (int ac, char **av);
-extern void config_msg (void);
-extern void config_read (int fd);
-extern void config_write (int fd);
-extern void copysockets (int clientsock, int serversock);
-extern void decr_client_count (void);
-extern void dealloc_reporter (Service *s);
-extern struct in_addr *dns (char const *hostname);
-extern void error (char const *fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-extern void expand_program_name (char const *av0);
-extern char *gmtstamp (int offset);
-extern unsigned hashpjw (char const *s);
-extern void http_copy (HttpHeader *h, int src_sock, int dst_sock,
- CopyDirection dir);
-extern void http_error (int clientsock);
-extern void http_header_addheader (HttpHeader *m, char const *hdr);
-extern void http_header_appendheader (HttpHeader *m, char const *hdr);
-extern HttpConnectionType http_header_connectiontype (HttpHeader *h);
-extern void http_header_free (HttpHeader *msg);
-extern int http_header_hascookie (HttpHeader *m, char const *cookie);
-extern double http_header_httpver (HttpHeader *h);
-extern void http_header_removeheader (HttpHeader *h, char const *hdr);
-extern unsigned char const *http_header_val (HttpHeader *h, char const *hdr);
-extern HttpHeader *http_header_new (void);
-extern void http_header_read (HttpHeader *m, int srcsock, CopyDirection dir);
-extern void http_header_setheader (HttpHeader *m, char const *hdr);
-extern void http_header_write (HttpHeader *m, int sock, CopyDirection dir);
-extern void http_log_activity (double start, double end, char const *fmt, ...);
-extern void http_serve (int clientsock);
-extern int http_serversocket (HttpHeader *m, int *is_continuation);
-extern int http_write (int sock, CopyDirection dir, unsigned char const *buf,
- int buflen);
-extern void incr_client_count (void);
-extern int init_sockaddr (struct sockaddr_in *name,
- const char *hostname, int port);
-extern void interrupt (int sig);
-extern int ipf_add_allow (Service *s, char const *val);
-extern int ipf_add_deny (Service *s, char const *val);
-extern int ipf_allowed (void);
-extern int ipf_denied (void);
-extern int ipf_loadfile (char const *fname, IpFilter **chain, int *nchain);
-extern int ipf_match (IpFilter f);
-extern int ipf_parse (char const *val, IpFilter *res);
-extern int is_hex_digit (char ch);
-extern int is_space (char ch);
-extern void limits_msg (void);
-extern void lock_reporter (void);
-extern void log_activity_any (char const *action);
-extern void log_activity_start (void);
-extern void log_activity_end (void);
-extern void log_activity_continuation (void);
-extern int make_socket (int port, char const *ipaddr);
-extern void mark_activity (double nbytes, double nsec, Backendavail newstate);
-extern void msg (char const *fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-extern void msgdumpbuf (unsigned char const *buf, int buflen);
-extern int net_copy (int clientsock, int serversock, int maxbytes,
- unsigned char *buf);
-extern int net_read (int sock, int maxbytes, unsigned char *buf,
- int is_client);
-extern void net_allocbufs (void);
-extern unsigned char *net_buffer (CopyDirection dir, unsigned *sz);
-extern unsigned char *net_bufread (int sock, int maxbytes,
- int *nreadp, int is_client);
-extern int net_write (int sock, unsigned char const *buf, int len,
- int is_client);
-extern void options_read (int fd);
-extern void options_write (int fd);
-extern int parser_close();
-extern char const *parser_filename(void);
-extern void parser_open (char const *name);
-extern int parser_input (char *buf, int max);
-extern void parser_run(void);
-extern void parser_skipchar(void);
-extern void parser_skipline(void);
-extern void runservice (void);
-extern void set_program_title (char const *fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-extern void show_config (void);
-extern char *stage_to_string (Programstage stage);
-extern char *state_to_string (Backendavail avail);
-extern Backendavail string_to_state (char const *str);
-extern char *str_expand_format (char const *h);
-extern char *str_printf (char const *fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-extern char *str_vprintf (char const *fmt, va_list args);
-extern void symtab_end (void);
-extern char const *symtab_lookup (char const *txt);
-extern void symtab_set (char const *symbol);
-extern void symtab_start (char const *symbol);
-extern int sysrun (char const *cmd);
-extern void tcpserve (int sock);
-extern double timeofday(void);
-extern void thruputlog (unsigned char const *buf, int len, CopyDirection dir);
-extern void trafficlog (unsigned char const *buf, int len, CopyDirection dir);
-extern void unlock_reporter (void);
-extern void uid_assume (void);
-extern void uid_restore (void);
-extern void usage (void);
-extern void wakeup_handler (void);
-extern void warning (char const *fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-extern void writelog (int prio, char const *fmt, ...)
- __attribute__ ((format (printf, 2, 3)));
-extern int yyparse (void);
-extern void *xcalloc (unsigned sz);
-extern void *xmalloc (unsigned sz);
-extern void *xrealloc (void *what, unsigned sz);
-extern char *xstrcat (char *what, char const *rest);
-extern char *xstrcatch (char *what, char ch);
-extern char *xstrdup (char const *what);
-
-/* strlcat() if it's missing on this system */
-#if HAVE_STRLCAT == 0
-extern size_t strlcat (char *dst, char const *src, size_t size);
-#endif
-
-/* vsyslog() if it's missing on this system */
-#if HAVE_VSYSLOG == 0
-extern void vsyslog (int fac, char const *fmt, va_list args);
-#endif
-
-/* strcasestr() if it's missing on this system */
-#if HAVE_STRCASESTR == 0
-extern char *strcasestr (char const *big, char const *little);
-#endif
-
-/* setproctitle() if it's missing on this system */
-#if HAVE_SETPROCTITLE == 0
-extern void setproctitle (char const *fmt, ...);
-#endif
-
-/* strupr() if it's missing on this system */
-#if HAVE_STRUPR == 0
-extern char *strupr (char *buf);
-#endif
-
-/* strnstr() if it's missing on this system */
-#if HAVE_STRNSTR == 0
-extern char *strnstr (char const *buf, char const *little, size_t len);
-#endif
-
-/* __progname_full on systems that have it */
-#if HAVE_PROGNAME_FULL == 1
-extern char *__progname_full;
-#endif
-
diff --git a/src/crossroads/Makefile b/src/crossroads/Makefile
@@ -1,29 +0,0 @@
-include $(BASE)/etc/Makefile.def
-include $(BASE)/etc/Makefile.conf
-
-BIN = crossroads
-all:
- BASE=$(BASE) $(MAKE) $(BIN)
-
-dbginstall: all $(BINDIR)/$(BIN)
-
-install: all $(BINDIR)/$(BIN)
- strip $(BINDIR)/$(BIN)
-
-distclean: clean
-clean:
- rm -f *.o $(BIN)
-
-$(BINDIR)/$(BIN): $(BIN)
- cp $(BIN) $(BINDIR)/$(BIN)
-
-main.o: main.c
- $(CC) -c -g -W -Wall $(DEFS) $(PG) main.c
-
-$(BIN): main.o ../lib/libcrossroads.a
- $(CC) $(PG) -o $(BIN) main.o -L$(BASE)/src/lib -lcrossroads \
- $(LIBS) $(EXTRALIBS)
-
-# Extra deps:
-main.o: main.c $(BASE)/src/crossroads.h $(BASE)/etc/Makefile.def
-
diff --git a/src/crossroads/main.c b/src/crossroads/main.c
@@ -1,164 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-typedef struct {
- char *arg; /* cmdline argument */
- int narg; /* required remaining args */
- int needconf; /* configuration file required? */
- int (*handler)(int ac, char **av); /* action handler */
-} Handler;
-
-int main (int argc, char **argv) {
- int o;
- unsigned i;
- int dumpconf = 0;
- char *cp;
- static Handler handler[] = {
- /* Argument Nr.args Needconf Handler function */
- /* -1=no check */
- { "services", 0, 1, cmd_services },
- { "status", -1, 1, cmd_status },
- { "stop", 0, 1, cmd_stop },
- { "start", 0, 1, cmd_start },
- { "restart", 0, 1, cmd_restart },
- { "tell", 4, 1, cmd_tell },
- { "configtest", 0, 1, cmd_configtest },
- };
-
- /* Expand argv[0] to a full program path */
- expand_program_name (argv[0]);
-
- /* Remember original ac/av/ep */
- org_argc = argc;
- org_argv = argv;
- org_argv[0] = program_name;
-
- /* Find the configuration file, relative to this program or as
- * /etc/crossroads.conf.
- */
- config_file = xstrdup (program_name);
- if ( (cp = strstr (config_file, "/bin/")) ) {
- *cp = 0;
- config_file = xstrcat (config_file, "/etc/crossroads.conf");
- } else if ( (cp = strstr (config_file, "/sbin/")) ) {
- *cp = 0;
- config_file = xstrcat (config_file, "/etc/crossroads.conf");
- } else {
- free (config_file);
- config_file = xstrdup ("/etc/crossroads.conf");
- }
- if (access (config_file, R_OK) &&
- strcmp (config_file, "/etc/crossroads.conf")) {
- free (config_file);
- config_file = xstrdup ("/etc/crossroads.conf");
- }
-
- /* Parse the command line.
- * NOTE: When changing the options list, remember to update:
- * - src/lib/usage.txt
- * - doc/main/using.yo
- * - doc/man/crossroads.yo
- */
- while ( (o = getopt (argc, argv, "bB:?c:fhvVal:stCm:xd:X:pP")) > 0 )
- switch (o) {
- case 'a':
- opt.log_activity++;
- break;
- case 'b':
- dumpconf++;
- break;
- case 'B':
- opt.tcp_bufsz = atoi (optarg);
- break;
- case 'c':
- config_file = optarg;
- break;
- case 'd':
- opt.dns_cachettl = atoi (optarg);
- break;
- case 'v':
- flag_verbose++;
- break;
- case 'l':
- opt.log_facility = atoi(optarg);
- break;
- case 'm':
- opt.shmperm = strtol (optarg, 0, 8);
- break;
- case 's':
- opt.sloppyportbind++;
- break;
- case 't':
- tabular_status++;
- break;
- case 'x':
- xml_status++;
- break;
- case 'X':
- xml_xslt = optarg;
- break;
- case 'C':
- show_config();
- exit (0);
- case 'p':
- opt.leave_proctitle++;
- break;
- case 'P':
- parser_debug++;
- break;
- case 'V':
- puts (VER);
- exit (0);
- case '?':
- case 'h':
- default:
- usage ();
- }
-
- /* Request to dump binary configuration? */
- if (dumpconf) {
- msg ("Parsing configuration '%s'", config_file);
- parser_open (config_file);
- parser_run();
- parser_close();
- options_write (1);
- config_write (1);
- exit (0);
- }
-
- /* We need at last one argument: the action */
- if (optind >= argc)
- usage();
-
- /* More sanity checks */
- if (xml_status && tabular_status)
- error ("Flags -t and -x are mutually exclusive");
-
- /* Act on the argument. */
- for (i = 0; i < sizeof(handler) / sizeof(Handler); i++) {
- /* Match the handler action string with argv, and match the
- * required remaining arguments. If they match..
- * scan the configuration (if needed) and GO!
- */
- if (!strcmp (argv[optind], handler[i].arg) &&
- (handler[i].narg == -1 ||
- handler[i].narg == argc - optind - 1)) {
- if (handler[i].needconf) {
- parser_open (config_file);
- parser_run();
- parser_close();
- }
- if (!handler[i].handler (argc - optind, argv + optind + 1))
- error ("'%s' failed", argv[optind]);
- return (0);
- }
- }
-
- usage();
- return (1);
-}
diff --git a/src/lib/Makefile b/src/lib/Makefile
@@ -1,56 +0,0 @@
-include $(BASE)/etc/Makefile.def
-include $(BASE)/etc/Makefile.conf
-
-LIB = libcrossroads.a
-SRC := $(wildcard *.c)
-OBJ := $(patsubst %.c, %.o, $(SRC))
-
-all:
- BASE=$(BASE) $(MAKE) textconv
- BASE=$(BASE) $(MAKE) grammar
- BASE=$(BASE) $(MAKE) $(LIB)
-
-dbginstall: install
-install: all
-
-$(LIB): $(OBJ)
- ar rs $(LIB) $(OBJ)
- ranlib $(LIB)
-
-textconv: usage.h proxyerror.h
-usage.h: usage.txt
- $(BASE)/tools/untab usage.txt
- $(BASE)/tools/e-txt2c USAGETEXT <usage.txt >usage.h
-proxyerror.h: proxyerror.txt
- $(BASE)/tools/untab proxyerror.txt
- $(BASE)/tools/e-txt2c ERRORTEXT <proxyerror.txt >proxyerror.h
-
-grammar: parser.c lexer.c
-lexer.c: lexer.l
- flex -I -o$@ $<
-parser.c: parser.y
- bison -d -o $@ $<
-
-objects: $(OBJ)
-
-
-parser.o: parser.c
- $(CC) $(DEFS) $(PG) -c -g $<
-
-lexer.o: lexer.c
- $(CC) $(DEFS) $(PG) -c -g $<
-
-%.o: %.c
- $(CC) $(DEFS) $(PG) $(ALF) -c -g -W -Wall $<
-
-distclean: clean
-clean:
- rm -f $(OBJ) libcrossroads.a usage.h proxyerror.h
-
-# Extra deps:
-strexpandformat.o: strexpandformat.c $(BASE)/etc/Makefile.def
-showconfig.o: showconfig.c $(BASE)/etc/Makefile.def Makefile
-data.o: data.c $(BASE)/src/crossroads.h
-usage.o: usage.c usage.h
-optionswrite.o: optionswrite.c ../crossroads.h
-optionsread.o: optionsread.c ../crossroads.h
diff --git a/src/lib/allocreporter.c b/src/lib/allocreporter.c
@@ -1,69 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-/* Here's the calculation of the required shm block size. The Servicereport
- * has already one Backendstate in it, so we need to add (n-1) blocks to
- * make block->backendstate a linear array. */
-#define REPORTSIZE(s) \
- sizeof(Servicereport) + ((s)->nbackend - 1) * sizeof(Backendstate)
-
-void alloc_reporter (Service *s, int first) {
- int shmid;
- struct shmid_ds shmbuf;
-
- /* Get an ID to work on, depending on the create mode.
- Get a corresponding semaphore too. */
- msg ("Obtaining reporting memory for service %s (key %d)",
- s->name, s->shmkey);
-
- if (first) {
- /* First time 'round. We're allocating for the first time here.*/
- if ( (shmid = shmget (s->shmkey, REPORTSIZE(s),
- opt.shmperm | IPC_CREAT) ) >= 0)
- msg ("Created new shm at id %d", shmid);
- else
- error ("Cannot create shared memory for service %s (key %d: %s)",
- s->name, s->shmkey, strerror(errno));
-
- /* Make sure that we're the owner of the segment. */
- if (shmctl (shmid, IPC_STAT, &shmbuf) == -1)
- error ("Failed to get status of shared memory: %s",
- strerror(errno));
- shmbuf.shm_perm.uid = getuid();
- shmbuf.shm_perm.gid = getgid();
- if (shmctl (shmid, IPC_SET, &shmbuf) == -1)
- error ("Failed to set status of shared memory: %s",
- strerror(errno));
-
- if ( (semid = semget (s->shmkey, 1, opt.shmperm | IPC_CREAT)) >= 0 )
- msg ("Created new sem at id %d", semid);
- else
- error ("Cannot create semaphore for service %s (key %d: %s)",
- s->name, s->shmkey, strerror(errno));
- } else {
- /* Second time 'round. We're getting a handle on previously
- * created shared memory and semaphores. */
- if ( (shmid = shmget (s->shmkey, REPORTSIZE(s), opt.shmperm) ) >= 0 )
- msg ("Got existing shm at id %d", shmid);
- else
- error ("Cannot get shared memory for service %s, key %d: %s. "
- "Maybe crossroads isn't running, or the configuration "
- "has changed.",
- s->name, s->shmkey, strerror(errno));
- if ( (semid = semget (s->shmkey, 1, opt.shmperm)) >= 0 )
- msg ("Got existing sem at id %d", semid);
- else
- error ("Cannot get semaphore for service %s (key %d: %s)",
- s->name, s->shmkey, strerror(errno));
- }
-
- /* Attach to our memory segment. */
- if ( ((servicereport = shmat (shmid, 0, 0))) == (void *) -1 )
- error ("Cannot attach shared memory for service %s: %s",
- s->name, strerror(errno));
-}
diff --git a/src/lib/ansistamp.c b/src/lib/ansistamp.c
@@ -1,27 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-char *ansistamp (TmType t, int offset) {
- static char buf[80];
- time_t now;
- struct tm *tmp;
-
- time (&now);
- now += offset;
- if (t == tm_localtime)
- tmp = localtime (&now);
- else
- tmp = gmtime (&now);
-
- snprintf (buf, sizeof(buf),
- "%4.4d-%2.2d-%2.2d/%2.2d:%2.2d:%2.2d",
- tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
-
- return (buf);
-}
diff --git a/src/lib/backendavailable.c b/src/lib/backendavailable.c
@@ -1,25 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-int backend_available (int target) {
- /* Backend is available when:
- * (a) The state indicates availability;
- * (b) Either, there is no max to the active connections, or
- * the # of connections is below the max.
- */
- if (servicereport->backendstate[target].actual_avail == st_available &&
- (activeservice->backend[target].maxconnections == 0 ||
- activeservice->backend[target].maxconnections >
- servicereport->backendstate[target].nclients)) {
- msg ("Backend %s is available", activeservice->backend[target].name);
- return (1);
- }
-
- msg ("Bckend %s is unavailable", activeservice->backend[target].name);
- return (0);
-}
diff --git a/src/lib/backendconnect.c b/src/lib/backendconnect.c
@@ -1,114 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-static int timed_out;
-
-static void alarmhandler (int sig) {
- timed_out++;
-}
-
-int backend_connect () {
- int sock;
- struct sockaddr_in servername;
- int val = 1;
- struct timeval con_start, con_end;
-
- /* Create the socket. */
- if ( (sock = socket (PF_INET, SOCK_STREAM, 0)) < 0 ) {
- if (program_stage != stage_retrying) {
- error ("failed to create socket for backend communication: %s",
- strerror(errno));
- } else {
- warning ("failed to create socket for backend communication: %s",
- activeservice->name, strerror(errno));
- return (-1);
- }
- }
-
-#ifdef SO_NOSIGPIPE
- /* Make sure we don't get SIGPIPE's on it. Not supported on all
- * platforms. */
- if (setsockopt (sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val))) {
- warning ("cannot set backend socket options (nosigpipe): %s",
- activeservice->name, strerror(errno));
- close (sock);
- return (-2);
- }
-#endif
-
- /* Assign to back end server address. */
- if (init_sockaddr (
- &servername,
- servicereport->backendstate[current_backend].actual_server,
- servicereport->backendstate[current_backend].actual_port)) {
- /* The hostname is unusable.. */
- warning ("unknown host %s",
- servicereport->backendstate[current_backend].actual_server);
- close (sock);
- mark_activity (0, 0, st_unavailable);
- return (-3);
- }
- if (program_stage != stage_retrying)
- msg ("Network socket to %s:%d created",
- servicereport->backendstate[current_backend].actual_server,
- servicereport->backendstate[current_backend].actual_port);
-
- /* If retrying, delay a bit, unless we're in the wakeup handler. */
- if (program_stage != stage_retrying &&
- servicereport->backendstate[current_backend].fail > 0) {
- msg ("Seen %d retries, waiting a bit",
- servicereport->backendstate[current_backend].fail);
- sleep (RETRY_WAIT);
- }
-
- /* Set up the connect interruption */
- signal (SIGALRM, alarmhandler);
- timed_out = 0;
- alarm (CONNECT_TIMEOUT);
-
- /* Try connecting. Remember the time we try this. */
- gettimeofday (&con_start, 0);
- if (connect (sock, (struct sockaddr *) &servername,
- sizeof(servername)) < 0) {
- /* This backend is unusable.
- * Either connect() has failed (connection refused) or it got
- * interrupted by the SIGALRM, or another signal went off.
- */
- close (sock);
- alarm(0);
- signal (SIGALRM, SIG_DFL);
-
- if (program_stage != stage_retrying) {
- if (timed_out)
- warning (
- "server %s:%d not usable due to timeout",
- servicereport->backendstate[current_backend].actual_server,
- servicereport->backendstate[current_backend].actual_port);
- else
- warning (
- "server %s:%d: cannot connect: %s",
- servicereport->backendstate[current_backend].actual_server,
- servicereport->backendstate[current_backend].actual_port,
- strerror(errno));
- }
- mark_activity (0, 0, st_unavailable);
- return (-3);
- }
- alarm(0);
- signal (SIGALRM, SIG_DFL);
-
- /* Log the last connect time. Store the duration of this connect. */
- gettimeofday (&con_end, 0);
- servicereport->backendstate[current_backend].last_con_sec =
- ( ((double)con_end.tv_sec * 1000000 + con_end.tv_usec) -
- ((double)con_start.tv_sec * 1000000 + con_start.tv_usec) )
- / 1000000;
- servicereport->backendstate[current_backend].laststamp = time(0);
-
- return (sock);
-}
diff --git a/src/lib/backendcount.c b/src/lib/backendcount.c
@@ -1,16 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-int backend_count () {
- int n = 0, i;
-
- for (i = 0; i < activeservice->nbackend; i++)
- if (backend_available(i))
- n++;
- msg ("%d backend(s) available", n);
- return (n);
-}
diff --git a/src/lib/checkservice.c b/src/lib/checkservice.c
@@ -1,83 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void check_service (Service s) {
- int i;
-
- /* Check for port duplicates, bindto duplicates */
- for (i = 0; i < nservice; i++) {
- if (service[i].port == s.port) {
- if (service[i].bind && s.bind &&
- !strcmp(service[i].bind, s.bind))
- error ("Services %s and %s cannot bind to same IP %s and "
- "port %d",
- service[i].name, s.name,
- s.bind, s.port);
- if (!service[i].bind && s.bind)
- error ("Services %s and %s use the same port %d, but "
- "%s does not bind to a specific IP",
- service[i].name, s.name,
- s.port, service[i].name);
- if (service[i].bind && !s.bind)
- error ("Services %s and %s use the same port %d, but "
- "%s does not bind to a specific IP",
- service[i].name, s.name,
- s.port, s.name);
- if (!service[i].bind && !s.bind)
- error ("Services %s and %s use the same port without "
- "binding to an IP",
- service[i].name, s.name);
- }
- }
-
- /* Verify the service description, port */
- if (!s.port)
- error ("Service %s lacks a port",
- s.name);
- if (!s.nbackend)
- error ("Service %s lacks back ends",
- s.name);
- if (s.rev_interval && s.check_interval)
- error ("Service %s has both a revivinginterval and "
- "a checkinterval", s.name);
-
- /* HTTP modification directives only with "type http" */
- if (s.type != type_http) {
- for (i = 0; i < s.nbackend; i++) {
- if (s.backend[i].stickycookie &&
- *s.backend[i].stickycookie)
- error ("Backend %s of service %s: sticky cookies "
- "only allowed in 'type http'",
- s.backend[i].name, s.name);
- if (s.backend[i].naddclientheader)
- error ("Backend %s of service %s: addclientheader "
- "only allowed in 'type http'",
- s.backend[i].name, s.name);
- if (s.backend[i].nsetclientheader)
- error ("Backend %s of service %s: setclientheader "
- "only allowed in 'type http'",
- s.backend[i].name, s.name);
- if (s.backend[i].nappendclientheader)
- error ("Backend %s of service %s: appendclientheader "
- "only allowed in 'type http'",
- s.backend[i].name, s.name);
- if (s.backend[i].naddserverheader)
- error ("Backend %s of service %s: addserverheader "
- "only allowed in 'type http'",
- s.backend[i].name, s.name);
- if (s.backend[i].nsetserverheader)
- error ("Backend %s of service %s: setserverheader "
- "only allowed in 'type http'",
- s.backend[i].name, s.name);
- if (s.backend[i].nappendserverheader)
- error ("Backend %s of service %s: appendserverheader "
- "only allowed in 'type http'",
- s.backend[i].name, s.name);
- }
- }
-}
diff --git a/src/lib/choosebackend.c b/src/lib/choosebackend.c
@@ -1,393 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void choose_backend () {
- int *backends = 0, nbackends = 0, h, i, j, k,
- target_set = 0, flat_weights = 1, *weights = 0, *sel_weights,
- tot_weights, lo_val, hi_val, done;
- double *values = 0, nbest;
- unsigned nclients;
- char *exthandler;
- FILE *f;
- char buf[80];
-# if HAVE_SRANDDEV == 0
- struct timeval tv;
-# endif
-
- /* Check that we're allowed to accept at all. */
- if (activeservice->maxconnections &&
- servicereport->nclients >= activeservice->maxconnections) {
- warning ("max clients %d exceeded", activeservice->maxconnections);
- current_backend = -1;
- return;
- }
-
- /* Incase of dispatching by client IP, check that the back end
- * is up. If it is, take that target. */
- if (activeservice->dispatchtype == ds_byclientip) {
- h = hashpjw (client_ip) % activeservice->nbackend;
- msg ("Client IP %s hashed to back end index %d", client_ip, h);
- if (servicereport->backendstate[h].actual_avail == st_available &&
- (activeservice->backend[h].maxconnections == 0 ||
- activeservice->backend[h].maxconnections >
- servicereport->backendstate[h].nclients)) {
- msg ("Hashed back end %d is acceptable", h);
- current_backend = h;
- return;
- } else
- msg ("Hashed back end %d is not available, redispatching", h);
- }
-
- /* Populate the array of selectable backends. */
- for (i = 0; i < activeservice->nbackend; i++) {
- /* Backend i is a candidate if:
- * (a) it is available, AND
- * (b) there's no max of connections, or the actual nr of connections
- * is below max
- */
- if (servicereport->backendstate[i].actual_avail == st_available &&
- (activeservice->backend[i].maxconnections == 0 ||
- activeservice->backend[i].maxconnections >
- servicereport->backendstate[i].nclients)) {
- msg ("candidate back end: %d (max clients %d, active %d, "
- "state %s)",
- i, activeservice->backend[i].maxconnections,
- servicereport->backendstate[i].nclients,
- state_to_string(servicereport->backendstate[i].actual_avail));
- backends = xrealloc (backends, (nbackends + 1) * sizeof(int) );
- backends[nbackends++] = i;
- }
- }
-
- /* When we don't have any active back ends, then we sleep a bit.
- * Abort choosing a back end, unless there is an external dispatcher -
- * it may overrule our assumptions. */
- if (!nbackends) {
- sleep (RETRY_WAIT);
- if (activeservice->dispatchtype != ds_externalhandler) {
- current_backend = -1;
- warning ("No active backends to select!");
- return;
- }
- }
-
- /* Only one backend? Then it's always the first one, whatever
- * you do. Exception is when we have an external dispatcher. In that
- * case we want to call it, even when there's just one back end.
- * Thanks Nicolas Prochazka for suggesting this. */
- if (nbackends == 1 && activeservice->dispatchtype != ds_externalhandler) {
- current_backend = backends[0];
- servicereport->last_backend = current_backend;
- msg ("only 1 backend to select (%d)", current_backend);
- free (backends);
- return;
- }
-
- /* More than 1 backends available, or external dispatching.
- Make a wise choice. */
- switch (activeservice->dispatchtype) {
-
- case ds_roundrobin:
- /* Find the currently used backend, go one forward. */
- msg ("last roundrobin back end was %d", servicereport->last_backend);
- for (i = 0; i < nbackends; i++)
- if (backends[i] == servicereport->last_backend) {
- i++;
- i %= nbackends;
- current_backend = backends[i];
- servicereport->last_backend = current_backend;
- msg ("next roundrobin back end is %d", current_backend);
- free (backends);
- return;
- }
- /* None found.. try the first one (run to momma). */
- current_backend = backends[0];
- servicereport->last_backend = current_backend;
- msg ("chosen backend (roundrobin, without historical info): %d",
- current_backend);
- free (backends);
- return;
-
- case ds_random:
- /* Re-randomize. */
-# if HAVE_SRANDDEV == 1
- sranddev();
- msg ("randomizer seeded with randdev");
-# else
- gettimeofday (&tv, 0);
- srand ((unsigned) tv.tv_usec);
- msg ("randomizer seeded with %u", (unsigned) tv.tv_usec);
-# endif
-
- /* First of all let's see if all the weights are the same. */
- values = xmalloc (nbackends * sizeof(double));
- weights = xmalloc (nbackends * sizeof(int));
- tot_weights = 0;
- for (i = 0; i < nbackends; i++) {
- values[i] = activeservice->backend[backends[i]].weight;
- if (activeservice->backend[backends[i]].weight != 1)
- flat_weights = 0;
- }
-
- if (! flat_weights) {
- /* Non-flat weight random balancing. Determine the chance
- * to hit a given back end. First we populate the weights array.
- * Eg imagine we have 4 back ends with weights 1,2,3,4. Then
- * ultimately we need to get a selection array of indices:
- * 0000111223, meaning that the chance to hit index 0 is 4/10
- * and so on */
-
- /* First of all we reverse the values vector, to get 4,3,2,1 */
- done = 0;
- while (!done) {
- done = 1;
- lo_val = 9999999;
- hi_val = 0;
- /* Find highest/lowest weights in values vector. */
- for (i = 0; i < nbackends; i++) {
- if (!values[i])
- continue;
- done = 0;
- if (lo_val >= values[i])
- lo_val = values[i];
- if (hi_val <= values[i])
- hi_val = values[i];
- }
-
- if (done)
- break;
-
- /* Stick the values into the duplicate 'weights' array,
- but the other way 'round. */
- for (i = 0; i < nbackends; i++)
- if (values[i] == lo_val)
- weights[i] = hi_val;
- else if (values[i] == hi_val)
- weights[i] = lo_val;
-
- for (i = 0; i < nbackends; i++)
- if (values[i] == lo_val) {
- tot_weights += hi_val;
- values[i] = 0;
- } else if (values[i] == hi_val) {
- tot_weights += lo_val;
- values[i] = 0;
- }
- }
-
- /* The 'weights' vector is now the reverse of 'values'.
- * Create a selection array. */
- sel_weights = xmalloc (tot_weights * sizeof(int));
- k = 0;
- for (i = 0; i < nbackends; i++)
- for (j = 0; j < weights[i]; j++) {
- sel_weights[k] = i;
- k++;
- }
-
- /* Debugging:
- * for (k = 0; k < tot_weights; k++)
- * msg ("random: sel_weight[%d] = %d", k, sel_weights[k]);
- */
-
- /* Select the next random back end. Algorithm is:
- * i = rand() % tot_weights;
- * j = sel_weights[i];
- * k = backends[j];
- * current_backend = k;
- * msg ("i=%d j=%d, k=%d", i, j, k);
- */
- i = rand() % tot_weights;
- current_backend = backends[sel_weights[i]];
- servicereport->last_backend = current_backend;
- free (sel_weights);
- msg ("chosen backend (weighted random): %d at index %d",
- current_backend, i);
- free (backends);
- free (values);
- free (weights);
- return;
- }
-
- /* ELSE: Choose a random one of the availables. */
- current_backend = backends[rand() % nbackends];
- servicereport->last_backend = current_backend;
- msg ("chosen backend (flat-weight random): %d", current_backend);
- free (backends);
- free (values);
- return;
-
- case ds_bysize:
- /* Fill the values */
- values = xmalloc (nbackends * sizeof(double));
- for (i = 0; i < nbackends; i++) {
- /* When dispatch over #-connections is in place, then we
- * compute using the averaged value. However if the averaged
- * value is 0 (not yet computed), we take the true value. */
- if (activeservice->dispatchover &&
- servicereport->backendstate[backends[i]].avg_nbytes)
- values[i] =
- servicereport->backendstate[backends[i]].avg_nbytes *
- activeservice->backend[backends[i]].weight;
- else
- values[i] = servicereport->backendstate[backends[i]].nbytes *
- activeservice->backend[backends[i]].weight;
- msg ("by size weighing backend %d has weight %d, value %u"
- " (bytes=%u, avgbytes=%u)",
- backends[i],
- activeservice->backend[backends[i]].weight,
- (unsigned) values[i],
- (unsigned) servicereport->backendstate[backends[i]].nbytes,
- (unsigned)
- servicereport->backendstate[backends[i]].avg_nbytes);
- }
- /* Get the backend that has transported the least bytes */
- for (i = 0; i < nbackends; i++)
- if (!target_set++ || values[i] < nbest) {
- nbest = values[i];
- current_backend = backends[i];
- servicereport->last_backend = current_backend;
- msg ("by size weighing: best so far is %d (value %g)",
- current_backend, nbest);
- }
- msg ("chosen backend (by size): %d", current_backend);
- free (backends);
- free (values);
- return;
-
- case ds_byduration:
- /* Fill the values */
- values = xmalloc (nbackends * sizeof(double));
- for (i = 0; i < nbackends; i++) {
- /* When dispatch over #-connections is in place, then we
- * compute using the averaged value. However if the averaged
- * value is 0 (not yet computed), we take the true value. */
- if (activeservice->dispatchover &&
- servicereport->backendstate[backends[i]].avg_nsec)
- values[i] =
- servicereport->backendstate[backends[i]].avg_nsec *
- 1000000 *
- activeservice->backend[backends[i]].weight;
- else
- values[i] = servicereport->backendstate[backends[i]].nsec *
- 1000000 *
- activeservice->backend[backends[i]].weight;
- msg ("By duration weighing: backend %d has value %g"
- " (sec=%g, avgsec=%g, weight=%d)",
- backends[i], values[i],
- servicereport->backendstate[backends[i]].nsec,
- servicereport->backendstate[backends[i]].avg_nsec,
- activeservice->backend[backends[i]].weight);
- }
- /* Get the backend that has transported the least connection secs */
- for (i = 0; i < nbackends; i++)
- if (!target_set++ || values[i] < nbest) {
- nbest = values[i];
- current_backend = backends[i];
- servicereport->last_backend = current_backend;
- msg ("by duration weighing: best so far is %d (value %g)",
- current_backend, nbest);
- }
- msg ("chosen backend (by duration): %d", current_backend);
- free (backends);
- free (values);
- return;
-
- case ds_byorder:
- /* Get the first available back end in line. */
- current_backend = backends[0];
- servicereport->last_backend = current_backend;
- msg ("chosen backend (by order): %d", current_backend);
- free (backends);
- return;
-
- case ds_byconnections:
- case ds_byclientip:
- /* Note: this serves byconnections dispatching, plus byclientip
- * when the actual back end has gone down. */
- values = xmalloc (nbackends * sizeof(double));
- for (i = 0; i < nbackends; i++) {
- values[i] =
- servicereport->backendstate[backends[i]].nclients *
- activeservice->backend[backends[i]].weight;
- msg ("by connections weighing: backend %d has value %g",
- backends[i], values[i]);
- }
- /* Find the minimum in the values array. */
- for (i = 0; i < nbackends; i++)
- if (!target_set++ || values[i] < nclients) {
- nclients = values[i];
- current_backend = backends[i];
- servicereport->last_backend = current_backend;
- msg ("by connections weighing: best so far is %d (value %u)",
- current_backend, nclients);
- }
- msg ("chosen backend (by connections): %d", current_backend);
- free (backends);
- free (values);
- return;
-
- case ds_externalhandler:
- /* External handler to be called. Assume selection will fail. */
- current_backend = -1;
- exthandler = str_expand_format (activeservice->dispatchext);
- msg ("calling external handler '%s'", exthandler);
- signal (SIGCHLD, SIG_DFL);
- uid_assume();
- if (! (f = popen (exthandler, "r")) ) {
- warning ("failed to start external handler '%s': %s",
- exthandler, strerror(errno));
- if (nbackends > 0) {
- current_backend = backends[0];
- servicereport->last_backend = current_backend;
- }
-
- uid_restore();
- signal (SIGCHLD, SIG_IGN);
- free (backends);
- free (exthandler);
- return;
- }
- while (1) {
- if (fscanf (f, " %80s ", buf) < 1) {
- msg ("external handler signals end");
- pclose (f);
- uid_restore();
- signal (SIGCHLD, SIG_IGN);
- break;
- }
- msg ("external handler says '%s'", buf);
- for (i = 0; i < activeservice->nbackend; i++) {
- if (!strcmp (buf, activeservice->backend[i].name)) {
- msg ("selecting back end %s due to external handler", buf);
- current_backend = i;
- servicereport->last_backend = current_backend;
- pclose (f);
- uid_restore();
- signal (SIGCHLD, SIG_IGN);
- free (backends);
- free (exthandler);
- return;
- }
- }
- }
- warning ("external handler '%s' didn't reply with a selectable back end",
- exthandler);
- if (nbackends > 0)
- current_backend = backends[0];
- servicereport->last_backend = current_backend;
- free (backends);
- free (exthandler);
- return;
-
- default:
- /* Internal fry.. */
- error ("internal error: unhandled dispatch type %d",
- activeservice->dispatchtype);
- }
-}
diff --git a/src/lib/cmdconfigtest.c b/src/lib/cmdconfigtest.c
@@ -1,12 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-int cmd_configtest (int ac, char **av) {
- /* If we got this far, after reading the config: */
- printf ("Configuration '%s' OK.\n", config_file);
- return (1);
-}
diff --git a/src/lib/cmdrestart.c b/src/lib/cmdrestart.c
@@ -1,22 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-int cmd_restart (int ac, char **av) {
-
- /* First run the 'stop' action. */
- if (!cmd_stop (ac, av))
- error ("Daemon stop failed, restart failure");
-
- sleep (2);
-
- /* Now run 'start' */
- if (!cmd_start (ac, av))
- error ("Daemon start failed, restart failure");
-
- /* All ok.. */
- return (1);
-}
diff --git a/src/lib/cmdservices.c b/src/lib/cmdservices.c
@@ -1,26 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-int cmd_services (int ac, char **av) {
- int i, j;
-
- for (i = 0; i < nservice; i++) {
- printf ("Service %s (on port %d) %d backends\n",
- service[i].name, service[i].port, service[i].nbackend);
- if (service[i].allowfile)
- printf (" Allow file: %s\n", service[i].allowfile);
- if (service[i].denyfile)
- printf (" Deny file: %s\n", service[i].denyfile);
- for (j = 0; j < service[i].nbackend; j++)
- printf (" Backend %s (%s:%d)\n",
- service[i].backend[j].name,
- service[i].backend[j].initial_server,
- service[i].backend[j].initial_port);
- }
- return (1);
-}
diff --git a/src/lib/cmdstart.c b/src/lib/cmdstart.c
@@ -1,36 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-int cmd_start (int ac, char **av) {
- FILE *f;
- char *cmd;
-
- /* Prepare the command to run. When the process title may be modified,
- * reserve space. */
- cmd = xstrdup (BINDIR "/crossroads-daemon");
- if (!opt.leave_proctitle)
- cmd = xstrcat (cmd, " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
-
- /*
- for (i = 1; i < org_argc; i++) {
- cmd = xstrcatch (cmd, ' ');
- cmd = xstrcat (cmd, org_argv[i]);
- }
- msg ("Starting daemon (%s), cmd");
- */
-
- if (! (f = popen (cmd, "w")) )
- error ("Failed to start %s: %s", cmd, strerror(errno));
- options_write (fileno(f));
- config_write (fileno(f));
- if (pclose (f) == -1)
- error ("Crossroads daemon '%s' indicates error", cmd);
-
- return (1);
-}
diff --git a/src/lib/cmdstatus.c b/src/lib/cmdstatus.c
@@ -1,192 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-static char *timestr (double nsec) {
- static char *buf;
- char *tmp;
-
- free (buf);
- buf = 0;
-
- if (nsec > 3600) {
- buf = str_printf ("%uh", (unsigned) (nsec / 3600));
- nsec = fmod (nsec, 3600);
- }
- if (nsec > 60) {
- tmp = str_printf ("%um", (unsigned) (nsec / 60));
- nsec = fmod (nsec, 60);
- buf = xstrcat (buf, tmp);
- free (tmp);
- }
- tmp = str_printf ("%.2fs", nsec);
- if (!strcmp (tmp + strlen(tmp) - 4, ".00s"))
- strcpy (tmp + strlen(tmp) - 4, "s");
- buf = xstrcat (buf, tmp);
- free (tmp);
-
- return (buf);
-}
-
-static char *bytestr (double nbytes) {
- static char *buf;
-
- free (buf);
-
- if (nbytes > (double)1024*1024*1024*1024)
- buf = str_printf ("%.2fTb",
- nbytes / ((double) 1024*1024*1024*1024));
- else if (nbytes > 1024*1024*1024)
- buf = str_printf ("%.2fGb",
- nbytes / ((double) 1024*1024*1024));
- else if (nbytes > 1024*1024)
- buf = str_printf ("%.2fMb",
- nbytes / ((double) 1024*1024));
- else if (nbytes > 1024)
- buf = str_printf ("%.2fKb",
- nbytes / (double) 1024);
- else
- buf = str_printf ("%gb", nbytes);
-
- return (buf);
-}
-
-int cmd_status (int ac, char **av) {
- int i, j, services_shown = 0;
- unsigned sec_ago;
- int state_count[NR_OF_STATES];
-
- if (xml_status) {
- printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
- if (xml_xslt)
- printf ("<?xml-stylesheet type=\"text/xsl\" "
- "href=\"%s\"?>\n", xml_xslt);
- printf ("<status>\n");
- }
-
- for (i = 0; i < nservice; i++) {
- if (ac > 1 && strcmp (service[i].name, av[0]))
- continue;
- if (services_shown++) {
- if (xml_status)
- printf (" </service>\n");
- else
- putchar ('\n');
- }
- alloc_reporter (service + i, 0);
- msg ("Reporting service %s (pid = %d)",
- service[i].name, servicereport->pid);
-
- /* Count the back ends by their state. */
- for (j = 0; j < NR_OF_STATES; j++)
- state_count[j] = 0;
- for (j = 0; j < service[i].nbackend; j++)
- state_count[servicereport->backendstate[j].actual_avail]++;
-
- if (tabular_status)
- printf ("%s ", service[i].name);
- else if (xml_status) {
- printf (" <service id=\"%d\" name=\"%s\">\n"
- " <connections>%d</connections>\n"
- " <lastbackend>%d</lastbackend>\n"
- " <pid>%u</pid>\n",
- i, service[i].name, servicereport->nclients,
- servicereport->last_backend,
- servicereport->pid);
- for (j = 0; j < NR_OF_STATES; j++)
- printf (" <backends_%s>%d</backends_%s>\n",
- state_to_string ( (Backendavail)j ),
- state_count[j],
- state_to_string ( (Backendavail)j ));
- } else
- printf ("Service : %s, %d live connections, "
- "last backend %d, at pid %u\n",
- service[i].name, servicereport->nclients,
- servicereport->last_backend, servicereport->pid);
- for (j = 0; j < service[i].nbackend; j++) {
- if (ac > 2 && strcmp (service[i].backend[j].name, av[1]))
- continue;
- if (! servicereport->backendstate[j].laststamp)
- sec_ago = 0;
- else
- sec_ago = time(0) - servicereport->backendstate[j].laststamp;
- if (tabular_status)
- printf ("%s=%s ", service[i].backend[j].name,
- state_to_string(servicereport->backendstate[j].actual_avail));
- else if (xml_status) {
- printf (" <backend id=\"%d\" name=\"%s\">\n"
- " <availability id=\"%d\">%s</availability>\n"
- " <clients>%u</clients>\n"
- " <failures>%lu</failures>\n"
- " <connections>%lu</connections>\n"
- " <duration sec=\"%g\">%s</duration>\n"
- " <throughput bytes=\"%g\">%s</throughput>\n",
- j, service[i].backend[j].name,
- servicereport->backendstate[j].actual_avail,
- state_to_string(
- servicereport->backendstate[j].actual_avail),
- servicereport->backendstate[j].nclients,
- servicereport->backendstate[j].failures,
- servicereport->backendstate[j].totuses,
- servicereport->backendstate[j].nsec,
- timestr (servicereport->backendstate[j].nsec),
- servicereport->backendstate[j].nbytes,
- bytestr (servicereport->backendstate[j].nbytes));
- printf (" <lastaccess sec=\"%u\">%s</lastaccess>\n"
- " <server>%s</server>\n"
- " <port>%d</port>\n",
- sec_ago, timestr( (double) sec_ago),
- servicereport->backendstate[j].actual_server,
- servicereport->backendstate[j].actual_port);
- if (service[i].type == type_http)
- printf (" <sessions>%lu</sessions>\n",
- servicereport->backendstate[j].sessions);
- printf (" </backend>\n");
- }
- else {
- printf (" Backend %2d : %s is %s, %u live connections\n"
- " Stats : %lu failures out of %lu connections",
- j,
- service[i].backend[j].name,
- state_to_string (
- servicereport->backendstate[j].actual_avail),
- servicereport->backendstate[j].nclients,
- servicereport->backendstate[j].failures,
- servicereport->backendstate[j].totuses);
- if (service[i].type == type_http)
- printf (", %lu sessions,",
- servicereport->backendstate[j].sessions);
- printf ("\n"
- " usage %s, %s",
- timestr (servicereport->backendstate[j].nsec),
- bytestr (servicereport->backendstate[j].nbytes));
- if (service[i].dispatchover)
- printf (", avg %s, %s",
- timestr(servicereport->backendstate[j].avg_nsec),
- bytestr(servicereport->backendstate[j].avg_nbytes));
- printf (", last hit %s ago\n"
- " address %s:%d\n",
- timestr ( (double) sec_ago),
- servicereport->backendstate[j].actual_server,
- servicereport->backendstate[j].actual_port);
- }
- }
-
- if (shmdt (servicereport) < 0)
- error ("Failure releasing reporter memory: %s",
- strerror(errno));
- }
- if (tabular_status)
- putchar ('\n');
- else if (xml_status) {
- if (services_shown)
- printf (" </service>\n");
- printf ("</status>\n");
- }
-
- return (1);
-}
diff --git a/src/lib/cmdstop.c b/src/lib/cmdstop.c
@@ -1,35 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-int cmd_stop (int ac, char **av) {
- int i, result = 0;
-
- for (i = 0; i < nservice; i++) {
- alloc_reporter (service + i, 0);
- msg ("Stopping service %s (daemon pid %d, wakeup handler pid %d)",
- service[i].name, servicereport->pid, servicereport->rev_pid);
- if (kill (servicereport->pid, SIGINT)) {
- warning ("Failed to stop service %s (%s)",
- service[i].name, strerror(errno));
- result++;
- } else if (servicereport->rev_pid &&
- kill (servicereport->rev_pid, SIGINT)) {
- warning ("Failed to stop wakeup handler of service %s (%s)",
- service[i].name, strerror(errno));
- result++;
- }
-
- /* Note: We run the deallocator of shmem here anyway, though the
- * signalled listener does it too.. just to make sure.. We do this
- * only if above kills have succeeded.
- */
- if (!result)
- dealloc_reporter (service + i);
- }
-
- return (1);
-}
diff --git a/src/lib/cmdtell.c b/src/lib/cmdtell.c
@@ -1,73 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-int cmd_tell (int ac, char **av) {
- Service *target_service = 0;
- int target_backend = -1, i;
- Backendavail avail;
- int newstate, port;
- char *hostname, *cp;
-
- /* Locate service */
- for (i = 0; i < nservice; i++)
- if (!strcasecmp (service[i].name, av[0])) {
- target_service = service + i;
- break;
- }
- if (!target_service)
- error ("Service '%s' isn't known. "
- "Maybe the configuration has changed?", av[0]);
-
- /* Locate back end */
- for (i = 0; i < target_service->nbackend; i++)
- if (!strcasecmp (target_service->backend[i].name, av[1])) {
- target_backend = i;
- break;
- }
- if (target_backend == -1)
- error ("Backend '%s' of service '%s' isn't known. "
- "Maybe the configuration has changed?", av[1], av[0]);
-
- /* Let's see what we need to tell the back end of that service. */
- if (!strcmp (av[2], "state")) {
- /* Locate new state: either the direct number, or alpha name */
- if (sscanf (av[3], "%d", &newstate) > 0) {
- avail = (Backendavail) newstate;
- if (avail > st_unknown)
- error ("Bad state number '%s'", av[3]);
- } else if ( (avail = string_to_state (av[3])) == st_unknown )
- error ("Incorrect state '%s'.", av[3]);
-
- /* Got all data. Poke the new state into shared memory. */
- alloc_reporter (target_service, 0);
- servicereport->backendstate[target_backend].actual_avail = avail;
- servicereport->backendstate[target_backend].fail = 0;
- msg ("Marked backend %s of service %s as %s.",
- av[1], av[0], state_to_string (avail));
- } else if (!strcmp (av[2], "server")) {
- /* Get the hostname and port part. */
- hostname = av[3];
- if (! (cp = strchr (hostname, ':')) )
- error ("Bad address '%s' (hostname:port expected)", av[3]);
- *cp = 0;
- if (sscanf (cp + 1, "%d", &port) < 1)
- error ("Bad port part in address");
- /* Got all data. Poke the new state into shared memory. */
- alloc_reporter (target_service, 0);
- strncpy (servicereport->backendstate[target_backend].actual_server,
- hostname, FQDN_LENGTH - 1);
- servicereport->backendstate[target_backend].actual_port = port;
- msg ("Address for backend %s of service %s set to %s:%d.",
- av[1], av[0], hostname, port);
- } else {
- usage();
- }
- /* All done.. success */
- return (1);
-}
-
diff --git a/src/lib/configmsg.c b/src/lib/configmsg.c
@@ -1,144 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-#define MSGSTR(x,y) msg(x ": [%s]", y ? y : "<none>")
-#define MSGUNS(x,y) msg(x ": [%u]", y)
-#define MSGINT(x,y) msg(x ": [%d]", y)
-
-#define BMSGSTR(x,y,z) msg("Backend %d: " y " [%s]", x + 1, z ? z : "<none>")
-#define BMSGINT(x,y,z) msg("Backend %d: " y " [%d]", x + 1, z)
-#define BMSGUNS(x,y,z) msg("Backend %d: " y " [%u]", x + 1, z)
-
-static char *dispatchstr (Dispatchtype t) {
- switch (t) {
- case ds_roundrobin:
- return ("roundrobin");
- case ds_random:
- return ("random");
- case ds_bysize:
- return ("bysize");
- case ds_byduration:
- return ("byduration");
- case ds_byorder:
- return ("byorder");
- case ds_byconnections:
- return ("byconnections");
- case ds_byclientip:
- return ("byclientip");
- case ds_externalhandler:
- return ("externalhandler");
- default:
- return ("*** cannot display ***");
- }
-}
-
-static char *servicestr (Servicetype t) {
- switch (t) {
- case type_any:
- return ("any");
- case type_http:
- return ("http");
- default:
- return ("*** cannot display ***");
- }
-}
-
-static char *inspectionstr (HttpInspection t) {
- switch (t) {
- case ins_deep:
- return ("deep");
- case ins_shallow:
- return ("shallow");
- default:
- return ("*** cannot display ***");
- }
-}
-
-static void headers (int nr, char **hdr, int nhdr, char *desc) {
- int i;
-
- msg ("Backend %d: %d %s header(s)", nr + 1, nhdr, desc);
- for (i = 0; i < nhdr; i++)
- msg ("Backend %d: %s #%d: %s", nr + 1, desc, i + 1, hdr[i]);
-}
-
-void config_msg () {
- int i;
-
- if (!activeservice->verbosity)
- return;
-
- msg ("*** Overview of initial configuration of service '%s' ***",
- activeservice->name);
- MSGSTR ("Bind address", activeservice->bind);
- MSGUNS ("Bind port", activeservice->port);
- MSGUNS ("Verbosity", activeservice->verbosity);
- MSGSTR ("Dispatch type", dispatchstr (activeservice->dispatchtype));
- MSGSTR ("External handler", activeservice->dispatchext);
- MSGUNS ("Reviving interval", activeservice->rev_interval);
- MSGUNS ("Check interval", activeservice->check_interval);
- MSGSTR ("External checker", activeservice->check_cmd);
- MSGUNS ("TCP backlog", activeservice->backlog);
- MSGUNS ("SHM key", activeservice->shmkey);
- MSGUNS ("Connection timeout", activeservice->connectiontimeout);
- MSGUNS ("Max connections", activeservice->maxconnections);
- MSGSTR ("Service type", servicestr (activeservice->type));
- MSGSTR ("HTTP inspection", inspectionstr (activeservice->inspection));
- MSGSTR ("Allow file", activeservice->allowfile);
- MSGSTR ("Deny file", activeservice->denyfile);
- MSGINT ("UID", activeservice->uid);
- MSGINT ("GID", activeservice->gid);
- MSGINT ("Initial deny chain", activeservice->ndenychain);
- for (i = 0; i < activeservice->ndenychain; i++)
- msg ("Deny #%d: %4.4x/%4.4x", i + 1, activeservice->denychain[i].ip,
- activeservice->denychain[i].mask);
- MSGINT ("Initial allow chain", activeservice->nallowchain);
- for (i = 0; i < activeservice->nallowchain; i++)
- msg ("Allow #%d: %4.4x/%4.4x", i + 1, activeservice->allowchain[i].ip,
- activeservice->allowchain[i].mask);
- MSGINT ("Back ends", activeservice->nbackend);
-
- for (i = 0; i < activeservice->nbackend; i++) {
- BMSGSTR (i, "name", activeservice->backend[i].name);
- BMSGINT (i, "port", activeservice->backend[i].initial_port);
- BMSGSTR (i, "server", activeservice->backend[i].initial_server);
- BMSGINT (i, "verbosity", activeservice->backend[i].verbosity);
- BMSGINT (i, "weight", activeservice->backend[i].weight);
- BMSGINT (i, "decay", activeservice->backend[i].decay);
- BMSGSTR (i, "onstart cmd", activeservice->backend[i].onstart);
- BMSGSTR (i, "onfail cmd", activeservice->backend[i].onfail);
- BMSGSTR (i, "onend cmd", activeservice->backend[i].onend);
- BMSGSTR (i, "dumplog", activeservice->backend[i].dumpfile);
- BMSGSTR (i, "thruputlog", activeservice->backend[i].thruputfile);
- BMSGSTR (i, "timinglog", activeservice->backend[i].timinglog);
- BMSGUNS (i, "maxconnections", activeservice->backend[i].maxconnections);
- BMSGSTR (i, "stickycookie", activeservice->backend[i].stickycookie);
- BMSGINT (i, "retries", activeservice->backend[i].retries);
- headers (i, activeservice->backend[i].addclientheader,
- activeservice->backend[i].naddclientheader,
- "addclientheader");
- headers (i, activeservice->backend[i].setclientheader,
- activeservice->backend[i].nsetclientheader,
- "setclientheader");
- headers (i, activeservice->backend[i].appendclientheader,
- activeservice->backend[i].nappendclientheader,
- "appendclientheader");
- headers (i, activeservice->backend[i].addserverheader,
- activeservice->backend[i].naddserverheader,
- "addserverheader");
- headers (i, activeservice->backend[i].setserverheader,
- activeservice->backend[i].nsetserverheader,
- "setserverheader");
- headers (i, activeservice->backend[i].appendserverheader,
- activeservice->backend[i].nappendserverheader,
- "appendserverheader");
- BMSGSTR (i, "availability",
- state_to_string (activeservice->backend[i].initial_avail));
- }
-}
-
diff --git a/src/lib/configread.c b/src/lib/configread.c
@@ -1,164 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-static void rd (int fd, void *buf, unsigned sz) {
- int res;
- int toread = (int) sz;
-
- if ( (res = read (fd, buf, sz)) != toread )
- error ("Failed to fetch %d bytes (%d)", toread, res);
-}
-
-static int rd_int (int fd) {
- int res;
-
- rd (fd, &res, sizeof(int));
- return (res);
-}
-
-static int rd_uns (int fd) {
- unsigned res;
-
- rd (fd, &res, sizeof(unsigned));
- return (res);
-}
-
-static char *rd_str (int fd) {
- char *buf;
- int len;
-
- len = rd_int (fd);
- if (!len)
- return (0);
- if (len > 1024)
- error ("Maximum string length exceeded, attempt for %d", len);
- buf = xcalloc (len + 1);
- rd (fd, buf, len);
- return (buf);
-}
-
-
-void config_read (int fd) {
- int i, j, k;
-
- msg ("Reading binary service definition from fd %d", fd);
-
- nservice = rd_int (fd);
- msg ("Configured services: %d", nservice);
- service = xcalloc (nservice * sizeof(Service));
- for (i = 0; i < nservice; i++) {
- /* Basic stuff */
- service[i].name = rd_str (fd);
- msg (" Scanning service %d (%s)", i + 1, service[i].name);
- service[i].bind = rd_str (fd);
- service[i].port = rd_uns (fd);
- service[i].verbosity = rd_uns (fd);
- service[i].dispatchtype = (Dispatchtype)rd_int (fd);
- service[i].dispatchover = rd_uns (fd);
- service[i].dispatchext = rd_str (fd);
- service[i].rev_interval = rd_uns (fd);
- service[i].check_interval = rd_uns (fd);
- service[i].check_cmd = rd_str (fd);
- service[i].backlog = rd_uns (fd);
- service[i].shmkey = rd_uns (fd);
- service[i].connectiontimeout = rd_uns (fd);
- service[i].maxconnections = rd_uns (fd);
- service[i].type = (Dispatchtype)rd_int (fd);
- service[i].allowfile = rd_str (fd);
- service[i].denyfile = rd_str (fd);
- service[i].uid = rd_int (fd);
- service[i].gid = rd_int (fd);
- service[i].inspection = rd_int (fd);
-
- /* Deny chain */
- service[i].ndenychain = rd_int (fd);
- service[i].denychain = xcalloc (service[i].ndenychain *
- sizeof(IpFilter));
- for (j = 0; j < service[i].ndenychain; j++) {
- service[i].denychain[j].ip = rd_int (fd);
- service[i].denychain[j].mask = rd_int (fd);
- }
-
- /* Allow chain */
- service[i].nallowchain = rd_int (fd);
- service[i].allowchain = xcalloc (service[i].nallowchain *
- sizeof(IpFilter));
- for (j = 0; j < service[i].nallowchain; j++) {
- service[i].allowchain[j].ip = rd_int (fd);
- service[i].allowchain[j].mask = rd_int (fd);
- }
-
- /* Back ends */
- service[i].nbackend = rd_int (fd);
- msg (" Configured back ends: %d", service[i].nbackend);
- service[i].backend = xcalloc (service[i].nbackend *
- sizeof(Backend));
- for (j = 0; j < service[i].nbackend; j++) {
- service[i].backend[j].name = rd_str (fd);
- msg (" Backend %d: %s", j + i, service[i].backend[j].name);
- service[i].backend[j].initial_port = rd_int (fd);
- service[i].backend[j].initial_server = rd_str (fd);
- service[i].backend[j].verbosity = rd_int (fd);
- service[i].backend[j].weight = rd_int (fd);
- service[i].backend[j].decay = rd_int (fd);
- service[i].backend[j].onstart = rd_str (fd);
- service[i].backend[j].onend = rd_str (fd);
- service[i].backend[j].dumpfile = rd_str (fd);
- service[i].backend[j].thruputfile = rd_str (fd);
- service[i].backend[j].timinglog = rd_str (fd);
- service[i].backend[j].maxconnections = rd_uns (fd);
- service[i].backend[j].stickycookie = rd_str (fd);
- service[i].backend[j].retries = rd_int (fd);
- service[i].backend[j].initial_avail = rd_int (fd);
-
- service[i].backend[j].naddclientheader = rd_int (fd);
- service[i].backend[j].addclientheader =
- xcalloc (service[i].backend[j].naddclientheader *
- sizeof(char*));
- for (k = 0; k < service[i].backend[j].naddclientheader; k++)
- service[i].backend[j].addclientheader[k] = rd_str (fd);
-
- service[i].backend[j].nsetclientheader = rd_int (fd);
- service[i].backend[j].setclientheader =
- xcalloc (service[i].backend[j].nsetclientheader *
- sizeof(char*));
- for (k = 0; k < service[i].backend[j].nsetclientheader; k++)
- service[i].backend[j].setclientheader[k] = rd_str (fd);
-
- service[i].backend[j].nappendclientheader = rd_int (fd);
- service[i].backend[j].appendclientheader =
- xcalloc (service[i].backend[j].nappendclientheader *
- sizeof(char*));
- for (k = 0; k < service[i].backend[j].nappendclientheader; k++)
- service[i].backend[j].appendclientheader[k] = rd_str (fd);
-
- service[i].backend[j].naddserverheader = rd_int (fd);
- service[i].backend[j].addserverheader =
- xcalloc (service[i].backend[j].naddserverheader *
- sizeof(char*));
- for (k = 0; k < service[i].backend[j].naddserverheader; k++)
- service[i].backend[j].addserverheader[k] = rd_str (fd);
-
- service[i].backend[j].nsetserverheader = rd_int (fd);
- service[i].backend[j].setserverheader =
- xcalloc (service[i].backend[j].nsetserverheader *
- sizeof(char*));
- for (k = 0; k < service[i].backend[j].nsetserverheader; k++)
- service[i].backend[j].setserverheader[k] = rd_str (fd);
-
- service[i].backend[j].nappendserverheader = rd_int (fd);
- service[i].backend[j].appendserverheader =
- xcalloc (service[i].backend[j].nappendserverheader *
- sizeof(char*));
- for (k = 0; k < service[i].backend[j].nappendserverheader; k++)
- service[i].backend[j].appendserverheader[k] = rd_str (fd);
- }
- }
-
- msg ("Configuration scanned.");
-}
diff --git a/src/lib/configwrite.c b/src/lib/configwrite.c
@@ -1,153 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-/* For debugging, uncomment: */
-#define DEBUG
-
-static void wr (int fd, void const *buf, unsigned len) {
- int res;
- int towrite = (int)len;
-
- if ( (res = write (fd, buf, len)) != towrite )
- error ("Failed to transmit %d bytes (%d)", towrite, res);
-}
-
-static void wr_int (int fd, int x, char const *desc) {
- #ifdef DEBUG
- msg ("Configwrite: int %d (%u bytes), %s", x, (unsigned)sizeof(int), desc);
- #endif
- wr (fd, &x, sizeof(int));
-}
-
-static void wr_uns (int fd, unsigned x, char const *desc) {
- #ifdef DEBUG
- msg ("Configwrite: unsigned %u (%u bytes), %s", x, (unsigned)sizeof(int),
- desc);
- #endif
- wr (fd, &x, sizeof(unsigned));
-}
-
-static void wr_str (int fd, char const *s, char const *desc) {
- if (!s || !*s) {
- #ifdef DEBUG
- msg ("Configwrite: empty string, %s", desc);
- #endif
- wr_int (fd, 0, "zero string length");
- } else {
- #ifdef DEBUG
- msg ("Configwrite: string %s (%u bytes), %s", s, (unsigned)strlen(s),
- desc);
- #endif
- wr_int (fd, strlen(s), "nonzero string length");
- wr (fd, s, strlen(s));
- }
-}
-
-void config_write (int fd) {
- int i, j, k;
-
- msg ("Writing binary service definition to fd %d", fd);
- wr_int (fd, nservice, "number of services");
- for (i = 0; i < nservice; i++) {
- /* Basic stuff */
- wr_str (fd, service[i].name, "servicename");
- wr_str (fd, service[i].bind, "servicebind");
- wr_uns (fd, service[i].port, "serviceport");
- wr_uns (fd, service[i].verbosity, "serviceverbosity");
- wr_int (fd, (int)service[i].dispatchtype, "dispatchtype");
- wr_uns (fd, service[i].dispatchover, "dispatchover");
- wr_str (fd, service[i].dispatchext, "dispatchext");
- wr_uns (fd, service[i].rev_interval, "revivinginterval");
- wr_uns (fd, service[i].check_interval, "checkinterval");
- wr_str (fd, service[i].check_cmd, "checkcommand");
- wr_uns (fd, service[i].backlog, "backlog");
- wr_uns (fd, service[i].shmkey, "shmkey");
- wr_uns (fd, service[i].connectiontimeout, "connectiontimeout");
- wr_uns (fd, service[i].maxconnections, "maxconnections");
- wr_int (fd, (int)service[i].type, "type");
- wr_str (fd, service[i].allowfile, "allowfile");
- wr_str (fd, service[i].denyfile, "denyfile");
- wr_int (fd, service[i].uid, "uid");
- wr_int (fd, service[i].gid, "gid");
- wr_int (fd, service[i].inspection, "inspectiontype");
-
- /* Deny chain */
- wr_int (fd, service[i].ndenychain, "sizeof denychain");
- for (j = 0; j < service[i].ndenychain; j++) {
- wr_uns (fd, service[i].denychain[j].ip, "denied ip");
- wr_uns (fd, service[i].denychain[j].mask, "denied mask");
- }
-
- /* Allow chain */
- wr_int (fd, service[i].nallowchain, "sizeof allowchain");
- for (j = 0; j < service[i].nallowchain; j++) {
- wr_uns (fd, service[i].allowchain[j].ip, "allowed ip");
- wr_uns (fd, service[i].allowchain[j].mask, "allowed mask");
- }
-
- /* Back ends */
- wr_int (fd, service[i].nbackend, "nr of backends");
- for (j = 0; j < service[i].nbackend; j++) {
- wr_str (fd, service[i].backend[j].name, "backend name");
- wr_int (fd, service[i].backend[j].initial_port, "backend port");
- wr_str (fd, service[i].backend[j].initial_server, "backend server");
- wr_int (fd, service[i].backend[j].verbosity, "backend verbosity");
- wr_int (fd, service[i].backend[j].weight, "backend weight");
- wr_int (fd, service[i].backend[j].decay, "backend decay");
- wr_str (fd, service[i].backend[j].onstart, "backend onstart");
- wr_str (fd, service[i].backend[j].onend, "backend onend");
- wr_str (fd, service[i].backend[j].dumpfile, "backend dumpfile");
- wr_str (fd, service[i].backend[j].thruputfile,
- "backend thruputfile");
- wr_str (fd, service[i].backend[j].timinglog, "backend timinglog");
- wr_uns (fd, service[i].backend[j].maxconnections,
- "backend maxcconnections");
- wr_str (fd, service[i].backend[j].stickycookie,
- "backend stickycookie");
- wr_int (fd, service[i].backend[j].retries, "backend retries");
- wr_int (fd, service[i].backend[j].initial_avail,
- "backend availability");
-
- wr_int (fd, service[i].backend[j].naddclientheader,
- "nr of clientheaders to add");
- for (k = 0; k < service[i].backend[j].naddclientheader; k++)
- wr_str (fd, service[i].backend[j].addclientheader[k],
- "client header to add");
-
- wr_int (fd, service[i].backend[j].nsetclientheader,
- "nr of client headers to set");
- for (k = 0; k < service[i].backend[j].nsetclientheader; k++)
- wr_str (fd, service[i].backend[j].setclientheader[k],
- "client header to set");
-
- wr_int (fd, service[i].backend[j].nappendclientheader,
- "nr of client headers to append");
- for (k = 0; k < service[i].backend[j].nappendclientheader; k++)
- wr_str (fd, service[i].backend[j].appendclientheader[k],
- "client header to append");
-
- wr_int (fd, service[i].backend[j].naddserverheader,
- "nr of server headers to add");
- for (k = 0; k < service[i].backend[j].naddserverheader; k++)
- wr_str (fd, service[i].backend[j].addserverheader[k],
- "server header to add");
-
- wr_int (fd, service[i].backend[j].nsetserverheader,
- "nr of server headers to set");
- for (k = 0; k < service[i].backend[j].nsetserverheader; k++)
- wr_str (fd, service[i].backend[j].setserverheader[k],
- "server header to set");
-
- wr_int (fd, service[i].backend[j].nappendserverheader,
- "nr of server headers to append");
- for (k = 0; k < service[i].backend[j].nappendserverheader; k++)
- wr_str (fd, service[i].backend[j].appendserverheader[k],
- "server header to append");
- }
- }
-}
diff --git a/src/lib/copysockets.c b/src/lib/copysockets.c
@@ -1,17 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void copysockets (int clientsock, int serversock) {
- unsigned char *buf = xmalloc (opt.tcp_bufsz);
-
- /* Copy between client and server. Function net_copy() will
- * stop itself when either an error is seen, or when no more
- * data are there.
- * So there isn't even a reason to free(buf). */
- while (1)
- net_copy (clientsock, serversock, opt.tcp_bufsz, buf);
-}
diff --git a/src/lib/data.c b/src/lib/data.c
@@ -1,46 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#define EXTERN
-#include "../crossroads.h"
-
-/* Global data for all Crossroads programs */
-
-Options opt = {
- 0, /* log_activity */
- DEFAULT_TCP_BUFSZ, /* tcp_bufsz */
- DNS_CACHETTL, /* dns_cachettl */
- LOG_DAEMON, /* log_facility */
-
- 0644, /* shmperm */
- 0, /* sloppyportbind */
- 0, /* leave_proctitle */
- 0, /* log_http_activity */
-};
-
-StateStringMap statestringmap[] = {
- { st_available, "available" },
- { st_available, "up" },
- { st_unavailable, "unavailable" },
- { st_down, "down" },
- { st_waking, "waking" },
- { st_intermediate, "intermediate" },
- { st_unknown, "unknown" },
- { st_unknown, 0 }
-};
-
-int relevant_sigs[] = { /* signals relevant to this app */
- SIGHUP, /* either caught or ignored, */
- SIGINT, /* depending on the stage */
- SIGQUIT,
- SIGABRT,
- SIGKILL,
- SIGPIPE,
- SIGTERM,
- 0,
-};
-
-DnsCache dnscache[DNS_CACHESIZE]; /* The DNS cache */
diff --git a/src/lib/deallocreporter.c b/src/lib/deallocreporter.c
@@ -1,39 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void dealloc_reporter (Service *s) {
- int shmid;
-
- msg ("Freeing reporting memory for service %s (key %d)",
- s->name, s->shmkey);
-
- /* Get the shared memory ID. If this fails and we're in stage 0,
- * then ignore the error. The true handler will have already released it.
- */
- if ( (shmid = shmget (s->shmkey, sizeof(Servicereport),
- 0644) ) >= 0) {
- msg ("Got existing shm at id %d", shmid);
- /* Mark to be released. If this fails then warn. */
- if (shmctl (shmid, IPC_RMID, 0) < 0 && program_stage != stage_main)
- warning ("WARNING: Cannot mark shared memory as destructable: %s "
- "Root might need to 'ipcrm -m %d' and "
- "'ipcrm -s %d' to clean up!",
- strerror(errno), shmid, semid);
- if (semctl (semid, 0, IPC_RMID) < 0 && program_stage != stage_main)
- warning ("WARNING: Cannot remove semaphore: %s "
- "Root might need to 'ipcrm -s %d' to clean up!",
- strerror(errno), semid);
- }
- else if (program_stage != stage_main) {
- /* Errno 2 means that the shm block was already removed (by a
- * different listener) Don't warn if that's the case.
- */
- if (errno != 2)
- warning ("Cannot get shared memory for service %s (key %d: %d/%s)",
- s->name, s->shmkey, errno, strerror(errno));
- }
-}
diff --git a/src/lib/decrclientcount.c b/src/lib/decrclientcount.c
@@ -1,43 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void decr_client_count () {
- unsigned totclients = 0;
- int i;
-
- if (program_stage != stage_serving)
- return;
-
- lock_reporter();
-
- for (i = 0; i < activeservice->nbackend; i++)
- totclients += servicereport->backendstate[i].nclients;
- servicereport->nclients = totclients;
- msg ("total active clients now %u", totclients);
-
- /* Warning: Use current_backend as index only if >= 0; it
- * may be -1 when still searching for an HTTP back end */
- if (current_backend >= 0 &&
- servicereport->backendstate[current_backend].nclients > 0)
- servicereport->backendstate[current_backend].nclients--;
-
- unlock_reporter();
-
- if (current_backend >= 0) {
- msg ("extcmd-onend: "
- "current_backend = %d, clients = %d, "
- "totclients = %d, cmd = %s",
- current_backend,
- servicereport->backendstate[current_backend].nclients,
- servicereport->nclients,
- activeservice->backend[current_backend].onend ?
- activeservice->backend[current_backend].onend : "<none>");
-
- sysrun (activeservice->backend[current_backend].onend);
- }
-}
diff --git a/src/lib/dns.c b/src/lib/dns.c
@@ -1,101 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-/* #define DEBUG */
-
-static int noncache_resolve (char const *hostname, struct in_addr *res) {
- struct hostent *hent;
- double tick;
-
- tick = timeofday();
- if (! (hent = gethostbyname(hostname)) )
- return (0);
- *res = *(struct in_addr *)hent->h_addr;
- http_log_activity (tick, 0, "hostname resolved");
- return (1);
-}
-
-struct in_addr *dns (char const *hostname) {
- int i, target = -1;
- time_t now, age, min;
-
- /* No cache TTL? No caching. We use slot 0 for storage of the
- * intermediate result. */
- if (!dns_cachettl) {
- if (noncache_resolve (hostname, &dnscache[0].hostaddr))
- return (&dnscache[0].hostaddr);
- return (0);
- }
-
- /* Current time */
- now = time (0);
-
- #ifdef DEBUG
- if (program_stage != stage_retrying) {
- msg ("dnscache: now %d", now);
- for (i = 0; i < DNS_CACHESIZE; i++)
- msg ("dnscache[%d].hostname: %s, dnscache[%d].stamp: %d",
- i, dnscache[i].hostname, i, (int)dnscache[i].stamp);
- }
- #endif
-
- /* See if we still have the hostname. If so, if the TTL isn't
- * exceeded, return that. */
- for (i = 0; i < DNS_CACHESIZE && dnscache[i].hostname; i++) {
- if (!strcmp (dnscache[i].hostname, hostname)) {
- age = now - dnscache[i].stamp;
- if (age <= dns_cachettl) {
- if (program_stage != stage_retrying)
- msg ("host %s resolved from cache slot %d (age: %d sec)",
- hostname, i, (int)age);
- return (&(dnscache[i].hostaddr));
- } else {
- if (program_stage != stage_retrying)
- msg ("host entry for %s is too old at slot %d "
- "(age: %d sec, ttl %d sec)",
- hostname, i, (int)age,
- dns_cachettl);
- target = i;
- break;
- }
- }
- }
-
- /* We failed to return from cache. If target isn't set yet, set it. */
- if (target == -1) {
- if (i < DNS_CACHESIZE) {
- target = i;
- if (program_stage != stage_retrying)
- msg ("host entry '%s' at slot %d will be added",
- hostname, target);
- } else {
- for (i = 0; i < DNS_CACHESIZE; i++)
- if (i == 0 || dnscache[i].stamp < min) {
- target = i;
- min = dnscache[i].stamp;
-
- }
- if (program_stage != stage_retrying)
- msg ("host entry '%s' at slot %d "
- "will be overwritten",
- hostname, target);
- }
- }
-
- /* Get the name, and stick it in the cache if it's a resolved entry,
- * return the result.*/
- if (noncache_resolve (hostname, &dnscache[i].hostaddr)) {
- free (dnscache[i].hostname);
- dnscache[i].hostname = xstrdup (hostname);
- dnscache[i].stamp = now;
- return (&dnscache[i].hostaddr);
- }
-
- /* Failed, return a NULL ptr. */
- return (0);
-}
diff --git a/src/lib/error.c b/src/lib/error.c
@@ -1,32 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void error (char const *fmt, ...) {
- va_list args;
- char *str;
-
- if (fmt && *fmt) {
- va_start (args, fmt);
- str = str_vprintf (fmt, args);
- if (!daemonized) {
- if (activeservice)
- fprintf (stderr, "ERROR, Service %s: %s\n",
- activeservice->name, str);
- else
- fprintf (stderr, "ERROR: %s\n", str);
- } else {
- if (activeservice)
- writelog (LOG_ERR, "ERROR, Service %s: %s",
- activeservice->name, str);
- else
- writelog (LOG_ERR, "ERROR: %s", str);
- }
- free (str);
- }
- exit (1);
-}
diff --git a/src/lib/expandprogamname.c b/src/lib/expandprogamname.c
@@ -1,30 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void expand_program_name (char const *av0) {
- char *str, *cp, *last = (char*)expand_program_name;
-
- /* If we have path separators, then assume it's already expanded. */
- if (strchr (av0, '/')) {
- program_name = xstrdup (av0);
- return;
- }
-
- /* Try to locate av0 along the PATH */
- str = xstrdup(getenv("PATH"));
- for (cp = strtok_r (str, ":", &last); cp; cp = strtok_r (0, ":", &last)) {
- free (program_name);
- program_name = str_printf ("%s/crossroads", cp);
- if (!access (program_name, R_OK | X_OK))
- return;
- }
-
- /* All PATHs failed. Run back to av0. */
- free (program_name);
- program_name = xstrdup(av0);
-}
diff --git a/src/lib/gmtstamp.c b/src/lib/gmtstamp.c
@@ -1,26 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-char *gmtstamp (int offset) {
- static char buf[80];
- time_t now;
- struct tm *tmp;
- static char *monthname[] = {
- "January", "February", "March", "April",
- "May", "June", "July", "August", "September",
- "October", "November", "December" };
-
- time (&now);
- now += offset;
- tmp = gmtime (&now);
-
- snprintf (buf, sizeof(buf), "%s, %d %4.4d %2.2d:%2.2d:%2.2d",
- monthname[tmp->tm_mon], tmp->tm_mday, tmp->tm_year + 1900,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
- return (buf);
-}
diff --git a/src/lib/hashpjw.c b/src/lib/hashpjw.c
@@ -1,25 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-unsigned hashpjw (char const *str) {
- unsigned h = 0, g;
-
- while (str && *str) {
- h <<= 4;
- h += *str;
- if ( (g = h & 0xf0000000) ) {
- h ^= g >> 24;
- h ^= g;
- }
-
- str++;
- }
-
- return (h);
-}
-
diff --git a/src/lib/httpcopy.c b/src/lib/httpcopy.c
@@ -1,122 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-static void copy (int src, int dst, int dir, int tot) {
- int ncopied = 0, to_copy, bytes;
- unsigned char *buf;
-
- msg ("about to copy %d bytes from %s",
- tot, dir == dir_client_to_server ? "client" : "server");
- msg ("%d bytes in client buffer, %d in server buffer",
- clbufmax ? clbufmax - clbufpos : 0,
- srbufmax ? srbufmax - srbufpos : 0);
-
- while (ncopied < tot) {
- /* Here's how many bytes we should shuttle to and fro.
- * This is the remaining count, or if the buffer is too small
- * for that, the buffer size. */
- to_copy = tot - ncopied;
- if (to_copy > (int)opt.tcp_bufsz)
- to_copy = (int)opt.tcp_bufsz;
-
- buf = net_bufread (src, to_copy, &bytes, dir == dir_client_to_server);
- net_write (dst, buf, bytes, dir == dir_client_to_server);
- ncopied += bytes;
-
- /* msg ("Copied 0x%x (%d) bytes of 0x%x (%d) total",
- ncopied, ncopied, tot, tot);
- */
- }
-}
-
-unsigned getchunk (int sock, int dest, CopyDirection dir) {
- unsigned ret = 0;
- unsigned char *cp;
- char *hexbuf = 0;
- int in_number = 1;
-
- /* We match
- * <hex-chunksize> <any-mush> [\r]\n
- * while copying all to the other socket, and return the
- * chunk size */
- while (1) {
- cp = net_bufread (sock, 1, 0, dir == dir_client_to_server);
- /* msg ("Got character %c (%d) while scanning chunk size",
- *cp, *cp); */
- net_write (dest, cp, 1, dir == dir_client_to_server);
- if (*cp == '\n') {
- sscanf (hexbuf, "%x", &ret);
- free (hexbuf);
- msg ("Chunk size 0x%x (%d)", ret, ret);
- /* If the chunk size is zero, then match final [\r]\n */
- if (ret == 0) {
- cp = net_bufread (sock, 1, 0, dir == dir_client_to_server);
- net_write (dest, cp, 1, dir == dir_client_to_server);
- if (*cp == '\r') {
- cp = net_bufread (sock, 1, 0, dir == dir_client_to_server);
- net_write (dest, cp, 1, dir == dir_client_to_server);
- if (*cp != '\n')
- warning ("Chunks not terminated by \\r\\n "
- "but by \\r <decimal>%d", *cp);
- } else if (*cp != '\n')
- warning ("Chunks not terminated by \r\n or \n "
- "but by <decimal>%d", *cp);
- }
- return (ret);
- }
- if (in_number) {
- if (is_hex_digit (*cp))
- hexbuf = xstrcatch (hexbuf, *cp);
- else
- in_number = 0;
- }
- }
-}
-
-void http_copy (HttpHeader *h, int src, int dst, CopyDirection dir) {
- unsigned char const *mode, *cp;
- unsigned nbytes;
-
- msg ("copying HTTP body from %s",
- dir == dir_client_to_server ?
- "client to server" : "server to client");
-
- /* Check in what 'mode' we are.
- * We know the following modes:
- * - Transfer-Encoding is chunked: we copy chunks
- * - Content-Length is supplied: we copy that # of bytes
- * - None of the above: simply return, the caller http_serve()
- * will enter copy-thru mode
- */
-
- if ( (mode = http_header_val (h, "transfer-encoding")) && *mode ) {
- /* *** CHUNKED TRANSFER ENCODING *** */
- if (strncasecmp ( (char const *) mode, "chunked", 7))
- error ("can't handle transfer-encoding '%s'", mode);
- msg ("copying chunks from %s",
- dir == dir_client_to_server ?
- "client to server" : "server to client");
- while (1) {
- /* See how large the chunk will be. */
- nbytes = getchunk (src, dst, dir);
- msg ("Next chunk is 0x%x (%d) bytes", nbytes, nbytes);
- /* Copy the chunk. Add 2 bytes for the \r\n that follows. */
- copy (src, dst, dir, nbytes + 2);
- /* Last chunksize of 0 signals the end. */
- if (!nbytes)
- break;
- }
- } else if ( (mode = http_header_val (h, "content-length")) && *mode ) {
- /* *** CONTENT-LENGTH PRESENT *** */
- nbytes = atoi ( (char const *) mode );
- msg ("copying %u bytes of content from %s",
- nbytes,
- dir == dir_client_to_server ?
- "client to server" : "server to client");
- copy (src, dst, dir, nbytes);
- }
-}
diff --git a/src/lib/httperror.c b/src/lib/httperror.c
@@ -1,18 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-#include "proxyerror.h"
-
-void http_error (int clientsock) {
- char *buf = str_printf ("HTTP/1.0 502 Internal Server Error\r\n"
- "Content-Length: %u\r\n"
- "\r\n"
- ERRORTEXT,
- (unsigned) strlen(ERRORTEXT));
- write (clientsock, buf, strlen(buf));
- decr_client_count();
- error ("No back end could be selected. Client received error page.");
-}
diff --git a/src/lib/httpheaderaddheader.c b/src/lib/httpheaderaddheader.c
@@ -1,33 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-/* #define DEBUG */
-
-#ifdef DEBUG
-static void debughdr (HttpHeader *h) {
- int i;
- msg ("http header add: %d headers so far", h->nheader);
- for (i = 0; i < h->nheader; i++)
- msg ("http header add: header[%d] '%s'",
- i, h->header[i]);
-}
-
-#define SHOWHEADERS(h) debughdr((h))
-#else
-#define SHOWHEADERS(h)
-#endif
-
-void http_header_addheader (HttpHeader *m, char const *h) {
- char *exp;
-
- exp = str_expand_format (h);
- msg ("adding header '%s'", exp);
- m->header = xrealloc (m->header, (m->nheader + 1) * sizeof(char*));
- m->header[m->nheader++] = exp;
- SHOWHEADERS(m);
-}
diff --git a/src/lib/httpheaderappendheader.c b/src/lib/httpheaderappendheader.c
@@ -1,43 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void http_header_appendheader (HttpHeader *m, char const *h) {
- char *hname, *cp, *exp;
- int i;
-
- hname = xstrdup (h);
- if (! (cp = strchr (hname, ':')) ) {
- free (hname);
- return;
- }
- *cp = 0;
- cp++;
-
- while (is_space (*cp) || *cp == ':')
- cp++;
- exp = str_expand_format (cp);
-
- for (i = 0; i < m->nheader; i++) {
- if (!m->header[i] || !*m->header[i])
- continue;
- /* msg ("Append header: comparing '%s' to '%s'",
- hname, m->header[i]); */
-
- if (!strncasecmp (m->header[i], hname, strlen(hname))) {
- m->header[i] = xstrcat (m->header[i], "; ");
- m->header[i] = xstrcat (m->header[i], exp);
- /* msg ("appending (after existing) header, now '%s'",
- m->header[i]); */
- free (hname);
- return;
- }
- }
-
- /* msg ("appending (setting) header '%s'", h); */
-
- http_header_addheader (m, h);
-}
diff --git a/src/lib/httpheaderconnectiontype.c b/src/lib/httpheaderconnectiontype.c
@@ -1,27 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-HttpConnectionType http_header_connectiontype (HttpHeader *h) {
- unsigned char const *val;
-
- if (! (val = http_header_val (h, "proxy-connection")) )
- val = http_header_val (h, "connection");
-
- if (!val) {
- msg ("Cannot determine connection type, no such header");
- return (con_unknown);
- }
- if (strcasestr ((char const *)val, "close")) {
- msg ("Connection-Type is CLOSE");
- return (con_close);
- } else if (strcasestr ((char const *)val, "keep-alive")) {
- msg ("Connection-Type is KEEP-ALIVE");
- return (con_keepalive);
- }
- warning ("Unsupported Connection-Type '%s'", val);
- return (con_unknown);
-}
diff --git a/src/lib/httpheaderfree.c b/src/lib/httpheaderfree.c
@@ -1,18 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void http_header_free (HttpHeader *m) {
- int i;
-
- if (!m)
- return;
- for (i = 0; i < m->nheader; i++)
- free (m->header[i]);
- m->header = 0;
- m->nheader = 0;
-}
diff --git a/src/lib/httpheaderhascookie.c b/src/lib/httpheaderhascookie.c
@@ -1,32 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-int http_header_hascookie (HttpHeader *m, char const *cookie) {
- unsigned char const *val;
- char *cp, *buf;
-
- if (!cookie || !*cookie)
- return (0);
- if (! (val = http_header_val (m, "cookie")) ) {
- msg ("no cookies in HTTP message");
- return (0);
- }
-
- buf = xstrdup ((char const *) val);
- for (cp = buf; cp && *cp; cp = strchr (cp, ';')) {
- while (*cp == ';' || *cp == ' ')
- cp++;
- if (!strncmp (cp, cookie, strlen (cookie))) {
- msg ("found cookie '%s' in '%s'", cookie, buf);
- free (buf);
- return (1);
- }
- }
- msg ("cookie '%s' not present in '%s'", cookie, buf);
- free (buf);
- return (0);
-}
diff --git a/src/lib/httpheaderhttpver.c b/src/lib/httpheaderhttpver.c
@@ -1,33 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-double http_header_httpver (HttpHeader *h) {
- double ret;
-
- /* We need at least a header line */
- if (h->nheader < 1) {
- warning ("cannot get HTTP version, no headers");
- return (0.9);
- }
-
- /* We need HTTP/1.? length */
- if (strlen (h->header[0]) < 8) {
- warning ("cannot get HTTP version, header line '%s'", h->header[0]);
- return (0.9);
- }
-
- /* If the line starts with HTTP then it's a server line.
- * Otherwise it's a client line. */
- if (!strncmp (h->header[0], "HTTP/", 5))
- ret = atof (h->header[0] + 5);
- else
- ret = atof (h->header[0] + strlen(h->header[0]) - 3);
-
- msg ("HTTP version is %g (headerline %s)", ret, h->header[0]);
- return (ret);
-}
-
diff --git a/src/lib/httpheadernew.c b/src/lib/httpheadernew.c
@@ -1,16 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-HttpHeader *http_header_new () {
- HttpHeader *ret;
-
- /* Alloc & zero out */
- ret = xmalloc (sizeof (HttpHeader));
- memset (ret, 0, sizeof(HttpHeader));
-
- return (ret);
-}
diff --git a/src/lib/httpheaderread.c b/src/lib/httpheaderread.c
@@ -1,119 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-/* For more debugging information, undefine the following and set
- * "verbosity on" in the configuration file. */
-/* #define DEBUG */
-
-#ifdef DEBUG
-
-static void debughdr (HttpHeader *h) {
- int i;
- msg ("http_header_read: %d headers so far", h->nheader);
- for (i = 0; i < h->nheader; i++)
- msg ("http header read: header[%d] '%s'",
- i, h->header[i]);
-}
-
-#define SHOWHEADERS(h) debughdr((h))
-#define MSG(m) m;
-
-#else
-
-#define SHOWHEADERS(h)
-#define MSG(m)
-
-#endif
-
-void http_header_read (HttpHeader *h, int sock, CopyDirection dir) {
- unsigned char *hdrbuf = 0, *start, *buf, *cp;
- int hdrbuflen = 0, usedlen, *bufpos, *bufmax, i;
-
- msg ("reading HTTP headers from %s",
- dir == dir_client_to_server ? "client" : "server");
-
- /* Read from network until we match [\r]\n[\r]\n */
- if (dir == dir_client_to_server) {
- buf = clbuf;
- bufpos = &clbufpos;
- bufmax = &clbufmax;
- } else {
- buf = srbuf;
- bufpos = &srbufpos;
- bufmax = &srbufmax;
- }
- while (1) {
- if (! *bufmax) {
- *bufmax = net_read (sock, opt.tcp_bufsz, buf,
- dir == dir_client_to_server);
- MSG(msg("Got %d network bytes (%s)", *bufmax, buf));
- }
- hdrbuf = xrealloc (hdrbuf, hdrbuflen + *bufmax);
- memcpy (hdrbuf + hdrbuflen, buf + *bufpos, *bufmax);
- hdrbuflen += *bufmax;
- MSG(msg("Headers buffer so far: %d bytes (%s)", hdrbuflen, hdrbuf));
-
- *bufmax = 0;
-
- /* Try to find header ending sequence */
- if ( (cp = strnstr ((char const *)hdrbuf, "\r\n\r\n",
- (unsigned)hdrbuflen)) ||
- (cp = strnstr ((char const *)hdrbuf, "\n\n",
- (unsigned)hdrbuflen)) ) {
- break;
- }
- }
-
- MSG(msg("Headers done, end at %s", cp));
-
- /* Skip over the ending sequence and save remainder of buffer
- * for next usage */
- for (i = 0; i < 2; i++) {
- if (*cp == '\r')
- cp++;
- if (*cp == '\n')
- cp++;
- }
- usedlen = cp - hdrbuf;
- if (usedlen < hdrbuflen) {
- /* NOTE: We can always poke back the remainder, this is by definition
- * not longer than opt.tcp_bufsize */
- memcpy (buf, cp, hdrbuflen - usedlen);
- *bufpos = 0;
- *bufmax = hdrbuflen - usedlen;
- MSG(msg("Pushed back %d bytes (%s)", *bufmax, buf));
- } else {
- *bufmax = 0;
- MSG(msg("No remainding network for next read"));
- }
-
- /* Split up the header buffer into separate headers and store them */
- start = hdrbuf;
- while (1) {
- if (! (cp = memchr (start, '\r', usedlen - (start - hdrbuf))) )
- cp = memchr (start, '\n', usedlen - (start - hdrbuf));
- if (!cp)
- break;
- MSG(msg("Header %d: (%d bytes) at %s", h->nheader + 1,
- cp - start, start));
- if (cp - start) {
- h->header = xrealloc (h->header, (h->nheader + 1) * sizeof(char*));
- h->header[h->nheader] = xmalloc (cp - start + 1);
- memcpy (h->header[h->nheader], start, cp - start);
- h->header[h->nheader][cp - start] = 0;
- h->nheader++;
- }
- start = cp + 1;
- if (*start == '\n')
- start++;
- }
-
- free (hdrbuf);
-
- SHOWHEADERS(h);
-}
diff --git a/src/lib/httpheaderremoveheader.c b/src/lib/httpheaderremoveheader.c
@@ -1,21 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void http_header_removeheader (HttpHeader *h, char const *hdr) {
- int i;
- char *cp;
-
- for (i = 0; i < h->nheader; i++)
- if (h->header[i] && !strncasecmp (h->header[i], hdr, strlen(hdr))) {
- cp = h->header[i] + strlen(hdr);
- if (*cp == ':') {
- msg ("removing header '%s'", hdr);
- free (h->header[i]);
- h->header[i] = 0;
- }
- }
-}
diff --git a/src/lib/httpheadersetheader.c b/src/lib/httpheadersetheader.c
@@ -1,36 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void http_header_setheader (HttpHeader *m, char const *h) {
- int i;
- char *hname, *cp, *exp;
-
- hname = xstrdup (h);
- if (! (cp = strchr (hname, ':')) ) {
- free (hname);
- return;
- }
- *cp = 0;
-
- exp = str_expand_format (h);
- for (i = 0; i < m->nheader; i++) {
- if (!m->header[i] || !*m->header[i])
- continue;
- if (!strncasecmp (m->header[i], hname, strlen(hname))) {
- free (m->header[i]);
- msg ("setting (replacing) header '%s'", exp);
- m->header[i] = exp;
- free (hname);
- return;
- }
- }
-
- msg ("setting (adding) header '%s'", exp);
- m->header = xrealloc (m->header, (m->nheader + 1) * sizeof(char*));
- m->header[m->nheader++] = exp;
- free (hname);
-}
diff --git a/src/lib/httpheaderval.c b/src/lib/httpheaderval.c
@@ -1,27 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-unsigned char const *http_header_val (HttpHeader *m, char const *what) {
- unsigned char const *ret;
-
- int i;
-
- for (i = 0; i < m->nheader; i++) {
- /* msg ("Scanning header %s for %s", m->header[i], what); */
- if (m->header[i] && !strncasecmp (m->header[i], what, strlen(what))) {
- ret = (unsigned char const *) m->header[i] + strlen(what);
- if (*ret == ':') {
- ret++;
- while (is_space (*ret))
- ret++;
- return (ret);
- }
- }
- }
-
- return (0);
-}
diff --git a/src/lib/httpheaderwrite.c b/src/lib/httpheaderwrite.c
@@ -1,27 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void http_header_write (HttpHeader *m, int sock, CopyDirection dir) {
- int i;
-
- msg ("Sending %d HTTP headers to %s",
- m->nheader,
- dir == dir_server_to_client ? "client" : "server");
-
- for (i = 0; i < m->nheader; i++) {
- if (! m->header[i] || ! *m->header[i])
- continue;
- /*
- msg ("sending header %d: '%s'",
- i, m->header[i]);
- */
- http_write (sock, dir, (unsigned char const *) m->header[i],
- strlen(m->header[i]));
- http_write (sock, dir, (unsigned char const *) "\r\n", 2);
- }
- http_write (sock, dir, (unsigned char const *) "\r\n", 2);
-}
diff --git a/src/lib/httpinsertheader.c b/src/lib/httpinsertheader.c
@@ -1,55 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void http_insert_header (unsigned char **bufp, unsigned *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/lib/httplogactivity.c b/src/lib/httplogactivity.c
@@ -1,49 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void http_log_activity (double start, double now, char const *fmt, ...) {
- FILE *f;
- va_list args;
-
- if (activeservice->type != type_http || program_stage == stage_retrying ||
- current_backend < 0 ||
- !activeservice->backend[current_backend].timinglog ||
- ! *activeservice->backend[current_backend].timinglog)
- return;
-
- if (!now)
- now = timeofday();
- if (! (f = fopen (activeservice->backend[current_backend].timinglog,
- "a")) &&
- ! (f = fopen (activeservice->backend[current_backend].timinglog,
- "w")) ) {
- warning ("cannot write HTTP timings log %s: %s",
- activeservice->backend[current_backend].timinglog,
- strerror(errno));
- return;
- }
-
-#if HAVE_FLOCK == 1
- flock (fileno(f), LOCK_EX);
-#elif HAVE_LOCKF == 1
- lockf (fileno(f), F_LOCK, 0);
-#endif
-
- fprintf (f, "%7.7d %15f ", getpid(), now - start);
- va_start (args, fmt);
- vfprintf (f, fmt, args);
- fputc ('\n', f);
-
-#if defined HAVE_FLOCK
- flock (fileno(f), LOCK_UN);
-#elif defined HAVE_LOCKF
- lockf (fileno(f), F_ULOCK, 0);
-#endif
-
- fclose (f);
-}
diff --git a/src/lib/httpserve.c b/src/lib/httpserve.c
@@ -1,228 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void http_serve (int clientsock) {
- int serversock = -1, is_continuation, i;
- HttpHeader *clientreq, *serverresp;
- int client_persisting, server_persisting;
- double cl_header_start, cl_header_end,
- con_start, con_end, start, tcptotal, tick;
-
- /* Set relevant sigs etc. */
- program_stage = stage_serving;
- for (i = 0; relevant_sigs[i]; i++)
- signal (relevant_sigs[i], interrupt);
-
- set_program_title ("crossroads - Service %s: serving %s",
- activeservice->name, client_ip);
-
- /* We're the child branch now of fork_tcp_servicer().
- * Here's the logic of the HTTP services.
- * - Get the client's request;
- * - If we're not yet connected to a back end: determine the back
- * end and connect to it
- * - Apply all server-directed headers
- * - Send client's request to the server
- * - Read back the server's response
- * - Apply all client-directed headers
- * - Send the server's response to the client
- * - Redo from start; this might be a Keep-Alive connection.
- * Alternatively, if deep inspection is off, go to cpio-thru mode.
- */
-
- net_allocbufs();
- while (1) {
- start = timeofday();
- tcptotal = 0;
- /* Reset network IO buffers. */
- clbufpos = clbufmax = srbufpos = srbufmax = 0;
-
- /* Assume both client and server want to persist. */
- client_persisting = server_persisting = 1;
-
- /* Get the initial client headers. We store the times but do
- * not log yet, that can be done once we assign a back end. */
- clientreq = http_header_new();
- cl_header_start = timeofday();
- http_header_read (clientreq, clientsock, dir_client_to_server);
- cl_header_end = timeofday();
- tcptotal += (cl_header_end - cl_header_start);
-
- /* Determine the back end if necessary. */
- if (serversock == -1) {
- con_start = timeofday();
- if ( (serversock = http_serversocket (clientreq,
- &is_continuation)) < 1 )
- http_error (clientsock);
- con_end = timeofday();
- http_log_activity (cl_header_start, cl_header_end,
- "client headers received");
- http_log_activity (con_start, con_end, "connected to backend");
- tcptotal += (con_end - con_start);
- flag_verbose = activeservice->backend[current_backend].verbosity;
-
- incr_client_count();
- if (is_continuation)
- log_activity_continuation();
- else
- log_activity_start ();
- }
-
- /* Put all server-directed headers in place. */
- for (i = 0;
- i < activeservice->backend[current_backend].naddserverheader;
- i++)
- http_header_addheader (clientreq,
- activeservice->backend[current_backend].addserverheader[i]);
- for (i = 0;
- i < activeservice->backend[current_backend].nsetserverheader;
- i++)
- http_header_setheader (clientreq,
- activeservice->backend[current_backend].setserverheader[i]);
- for (i = 0;
- i < activeservice->backend[current_backend].nappendserverheader;
- i++)
- http_header_appendheader (clientreq,
- activeservice->backend[current_backend].appendserverheader[i]);
-
- /* See RFC2616. We're actually a proxy here. Clients that talk
- * HTTP/1.0 MUST be treated as single shot connection clients, even
- * when they specify Connection: Keep-Alive. */
- if (http_header_httpver (clientreq) < 1.1) {
- msg ("Client talks HTTP < 1.1, forcing closing connections");
- http_header_setheader (clientreq, "Connection: close");
- http_header_setheader (clientreq, "Proxy-Connection: close");
- client_persisting = 0;
- } else if (http_header_connectiontype (clientreq) == con_close) {
- msg ("Client asks for connection closing");
- client_persisting = 0;
- }
-
- /* Send client's headers to the back end. */
- tick = timeofday();
- http_header_write (clientreq, serversock, dir_client_to_server);
- tcptotal += timeofday() - tick;
- http_log_activity (tick, 0, "sent clientheaders to backend");
-
- /* Copy body from client to server */
- tick = timeofday();
- http_copy (clientreq, clientsock, serversock, dir_client_to_server);
- tcptotal += timeofday() - tick;
- http_log_activity (tick, 0, "sent clientbody to backend");
-
- /* Get server response. */
- serverresp = http_header_new();
- tick = timeofday();
- http_header_read (serverresp, serversock, dir_server_to_client);
- tcptotal += timeofday() - tick;
- http_log_activity (tick, 0, "received headers from backend");
-
- /* Put client-directed headers in place. */
- for (i = 0;
- i < activeservice->backend[current_backend].naddclientheader;
- i++)
- http_header_addheader (serverresp,
- activeservice->backend[current_backend].addclientheader[i]);
- for (i = 0;
- i < activeservice->backend[current_backend].nsetclientheader;
- i++)
- http_header_setheader (serverresp,
- activeservice->backend[current_backend].setclientheader[i]);
- for (i = 0;
- i < activeservice->backend[current_backend].nappendclientheader;
- i++)
- http_header_appendheader (serverresp,
- activeservice->backend[current_backend].appendclientheader[i]);
-
- /* According to RFC1616, we should convert chunked output from
- * the server to one big message. We won't do that here, it breaks
- * streaming. But we will close connections in the case of chunked
- * transfer. */
- if (client_persisting &&
- http_header_val (serverresp, "transfer-encoding")) {
- msg ("Server is sending chunks, forcing singleshot");
- server_persisting = 0;
- client_persisting = 0;
- http_header_setheader (serverresp, "Connection: close");
- http_header_setheader (serverresp, "Proxy-Connection: close");
- }
-
- /* If the server wants to close the connection, then we must
- * inform the client. */
- if (client_persisting) {
- if (http_header_httpver (serverresp) < 1.1) {
- msg ("Server talks HTTP < 1.1, forcing closing connections");
- http_header_setheader (serverresp, "Connection: close");
- http_header_setheader (serverresp, "Proxy-Connection: close");
- server_persisting = 0;
- } else if (http_header_connectiontype (serverresp) == con_close) {
- msg ("Server asks for connection closing");
- http_header_setheader (serverresp, "Connection: close");
- http_header_setheader (serverresp, "Proxy-Connection: close");
- server_persisting = 0;
- }
- }
-
- /* Send server headers to the client. */
- tick = timeofday();
- http_header_write (serverresp, clientsock, dir_server_to_client);
- tcptotal += timeofday() - tick;
- http_log_activity (tick, 0, "sent serverheaders to client");
-
- /* Copy body from server to client and flush network buffers if any */
- tick = timeofday();
- http_copy (serverresp, serversock, clientsock, dir_server_to_client);
- tcptotal += timeofday() - tick;
- http_log_activity (tick, 0, "sent serverbody to client");
-
- /* Free up info from this request/response chat. */
- http_header_free (clientreq);
- http_header_free (serverresp);
-
- /* Overall activity reporting */
- http_log_activity (start, 0, "total processing (%g in TCP)", tcptotal);
-
- /* Should we loop around? Go to copy-thru mode if either the
- * client or the server wants to stop. */
- if (!client_persisting || !server_persisting) {
- msg ("non-persistent connection");
- break;
- }
-
- if (activeservice->inspection == ins_deep)
- msg ("Will analyze following requests over the same TCP link");
- else {
- msg ("Shallow analysis - won't analyze following "
- "requests of the same TCP link");
- break;
- }
- }
-
- /* We're done analyzing. If there's leftovers in the network buffers,
- * then we flush them first. */
- if (clbufmax) {
- msg ("Flushing client-side buffer to server, %u bytes",
- clbufmax - clbufpos);
- http_write (serversock, dir_client_to_server,
- clbuf + clbufpos, clbufmax - clbufpos);
- clbufmax = clbufpos = 0;
- }
- if (srbufmax) {
- msg ("Flushing server-side buffer to client, %u bytes",
- srbufmax - srbufpos);
- http_write (clientsock, dir_server_to_client,
- srbuf + srbufpos, srbufmax - srbufpos);
- srbufmax = srbufpos = 0;
- }
-
- /* Copy through all that arrives on back end or client.
- * This doesn't return... */
- msg ("HTTP service done analyzing, entering copy-thru mode");
-
- /* This doesn't return */
- copysockets (clientsock, serversock);
-}
diff --git a/src/lib/httpserversocket.c b/src/lib/httpserversocket.c
@@ -1,72 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-int http_serversocket (HttpHeader *m, int *is_continuation) {
- int i, sock;
-
- msg ("searching for back end for HTTP request");
-
- /* Try to find a sticky cookie in the request. */
- for (i = 0; i < activeservice->nbackend; i++) {
- if (servicereport->backendstate[i].actual_avail == st_unavailable)
- continue;
- if (activeservice->backend[i].maxconnections > 0 &&
- activeservice->backend[i].maxconnections <=
- servicereport->backendstate[i].nclients)
- continue;
- if (http_header_hascookie (m,
- activeservice->backend[i].stickycookie)) {
- msg ("HTTP backend %d selected due to cookie '%s'",
- i,
- activeservice->backend[i].stickycookie);
-
- /* Got the target back end. Try to connect to it.
- * If it doesn't succeed, then we'll do a failover to
- * any other back end. */
- current_backend = i;
- if ( (sock = backend_connect ()) >= 0 ) {
- *is_continuation = 1;
- set_program_title ("crossroads - Service %s: "
- "serving %s to %s",
- activeservice->name,
- client_ip,
- activeservice->backend[current_backend].name);
- return (sock);
- }
- }
- }
-
- /* We got here because this is the first time 'round or because
- * a previously established back end went dead in the middle of a
- * session. So: Loop 'till we find a back end, or until we fail. */
- while (1) {
- /* No back end? Nogo. */
- if (! backend_count()) {
- msg ("out of back ends while scanning for HTTP back end");
- return (-1);
- }
-
- /* Try one. */
- choose_backend();
- if (current_backend < 0) {
- warning ("No back end for request.");
- return (-2);
- }
-
- msg ("trying back end %s for new HTTP connection",
- activeservice->backend[current_backend].name);
- if ( (sock = backend_connect ()) >= 0 ) {
- servicereport->backendstate[current_backend].sessions++;
- *is_continuation = 0;
- set_program_title ("crossroads - Service %s: serving %s to %s",
- activeservice->name,
- client_ip,
- activeservice->backend[current_backend].name);
- return (sock);
- }
- }
-}
diff --git a/src/lib/httpwrite.c b/src/lib/httpwrite.c
@@ -1,18 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-int http_write (int sock, CopyDirection dir, unsigned char const *buf,
- int buflen) {
- int nwritten, totwritten = 0;
-
- while (totwritten < buflen) {
- nwritten = net_write (sock, buf + totwritten, buflen - totwritten,
- dir == dir_client_to_server);
- totwritten += nwritten;
- }
- return (0);
-}
diff --git a/src/lib/incrclientcount.c b/src/lib/incrclientcount.c
@@ -1,41 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void incr_client_count () {
- unsigned totclients = 0;
- int i;
-
- if (program_stage != stage_serving)
- return;
-
- if (current_backend >= 0) {
- lock_reporter();
- servicereport->backendstate[current_backend].nclients++;
- servicereport->backendstate[current_backend].totuses++;
- for (i = 0; i < activeservice->nbackend; i++)
- totclients +=
- servicereport->backendstate[i].nclients;
- servicereport->nclients = totclients;
- unlock_reporter();
-
- msg ("extcmd-onstart: "
- " current_backend = %d, clients = %d, totclients = %d, cmd = %s",
- current_backend,
- servicereport->backendstate[current_backend].nclients,
- servicereport->nclients,
- activeservice->backend[current_backend].onstart ?
- activeservice->backend[current_backend].onstart : "<none>");
-
- sysrun (activeservice->backend[current_backend].onstart);
-
- msg ("Activity on back end %d now %d, total %d",
- current_backend,
- servicereport->backendstate[current_backend].nclients,
- totclients);
- }
-}
diff --git a/src/lib/initsockaddr.c b/src/lib/initsockaddr.c
@@ -1,21 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-int init_sockaddr (struct sockaddr_in *name,
- const char *hostname, int port) {
- struct in_addr *hostaddr;
-
- if (program_stage != stage_retrying)
- msg ("trying to connect to backend %s:%d", hostname, port);
- name->sin_family = AF_INET;
- name->sin_port = htons (port);
- if (! (hostaddr = dns (hostname)) )
- return (1);
- name->sin_addr = *hostaddr;
- return (0);
-}
diff --git a/src/lib/interrupt.c b/src/lib/interrupt.c
@@ -1,54 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-/* Signal handler. NOTE - don't use non-reentrant functions in code
- * that doesn't exit! */
-void interrupt (int sig) {
-
- switch (sig) {
-
- case SIGHUP:
- /* Reload allow/deny files upon next loop */
- reload_allow_deny++;
- break;
-
- case SIGPIPE:
- /* SIGPIPE shouldn't happen, the sockets are set up not to
- * generate this. Incase it does: ignore, the next read/write
- * will stop. */
- break;
-
- default:
- /* In any case, stop the listening socket. */
- interrupted++;
- shutdown (listen_sock, SHUT_RDWR);
- close (listen_sock);
-
- switch (program_stage) {
- case stage_waiting:
- warning ("listener caught signal %d, closing socket %d and exiting",
- sig, listen_sock);
- exit (0);
- break;
-
- case stage_serving:
- /* This will serve the current connection and then stop. */
- break;
-
- case stage_retrying:
- warning ("wakeup handler caught signal %d, "
- "stopping wake ups and exiting", sig);
- exit (0);
-
- default:
- msg ("Caught signal %d in program stage %s, exiting", sig,
- stage_to_string (program_stage));
- exit (0);
- }
- }
-}
diff --git a/src/lib/ipfaddallow.c b/src/lib/ipfaddallow.c
@@ -1,17 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-int ipf_add_allow (Service *s, char const *val) {
- IpFilter filter;
-
- if (ipf_parse (val, &filter))
- return (1);
- s->allowchain = xrealloc (s->allowchain,
- (s->nallowchain + 1) * sizeof(IpFilter));
- s->allowchain[s->nallowchain++] = filter;
- return (0);
-}
diff --git a/src/lib/ipfadddeny.c b/src/lib/ipfadddeny.c
@@ -1,17 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-int ipf_add_deny (Service *s, char const *val) {
- IpFilter filter;
-
- if (ipf_parse (val, &filter))
- return (1);
- s->denychain = xrealloc (s->denychain,
- (s->ndenychain + 1) * sizeof(IpFilter));
- s->denychain[s->ndenychain++] = filter;
- return (0);
-}
diff --git a/src/lib/ipfallowed.c b/src/lib/ipfallowed.c
@@ -1,30 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-int ipf_allowed () {
- int i;
-
- /* Always allow a connection when we ddon't have an allow list. */
- if (! activeservice->allowchain) {
- msg ("No allow chain (allowing client)");
- return (1);
- }
-
- /* Try all in the chain. */
- for (i = 0; i < activeservice->nallowchain; i++) {
- msg ("Testing allow rule %d", i);
- if (ipf_match (activeservice->allowchain[i])) {
- msg ("Allowing client (rule %d)", i);
- return (1);
- }
- }
-
- /* Allow chain doesn't match */
- msg ("Not allowing client due to non-match of allow chain");
- return (0);
-}
diff --git a/src/lib/ipfdenied.c b/src/lib/ipfdenied.c
@@ -1,30 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-int ipf_denied () {
- int i;
-
- /* Never deny a connection when we don't have a deny list. */
- if (! activeservice->denychain) {
- msg ("No deny chain (not denying client)");
- return (0);
- }
-
- /* Try all in the chain. */
- for (i = 0; i < activeservice->ndenychain; i++) {
- msg ("Testing deny rule %d", i);
- if (ipf_match (activeservice->denychain[i])) {
- msg ("Denying client (rule %d)", i);
- return (1);
- }
- }
-
- /* Deny chain doesn't match */
- msg ("Not denying client, no deny rule matches");
- return (0);
-}
diff --git a/src/lib/ipfloadfile.c b/src/lib/ipfloadfile.c
@@ -1,49 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-int ipf_loadfile (char const *fname, IpFilter **chain, int *nchain) {
- FILE *f;
- char buf[80];
- int nloaded = 0, ret = 0;
- IpFilter filter;
-
- /* No file? No update. */
- if (!fname || !*fname)
- return (0);
-
- msg ("loading IP filter file: '%s'", fname);
-
- if (! (f = fopen (fname, "r")) ) {
- warning ("can't read filter file '%s': %s", fname, strerror(errno));
- return (0);
- }
-
- free (*chain);
- *chain = 0;
- *nchain = 0;
-
- while (1) {
- if (fscanf (f, " %79s ", buf) < 1)
- break;
- if (ipf_parse (buf, &filter)) {
- warning ("bad ip filter in file '%s'", fname);
- ret++;
- } else {
- msg ("got ip filter specifier '%s'", buf);
- *chain = xrealloc (*chain, (*nchain + 1) * sizeof(IpFilter));
- (*chain)[*nchain] = filter;
- (*nchain)++;
- nloaded++;
- }
- }
-
- msg ("loaded IP filter file '%s': %d successfully loaded",
- fname, nloaded);
-
- fclose (f);
- return (ret);
-}
diff --git a/src/lib/ipfmatch.c b/src/lib/ipfmatch.c
@@ -1,20 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-int ipf_match (IpFilter f) {
- unsigned f_ip_and_mask = f.ip & f.mask;
- unsigned c_ip_and_mask = client_ip_nr & f.mask;
- unsigned res = f_ip_and_mask == c_ip_and_mask;
-
- msg ("IP match: filter IP 0x%8.8x/0x%8.8x (0x%8.8x), "
- "client IP 0x%8.8x/0x%8.8x (0x%8.8x), comparison %d",
- f.ip, f.mask, f_ip_and_mask,
- client_ip_nr, f.mask, c_ip_and_mask,
- res);
- return (res);
-}
diff --git a/src/lib/ipfparse.c b/src/lib/ipfparse.c
@@ -1,52 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-int ipf_parse (char const *val, IpFilter *res) {
- char *str, *cp, *last = (char *) ipf_parse;
- int counter, nr, i;
-
- memset (res, 0, sizeof(IpFilter));
- str = xstrdup (val);
-
- for (counter = 0, cp = strtok_r (str, ".", &last);
- cp;
- counter += 8, cp = strtok_r (0, ".", &last)) {
- if (counter > 24) {
- warning ("Invalid IP filter specifier '%s' "
- "(too many network bytes)", val);
- free (str);
- return (1);
- }
- if (sscanf (cp, "%d", &nr) < 1) {
- warning ("Invalid IP filter specifier '%s' "
- "('%s' not a number)", val, cp);
- free (str);
- return (2);
- }
- nr <<= counter;
- res->ip |= nr;
- }
- free (str);
-
- if ( (cp = strchr (val, '/')) ) {
- if (sscanf (cp + 1, "%d", &nr) < 1) {
- warning ("Invalid IP filter specifier '%s' "
- "(bad mask '%s')", val, cp + 1);
- return (3);
- }
- for (i = 1; i <= nr; i++) {
- res->mask <<= 1;
- res->mask |= 1;
- }
- } else
- res->mask = (unsigned) -1;
-
- return (0);
-}
-
-
diff --git a/src/lib/ishexdigit.c b/src/lib/ishexdigit.c
@@ -1,15 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-int is_hex_digit (char ch) {
- if ( (ch >= '0' && ch <= '9') ||
- (ch >= 'a' && ch <= 'f') ||
- (ch >= 'A' && ch <= 'F') )
- return (1);
- return (0);
-}
-
diff --git a/src/lib/isspace.c b/src/lib/isspace.c
@@ -1,15 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-/*
- * I'd much rather use ctype.h's isspace macro, but it's not available
- * everywhere...
- */
-
-int is_space (char ch) {
- return (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
-}
diff --git a/src/lib/lexer.c b/src/lib/lexer.c
@@ -1,2973 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#line 2 "lexer.c"
-
-#line 4 "lexer.c"
-
-#define YY_INT_ALIGNED short int
-
-/* A lexical scanner generated by flex */
-
-#define FLEX_SCANNER
-#define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 33
-#if YY_FLEX_SUBMINOR_VERSION > 0
-#define FLEX_BETA
-#endif
-
-/* First, we deal with platform-specific or compiler-specific issues. */
-
-/* begin standard C headers. */
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-
-/* end standard C headers. */
-
-/* flex integer type definitions */
-
-#ifndef FLEXINT_H
-#define FLEXINT_H
-
-/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
-
-#if __STDC_VERSION__ >= 199901L
-
-/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types.
- */
-#ifndef __STDC_LIMIT_MACROS
-#define __STDC_LIMIT_MACROS 1
-#endif
-
-#include <inttypes.h>
-typedef int8_t flex_int8_t;
-typedef uint8_t flex_uint8_t;
-typedef int16_t flex_int16_t;
-typedef uint16_t flex_uint16_t;
-typedef int32_t flex_int32_t;
-typedef uint32_t flex_uint32_t;
-#else
-typedef signed char flex_int8_t;
-typedef short int flex_int16_t;
-typedef int flex_int32_t;
-typedef unsigned char flex_uint8_t;
-typedef unsigned short int flex_uint16_t;
-typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
-
-/* Limits of integral types. */
-#ifndef INT8_MIN
-#define INT8_MIN (-128)
-#endif
-#ifndef INT16_MIN
-#define INT16_MIN (-32767-1)
-#endif
-#ifndef INT32_MIN
-#define INT32_MIN (-2147483647-1)
-#endif
-#ifndef INT8_MAX
-#define INT8_MAX (127)
-#endif
-#ifndef INT16_MAX
-#define INT16_MAX (32767)
-#endif
-#ifndef INT32_MAX
-#define INT32_MAX (2147483647)
-#endif
-#ifndef UINT8_MAX
-#define UINT8_MAX (255U)
-#endif
-#ifndef UINT16_MAX
-#define UINT16_MAX (65535U)
-#endif
-#ifndef UINT32_MAX
-#define UINT32_MAX (4294967295U)
-#endif
-
-#endif /* ! FLEXINT_H */
-
-#ifdef __cplusplus
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else /* ! __cplusplus */
-
-#if __STDC__
-
-#define YY_USE_CONST
-
-#endif /* __STDC__ */
-#endif /* ! __cplusplus */
-
-#ifdef YY_USE_CONST
-#define yyconst const
-#else
-#define yyconst
-#endif
-
-/* Returned upon end-of-file. */
-#define YY_NULL 0
-
-/* Promotes a possibly negative, possibly signed char to an unsigned
- * integer for use as an array index. If the signed char is negative,
- * we want to instead treat it as an 8-bit unsigned char, hence the
- * double cast.
- */
-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
-
-/* Enter a start condition. This macro really ought to take a parameter,
- * but we do it the disgusting crufty way forced on us by the ()-less
- * definition of BEGIN.
- */
-#define BEGIN (yy_start) = 1 + 2 *
-
-/* Translate the current start state into a value that can be later handed
- * to BEGIN to return to the state. The YYSTATE alias is for lex
- * compatibility.
- */
-#define YY_START (((yy_start) - 1) / 2)
-#define YYSTATE YY_START
-
-/* Action number for EOF rule of a given start state. */
-#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-
-/* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE yyrestart(yyin )
-
-#define YY_END_OF_BUFFER_CHAR 0
-
-/* Size of default input buffer. */
-#ifndef YY_BUF_SIZE
-#define YY_BUF_SIZE 16384
-#endif
-
-/* The state buf must be large enough to hold one state per character in the main buffer.
- */
-#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
-
-#ifndef YY_TYPEDEF_YY_BUFFER_STATE
-#define YY_TYPEDEF_YY_BUFFER_STATE
-typedef struct yy_buffer_state *YY_BUFFER_STATE;
-#endif
-
-extern int yyleng;
-
-extern FILE *yyin, *yyout;
-
-#define EOB_ACT_CONTINUE_SCAN 0
-#define EOB_ACT_END_OF_FILE 1
-#define EOB_ACT_LAST_MATCH 2
-
- #define YY_LESS_LINENO(n)
-
-/* Return all but the first "n" matched characters back to the input stream. */
-#define yyless(n) \
- do \
- { \
- /* Undo effects of setting up yytext. */ \
- int yyless_macro_arg = (n); \
- YY_LESS_LINENO(yyless_macro_arg);\
- *yy_cp = (yy_hold_char); \
- YY_RESTORE_YY_MORE_OFFSET \
- (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
- YY_DO_BEFORE_ACTION; /* set up yytext again */ \
- } \
- while ( 0 )
-
-#define unput(c) yyunput( c, (yytext_ptr) )
-
-/* The following is because we cannot portably get our hands on size_t
- * (without autoconf's help, which isn't available because we want
- * flex-generated scanners to compile on their own).
- */
-
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef unsigned int yy_size_t;
-#endif
-
-#ifndef YY_STRUCT_YY_BUFFER_STATE
-#define YY_STRUCT_YY_BUFFER_STATE
-struct yy_buffer_state
- {
- FILE *yy_input_file;
-
- char *yy_ch_buf; /* input buffer */
- char *yy_buf_pos; /* current position in input buffer */
-
- /* Size of input buffer in bytes, not including room for EOB
- * characters.
- */
- yy_size_t yy_buf_size;
-
- /* Number of characters read into yy_ch_buf, not including EOB
- * characters.
- */
- int yy_n_chars;
-
- /* Whether we "own" the buffer - i.e., we know we created it,
- * and can realloc() it to grow it, and should free() it to
- * delete it.
- */
- int yy_is_our_buffer;
-
- /* Whether this is an "interactive" input source; if so, and
- * if we're using stdio for input, then we want to use getc()
- * instead of fread(), to make sure we stop fetching input after
- * each newline.
- */
- int yy_is_interactive;
-
- /* Whether we're considered to be at the beginning of a line.
- * If so, '^' rules will be active on the next match, otherwise
- * not.
- */
- int yy_at_bol;
-
- int yy_bs_lineno; /**< The line count. */
- int yy_bs_column; /**< The column count. */
-
- /* Whether to try to fill the input buffer when we reach the
- * end of it.
- */
- int yy_fill_buffer;
-
- int yy_buffer_status;
-
-#define YY_BUFFER_NEW 0
-#define YY_BUFFER_NORMAL 1
- /* When an EOF's been seen but there's still some text to process
- * then we mark the buffer as YY_EOF_PENDING, to indicate that we
- * shouldn't try reading from the input source any more. We might
- * still have a bunch of tokens to match, though, because of
- * possible backing-up.
- *
- * When we actually see the EOF, we change the status to "new"
- * (via yyrestart()), so that the user can continue scanning by
- * just pointing yyin at a new input file.
- */
-#define YY_BUFFER_EOF_PENDING 2
-
- };
-#endif /* !YY_STRUCT_YY_BUFFER_STATE */
-
-/* Stack of input buffers. */
-static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
-static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
-static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
-
-/* We provide macros for accessing buffer states in case in the
- * future we want to put the buffer states in a more general
- * "scanner state".
- *
- * Returns the top of the stack, or NULL.
- */
-#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
- ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
- : NULL)
-
-/* Same as previous macro, but useful when we know that the buffer stack is not
- * NULL or when we need an lvalue. For internal use only.
- */
-#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
-
-/* yy_hold_char holds the character lost when yytext is formed. */
-static char yy_hold_char;
-static int yy_n_chars; /* number of characters read into yy_ch_buf */
-int yyleng;
-
-/* Points to current character in buffer. */
-static char *yy_c_buf_p = (char *) 0;
-static int yy_init = 0; /* whether we need to initialize */
-static int yy_start = 0; /* start state number */
-
-/* Flag which is used to allow yywrap()'s to do buffer switches
- * instead of setting up a fresh yyin. A bit of a hack ...
- */
-static int yy_did_buffer_switch_on_eof;
-
-void yyrestart (FILE *input_file );
-void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
-YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
-void yy_delete_buffer (YY_BUFFER_STATE b );
-void yy_flush_buffer (YY_BUFFER_STATE b );
-void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
-void yypop_buffer_state (void );
-
-static void yyensure_buffer_stack (void );
-static void yy_load_buffer_state (void );
-static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
-
-#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
-
-YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
-YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
-
-void *yyalloc (yy_size_t );
-void *yyrealloc (void *,yy_size_t );
-void yyfree (void * );
-
-#define yy_new_buffer yy_create_buffer
-
-#define yy_set_interactive(is_interactive) \
- { \
- if ( ! YY_CURRENT_BUFFER ){ \
- yyensure_buffer_stack (); \
- YY_CURRENT_BUFFER_LVALUE = \
- yy_create_buffer(yyin,YY_BUF_SIZE ); \
- } \
- YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
- }
-
-#define yy_set_bol(at_bol) \
- { \
- if ( ! YY_CURRENT_BUFFER ){\
- yyensure_buffer_stack (); \
- YY_CURRENT_BUFFER_LVALUE = \
- yy_create_buffer(yyin,YY_BUF_SIZE ); \
- } \
- YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
- }
-
-#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
-
-typedef unsigned char YY_CHAR;
-
-FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
-
-typedef int yy_state_type;
-
-extern int yylineno;
-
-int yylineno = 1;
-
-extern char *yytext;
-#define yytext_ptr yytext
-
-static yy_state_type yy_get_previous_state (void );
-static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
-static int yy_get_next_buffer (void );
-static void yy_fatal_error (yyconst char msg[] );
-
-/* Done after the current pattern has been matched and before the
- * corresponding action - sets up yytext.
- */
-#define YY_DO_BEFORE_ACTION \
- (yytext_ptr) = yy_bp; \
- yyleng = (size_t) (yy_cp - yy_bp); \
- (yy_hold_char) = *yy_cp; \
- *yy_cp = '\0'; \
- (yy_c_buf_p) = yy_cp;
-
-#define YY_NUM_RULES 98
-#define YY_END_OF_BUFFER 99
-/* This struct is not used in this scanner,
- but its presence is necessary. */
-struct yy_trans_info
- {
- flex_int32_t yy_verify;
- flex_int32_t yy_nxt;
- };
-static yyconst flex_int16_t yy_accept[616] =
- { 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 95, 95, 96, 96, 99, 73, 71, 72,
- 73, 70, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 73, 79, 78, 78, 85, 86, 84, 85,
- 85, 83, 85, 77, 76, 77, 90, 88, 89, 87,
- 94, 93, 91, 92, 91, 98, 95, 96, 97, 71,
- 74, 0, 70, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 68, 69, 67, 69,
-
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 19, 69, 69, 69, 69, 0,
- 0, 0, 0, 81, 0, 82, 80, 75, 87, 91,
- 92, 91, 95, 96, 0, 3, 69, 69, 46, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 67,
- 0, 0, 69, 69, 69, 69, 69, 69, 69, 69,
-
- 69, 69, 69, 69, 69, 69, 69, 44, 69, 69,
- 69, 21, 69, 69, 69, 69, 48, 69, 69, 69,
- 69, 69, 69, 69, 69, 15, 14, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 42, 69, 69, 69, 69, 0, 0,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 28, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 55, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 18, 69, 69, 69, 69, 69, 69,
-
- 69, 69, 0, 0, 69, 69, 69, 69, 69, 69,
- 69, 13, 69, 69, 69, 69, 34, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 54, 69, 69, 32, 69, 69, 69, 29, 69,
- 69, 69, 69, 16, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 27, 0, 0, 69, 69, 69, 69,
- 69, 69, 69, 17, 22, 69, 69, 69, 35, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 53, 4, 23, 69, 69, 12, 69,
- 69, 45, 69, 69, 69, 69, 69, 69, 69, 69,
-
- 69, 24, 69, 2, 0, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 66, 64, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 1, 69, 69, 65, 63, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 38, 69, 33, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 31, 69,
-
- 69, 69, 69, 69, 47, 69, 69, 50, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 7, 52,
- 69, 69, 69, 69, 5, 8, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 20, 39, 69, 69, 69,
- 69, 69, 69, 69, 30, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 56, 69, 69, 69, 69,
- 69, 69, 36, 41, 69, 69, 69, 51, 69, 69,
- 69, 69, 69, 69, 69, 6, 49, 69, 69, 69,
- 69, 69, 69, 69, 69, 26, 69, 69, 69, 9,
- 10, 57, 60, 69, 69, 69, 37, 69, 69, 69,
-
- 58, 61, 69, 69, 69, 43, 69, 40, 69, 69,
- 25, 11, 59, 62, 0
- } ;
-
-static yyconst flex_int32_t yy_ec[256] =
- { 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
- 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 5, 1, 6, 7, 1, 1, 1, 8, 1,
- 1, 9, 1, 1, 10, 10, 11, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 10, 13, 10,
- 1, 10, 1, 1, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 1, 15, 1, 1, 14, 1, 16, 17, 18, 19,
-
- 20, 21, 22, 23, 24, 14, 25, 26, 27, 28,
- 29, 30, 14, 31, 32, 33, 34, 35, 36, 37,
- 38, 39, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1
- } ;
-
-static yyconst flex_int32_t yy_meta[40] =
- { 0,
- 1, 1, 2, 1, 1, 3, 1, 1, 1, 3,
- 3, 4, 1, 4, 3, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4
- } ;
-
-static yyconst flex_int16_t yy_base[630] =
- { 0,
- 0, 726, 38, 42, 45, 58, 46, 53, 73, 86,
- 99, 131, 65, 113, 729, 728, 730, 734, 52, 734,
- 74, 717, 0, 94, 129, 36, 127, 691, 711, 59,
- 97, 710, 696, 129, 695, 142, 146, 142, 91, 703,
- 702, 701, 172, 734, 734, 734, 734, 734, 734, 714,
- 711, 734, 90, 734, 734, 707, 734, 734, 734, 0,
- 734, 734, 120, 0, 122, 734, 67, 0, 734, 173,
- 734, 714, 704, 0, 696, 688, 675, 682, 695, 692,
- 681, 163, 688, 679, 165, 674, 673, 668, 676, 669,
- 675, 684, 666, 682, 675, 659, 0, 674, 166, 661,
-
- 673, 661, 663, 95, 656, 137, 172, 660, 160, 658,
- 656, 173, 656, 669, 0, 664, 652, 658, 649, 192,
- 660, 651, 672, 734, 669, 734, 734, 734, 0, 185,
- 0, 195, 199, 0, 673, 734, 187, 646, 0, 654,
- 649, 647, 652, 177, 636, 638, 644, 649, 638, 649,
- 634, 625, 632, 643, 632, 629, 638, 625, 637, 625,
- 619, 192, 635, 624, 635, 617, 625, 617, 614, 627,
- 614, 620, 615, 607, 191, 615, 185, 610, 606, 620,
- 620, 607, 614, 614, 613, 597, 600, 613, 607, 0,
- 607, 609, 600, 605, 588, 595, 596, 192, 588, 596,
-
- 591, 587, 598, 577, 590, 594, 575, 0, 591, 595,
- 594, 0, 576, 577, 587, 586, 572, 584, 585, 586,
- 572, 581, 575, 582, 568, 0, 0, 567, 571, 559,
- 574, 200, 566, 571, 564, 569, 568, 557, 566, 560,
- 550, 549, 561, 0, 565, 564, 550, 555, 553, 550,
- 551, 543, 552, 553, 555, 542, 540, 539, 547, 538,
- 549, 544, 543, 538, 543, 0, 190, 527, 541, 527,
- 529, 525, 531, 524, 520, 534, 523, 0, 524, 518,
- 520, 520, 526, 521, 513, 512, 524, 517, 509, 510,
- 500, 506, 498, 0, 497, 513, 511, 508, 507, 512,
-
- 497, 495, 499, 492, 505, 489, 198, 207, 506, 503,
- 499, 0, 492, 499, 485, 486, 0, 488, 482, 488,
- 484, 494, 488, 494, 493, 484, 480, 475, 481, 480,
- 475, 0, 469, 469, 0, 468, 471, 469, 0, 477,
- 476, 460, 458, 0, 466, 462, 208, 470, 467, 471,
- 462, 469, 208, 0, 466, 466, 456, 463, 456, 452,
- 454, 459, 452, 0, 0, 444, 458, 451, 0, 441,
- 449, 452, 444, 447, 449, 447, 441, 438, 441, 435,
- 428, 436, 441, 0, 0, 0, 438, 442, 0, 430,
- 437, 0, 432, 426, 425, 420, 432, 421, 424, 433,
-
- 419, 0, 414, 734, 426, 412, 413, 423, 415, 417,
- 409, 419, 414, 404, 407, 415, 405, 0, 0, 406,
- 399, 410, 407, 397, 400, 409, 402, 401, 406, 399,
- 398, 388, 389, 387, 387, 388, 383, 384, 380, 384,
- 395, 377, 372, 734, 386, 385, 0, 0, 387, 371,
- 375, 380, 375, 371, 373, 371, 366, 374, 381, 366,
- 373, 374, 360, 359, 358, 362, 361, 365, 364, 354,
- 352, 359, 353, 350, 348, 358, 353, 350, 357, 356,
- 347, 354, 0, 344, 0, 337, 338, 351, 343, 350,
- 339, 346, 339, 332, 325, 324, 337, 327, 0, 339,
-
- 338, 333, 339, 331, 0, 330, 327, 0, 332, 318,
- 334, 333, 315, 316, 318, 329, 320, 323, 0, 0,
- 323, 323, 311, 307, 0, 0, 309, 317, 320, 319,
- 305, 309, 312, 292, 301, 0, 0, 310, 309, 304,
- 303, 293, 298, 296, 0, 296, 288, 298, 286, 290,
- 286, 297, 296, 286, 285, 0, 292, 289, 290, 289,
- 288, 287, 0, 0, 286, 285, 280, 0, 279, 270,
- 266, 280, 279, 266, 278, 0, 0, 265, 264, 278,
- 277, 263, 260, 261, 256, 0, 272, 256, 255, 0,
- 0, 0, 0, 260, 219, 203, 0, 208, 209, 208,
-
- 0, 0, 213, 210, 169, 0, 129, 0, 117, 66,
- 0, 0, 0, 0, 734, 239, 243, 247, 251, 255,
- 259, 263, 80, 267, 271, 273, 48, 277, 281
- } ;
-
-static yyconst flex_int16_t yy_def[630] =
- { 0,
- 615, 1, 616, 616, 617, 617, 618, 618, 619, 619,
- 620, 620, 621, 621, 622, 622, 615, 615, 615, 615,
- 615, 615, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 615, 615, 615, 615, 615, 615, 615, 624,
- 625, 615, 615, 615, 615, 615, 615, 615, 615, 626,
- 615, 615, 615, 627, 627, 615, 615, 628, 615, 615,
- 615, 629, 615, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
-
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 615,
- 615, 615, 624, 615, 625, 615, 615, 615, 626, 615,
- 627, 627, 615, 628, 629, 615, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 615, 615, 623, 623, 623, 623, 623, 623, 623, 623,
-
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 615, 615,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
-
- 623, 623, 615, 615, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 615, 615, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
-
- 623, 623, 623, 615, 615, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 615, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
-
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
-
- 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 623, 623, 0, 615, 615, 615, 615, 615,
- 615, 615, 615, 615, 615, 615, 615, 615, 615
- } ;
-
-static yyconst flex_int16_t yy_nxt[774] =
- { 0,
- 18, 19, 20, 18, 19, 18, 18, 18, 18, 18,
- 21, 22, 18, 23, 18, 24, 25, 26, 27, 28,
- 29, 23, 30, 23, 23, 31, 32, 33, 34, 35,
- 36, 37, 38, 39, 40, 41, 23, 42, 23, 45,
- 46, 45, 45, 45, 46, 45, 45, 48, 55, 49,
- 50, 131, 51, 70, 56, 55, 70, 52, 83, 53,
- 48, 56, 49, 50, 84, 51, 67, 62, 133, 67,
- 52, 133, 53, 57, 58, 59, 57, 58, 92, 57,
- 57, 57, 71, 74, 72, 57, 57, 58, 59, 57,
- 58, 93, 57, 57, 57, 127, 614, 127, 57, 61,
-
- 61, 62, 61, 63, 61, 61, 61, 61, 61, 61,
- 61, 61, 75, 61, 67, 62, 94, 67, 114, 76,
- 115, 77, 116, 78, 130, 95, 130, 171, 79, 172,
- 65, 61, 61, 62, 61, 63, 61, 61, 61, 61,
- 61, 61, 61, 61, 80, 61, 85, 613, 612, 98,
- 86, 130, 81, 132, 87, 88, 99, 103, 100, 110,
- 89, 104, 65, 101, 111, 106, 82, 174, 107, 175,
- 105, 108, 112, 120, 70, 179, 120, 70, 109, 113,
- 144, 145, 150, 180, 151, 164, 165, 176, 183, 130,
- 121, 146, 152, 120, 147, 122, 120, 166, 177, 130,
-
- 133, 611, 200, 133, 193, 201, 184, 219, 233, 236,
- 121, 256, 220, 320, 237, 122, 130, 257, 194, 286,
- 321, 359, 234, 287, 361, 395, 132, 402, 360, 610,
- 396, 403, 609, 608, 607, 606, 605, 604, 362, 44,
- 44, 44, 44, 47, 47, 47, 47, 54, 54, 54,
- 54, 60, 60, 60, 60, 64, 64, 64, 64, 66,
- 66, 66, 66, 68, 68, 68, 68, 123, 123, 123,
- 123, 125, 125, 125, 125, 129, 129, 134, 603, 134,
- 134, 135, 135, 135, 135, 602, 601, 600, 599, 598,
- 597, 596, 595, 594, 593, 592, 591, 590, 589, 588,
-
- 587, 586, 585, 584, 583, 582, 581, 580, 579, 578,
- 577, 576, 575, 574, 573, 572, 571, 570, 569, 568,
- 567, 566, 565, 564, 563, 562, 561, 560, 559, 558,
- 557, 556, 555, 554, 553, 552, 551, 550, 549, 548,
- 547, 546, 545, 544, 543, 542, 541, 540, 539, 538,
- 537, 536, 535, 534, 533, 532, 531, 530, 529, 528,
- 527, 526, 525, 524, 523, 522, 521, 520, 519, 518,
- 517, 516, 515, 514, 513, 512, 511, 510, 509, 508,
- 507, 506, 505, 504, 503, 502, 501, 500, 499, 498,
- 497, 496, 495, 494, 493, 492, 491, 490, 489, 488,
-
- 487, 486, 485, 484, 483, 482, 481, 480, 479, 402,
- 478, 477, 476, 475, 474, 473, 472, 471, 470, 469,
- 468, 467, 466, 465, 464, 463, 462, 461, 460, 459,
- 458, 457, 456, 455, 454, 453, 452, 451, 115, 450,
- 449, 448, 447, 446, 445, 444, 443, 442, 441, 440,
- 439, 438, 437, 436, 435, 434, 433, 432, 431, 430,
- 429, 428, 427, 426, 425, 424, 423, 422, 421, 420,
- 419, 418, 417, 416, 415, 414, 413, 412, 411, 410,
- 409, 408, 407, 406, 405, 404, 401, 400, 399, 398,
- 397, 394, 393, 392, 391, 390, 389, 388, 387, 386,
-
- 385, 384, 383, 382, 381, 380, 379, 378, 377, 376,
- 375, 374, 373, 372, 371, 370, 369, 368, 367, 366,
- 365, 364, 363, 358, 357, 356, 355, 354, 353, 352,
- 351, 350, 349, 348, 347, 346, 345, 344, 343, 342,
- 341, 340, 339, 338, 337, 336, 335, 334, 333, 332,
- 331, 330, 329, 328, 327, 326, 325, 324, 323, 322,
- 319, 318, 317, 316, 315, 314, 313, 312, 311, 310,
- 309, 308, 307, 306, 305, 304, 303, 302, 301, 300,
- 299, 298, 297, 296, 295, 294, 293, 292, 291, 290,
- 289, 288, 285, 284, 283, 282, 281, 280, 279, 278,
-
- 277, 276, 275, 274, 273, 272, 97, 271, 270, 269,
- 268, 267, 266, 265, 264, 263, 262, 261, 260, 259,
- 258, 255, 254, 253, 252, 251, 250, 249, 248, 247,
- 246, 245, 244, 190, 243, 242, 241, 240, 239, 238,
- 235, 232, 231, 230, 229, 228, 227, 226, 225, 224,
- 223, 222, 221, 218, 217, 216, 215, 214, 213, 212,
- 211, 210, 209, 208, 207, 206, 205, 204, 203, 202,
- 199, 198, 197, 196, 195, 136, 126, 124, 192, 191,
- 190, 189, 188, 187, 186, 185, 182, 181, 178, 173,
- 170, 169, 168, 167, 97, 163, 162, 161, 160, 159,
-
- 158, 157, 156, 155, 154, 153, 149, 148, 143, 142,
- 141, 140, 139, 138, 137, 73, 136, 128, 126, 124,
- 119, 118, 117, 102, 97, 96, 91, 90, 73, 615,
- 69, 69, 43, 17, 615, 615, 615, 615, 615, 615,
- 615, 615, 615, 615, 615, 615, 615, 615, 615, 615,
- 615, 615, 615, 615, 615, 615, 615, 615, 615, 615,
- 615, 615, 615, 615, 615, 615, 615, 615, 615, 615,
- 615, 615, 615
- } ;
-
-static yyconst flex_int16_t yy_chk[774] =
- { 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 3,
- 3, 3, 3, 4, 4, 4, 4, 5, 7, 5,
- 5, 627, 5, 19, 7, 8, 19, 5, 26, 5,
- 6, 8, 6, 6, 26, 6, 13, 13, 67, 13,
- 6, 67, 6, 9, 9, 9, 9, 9, 30, 9,
- 9, 9, 21, 623, 21, 9, 10, 10, 10, 10,
- 10, 30, 10, 10, 10, 53, 610, 53, 10, 11,
-
- 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
- 11, 11, 24, 11, 14, 14, 31, 14, 39, 24,
- 39, 24, 39, 24, 63, 31, 65, 104, 24, 104,
- 11, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 25, 12, 27, 609, 607, 34,
- 27, 63, 25, 65, 27, 27, 34, 36, 34, 38,
- 27, 36, 12, 34, 38, 37, 25, 106, 37, 106,
- 36, 37, 38, 43, 70, 109, 43, 70, 37, 38,
- 82, 82, 85, 109, 85, 99, 99, 107, 112, 130,
- 43, 82, 85, 120, 82, 43, 120, 99, 107, 132,
-
- 133, 605, 144, 133, 137, 144, 112, 162, 175, 177,
- 120, 198, 162, 267, 177, 120, 130, 198, 137, 232,
- 267, 307, 175, 232, 308, 347, 132, 353, 307, 604,
- 347, 353, 603, 600, 599, 598, 596, 595, 308, 616,
- 616, 616, 616, 617, 617, 617, 617, 618, 618, 618,
- 618, 619, 619, 619, 619, 620, 620, 620, 620, 621,
- 621, 621, 621, 622, 622, 622, 622, 624, 624, 624,
- 624, 625, 625, 625, 625, 626, 626, 628, 594, 628,
- 628, 629, 629, 629, 629, 589, 588, 587, 585, 584,
- 583, 582, 581, 580, 579, 578, 575, 574, 573, 572,
-
- 571, 570, 569, 567, 566, 565, 562, 561, 560, 559,
- 558, 557, 555, 554, 553, 552, 551, 550, 549, 548,
- 547, 546, 544, 543, 542, 541, 540, 539, 538, 535,
- 534, 533, 532, 531, 530, 529, 528, 527, 524, 523,
- 522, 521, 518, 517, 516, 515, 514, 513, 512, 511,
- 510, 509, 507, 506, 504, 503, 502, 501, 500, 498,
- 497, 496, 495, 494, 493, 492, 491, 490, 489, 488,
- 487, 486, 484, 482, 481, 480, 479, 478, 477, 476,
- 475, 474, 473, 472, 471, 470, 469, 468, 467, 466,
- 465, 464, 463, 462, 461, 460, 459, 458, 457, 456,
-
- 455, 454, 453, 452, 451, 450, 449, 446, 445, 443,
- 442, 441, 440, 439, 438, 437, 436, 435, 434, 433,
- 432, 431, 430, 429, 428, 427, 426, 425, 424, 423,
- 422, 421, 420, 417, 416, 415, 414, 413, 412, 411,
- 410, 409, 408, 407, 406, 405, 403, 401, 400, 399,
- 398, 397, 396, 395, 394, 393, 391, 390, 388, 387,
- 383, 382, 381, 380, 379, 378, 377, 376, 375, 374,
- 373, 372, 371, 370, 368, 367, 366, 363, 362, 361,
- 360, 359, 358, 357, 356, 355, 352, 351, 350, 349,
- 348, 346, 345, 343, 342, 341, 340, 338, 337, 336,
-
- 334, 333, 331, 330, 329, 328, 327, 326, 325, 324,
- 323, 322, 321, 320, 319, 318, 316, 315, 314, 313,
- 311, 310, 309, 306, 305, 304, 303, 302, 301, 300,
- 299, 298, 297, 296, 295, 293, 292, 291, 290, 289,
- 288, 287, 286, 285, 284, 283, 282, 281, 280, 279,
- 277, 276, 275, 274, 273, 272, 271, 270, 269, 268,
- 265, 264, 263, 262, 261, 260, 259, 258, 257, 256,
- 255, 254, 253, 252, 251, 250, 249, 248, 247, 246,
- 245, 243, 242, 241, 240, 239, 238, 237, 236, 235,
- 234, 233, 231, 230, 229, 228, 225, 224, 223, 222,
-
- 221, 220, 219, 218, 217, 216, 215, 214, 213, 211,
- 210, 209, 207, 206, 205, 204, 203, 202, 201, 200,
- 199, 197, 196, 195, 194, 193, 192, 191, 189, 188,
- 187, 186, 185, 184, 183, 182, 181, 180, 179, 178,
- 176, 174, 173, 172, 171, 170, 169, 168, 167, 166,
- 165, 164, 163, 161, 160, 159, 158, 157, 156, 155,
- 154, 153, 152, 151, 150, 149, 148, 147, 146, 145,
- 143, 142, 141, 140, 138, 135, 125, 123, 122, 121,
- 119, 118, 117, 116, 114, 113, 111, 110, 108, 105,
- 103, 102, 101, 100, 98, 96, 95, 94, 93, 92,
-
- 91, 90, 89, 88, 87, 86, 84, 83, 81, 80,
- 79, 78, 77, 76, 75, 73, 72, 56, 51, 50,
- 42, 41, 40, 35, 33, 32, 29, 28, 22, 17,
- 16, 15, 2, 615, 615, 615, 615, 615, 615, 615,
- 615, 615, 615, 615, 615, 615, 615, 615, 615, 615,
- 615, 615, 615, 615, 615, 615, 615, 615, 615, 615,
- 615, 615, 615, 615, 615, 615, 615, 615, 615, 615,
- 615, 615, 615
- } ;
-
-static yy_state_type yy_last_accepting_state;
-static char *yy_last_accepting_cpos;
-
-extern int yy_flex_debug;
-int yy_flex_debug = 0;
-
-/* The intent behind this definition is that it'll catch
- * any uses of REJECT which flex missed.
- */
-#define REJECT reject_used_but_not_detected
-#define yymore() yymore_used_but_not_detected
-#define YY_MORE_ADJ 0
-#define YY_RESTORE_YY_MORE_OFFSET
-char *yytext;
-#line 1 "lexer.l"
-#line 2 "lexer.l"
-#include "../crossroads.h"
-#include "parser.h"
-
-/* Redefinition of YY_INPUT to respect the parserstate. */
-#define YY_INPUT(buf,res,max) (res) = parser_input( (buf), (max) )
-#define yywrap parser_close
-
-/* Globals */
-static int i;
-
-/* Lexer debugging related */
-static void lmsg (char const *fmt, ...) {
- va_list args;
-
- if (parser_debug) {
- va_start (args, fmt);
- printf ("LEXER: ");
- vprintf (fmt, args);
- }
-}
-
-#line 848 "lexer.c"
-
-#define INITIAL 0
-#define stringstate 1
-#define instr 2
-#define commentstate 3
-#define includestate 4
-#define definestate 5
-#define defineredef 6
-#define definesym 7
-
-#ifndef YY_NO_UNISTD_H
-/* Special case for "unistd.h", since it is non-ANSI. We include it way
- * down here because we want the user's section 1 to have been scanned first.
- * The user has a chance to override it with an option.
- */
-#include <unistd.h>
-#endif
-
-#ifndef YY_EXTRA_TYPE
-#define YY_EXTRA_TYPE void *
-#endif
-
-static int yy_init_globals (void );
-
-/* Macros after this point can all be overridden by user definitions in
- * section 1.
- */
-
-#ifndef YY_SKIP_YYWRAP
-#ifdef __cplusplus
-extern "C" int yywrap (void );
-#else
-extern int yywrap (void );
-#endif
-#endif
-
- static void yyunput (int c,char *buf_ptr );
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char *,yyconst char *,int );
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * );
-#endif
-
-#ifndef YY_NO_INPUT
-
-#ifdef __cplusplus
-static int yyinput (void );
-#else
-static int input (void );
-#endif
-
-#endif
-
-/* Amount of stuff to slurp up with each read. */
-#ifndef YY_READ_BUF_SIZE
-#define YY_READ_BUF_SIZE 8192
-#endif
-
-/* Copy whatever the last rule matched to the standard output. */
-#ifndef ECHO
-/* This used to be an fputs(), but since the string might contain NUL's,
- * we now use fwrite().
- */
-#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
-#endif
-
-/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
- * is returned in "result".
- */
-#ifndef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
- if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
- { \
- int c = '*'; \
- size_t n; \
- for ( n = 0; n < max_size && \
- (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
- buf[n] = (char) c; \
- if ( c == '\n' ) \
- buf[n++] = (char) c; \
- if ( c == EOF && ferror( yyin ) ) \
- YY_FATAL_ERROR( "input in flex scanner failed" ); \
- result = n; \
- } \
- else \
- { \
- errno=0; \
- while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
- { \
- if( errno != EINTR) \
- { \
- YY_FATAL_ERROR( "input in flex scanner failed" ); \
- break; \
- } \
- errno=0; \
- clearerr(yyin); \
- } \
- }\
-\
-
-#endif
-
-/* No semi-colon after return; correct usage is to write "yyterminate();" -
- * we don't want an extra ';' after the "return" because that will cause
- * some compilers to complain about unreachable statements.
- */
-#ifndef yyterminate
-#define yyterminate() return YY_NULL
-#endif
-
-/* Number of entries by which start-condition stack grows. */
-#ifndef YY_START_STACK_INCR
-#define YY_START_STACK_INCR 25
-#endif
-
-/* Report a fatal error. */
-#ifndef YY_FATAL_ERROR
-#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
-#endif
-
-/* end tables serialization structures and prototypes */
-
-/* Default declaration of generated scanner - a define so the user can
- * easily add parameters.
- */
-#ifndef YY_DECL
-#define YY_DECL_IS_OURS 1
-
-extern int yylex (void);
-
-#define YY_DECL int yylex (void)
-#endif /* !YY_DECL */
-
-/* Code executed at the beginning of each rule, after yytext and yyleng
- * have been set up.
- */
-#ifndef YY_USER_ACTION
-#define YY_USER_ACTION
-#endif
-
-/* Code executed at the end of each rule. */
-#ifndef YY_BREAK
-#define YY_BREAK break;
-#endif
-
-#define YY_RULE_SETUP \
- if ( yyleng > 0 ) \
- YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
- (yytext[yyleng - 1] == '\n'); \
- YY_USER_ACTION
-
-/** The main scanner function which does all the work.
- */
-YY_DECL
-{
- register yy_state_type yy_current_state;
- register char *yy_cp, *yy_bp;
- register int yy_act;
-
-#line 27 "lexer.l"
-
-
-#line 1014 "lexer.c"
-
- if ( !(yy_init) )
- {
- (yy_init) = 1;
-
-#ifdef YY_USER_INIT
- YY_USER_INIT;
-#endif
-
- if ( ! (yy_start) )
- (yy_start) = 1; /* first start state */
-
- if ( ! yyin )
- yyin = stdin;
-
- if ( ! yyout )
- yyout = stdout;
-
- if ( ! YY_CURRENT_BUFFER ) {
- yyensure_buffer_stack ();
- YY_CURRENT_BUFFER_LVALUE =
- yy_create_buffer(yyin,YY_BUF_SIZE );
- }
-
- yy_load_buffer_state( );
- }
-
- while ( 1 ) /* loops until end-of-file is reached */
- {
- yy_cp = (yy_c_buf_p);
-
- /* Support of yytext. */
- *yy_cp = (yy_hold_char);
-
- /* yy_bp points to the position in yy_ch_buf of the start of
- * the current run.
- */
- yy_bp = yy_cp;
-
- yy_current_state = (yy_start);
- yy_current_state += YY_AT_BOL();
-yy_match:
- do
- {
- register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
- if ( yy_accept[yy_current_state] )
- {
- (yy_last_accepting_state) = yy_current_state;
- (yy_last_accepting_cpos) = yy_cp;
- }
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 616 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- ++yy_cp;
- }
- while ( yy_base[yy_current_state] != 734 );
-
-yy_find_action:
- yy_act = yy_accept[yy_current_state];
- if ( yy_act == 0 )
- { /* have to back up */
- yy_cp = (yy_last_accepting_cpos);
- yy_current_state = (yy_last_accepting_state);
- yy_act = yy_accept[yy_current_state];
- }
-
- YY_DO_BEFORE_ACTION;
-
-do_action: /* This label is used only to access EOF actions. */
-
- switch ( yy_act )
- { /* beginning of action switch */
- case 0: /* must back up */
- /* undo the effects of YY_DO_BEFORE_ACTION */
- *yy_cp = (yy_hold_char);
- yy_cp = (yy_last_accepting_cpos);
- yy_current_state = (yy_last_accepting_state);
- goto yy_find_action;
-
-case 1:
-YY_RULE_SETUP
-#line 29 "lexer.l"
-{
- lmsg ("include starts\n");
- BEGIN (includestate);
-}
- YY_BREAK
-case 2:
-YY_RULE_SETUP
-#line 35 "lexer.l"
-{
- lmsg ("define starts\n");
- BEGIN (definestate);
-}
- YY_BREAK
-case 3:
-/* rule 3 can match eol */
-YY_RULE_SETUP
-#line 40 "lexer.l"
-{
- lmsg ("comment\n");
- yylineno++;
-}
- YY_BREAK
-case 4:
-YY_RULE_SETUP
-#line 45 "lexer.l"
-{
- lmsg ("options\n");
- return (OPTIONS);
-}
- YY_BREAK
-case 5:
-YY_RULE_SETUP
-#line 50 "lexer.l"
-{
- lmsg ("logactivity\n");
- return (LOGACTIVITY);
-}
- YY_BREAK
-case 6:
-YY_RULE_SETUP
-#line 55 "lexer.l"
-{
- lmsg ("tcpbuffersize\n");
- return (TCPBUFFERSIZE);
-}
- YY_BREAK
-case 7:
-YY_RULE_SETUP
-#line 60 "lexer.l"
-{
- lmsg ("dnscachettl\n");
- return (DNSCACHETTL);
-}
- YY_BREAK
-case 8:
-YY_RULE_SETUP
-#line 65 "lexer.l"
-{
- lmsg ("logfacility\n");
- return (LOGFACILITY);
-}
- YY_BREAK
-case 9:
-YY_RULE_SETUP
-#line 70 "lexer.l"
-{
- lmsg ("shmpermissions\n");
- return (SHMPERMISSIONS);
-}
- YY_BREAK
-case 10:
-YY_RULE_SETUP
-#line 75 "lexer.l"
-{
- lmsg ("sloppyportbind\n");
- return (SLOPPYPORTBIND);
-}
- YY_BREAK
-case 11:
-YY_RULE_SETUP
-#line 80 "lexer.l"
-{
- lmsg ("leaveprocesstitle\n");
- return (LEAVEPROCESSTITLE);
-}
- YY_BREAK
-case 12:
-YY_RULE_SETUP
-#line 85 "lexer.l"
-{
- lmsg ("service\n");
- return (SERVICE);
-}
- YY_BREAK
-case 13:
-YY_RULE_SETUP
-#line 90 "lexer.l"
-{
- lmsg ("bindto\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (BINDTO);
-}
- YY_BREAK
-case 14:
-YY_RULE_SETUP
-#line 98 "lexer.l"
-{
- lmsg ("port\n");
- return (PORT);
-}
- YY_BREAK
-case 15:
-YY_RULE_SETUP
-#line 103 "lexer.l"
-{
- lmsg ("over\n");
- return (OVER);
-}
- YY_BREAK
-case 16:
-YY_RULE_SETUP
-#line 108 "lexer.l"
-{
- lmsg ("shmkey\n");
- return (SHMKEY);
-}
- YY_BREAK
-case 17:
-YY_RULE_SETUP
-#line 113 "lexer.l"
-{
- lmsg ("backend\n");
- return (BACKEND);
-}
- YY_BREAK
-case 18:
-YY_RULE_SETUP
-#line 118 "lexer.l"
-{
- lmsg ("state\n");
- return (STATE);
-}
- YY_BREAK
-case 19:
-YY_RULE_SETUP
-#line 123 "lexer.l"
-{
- lmsg ("available\n");
- return (AVAILABLE);
-}
- YY_BREAK
-case 20:
-YY_RULE_SETUP
-#line 128 "lexer.l"
-{
- lmsg ("unavailable\n");
- return (UNAVAILABLE);
-}
- YY_BREAK
-case 21:
-YY_RULE_SETUP
-#line 133 "lexer.l"
-{
- lmsg ("down\n");
- return (DOWN);
-}
- YY_BREAK
-case 22:
-YY_RULE_SETUP
-#line 138 "lexer.l"
-{
- lmsg ("backlog\n");
- return (BACKLOG);
-}
- YY_BREAK
-case 23:
-YY_RULE_SETUP
-#line 143 "lexer.l"
-{
- lmsg ("retries\n");
- return (RETRIES);
-}
- YY_BREAK
-case 24:
-YY_RULE_SETUP
-#line 148 "lexer.l"
-{
- lmsg ("verbosity\n");
- return (VERBOSITY);
-}
- YY_BREAK
-case 25:
-YY_RULE_SETUP
-#line 153 "lexer.l"
-{
- lmsg ("connectiontimeout\n");
- return (CONNECTIONTIMEOUT);
-}
- YY_BREAK
-case 26:
-YY_RULE_SETUP
-#line 158 "lexer.l"
-{
- lmsg ("maxconnections\n");
- return (MAXCONNECTIONS);
-}
- YY_BREAK
-case 27:
-YY_RULE_SETUP
-#line 163 "lexer.l"
-{
- lmsg ("weight\n");
- return (WEIGHT);
-}
- YY_BREAK
-case 28:
-YY_RULE_SETUP
-#line 168 "lexer.l"
-{
- lmsg ("decay\n");
- return (DECAY);
-}
- YY_BREAK
-case 29:
-YY_RULE_SETUP
-#line 173 "lexer.l"
-{
- lmsg ("server\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (SERVER);
-}
- YY_BREAK
-case 30:
-YY_RULE_SETUP
-#line 181 "lexer.l"
-{
- lmsg ("dispatchmode\n");
- return (DISPATCHMODE);
-}
- YY_BREAK
-case 31:
-YY_RULE_SETUP
-#line 186 "lexer.l"
-{
- lmsg ("roundrobin\n");
- return (ROUNDROBIN);
-}
- YY_BREAK
-case 32:
-YY_RULE_SETUP
-#line 191 "lexer.l"
-{
- lmsg ("random\n");
- return (RANDOM);
-}
- YY_BREAK
-case 33:
-YY_RULE_SETUP
-#line 196 "lexer.l"
-{
- lmsg ("byduration\n");
- return (BYDURATION);
-}
- YY_BREAK
-case 34:
-YY_RULE_SETUP
-#line 201 "lexer.l"
-{
- lmsg ("bysize\n");
- return (BYSIZE);
-}
- YY_BREAK
-case 35:
-YY_RULE_SETUP
-#line 206 "lexer.l"
-{
- lmsg ("byorder\n");
- return (BYORDER);
-}
- YY_BREAK
-case 36:
-YY_RULE_SETUP
-#line 211 "lexer.l"
-{
- lmsg ("byconnections\n");
- return (BYCONNECTIONS);
-}
- YY_BREAK
-case 37:
-YY_RULE_SETUP
-#line 216 "lexer.l"
-{
- lmsg ("externalhandler\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (EXTERNALHANDLER);
-}
- YY_BREAK
-case 38:
-YY_RULE_SETUP
-#line 224 "lexer.l"
-{
- lmsg ("byclientip\n");
- return (BYCLIENTIP);
-}
- YY_BREAK
-case 39:
-YY_RULE_SETUP
-#line 229 "lexer.l"
-{
- lmsg ("useraccount\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (USERACCOUNT);
-}
- YY_BREAK
-case 40:
-YY_RULE_SETUP
-#line 237 "lexer.l"
-{
- lmsg ("revivinginterval\n");
- return (REVIVINGINTERVAL);
-}
- YY_BREAK
-case 41:
-YY_RULE_SETUP
-#line 242 "lexer.l"
-{
- lmsg ("checkinterval\n");
- return (CHECKINTERVAL);
-}
- YY_BREAK
-case 42:
-YY_RULE_SETUP
-#line 247 "lexer.l"
-{
- lmsg ("type\n");
- return (TYPE);
-}
- YY_BREAK
-case 43:
-YY_RULE_SETUP
-#line 252 "lexer.l"
-{
- lmsg ("headerinspection\n");
- return (HEADERINSPECTION);
-}
- YY_BREAK
-case 44:
-YY_RULE_SETUP
-#line 257 "lexer.l"
-{
- lmsg ("deep\n");
- return (DEEP);
-}
- YY_BREAK
-case 45:
-YY_RULE_SETUP
-#line 262 "lexer.l"
-{
- lmsg ("shallow\n");
- return (SHALLOW);
-}
- YY_BREAK
-case 46:
-YY_RULE_SETUP
-#line 267 "lexer.l"
-{
- lmsg ("any\n");
- return (ANY);
-}
- YY_BREAK
-case 47:
-YY_RULE_SETUP
-#line 272 "lexer.l"
-{
- lmsg ("stickyhttp\n");
- warning ("The 'stickyhttp protocol is obsolte.\n"
- "You should change to 'http'.");
- return (HTTP);
-}
- YY_BREAK
-case 48:
-YY_RULE_SETUP
-#line 279 "lexer.l"
-{
- lmsg ("http\n");
- return (HTTP);
-}
- YY_BREAK
-case 49:
-YY_RULE_SETUP
-#line 284 "lexer.l"
-{
- lmsg ("throughputlog\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (THROUGHPUTLOG);
-}
- YY_BREAK
-case 50:
-YY_RULE_SETUP
-#line 292 "lexer.l"
-{
- lmsg ("trafficlog\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (TRAFFICLOG);
-}
- YY_BREAK
-case 51:
-YY_RULE_SETUP
-#line 300 "lexer.l"
-{
- lmsg ("httptiminglog\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (HTTPTIMINGLOG);
-}
- YY_BREAK
-case 52:
-YY_RULE_SETUP
-#line 308 "lexer.l"
-{
- lmsg ("dumptraffic\n");
- warning ("The 'dumptraffic' statement is obsolete.\n"
- "You should change to 'trafficlog'.");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (TRAFFICLOG);
-}
- YY_BREAK
-case 53:
-YY_RULE_SETUP
-#line 318 "lexer.l"
-{
- lmsg ("onstart\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (ONSTART);
-}
- YY_BREAK
-case 54:
-YY_RULE_SETUP
-#line 326 "lexer.l"
-{
- lmsg ("onfail\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (ONFAIL);
-}
- YY_BREAK
-case 55:
-YY_RULE_SETUP
-#line 334 "lexer.l"
-{
- lmsg ("onend\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (ONEND);
-}
- YY_BREAK
-case 56:
-YY_RULE_SETUP
-#line 342 "lexer.l"
-{
- lmsg ("stickycookie\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (STICKYCOOKIE);
-}
- YY_BREAK
-case 57:
-YY_RULE_SETUP
-#line 350 "lexer.l"
-{
- lmsg ("addclientheader\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (ADDCLIENTHEADER);
-}
- YY_BREAK
-case 58:
-YY_RULE_SETUP
-#line 358 "lexer.l"
-{
- lmsg ("setclientheader\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (SETCLIENTHEADER);
-}
- YY_BREAK
-case 59:
-YY_RULE_SETUP
-#line 366 "lexer.l"
-{
- lmsg ("appendclientheader\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (APPENDCLIENTHEADER);
-}
- YY_BREAK
-case 60:
-YY_RULE_SETUP
-#line 374 "lexer.l"
-{
- lmsg ("addserverheader\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (ADDSERVERHEADER);
-}
- YY_BREAK
-case 61:
-YY_RULE_SETUP
-#line 382 "lexer.l"
-{
- lmsg ("setserverheader\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (SETSERVERHEADER);
-}
- YY_BREAK
-case 62:
-YY_RULE_SETUP
-#line 390 "lexer.l"
-{
- lmsg ("appendserverheader\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (APPENDSERVERHEADER);
-}
- YY_BREAK
-case 63:
-YY_RULE_SETUP
-#line 398 "lexer.l"
-{
- lmsg ("allowfrom\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (ALLOWFROM);
-}
- YY_BREAK
-case 64:
-YY_RULE_SETUP
-#line 406 "lexer.l"
-{
- lmsg ("denyfrom\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (DENYFROM);
-}
- YY_BREAK
-case 65:
-YY_RULE_SETUP
-#line 414 "lexer.l"
-{
- lmsg ("allowfile\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (ALLOWFILE);
-}
- YY_BREAK
-case 66:
-YY_RULE_SETUP
-#line 422 "lexer.l"
-{
- lmsg ("denyfile\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (DENYFILE);
-}
- YY_BREAK
-case 67:
-YY_RULE_SETUP
-#line 430 "lexer.l"
-{
- lmsg ("on\n");
- return (ON);
-}
- YY_BREAK
-case 68:
-YY_RULE_SETUP
-#line 435 "lexer.l"
-{
- lmsg ("off\n");
- return (OFF);
-}
- YY_BREAK
-case 69:
-YY_RULE_SETUP
-#line 440 "lexer.l"
-{
- lmsg ("identifier [%s]\n", yytext);
- return (IDENTIFIER);
-}
- YY_BREAK
-case 70:
-YY_RULE_SETUP
-#line 445 "lexer.l"
-{
- lmsg ("number [%s]\n", yytext);
- return (NUMBER);
-}
- YY_BREAK
-case 71:
-YY_RULE_SETUP
-#line 450 "lexer.l"
-{
- lmsg ("space(s)\n");
-}
- YY_BREAK
-case 72:
-/* rule 72 can match eol */
-YY_RULE_SETUP
-#line 454 "lexer.l"
-{
- lmsg ("newline\n");
- yylineno++;
-}
- YY_BREAK
-case 73:
-YY_RULE_SETUP
-#line 459 "lexer.l"
-{
- lmsg ("lone char ['%c' (ASCII %d)]\n",
- isprint(*yytext) ? *yytext : '.',
- *yytext);
- return (*yytext);
-}
- YY_BREAK
-case 74:
-YY_RULE_SETUP
-#line 466 "lexer.l"
-{
- lmsg ("C-comment starts\n");
- BEGIN(commentstate);
-}
- YY_BREAK
-case 75:
-YY_RULE_SETUP
-#line 470 "lexer.l"
-{
- lmsg ("C-comment ends\n");
- BEGIN(0);
-}
- YY_BREAK
-case 76:
-/* rule 76 can match eol */
-YY_RULE_SETUP
-#line 474 "lexer.l"
-{
- yylineno++;
-}
- YY_BREAK
-case 77:
-YY_RULE_SETUP
-#line 477 "lexer.l"
-;
- YY_BREAK
-case 78:
-/* rule 78 can match eol */
-YY_RULE_SETUP
-#line 479 "lexer.l"
-{
- lmsg ("string state: skipping initial spaces [ASCII %d]\n", *yytext);
- if (*yytext == '\n')
- yylineno++;
-}
- YY_BREAK
-case 79:
-YY_RULE_SETUP
-#line 484 "lexer.l"
-{
- lmsg ("string state: entering instring on [%s (ASCII %d)]\n",
- yytext, *yytext);
- unput (*yytext);
- BEGIN (instr);
-}
- YY_BREAK
-case 80:
-YY_RULE_SETUP
-#line 491 "lexer.l"
-{
- lmsg ("string part [%s]\n", yytext);
- laststring = xstrcat (laststring, yytext);
-}
- YY_BREAK
-case 81:
-/* rule 81 can match eol */
-YY_RULE_SETUP
-#line 496 "lexer.l"
-{
- lmsg ("string part in double quotes [%s]\n", yytext);
- laststring = xstrcat (laststring, yytext + 1);
- laststring[strlen(laststring) - 1] = 0;
-}
- YY_BREAK
-case 82:
-/* rule 82 can match eol */
-YY_RULE_SETUP
-#line 501 "lexer.l"
-{
- lmsg ("string part in single quotes [%s]\n", yytext);
- laststring = xstrcat (laststring, yytext + 1);
- laststring[strlen(laststring) - 1] = 0;
-}
- YY_BREAK
-case 83:
-YY_RULE_SETUP
-#line 506 "lexer.l"
-{
- BEGIN (0);
- /* Strip terminating whitespace incase the ; is preceded by them */
- if (laststring && *laststring)
- for (i = strlen(laststring) - 1; i >= 0 && isspace(laststring[i]); i--)
- laststring[i] = 0;
- unput (';');
- lmsg ("string complete [%s]\n", laststring);
- return (STRING);
-}
- YY_BREAK
-case 84:
-YY_RULE_SETUP
-#line 516 "lexer.l"
-{
- if (laststring) {
- laststring = xstrcat (laststring, yytext);
- lmsg ("string part space [%s]\n", yytext);
- }
-}
- YY_BREAK
-case 85:
-YY_RULE_SETUP
-#line 522 "lexer.l"
-{
- lmsg ("string part char [%s]\n", yytext);
- laststring = xstrcat (laststring, yytext);
-}
- YY_BREAK
-case 86:
-/* rule 86 can match eol */
-YY_RULE_SETUP
-#line 526 "lexer.l"
-{
- if (laststring) {
- laststring = xstrcat (laststring, " ");
- lmsg ("string part: newline, now space\n");
- }
- yylineno++;
-}
- YY_BREAK
-case 87:
-YY_RULE_SETUP
-#line 534 "lexer.l"
-{
- lmsg ("includefile\n");
- /* parser_skipline(); */
- parser_open (yytext);
- BEGIN (0);
-}
- YY_BREAK
-case YY_STATE_EOF(includestate):
-#line 540 "lexer.l"
-{
- error ("Unterminated #include");
-}
- YY_BREAK
-case 88:
-YY_RULE_SETUP
-#line 543 "lexer.l"
-;
- YY_BREAK
-case 89:
-/* rule 89 can match eol */
-YY_RULE_SETUP
-#line 544 "lexer.l"
-{
- yylineno++;
-}
- YY_BREAK
-case 90:
-YY_RULE_SETUP
-#line 547 "lexer.l"
-{
- error ("Illegal character 0x%2.2x in #include line", *yytext);
-}
- YY_BREAK
-case 91:
-YY_RULE_SETUP
-#line 551 "lexer.l"
-;
- YY_BREAK
-case 92:
-YY_RULE_SETUP
-#line 552 "lexer.l"
-{
- symtab_start (yytext);
- BEGIN (defineredef);
-}
- YY_BREAK
-case YY_STATE_EOF(definestate):
-case YY_STATE_EOF(defineredef):
-case YY_STATE_EOF(definesym):
-#line 556 "lexer.l"
-{
- error ("Unterminated #define");
-}
- YY_BREAK
-case 93:
-/* rule 93 can match eol */
-YY_RULE_SETUP
-#line 559 "lexer.l"
-{
- error ("Unterminated #define");
-}
- YY_BREAK
-case 94:
-YY_RULE_SETUP
-#line 562 "lexer.l"
-{
- error ("Unrecognized character '%c' in #define", *yytext);
-}
- YY_BREAK
-case 95:
-YY_RULE_SETUP
-#line 566 "lexer.l"
-{
- BEGIN (definesym);
-}
- YY_BREAK
-case 96:
-YY_RULE_SETUP
-#line 569 "lexer.l"
-{
- symtab_set (yytext);
-}
- YY_BREAK
-case 97:
-/* rule 97 can match eol */
-YY_RULE_SETUP
-#line 572 "lexer.l"
-{
- yylineno++;
- symtab_end();
- BEGIN (0);
-}
- YY_BREAK
-case 98:
-YY_RULE_SETUP
-#line 577 "lexer.l"
-ECHO;
- YY_BREAK
-#line 1977 "lexer.c"
-case YY_STATE_EOF(INITIAL):
-case YY_STATE_EOF(stringstate):
-case YY_STATE_EOF(instr):
-case YY_STATE_EOF(commentstate):
- yyterminate();
-
- case YY_END_OF_BUFFER:
- {
- /* Amount of text matched not including the EOB char. */
- int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
-
- /* Undo the effects of YY_DO_BEFORE_ACTION. */
- *yy_cp = (yy_hold_char);
- YY_RESTORE_YY_MORE_OFFSET
-
- if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
- {
- /* We're scanning a new file or input source. It's
- * possible that this happened because the user
- * just pointed yyin at a new source and called
- * yylex(). If so, then we have to assure
- * consistency between YY_CURRENT_BUFFER and our
- * globals. Here is the right place to do so, because
- * this is the first action (other than possibly a
- * back-up) that will match for the new input source.
- */
- (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
- YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
- YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
- }
-
- /* Note that here we test for yy_c_buf_p "<=" to the position
- * of the first EOB in the buffer, since yy_c_buf_p will
- * already have been incremented past the NUL character
- * (since all states make transitions on EOB to the
- * end-of-buffer state). Contrast this with the test
- * in input().
- */
- if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
- { /* This was really a NUL. */
- yy_state_type yy_next_state;
-
- (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
-
- yy_current_state = yy_get_previous_state( );
-
- /* Okay, we're now positioned to make the NUL
- * transition. We couldn't have
- * yy_get_previous_state() go ahead and do it
- * for us because it doesn't know how to deal
- * with the possibility of jamming (and we don't
- * want to build jamming into it because then it
- * will run more slowly).
- */
-
- yy_next_state = yy_try_NUL_trans( yy_current_state );
-
- yy_bp = (yytext_ptr) + YY_MORE_ADJ;
-
- if ( yy_next_state )
- {
- /* Consume the NUL. */
- yy_cp = ++(yy_c_buf_p);
- yy_current_state = yy_next_state;
- goto yy_match;
- }
-
- else
- {
- yy_cp = (yy_c_buf_p);
- goto yy_find_action;
- }
- }
-
- else switch ( yy_get_next_buffer( ) )
- {
- case EOB_ACT_END_OF_FILE:
- {
- (yy_did_buffer_switch_on_eof) = 0;
-
- if ( yywrap( ) )
- {
- /* Note: because we've taken care in
- * yy_get_next_buffer() to have set up
- * yytext, we can now set up
- * yy_c_buf_p so that if some total
- * hoser (like flex itself) wants to
- * call the scanner after we return the
- * YY_NULL, it'll still work - another
- * YY_NULL will get returned.
- */
- (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
-
- yy_act = YY_STATE_EOF(YY_START);
- goto do_action;
- }
-
- else
- {
- if ( ! (yy_did_buffer_switch_on_eof) )
- YY_NEW_FILE;
- }
- break;
- }
-
- case EOB_ACT_CONTINUE_SCAN:
- (yy_c_buf_p) =
- (yytext_ptr) + yy_amount_of_matched_text;
-
- yy_current_state = yy_get_previous_state( );
-
- yy_cp = (yy_c_buf_p);
- yy_bp = (yytext_ptr) + YY_MORE_ADJ;
- goto yy_match;
-
- case EOB_ACT_LAST_MATCH:
- (yy_c_buf_p) =
- &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
-
- yy_current_state = yy_get_previous_state( );
-
- yy_cp = (yy_c_buf_p);
- yy_bp = (yytext_ptr) + YY_MORE_ADJ;
- goto yy_find_action;
- }
- break;
- }
-
- default:
- YY_FATAL_ERROR(
- "fatal flex scanner internal error--no action found" );
- } /* end of action switch */
- } /* end of scanning one token */
-} /* end of yylex */
-
-/* yy_get_next_buffer - try to read in a new buffer
- *
- * Returns a code representing an action:
- * EOB_ACT_LAST_MATCH -
- * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
- * EOB_ACT_END_OF_FILE - end of file
- */
-static int yy_get_next_buffer (void)
-{
- register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
- register char *source = (yytext_ptr);
- register int number_to_move, i;
- int ret_val;
-
- if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
- YY_FATAL_ERROR(
- "fatal flex scanner internal error--end of buffer missed" );
-
- if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
- { /* Don't try to fill the buffer, so this is an EOF. */
- if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
- {
- /* We matched a single character, the EOB, so
- * treat this as a final EOF.
- */
- return EOB_ACT_END_OF_FILE;
- }
-
- else
- {
- /* We matched some text prior to the EOB, first
- * process it.
- */
- return EOB_ACT_LAST_MATCH;
- }
- }
-
- /* Try to read more data. */
-
- /* First move last chars to start of buffer. */
- number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
-
- for ( i = 0; i < number_to_move; ++i )
- *(dest++) = *(source++);
-
- if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
- /* don't do the read, it's not guaranteed to return an EOF,
- * just force an EOF
- */
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
-
- else
- {
- int num_to_read =
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
-
- while ( num_to_read <= 0 )
- { /* Not enough room in the buffer - grow it. */
-
- /* just a shorter name for the current buffer */
- YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
-
- int yy_c_buf_p_offset =
- (int) ((yy_c_buf_p) - b->yy_ch_buf);
-
- if ( b->yy_is_our_buffer )
- {
- int new_size = b->yy_buf_size * 2;
-
- if ( new_size <= 0 )
- b->yy_buf_size += b->yy_buf_size / 8;
- else
- b->yy_buf_size *= 2;
-
- b->yy_ch_buf = (char *)
- /* Include room in for 2 EOB chars. */
- yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
- }
- else
- /* Can't grow it, we don't own it. */
- b->yy_ch_buf = 0;
-
- if ( ! b->yy_ch_buf )
- YY_FATAL_ERROR(
- "fatal error - scanner input buffer overflow" );
-
- (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
-
- num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
- number_to_move - 1;
-
- }
-
- if ( num_to_read > YY_READ_BUF_SIZE )
- num_to_read = YY_READ_BUF_SIZE;
-
- /* Read in more data. */
- YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
- (yy_n_chars), num_to_read );
-
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
- }
-
- if ( (yy_n_chars) == 0 )
- {
- if ( number_to_move == YY_MORE_ADJ )
- {
- ret_val = EOB_ACT_END_OF_FILE;
- yyrestart(yyin );
- }
-
- else
- {
- ret_val = EOB_ACT_LAST_MATCH;
- YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
- YY_BUFFER_EOF_PENDING;
- }
- }
-
- else
- ret_val = EOB_ACT_CONTINUE_SCAN;
-
- (yy_n_chars) += number_to_move;
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
-
- (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
-
- return ret_val;
-}
-
-/* yy_get_previous_state - get the state just before the EOB char was reached */
-
- static yy_state_type yy_get_previous_state (void)
-{
- register yy_state_type yy_current_state;
- register char *yy_cp;
-
- yy_current_state = (yy_start);
- yy_current_state += YY_AT_BOL();
-
- for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
- {
- register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
- if ( yy_accept[yy_current_state] )
- {
- (yy_last_accepting_state) = yy_current_state;
- (yy_last_accepting_cpos) = yy_cp;
- }
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 616 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- }
-
- return yy_current_state;
-}
-
-/* yy_try_NUL_trans - try to make a transition on the NUL character
- *
- * synopsis
- * next_state = yy_try_NUL_trans( current_state );
- */
- static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
-{
- register int yy_is_jam;
- register char *yy_cp = (yy_c_buf_p);
-
- register YY_CHAR yy_c = 1;
- if ( yy_accept[yy_current_state] )
- {
- (yy_last_accepting_state) = yy_current_state;
- (yy_last_accepting_cpos) = yy_cp;
- }
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 616 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- yy_is_jam = (yy_current_state == 615);
-
- return yy_is_jam ? 0 : yy_current_state;
-}
-
- static void yyunput (int c, register char * yy_bp )
-{
- register char *yy_cp;
-
- yy_cp = (yy_c_buf_p);
-
- /* undo effects of setting up yytext */
- *yy_cp = (yy_hold_char);
-
- if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
- { /* need to shift things up to make room */
- /* +2 for EOB chars. */
- register int number_to_move = (yy_n_chars) + 2;
- register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
- register char *source =
- &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
-
- while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
- *--dest = *--source;
-
- yy_cp += (int) (dest - source);
- yy_bp += (int) (dest - source);
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
- (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
-
- if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
- YY_FATAL_ERROR( "flex scanner push-back overflow" );
- }
-
- *--yy_cp = (char) c;
-
- (yytext_ptr) = yy_bp;
- (yy_hold_char) = *yy_cp;
- (yy_c_buf_p) = yy_cp;
-}
-
-#ifndef YY_NO_INPUT
-#ifdef __cplusplus
- static int yyinput (void)
-#else
- static int input (void)
-#endif
-
-{
- int c;
-
- *(yy_c_buf_p) = (yy_hold_char);
-
- if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
- {
- /* yy_c_buf_p now points to the character we want to return.
- * If this occurs *before* the EOB characters, then it's a
- * valid NUL; if not, then we've hit the end of the buffer.
- */
- if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
- /* This was really a NUL. */
- *(yy_c_buf_p) = '\0';
-
- else
- { /* need more input */
- int offset = (yy_c_buf_p) - (yytext_ptr);
- ++(yy_c_buf_p);
-
- switch ( yy_get_next_buffer( ) )
- {
- case EOB_ACT_LAST_MATCH:
- /* This happens because yy_g_n_b()
- * sees that we've accumulated a
- * token and flags that we need to
- * try matching the token before
- * proceeding. But for input(),
- * there's no matching to consider.
- * So convert the EOB_ACT_LAST_MATCH
- * to EOB_ACT_END_OF_FILE.
- */
-
- /* Reset buffer status. */
- yyrestart(yyin );
-
- /*FALLTHROUGH*/
-
- case EOB_ACT_END_OF_FILE:
- {
- if ( yywrap( ) )
- return 0;
-
- if ( ! (yy_did_buffer_switch_on_eof) )
- YY_NEW_FILE;
-#ifdef __cplusplus
- return yyinput();
-#else
- return input();
-#endif
- }
-
- case EOB_ACT_CONTINUE_SCAN:
- (yy_c_buf_p) = (yytext_ptr) + offset;
- break;
- }
- }
- }
-
- c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
- *(yy_c_buf_p) = '\0'; /* preserve yytext */
- (yy_hold_char) = *++(yy_c_buf_p);
-
- YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
-
- return c;
-}
-#endif /* ifndef YY_NO_INPUT */
-
-/** Immediately switch to a different input stream.
- * @param input_file A readable stream.
- *
- * @note This function does not reset the start condition to @c INITIAL .
- */
- void yyrestart (FILE * input_file )
-{
-
- if ( ! YY_CURRENT_BUFFER ){
- yyensure_buffer_stack ();
- YY_CURRENT_BUFFER_LVALUE =
- yy_create_buffer(yyin,YY_BUF_SIZE );
- }
-
- yy_init_buffer(YY_CURRENT_BUFFER,input_file );
- yy_load_buffer_state( );
-}
-
-/** Switch to a different input buffer.
- * @param new_buffer The new input buffer.
- *
- */
- void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
-{
-
- /* TODO. We should be able to replace this entire function body
- * with
- * yypop_buffer_state();
- * yypush_buffer_state(new_buffer);
- */
- yyensure_buffer_stack ();
- if ( YY_CURRENT_BUFFER == new_buffer )
- return;
-
- if ( YY_CURRENT_BUFFER )
- {
- /* Flush out information for old buffer. */
- *(yy_c_buf_p) = (yy_hold_char);
- YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
- }
-
- YY_CURRENT_BUFFER_LVALUE = new_buffer;
- yy_load_buffer_state( );
-
- /* We don't actually know whether we did this switch during
- * EOF (yywrap()) processing, but the only time this flag
- * is looked at is after yywrap() is called, so it's safe
- * to go ahead and always set it.
- */
- (yy_did_buffer_switch_on_eof) = 1;
-}
-
-static void yy_load_buffer_state (void)
-{
- (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
- (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
- yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
- (yy_hold_char) = *(yy_c_buf_p);
-}
-
-/** Allocate and initialize an input buffer state.
- * @param file A readable stream.
- * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
- *
- * @return the allocated buffer state.
- */
- YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
-{
- YY_BUFFER_STATE b;
-
- b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
- if ( ! b )
- YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
- b->yy_buf_size = size;
-
- /* yy_ch_buf has to be 2 characters longer than the size given because
- * we need to put in 2 end-of-buffer characters.
- */
- b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 );
- if ( ! b->yy_ch_buf )
- YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
- b->yy_is_our_buffer = 1;
-
- yy_init_buffer(b,file );
-
- return b;
-}
-
-/** Destroy the buffer.
- * @param b a buffer created with yy_create_buffer()
- *
- */
- void yy_delete_buffer (YY_BUFFER_STATE b )
-{
-
- if ( ! b )
- return;
-
- if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
- YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
-
- if ( b->yy_is_our_buffer )
- yyfree((void *) b->yy_ch_buf );
-
- yyfree((void *) b );
-}
-
-#ifndef __cplusplus
-extern int isatty (int );
-#endif /* __cplusplus */
-
-/* Initializes or reinitializes a buffer.
- * This function is sometimes called more than once on the same buffer,
- * such as during a yyrestart() or at EOF.
- */
- static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
-
-{
- int oerrno = errno;
-
- yy_flush_buffer(b );
-
- b->yy_input_file = file;
- b->yy_fill_buffer = 1;
-
- /* If b is the current buffer, then yy_init_buffer was _probably_
- * called from yyrestart() or through yy_get_next_buffer.
- * In that case, we don't want to reset the lineno or column.
- */
- if (b != YY_CURRENT_BUFFER){
- b->yy_bs_lineno = 1;
- b->yy_bs_column = 0;
- }
-
- b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
-
- errno = oerrno;
-}
-
-/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
- * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
- *
- */
- void yy_flush_buffer (YY_BUFFER_STATE b )
-{
- if ( ! b )
- return;
-
- b->yy_n_chars = 0;
-
- /* We always need two end-of-buffer characters. The first causes
- * a transition to the end-of-buffer state. The second causes
- * a jam in that state.
- */
- b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
- b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
-
- b->yy_buf_pos = &b->yy_ch_buf[0];
-
- b->yy_at_bol = 1;
- b->yy_buffer_status = YY_BUFFER_NEW;
-
- if ( b == YY_CURRENT_BUFFER )
- yy_load_buffer_state( );
-}
-
-/** Pushes the new state onto the stack. The new state becomes
- * the current state. This function will allocate the stack
- * if necessary.
- * @param new_buffer The new state.
- *
- */
-void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
-{
- if (new_buffer == NULL)
- return;
-
- yyensure_buffer_stack();
-
- /* This block is copied from yy_switch_to_buffer. */
- if ( YY_CURRENT_BUFFER )
- {
- /* Flush out information for old buffer. */
- *(yy_c_buf_p) = (yy_hold_char);
- YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
- }
-
- /* Only push if top exists. Otherwise, replace top. */
- if (YY_CURRENT_BUFFER)
- (yy_buffer_stack_top)++;
- YY_CURRENT_BUFFER_LVALUE = new_buffer;
-
- /* copied from yy_switch_to_buffer. */
- yy_load_buffer_state( );
- (yy_did_buffer_switch_on_eof) = 1;
-}
-
-/** Removes and deletes the top of the stack, if present.
- * The next element becomes the new top.
- *
- */
-void yypop_buffer_state (void)
-{
- if (!YY_CURRENT_BUFFER)
- return;
-
- yy_delete_buffer(YY_CURRENT_BUFFER );
- YY_CURRENT_BUFFER_LVALUE = NULL;
- if ((yy_buffer_stack_top) > 0)
- --(yy_buffer_stack_top);
-
- if (YY_CURRENT_BUFFER) {
- yy_load_buffer_state( );
- (yy_did_buffer_switch_on_eof) = 1;
- }
-}
-
-/* Allocates the stack if it does not exist.
- * Guarantees space for at least one push.
- */
-static void yyensure_buffer_stack (void)
-{
- int num_to_alloc;
-
- if (!(yy_buffer_stack)) {
-
- /* First allocation is just for 2 elements, since we don't know if this
- * scanner will even need a stack. We use 2 instead of 1 to avoid an
- * immediate realloc on the next call.
- */
- num_to_alloc = 1;
- (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
- (num_to_alloc * sizeof(struct yy_buffer_state*)
- );
-
- memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-
- (yy_buffer_stack_max) = num_to_alloc;
- (yy_buffer_stack_top) = 0;
- return;
- }
-
- if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
-
- /* Increase the buffer to prepare for a possible push. */
- int grow_size = 8 /* arbitrary grow size */;
-
- num_to_alloc = (yy_buffer_stack_max) + grow_size;
- (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
- ((yy_buffer_stack),
- num_to_alloc * sizeof(struct yy_buffer_state*)
- );
-
- /* zero only the new slots.*/
- memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
- (yy_buffer_stack_max) = num_to_alloc;
- }
-}
-
-/** Setup the input buffer state to scan directly from a user-specified character buffer.
- * @param base the character buffer
- * @param size the size in bytes of the character buffer
- *
- * @return the newly allocated buffer state object.
- */
-YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
-{
- YY_BUFFER_STATE b;
-
- if ( size < 2 ||
- base[size-2] != YY_END_OF_BUFFER_CHAR ||
- base[size-1] != YY_END_OF_BUFFER_CHAR )
- /* They forgot to leave room for the EOB's. */
- return 0;
-
- b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
- if ( ! b )
- YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
-
- b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
- b->yy_buf_pos = b->yy_ch_buf = base;
- b->yy_is_our_buffer = 0;
- b->yy_input_file = 0;
- b->yy_n_chars = b->yy_buf_size;
- b->yy_is_interactive = 0;
- b->yy_at_bol = 1;
- b->yy_fill_buffer = 0;
- b->yy_buffer_status = YY_BUFFER_NEW;
-
- yy_switch_to_buffer(b );
-
- return b;
-}
-
-/** Setup the input buffer state to scan a string. The next call to yylex() will
- * scan from a @e copy of @a str.
- * @param str a NUL-terminated string to scan
- *
- * @return the newly allocated buffer state object.
- * @note If you want to scan bytes that may contain NUL values, then use
- * yy_scan_bytes() instead.
- */
-YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
-{
-
- return yy_scan_bytes(yystr,strlen(yystr) );
-}
-
-/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
- * scan from a @e copy of @a bytes.
- * @param bytes the byte buffer to scan
- * @param len the number of bytes in the buffer pointed to by @a bytes.
- *
- * @return the newly allocated buffer state object.
- */
-YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
-{
- YY_BUFFER_STATE b;
- char *buf;
- yy_size_t n;
- int i;
-
- /* Get memory for full buffer, including space for trailing EOB's. */
- n = _yybytes_len + 2;
- buf = (char *) yyalloc(n );
- if ( ! buf )
- YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
-
- for ( i = 0; i < _yybytes_len; ++i )
- buf[i] = yybytes[i];
-
- buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
-
- b = yy_scan_buffer(buf,n );
- if ( ! b )
- YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
-
- /* It's okay to grow etc. this buffer, and we should throw it
- * away when we're done.
- */
- b->yy_is_our_buffer = 1;
-
- return b;
-}
-
-#ifndef YY_EXIT_FAILURE
-#define YY_EXIT_FAILURE 2
-#endif
-
-static void yy_fatal_error (yyconst char* msg )
-{
- (void) fprintf( stderr, "%s\n", msg );
- exit( YY_EXIT_FAILURE );
-}
-
-/* Redefine yyless() so it works in section 3 code. */
-
-#undef yyless
-#define yyless(n) \
- do \
- { \
- /* Undo effects of setting up yytext. */ \
- int yyless_macro_arg = (n); \
- YY_LESS_LINENO(yyless_macro_arg);\
- yytext[yyleng] = (yy_hold_char); \
- (yy_c_buf_p) = yytext + yyless_macro_arg; \
- (yy_hold_char) = *(yy_c_buf_p); \
- *(yy_c_buf_p) = '\0'; \
- yyleng = yyless_macro_arg; \
- } \
- while ( 0 )
-
-/* Accessor methods (get/set functions) to struct members. */
-
-/** Get the current line number.
- *
- */
-int yyget_lineno (void)
-{
-
- return yylineno;
-}
-
-/** Get the input stream.
- *
- */
-FILE *yyget_in (void)
-{
- return yyin;
-}
-
-/** Get the output stream.
- *
- */
-FILE *yyget_out (void)
-{
- return yyout;
-}
-
-/** Get the length of the current token.
- *
- */
-int yyget_leng (void)
-{
- return yyleng;
-}
-
-/** Get the current token.
- *
- */
-
-char *yyget_text (void)
-{
- return yytext;
-}
-
-/** Set the current line number.
- * @param line_number
- *
- */
-void yyset_lineno (int line_number )
-{
-
- yylineno = line_number;
-}
-
-/** Set the input stream. This does not discard the current
- * input buffer.
- * @param in_str A readable stream.
- *
- * @see yy_switch_to_buffer
- */
-void yyset_in (FILE * in_str )
-{
- yyin = in_str ;
-}
-
-void yyset_out (FILE * out_str )
-{
- yyout = out_str ;
-}
-
-int yyget_debug (void)
-{
- return yy_flex_debug;
-}
-
-void yyset_debug (int bdebug )
-{
- yy_flex_debug = bdebug ;
-}
-
-static int yy_init_globals (void)
-{
- /* Initialization is the same as for the non-reentrant scanner.
- * This function is called from yylex_destroy(), so don't allocate here.
- */
-
- (yy_buffer_stack) = 0;
- (yy_buffer_stack_top) = 0;
- (yy_buffer_stack_max) = 0;
- (yy_c_buf_p) = (char *) 0;
- (yy_init) = 0;
- (yy_start) = 0;
-
-/* Defined in main.c */
-#ifdef YY_STDINIT
- yyin = stdin;
- yyout = stdout;
-#else
- yyin = (FILE *) 0;
- yyout = (FILE *) 0;
-#endif
-
- /* For future reference: Set errno on error, since we are called by
- * yylex_init()
- */
- return 0;
-}
-
-/* yylex_destroy is for both reentrant and non-reentrant scanners. */
-int yylex_destroy (void)
-{
-
- /* Pop the buffer stack, destroying each element. */
- while(YY_CURRENT_BUFFER){
- yy_delete_buffer(YY_CURRENT_BUFFER );
- YY_CURRENT_BUFFER_LVALUE = NULL;
- yypop_buffer_state();
- }
-
- /* Destroy the stack itself. */
- yyfree((yy_buffer_stack) );
- (yy_buffer_stack) = NULL;
-
- /* Reset the globals. This is important in a non-reentrant scanner so the next time
- * yylex() is called, initialization will occur. */
- yy_init_globals( );
-
- return 0;
-}
-
-/*
- * Internal utility routines.
- */
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
-{
- register int i;
- for ( i = 0; i < n; ++i )
- s1[i] = s2[i];
-}
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * s )
-{
- register int n;
- for ( n = 0; s[n]; ++n )
- ;
-
- return n;
-}
-#endif
-
-void *yyalloc (yy_size_t size )
-{
- return (void *) malloc( size );
-}
-
-void *yyrealloc (void * ptr, yy_size_t size )
-{
- /* The cast to (char *) in the following accommodates both
- * implementations that use char* generic pointers, and those
- * that use void* generic pointers. It works with the latter
- * because both ANSI C and C++ allow castless assignment from
- * any pointer type to void*, and deal with argument conversions
- * as though doing an assignment.
- */
- return (void *) realloc( (char *) ptr, size );
-}
-
-void yyfree (void * ptr )
-{
- free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
-}
-
-#define YYTABLES_NAME "yytables"
-
-#line 577 "lexer.l"
diff --git a/src/lib/lexer.l b/src/lib/lexer.l
@@ -1,576 +0,0 @@
-%{
-#include "../crossroads.h"
-#include "parser.h"
-
-/* Redefinition of YY_INPUT to respect the parserstate. */
-#define YY_INPUT(buf,res,max) (res) = parser_input( (buf), (max) )
-#define yywrap parser_close
-
-/* Globals */
-static int i;
-
-/* Lexer debugging related */
-static void lmsg (char const *fmt, ...) {
- va_list args;
-
- if (parser_debug) {
- va_start (args, fmt);
- printf ("LEXER: ");
- vprintf (fmt, args);
- }
-}
-%}
-
-%pointer
-%x stringstate instr commentstate includestate definestate defineredef definesym
-
-%%
-
-^#[ \t]*include {
- lmsg ("include starts\n");
- BEGIN (includestate);
-}
-
-
-^#[ \t]*define {
- lmsg ("define starts\n");
- BEGIN (definestate);
-}
-
-\/\/.*\n {
- lmsg ("comment\n");
- yylineno++;
-}
-
-options {
- lmsg ("options\n");
- return (OPTIONS);
-}
-
-logactivity {
- lmsg ("logactivity\n");
- return (LOGACTIVITY);
-}
-
-tcpbuffersize {
- lmsg ("tcpbuffersize\n");
- return (TCPBUFFERSIZE);
-}
-
-dnscachettl {
- lmsg ("dnscachettl\n");
- return (DNSCACHETTL);
-}
-
-logfacility {
- lmsg ("logfacility\n");
- return (LOGFACILITY);
-}
-
-shmpermissions {
- lmsg ("shmpermissions\n");
- return (SHMPERMISSIONS);
-}
-
-sloppyportbind {
- lmsg ("sloppyportbind\n");
- return (SLOPPYPORTBIND);
-}
-
-leaveprocesstitle {
- lmsg ("leaveprocesstitle\n");
- return (LEAVEPROCESSTITLE);
-}
-
-service {
- lmsg ("service\n");
- return (SERVICE);
-}
-
-bindto {
- lmsg ("bindto\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (BINDTO);
-}
-
-port {
- lmsg ("port\n");
- return (PORT);
-}
-
-over {
- lmsg ("over\n");
- return (OVER);
-}
-
-shmkey {
- lmsg ("shmkey\n");
- return (SHMKEY);
-}
-
-backend {
- lmsg ("backend\n");
- return (BACKEND);
-}
-
-state {
- lmsg ("state\n");
- return (STATE);
-}
-
-(available)|(up) {
- lmsg ("available\n");
- return (AVAILABLE);
-}
-
-unavailable {
- lmsg ("unavailable\n");
- return (UNAVAILABLE);
-}
-
-down {
- lmsg ("down\n");
- return (DOWN);
-}
-
-backlog {
- lmsg ("backlog\n");
- return (BACKLOG);
-}
-
-retries {
- lmsg ("retries\n");
- return (RETRIES);
-}
-
-(verbosity)|(verbose) {
- lmsg ("verbosity\n");
- return (VERBOSITY);
-}
-
-connectiontimeout {
- lmsg ("connectiontimeout\n");
- return (CONNECTIONTIMEOUT);
-}
-
-maxconnections {
- lmsg ("maxconnections\n");
- return (MAXCONNECTIONS);
-}
-
-weight {
- lmsg ("weight\n");
- return (WEIGHT);
-}
-
-decay {
- lmsg ("decay\n");
- return (DECAY);
-}
-
-server {
- lmsg ("server\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (SERVER);
-}
-
-dispatchmode {
- lmsg ("dispatchmode\n");
- return (DISPATCHMODE);
-}
-
-roundrobin {
- lmsg ("roundrobin\n");
- return (ROUNDROBIN);
-}
-
-random {
- lmsg ("random\n");
- return (RANDOM);
-}
-
-byduration {
- lmsg ("byduration\n");
- return (BYDURATION);
-}
-
-bysize {
- lmsg ("bysize\n");
- return (BYSIZE);
-}
-
-byorder {
- lmsg ("byorder\n");
- return (BYORDER);
-}
-
-byconnections {
- lmsg ("byconnections\n");
- return (BYCONNECTIONS);
-}
-
-externalhandler {
- lmsg ("externalhandler\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (EXTERNALHANDLER);
-}
-
-byclientip {
- lmsg ("byclientip\n");
- return (BYCLIENTIP);
-}
-
-useraccount {
- lmsg ("useraccount\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (USERACCOUNT);
-}
-
-revivinginterval {
- lmsg ("revivinginterval\n");
- return (REVIVINGINTERVAL);
-}
-
-checkinterval {
- lmsg ("checkinterval\n");
- return (CHECKINTERVAL);
-}
-
-type {
- lmsg ("type\n");
- return (TYPE);
-}
-
-headerinspection {
- lmsg ("headerinspection\n");
- return (HEADERINSPECTION);
-}
-
-deep {
- lmsg ("deep\n");
- return (DEEP);
-}
-
-shallow {
- lmsg ("shallow\n");
- return (SHALLOW);
-}
-
-any {
- lmsg ("any\n");
- return (ANY);
-}
-
-stickyhttp {
- lmsg ("stickyhttp\n");
- warning ("The 'stickyhttp protocol is obsolte.\n"
- "You should change to 'http'.");
- return (HTTP);
-}
-
-http {
- lmsg ("http\n");
- return (HTTP);
-}
-
-throughputlog {
- lmsg ("throughputlog\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (THROUGHPUTLOG);
-}
-
-trafficlog {
- lmsg ("trafficlog\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (TRAFFICLOG);
-}
-
-httptiminglog {
- lmsg ("httptiminglog\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (HTTPTIMINGLOG);
-}
-
-dumptraffic {
- lmsg ("dumptraffic\n");
- warning ("The 'dumptraffic' statement is obsolete.\n"
- "You should change to 'trafficlog'.");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (TRAFFICLOG);
-}
-
-onstart {
- lmsg ("onstart\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (ONSTART);
-}
-
-onfail {
- lmsg ("onfail\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (ONFAIL);
-}
-
-onend {
- lmsg ("onend\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (ONEND);
-}
-
-stickycookie {
- lmsg ("stickycookie\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (STICKYCOOKIE);
-}
-
-addclientheader {
- lmsg ("addclientheader\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (ADDCLIENTHEADER);
-}
-
-setclientheader {
- lmsg ("setclientheader\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (SETCLIENTHEADER);
-}
-
-appendclientheader {
- lmsg ("appendclientheader\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (APPENDCLIENTHEADER);
-}
-
-addserverheader {
- lmsg ("addserverheader\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (ADDSERVERHEADER);
-}
-
-setserverheader {
- lmsg ("setserverheader\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (SETSERVERHEADER);
-}
-
-appendserverheader {
- lmsg ("appendserverheader\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (APPENDSERVERHEADER);
-}
-
-allowfrom {
- lmsg ("allowfrom\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (ALLOWFROM);
-}
-
-denyfrom {
- lmsg ("denyfrom\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (DENYFROM);
-}
-
-allowfile {
- lmsg ("allowfile\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (ALLOWFILE);
-}
-
-denyfile {
- lmsg ("denyfile\n");
- BEGIN (stringstate);
- free (laststring);
- laststring = 0;
- return (DENYFILE);
-}
-
-on|true|yes {
- lmsg ("on\n");
- return (ON);
-}
-
-off|false|no {
- lmsg ("off\n");
- return (OFF);
-}
-
-[a-zA-Z_][a-zA-Z0-9_]* {
- lmsg ("identifier [%s]\n", yytext);
- return (IDENTIFIER);
-}
-
-[0-9]+ {
- lmsg ("number [%s]\n", yytext);
- return (NUMBER);
-}
-
-[ \t]+ {
- lmsg ("space(s)\n");
-}
-
-\n {
- lmsg ("newline\n");
- yylineno++;
-}
-
-. {
- lmsg ("lone char ['%c' (ASCII %d)]\n",
- isprint(*yytext) ? *yytext : '.',
- *yytext);
- return (*yytext);
-}
-
-\/\* {
- lmsg ("C-comment starts\n");
- BEGIN(commentstate);
-}
-<commentstate>\*\/ {
- lmsg ("C-comment ends\n");
- BEGIN(0);
-}
-<commentstate>\n {
- yylineno++;
-}
-<commentstate>. ;
-
-<stringstate>[ \r\n\t] {
- lmsg ("string state: skipping initial spaces [ASCII %d]\n", *yytext);
- if (*yytext == '\n')
- yylineno++;
-}
-<stringstate>. {
- lmsg ("string state: entering instring on [%s (ASCII %d)]\n",
- yytext, *yytext);
- unput (*yytext);
- BEGIN (instr);
-}
-
-<instr>(\\\")|(\\\') {
- lmsg ("string part [%s]\n", yytext);
- laststring = xstrcat (laststring, yytext);
-}
-
-<instr>\"[^\"]*\" {
- lmsg ("string part in double quotes [%s]\n", yytext);
- laststring = xstrcat (laststring, yytext + 1);
- laststring[strlen(laststring) - 1] = 0;
-}
-<instr>\'[^\']*\' {
- lmsg ("string part in single quotes [%s]\n", yytext);
- laststring = xstrcat (laststring, yytext + 1);
- laststring[strlen(laststring) - 1] = 0;
-}
-<instr>; {
- BEGIN (0);
- /* Strip terminating whitespace incase the ; is preceded by them */
- if (laststring && *laststring)
- for (i = strlen(laststring) - 1; i >= 0 && isspace(laststring[i]); i--)
- laststring[i] = 0;
- unput (';');
- lmsg ("string complete [%s]\n", laststring);
- return (STRING);
-}
-<instr>" " {
- if (laststring) {
- laststring = xstrcat (laststring, yytext);
- lmsg ("string part space [%s]\n", yytext);
- }
-}
-<instr>. {
- lmsg ("string part char [%s]\n", yytext);
- laststring = xstrcat (laststring, yytext);
-}
-<instr>\n {
- if (laststring) {
- laststring = xstrcat (laststring, " ");
- lmsg ("string part: newline, now space\n");
- }
- yylineno++;
-}
-
-<includestate>[<>\"a-zA-Z0-9_\-\./:\\]+ {
- lmsg ("includefile\n");
- /* parser_skipline(); */
- parser_open (yytext);
- BEGIN (0);
-}
-<includestate><<EOF>> {
- error ("Unterminated #include");
-}
-<includestate>[ \t] ;
-<includestate>\n {
- yylineno++;
-}
-<includestate>. {
- error ("Illegal character 0x%2.2x in #include line", *yytext);
-}
-
-<definestate>[ \s]+ ;
-<definestate>[A-Za-z_][A-Za-z0-9_]* {
- symtab_start (yytext);
- BEGIN (defineredef);
-}
-<definestate,defineredef,definesym><<EOF>> {
- error ("Unterminated #define");
-}
-<definestate,defineredef>\n {
- error ("Unterminated #define");
-}
-<definestate>. {
- error ("Unrecognized character '%c' in #define", *yytext);
-}
-
-<defineredef>[ \t]* {
- BEGIN (definesym);
-}
-<definesym>.* {
- symtab_set (yytext);
-}
-<definesym>\n {
- yylineno++;
- symtab_end();
- BEGIN (0);
-}
diff --git a/src/lib/limitsmsg.c b/src/lib/limitsmsg.c
@@ -1,47 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-typedef struct {
- int type;
- char *desc;
-} Rlimits;
-
-static Rlimits rlimits[] = {
- { RLIMIT_CORE, "core file size" },
- { RLIMIT_CPU, "max seconds CPU usage" },
- { RLIMIT_DATA, "max bytes data segment usage" },
- { RLIMIT_FSIZE, "max bytes in created files" },
- #ifdef RLIMIT_MEMLOCK
- { RLIMIT_MEMLOCK, "max bytes in locked memory" },
- #endif
- { RLIMIT_NOFILE, "max nr of open files" },
- #ifdef RLIMIT_NPROC
- { RLIMIT_NPROC, "max nr of processes of this id" },
- #endif
- #ifdef RLIMIT_RSS
- { RLIMIT_RSS, "max bytes in resident memory" },
- #endif
- { RLIMIT_STACK, "max bytes in stack" },
-};
-
-void limits_msg () {
- struct rlimit lim;
- unsigned i;
-
- if (!activeservice->verbosity)
- return;
-
- msg ("*** Overview of run limits ***");
- for (i = 0; i < sizeof(rlimits) / sizeof(Rlimits); i++) {
- if (getrlimit (rlimits[i].type, &lim))
- error ("failed to get limits for '%s'", rlimits[i].desc);
- msg ("Limit for '%s': current %u, max %u",
- rlimits[i].desc,
- (unsigned) lim.rlim_cur, (unsigned)lim.rlim_max);
- }
-}
diff --git a/src/lib/lockreporter.c b/src/lib/lockreporter.c
@@ -1,32 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void lock_reporter() {
- static int warning_issued = 0;
- struct sembuf buf[] = {
- {
- 0, /* semaphore number */
- 0, /* wait for zero */
- 0, /* no special flags */
- },
- {
- 0, /* semaphore number */
- 1, /* add 1 to the value */
- 0 /* no special flags */
- }
- };
-
- /* msg ("Locking reporter memory"); */
- if ( (!warning_issued++) && (semop (semid, buf, 2) < 0) ) {
- warning ("Failed to lock reporter memory (stage %s): %s",
- stage_to_string (program_stage), strerror(errno));
- if (program_stage != stage_serving)
- _exit (1);
- else
- warning (".. but continuing serving this TCP connection");
- }
-}
diff --git a/src/lib/logactivityany.c b/src/lib/logactivityany.c
@@ -1,19 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void log_activity_any (char const *action) {
- if (!opt.log_activity || current_backend < 0)
- return;
- if (!logstarted++)
- openlog ("crossroads", LOG_PID, opt.log_facility);
- syslog (LOG_NOTICE, "%s %s %s from %s to %s:%d",
- ansistamp(tm_localtime, 0), action, activeservice->name,
- client_ip,
- servicereport->backendstate[current_backend].actual_server,
- servicereport->backendstate[current_backend].actual_port);
-}
diff --git a/src/lib/logactivitycontinuation.c b/src/lib/logactivitycontinuation.c
@@ -1,10 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void log_activity_continuation () {
- log_activity_any ("continuing");
-}
diff --git a/src/lib/logactivityend.c b/src/lib/logactivityend.c
@@ -1,10 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void log_activity_end () {
- log_activity_any ("ending");
-}
diff --git a/src/lib/logactivitystart.c b/src/lib/logactivitystart.c
@@ -1,10 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void log_activity_start () {
- log_activity_any ("starting");
-}
diff --git a/src/lib/makesocket.c b/src/lib/makesocket.c
@@ -1,62 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-int make_socket (int port, char const *ipaddr) {
- int sock, val = 1;
- struct sockaddr_in name;
-
- /* Create the socket. */
- if ( (sock = socket (PF_INET, SOCK_STREAM, 0)) < 0) {
- warning ("cannot create network socket: %s", strerror(errno));
- return (-1);
- }
- if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) {
- warning ("cannot set socket options (reuseaddr): %s", strerror(errno));
- close (sock);
- return (-2);
- }
-#ifdef SO_NOSIGPIPE
- if (setsockopt (sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val))) {
- warning ("cannot set socket options (nosigpipe): %s", strerror(errno));
- close (sock);
- return (-2);
- }
-#endif
-
- /* Give the socket a name. */
- name.sin_family = AF_INET;
- name.sin_port = htons (port);
-
- /* Propagate 'bindto' if given. */
- if (ipaddr && *ipaddr && strcmp(ipaddr, "any")) {
- msg ("creating socket for IP address '%s'", ipaddr);
- if ( (name.sin_addr.s_addr = inet_addr (ipaddr)) == INADDR_NONE ) {
- close (sock);
- error ("cannot convert address '%s' to network bytes", ipaddr);
- }
- /*
- if (!inet_aton (ipaddr, &name.sin_addr.s_addr)) {
- close (sock);
- error ("Cannnot assign bindto address '%s'", ipaddr);
- }
- */
- } else {
- msg ("creating socket for all interfaces");
- name.sin_addr.s_addr = htonl (INADDR_ANY);
- }
-
- /* Finally, bind the socket. */
- if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
- warning ("Cannot bind socket to port %d: %s",
- port, strerror(errno));
- close (sock);
- return (-3);
- }
-
- return (sock);
-}
diff --git a/src/lib/markactivity.c b/src/lib/markactivity.c
@@ -1,147 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void mark_activity (double nbytes, double nsec,
- Backendavail newstate) {
- double llval;
- double dlval;
- unsigned multiplier;
- int i, marked_unavailable = 0;
-
- /* If we had a signal somewhere, don't update the values.
- * If we don't have a back end yet, don't update the values. */
- if (interrupted || current_backend == -1)
- return;
-
- /* Update values. */
- lock_reporter();
-
- /* If the new activity is a failure: increase fails count.
- * Upon other state, set fails count to zero. */
- if (newstate == st_unavailable &&
- servicereport->backendstate[current_backend].actual_avail !=
- st_unavailable &&
- program_stage != stage_retrying) {
- servicereport->backendstate[current_backend].fail++;
- msg ("Back end %d's fail count increased to %d",
- current_backend,
- servicereport->backendstate[current_backend].fail);
- } else if (newstate == st_available)
- servicereport->backendstate[current_backend].fail = 0;
-
- if (program_stage != stage_retrying) {
- /* Handle the decays of all other back ends */
- for (i = 0; i < activeservice->nbackend; i++) {
- if (i != current_backend && activeservice->backend[i].decay) {
- if (activeservice->dispatchover) {
- servicereport->backendstate[i].avg_nbytes *=
- (100 - activeservice->backend[i].decay);
- servicereport->backendstate[i].avg_nbytes /= 100;
- servicereport->backendstate[i].avg_nsec *=
- (100 - activeservice->backend[i].decay);
- servicereport->backendstate[i].avg_nsec /= 100;
- } else {
- servicereport->backendstate[i].nbytes *=
- (100 - activeservice->backend[i].decay);
- servicereport->backendstate[i].nbytes /= 100;
- servicereport->backendstate[i].nsec *=
- (100 - activeservice->backend[i].decay);
- servicereport->backendstate[i].nsec /= 100;
- }
- }
- }
-
- /* Update average seconds and bytes. */
- if (activeservice->dispatchover) {
- multiplier = activeservice->dispatchover - 1;
- if (servicereport->backendstate[current_backend].totuses <
- multiplier)
- multiplier =
- servicereport->backendstate[current_backend].totuses;
-
- dlval = servicereport->backendstate[current_backend].avg_nsec;
- dlval *= multiplier;
- dlval += nsec;
- dlval /= (multiplier + 1);
- servicereport->backendstate[current_backend].avg_nsec = dlval;
-
- llval = servicereport->backendstate[current_backend].avg_nbytes;
- llval *= multiplier;
- llval += nbytes;
- llval /= (multiplier + 1);
- servicereport->backendstate[current_backend].avg_nbytes = llval;
- }
-
- /* Update total secs / bytes. */
- servicereport->backendstate[current_backend].nsec += nsec;
- servicereport->backendstate[current_backend].nbytes += nbytes;
- if (newstate == st_unavailable)
- servicereport->backendstate[current_backend].failures++;
- }
-
- /* Set the state, unless it's already marked for wakeup or brought down.
- * Do this only for 'final' states, not for intermediate. */
- if (servicereport->backendstate[current_backend].actual_avail
- != st_waking &&
- servicereport->backendstate[current_backend].actual_avail
- != st_down) {
- /* When trying to mark as unavailable, only proceed when we
- * actually exceed the retries setting. */
- if (newstate == st_unavailable) {
- if (servicereport->backendstate[current_backend].fail >=
- (unsigned) activeservice->backend[current_backend].retries) {
- msg ("backend %d: %d fails, %d retries, going offline",
- current_backend,
- servicereport->backendstate[current_backend].fail,
- activeservice->backend[current_backend].retries);
- servicereport->backendstate[current_backend].fail = 0;
- servicereport->backendstate[current_backend].actual_avail =
- st_unavailable;
- marked_unavailable++;
- }
- servicereport->backendstate[current_backend].totuses++;
- } else if (newstate != st_intermediate) {
- /* When applying any other state than intermediate, it's OK */
- servicereport->backendstate[current_backend].fail = 0;
- servicereport->backendstate[current_backend].actual_avail =
- newstate;
- servicereport->backendstate[current_backend].totuses++;
- }
- }
-
- /* Don't update servicereport beyond this point! */
- unlock_reporter();
-
- /* Give some feedback (though not during intermediate updates) */
- if (newstate != st_intermediate && program_stage != stage_retrying)
- msg ("updated stats for backend %d (%s): "
- "hits=%lu, "
- "totfails=%lu, secs=%g, avgsecs=%g, "
- "bytes=%g, avgbytes=%lu, state=%s",
- current_backend, activeservice->backend[current_backend].name,
- servicereport->backendstate[current_backend].totuses,
- servicereport->backendstate[current_backend].failures,
- servicereport->backendstate[current_backend].nsec,
- servicereport->backendstate[current_backend].avg_nsec,
- servicereport->backendstate[current_backend].nbytes,
- servicereport->backendstate[current_backend].avg_nbytes,
- state_to_string
- (servicereport->backendstate[current_backend].actual_avail));
-
- /* Run the onfailure hook if one is specified. */
- if (marked_unavailable && program_stage != stage_retrying) {
- msg ("extcmd-onfail: "
- " current_backend = %d, clients = %d, totclients = %d, cmd = %s",
- current_backend,
- servicereport->backendstate[current_backend].nclients,
- servicereport->nclients,
- activeservice->backend[current_backend].onfail);
-
- sysrun (activeservice->backend[current_backend].onfail);
- }
-}
diff --git a/src/lib/msg.c b/src/lib/msg.c
@@ -1,32 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void msg (char const *fmt, ...) {
- va_list args;
- char *str;
-
- if (!flag_verbose || !fmt || !*fmt)
- return;
- va_start (args, fmt);
- str = str_vprintf (fmt, args);
- if (!daemonized) {
- if (activeservice)
- fprintf (stderr, "INFO: Service %s: %s\n", activeservice->name,
- str);
- else
- fprintf (stderr, "INFO: Crossroads: %s\n", str);
- } else {
- if (activeservice)
- writelog (LOG_NOTICE, "INFO: Service %s: %s",
- activeservice->name, str);
- else
- writelog (LOG_NOTICE, "INFO: Crossroads: %s", str);
- }
- free (str);
- va_end (args);
-}
diff --git a/src/lib/msgdumpbuf.c b/src/lib/msgdumpbuf.c
@@ -1,48 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void msgdumpbuf (unsigned char const *buf, int buflen) {
- char
- hexbuf[80] = { 0 },
- disp[17] = { 0 },
- tmp[5];
- int i, j, n = 0;
-
- if (! flag_verbose)
- return;
-
- for (i = 0; i < buflen; i++) {
- if (! n)
- snprintf (hexbuf, 80, "%8.8x ", i);
-
- snprintf (tmp, 5, " %2.2x", buf[i]);
- strlcat (hexbuf, tmp, 80);
-
- disp[n] = isprint (buf[i]) ? buf[i] : '.';
- disp[n + 1] = 0;
-
- if (++n == 16) {
- strlcat (hexbuf, " ", 80);
- strlcat (hexbuf, disp, 80);
- msg ("Message hexdump: %s", hexbuf);
- n = 0;
- disp[0] = 0;
- hexbuf[0] = 0;
- }
- }
-
- if (n < 16 - 1) {
- for (j = n; j < 16; j++)
- strlcat (hexbuf, " ", 80);
- strlcat (hexbuf, " ", 80);
- strlcat (hexbuf, disp, 80);
- msg ("Message hex end: %s", hexbuf);
- }
- else
- msg ("Message hex ends");
-}
-
diff --git a/src/lib/netallocbufs.c b/src/lib/netallocbufs.c
@@ -1,18 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void net_allocbufs () {
- if (!clbuf) {
- clbuf = xmalloc (opt.tcp_bufsz + 1);
- clbuf[opt.tcp_bufsz] = 0;
- srbuf = xmalloc (opt.tcp_bufsz + 1);
- srbuf[opt.tcp_bufsz] = 0;
- clbufmax = srbufmax = clbufpos = srbufpos = 0;
- msg ("Allocated client and server buffers");
- }
-}
diff --git a/src/lib/netbuffer.c b/src/lib/netbuffer.c
@@ -1,31 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-unsigned char *net_buffer (CopyDirection dir, unsigned *sz) {
- if (dir == dir_server_to_client) {
- if (srbufmax) {
- *sz = srbufmax - srbufpos;
- msg ("%d bytes still in server buffer", *sz);
- srbufmax = 0;
- return (srbuf + srbufpos);
- } else {
- msg ("server buffer is empty");
- return (0);
- }
- } else {
- if (clbufmax) {
- *sz = clbufmax - clbufpos;
- msg ("%d bytes still in client buffer", *sz);
- clbufmax = 0;
- return (clbuf + clbufpos);
- } else {
- msg ("client buffer is empty");
- return (0);
- }
- }
-}
diff --git a/src/lib/netbufread.c b/src/lib/netbufread.c
@@ -1,54 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-unsigned char *net_bufread (int sock, int max, int *nread,
- int is_client) {
- unsigned char *buf, *ret;
- int *bufpos, *bufmax, rest;
-
- /* Make sure we have the buffers. */
- net_allocbufs();
-
- /* Set our own ptrs */
- if (is_client) {
- buf = clbuf;
- bufpos = &clbufpos;
- bufmax = &clbufmax;
- } else {
- buf = srbuf;
- bufpos = &srbufpos;
- bufmax = &srbufmax;
- }
-
- /* If buffer is empty, do an actual read */
- if (! *bufmax) {
- *bufmax = net_read (sock, opt.tcp_bufsz, buf, is_client);
- msg ("Got %d bytes from %s", *bufmax, is_client ? "client" : "server");
- *bufpos = 0;
- }
-
- /* Got buffer contents. How much do we return? */
- rest = *bufmax - *bufpos;
-
- if (rest > max) {
- /* Caller wants less than what we have in cache. */
- if (nread)
- *nread = max;
- ret = buf + *bufpos;
- *bufpos += max;
- } else {
- /* Caller wants more than what we have in cache.
- * We'll return what we got. */
- if (nread)
- *nread = rest;
- ret = buf + *bufpos;
- *bufmax = *bufpos = 0;
- }
-
- return (ret);
-}
diff --git a/src/lib/netcopy.c b/src/lib/netcopy.c
@@ -1,111 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-int net_copy (int cl, int sr, int max, unsigned char *buf) {
- fd_set readset, exset;
- struct timeval tv, *tvp, tv1, tv2;
- int nfd;
- int nread, nwritten, totwritten;
- CopyDirection dir;
- double microsec;
-
- /* Prepare select() sets */
- FD_ZERO (&readset);
- FD_ZERO (&exset);
-
- FD_SET (cl, &readset);
- FD_SET (cl, &exset);
- FD_SET (sr, &readset);
- FD_SET (sr, &exset);
-
- /* Prepare timout state */
- if (activeservice->connectiontimeout) {
- tv.tv_sec = activeservice->connectiontimeout;
- tv.tv_usec = 0;
- tvp = &tv;
- } else
- tvp = 0;
-
- /* Wait for a socket to become readable */
- gettimeofday (&tv1, 0);
- nfd = select (FD_SETSIZE, &readset, 0, &exset, tvp);
- if (nfd < 1) {
- decr_client_count();
- log_activity_end();
- mark_activity (0, 0, st_available);
- error ("network copy stopped after timeout");
- }
-
- /* Check for exceptions. */
- if (FD_ISSET (cl, &exset)) {
- decr_client_count();
- log_activity_end();
- error ("client exception");
- }
- if (FD_ISSET (sr, &exset)) {
- decr_client_count();
- log_activity_end();
- mark_activity (0, 0, st_unavailable);
- error ("server exception");
- }
-
- /* Do the read. */
- if (FD_ISSET (sr, &readset))
- dir = dir_server_to_client;
- else
- dir = dir_client_to_server;
-
- nread = read (dir == dir_client_to_server ? cl : sr, buf, max);
- if (nread < 1) {
- decr_client_count();
- log_activity_end();
- if (nread < 0) {
- /* An exception on the network socket. If this is the server
- * that's sending, then we issue an error message.
- * If this is the client, then we'll just issue a verbose
- * message; clients are notorious for just dropping dead. */
- if (dir == dir_server_to_client)
- error ("Read error from server");
- else {
- msg ("Read error from client");
- exit (0);
- }
- } else {
- msg ("%s signals end of data",
- dir == dir_client_to_server ? "client" : "server");
- exit (0);
- }
- }
-
- /* Update thruput / traffic logs. */
- trafficlog (buf, nread, dir);
- thruputlog (buf, nread, dir);
-
- /* Write to dest. */
- totwritten = 0;
- while (totwritten < nread) {
- nwritten = write (dir == dir_client_to_server ? sr : cl,
- buf + totwritten,
- nread - totwritten);
- if (nwritten < 1) {
- decr_client_count();
- log_activity_end();
- warning ("write error when sending data to %s",
- dir == dir_client_to_server ? "server" : "client");
- exit (0);
- }
- totwritten += nwritten;
- }
-
- gettimeofday (&tv2, 0);
- microsec = ( (tv2.tv_sec * 1000000 + tv2.tv_usec) -
- (tv1.tv_sec * 1000000 + tv1.tv_usec) );
-
- mark_activity (totwritten, microsec / 1000000, st_intermediate);
-
- return (nread);
-}
diff --git a/src/lib/netread.c b/src/lib/netread.c
@@ -1,101 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-/* For special-extra verbosity: add "verbose yes" to crossroads.conf
- * and undefine the following line. */
-/* #define DEBUG */
-
-#ifdef DEBUG
-#define LOGGIT msg ("back end %d", current_backend)
-#else
-#define LOGGIT
-#endif
-
-int net_read (int sock, int max, unsigned char *buf, int is_client) {
- fd_set readset, exset;
- struct timeval tv, *tvp, tv1, tv2;
- int nfd;
- int nread;
- CopyDirection dir;
- double microsec;
- char *desc;
-
- desc = is_client ? "client" : "server";
- dir = is_client ? dir_client_to_server : dir_server_to_client;
-
- msg ("fetching atmost %u bytes from %s", max, desc);
-
- /* Prepare select() sets */
- FD_ZERO (&readset);
- FD_ZERO (&exset);
- FD_SET (sock, &readset);
- FD_SET (sock, &exset);
-
- /* Prepare timout state */
- if (activeservice->connectiontimeout) {
- tv.tv_sec = activeservice->connectiontimeout;
- tv.tv_usec = 0;
- tvp = &tv;
- } else
- tvp = 0;
-
- /* Wait for the socket to become readable */
- gettimeofday (&tv1, 0);
- nfd = select (FD_SETSIZE, &readset, 0, &exset, tvp);
- if (nfd < 1) {
- decr_client_count();
- log_activity_end();
- mark_activity (0, 0, is_client ? st_available : st_unavailable);
- if (is_client)
- msg ("read from %s timed out", desc);
- else
- error ("read from %s timed out", desc);
- }
-
- /* Check for exceptions. */
- if (FD_ISSET (sock, &exset)) {
- decr_client_count();
- log_activity_end();
- mark_activity (0, 0, is_client ? st_available : st_unavailable);
- error ("%s exception", desc);
- }
-
- /* Do the read. */
- nread = read (sock, buf, max);
- LOGGIT;
- if (nread < 1) {
- decr_client_count();
- log_activity_end();
- if (nread < 0) {
- /* An exception on the network socket. If this is the server
- * that's sending, then we issue an error message.
- * If this is the client, then we'll just issue a verbose
- * message; clients are notorious for just dropping dead. */
- if (dir == dir_server_to_client)
- error ("Read error from server");
- else {
- msg ("Read error from client");
- exit (0);
- }
- } else {
- msg ("%s signals end of data", desc);
- exit (0);
- }
- }
-
- /* Update thruput / traffic logs. */
- trafficlog (buf, nread, dir);
- thruputlog (buf, nread, dir);
- gettimeofday (&tv2, 0);
- microsec = ( (tv2.tv_sec * 1000000 + tv2.tv_usec) -
- (tv1.tv_sec * 1000000 + tv1.tv_usec) );
-
- mark_activity (nread, microsec / 1000000, st_intermediate);
-
- return (nread);
-}
diff --git a/src/lib/netwrite.c b/src/lib/netwrite.c
@@ -1,109 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-/* Define DUMPFILE if you want Crossroads to dump the contents of what's
- * written to the client or to the server to
- * /tmp/crossroads-sentto{client,server}.dump. This is of course for deep
- * mode debugging only.
- */
-
-/* #define DUMPFILE */
-
-int net_write (int sock, unsigned char const *buf, int buflen,
- int is_client) {
- int ret, nfd;
- struct timeval tv, tv1, tv2, *tvp;
- double microsec;
- fd_set fdset, exset;
-
- #ifdef DUMPFILE
- FILE *f;
- char *fname;
-
- if (is_client)
- fname = "/tmp/crossroads-senttobackend.dump";
- else
- fname = "/tmp/crossroads-senttoclient.dump";
- if (! (f = fopen (fname, "a")))
- f = fopen (fname, "w");
- if (f) {
- fprintf (f, "[0x%x %d bytes] ", buflen, buflen);
- fwrite (buf, 1, buflen, f);
- fclose (f);
- }
- #endif
-
- /* Start timer */
- gettimeofday (&tv1, 0);
-
- /* Prepare the write. */
- FD_ZERO (&fdset);
- FD_ZERO (&exset);
- FD_SET (sock, &fdset);
- FD_SET (sock, &exset);
- if (activeservice->connectiontimeout) {
- tv.tv_sec = activeservice->connectiontimeout;
- tv.tv_usec = 0;
- tvp = &tv;
- } else
- tvp = 0;
- if ( (nfd = select (FD_SETSIZE, 0, &fdset, &exset, tvp)) < 1) {
- if (!nfd) {
- /* Issue an appropriate warning for TIMEOUTS */
- if (is_client)
- warning ("Timeout while writing client on socket %d", sock);
- else
- warning ("Timeout while writing backend %s on socket %d",
- activeservice->backend[current_backend].name,
- sock);
- } else {
- /* Issue an appropriate warning for NETWORK ERRORS */
- if (is_client)
- warning ("Select failed while writing client on socket %d",
- sock);
- else
- warning ("Select failed while writing backend %s on socket %d",
- activeservice->backend[current_backend].name,
- sock);
- }
-
- decr_client_count();
- log_activity_end();
- exit (0);
- }
-
- if (FD_ISSET (sock, &exset)) {
- decr_client_count();
- log_activity_end();
- error ("exception on %s network", is_client ? "client" : "server");
- }
-
- /* We can write! */
- ret = write (sock, buf, buflen);
-
- /* Check for finished / errors */
- if (ret < 1) {
- msg ("failed to send to %s: %s (%d)",
- is_client ? "client" : "server",
- strerror(errno), ret);
- decr_client_count();
- log_activity_end ();
- exit (0);
- }
-
- /* Update activity. */
- gettimeofday (&tv2, 0);
- microsec = ( (tv2.tv_sec * 1000000 + tv2.tv_usec) -
- (tv1.tv_sec * 1000000 + tv1.tv_usec) );
- mark_activity (ret, microsec / 1000000, st_intermediate);
-
- /* Signal caller how many bytes were written. */
- return (ret);
-}
-
-
diff --git a/src/lib/optionsread.c b/src/lib/optionsread.c
@@ -1,27 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void options_read (int fd) {
- int res;
-
- if ( (res = read (fd, &opt, sizeof(Options))) != sizeof(Options) )
- error ("Received only %d bytes (out of %d) "
- "while reading options on fd %d",
- res, (int)sizeof(Options), fd);
-
-# ifdef DEBUG
- printf ("Option log_activity: %d\n", opt.log_activity);
- printf ("Option tcp_bufsz: %u\n", opt.tcp_bufsz);
- printf ("Option dns_cachettl: %d\n", opt.dns_cachettl);
- printf ("Option log_facility: %d\n", opt.log_facility);
- printf ("Option shmperm: %d\n", opt.shmperm);
- printf ("Option sloppyportbind: %d\n", opt.sloppyportbind);
- printf ("Option leave_proctitle: %d\n", opt.leave_proctitle);
- printf ("Option log_http_activity: %d\n", opt.log_http_activity);
-# endif
-}
diff --git a/src/lib/optionswrite.c b/src/lib/optionswrite.c
@@ -1,16 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void options_write (int fd) {
- int res;
-
- msg ("Writing binary program options to fd %d", fd);
- if ( (res = write (fd, &opt, sizeof(Options))) != sizeof(Options) )
- error ("Failed to transmit options, sent %d bytes of %d",
- res, (int)sizeof(Options));
-}
diff --git a/src/lib/parser.c b/src/lib/parser.c
@@ -1,3538 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-/* A Bison parser, made by GNU Bison 2.3. */
-
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
-
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
- simplifying the original so-called "semantic" parser. */
-
-/* All symbols defined below should begin with yy or YY, to avoid
- infringing on user name space. This should be done even for local
- variables, as they might otherwise be expanded by user macros.
- There are some unavoidable exceptions within include files to
- define necessary library symbols; they are noted "INFRINGES ON
- USER NAME SPACE" below. */
-
-/* Identify Bison output. */
-#define YYBISON 1
-
-/* Bison version. */
-#define YYBISON_VERSION "2.3"
-
-/* Skeleton name. */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers. */
-#define YYPURE 0
-
-/* Using locations. */
-#define YYLSP_NEEDED 0
-
-
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- IDENTIFIER = 258,
- NUMBER = 259,
- STRING = 260,
- SERVICE = 261,
- PORT = 262,
- VERBOSITY = 263,
- MAXCONNECTIONS = 264,
- TYPE = 265,
- ANY = 266,
- HTTP = 267,
- BACKEND = 268,
- SERVER = 269,
- BINDTO = 270,
- CONNECTIONTIMEOUT = 271,
- ON = 272,
- OFF = 273,
- DISPATCHMODE = 274,
- ROUNDROBIN = 275,
- RANDOM = 276,
- BYDURATION = 277,
- BYSIZE = 278,
- BYCONNECTIONS = 279,
- BYORDER = 280,
- BYCLIENTIP = 281,
- OVER = 282,
- DECAY = 283,
- REVIVINGINTERVAL = 284,
- CHECKINTERVAL = 285,
- RETRIES = 286,
- SHMKEY = 287,
- WEIGHT = 288,
- ONSTART = 289,
- ONFAIL = 290,
- BACKLOG = 291,
- THROUGHPUTLOG = 292,
- TRAFFICLOG = 293,
- HTTPTIMINGLOG = 294,
- STICKYCOOKIE = 295,
- ADDCLIENTHEADER = 296,
- SETCLIENTHEADER = 297,
- APPENDCLIENTHEADER = 298,
- ADDSERVERHEADER = 299,
- SETSERVERHEADER = 300,
- APPENDSERVERHEADER = 301,
- ALLOWFROM = 302,
- DENYFROM = 303,
- ALLOWFILE = 304,
- DENYFILE = 305,
- EXTERNALHANDLER = 306,
- USERACCOUNT = 307,
- ONEND = 308,
- HEADERINSPECTION = 309,
- DEEP = 310,
- SHALLOW = 311,
- STATE = 312,
- AVAILABLE = 313,
- UNAVAILABLE = 314,
- DOWN = 315,
- OPTIONS = 316,
- LOGACTIVITY = 317,
- TCPBUFFERSIZE = 318,
- DNSCACHETTL = 319,
- LOGFACILITY = 320,
- SHMPERMISSIONS = 321,
- SLOPPYPORTBIND = 322,
- LEAVEPROCESSTITLE = 323
- };
-#endif
-/* Tokens. */
-#define IDENTIFIER 258
-#define NUMBER 259
-#define STRING 260
-#define SERVICE 261
-#define PORT 262
-#define VERBOSITY 263
-#define MAXCONNECTIONS 264
-#define TYPE 265
-#define ANY 266
-#define HTTP 267
-#define BACKEND 268
-#define SERVER 269
-#define BINDTO 270
-#define CONNECTIONTIMEOUT 271
-#define ON 272
-#define OFF 273
-#define DISPATCHMODE 274
-#define ROUNDROBIN 275
-#define RANDOM 276
-#define BYDURATION 277
-#define BYSIZE 278
-#define BYCONNECTIONS 279
-#define BYORDER 280
-#define BYCLIENTIP 281
-#define OVER 282
-#define DECAY 283
-#define REVIVINGINTERVAL 284
-#define CHECKINTERVAL 285
-#define RETRIES 286
-#define SHMKEY 287
-#define WEIGHT 288
-#define ONSTART 289
-#define ONFAIL 290
-#define BACKLOG 291
-#define THROUGHPUTLOG 292
-#define TRAFFICLOG 293
-#define HTTPTIMINGLOG 294
-#define STICKYCOOKIE 295
-#define ADDCLIENTHEADER 296
-#define SETCLIENTHEADER 297
-#define APPENDCLIENTHEADER 298
-#define ADDSERVERHEADER 299
-#define SETSERVERHEADER 300
-#define APPENDSERVERHEADER 301
-#define ALLOWFROM 302
-#define DENYFROM 303
-#define ALLOWFILE 304
-#define DENYFILE 305
-#define EXTERNALHANDLER 306
-#define USERACCOUNT 307
-#define ONEND 308
-#define HEADERINSPECTION 309
-#define DEEP 310
-#define SHALLOW 311
-#define STATE 312
-#define AVAILABLE 313
-#define UNAVAILABLE 314
-#define DOWN 315
-#define OPTIONS 316
-#define LOGACTIVITY 317
-#define TCPBUFFERSIZE 318
-#define DNSCACHETTL 319
-#define LOGFACILITY 320
-#define SHMPERMISSIONS 321
-#define SLOPPYPORTBIND 322
-#define LEAVEPROCESSTITLE 323
-
-
-
-
-/* Copy the first part of user declarations. */
-#line 4 "parser.y"
-
-/* Prologue */
-#include "../crossroads.h"
-
-#define YYSTYPE Confsets
-
-/* Static parser vars */
-static int i; /* Loop counter */
-static Backend cur_backend; /* Storage for a handled backend */
-static Service cur_service; /* Storage for a handled service */
-
-/* Parser debugging related */
-static void pmsg (char const *fmt, ...) {
- va_list args;
-
- if (parser_debug) {
- printf ("PARSER: ");
- va_start (args, fmt);
- vprintf (fmt, args);
- }
-}
-
-/* Conversion of yytext for symbol table */
-#define SYMBOL (symtab_lookup((yytext)))
-
-/* Error handler for yyparse() */
-static int yyerror (char *msg) {
- char *sym;
-
- if (! yytext || ! *yytext)
- sym = "<end of file>";
- else if (isspace (*yytext))
- sym = "<white space>";
- else if (isprint (*yytext))
- sym = yytext;
- else
- sym = "<nonprintable>";
-
- error ("Parse error at %s, line %d, '%s': %s",
- parser_filename(), yylineno + 1,
- sym, yyerrmsg);
-}
-
-/* Store an encountered string */
-static char *laststr;
-static void setlaststr (char const *what) {
- free (laststr);
- laststr = xstrdup (what);
-}
-
-/* Store an encountered number */
-static int lastnr;
-static void setlastnr (char const *what) {
- if (what && *what && *what == '0')
- lastnr = strtol (what, 0, 8);
- else
- lastnr = atoi (what);
-}
-
-/* Store an encountered 'over' number */
-static int lastovernr;
-static void setlastovernr (char const *what) {
- if (what && *what && *what == '0')
- lastovernr = strtol (what, 0, 8);
- else
- lastovernr = atoi(what);
-}
-
-/* Store an encountered 'externalhandler' */
-static char *lastext;
-static void setlastext (char const *what) {
- free (lastext);
- lastext = xstrdup (what);
-}
-
-/* Get the server part from HOSTNAME:PORT in allocated memory */
-static char *serverpart (char const *what) {
- char *ret = xstrdup (what);
- char *cp;
-
- if ( (cp = strchr (ret, ':')) )
- *cp = 0;
- return (ret);
-}
-
-/* Get the port part from HOSTNAME:PORT */
-static int portpart (char const *what) {
- char *cp;
-
- if ( (cp = strchr (what, ':')) )
- return (atoi (cp + 1));
- return (0);
-}
-
-/* Add a list of IP filters to the allowlist or the denylist */
-static void add_any (char *what, int chain) {
- char *item, *last = (char*) add_any;
- int result;
-
- for (item = strtok_r (what, " ", &last);
- item;
- item = strtok_r (0, " ", &last)) {
- if (chain)
- result = ipf_add_allow (&cur_service, item);
- else
- result = ipf_add_deny (&cur_service, item);
- if (result)
- error ("Bad IP filter specifier '%s' at line %d",
- item, yylineno + 1);
- }
-}
-static void add_allowfrom (char *what) {
- add_any (what, 1);
-}
-static void add_denyfrom (char *what) {
- add_any (what, 0);
-}
-
-/* Set uid/gid for external commands. */
-static void setuseraccount (char *username) {
- struct passwd *pw;
-
- if (! (pw = getpwnam (username)) )
- error ("Invalid username '%s' at line %d", username, yylineno + 1);
- cur_service.uid = pw->pw_uid;
- cur_service.gid = pw->pw_gid;
-}
-
-
-
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef int YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-
-
-/* Copy the second part of user declarations. */
-
-
-/* Line 216 of yacc.c. */
-#line 372 "parser.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-# define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-# define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# else
-# define YYSIZE_T unsigned int
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if YYENABLE_NLS
-# if ENABLE_NLS
-# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
-# endif
-# endif
-# ifndef YY_
-# define YY_(msgid) msgid
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E. */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions. */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int i)
-#else
-static int
-YYID (i)
- int i;
-#endif
-{
- return i;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols. */
-
-# ifdef YYSTACK_USE_ALLOCA
-# if YYSTACK_USE_ALLOCA
-# ifdef __GNUC__
-# define YYSTACK_ALLOC __builtin_alloca
-# elif defined __BUILTIN_VA_ARG_INCR
-# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-# elif defined _AIX
-# define YYSTACK_ALLOC __alloca
-# elif defined _MSC_VER
-# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-# define alloca _alloca
-# else
-# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# endif
-# endif
-# endif
-
-# ifdef YYSTACK_ALLOC
- /* Pacify GCC's `empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-# ifndef YYSTACK_ALLOC_MAXIMUM
- /* The OS might guarantee only one guard page at the bottom of the stack,
- and a page size can be as small as 4096 bytes. So we cannot safely
- invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
- to allow for a few compiler-allocated temporary stack slots. */
-# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-# endif
-# else
-# define YYSTACK_ALLOC YYMALLOC
-# define YYSTACK_FREE YYFREE
-# ifndef YYSTACK_ALLOC_MAXIMUM
-# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-# endif
-# if (defined __cplusplus && ! defined _STDLIB_H \
- && ! ((defined YYMALLOC || defined malloc) \
- && (defined YYFREE || defined free)))
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# ifndef YYMALLOC
-# define YYMALLOC malloc
-# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# ifndef YYFREE
-# define YYFREE free
-# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
- && (! defined __cplusplus \
- || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member. */
-union yyalloc
-{
- yytype_int16 yyss;
- YYSTYPE yyvs;
- };
-
-/* The size of the maximum gap between one aligned stack and the next. */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
- N elements. */
-# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
- + YYSTACK_GAP_MAXIMUM)
-
-/* Copy COUNT objects from FROM to TO. The source and destination do
- not overlap. */
-# ifndef YYCOPY
-# if defined __GNUC__ && 1 < __GNUC__
-# define YYCOPY(To, From, Count) \
- __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-# else
-# define YYCOPY(To, From, Count) \
- do \
- { \
- YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (To)[yyi] = (From)[yyi]; \
- } \
- while (YYID (0))
-# endif
-# endif
-
-/* Relocate STACK from its old location to the new one. The
- local variables YYSIZE and YYSTACKSIZE give the old and new number of
- elements in the stack, and YYPTR gives the new location of the
- stack. Advance YYPTR to a properly aligned location for the next
- stack. */
-# define YYSTACK_RELOCATE(Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack, Stack, yysize); \
- Stack = &yyptr->Stack; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (YYID (0))
-
-#endif
-
-/* YYFINAL -- State number of the termination state. */
-#define YYFINAL 10
-/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 254
-
-/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 72
-/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 110
-/* YYNRULES -- Number of rules. */
-#define YYNRULES 173
-/* YYNRULES -- Number of states. */
-#define YYNSTATES 277
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
-#define YYUNDEFTOK 2
-#define YYMAXUTOK 323
-
-#define YYTRANSLATE(YYX) \
- ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
-static const yytype_uint8 yytranslate[] =
-{
- 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 69,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 70, 2, 71, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
- 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
- 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
- 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
- 65, 66, 67, 68
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
- YYRHS. */
-static const yytype_uint16 yyprhs[] =
-{
- 0, 0, 3, 6, 8, 10, 12, 17, 20, 22,
- 25, 27, 29, 31, 33, 35, 37, 39, 44, 48,
- 52, 56, 60, 65, 70, 76, 79, 82, 85, 87,
- 90, 92, 94, 96, 98, 100, 102, 104, 106, 108,
- 110, 112, 114, 116, 118, 120, 122, 124, 126, 130,
- 134, 137, 140, 143, 148, 150, 152, 157, 159, 161,
- 162, 165, 168, 170, 173, 175, 177, 179, 181, 183,
- 185, 187, 189, 193, 196, 201, 206, 208, 209, 212,
- 216, 220, 224, 228, 232, 235, 237, 239, 243, 246,
- 248, 250, 254, 258, 262, 266, 269, 275, 278, 281,
- 283, 286, 288, 290, 292, 294, 296, 298, 300, 302,
- 304, 306, 308, 310, 312, 314, 316, 318, 320, 322,
- 324, 326, 328, 333, 337, 341, 343, 347, 351, 354,
- 356, 358, 360, 364, 368, 372, 376, 380, 384, 387,
- 390, 394, 397, 401, 405, 409, 413, 417, 421, 424,
- 425, 426, 427, 428, 429, 430, 431, 432, 433, 434,
- 435, 436, 437, 438, 439, 440, 441, 442, 443, 444,
- 447, 450, 451, 452
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS. */
-static const yytype_int16 yyrhs[] =
-{
- 73, 0, -1, 73, 74, -1, 74, -1, 86, -1,
- 75, -1, 61, 177, 76, 178, -1, 76, 77, -1,
- 77, -1, 181, 78, -1, 79, -1, 80, -1, 81,
- -1, 82, -1, 83, -1, 84, -1, 85, -1, 62,
- 165, 98, 96, -1, 63, 95, 96, -1, 64, 95,
- 96, -1, 65, 95, 96, -1, 66, 95, 96, -1,
- 67, 165, 98, 96, -1, 68, 165, 98, 96, -1,
- 87, 88, 177, 89, 178, -1, 161, 6, -1, 169,
- 3, -1, 89, 90, -1, 90, -1, 163, 91, -1,
- 92, -1, 93, -1, 97, -1, 99, -1, 108, -1,
- 109, -1, 112, -1, 113, -1, 114, -1, 115, -1,
- 116, -1, 119, -1, 122, -1, 124, -1, 123, -1,
- 125, -1, 106, -1, 127, -1, 7, 95, 96, -1,
- 15, 94, 96, -1, 171, 5, -1, 159, 4, -1,
- 164, 69, -1, 8, 165, 98, 96, -1, 17, -1,
- 18, -1, 19, 104, 100, 96, -1, 101, -1, 103,
- -1, -1, 27, 102, -1, 159, 4, -1, 146, -1,
- 166, 105, -1, 20, -1, 21, -1, 22, -1, 23,
- -1, 25, -1, 24, -1, 51, -1, 26, -1, 52,
- 107, 96, -1, 175, 5, -1, 29, 95, 110, 96,
- -1, 30, 95, 110, 96, -1, 111, -1, -1, 51,
- 146, -1, 36, 95, 96, -1, 32, 95, 96, -1,
- 16, 95, 96, -1, 9, 95, 96, -1, 10, 117,
- 96, -1, 172, 118, -1, 11, -1, 12, -1, 54,
- 120, 96, -1, 173, 121, -1, 55, -1, 56, -1,
- 47, 126, 96, -1, 48, 126, 96, -1, 49, 147,
- 96, -1, 50, 147, 96, -1, 174, 5, -1, 13,
- 128, 177, 129, 178, -1, 170, 3, -1, 129, 130,
- -1, 130, -1, 162, 131, -1, 132, -1, 92, -1,
- 97, -1, 140, -1, 142, -1, 141, -1, 143, -1,
- 144, -1, 145, -1, 133, -1, 134, -1, 115, -1,
- 148, -1, 150, -1, 151, -1, 152, -1, 153, -1,
- 154, -1, 155, -1, 136, -1, 137, -1, 14, 160,
- 135, 96, -1, 33, 95, 96, -1, 28, 95, 96,
- -1, 5, -1, 31, 95, 96, -1, 57, 138, 96,
- -1, 176, 139, -1, 58, -1, 59, -1, 60, -1,
- 34, 146, 96, -1, 35, 146, 96, -1, 53, 146,
- 96, -1, 38, 147, 96, -1, 37, 147, 96, -1,
- 39, 147, 96, -1, 167, 5, -1, 168, 5, -1,
- 40, 149, 96, -1, 158, 5, -1, 41, 156, 96,
- -1, 42, 156, 96, -1, 43, 156, 96, -1, 44,
- 156, 96, -1, 45, 156, 96, -1, 46, 156, 96,
- -1, 157, 5, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 179, 70, -1, 180, 71, -1,
- -1, -1, -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
-static const yytype_uint16 yyrline[] =
-{
- 0, 161, 161, 164, 168, 170, 174, 181, 184, 188,
- 193, 195, 197, 199, 201, 203, 205, 209, 218, 226,
- 234, 242, 250, 259, 268, 292, 297, 308, 311, 315,
- 320, 326, 332, 338, 348, 356, 363, 369, 375, 381,
- 387, 393, 399, 405, 411, 417, 423, 430, 604, 616,
- 628, 637, 644, 649, 662, 666, 672, 681, 683, 685,
- 691, 708, 715, 725, 734, 738, 742, 746, 750, 754,
- 758, 762, 768, 780, 789, 807, 825, 827, 833, 842,
- 854, 866, 878, 890, 902, 907, 911, 917, 929, 934,
- 938, 944, 956, 968, 980, 992, 1001, 1011, 1023, 1031,
- 1037, 1044, 1049, 1054, 1059, 1064, 1069, 1074, 1079, 1084,
- 1089, 1094, 1099, 1104, 1109, 1114, 1119, 1124, 1129, 1134,
- 1139, 1144, 1151, 1164, 1176, 1188, 1194, 1206, 1218, 1223,
- 1227, 1231, 1237, 1249, 1261, 1273, 1285, 1297, 1309, 1318,
- 1327, 1339, 1348, 1360, 1372, 1384, 1396, 1408, 1420, 1428,
- 1433, 1438, 1443, 1448, 1453, 1458, 1463, 1468, 1473, 1478,
- 1483, 1488, 1493, 1498, 1503, 1508, 1513, 1518, 1523, 1529,
- 1534, 1538, 1542, 1546
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
- First, the terminals, then, starting at YYNTOKENS, nonterminals. */
-static const char *const yytname[] =
-{
- "$end", "error", "$undefined", "IDENTIFIER", "NUMBER", "STRING",
- "SERVICE", "PORT", "VERBOSITY", "MAXCONNECTIONS", "TYPE", "ANY", "HTTP",
- "BACKEND", "SERVER", "BINDTO", "CONNECTIONTIMEOUT", "ON", "OFF",
- "DISPATCHMODE", "ROUNDROBIN", "RANDOM", "BYDURATION", "BYSIZE",
- "BYCONNECTIONS", "BYORDER", "BYCLIENTIP", "OVER", "DECAY",
- "REVIVINGINTERVAL", "CHECKINTERVAL", "RETRIES", "SHMKEY", "WEIGHT",
- "ONSTART", "ONFAIL", "BACKLOG", "THROUGHPUTLOG", "TRAFFICLOG",
- "HTTPTIMINGLOG", "STICKYCOOKIE", "ADDCLIENTHEADER", "SETCLIENTHEADER",
- "APPENDCLIENTHEADER", "ADDSERVERHEADER", "SETSERVERHEADER",
- "APPENDSERVERHEADER", "ALLOWFROM", "DENYFROM", "ALLOWFILE", "DENYFILE",
- "EXTERNALHANDLER", "USERACCOUNT", "ONEND", "HEADERINSPECTION", "DEEP",
- "SHALLOW", "STATE", "AVAILABLE", "UNAVAILABLE", "DOWN", "OPTIONS",
- "LOGACTIVITY", "TCPBUFFERSIZE", "DNSCACHETTL", "LOGFACILITY",
- "SHMPERMISSIONS", "SLOPPYPORTBIND", "LEAVEPROCESSTITLE", "';'", "'{'",
- "'}'", "$accept", "input", "element", "option_element",
- "option_statements", "option_statement", "optstat",
- "logactivity_statement", "tcpbuffersize_statement",
- "dnscachettl_statement", "logfacility_statement",
- "shmpermissions_statement", "sloppyportbind_statement",
- "leaveprocesstitle_statement", "service_element", "service",
- "servicename", "servicestatements", "servicestatement", "servicebody",
- "portstatement", "bindstatement", "ipaddress", "number", "semicol",
- "verbositystatement", "onoff", "dispatchmodestatement", "dispatchtail",
- "dispatchover", "overnumber", "dispatchext", "dispatchmethod",
- "dispatchmethodspec", "useraccountstatement", "useraccount",
- "revivingintervalstatement", "checkintervalstatement",
- "opt_externalhandler", "externalhandler", "backlogstatement",
- "shmkeystatement", "connectiontimeoutstatement",
- "maxconnectionsstatement", "typestatement", "typespec", "typespecifier",
- "inspectionstatement", "shallowdeepspec", "shallowdeepspecifier",
- "allowfromstatement", "denyfromstatement", "allowfilestatement",
- "denyfilestatement", "ipfilters", "backendblock", "backendname",
- "backenddefinitions", "backenddefinition", "backendstatement",
- "serverstatement", "weightstatement", "decaystatement", "serveraddress",
- "retriesstatement", "initialstatestatement", "statedef", "somestate",
- "onstartstatement", "onfailstatement", "onendstatement",
- "dumptrafficstatement", "throughputstatement", "httptiminglogstatement",
- "commandline", "filename", "stickycookiestatement", "cookiespecifier",
- "addclientheaderstatement", "setclientheaderstatement",
- "appendclientheaderstatement", "addserverheaderstatement",
- "setserverheaderstatement", "appendserverheaderstatement",
- "headerstring", "headerstring_expected", "cookie_expected",
- "number_expected", "serveraddress_expected", "service_expected",
- "backendstatement_expected", "servicebody_expected", "semicol_expected",
- "onoff_expected", "dispatchmethod_expected", "commandline_expected",
- "filename_expected", "servicename_expected", "backendname_expected",
- "ipaddress_expected", "type_expected", "shallowdeep_expected",
- "ipfilters_expected", "useraccount_expected", "statedef_expected",
- "openbrace", "closebrace", "openbrace_expected", "closebrace_expected",
- "option_statement_expected", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
- token YYLEX-NUM. */
-static const yytype_uint16 yytoknum[] =
-{
- 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
- 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
- 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
- 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
- 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
- 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
- 315, 316, 317, 318, 319, 320, 321, 322, 323, 59,
- 123, 125
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const yytype_uint8 yyr1[] =
-{
- 0, 72, 73, 73, 74, 74, 75, 76, 76, 77,
- 78, 78, 78, 78, 78, 78, 78, 79, 80, 81,
- 82, 83, 84, 85, 86, 87, 88, 89, 89, 90,
- 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
- 91, 91, 91, 91, 91, 91, 91, 91, 92, 93,
- 94, 95, 96, 97, 98, 98, 99, 100, 100, 100,
- 101, 102, 103, 104, 105, 105, 105, 105, 105, 105,
- 105, 105, 106, 107, 108, 109, 110, 110, 111, 112,
- 113, 114, 115, 116, 117, 118, 118, 119, 120, 121,
- 121, 122, 123, 124, 125, 126, 127, 128, 129, 129,
- 130, 131, 131, 131, 131, 131, 131, 131, 131, 131,
- 131, 131, 131, 131, 131, 131, 131, 131, 131, 131,
- 131, 131, 132, 133, 134, 135, 136, 137, 138, 139,
- 139, 139, 140, 141, 142, 143, 144, 145, 146, 147,
- 148, 149, 150, 151, 152, 153, 154, 155, 156, 157,
- 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
- 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
- 178, 179, 180, 181
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const yytype_uint8 yyr2[] =
-{
- 0, 2, 2, 1, 1, 1, 4, 2, 1, 2,
- 1, 1, 1, 1, 1, 1, 1, 4, 3, 3,
- 3, 3, 4, 4, 5, 2, 2, 2, 1, 2,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 3, 3,
- 2, 2, 2, 4, 1, 1, 4, 1, 1, 0,
- 2, 2, 1, 2, 1, 1, 1, 1, 1, 1,
- 1, 1, 3, 2, 4, 4, 1, 0, 2, 3,
- 3, 3, 3, 3, 2, 1, 1, 3, 2, 1,
- 1, 3, 3, 3, 3, 2, 5, 2, 2, 1,
- 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 4, 3, 3, 1, 3, 3, 2, 1,
- 1, 1, 3, 3, 3, 3, 3, 3, 2, 2,
- 3, 2, 3, 3, 3, 3, 3, 3, 2, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
- 2, 0, 0, 0
-};
-
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
- STATE-NUM when YYTABLE doesn't specify something else to do. Zero
- means the default is an error. */
-static const yytype_uint8 yydefact[] =
-{
- 153, 171, 153, 3, 5, 4, 161, 0, 173, 0,
- 1, 2, 171, 0, 25, 173, 8, 0, 169, 155,
- 26, 7, 6, 0, 157, 151, 151, 151, 151, 157,
- 157, 9, 10, 11, 12, 13, 14, 15, 16, 155,
- 28, 0, 170, 0, 156, 0, 156, 156, 156, 0,
- 0, 27, 24, 151, 157, 151, 164, 162, 163, 151,
- 158, 151, 151, 151, 151, 166, 166, 160, 160, 167,
- 165, 29, 30, 31, 32, 33, 46, 34, 35, 36,
- 37, 38, 39, 40, 41, 42, 44, 43, 45, 47,
- 54, 55, 156, 18, 0, 51, 19, 20, 21, 156,
- 156, 156, 0, 156, 156, 0, 171, 0, 156, 0,
- 156, 59, 0, 77, 77, 156, 156, 156, 0, 156,
- 156, 0, 156, 156, 0, 156, 0, 17, 52, 22,
- 23, 48, 156, 82, 83, 85, 86, 84, 154, 97,
- 49, 50, 81, 151, 156, 57, 58, 62, 0, 64,
- 65, 66, 67, 69, 68, 71, 70, 63, 159, 156,
- 76, 156, 80, 79, 91, 95, 92, 93, 139, 94,
- 72, 73, 87, 89, 90, 88, 53, 154, 99, 0,
- 60, 0, 56, 138, 78, 74, 75, 98, 96, 152,
- 151, 151, 151, 159, 159, 160, 160, 160, 150, 149,
- 149, 149, 149, 149, 149, 159, 168, 102, 103, 112,
- 100, 101, 110, 111, 120, 121, 104, 106, 105, 107,
- 108, 109, 113, 114, 115, 116, 117, 118, 119, 61,
- 0, 156, 156, 156, 156, 156, 156, 156, 156, 156,
- 0, 156, 0, 156, 156, 156, 156, 156, 156, 156,
- 0, 125, 156, 124, 126, 123, 132, 133, 136, 135,
- 137, 140, 141, 142, 148, 143, 144, 145, 146, 147,
- 134, 127, 129, 130, 131, 128, 122
-};
-
-/* YYDEFGOTO[NTERM-NUM]. */
-static const yytype_int16 yydefgoto[] =
-{
- -1, 2, 3, 4, 15, 16, 31, 32, 33, 34,
- 35, 36, 37, 38, 5, 6, 12, 39, 40, 71,
- 72, 73, 108, 44, 93, 74, 92, 75, 144, 145,
- 180, 146, 111, 157, 76, 123, 77, 78, 159, 160,
- 79, 80, 81, 82, 83, 104, 137, 84, 125, 175,
- 85, 86, 87, 88, 117, 89, 106, 177, 178, 210,
- 211, 212, 213, 252, 214, 215, 249, 275, 216, 217,
- 218, 219, 220, 221, 147, 120, 222, 239, 223, 224,
- 225, 226, 227, 228, 241, 242, 240, 45, 230, 7,
- 179, 41, 94, 43, 112, 148, 121, 13, 107, 109,
- 105, 126, 118, 124, 250, 8, 22, 9, 23, 17
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
- STATE-NUM. */
-#define YYPACT_NINF -150
-static const yytype_int16 yypact[] =
-{
- -51, -150, 11, -150, -150, -150, -150, 8, -150, -54,
- -150, -150, -150, 26, -150, -40, -150, 41, -150, -150,
- -150, -150, -150, -36, -150, -150, -150, -150, -150, -150,
- -150, -150, -150, -150, -150, -150, -150, -150, -150, -40,
- -150, 200, -150, 16, -150, 43, -150, -150, -150, 16,
- 16, -150, -150, -150, -150, -150, -150, -150, -150, -150,
- -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,
- -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,
- -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,
- -150, -150, -150, -150, -19, -150, -150, -150, -150, -150,
- -150, -150, 16, -150, -150, 31, -150, 48, -150, 47,
- -150, 10, -3, 12, 12, -150, -150, -150, 56, -150,
- -150, 61, -150, -150, 62, -150, 4, -150, -150, -150,
- -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,
- -150, -150, -150, -150, -150, -150, -150, -150, 63, -150,
- -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,
- -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,
- -150, -150, -150, -150, -150, -150, -150, -40, -150, 86,
- -150, 71, -150, -150, -150, -150, -150, -150, -150, -150,
- -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,
- -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,
- -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,
- -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,
- 73, -150, -150, -150, -150, -150, -150, -150, -150, -150,
- 80, -150, 82, -150, -150, -150, -150, -150, -150, -150,
- -32, -150, -150, -150, -150, -150, -150, -150, -150, -150,
- -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,
- -150, -150, -150, -150, -150, -150, -150
-};
-
-/* YYPGOTO[NTERM-NUM]. */
-static const yytype_int16 yypgoto[] =
-{
- -150, -150, 87, -150, -150, 75, -150, -150, -150, -150,
- -150, -150, -150, -150, -150, -150, -150, -150, 49, -150,
- -88, -150, -150, -23, -46, -87, -37, -150, -150, -150,
- -150, -150, -150, -150, -150, -150, -150, -150, -18, -150,
- -150, -150, -150, -82, -150, -150, -150, -150, -150, -150,
- -150, -150, -150, -150, 33, -150, -150, -150, -76, -150,
- -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,
- -150, -150, -150, -150, -149, -61, -150, -150, -150, -150,
- -150, -150, -150, -150, -120, -150, -150, -31, -150, -150,
- -150, -150, -150, -5, -150, -150, -150, -150, -150, -150,
- -150, -150, -150, -150, -150, -4, -33, -150, -150, -150
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
- positive, shift that token. If negative, reduce the rule which
- number is the opposite. If zero, do what YYDEFACT says.
- If YYTABLE_NINF, syntax error. */
-#define YYTABLE_NINF -173
-static const yytype_int16 yytable[] =
-{
- 96, 97, 98, 46, 47, 48, 52, 122, 19, 184,
- 1, 10, 99, 100, 14, -159, 18, 149, 150, 151,
- 152, 153, 154, 155, 49, 50, 272, 273, 274, 20,
- 101, -172, 103, 90, 91, 42, 110, 143, 113, 114,
- 115, 116, 135, 136, 234, 235, 127, 95, 156, 102,
- 128, 139, 141, 129, 130, 131, 248, 133, 134, 173,
- 174, 165, 140, 158, 142, 132, 168, 171, 183, 162,
- 163, 164, 1, 166, 167, 229, 169, 170, 251, 172,
- 243, 244, 245, 246, 247, 262, 176, 264, 51, 11,
- 21, 207, 208, 53, 54, 55, 161, 209, 182, 119,
- 189, 187, 138, 24, 25, 26, 27, 28, 29, 30,
- 0, 0, 181, 185, 190, 186, 0, 191, 0, 192,
- 193, 194, 0, 195, 196, 197, 198, 199, 200, 201,
- 202, 203, 204, 0, 236, 237, 238, 0, 0, 205,
- 0, 0, 0, 206, 188, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 231, 232, 233,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 253, 254, 255, 256, 257,
- 258, 259, 260, 261, 0, 263, 0, 265, 266, 267,
- 268, 269, 270, 271, 0, 0, 276, 53, 54, 55,
- 56, 0, 0, 57, 0, 58, 59, 0, 0, 60,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 61,
- 62, 0, 63, 0, 0, 0, 64, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 65, 66, 67,
- 68, 0, 69, 0, 70
-};
-
-static const yytype_int16 yycheck[] =
-{
- 46, 47, 48, 26, 27, 28, 39, 68, 12, 158,
- 61, 0, 49, 50, 6, 5, 70, 20, 21, 22,
- 23, 24, 25, 26, 29, 30, 58, 59, 60, 3,
- 53, 71, 55, 17, 18, 71, 59, 27, 61, 62,
- 63, 64, 11, 12, 193, 194, 92, 4, 51, 54,
- 69, 3, 5, 99, 100, 101, 205, 103, 104, 55,
- 56, 5, 108, 51, 110, 102, 5, 5, 5, 115,
- 116, 117, 61, 119, 120, 4, 122, 123, 5, 125,
- 200, 201, 202, 203, 204, 5, 132, 5, 39, 2,
- 15, 179, 179, 7, 8, 9, 114, 179, 144, 66,
- 14, 177, 106, 62, 63, 64, 65, 66, 67, 68,
- -1, -1, 143, 159, 28, 161, -1, 31, -1, 33,
- 34, 35, -1, 37, 38, 39, 40, 41, 42, 43,
- 44, 45, 46, -1, 195, 196, 197, -1, -1, 53,
- -1, -1, -1, 57, 177, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 190, 191, 192,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 231, 232, 233, 234, 235,
- 236, 237, 238, 239, -1, 241, -1, 243, 244, 245,
- 246, 247, 248, 249, -1, -1, 252, 7, 8, 9,
- 10, -1, -1, 13, -1, 15, 16, -1, -1, 19,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 29,
- 30, -1, 32, -1, -1, -1, 36, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 47, 48, 49,
- 50, -1, 52, -1, 54
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
- symbol of state STATE-NUM. */
-static const yytype_uint8 yystos[] =
-{
- 0, 61, 73, 74, 75, 86, 87, 161, 177, 179,
- 0, 74, 88, 169, 6, 76, 77, 181, 70, 177,
- 3, 77, 178, 180, 62, 63, 64, 65, 66, 67,
- 68, 78, 79, 80, 81, 82, 83, 84, 85, 89,
- 90, 163, 71, 165, 95, 159, 95, 95, 95, 165,
- 165, 90, 178, 7, 8, 9, 10, 13, 15, 16,
- 19, 29, 30, 32, 36, 47, 48, 49, 50, 52,
- 54, 91, 92, 93, 97, 99, 106, 108, 109, 112,
- 113, 114, 115, 116, 119, 122, 123, 124, 125, 127,
- 17, 18, 98, 96, 164, 4, 96, 96, 96, 98,
- 98, 95, 165, 95, 117, 172, 128, 170, 94, 171,
- 95, 104, 166, 95, 95, 95, 95, 126, 174, 126,
- 147, 168, 147, 107, 175, 120, 173, 96, 69, 96,
- 96, 96, 98, 96, 96, 11, 12, 118, 177, 3,
- 96, 5, 96, 27, 100, 101, 103, 146, 167, 20,
- 21, 22, 23, 24, 25, 26, 51, 105, 51, 110,
- 111, 110, 96, 96, 96, 5, 96, 96, 5, 96,
- 96, 5, 96, 55, 56, 121, 96, 129, 130, 162,
- 102, 159, 96, 5, 146, 96, 96, 130, 178, 14,
- 28, 31, 33, 34, 35, 37, 38, 39, 40, 41,
- 42, 43, 44, 45, 46, 53, 57, 92, 97, 115,
- 131, 132, 133, 134, 136, 137, 140, 141, 142, 143,
- 144, 145, 148, 150, 151, 152, 153, 154, 155, 4,
- 160, 95, 95, 95, 146, 146, 147, 147, 147, 149,
- 158, 156, 157, 156, 156, 156, 156, 156, 146, 138,
- 176, 5, 135, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 5, 96, 5, 96, 96, 96, 96, 96,
- 96, 96, 58, 59, 60, 139, 96
-};
-
-#define yyerrok (yyerrstatus = 0)
-#define yyclearin (yychar = YYEMPTY)
-#define YYEMPTY (-2)
-#define YYEOF 0
-
-#define YYACCEPT goto yyacceptlab
-#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror. This remains here temporarily
- to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. */
-
-#define YYFAIL goto yyerrlab
-
-#define YYRECOVERING() (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value) \
-do \
- if (yychar == YYEMPTY && yylen == 1) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- yytoken = YYTRANSLATE (yychar); \
- YYPOPSTACK (1); \
- goto yybackup; \
- } \
- else \
- { \
- yyerror (YY_("syntax error: cannot back up")); \
- YYERROR; \
- } \
-while (YYID (0))
-
-
-#define YYTERROR 1
-#define YYERRCODE 256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- do \
- if (YYID (N)) \
- { \
- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
- } \
- else \
- { \
- (Current).first_line = (Current).last_line = \
- YYRHSLOC (Rhs, 0).last_line; \
- (Current).first_column = (Current).last_column = \
- YYRHSLOC (Rhs, 0).last_column; \
- } \
- while (YYID (0))
-#endif
-
-
-/* YY_LOCATION_PRINT -- Print the location on the stream.
- This macro was not mandated originally: define only if we know
- we won't break user code: when these are the locations we know. */
-
-#ifndef YY_LOCATION_PRINT
-# if YYLTYPE_IS_TRIVIAL
-# define YY_LOCATION_PRINT(File, Loc) \
- fprintf (File, "%d.%d-%d.%d", \
- (Loc).first_line, (Loc).first_column, \
- (Loc).last_line, (Loc).last_column)
-# else
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments. */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (YYLEX_PARAM)
-#else
-# define YYLEX yylex ()
-#endif
-
-/* Enable debugging if requested. */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-# define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args) \
-do { \
- if (yydebug) \
- YYFPRINTF Args; \
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
-do { \
- if (yydebug) \
- { \
- YYFPRINTF (stderr, "%s ", Title); \
- yy_symbol_print (stderr, \
- Type, Value); \
- YYFPRINTF (stderr, "\n"); \
- } \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (!yyvaluep)
- return;
-# ifdef YYPRINT
- if (yytype < YYNTOKENS)
- YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
- YYUSE (yyoutput);
-# endif
- switch (yytype)
- {
- default:
- break;
- }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (yytype < YYNTOKENS)
- YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
- else
- YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
- yy_symbol_value_print (yyoutput, yytype, yyvaluep);
- YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included). |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
-#else
-static void
-yy_stack_print (bottom, top)
- yytype_int16 *bottom;
- yytype_int16 *top;
-#endif
-{
- YYFPRINTF (stderr, "Stack now");
- for (; bottom <= top; ++bottom)
- YYFPRINTF (stderr, " %d", *bottom);
- YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top) \
-do { \
- if (yydebug) \
- yy_stack_print ((Bottom), (Top)); \
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced. |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
-#else
-static void
-yy_reduce_print (yyvsp, yyrule)
- YYSTYPE *yyvsp;
- int yyrule;
-#endif
-{
- int yynrhs = yyr2[yyrule];
- int yyi;
- unsigned long int yylno = yyrline[yyrule];
- YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
- yyrule - 1, yylno);
- /* The symbols being reduced. */
- for (yyi = 0; yyi < yynrhs; yyi++)
- {
- fprintf (stderr, " $%d = ", yyi + 1);
- yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
- &(yyvsp[(yyi + 1) - (yynrhs)])
- );
- fprintf (stderr, "\n");
- }
-}
-
-# define YY_REDUCE_PRINT(Rule) \
-do { \
- if (yydebug) \
- yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace. It is left uninitialized so that
- multiple parsers can coexist. */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks. */
-#ifndef YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
- if the built-in stack extension method is used).
-
- Do not make this value too large; the results are undefined if
- YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
- evaluated with infinite-precision integer arithmetic. */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-
-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-# if defined __GLIBC__ && defined _STRING_H
-# define yystrlen strlen
-# else
-/* Return the length of YYSTR. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
- const char *yystr;
-#endif
-{
- YYSIZE_T yylen;
- for (yylen = 0; yystr[yylen]; yylen++)
- continue;
- return yylen;
-}
-# endif
-# endif
-
-# ifndef yystpcpy
-# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-# define yystpcpy stpcpy
-# else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
- YYDEST. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
- char *yydest;
- const char *yysrc;
-#endif
-{
- char *yyd = yydest;
- const char *yys = yysrc;
-
- while ((*yyd++ = *yys++) != '\0')
- continue;
-
- return yyd - 1;
-}
-# endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
- quotes and backslashes, so that it's suitable for yyerror. The
- heuristic is that double-quoting is unnecessary unless the string
- contains an apostrophe, a comma, or backslash (other than
- backslash-backslash). YYSTR is taken from yytname. If YYRES is
- null, do not copy; instead, return the length of what the result
- would have been. */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
- if (*yystr == '"')
- {
- YYSIZE_T yyn = 0;
- char const *yyp = yystr;
-
- for (;;)
- switch (*++yyp)
- {
- case '\'':
- case ',':
- goto do_not_strip_quotes;
-
- case '\\':
- if (*++yyp != '\\')
- goto do_not_strip_quotes;
- /* Fall through. */
- default:
- if (yyres)
- yyres[yyn] = *yyp;
- yyn++;
- break;
-
- case '"':
- if (yyres)
- yyres[yyn] = '\0';
- return yyn;
- }
- do_not_strip_quotes: ;
- }
-
- if (! yyres)
- return yystrlen (yystr);
-
- return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into YYRESULT an error message about the unexpected token
- YYCHAR while in state YYSTATE. Return the number of bytes copied,
- including the terminating null byte. If YYRESULT is null, do not
- copy anything; just return the number of bytes that would be
- copied. As a special case, return 0 if an ordinary "syntax error"
- message will do. Return YYSIZE_MAXIMUM if overflow occurs during
- size calculation. */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
- int yyn = yypact[yystate];
-
- if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
- return 0;
- else
- {
- int yytype = YYTRANSLATE (yychar);
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
- YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
- int yysize_overflow = 0;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- int yyx;
-
-# if 0
- /* This is so xgettext sees the translatable formats that are
- constructed on the fly. */
- YY_("syntax error, unexpected %s");
- YY_("syntax error, unexpected %s, expecting %s");
- YY_("syntax error, unexpected %s, expecting %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
- char *yyfmt;
- char const *yyf;
- static char const yyunexpected[] = "syntax error, unexpected %s";
- static char const yyexpecting[] = ", expecting %s";
- static char const yyor[] = " or %s";
- char yyformat[sizeof yyunexpected
- + sizeof yyexpecting - 1
- + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
- * (sizeof yyor - 1))];
- char const *yyprefix = yyexpecting;
-
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. */
- int yyxbegin = yyn < 0 ? -yyn : 0;
-
- /* Stay within bounds of both yycheck and yytname. */
- int yychecklim = YYLAST - yyn + 1;
- int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- int yycount = 1;
-
- yyarg[0] = yytname[yytype];
- yyfmt = yystpcpy (yyformat, yyunexpected);
-
- for (yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- yysize = yysize0;
- yyformat[sizeof yyunexpected - 1] = '\0';
- break;
- }
- yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
- yyfmt = yystpcpy (yyfmt, yyprefix);
- yyprefix = yyor;
- }
-
- yyf = YY_(yyformat);
- yysize1 = yysize + yystrlen (yyf);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
-
- if (yysize_overflow)
- return YYSIZE_MAXIMUM;
-
- if (yyresult)
- {
- /* Avoid sprintf, as that infringes on the user's name space.
- Don't have undefined behavior even if the translation
- produced a string with the wrong number of "%s"s. */
- char *yyp = yyresult;
- int yyi = 0;
- while ((*yyp = *yyf) != '\0')
- {
- if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
- {
- yyp += yytnamerr (yyp, yyarg[yyi++]);
- yyf += 2;
- }
- else
- {
- yyp++;
- yyf++;
- }
- }
- }
- return yysize;
- }
-}
-#endif /* YYERROR_VERBOSE */
-
-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol. |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep)
- const char *yymsg;
- int yytype;
- YYSTYPE *yyvaluep;
-#endif
-{
- YYUSE (yyvaluep);
-
- if (!yymsg)
- yymsg = "Deleting";
- YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
- switch (yytype)
- {
-
- default:
- break;
- }
-}
-
-
-/* Prevent warnings from -Wmissing-prototypes. */
-
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-
-/* The look-ahead symbol. */
-int yychar;
-
-/* The semantic value of the look-ahead symbol. */
-YYSTYPE yylval;
-
-/* Number of syntax errors so far. */
-int yynerrs;
-
-
-
-/*----------.
-| yyparse. |
-`----------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
- void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
-{
-
- int yystate;
- int yyn;
- int yyresult;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
- /* Look-ahead token as an internal (translated) token number. */
- int yytoken = 0;
-#if YYERROR_VERBOSE
- /* Buffer for error messages, and its allocated size. */
- char yymsgbuf[128];
- char *yymsg = yymsgbuf;
- YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
- /* Three stacks and their tools:
- `yyss': related to states,
- `yyvs': related to semantic values,
- `yyls': related to locations.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
- yytype_int16 yyssa[YYINITDEPTH];
- yytype_int16 *yyss = yyssa;
- yytype_int16 *yyssp;
-
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs = yyvsa;
- YYSTYPE *yyvsp;
-
-
-
-#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
-
- YYSIZE_T yystacksize = YYINITDEPTH;
-
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
-
-
- /* The number of symbols on the RHS of the reduced rule.
- Keep to zero when no symbol should be popped. */
- int yylen = 0;
-
- YYDPRINTF ((stderr, "Starting parse\n"));
-
- yystate = 0;
- yyerrstatus = 0;
- yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
-
- yyssp = yyss;
- yyvsp = yyvs;
-
- goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate. |
-`------------------------------------------------------------*/
- yynewstate:
- /* In all cases, when you get here, the value and location stacks
- have just been pushed. So pushing a state here evens the stacks. */
- yyssp++;
-
- yysetstate:
- *yyssp = yystate;
-
- if (yyss + yystacksize - 1 <= yyssp)
- {
- /* Get the current used size of the three stacks, in elements. */
- YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
- {
- /* Give user a chance to reallocate the stack. Use copies of
- these so that the &'s don't force the real ones into
- memory. */
- YYSTYPE *yyvs1 = yyvs;
- yytype_int16 *yyss1 = yyss;
-
-
- /* Each stack pointer address is followed by the size of the
- data in use in that stack, in bytes. This used to be a
- conditional around just the two extra args, but that might
- be undefined if yyoverflow is a macro. */
- yyoverflow (YY_("memory exhausted"),
- &yyss1, yysize * sizeof (*yyssp),
- &yyvs1, yysize * sizeof (*yyvsp),
-
- &yystacksize);
-
- yyss = yyss1;
- yyvs = yyvs1;
- }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
- goto yyexhaustedlab;
-# else
- /* Extend the stack our own way. */
- if (YYMAXDEPTH <= yystacksize)
- goto yyexhaustedlab;
- yystacksize *= 2;
- if (YYMAXDEPTH < yystacksize)
- yystacksize = YYMAXDEPTH;
-
- {
- yytype_int16 *yyss1 = yyss;
- union yyalloc *yyptr =
- (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
- if (! yyptr)
- goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss);
- YYSTACK_RELOCATE (yyvs);
-
-# undef YYSTACK_RELOCATE
- if (yyss1 != yyssa)
- YYSTACK_FREE (yyss1);
- }
-# endif
-#endif /* no yyoverflow */
-
- yyssp = yyss + yysize - 1;
- yyvsp = yyvs + yysize - 1;
-
-
- YYDPRINTF ((stderr, "Stack size increased to %lu\n",
- (unsigned long int) yystacksize));
-
- if (yyss + yystacksize - 1 <= yyssp)
- YYABORT;
- }
-
- YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
- goto yybackup;
-
-/*-----------.
-| yybackup. |
-`-----------*/
-yybackup:
-
- /* Do appropriate processing given the current state. Read a
- look-ahead token if we need one and don't already have one. */
-
- /* First try to decide what to do without reference to look-ahead token. */
- yyn = yypact[yystate];
- if (yyn == YYPACT_NINF)
- goto yydefault;
-
- /* Not known => get a look-ahead token if don't already have one. */
-
- /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
- if (yychar == YYEMPTY)
- {
- YYDPRINTF ((stderr, "Reading a token: "));
- yychar = YYLEX;
- }
-
- if (yychar <= YYEOF)
- {
- yychar = yytoken = YYEOF;
- YYDPRINTF ((stderr, "Now at end of input.\n"));
- }
- else
- {
- yytoken = YYTRANSLATE (yychar);
- YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
- }
-
- /* If the proper action on seeing token YYTOKEN is to reduce or to
- detect an error, take that action. */
- yyn += yytoken;
- if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
- goto yydefault;
- yyn = yytable[yyn];
- if (yyn <= 0)
- {
- if (yyn == 0 || yyn == YYTABLE_NINF)
- goto yyerrlab;
- yyn = -yyn;
- goto yyreduce;
- }
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- /* Count tokens shifted since error; after three, turn off error
- status. */
- if (yyerrstatus)
- yyerrstatus--;
-
- /* Shift the look-ahead token. */
- YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
- /* Discard the shifted token unless it is eof. */
- if (yychar != YYEOF)
- yychar = YYEMPTY;
-
- yystate = yyn;
- *++yyvsp = yylval;
-
- goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state. |
-`-----------------------------------------------------------*/
-yydefault:
- yyn = yydefact[yystate];
- if (yyn == 0)
- goto yyerrlab;
- goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction. |
-`-----------------------------*/
-yyreduce:
- /* yyn is the number of a rule to reduce with. */
- yylen = yyr2[yyn];
-
- /* If YYLEN is nonzero, implement the default value of the action:
- `$$ = $1'.
-
- Otherwise, the following line sets YYVAL to garbage.
- This behavior is undocumented and Bison
- users should not rely upon it. Assigning to YYVAL
- unconditionally makes the parser a bit smaller, and it avoids a
- GCC warning that YYVAL may be used uninitialized. */
- yyval = yyvsp[1-yylen];
-
-
- YY_REDUCE_PRINT (yyn);
- switch (yyn)
- {
- case 17:
-#line 212 "parser.y"
- {
- opt.log_activity = lastnr;
- ;}
- break;
-
- case 18:
-#line 220 "parser.y"
- {
- opt.tcp_bufsz = lastnr;
- ;}
- break;
-
- case 19:
-#line 228 "parser.y"
- {
- opt.dns_cachettl = lastnr;
- ;}
- break;
-
- case 20:
-#line 236 "parser.y"
- {
- opt.log_facility = lastnr;
- ;}
- break;
-
- case 21:
-#line 244 "parser.y"
- {
- opt.shmperm = lastnr;
- ;}
- break;
-
- case 22:
-#line 253 "parser.y"
- {
- opt.sloppyportbind = lastnr;
- ;}
- break;
-
- case 23:
-#line 262 "parser.y"
- {
- opt.leave_proctitle = lastnr;
- ;}
- break;
-
- case 24:
-#line 272 "parser.y"
- {
- /* Check integrity, supply defaults */
- check_service (cur_service);
-
- if (!cur_service.shmkey)
- cur_service.shmkey = (unsigned) hashpjw (cur_service.name);
- msg ("Service %s: shared memory key set to 0x%8.8x",
- cur_service.name, cur_service.shmkey);
-
- if (!cur_service.check_cmd)
- cur_service.check_cmd = xstrdup ("");
-
- /* Add to the list, reset cur_service for next run */
- service = xrealloc (service, ++nservice * sizeof(Service));
- service[nservice - 1] = cur_service;
- memset (&cur_service, 0, sizeof(Service));
- ;}
- break;
-
- case 26:
-#line 298 "parser.y"
- {
- pmsg ("service [%s]\n", SYMBOL);
- for (i = 0; i < nservice; i++)
- if (!strcmp (service[i].name, SYMBOL))
- error ("Duplicate definition of service '%s'", SYMBOL);
- cur_service.name = xstrdup(SYMBOL);
- ;}
- break;
-
- case 30:
-#line 320 "parser.y"
- {
- pmsg ("sevice port [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- cur_service.port = (yyvsp[(1) - (1)]).set[0].v.ival;
- free ((yyvsp[(1) - (1)]).set);
- ;}
- break;
-
- case 31:
-#line 326 "parser.y"
- {
- pmsg ("service binding [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- cur_service.bind = (yyvsp[(1) - (1)]).set[0].v.sval;
- free ((yyvsp[(1) - (1)]).set);
- ;}
- break;
-
- case 32:
-#line 332 "parser.y"
- {
- pmsg ("service verbosity [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- cur_service.verbosity = (yyvsp[(1) - (1)]).set[0].v.ival;
- free ((yyvsp[(1) - (1)]).set);
- ;}
- break;
-
- case 33:
-#line 338 "parser.y"
- {
- pmsg ("service dispatch mode [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- pmsg ("service dispatch over [%d]\n", lastovernr);
- pmsg ("service dispatch exthandler [%s]\n", lastext);
- cur_service.dispatchtype = (yyvsp[(1) - (1)]).set[0].v.ival;
- cur_service.dispatchover = lastovernr;
- cur_service.dispatchext = xstrdup(lastext);
- free ((yyvsp[(1) - (1)]).set);
- ;}
- break;
-
- case 34:
-#line 348 "parser.y"
- {
- pmsg ("service revival interval [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- pmsg ("service revival cmd [%s]\n", (yyvsp[(1) - (1)]).set[1].v.sval);
- cur_service.rev_interval = (yyvsp[(1) - (1)]).set[0].v.ival;
- cur_service.check_cmd = (yyvsp[(1) - (1)]).set[1].v.sval;
- free ((yyvsp[(1) - (1)]).set);
- ;}
- break;
-
- case 35:
-#line 356 "parser.y"
- {
- pmsg ("service check interval [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- pmsg ("service check cmd [%s]\n", (yyvsp[(1) - (1)]).set[1].v.sval);
- cur_service.check_interval = (yyvsp[(1) - (1)]).set[0].v.ival;
- cur_service.check_cmd = (yyvsp[(1) - (1)]).set[1].v.sval;
- ;}
- break;
-
- case 36:
-#line 363 "parser.y"
- {
- pmsg ("service backlog [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- cur_service.backlog = (yyvsp[(1) - (1)]).set[0].v.ival;
- free ((yyvsp[(1) - (1)]).set);
- ;}
- break;
-
- case 37:
-#line 369 "parser.y"
- {
- pmsg ("service shmkey [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- cur_service.shmkey = (yyvsp[(1) - (1)]).set[0].v.ival;
- free ((yyvsp[(1) - (1)]).set);
- ;}
- break;
-
- case 38:
-#line 375 "parser.y"
- {
- pmsg ("connection timout [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- cur_service.connectiontimeout = (yyvsp[(1) - (1)]).set[0].v.ival;
- free ((yyvsp[(1) - (1)]).set);
- ;}
- break;
-
- case 39:
-#line 381 "parser.y"
- {
- pmsg ("max clients in service [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- cur_service.maxconnections = (yyvsp[(1) - (1)]).set[0].v.ival;
- free ((yyvsp[(1) - (1)]).set);
- ;}
- break;
-
- case 40:
-#line 387 "parser.y"
- {
- pmsg ("service type [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- cur_service.type = (yyvsp[(1) - (1)]).set[0].v.ival;
- free ((yyvsp[(1) - (1)]).set);
- ;}
- break;
-
- case 41:
-#line 393 "parser.y"
- {
- pmsg ("service header inspection [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- cur_service.inspection = (yyvsp[(1) - (1)]).set[0].v.ival;
- free ((yyvsp[(1) - (1)]).set);
- ;}
- break;
-
- case 42:
-#line 399 "parser.y"
- {
- pmsg ("allow from [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- add_allowfrom ((yyvsp[(1) - (1)]).set[0].v.sval);
- free ((yyvsp[(1) - (1)]).set);
- ;}
- break;
-
- case 43:
-#line 405 "parser.y"
- {
- pmsg ("allow file [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- cur_service.allowfile = (yyvsp[(1) - (1)]).set[0].v.sval;
- free ((yyvsp[(1) - (1)]).set);
- ;}
- break;
-
- case 44:
-#line 411 "parser.y"
- {
- pmsg ("deny from [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- add_denyfrom ((yyvsp[(1) - (1)]).set[0].v.sval);
- free ((yyvsp[(1) - (1)]).set);
- ;}
- break;
-
- case 45:
-#line 417 "parser.y"
- {
- pmsg ("deny file [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- cur_service.denyfile = (yyvsp[(1) - (1)]).set[0].v.sval;
- free ((yyvsp[(1) - (1)]).set);
- ;}
- break;
-
- case 46:
-#line 423 "parser.y"
- {
- pmsg ("user account [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- setuseraccount ((yyvsp[(1) - (1)]).set[0].v.sval);
- free ((yyvsp[(1) - (1)]).set[0].v.sval);
- free ((yyvsp[(1) - (1)]).set);
- ;}
- break;
-
- case 47:
-#line 430 "parser.y"
- {
- pmsg ("converting backend statements, count is [%d]\n", (yyvsp[(1) - (1)]).n);
- for (i = 0; i < (yyvsp[(1) - (1)]).n; i++)
- switch ((yyvsp[(1) - (1)]).set[i].cf) {
- case cf_portspec:
- pmsg ("backend port [%d]\n", (yyvsp[(1) - (1)]).set[i].v.ival);
- cur_backend.initial_port = (yyvsp[(1) - (1)]).set[i].v.ival;
- break;
- case cf_serverspec:
- pmsg ("backend server [%s]\n", (yyvsp[(1) - (1)]).set[i].v.sval);
- cur_backend.initial_server = serverpart ((yyvsp[(1) - (1)]).set[i].v.sval);
- cur_backend.initial_port = portpart ((yyvsp[(1) - (1)]).set[i].v.sval);
- free ((yyvsp[(1) - (1)]).set[i].v.sval);
- break;
- case cf_verbosityspec:
- pmsg ("backend verbosity [%d]\n", (yyvsp[(1) - (1)]).set[i].v.ival);
- cur_backend.verbosity = (yyvsp[(1) - (1)]).set[i].v.ival;
- break;
- case cf_onstartspec:
- pmsg ("backend onstart [%s]\n", (yyvsp[(1) - (1)]).set[i].v.sval);
- cur_backend.onstart = (yyvsp[(1) - (1)]).set[i].v.sval;
- break;
- case cf_onfailspec:
- pmsg ("backend onfail [%s]\n", (yyvsp[(1) - (1)]).set[i].v.sval);
- cur_backend.onfail = (yyvsp[(1) - (1)]).set[i].v.sval;
- break;
- case cf_onendspec:
- pmsg ("backend onend [%s]\n", (yyvsp[(1) - (1)]).set[i].v.sval);
- cur_backend.onend = (yyvsp[(1) - (1)]).set[i].v.sval;
- break;
- case cf_dumpspec:
- pmsg ("backend trafficlog [%s]\n", (yyvsp[(1) - (1)]).set[i].v.sval);
- cur_backend.dumpfile = (yyvsp[(1) - (1)]).set[i].v.sval;
- break;
- case cf_thruspec:
- pmsg ("backend throughputlog [%s]\n", (yyvsp[(1) - (1)]).set[i].v.sval);
- cur_backend.thruputfile = (yyvsp[(1) - (1)]).set[i].v.sval;
- break;
- case cf_httptimingspec:
- if (cur_service.type != type_http)
- error ("'httptiminglog' only allowed in 'type http' "
- "service definitions");
- pmsg ("backend http timing log [%s]\n", (yyvsp[(1) - (1)]).set[i].v.sval);
- cur_backend.timinglog = (yyvsp[(1) - (1)]).set[i].v.sval;
- break;
- case cf_weightspec:
- pmsg ("backend weight [%d]\n", (yyvsp[(1) - (1)]).set[i].v.ival);
- cur_backend.weight = (yyvsp[(1) - (1)]).set[i].v.ival;
- break;
- case cf_decayspec:
- pmsg ("backend decay [%d]\n", (yyvsp[(1) - (1)]).set[i].v.ival);
- if ((yyvsp[(1) - (1)]).set[i].v.ival >= 100)
- error ("Decay specifier %d must be a percentage, "
- "never more than 99",
- (yyvsp[(1) - (1)]).set[i].v.ival);
- cur_backend.decay = (yyvsp[(1) - (1)]).set[i].v.ival;
- break;
- case cf_maxconnectionsspec:
- pmsg ("backend max clients [%d]\n", (yyvsp[(1) - (1)]).set[i].v.ival);
- cur_backend.maxconnections = (yyvsp[(1) - (1)]).set[i].v.ival;
- break;
- case cf_stickycookiespec:
- pmsg ("backend sticky cookie [%s]\n",
- (yyvsp[(1) - (1)]).set[i].v.sval);
- cur_backend.stickycookie = (yyvsp[(1) - (1)]).set[i].v.sval;
- break;
- case cf_addclientheaderspec:
- pmsg ("client header to add [%s]\n",
- (yyvsp[(1) - (1)]).set[i].v.sval);
- cur_backend.addclientheader =
- xrealloc (cur_backend.addclientheader,
- (cur_backend.naddclientheader + 1) *
- sizeof(char*));
- cur_backend.addclientheader
- [cur_backend.naddclientheader++] =
- (yyvsp[(1) - (1)]).set[i].v.sval;
- break;
- case cf_setclientheaderspec:
- pmsg ("client header to set [%s]\n",
- (yyvsp[(1) - (1)]).set[i].v.sval);
- cur_backend.setclientheader =
- xrealloc (cur_backend.setclientheader,
- (cur_backend.nsetclientheader + 1) *
- sizeof(char*));
- cur_backend.setclientheader
- [cur_backend.nsetclientheader++] =
- (yyvsp[(1) - (1)]).set[i].v.sval;
- break;
- case cf_appendclientheaderspec:
- pmsg ("client header to append [%s]\n",
- (yyvsp[(1) - (1)]).set[i].v.sval);
- cur_backend.appendclientheader =
- xrealloc (cur_backend.appendclientheader,
- (cur_backend.nappendclientheader + 1) *
- sizeof(char*));
- cur_backend.appendclientheader
- [cur_backend.nappendclientheader++] =
- (yyvsp[(1) - (1)]).set[i].v.sval;
- break;
- case cf_addserverheaderspec:
- pmsg ("server header to add [%s]\n",
- (yyvsp[(1) - (1)]).set[i].v.sval);
- cur_backend.addserverheader =
- xrealloc (cur_backend.addserverheader,
- (cur_backend.naddserverheader + 1) *
- sizeof(char*));
- cur_backend.addserverheader
- [cur_backend.naddserverheader++] =
- (yyvsp[(1) - (1)]).set[i].v.sval;
- break;
- case cf_setserverheaderspec:
- pmsg ("server header to set [%s]\n",
- (yyvsp[(1) - (1)]).set[i].v.sval);
- cur_backend.setserverheader =
- xrealloc (cur_backend.setserverheader,
- (cur_backend.nsetserverheader + 1) *
- sizeof(char*));
- cur_backend.setserverheader
- [cur_backend.nsetserverheader++] =
- (yyvsp[(1) - (1)]).set[i].v.sval;
- break;
- case cf_appendserverheaderspec:
- pmsg ("server header to append:",
- (yyvsp[(1) - (1)]).set[i].v.sval);
- cur_backend.appendserverheader =
- xrealloc (cur_backend.appendserverheader,
- (cur_backend.nappendserverheader + 1) *
- sizeof(char*));
- cur_backend.appendserverheader
- [cur_backend.nappendserverheader++] =
- (yyvsp[(1) - (1)]).set[i].v.sval;
- break;
- case cf_retriesspec:
- pmsg ("backend retries [%d]\n", (yyvsp[(1) - (1)]).set[i].v.ival);
- cur_backend.retries = (yyvsp[(1) - (1)]).set[i].v.ival;
- break;
- case cf_statespec:
- pmsg ("backend initial state [%d]\n", (yyvsp[(1) - (1)]).set[i].v.ival);
- cur_backend.initial_avail = (yyvsp[(1) - (1)]).set[i].v.ival;
- break;
- default:
- error ("Internal jam, unhandled type %d "
- "in backend specification",
- (yyvsp[(1) - (1)]).set[i].cf);
- }
- free ((yyvsp[(1) - (1)]).set);
-
- /* Verify the backend block, supply defaults,
- * And so on.
- */
- if (!cur_backend.initial_port)
- error ("Service %s: back end %s lacks port",
- cur_service.name, cur_backend.name);
- if (cur_service.dispatchext && cur_backend.maxconnections)
- error ("Service %s: back end %s defines maxconnections, "
- "but an external dispatcher is in effect",
- cur_service.name, cur_backend.name);
- if (cur_backend.weight < 1)
- cur_backend.weight = 1;
- if (cur_backend.retries < 1)
- cur_backend.retries = 1;
-
- /* Add to the list. */
- cur_service.backend = xrealloc (cur_service.backend,
- ++cur_service.nbackend *
- sizeof(Backend));
- cur_service.backend[cur_service.nbackend - 1] =
- cur_backend;
- pmsg ("this was backend definition [%d]\n", cur_service.nbackend);
- memset (&cur_backend, 0, sizeof(cur_backend));
- ;}
- break;
-
- case 48:
-#line 606 "parser.y"
- {
- pmsg ("port statement [%d]\n", lastnr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_portspec;
- (yyval).set[0].v.ival = lastnr;
- ;}
- break;
-
- case 49:
-#line 618 "parser.y"
- {
- pmsg ("bindto statement [%d]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_bindspec;
- (yyval).set[0].v.sval = xstrdup(laststr);
- ;}
- break;
-
- case 50:
-#line 629 "parser.y"
- {
- setlaststr (laststring);
- free (laststring);
- laststring = 0;
- ;}
- break;
-
- case 51:
-#line 638 "parser.y"
- {
- setlastnr (SYMBOL);
- ;}
- break;
-
- case 53:
-#line 652 "parser.y"
- {
- pmsg ("verbosity statement [%d]\n", lastnr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_verbosityspec;
- (yyval).set[0].v.ival = lastnr;
- ;}
- break;
-
- case 54:
-#line 662 "parser.y"
- {
- lastnr = 1;
- ;}
- break;
-
- case 55:
-#line 666 "parser.y"
- {
- lastnr = 0;
- ;}
- break;
-
- case 56:
-#line 675 "parser.y"
- {
- (yyval) = (yyvsp[(2) - (4)]);
- ;}
- break;
-
- case 59:
-#line 685 "parser.y"
- {
- (yyval).n = 0;
- ;}
- break;
-
- case 60:
-#line 692 "parser.y"
- {
- pmsg ("dispatch mode statement [%d]\n", lastnr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_dispatchspec;
- (yyval).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);
- ;}
- break;
-
- case 61:
-#line 709 "parser.y"
- {
- setlastovernr (SYMBOL);
- ;}
- break;
-
- case 62:
-#line 715 "parser.y"
- {
- pmsg ("external handler [%s]\n", laststr);
- if (lastnr != ds_externalhandler)
- error ("Service %s: this dispatch mode doesn't support "
- "an external handler", cur_service.name);
- setlastext (laststr);
- ;}
- break;
-
- case 63:
-#line 726 "parser.y"
- {
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].v.ival = lastnr;
- ;}
- break;
-
- case 64:
-#line 734 "parser.y"
- {
- lastnr = ds_roundrobin;
- ;}
- break;
-
- case 65:
-#line 738 "parser.y"
- {
- lastnr = ds_random;
- ;}
- break;
-
- case 66:
-#line 742 "parser.y"
- {
- lastnr = ds_byduration;
- ;}
- break;
-
- case 67:
-#line 746 "parser.y"
- {
- lastnr = ds_bysize;
- ;}
- break;
-
- case 68:
-#line 750 "parser.y"
- {
- lastnr = ds_byorder;
- ;}
- break;
-
- case 69:
-#line 754 "parser.y"
- {
- lastnr = ds_byconnections;
- ;}
- break;
-
- case 70:
-#line 758 "parser.y"
- {
- lastnr = ds_externalhandler;
- ;}
- break;
-
- case 71:
-#line 762 "parser.y"
- {
- lastnr = ds_byclientip;
- ;}
- break;
-
- case 72:
-#line 770 "parser.y"
- {
- pmsg ("user account statement [%d]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_useraccountspec;
- (yyval).set[0].v.sval = xstrdup (laststr);
- ;}
- break;
-
- case 73:
-#line 781 "parser.y"
- {
- setlaststr (laststring);
- free (laststring);
- laststring = 0;
- ;}
- break;
-
- case 74:
-#line 792 "parser.y"
- {
- pmsg ("reviving interval statement [%d]\n", lastnr);
- (yyval).n = 2;
- (yyval).set = xmalloc (2 * sizeof(Confset));
- (yyval).set[0].cf = cf_revivespec;
- (yyval).set[0].v.ival = lastnr;
- if ((yyvsp[(3) - (4)]).n) {
- pmsg ("reviving externalhandler [%s]\n", (yyvsp[(3) - (4)]).set[0].v.sval);
- (yyval).set[1].v.sval = (yyvsp[(3) - (4)]).set[0].v.sval;
- } else
- (yyval).set[1].v.sval = 0;
- ;}
- break;
-
- case 75:
-#line 810 "parser.y"
- {
- pmsg ("check interval [%d]\n", lastnr);
- (yyval).n = 2;
- (yyval).set = xmalloc (2 * sizeof(Confset));
- (yyval).set[0].cf = cf_checkspec;
- (yyval).set[0].v.ival = lastnr;
- if ((yyvsp[(3) - (4)]).n) {
- pmsg ("check externalhandler [%s]\n", (yyvsp[(3) - (4)]).set[0].v.sval);
- (yyval).set[1].v.sval = (yyvsp[(3) - (4)]).set[0].v.sval;
- } else
- (yyval).set[1].v.sval = 0;
- ;}
- break;
-
- case 77:
-#line 827 "parser.y"
- {
- (yyval).n = 0;
- ;}
- break;
-
- case 78:
-#line 834 "parser.y"
- {
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].v.sval = xstrdup (laststr);
- ;}
- break;
-
- case 79:
-#line 844 "parser.y"
- {
- pmsg ("backlog statement [%d]\n", lastnr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_backlogspec;
- (yyval).set[0].v.ival = lastnr;
- ;}
- break;
-
- case 80:
-#line 856 "parser.y"
- {
- pmsg ("shmkey statement [%d]\n", lastnr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_shmkeyspec;
- (yyval).set[0].v.ival = lastnr;
- ;}
- break;
-
- case 81:
-#line 868 "parser.y"
- {
- pmsg ("connection timeout statement [%d]\n", lastnr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_connectiontimeoutspec;
- (yyval).set[0].v.ival = lastnr;
- ;}
- break;
-
- case 82:
-#line 880 "parser.y"
- {
- pmsg ("max clients statement (service) [%d]\n", lastnr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_maxconnectionsspec;
- (yyval).set[0].v.ival = lastnr;
- ;}
- break;
-
- case 83:
-#line 892 "parser.y"
- {
- pmsg ("service type [%d]\n", lastnr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_typespec;
- (yyval).set[0].v.ival = lastnr;
- ;}
- break;
-
- case 85:
-#line 907 "parser.y"
- {
- lastnr = type_any;
- ;}
- break;
-
- case 86:
-#line 911 "parser.y"
- {
- lastnr = type_http;
- ;}
- break;
-
- case 87:
-#line 919 "parser.y"
- {
- pmsg ("service header inspection [%d]\n", lastnr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_inspectionspec;
- (yyval).set[0].v.ival = lastnr;
- ;}
- break;
-
- case 89:
-#line 934 "parser.y"
- {
- lastnr = ins_deep;
- ;}
- break;
-
- case 90:
-#line 938 "parser.y"
- {
- lastnr = ins_shallow;
- ;}
- break;
-
- case 91:
-#line 946 "parser.y"
- {
- pmsg ("allow from [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_allowfromspec;
- (yyval).set[0].v.sval = xstrdup(laststr);
- ;}
- break;
-
- case 92:
-#line 958 "parser.y"
- {
- pmsg ("deny from [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_denyfromspec;
- (yyval).set[0].v.sval = xstrdup(laststr);
- ;}
- break;
-
- case 93:
-#line 970 "parser.y"
- {
- pmsg ("allow file [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_allowfilespec;
- (yyval).set[0].v.sval = xstrdup(laststr);
- ;}
- break;
-
- case 94:
-#line 982 "parser.y"
- {
- pmsg ("deny file [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_allowfilespec;
- (yyval).set[0].v.sval = xstrdup(laststr);
- ;}
- break;
-
- case 95:
-#line 993 "parser.y"
- {
- setlaststr (laststring);
- free (laststring);
- laststring = 0;
- ;}
- break;
-
- case 96:
-#line 1005 "parser.y"
- {
- (yyval) = (yyvsp[(4) - (5)]);
- ;}
- break;
-
- case 97:
-#line 1012 "parser.y"
- {
- pmsg ("backend name [%s]\n", SYMBOL);
- for (i = 0; i < cur_service.nbackend; i++)
- if (!strcmp (cur_service.backend[i].name, SYMBOL))
- error ("Service %s: back end '%s' multiply defined",
- cur_service.name, SYMBOL);
- cur_backend.name = xstrdup (SYMBOL);
- ;}
- break;
-
- case 98:
-#line 1024 "parser.y"
- {
- (yyvsp[(1) - (2)]).n++;
- (yyvsp[(1) - (2)]).set = xrealloc ((yyvsp[(1) - (2)]).set, (yyvsp[(1) - (2)]).n * sizeof(Confset));
- (yyvsp[(1) - (2)]).set[(yyvsp[(1) - (2)]).n - 1] = (yyvsp[(2) - (2)]).set[0];
- (yyval) = (yyvsp[(1) - (2)]);
- ;}
- break;
-
- case 99:
-#line 1031 "parser.y"
- {
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 100:
-#line 1038 "parser.y"
- {
- (yyval) = (yyvsp[(2) - (2)]);
- ;}
- break;
-
- case 101:
-#line 1044 "parser.y"
- {
- pmsg ("backend server [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 102:
-#line 1049 "parser.y"
- {
- pmsg ("backend port [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 103:
-#line 1054 "parser.y"
- {
- pmsg ("backend verbosity [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 104:
-#line 1059 "parser.y"
- {
- pmsg ("backend onstart [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 105:
-#line 1064 "parser.y"
- {
- pmsg ("backend onend [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 106:
-#line 1069 "parser.y"
- {
- pmsg ("backend onfail [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 107:
-#line 1074 "parser.y"
- {
- pmsg ("backend trafficlog [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 108:
-#line 1079 "parser.y"
- {
- pmsg ("backend trafficlog [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 109:
-#line 1084 "parser.y"
- {
- pmsg ("backend HTTP timing log [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 110:
-#line 1089 "parser.y"
- {
- pmsg ("backend weight [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 111:
-#line 1094 "parser.y"
- {
- pmsg ("backend decay [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 112:
-#line 1099 "parser.y"
- {
- pmsg ("backend maxconnections [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 113:
-#line 1104 "parser.y"
- {
- pmsg ("backend sticky cookie [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 114:
-#line 1109 "parser.y"
- {
- pmsg ("addclientheader [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 115:
-#line 1114 "parser.y"
- {
- pmsg ("setclientheader [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 116:
-#line 1119 "parser.y"
- {
- pmsg ("appendclientheader [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 117:
-#line 1124 "parser.y"
- {
- pmsg ("addserverheader [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 118:
-#line 1129 "parser.y"
- {
- pmsg ("setserverheader [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 119:
-#line 1134 "parser.y"
- {
- pmsg ("appendserverheader [%s]\n", (yyvsp[(1) - (1)]).set[0].v.sval);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 120:
-#line 1139 "parser.y"
- {
- pmsg ("backend retries [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 121:
-#line 1144 "parser.y"
- {
- pmsg ("backend state [%d]\n", (yyvsp[(1) - (1)]).set[0].v.ival);
- (yyval) = (yyvsp[(1) - (1)]);
- ;}
- break;
-
- case 122:
-#line 1154 "parser.y"
- {
- pmsg ("server statement [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof (Confset));
- (yyval).set[0].cf = cf_serverspec;
- (yyval).set[0].v.sval = xstrdup (laststr);
- ;}
- break;
-
- case 123:
-#line 1166 "parser.y"
- {
- pmsg ("weight statement [%d]\n", lastnr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof (Confset));
- (yyval).set[0].cf = cf_weightspec;
- (yyval).set[0].v.ival = lastnr;
- ;}
- break;
-
- case 124:
-#line 1178 "parser.y"
- {
- pmsg ("decay statement [%d]\n", lastnr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof (Confset));
- (yyval).set[0].cf = cf_decayspec;
- (yyval).set[0].v.ival = lastnr;
- ;}
- break;
-
- case 125:
-#line 1188 "parser.y"
- {
- setlaststr (laststring);
- ;}
- break;
-
- case 126:
-#line 1196 "parser.y"
- {
- pmsg ("retries [%d]\n", lastnr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_retriesspec;
- (yyval).set[0].v.ival = lastnr;
- ;}
- break;
-
- case 127:
-#line 1208 "parser.y"
- {
- pmsg ("state [%d]\n", lastnr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_statespec;
- (yyval).set[0].v.ival = lastnr;
- ;}
- break;
-
- case 129:
-#line 1223 "parser.y"
- {
- lastnr = st_available;
- ;}
- break;
-
- case 130:
-#line 1227 "parser.y"
- {
- lastnr = st_unavailable;
- ;}
- break;
-
- case 131:
-#line 1231 "parser.y"
- {
- lastnr = st_down;
- ;}
- break;
-
- case 132:
-#line 1239 "parser.y"
- {
- pmsg ("onstart statement [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof (Confset));
- (yyval).set[0].cf = cf_onstartspec;
- (yyval).set[0].v.sval = xstrdup (laststr);
- ;}
- break;
-
- case 133:
-#line 1251 "parser.y"
- {
- pmsg ("onfail statement [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof (Confset));
- (yyval).set[0].cf = cf_onfailspec;
- (yyval).set[0].v.sval = xstrdup (laststr);
- ;}
- break;
-
- case 134:
-#line 1263 "parser.y"
- {
- pmsg ("onend statement [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof (Confset));
- (yyval).set[0].cf = cf_onendspec;
- (yyval).set[0].v.sval = xstrdup (laststr);
- ;}
- break;
-
- case 135:
-#line 1275 "parser.y"
- {
- pmsg ("trafficlog statement [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof (Confset));
- (yyval).set[0].cf = cf_dumpspec;
- (yyval).set[0].v.sval = xstrdup (laststr);
- ;}
- break;
-
- case 136:
-#line 1287 "parser.y"
- {
- pmsg ("throughputlog statement [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof (Confset));
- (yyval).set[0].cf = cf_thruspec;
- (yyval).set[0].v.sval = xstrdup (laststr);
- ;}
- break;
-
- case 137:
-#line 1299 "parser.y"
- {
- pmsg ("httptiminglog statement [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof (Confset));
- (yyval).set[0].cf = cf_httptimingspec;
- (yyval).set[0].v.sval = xstrdup (laststr);
- ;}
- break;
-
- case 138:
-#line 1310 "parser.y"
- {
- setlaststr (laststring);
- free (laststring);
- laststring = 0;
- ;}
- break;
-
- case 139:
-#line 1319 "parser.y"
- {
- setlaststr (laststring);
- free (laststring);
- laststring = 0;
- ;}
- break;
-
- case 140:
-#line 1329 "parser.y"
- {
- pmsg ("insertcookie statement [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof (Confset));
- (yyval).set[0].cf = cf_stickycookiespec;
- (yyval).set[0].v.sval = xstrdup (laststr);
- ;}
- break;
-
- case 141:
-#line 1340 "parser.y"
- {
- setlaststr (laststring);
- free (laststring);
- laststring = 0;
- ;}
- break;
-
- case 142:
-#line 1350 "parser.y"
- {
- pmsg ("addclientheader statement [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_addclientheaderspec;
- (yyval).set[0].v.sval = xstrdup (laststr);
- ;}
- break;
-
- case 143:
-#line 1362 "parser.y"
- {
- pmsg ("setclientheader statement [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_setclientheaderspec;
- (yyval).set[0].v.sval = xstrdup (laststr);
- ;}
- break;
-
- case 144:
-#line 1374 "parser.y"
- {
- pmsg ("appendclientheader statement [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_appendclientheaderspec;
- (yyval).set[0].v.sval = xstrdup (laststr);
- ;}
- break;
-
- case 145:
-#line 1386 "parser.y"
- {
- pmsg ("addserverheader statement [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_addserverheaderspec;
- (yyval).set[0].v.sval = xstrdup (laststr);
- ;}
- break;
-
- case 146:
-#line 1398 "parser.y"
- {
- pmsg ("setserverheader statement [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_setserverheaderspec;
- (yyval).set[0].v.sval = xstrdup (laststr);
- ;}
- break;
-
- case 147:
-#line 1410 "parser.y"
- {
- pmsg ("appendserverheader statement [%s]\n", laststr);
- (yyval).n = 1;
- (yyval).set = xmalloc (sizeof(Confset));
- (yyval).set[0].cf = cf_appendserverheaderspec;
- (yyval).set[0].v.sval = xstrdup (laststr);
- ;}
- break;
-
- case 148:
-#line 1421 "parser.y"
- {
- setlaststr (laststring);
- free (laststring);
- laststring = 0;
- ;}
- break;
-
- case 149:
-#line 1428 "parser.y"
- {
- yyerrmsg = "HTTP header specifier expected";
-;}
- break;
-
- case 150:
-#line 1433 "parser.y"
- {
- yyerrmsg = "cookie specifier expected";
-;}
- break;
-
- case 151:
-#line 1438 "parser.y"
- {
- yyerrmsg = "number expected";
-;}
- break;
-
- case 152:
-#line 1443 "parser.y"
- {
- yyerrmsg = "hostname or IP address expected";
-;}
- break;
-
- case 153:
-#line 1448 "parser.y"
- {
- yyerrmsg = "'service' expected";
-;}
- break;
-
- case 154:
-#line 1453 "parser.y"
- {
- yyerrmsg = "backend definition statement expected";
-;}
- break;
-
- case 155:
-#line 1458 "parser.y"
- {
- yyerrmsg = "service body statement expected";
-;}
- break;
-
- case 156:
-#line 1463 "parser.y"
- {
- yyerrmsg = "semicolon (;) expected";
-;}
- break;
-
- case 157:
-#line 1468 "parser.y"
- {
- yyerrmsg = "'on' or 'off' expetcted";
-;}
- break;
-
- case 158:
-#line 1473 "parser.y"
- {
- yyerrmsg = "dispatch method expected";
-;}
- break;
-
- case 159:
-#line 1478 "parser.y"
- {
- yyerrmsg = "command line expected";
-;}
- break;
-
- case 160:
-#line 1483 "parser.y"
- {
- yyerrmsg = "file name expected";
-;}
- break;
-
- case 161:
-#line 1488 "parser.y"
- {
- yyerrmsg = "service name (identifier) expected";
-;}
- break;
-
- case 162:
-#line 1493 "parser.y"
- {
- yyerrmsg = "backend name (identifier) expected";
-;}
- break;
-
- case 163:
-#line 1498 "parser.y"
- {
- yyerrmsg = "IP address such as 1.2.3.4 or 'any' expected";
-;}
- break;
-
- case 164:
-#line 1503 "parser.y"
- {
- yyerrmsg = "Service type expected ('any', 'stickyhttp', ...)";
-;}
- break;
-
- case 165:
-#line 1508 "parser.y"
- {
- yyerrmsg = "Header inspection mode mode expected ('shallow' or 'deep')";
-;}
- break;
-
- case 166:
-#line 1513 "parser.y"
- {
- yyerrmsg = "IP filter(s) expected";
-;}
- break;
-
- case 167:
-#line 1518 "parser.y"
- {
- yyerrmsg = "username expected";
-;}
- break;
-
- case 168:
-#line 1523 "parser.y"
- {
- yyerrmsg = "state definition expected";
-;}
- break;
-
- case 171:
-#line 1538 "parser.y"
- {
- yyerrmsg = "'{' expected";
-;}
- break;
-
- case 172:
-#line 1542 "parser.y"
- {
- yyerrmsg = "'}' expected";
-;}
- break;
-
- case 173:
-#line 1546 "parser.y"
- {
- yyerrmsg = "option statement (logactivity, tcpbuffersize, ...) expected";
-;}
- break;
-
-
-/* Line 1267 of yacc.c. */
-#line 3320 "parser.c"
- default: break;
- }
- YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
-
- *++yyvsp = yyval;
-
-
- /* Now `shift' the result of the reduction. Determine what state
- that goes to, based on the state we popped back to and the rule
- number reduced by. */
-
- yyn = yyr1[yyn];
-
- yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
- if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
- yystate = yytable[yystate];
- else
- yystate = yydefgoto[yyn - YYNTOKENS];
-
- goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
- /* If not already recovering from an error, report this error. */
- if (!yyerrstatus)
- {
- ++yynerrs;
-#if ! YYERROR_VERBOSE
- yyerror (YY_("syntax error"));
-#else
- {
- YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
- if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
- {
- YYSIZE_T yyalloc = 2 * yysize;
- if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
- yyalloc = YYSTACK_ALLOC_MAXIMUM;
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- yymsg = (char *) YYSTACK_ALLOC (yyalloc);
- if (yymsg)
- yymsg_alloc = yyalloc;
- else
- {
- yymsg = yymsgbuf;
- yymsg_alloc = sizeof yymsgbuf;
- }
- }
-
- if (0 < yysize && yysize <= yymsg_alloc)
- {
- (void) yysyntax_error (yymsg, yystate, yychar);
- yyerror (yymsg);
- }
- else
- {
- yyerror (YY_("syntax error"));
- if (yysize != 0)
- goto yyexhaustedlab;
- }
- }
-#endif
- }
-
-
-
- if (yyerrstatus == 3)
- {
- /* If just tried and failed to reuse look-ahead token after an
- error, discard it. */
-
- if (yychar <= YYEOF)
- {
- /* Return failure if at end of input. */
- if (yychar == YYEOF)
- YYABORT;
- }
- else
- {
- yydestruct ("Error: discarding",
- yytoken, &yylval);
- yychar = YYEMPTY;
- }
- }
-
- /* Else will try to reuse look-ahead token after shifting the error
- token. */
- goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR. |
-`---------------------------------------------------*/
-yyerrorlab:
-
- /* Pacify compilers like GCC when the user code never invokes
- YYERROR and the label yyerrorlab therefore never appears in user
- code. */
- if (/*CONSTCOND*/ 0)
- goto yyerrorlab;
-
- /* Do not reclaim the symbols of the rule which action triggered
- this YYERROR. */
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
- yystate = *yyssp;
- goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR. |
-`-------------------------------------------------------------*/
-yyerrlab1:
- yyerrstatus = 3; /* Each real token shifted decrements this. */
-
- for (;;)
- {
- yyn = yypact[yystate];
- if (yyn != YYPACT_NINF)
- {
- yyn += YYTERROR;
- if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
- {
- yyn = yytable[yyn];
- if (0 < yyn)
- break;
- }
- }
-
- /* Pop the current state because it cannot handle the error token. */
- if (yyssp == yyss)
- YYABORT;
-
-
- yydestruct ("Error: popping",
- yystos[yystate], yyvsp);
- YYPOPSTACK (1);
- yystate = *yyssp;
- YY_STACK_PRINT (yyss, yyssp);
- }
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- *++yyvsp = yylval;
-
-
- /* Shift the error token. */
- YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
- yystate = yyn;
- goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here. |
-`-------------------------------------*/
-yyacceptlab:
- yyresult = 0;
- goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here. |
-`-----------------------------------*/
-yyabortlab:
- yyresult = 1;
- goto yyreturn;
-
-#ifndef yyoverflow
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here. |
-`-------------------------------------------------*/
-yyexhaustedlab:
- yyerror (YY_("memory exhausted"));
- yyresult = 2;
- /* Fall through. */
-#endif
-
-yyreturn:
- if (yychar != YYEOF && yychar != YYEMPTY)
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval);
- /* Do not reclaim the symbols of the rule which action triggered
- this YYABORT or YYACCEPT. */
- YYPOPSTACK (yylen);
- YY_STACK_PRINT (yyss, yyssp);
- while (yyssp != yyss)
- {
- yydestruct ("Cleanup: popping",
- yystos[*yyssp], yyvsp);
- YYPOPSTACK (1);
- }
-#ifndef yyoverflow
- if (yyss != yyssa)
- YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
-#endif
- /* Make sure YYID is used. */
- return YYID (yyresult);
-}
-
-
-
diff --git a/src/lib/parser.h b/src/lib/parser.h
@@ -1,189 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3. */
-
-/* Skeleton interface for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
-
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- IDENTIFIER = 258,
- NUMBER = 259,
- STRING = 260,
- SERVICE = 261,
- PORT = 262,
- VERBOSITY = 263,
- MAXCONNECTIONS = 264,
- TYPE = 265,
- ANY = 266,
- HTTP = 267,
- BACKEND = 268,
- SERVER = 269,
- BINDTO = 270,
- CONNECTIONTIMEOUT = 271,
- ON = 272,
- OFF = 273,
- DISPATCHMODE = 274,
- ROUNDROBIN = 275,
- RANDOM = 276,
- BYDURATION = 277,
- BYSIZE = 278,
- BYCONNECTIONS = 279,
- BYORDER = 280,
- BYCLIENTIP = 281,
- OVER = 282,
- DECAY = 283,
- REVIVINGINTERVAL = 284,
- CHECKINTERVAL = 285,
- RETRIES = 286,
- SHMKEY = 287,
- WEIGHT = 288,
- ONSTART = 289,
- ONFAIL = 290,
- BACKLOG = 291,
- THROUGHPUTLOG = 292,
- TRAFFICLOG = 293,
- HTTPTIMINGLOG = 294,
- STICKYCOOKIE = 295,
- ADDCLIENTHEADER = 296,
- SETCLIENTHEADER = 297,
- APPENDCLIENTHEADER = 298,
- ADDSERVERHEADER = 299,
- SETSERVERHEADER = 300,
- APPENDSERVERHEADER = 301,
- ALLOWFROM = 302,
- DENYFROM = 303,
- ALLOWFILE = 304,
- DENYFILE = 305,
- EXTERNALHANDLER = 306,
- USERACCOUNT = 307,
- ONEND = 308,
- HEADERINSPECTION = 309,
- DEEP = 310,
- SHALLOW = 311,
- STATE = 312,
- AVAILABLE = 313,
- UNAVAILABLE = 314,
- DOWN = 315,
- OPTIONS = 316,
- LOGACTIVITY = 317,
- TCPBUFFERSIZE = 318,
- DNSCACHETTL = 319,
- LOGFACILITY = 320,
- SHMPERMISSIONS = 321,
- SLOPPYPORTBIND = 322,
- LEAVEPROCESSTITLE = 323
- };
-#endif
-/* Tokens. */
-#define IDENTIFIER 258
-#define NUMBER 259
-#define STRING 260
-#define SERVICE 261
-#define PORT 262
-#define VERBOSITY 263
-#define MAXCONNECTIONS 264
-#define TYPE 265
-#define ANY 266
-#define HTTP 267
-#define BACKEND 268
-#define SERVER 269
-#define BINDTO 270
-#define CONNECTIONTIMEOUT 271
-#define ON 272
-#define OFF 273
-#define DISPATCHMODE 274
-#define ROUNDROBIN 275
-#define RANDOM 276
-#define BYDURATION 277
-#define BYSIZE 278
-#define BYCONNECTIONS 279
-#define BYORDER 280
-#define BYCLIENTIP 281
-#define OVER 282
-#define DECAY 283
-#define REVIVINGINTERVAL 284
-#define CHECKINTERVAL 285
-#define RETRIES 286
-#define SHMKEY 287
-#define WEIGHT 288
-#define ONSTART 289
-#define ONFAIL 290
-#define BACKLOG 291
-#define THROUGHPUTLOG 292
-#define TRAFFICLOG 293
-#define HTTPTIMINGLOG 294
-#define STICKYCOOKIE 295
-#define ADDCLIENTHEADER 296
-#define SETCLIENTHEADER 297
-#define APPENDCLIENTHEADER 298
-#define ADDSERVERHEADER 299
-#define SETSERVERHEADER 300
-#define APPENDSERVERHEADER 301
-#define ALLOWFROM 302
-#define DENYFROM 303
-#define ALLOWFILE 304
-#define DENYFILE 305
-#define EXTERNALHANDLER 306
-#define USERACCOUNT 307
-#define ONEND 308
-#define HEADERINSPECTION 309
-#define DEEP 310
-#define SHALLOW 311
-#define STATE 312
-#define AVAILABLE 313
-#define UNAVAILABLE 314
-#define DOWN 315
-#define OPTIONS 316
-#define LOGACTIVITY 317
-#define TCPBUFFERSIZE 318
-#define DNSCACHETTL 319
-#define LOGFACILITY 320
-#define SHMPERMISSIONS 321
-#define SLOPPYPORTBIND 322
-#define LEAVEPROCESSTITLE 323
-
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef int YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-extern YYSTYPE yylval;
-
diff --git a/src/lib/parser.y b/src/lib/parser.y
@@ -1,1548 +0,0 @@
-
-/* Parser of crossroads configuration files */
-
-%{
-/* Prologue */
-#include "../crossroads.h"
-
-#define YYSTYPE Confsets
-
-/* Static parser vars */
-static int i; /* Loop counter */
-static Backend cur_backend; /* Storage for a handled backend */
-static Service cur_service; /* Storage for a handled service */
-
-/* Parser debugging related */
-static void pmsg (char const *fmt, ...) {
- va_list args;
-
- if (parser_debug) {
- printf ("PARSER: ");
- va_start (args, fmt);
- vprintf (fmt, args);
- }
-}
-
-/* Conversion of yytext for symbol table */
-#define SYMBOL (symtab_lookup((yytext)))
-
-/* Error handler for yyparse() */
-static int yyerror (char *msg) {
- char *sym;
-
- if (! yytext || ! *yytext)
- sym = "<end of file>";
- else if (isspace (*yytext))
- sym = "<white space>";
- else if (isprint (*yytext))
- sym = yytext;
- else
- sym = "<nonprintable>";
-
- error ("Parse error at %s, line %d, '%s': %s",
- parser_filename(), yylineno + 1,
- sym, yyerrmsg);
-}
-
-/* Store an encountered string */
-static char *laststr;
-static void setlaststr (char const *what) {
- free (laststr);
- laststr = xstrdup (what);
-}
-
-/* Store an encountered number */
-static int lastnr;
-static void setlastnr (char const *what) {
- if (what && *what && *what == '0')
- lastnr = strtol (what, 0, 8);
- else
- lastnr = atoi (what);
-}
-
-/* Store an encountered 'over' number */
-static int lastovernr;
-static void setlastovernr (char const *what) {
- if (what && *what && *what == '0')
- lastovernr = strtol (what, 0, 8);
- else
- lastovernr = atoi(what);
-}
-
-/* Store an encountered 'externalhandler' */
-static char *lastext;
-static void setlastext (char const *what) {
- free (lastext);
- lastext = xstrdup (what);
-}
-
-/* Get the server part from HOSTNAME:PORT in allocated memory */
-static char *serverpart (char const *what) {
- char *ret = xstrdup (what);
- char *cp;
-
- if ( (cp = strchr (ret, ':')) )
- *cp = 0;
- return (ret);
-}
-
-/* Get the port part from HOSTNAME:PORT */
-static int portpart (char const *what) {
- char *cp;
-
- if ( (cp = strchr (what, ':')) )
- return (atoi (cp + 1));
- return (0);
-}
-
-/* Add a list of IP filters to the allowlist or the denylist */
-static void add_any (char *what, int chain) {
- char *item, *last = (char*) add_any;
- int result;
-
- for (item = strtok_r (what, " ", &last);
- item;
- item = strtok_r (0, " ", &last)) {
- if (chain)
- result = ipf_add_allow (&cur_service, item);
- else
- result = ipf_add_deny (&cur_service, item);
- if (result)
- error ("Bad IP filter specifier '%s' at line %d",
- item, yylineno + 1);
- }
-}
-static void add_allowfrom (char *what) {
- add_any (what, 1);
-}
-static void add_denyfrom (char *what) {
- add_any (what, 0);
-}
-
-/* Set uid/gid for external commands. */
-static void setuseraccount (char *username) {
- struct passwd *pw;
-
- if (! (pw = getpwnam (username)) )
- error ("Invalid username '%s' at line %d", username, yylineno + 1);
- cur_service.uid = pw->pw_uid;
- cur_service.gid = pw->pw_gid;
-}
-
-%}
-
-/* Tokens: the meta tokens */
-%token IDENTIFIER NUMBER STRING
-
- /* Tokens: the literal ones (these go automatically into the docs) */
-%token SERVICE PORT VERBOSITY MAXCONNECTIONS
- TYPE ANY HTTP
- BACKEND SERVER BINDTO CONNECTIONTIMEOUT
- ON OFF
- DISPATCHMODE ROUNDROBIN RANDOM BYDURATION BYSIZE BYCONNECTIONS
- BYORDER BYCLIENTIP
- OVER DECAY
- REVIVINGINTERVAL CHECKINTERVAL RETRIES SHMKEY WEIGHT
- ONSTART ONFAIL BACKLOG
- THROUGHPUTLOG TRAFFICLOG HTTPTIMINGLOG
- STICKYCOOKIE ADDCLIENTHEADER SETCLIENTHEADER APPENDCLIENTHEADER
- ADDSERVERHEADER SETSERVERHEADER APPENDSERVERHEADER
- ALLOWFROM DENYFROM ALLOWFILE DENYFILE
- EXTERNALHANDLER USERACCOUNT ONEND
- HEADERINSPECTION DEEP SHALLOW
- STATE AVAILABLE UNAVAILABLE DOWN
- OPTIONS LOGACTIVITY TCPBUFFERSIZE DNSCACHETTL LOGFACILITY
- SHMPERMISSIONS SLOPPYPORTBIND LEAVEPROCESSTITLE
-
-%%
-/* Config file grammar rules */
-
-input:
- input
- element
-|
- element
-;
-
-element:
- service_element
-|
- option_element
-;
-
-option_element:
- OPTIONS
- openbrace
- option_statements
- closebrace
-;
-
-option_statements:
- option_statements
- option_statement
-|
- option_statement
-;
-
-option_statement:
- option_statement_expected
- optstat
-;
-
-optstat:
- logactivity_statement
-|
- tcpbuffersize_statement
-|
- dnscachettl_statement
-|
- logfacility_statement
-|
- shmpermissions_statement
-|
- sloppyportbind_statement
-|
- leaveprocesstitle_statement
-;
-
-logactivity_statement:
- LOGACTIVITY
- onoff_expected
- onoff
- semicol {
- opt.log_activity = lastnr;
- }
-;
-
-tcpbuffersize_statement:
- TCPBUFFERSIZE
- number
- semicol {
- opt.tcp_bufsz = lastnr;
- }
-;
-
-dnscachettl_statement:
- DNSCACHETTL
- number
- semicol {
- opt.dns_cachettl = lastnr;
- }
-;
-
-logfacility_statement:
- LOGFACILITY
- number
- semicol {
- opt.log_facility = lastnr;
- }
-;
-
-shmpermissions_statement:
- SHMPERMISSIONS
- number
- semicol {
- opt.shmperm = lastnr;
- }
-;
-
-sloppyportbind_statement:
- SLOPPYPORTBIND
- onoff_expected
- onoff
- semicol {
- opt.sloppyportbind = lastnr;
- }
-;
-
-leaveprocesstitle_statement:
- LEAVEPROCESSTITLE
- onoff_expected
- onoff
- semicol {
- opt.leave_proctitle = lastnr;
- }
-;
-
-service_element:
- service
- servicename
- openbrace
- servicestatements
- closebrace {
- /* Check integrity, supply defaults */
- check_service (cur_service);
-
- if (!cur_service.shmkey)
- cur_service.shmkey = (unsigned) hashpjw (cur_service.name);
- msg ("Service %s: shared memory key set to 0x%8.8x",
- cur_service.name, cur_service.shmkey);
-
- if (!cur_service.check_cmd)
- cur_service.check_cmd = xstrdup ("");
-
- /* Add to the list, reset cur_service for next run */
- service = xrealloc (service, ++nservice * sizeof(Service));
- service[nservice - 1] = cur_service;
- memset (&cur_service, 0, sizeof(Service));
- }
-;
-
-service:
- service_expected
- SERVICE
-;
-
-servicename:
- servicename_expected
- IDENTIFIER {
- pmsg ("service [%s]\n", SYMBOL);
- for (i = 0; i < nservice; i++)
- if (!strcmp (service[i].name, SYMBOL))
- error ("Duplicate definition of service '%s'", SYMBOL);
- cur_service.name = xstrdup(SYMBOL);
- }
-;
-
-servicestatements:
- servicestatements
- servicestatement
-|
- servicestatement
-;
-
-servicestatement:
- servicebody_expected
- servicebody
-;
-
-servicebody:
- portstatement {
- pmsg ("sevice port [%d]\n", $1.set[0].v.ival);
- cur_service.port = $1.set[0].v.ival;
- free ($1.set);
- }
-|
- bindstatement {
- pmsg ("service binding [%s]\n", $1.set[0].v.sval);
- cur_service.bind = $1.set[0].v.sval;
- free ($1.set);
- }
-|
- verbositystatement {
- pmsg ("service verbosity [%d]\n", $1.set[0].v.ival);
- cur_service.verbosity = $1.set[0].v.ival;
- free ($1.set);
- }
-|
- dispatchmodestatement {
- pmsg ("service dispatch mode [%d]\n", $1.set[0].v.ival);
- pmsg ("service dispatch over [%d]\n", lastovernr);
- pmsg ("service dispatch exthandler [%s]\n", lastext);
- cur_service.dispatchtype = $1.set[0].v.ival;
- cur_service.dispatchover = lastovernr;
- cur_service.dispatchext = xstrdup(lastext);
- free ($1.set);
- }
-|
- revivingintervalstatement {
- pmsg ("service revival interval [%d]\n", $1.set[0].v.ival);
- pmsg ("service revival cmd [%s]\n", $1.set[1].v.sval);
- cur_service.rev_interval = $1.set[0].v.ival;
- cur_service.check_cmd = $1.set[1].v.sval;
- free ($1.set);
- }
-|
- checkintervalstatement {
- pmsg ("service check interval [%d]\n", $1.set[0].v.ival);
- pmsg ("service check cmd [%s]\n", $1.set[1].v.sval);
- cur_service.check_interval = $1.set[0].v.ival;
- cur_service.check_cmd = $1.set[1].v.sval;
- }
-|
- backlogstatement {
- pmsg ("service backlog [%d]\n", $1.set[0].v.ival);
- cur_service.backlog = $1.set[0].v.ival;
- free ($1.set);
- }
-|
- shmkeystatement {
- pmsg ("service shmkey [%d]\n", $1.set[0].v.ival);
- cur_service.shmkey = $1.set[0].v.ival;
- free ($1.set);
- }
-|
- connectiontimeoutstatement {
- pmsg ("connection timout [%d]\n", $1.set[0].v.ival);
- cur_service.connectiontimeout = $1.set[0].v.ival;
- free ($1.set);
- }
-|
- maxconnectionsstatement {
- pmsg ("max clients in service [%d]\n", $1.set[0].v.ival);
- cur_service.maxconnections = $1.set[0].v.ival;
- free ($1.set);
- }
-|
- typestatement {
- pmsg ("service type [%d]\n", $1.set[0].v.ival);
- cur_service.type = $1.set[0].v.ival;
- free ($1.set);
- }
-|
- inspectionstatement {
- pmsg ("service header inspection [%d]\n", $1.set[0].v.ival);
- cur_service.inspection = $1.set[0].v.ival;
- free ($1.set);
- }
-|
- allowfromstatement {
- pmsg ("allow from [%s]\n", $1.set[0].v.sval);
- add_allowfrom ($1.set[0].v.sval);
- free ($1.set);
- }
-|
- allowfilestatement {
- pmsg ("allow file [%s]\n", $1.set[0].v.sval);
- cur_service.allowfile = $1.set[0].v.sval;
- free ($1.set);
- }
-|
- denyfromstatement {
- pmsg ("deny from [%s]\n", $1.set[0].v.sval);
- add_denyfrom ($1.set[0].v.sval);
- free ($1.set);
- }
-|
- denyfilestatement {
- pmsg ("deny file [%s]\n", $1.set[0].v.sval);
- cur_service.denyfile = $1.set[0].v.sval;
- free ($1.set);
- }
-|
- useraccountstatement {
- pmsg ("user account [%s]\n", $1.set[0].v.sval);
- setuseraccount ($1.set[0].v.sval);
- free ($1.set[0].v.sval);
- free ($1.set);
- }
-|
- backendblock {
- pmsg ("converting backend statements, count is [%d]\n", $1.n);
- for (i = 0; i < $1.n; i++)
- switch ($1.set[i].cf) {
- case cf_portspec:
- pmsg ("backend port [%d]\n", $1.set[i].v.ival);
- cur_backend.initial_port = $1.set[i].v.ival;
- break;
- case cf_serverspec:
- pmsg ("backend server [%s]\n", $1.set[i].v.sval);
- cur_backend.initial_server = serverpart ($1.set[i].v.sval);
- cur_backend.initial_port = portpart ($1.set[i].v.sval);
- free ($1.set[i].v.sval);
- break;
- case cf_verbosityspec:
- pmsg ("backend verbosity [%d]\n", $1.set[i].v.ival);
- cur_backend.verbosity = $1.set[i].v.ival;
- break;
- case cf_onstartspec:
- pmsg ("backend onstart [%s]\n", $1.set[i].v.sval);
- cur_backend.onstart = $1.set[i].v.sval;
- break;
- case cf_onfailspec:
- pmsg ("backend onfail [%s]\n", $1.set[i].v.sval);
- cur_backend.onfail = $1.set[i].v.sval;
- break;
- case cf_onendspec:
- pmsg ("backend onend [%s]\n", $1.set[i].v.sval);
- cur_backend.onend = $1.set[i].v.sval;
- break;
- case cf_dumpspec:
- pmsg ("backend trafficlog [%s]\n", $1.set[i].v.sval);
- cur_backend.dumpfile = $1.set[i].v.sval;
- break;
- case cf_thruspec:
- pmsg ("backend throughputlog [%s]\n", $1.set[i].v.sval);
- cur_backend.thruputfile = $1.set[i].v.sval;
- break;
- case cf_httptimingspec:
- if (cur_service.type != type_http)
- error ("'httptiminglog' only allowed in 'type http' "
- "service definitions");
- pmsg ("backend http timing log [%s]\n", $1.set[i].v.sval);
- cur_backend.timinglog = $1.set[i].v.sval;
- break;
- case cf_weightspec:
- pmsg ("backend weight [%d]\n", $1.set[i].v.ival);
- cur_backend.weight = $1.set[i].v.ival;
- break;
- case cf_decayspec:
- pmsg ("backend decay [%d]\n", $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:
- pmsg ("backend max clients [%d]\n", $1.set[i].v.ival);
- cur_backend.maxconnections = $1.set[i].v.ival;
- break;
- case cf_stickycookiespec:
- pmsg ("backend sticky cookie [%s]\n",
- $1.set[i].v.sval);
- cur_backend.stickycookie = $1.set[i].v.sval;
- break;
- case cf_addclientheaderspec:
- pmsg ("client header to add [%s]\n",
- $1.set[i].v.sval);
- cur_backend.addclientheader =
- xrealloc (cur_backend.addclientheader,
- (cur_backend.naddclientheader + 1) *
- sizeof(char*));
- cur_backend.addclientheader
- [cur_backend.naddclientheader++] =
- $1.set[i].v.sval;
- break;
- case cf_setclientheaderspec:
- pmsg ("client header to set [%s]\n",
- $1.set[i].v.sval);
- cur_backend.setclientheader =
- xrealloc (cur_backend.setclientheader,
- (cur_backend.nsetclientheader + 1) *
- sizeof(char*));
- cur_backend.setclientheader
- [cur_backend.nsetclientheader++] =
- $1.set[i].v.sval;
- break;
- case cf_appendclientheaderspec:
- pmsg ("client header to append [%s]\n",
- $1.set[i].v.sval);
- cur_backend.appendclientheader =
- xrealloc (cur_backend.appendclientheader,
- (cur_backend.nappendclientheader + 1) *
- sizeof(char*));
- cur_backend.appendclientheader
- [cur_backend.nappendclientheader++] =
- $1.set[i].v.sval;
- break;
- case cf_addserverheaderspec:
- pmsg ("server header to add [%s]\n",
- $1.set[i].v.sval);
- cur_backend.addserverheader =
- xrealloc (cur_backend.addserverheader,
- (cur_backend.naddserverheader + 1) *
- sizeof(char*));
- cur_backend.addserverheader
- [cur_backend.naddserverheader++] =
- $1.set[i].v.sval;
- break;
- case cf_setserverheaderspec:
- pmsg ("server header to set [%s]\n",
- $1.set[i].v.sval);
- cur_backend.setserverheader =
- xrealloc (cur_backend.setserverheader,
- (cur_backend.nsetserverheader + 1) *
- sizeof(char*));
- cur_backend.setserverheader
- [cur_backend.nsetserverheader++] =
- $1.set[i].v.sval;
- break;
- case cf_appendserverheaderspec:
- pmsg ("server header to append:",
- $1.set[i].v.sval);
- cur_backend.appendserverheader =
- xrealloc (cur_backend.appendserverheader,
- (cur_backend.nappendserverheader + 1) *
- sizeof(char*));
- cur_backend.appendserverheader
- [cur_backend.nappendserverheader++] =
- $1.set[i].v.sval;
- break;
- case cf_retriesspec:
- pmsg ("backend retries [%d]\n", $1.set[i].v.ival);
- cur_backend.retries = $1.set[i].v.ival;
- break;
- case cf_statespec:
- pmsg ("backend initial state [%d]\n", $1.set[i].v.ival);
- cur_backend.initial_avail = $1.set[i].v.ival;
- 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_backend.initial_port)
- error ("Service %s: back end %s lacks port",
- cur_service.name, cur_backend.name);
- if (cur_service.dispatchext && cur_backend.maxconnections)
- error ("Service %s: back end %s defines maxconnections, "
- "but an external dispatcher is in effect",
- cur_service.name, cur_backend.name);
- if (cur_backend.weight < 1)
- cur_backend.weight = 1;
- if (cur_backend.retries < 1)
- cur_backend.retries = 1;
-
- /* Add to the list. */
- cur_service.backend = xrealloc (cur_service.backend,
- ++cur_service.nbackend *
- sizeof(Backend));
- cur_service.backend[cur_service.nbackend - 1] =
- cur_backend;
- pmsg ("this was backend definition [%d]\n", cur_service.nbackend);
- memset (&cur_backend, 0, sizeof(cur_backend));
- }
-;
-
-portstatement:
- PORT
- number
- semicol {
- pmsg ("port statement [%d]\n", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_portspec;
- $$.set[0].v.ival = lastnr;
- }
-;
-
-bindstatement:
- BINDTO
- ipaddress
- semicol {
- pmsg ("bindto statement [%d]\n", 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;
- }
-;
-
-number:
- number_expected
- NUMBER {
- setlastnr (SYMBOL);
- }
-;
-
-semicol:
- semicol_expected
- ';'
-;
-
-verbositystatement:
- VERBOSITY
- onoff_expected
- onoff
- semicol {
- pmsg ("verbosity statement [%d]\n", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_verbosityspec;
- $$.set[0].v.ival = lastnr;
- }
-;
-
-onoff:
- ON {
- lastnr = 1;
- }
-|
- OFF {
- lastnr = 0;
- }
-;
-
-dispatchmodestatement:
- DISPATCHMODE
- dispatchmethod
- dispatchtail
- semicol {
- $$ = $2;
- }
-;
-
-dispatchtail:
- dispatchover
- |
- dispatchext
- |
- /* empty */ {
- $$.n = 0;
- }
-;
-
-dispatchover:
- OVER
- overnumber {
- pmsg ("dispatch mode statement [%d]\n", 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);
- }
-;
-
-overnumber:
- number_expected
- NUMBER {
- setlastovernr (SYMBOL);
- }
-;
-
-dispatchext:
- commandline {
- pmsg ("external handler [%s]\n", laststr);
- if (lastnr != ds_externalhandler)
- error ("Service %s: this dispatch mode doesn't support "
- "an external handler", cur_service.name);
- setlastext (laststr);
- }
-;
-
-dispatchmethod:
- dispatchmethod_expected
- dispatchmethodspec {
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].v.ival = lastnr;
- }
-;
-
-dispatchmethodspec:
- ROUNDROBIN {
- lastnr = ds_roundrobin;
- }
-|
- RANDOM {
- lastnr = ds_random;
- }
-|
- BYDURATION {
- lastnr = ds_byduration;
- }
-|
- BYSIZE {
- lastnr = ds_bysize;
- }
-|
- BYORDER {
- lastnr = ds_byorder;
- }
-|
- BYCONNECTIONS {
- lastnr = ds_byconnections;
- }
-|
- EXTERNALHANDLER {
- lastnr = ds_externalhandler;
- }
-|
- BYCLIENTIP {
- lastnr = ds_byclientip;
- }
-;
-
-useraccountstatement:
- USERACCOUNT
- useraccount
- semicol {
- pmsg ("user account statement [%d]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_useraccountspec;
- $$.set[0].v.sval = xstrdup (laststr);
- }
-;
-
-useraccount:
- useraccount_expected
- STRING {
- setlaststr (laststring);
- free (laststring);
- laststring = 0;
- }
-;
-
-revivingintervalstatement:
- REVIVINGINTERVAL
- number
- opt_externalhandler
- semicol {
- pmsg ("reviving interval statement [%d]\n", lastnr);
- $$.n = 2;
- $$.set = xmalloc (2 * sizeof(Confset));
- $$.set[0].cf = cf_revivespec;
- $$.set[0].v.ival = lastnr;
- if ($3.n) {
- pmsg ("reviving externalhandler [%s]\n", $3.set[0].v.sval);
- $$.set[1].v.sval = $3.set[0].v.sval;
- } else
- $$.set[1].v.sval = 0;
- }
-;
-
-checkintervalstatement:
- CHECKINTERVAL
- number
- opt_externalhandler
- semicol {
- pmsg ("check interval [%d]\n", lastnr);
- $$.n = 2;
- $$.set = xmalloc (2 * sizeof(Confset));
- $$.set[0].cf = cf_checkspec;
- $$.set[0].v.ival = lastnr;
- if ($3.n) {
- pmsg ("check externalhandler [%s]\n", $3.set[0].v.sval);
- $$.set[1].v.sval = $3.set[0].v.sval;
- } else
- $$.set[1].v.sval = 0;
- }
-;
-
-opt_externalhandler:
- externalhandler
- |
- /* empty */ {
- $$.n = 0;
- }
-;
-
-externalhandler:
- EXTERNALHANDLER
- commandline {
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].v.sval = xstrdup (laststr);
- }
-;
-
-backlogstatement:
- BACKLOG
- number
- semicol {
- pmsg ("backlog statement [%d]\n", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_backlogspec;
- $$.set[0].v.ival = lastnr;
- }
-;
-
-shmkeystatement:
- SHMKEY
- number
- semicol {
- pmsg ("shmkey statement [%d]\n", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_shmkeyspec;
- $$.set[0].v.ival = lastnr;
- }
-;
-
-connectiontimeoutstatement:
- CONNECTIONTIMEOUT
- number
- semicol {
- pmsg ("connection timeout statement [%d]\n", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_connectiontimeoutspec;
- $$.set[0].v.ival = lastnr;
- }
-;
-
-maxconnectionsstatement:
- MAXCONNECTIONS
- number
- semicol {
- pmsg ("max clients statement (service) [%d]\n", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_maxconnectionsspec;
- $$.set[0].v.ival = lastnr;
- }
-;
-
-typestatement:
- TYPE
- typespec
- semicol {
- pmsg ("service type [%d]\n", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_typespec;
- $$.set[0].v.ival = lastnr;
- }
-;
-
-typespec:
- type_expected
- typespecifier
- ;
-
-typespecifier:
- ANY {
- lastnr = type_any;
- }
-|
- HTTP {
- lastnr = type_http;
- }
-;
-
-inspectionstatement:
- HEADERINSPECTION
- shallowdeepspec
- semicol {
- pmsg ("service header inspection [%d]\n", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_inspectionspec;
- $$.set[0].v.ival = lastnr;
- }
-;
-
-shallowdeepspec:
- shallowdeep_expected
- shallowdeepspecifier
- ;
-
-shallowdeepspecifier:
- DEEP {
- lastnr = ins_deep;
- }
-|
- SHALLOW {
- lastnr = ins_shallow;
- }
-;
-
-allowfromstatement:
- ALLOWFROM
- ipfilters
- semicol {
- pmsg ("allow from [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_allowfromspec;
- $$.set[0].v.sval = xstrdup(laststr);
- }
-;
-
-denyfromstatement:
- DENYFROM
- ipfilters
- semicol {
- pmsg ("deny from [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_denyfromspec;
- $$.set[0].v.sval = xstrdup(laststr);
- }
-;
-
-allowfilestatement:
- ALLOWFILE
- filename
- semicol {
- pmsg ("allow file [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_allowfilespec;
- $$.set[0].v.sval = xstrdup(laststr);
- }
-;
-
-denyfilestatement:
- DENYFILE
- filename
- semicol {
- pmsg ("deny file [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_allowfilespec;
- $$.set[0].v.sval = xstrdup(laststr);
- }
-;
-
-ipfilters:
- ipfilters_expected
- STRING {
- setlaststr (laststring);
- free (laststring);
- laststring = 0;
- }
-;
-
-backendblock:
- BACKEND
- backendname
- openbrace
- backenddefinitions
- closebrace {
- $$ = $4;
- }
-;
-
-backendname:
- backendname_expected
- IDENTIFIER {
- pmsg ("backend name [%s]\n", SYMBOL);
- for (i = 0; i < cur_service.nbackend; i++)
- if (!strcmp (cur_service.backend[i].name, SYMBOL))
- error ("Service %s: back end '%s' multiply defined",
- cur_service.name, SYMBOL);
- cur_backend.name = xstrdup (SYMBOL);
- }
-;
-
-backenddefinitions:
- backenddefinitions
- backenddefinition {
- $1.n++;
- $1.set = xrealloc ($1.set, $1.n * sizeof(Confset));
- $1.set[$1.n - 1] = $2.set[0];
- $$ = $1;
- }
-|
- backenddefinition {
- $$ = $1;
- }
-;
-
-backenddefinition:
- backendstatement_expected
- backendstatement {
- $$ = $2;
- }
-;
-
-backendstatement:
- serverstatement {
- pmsg ("backend server [%s]\n", $1.set[0].v.sval);
- $$ = $1;
- }
-|
- portstatement {
- pmsg ("backend port [%d]\n", $1.set[0].v.ival);
- $$ = $1;
- }
-|
- verbositystatement {
- pmsg ("backend verbosity [%d]\n", $1.set[0].v.ival);
- $$ = $1;
- }
-|
- onstartstatement {
- pmsg ("backend onstart [%s]\n", $1.set[0].v.sval);
- $$ = $1;
- }
-|
- onendstatement {
- pmsg ("backend onend [%s]\n", $1.set[0].v.sval);
- $$ = $1;
- }
-|
- onfailstatement {
- pmsg ("backend onfail [%s]\n", $1.set[0].v.sval);
- $$ = $1;
- }
-|
- dumptrafficstatement {
- pmsg ("backend trafficlog [%s]\n", $1.set[0].v.sval);
- $$ = $1;
- }
-|
- throughputstatement {
- pmsg ("backend trafficlog [%s]\n", $1.set[0].v.sval);
- $$ = $1;
- }
-|
- httptiminglogstatement {
- pmsg ("backend HTTP timing log [%s]\n", $1.set[0].v.sval);
- $$ = $1;
- }
-|
- weightstatement {
- pmsg ("backend weight [%d]\n", $1.set[0].v.ival);
- $$ = $1;
- }
-|
- decaystatement {
- pmsg ("backend decay [%d]\n", $1.set[0].v.ival);
- $$ = $1;
- }
-|
- maxconnectionsstatement {
- pmsg ("backend maxconnections [%d]\n", $1.set[0].v.ival);
- $$ = $1;
- }
-|
- stickycookiestatement {
- pmsg ("backend sticky cookie [%s]\n", $1.set[0].v.sval);
- $$ = $1;
- }
-|
- addclientheaderstatement {
- pmsg ("addclientheader [%s]\n", $1.set[0].v.sval);
- $$ = $1;
- }
-|
- setclientheaderstatement {
- pmsg ("setclientheader [%s]\n", $1.set[0].v.sval);
- $$ = $1;
- }
-|
- appendclientheaderstatement {
- pmsg ("appendclientheader [%s]\n", $1.set[0].v.sval);
- $$ = $1;
- }
-|
- addserverheaderstatement {
- pmsg ("addserverheader [%s]\n", $1.set[0].v.sval);
- $$ = $1;
- }
-|
- setserverheaderstatement {
- pmsg ("setserverheader [%s]\n", $1.set[0].v.sval);
- $$ = $1;
- }
-|
- appendserverheaderstatement {
- pmsg ("appendserverheader [%s]\n", $1.set[0].v.sval);
- $$ = $1;
- }
-|
- retriesstatement {
- pmsg ("backend retries [%d]\n", $1.set[0].v.ival);
- $$ = $1;
- }
-|
- initialstatestatement {
- pmsg ("backend state [%d]\n", $1.set[0].v.ival);
- $$ = $1;
- }
-;
-
-serverstatement:
- SERVER
- serveraddress_expected
- serveraddress
- semicol {
- pmsg ("server statement [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_serverspec;
- $$.set[0].v.sval = xstrdup (laststr);
- }
-;
-
-weightstatement:
- WEIGHT
- number
- semicol {
- pmsg ("weight statement [%d]\n", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_weightspec;
- $$.set[0].v.ival = lastnr;
- }
-;
-
-decaystatement:
- DECAY
- number
- semicol {
- pmsg ("decay statement [%d]\n", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_decayspec;
- $$.set[0].v.ival = lastnr;
- }
-;
-
-serveraddress:
- STRING {
- setlaststr (laststring);
- }
-;
-
-retriesstatement:
- RETRIES
- number
- semicol {
- pmsg ("retries [%d]\n", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_retriesspec;
- $$.set[0].v.ival = lastnr;
- }
-;
-
-initialstatestatement:
- STATE
- statedef
- semicol {
- pmsg ("state [%d]\n", lastnr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_statespec;
- $$.set[0].v.ival = lastnr;
- }
-;
-
-statedef:
- statedef_expected
- somestate
-;
-
-somestate:
- AVAILABLE {
- lastnr = st_available;
- }
-|
- UNAVAILABLE {
- lastnr = st_unavailable;
- }
-|
- DOWN {
- lastnr = st_down;
- }
-;
-
-onstartstatement:
- ONSTART
- commandline
- semicol {
- pmsg ("onstart statement [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_onstartspec;
- $$.set[0].v.sval = xstrdup (laststr);
- }
-;
-
-onfailstatement:
- ONFAIL
- commandline
- semicol {
- pmsg ("onfail statement [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_onfailspec;
- $$.set[0].v.sval = xstrdup (laststr);
- }
-;
-
-onendstatement:
- ONEND
- commandline
- semicol {
- pmsg ("onend statement [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_onendspec;
- $$.set[0].v.sval = xstrdup (laststr);
- }
-;
-
-dumptrafficstatement:
- TRAFFICLOG
- filename
- semicol {
- pmsg ("trafficlog statement [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_dumpspec;
- $$.set[0].v.sval = xstrdup (laststr);
- }
-;
-
-throughputstatement:
- THROUGHPUTLOG
- filename
- semicol {
- pmsg ("throughputlog statement [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_thruspec;
- $$.set[0].v.sval = xstrdup (laststr);
- }
-;
-
-httptiminglogstatement:
- HTTPTIMINGLOG
- filename
- semicol {
- pmsg ("httptiminglog statement [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_httptimingspec;
- $$.set[0].v.sval = xstrdup (laststr);
- }
-;
-
-commandline:
- commandline_expected
- STRING {
- setlaststr (laststring);
- free (laststring);
- laststring = 0;
- }
-;
-
-filename:
- filename_expected
- STRING {
- setlaststr (laststring);
- free (laststring);
- laststring = 0;
- }
-;
-
-stickycookiestatement:
- STICKYCOOKIE
- cookiespecifier
- semicol {
- pmsg ("insertcookie statement [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof (Confset));
- $$.set[0].cf = cf_stickycookiespec;
- $$.set[0].v.sval = xstrdup (laststr);
- }
-;
-
-cookiespecifier:
- cookie_expected
- STRING {
- setlaststr (laststring);
- free (laststring);
- laststring = 0;
- }
-;
-
-addclientheaderstatement:
- ADDCLIENTHEADER
- headerstring
- semicol {
- pmsg ("addclientheader statement [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_addclientheaderspec;
- $$.set[0].v.sval = xstrdup (laststr);
- }
-;
-
-setclientheaderstatement:
- SETCLIENTHEADER
- headerstring
- semicol {
- pmsg ("setclientheader statement [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_setclientheaderspec;
- $$.set[0].v.sval = xstrdup (laststr);
- }
-;
-
-appendclientheaderstatement:
- APPENDCLIENTHEADER
- headerstring
- semicol {
- pmsg ("appendclientheader statement [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_appendclientheaderspec;
- $$.set[0].v.sval = xstrdup (laststr);
- }
-;
-
-addserverheaderstatement:
- ADDSERVERHEADER
- headerstring
- semicol {
- pmsg ("addserverheader statement [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_addserverheaderspec;
- $$.set[0].v.sval = xstrdup (laststr);
- }
-;
-
-setserverheaderstatement:
- SETSERVERHEADER
- headerstring
- semicol {
- pmsg ("setserverheader statement [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_setserverheaderspec;
- $$.set[0].v.sval = xstrdup (laststr);
- }
-;
-
-appendserverheaderstatement:
- APPENDSERVERHEADER
- headerstring
- semicol {
- pmsg ("appendserverheader statement [%s]\n", laststr);
- $$.n = 1;
- $$.set = xmalloc (sizeof(Confset));
- $$.set[0].cf = cf_appendserverheaderspec;
- $$.set[0].v.sval = xstrdup (laststr);
- }
-;
-
-headerstring:
- headerstring_expected
- STRING {
- setlaststr (laststring);
- free (laststring);
- laststring = 0;
- }
-;
-
-headerstring_expected: {
- yyerrmsg = "HTTP header specifier expected";
-}
-;
-
-cookie_expected: {
- yyerrmsg = "cookie specifier expected";
-}
-;
-
-number_expected: {
- yyerrmsg = "number expected";
-}
-;
-
-serveraddress_expected: {
- yyerrmsg = "hostname or IP address expected";
-}
-;
-
-service_expected: {
- yyerrmsg = "'service' expected";
-}
-;
-
-backendstatement_expected: {
- yyerrmsg = "backend definition statement expected";
-}
-;
-
-servicebody_expected: {
- yyerrmsg = "service body statement expected";
-}
-;
-
-semicol_expected: {
- yyerrmsg = "semicolon (;) expected";
-}
-;
-
-onoff_expected: {
- yyerrmsg = "'on' or 'off' expetcted";
-}
-;
-
-dispatchmethod_expected: {
- yyerrmsg = "dispatch method expected";
-}
-;
-
-commandline_expected: {
- yyerrmsg = "command line expected";
-}
-;
-
-filename_expected: {
- yyerrmsg = "file name expected";
-}
-;
-
-servicename_expected: {
- yyerrmsg = "service name (identifier) expected";
-}
-;
-
-backendname_expected: {
- yyerrmsg = "backend name (identifier) expected";
-}
-;
-
-ipaddress_expected: {
- yyerrmsg = "IP address such as 1.2.3.4 or 'any' expected";
-}
-;
-
-type_expected: {
- yyerrmsg = "Service type expected ('any', 'stickyhttp', ...)";
-}
-;
-
-shallowdeep_expected: {
- yyerrmsg = "Header inspection mode mode expected ('shallow' or 'deep')";
-}
-;
-
-ipfilters_expected: {
- yyerrmsg = "IP filter(s) expected";
-}
-;
-
-useraccount_expected: {
- yyerrmsg = "username expected";
-}
-;
-
-statedef_expected: {
- yyerrmsg = "state definition expected";
-}
-;
-
-openbrace:
- openbrace_expected
- '{'
-;
-
-closebrace:
- closebrace_expected
- '}'
-;
-
-openbrace_expected: {
- yyerrmsg = "'{' expected";
-}
-
-closebrace_expected: {
- yyerrmsg = "'}' expected";
-}
-
-option_statement_expected: {
- yyerrmsg = "option statement (logactivity, tcpbuffersize, ...) expected";
-}
diff --git a/src/lib/parserclose.c b/src/lib/parserclose.c
@@ -1,29 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-int parser_close () {
- int remaining = 0;
-
- nparserstate--;
- if (nparserstate > 0) {
- /* We still have files in the parserstate stack. Set up yyin and
- * yylineno, and return 0 to signal that yyin has been set up
- * again. */
- yyin = parserstate[nparserstate - 1].file;
- yylineno = parserstate[nparserstate - 1].lineno;
- if (parserstate[nparserstate - 1].buf &&
- *parserstate[nparserstate - 1].buf)
- remaining = strlen(parserstate[nparserstate - 1].buf);
- msg ("Returning to configuration '%s' (line %d), %d bytes remain",
- parserstate[nparserstate - 1].name, yylineno, remaining);
- return (0);
- }
-
- /* The parser stack is empty. Return 1 to signal that we're really done. */
- return (1);
-}
diff --git a/src/lib/parserfilename.c b/src/lib/parserfilename.c
@@ -1,13 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-char const *parser_filename() {
- if (nparserstate > 0)
- return (parserstate[nparserstate - 1].name);
- return ("<unknown file>");
-}
diff --git a/src/lib/parserinput.c b/src/lib/parserinput.c
@@ -1,40 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-/* #define DEBUG */
-
-int parser_input (char *buf, int max) {
- int i, ndef = 0;
- char *cp, *newbuf;
-
- if (! nparserstate ||
- ! parserstate[nparserstate - 1].buf ||
- ! *parserstate[nparserstate - 1].buf)
- return (0);
-
- for (i = 0; i < nsymtab; i++) {
- if (!strncmp (parserstate[nparserstate - 1].buf, symtab[i].symbol,
- strlen(symtab[i].symbol))) {
- if (ndef++ >= DEF_MAX)
- error ("Too many #defines (%d) at %s (circular definition?",
- ndef, symtab[i].symbol);
- cp = parserstate[nparserstate - 1].buf + strlen(symtab[i].symbol);
- newbuf = xstrdup (symtab[i].redef);
- newbuf = xstrcat (newbuf, cp);
- free (parserstate[nparserstate - 1].buf);
- parserstate[nparserstate - 1].buf = newbuf;
- }
- }
-
- *buf = *parserstate[nparserstate - 1].buf;
- #ifdef DEBUG
- fprintf (stderr, "LEXER input char: %c (%d)\n", *buf, *buf);
- #endif
- parser_skipchar();
- return (1);
-}
diff --git a/src/lib/parseropen.c b/src/lib/parseropen.c
@@ -1,56 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void parser_open (char const *name) {
- FILE *f;
- struct stat statbuf;
- int nread;
- char *actual, *cp;
-
- /* "name" or <name> is converted to name */
- actual = xstrdup (name);
- cp = actual + strlen(actual) - 1;
- if ( (*actual == '"' && *cp == '"') ||
- (*actual == '<' && *cp == '>') ) {
- *cp = 0;
- strcpy (actual, actual + 1);
- }
-
- if (! (f = fopen (actual, "r")) )
- error ("Cannot read configuration %s: %s", actual, strerror(errno));
- if (fstat(fileno(f), &statbuf))
- error ("Cannot stat configuration %s: %s", actual, strerror(errno));
-
- /* Anticipate the terminating \n, process it and store. */
- yylineno++;
- if (nparserstate > 0) {
- parserstate[nparserstate - 1].lineno = yylineno;
- msg ("%d bytes remain in configuration %s beyond line %d",
- (int) strlen(parserstate[nparserstate - 1].buf),
- parserstate[nparserstate - 1].name, yylineno);
- }
-
- parserstate = xrealloc (parserstate,
- (nparserstate + 1) * sizeof(ParserState));
- parserstate[nparserstate].name = actual;
- parserstate[nparserstate].file = f;
- parserstate[nparserstate].lineno = 0;
- parserstate[nparserstate].buf = xmalloc (statbuf.st_size + 1);
- nread = fread (parserstate[nparserstate].buf, 1, statbuf.st_size, f);
- /* msg ("Got %d bytes from configuration %s", nread, actual); */
- if (nread < statbuf.st_size)
- error ("Read only %d bytes from configuration %s (out of %d)",
- nread, actual, (int) statbuf.st_size);
- parserstate[nparserstate].buf[statbuf.st_size] = 0;
- nparserstate++;
-
- yylineno = 0;
- yyin = f;
-}
-
-
diff --git a/src/lib/parserrun.c b/src/lib/parserrun.c
@@ -1,11 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void parser_run () {
- yyparse();
-}
diff --git a/src/lib/parserskipchar.c b/src/lib/parserskipchar.c
@@ -1,26 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-/* #define DEBUG */
-
-void parser_skipchar () {
- if (! parserstate[nparserstate - 1].buf ||
- ! *parserstate[nparserstate - 1].buf)
- return;
-
- #ifdef DEBUG
- fprintf (stderr, "LEXER skipping %c (%d)\n",
- *parserstate[nparserstate - 1].buf,
- *parserstate[nparserstate - 1].buf);
- #endif
-
- memmove (parserstate[nparserstate - 1].buf,
- parserstate[nparserstate - 1].buf + 1,
- strlen(parserstate[nparserstate - 1].buf));
-}
-
diff --git a/src/lib/parserskipline.c b/src/lib/parserskipline.c
@@ -1,21 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void parser_skipline () {
- char ch;
-
- while (parserstate[nparserstate - 1].buf &&
- *parserstate[nparserstate - 1].buf) {
- ch = *parserstate[nparserstate - 1].buf;
- parser_skipchar();
- if (ch == '\n') {
- yylineno++;
- break;
- }
- }
-}
diff --git a/src/lib/proxyerror.txt b/src/lib/proxyerror.txt
@@ -1,10 +0,0 @@
-<html>
- <head>
- <title>Internal Server Error</title>
- </head>
- <body>
- <h1>Internal Server Error</h1>
- Your request could not be fulfilled at this time.<br>
- Please try again later.
- </body>
-</html>
diff --git a/src/lib/runservice.c b/src/lib/runservice.c
@@ -1,130 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void runservice () {
- int pid;
- int first_serving = 1;
-
- /* Allocate the shared mem segment. */
- alloc_reporter(activeservice, 1);
-
- /* Load any allow- or deny filter files if appropriate. */
- if (ipf_loadfile (activeservice->allowfile, &(activeservice->allowchain),
- &(activeservice->nallowchain)))
- error ("Error in allow file");
- if (ipf_loadfile (activeservice->denyfile, &(activeservice->denychain),
- &(activeservice->ndenychain)))
- error ("Error in deny file");
-
- /* Go into the background. */
- if ( (pid = fork()) < 0 ) {
- /* Fork failed */
- error ("fork failure: %s", strerror(errno));
- } else if (pid) {
- /* Parent branch */
- msg ("detached as PID %d", pid);
- return;
- }
-
- /*** Child branch ***/
-
- /* We've forked for the first time */
- daemonized++;
- program_stage = stage_waiting;
-
- /* Promote verbosity. */
- flag_verbose = activeservice->verbosity;
-
- /* ALF support: open the status file fd */
- #ifdef ALF
- {
- char file[80];
- snprintf (file, 80, "/tmp/xr-%d.alf", getpid());
- close (alf_fd);
- alf_fd = open (file, O_WRONLY | O_CREAT);
- msg ("Service listener: alf logging to '%s', fd %d", file, alf_fd);
- }
- #endif
-
- /* Provide configuration/limits feedback */
- if (flag_verbose) {
- config_msg();
- limits_msg();
- }
-
- msg ("STARTING on port %d", activeservice->port);
-
- set_program_title ("crossroads - Service %s: listening",
- activeservice->name);
- close (0);
- close (1);
- close (2);
- if ( (open ("/dev/null", O_RDONLY) < 0) ||
- (open ("/dev/null", O_WRONLY) < 0) ||
- (open ("/dev/null", O_WRONLY) < 0) )
- error ("failed to reopen stdin/out/err on /dev/null");
- if (setsid() < 0)
- error ("failed to become session leader");
-
- /* In 'forever' mode, we create a server-side socket and ask tcpserve()
- * to service it. tcpserve() will return to us if there are no back
- * ends to service the request. In that case, we close the listening
- * socket (so that new clients get denied), take a nap, and redo.
- * Of course we only start listening if we have back ends at all...
- */
- while (1) {
- /* We need at least one working back end to operate. */
- if (!backend_count()) {
- msg ("taking a nap...");
- sleep (SLEEP_TIME);
- continue;
- }
-
- /* We have (at least) one back end. Let's run the service.
- * Create the socket, bind to port. */
- if ( (listen_sock = make_socket (activeservice->port,
- activeservice->bind)) < 0 ) {
- if (!opt.sloppyportbind)
- error ("failed to listen to port %d: %s",
- activeservice->port,
- strerror(errno));
- warning ("listening socket creation failed.. will retry");
-
- /* We wait here for some time, to let the system regain
- * equilibrium. Something's really afoot, so let's not retry
- * right away. */
- sleep (SLEEP_TIME);
-
- continue;
- }
-
- msg ("server-side network socket: %d", listen_sock);
-
- /* Zero out the stats for first usage. */
- if (first_serving) {
- first_serving = 0;
- memset (servicereport, 0, sizeof(Servicereport));
- /* Store our pid, so that 'crossroads stop' may kill us. */
- lock_reporter();
- servicereport->pid = getpid();
- unlock_reporter();
- }
-
- /* Start serving the port! */
- tcpserve (listen_sock);
-
- /* tcpserve() returned -- must be because this service is out
- * of back ends */
- if (shutdown (listen_sock, SHUT_RDWR))
- warning ("failed to shut down server-side socket %d: %s",
- listen_sock, strerror(errno));
- if (close (listen_sock))
- warning ("failed to close server-side socket %d: %s",
- listen_sock, strerror(errno));
- }
-}
diff --git a/src/lib/setproctitle.c b/src/lib/setproctitle.c
@@ -1,64 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-/* This defines setproctitle() incase your system lacks it. */
-
-#if HAVE_SETPROCTITLE == 0
-
-extern char **environ;
-
-void setproctitle (char const *fmt, ...) {
-#if SET_PROC_TITLE_BY_ARGV == 1
- int i;
- char buf[SPT_BUFSIZE], **envp;
- va_list ap;
- static int argv_lth = -1;
-
- if (argv_lth == -1) {
- /* First time around. Save the environment, initialize. */
- envp = environ;
- for (i = 0; envp[i]; i++)
- ;
- environ = xmalloc (sizeof(char*) * (i + 1));
- for (i = 0; envp[i]; i++)
- environ[i] = xstrdup(envp[i]);
- environ[i] = 0;
-
- if (i)
- argv_lth = envp[i - 1] + strlen(envp[i - 1]) - org_argv[0];
- else
- argv_lth = org_argv[org_argc - 1] +
- strlen(org_argv[org_argc - 1]) - org_argv[0];
- }
-
- /* Prepare the new commandline */
- va_start (ap, fmt);
- vsnprintf (buf, SPT_BUFSIZE, fmt, ap);
- va_end (ap);
-
- /* Determine max length */
- i = strlen (buf);
- if (i > argv_lth - 2) {
- i = argv_lth - 2;
- buf[i] = 0;
- }
-
- /* Set into original argv[0] */
-#if HAVE_PROGNAME_FULL == 1
- strcpy (__progname_full, buf);
-#else
- memset (org_argv[0], 0, argv_lth);
- strcpy (org_argv[0], buf);
-#endif /* HAVE_PROGNAME_FULL */
-
- org_argv[1] = 0;
-#endif /* SET_PROC_TITLE_BY_ARGV */
-}
-
-#endif /* HAVE_SETPROCTITLE */
-
diff --git a/src/lib/setprogramtitle.c b/src/lib/setprogramtitle.c
@@ -1,20 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void set_program_title (char const *fmt, ...) {
- char *buf;
- va_list args;
-
- if (opt.leave_proctitle)
- return;
- va_start (args, fmt);
- buf = str_vprintf (fmt, args);
- va_end (args);
- setproctitle (buf);
- free (buf);
-}
diff --git a/src/lib/showconfig.c b/src/lib/showconfig.c
@@ -1,54 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-#define SHOWDEF(a,b,c) \
- printf ("%-22s %-31s: %s \n", b, c, a ? "yes" : "no");
-
-void show_config () {
- printf ("VER version: %s\n"
- "REVVER revision version: %s\n"
- "YEARS it's been around since: %s\n"
- "AUTHORNAME author: %s\n"
- "MAINTAINERNAME maintainer: %s\n"
- "MAINTAINEREMAIL e-mail of maintainer: %s\n"
- "FQDN_LENGTH max length of a hostname: %d\n"
- "SLEEP_TIME service inactivy pause: %d\n"
- "DEF_MAX max nr of defines in a file %d\n"
- "DNS_CACHESIZE size of the DNS cache: %d\n"
- "DNS_CACHETTL default ttl of cached DNS: %d\n"
- "CONNECT_TIMEOUT backend connect timeout: %d\n"
- "RETRY_WAIT backend retry pause: %d\n"
- "DEFAULT_TCP_BUFSZ default network buffer size: %d\n"
- "PREFIX installation tree prefix: %s\n"
- "BINDIR directory for binaries: %s\n"
- "DEFAULT_SPT_BUFSIZE default cmdline length: %d\n"
- "SPT_BUFSIZE used cmdline length: %d\n"
- "SET_PROC_TITLE_BY_ARGV argv assumed linear array: %d\n"
- "EXTRALIBS extra library dependencies: %s\n"
- "LIBS standard library dependencies: %s\n"
- ,
- VER, REVVER, YEARS, AUTHORNAME, MAINTAINERNAME,
- MAINTAINEREMAIL,
- FQDN_LENGTH, SLEEP_TIME, DEF_MAX,
- DNS_CACHESIZE, DNS_CACHETTL,
- CONNECT_TIMEOUT, RETRY_WAIT, DEFAULT_TCP_BUFSZ, PREFIX, BINDIR,
- DEFAULT_SPT_BUFSIZE, SPT_BUFSIZE,
- SET_PROC_TITLE_BY_ARGV, EXTRALIBS, LIBS);
- SHOWDEF (HAVE_MALLOC_H, "HAVE_MALLOC_H", "<malloc.h> present");
- SHOWDEF (HAVE_STDINT_H, "HAVE_STDINT_H", "<stdint.h> present");
- SHOWDEF (HAVE_FLOCK, "HAVE_FLOCK", "flock() present");
- SHOWDEF (HAVE_LOCKF, "HAVE_LOCKF", "lockf() present");
- SHOWDEF (HAVE_STRLCAT, "HAVE_STRLCAT", "strlcat() present");
- SHOWDEF (HAVE_SRANDDEV, "HAVE_SRANDDEV", "sranddev() present");
- SHOWDEF (HAVE_VSYSLOG, "HAVE_VSYSLOG", "vsyslog() present");
- SHOWDEF (HAVE_STRUPR, "HAVE_STRUPR", "strupr() present");
- SHOWDEF (HAVE_STRCASESTR, "HAVE_STRCASESTR", "strcasestr() present");
- SHOWDEF (HAVE_SETPROCTITLE, "HAVE_SETPROCTITLE", "setproctitle() present");
- SHOWDEF (HAVE_STRNSTR, "HAVE_STRNSTR", "strnstr() present");
- SHOWDEF (HAVE_PROGNAME_FULL,"HAVE_PROGNAME_FULL","__progname_full present");
-}
diff --git a/src/lib/stagetostring.c b/src/lib/stagetostring.c
@@ -1,21 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-char *stage_to_string (Programstage stage) {
- switch (stage) {
- case stage_main:
- return ("main");
- case stage_waiting:
- return ("waiting");
- case stage_serving:
- return ("serving");
- case stage_retrying:
- return ("retrying");
- default:
- return ("unknown");
- }
-}
diff --git a/src/lib/statetostring.c b/src/lib/statetostring.c
@@ -1,16 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-char *state_to_string (Backendavail avail) {
- int i;
-
- for (i = 0; statestringmap[i].nm; i++)
- if (avail == statestringmap[i].av)
- return (statestringmap[i].nm);
- return ("UNKNOWN");
-}
diff --git a/src/lib/strcasestr.c b/src/lib/strcasestr.c
@@ -1,25 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-#if HAVE_STRCASESTR == 0
-char *strcasestr (char const *big, char const *little) {
- char *bcopy, *lcopy, *res;
-
- if (!little || !*little)
- return ( (char*) big);
- if (!big || !*big)
- return (0);
-
- bcopy = strupr (xstrdup (big));
- lcopy = strupr (xstrdup (little));
- if ( (res = strstr (bcopy, lcopy)) )
- res = (char*) big + (res - bcopy);
- free (bcopy);
- free (lcopy);
- return (res);
-}
-#endif
diff --git a/src/lib/strexpandformat.c b/src/lib/strexpandformat.c
@@ -1,191 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-char *fmt_expand (char const *s, int *skip, int fmt_number) {
- static char buf[80];
- int nextnumber;
-
- /* Expansion table:
- * %a - availability of current back end (if any), 0 not available,
- * %1a = first back end etc.
- * %b - name of current back end (if any), %1b = first back end etc.
- * %e - seconds since epoch, number is an addition count
- * %g - GMT format timestamp. The time in between is the minutes
- * offset into the future, so %30g is now + 1/2 hour
- * %h - actual serveraddress of current back end, %h1 = first etc.
- * %l - last connect time of current back end, %l1 = first etc.
- * %n - nr of clients of current back end, %1n = first back end etc.
- * %p - actual port of current back end, %1p = first etc.
- * %P - process ID of the Crossroads handler (debugging)
- * %r - client IP, number is not interpreted
- * %s - name of service, number is not interpreted
- * %t, %T - ANSI timestamp of local or GMT time, number is offset in min
- * into the future
- * %v - Crossroads version, number not interpreted
- * %w - weight of current back end, %1w = first back end etc.
- */
-
- (*skip)++;
- /*
- msg ("Fmt expand [%s], skip=%d, nr=%d",
- s, *skip, fmt_number);
- */
-
- switch (*s) {
-
- case 'a':
- if (!fmt_number)
- fmt_number = current_backend;
- else
- fmt_number--;
- if (fmt_number < 0 || fmt_number >= activeservice->nbackend ||
- !backend_available (fmt_number))
- return ("0");
- return ("1");
-
- case 'b':
- if (!fmt_number)
- fmt_number = current_backend;
- else
- fmt_number--;
- if (fmt_number >= 0 && fmt_number < activeservice->nbackend)
- return (activeservice->backend[fmt_number].name);
- return ("noname");
-
- case 'e':
- snprintf (buf, sizeof(buf) - 1, "%u", (unsigned) time(0) + fmt_number);
- return (buf);
-
- case 'g':
- return (gmtstamp (fmt_number));
-
- case 'h':
- if (!fmt_number)
- fmt_number = current_backend;
- else
- fmt_number--;
- if (fmt_number < 0 || fmt_number >= activeservice->nbackend)
- return ("noname");
- return (servicereport->backendstate[fmt_number].actual_server);
-
- case 'l':
- if (!fmt_number)
- fmt_number = current_backend;
- else
- fmt_number--;
- if (fmt_number >= 0 && fmt_number < activeservice->nbackend) {
- snprintf (buf, sizeof(buf) - 1, "%f",
- servicereport->backendstate[fmt_number].last_con_sec);
- return (buf);
- }
- return ("0");
-
- case 'n':
- if (!fmt_number)
- fmt_number = current_backend;
- else
- fmt_number--;
- if (fmt_number >= 0 && fmt_number < activeservice->nbackend) {
- snprintf (buf, sizeof(buf) - 1, "%u",
- (unsigned)
- servicereport->backendstate[fmt_number].nclients);
- return (buf);
- }
- return ("0");
-
- case 'p':
- if (!fmt_number)
- fmt_number = current_backend;
- else
- fmt_number--;
- if (fmt_number < 0 || fmt_number >= activeservice->nbackend)
- return ("0");
- snprintf (buf, sizeof(buf), "%d",
- servicereport->backendstate[fmt_number].actual_port);
- return (buf);
-
- case 'P':
- snprintf (buf, sizeof(buf), "%u", getpid());
- return (buf);
-
- case 'r':
- if (client_ip && *client_ip)
- return (client_ip);
- return ("0.0.0.0");
-
- case 's':
- return (activeservice->name);
-
- case 't':
- return (ansistamp (tm_localtime, fmt_number));
-
- case 'T':
- return (ansistamp (tm_gmtime, fmt_number));
-
- case 'v':
- return (VER);
-
- case 'w':
- if (!fmt_number)
- fmt_number = current_backend;
- else
- fmt_number--;
- if (fmt_number >= 0 && fmt_number < activeservice->nbackend) {
- snprintf (buf, sizeof(buf) - 1, "%u",
- (unsigned)
- activeservice->backend[fmt_number].weight);
- return (buf);
- }
- return ("0");
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- nextnumber = atoi(s);
- while (isdigit (*s)) {
- (*skip)++;
- s++;
- }
- (*skip)--;
- return (fmt_expand (s, skip, nextnumber));
-
- default:
- *buf = *(s + 1);
- *(buf + 1) = 0;
- return (buf);
- }
-}
-
-char *str_expand_format (char const *h) {
- char *ret = 0;
- char const *cp;
- int skip;
-
- for (cp = h; cp && *cp; cp++) {
- if (*cp == '%') {
- skip = 0;
- ret = xstrcat (ret, fmt_expand (cp + 1, &skip, 0));
- cp += skip;
- } else {
- ret = xstrcatch (ret, *cp);
- }
- }
-
- /*
- msg ("String [%s] expanded to [%s]",
- h, ret);
- */
- return (ret);
-}
diff --git a/src/lib/stringtostate.c b/src/lib/stringtostate.c
@@ -1,16 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-Backendavail string_to_state (char const *str) {
- int i;
-
- for (i = 0; statestringmap[i].nm; i++)
- if (!strcasecmp (str, statestringmap[i].nm))
- return (statestringmap[i].av);
- return (st_unknown);
-}
diff --git a/src/lib/strlcat.c b/src/lib/strlcat.c
@@ -1,30 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#if HAVE_STRLCAT == 0
-
-#include "../crossroads.h"
-
-size_t strlcat (char *dst, char const *src, size_t size) {
- size_t bytes = 0;
- char *q = dst;
- char const *p = src;
- char ch;
-
- while ( bytes < size && *q ) {
- q++;
- bytes++;
- }
- while ( (ch = *p++) ) {
- if ( bytes < size )
- *q++ = ch;
- bytes++;
- }
- *q = '\0';
- return bytes;
-}
-
-#endif
diff --git a/src/lib/strnstr.c b/src/lib/strnstr.c
@@ -1,35 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-#if HAVE_STRNSTR == 0
-char *strnstr (char const *big, char const *little, size_t len) {
- int i, max, llen;
-
- /* Check that we have strings */
- if (!big)
- return (0);
- if (!little)
- return ( (char*) big);
-
- /* Get lengths */
- llen = strlen(little);
- max = strlen(big) - llen;
-
- /* Check that big is bigger */
- if (max < 1)
- return (0);
-
- /* Do the search */
- for (i = 0; i <= max; i++)
- if (!strncmp (big + i, little, llen))
- return ((char*)(big + i));
-
- /* Nothing found... */
- return (0);
-}
-#endif
diff --git a/src/lib/strprintf.c b/src/lib/strprintf.c
@@ -1,13 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-char *str_printf (char const *fmt, ...) {
- va_list args;
-
- va_start (args, fmt);
- return (str_vprintf (fmt, args));
-}
diff --git a/src/lib/strupr.c b/src/lib/strupr.c
@@ -1,16 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-#if HAVE_STRUPR == 0
-char *strupr (char *buf) {
- char *cp;
-
- for (cp = buf; cp && *cp; cp++)
- *cp = toupper(*cp);
- return (buf);
-}
-#endif
diff --git a/src/lib/strvprintf.c b/src/lib/strvprintf.c
@@ -1,32 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-#define STR_BLOCK 512
-
-char *str_vprintf (char const *fmt, va_list arguments) {
- int size = STR_BLOCK; /* initial size guess */
- char *buffer = xmalloc (size); /* initial buffer */
- int nchars; /* return value of vsnprintf */
-
- while (1) { /* try to make string */
- nchars = vsnprintf (buffer, size, fmt, arguments);
-
- /* if this worked, return string */
- if (nchars > -1 && nchars < size)
- return (buffer);
-
- /* try again with more space */
- if (nchars > -1)
- size = nchars + 1;
- else
- size += STR_BLOCK;
-
- buffer = xrealloc (buffer, size);
- }
-
- return (0); /* to satisfy prototype */
-}
diff --git a/src/lib/symtabend.c b/src/lib/symtabend.c
@@ -1,13 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void symtab_end () {
- if (!symtab[nsymtab].redef)
- error ("#define %s lacks a redefinition", symtab[nsymtab].symbol);
- nsymtab++;
-}
diff --git a/src/lib/symtablookup.c b/src/lib/symtablookup.c
@@ -1,16 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-char const *symtab_lookup (char const *txt) {
- int i;
-
- for (i = 0; i < nsymtab; i++)
- if (!strcmp (symtab[i].symbol, txt))
- return (symtab[i].redef);
- return (txt);
-}
diff --git a/src/lib/symtabset.c b/src/lib/symtabset.c
@@ -1,11 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void symtab_set (char const *redef) {
- symtab[nsymtab].redef = xstrdup (redef);
-}
diff --git a/src/lib/symtabstart.c b/src/lib/symtabstart.c
@@ -1,13 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void symtab_start (char const *sym) {
- symtab = xrealloc (symtab, (nsymtab + 1) * sizeof(Symtab));
- symtab[nsymtab].symbol = xstrdup (sym);
- symtab[nsymtab].redef = 0;
-}
diff --git a/src/lib/sysrun.c b/src/lib/sysrun.c
@@ -1,50 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-/* To see the command that runs, even in the wakeup handler, undefine: */
-/* #define DEBUG */
-
-int sysrun (char const *cmd) {
- char *expanded;
- int ret;
-
- if (!cmd || ! *cmd)
- return (0);
-
- expanded = str_expand_format (cmd);
-
-# ifdef DEBUG
- msg ("running command '%s'", expanded);
-# else
- if (program_stage != stage_retrying)
- msg ("running command: '%s'", expanded);
-# endif
-
- /* Child signals are handled in system now. Also assume the right UID. */
- signal (SIGCHLD, SIG_DFL);
- uid_assume();
- ret = system (expanded);
-
- /* Get our own UID back and ignore child sigs. */
- uid_restore();
- signal (SIGCHLD, SIG_IGN);
-
- if (ret > 0)
- warning ("command '%s' returned %d", expanded, ret);
- else if (ret < 0)
- warning ("failed to run command '%s': %s", expanded, strerror(errno));
-
-# ifdef DEBUG
- if (!ret)
- msg ("command '%s' returned %d", expanded, ret);
-# endif
-
- free (expanded);
-
- return (ret);
-}
diff --git a/src/lib/tcpserve.c b/src/lib/tcpserve.c
@@ -1,235 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void tcpserve (int server_sock) {
- fd_set set;
- int backend_sock, new, size, i, pid, counter;
- unsigned octet;
- char *tmp, *cp, *last = (char *) tcpserve;
- struct sockaddr_in clientname;
- static int wakeup_started = 0;
-
- /* Set up our signal handlers. */
- if (! wakeup_started++) {
- /* Interruption signals */
- for (i = 0; relevant_sigs[i]; i++)
- signal (relevant_sigs[i], interrupt);
- /* Child termination is ignored. */
- signal (SIGCHLD, SIG_IGN);
- /* Set wakeup handler for the wakeup calls. */
- if (activeservice->rev_interval || activeservice->check_interval) {
- msg ("Starting wakeup handler");
- if ( (pid = fork()) < 0 )
- error ("Fork failed: %s", strerror(errno));
- else if (!pid) {
- set_program_title ("crossroads - Service %s: wakeup",
- activeservice->name);
- wakeup_handler();
- } else {
- msg ("started wakeup handler at pid %d", pid);
- servicereport->rev_pid = pid;
- }
- } else {
- msg ("Wakeup hander not started (reviving interval %d, check %d)",
- activeservice->rev_interval,
- activeservice->check_interval);
- }
- }
-
- /* Promote all config-side "initial" settings to "actual" ones. */
- for (i = 0; i < activeservice->nbackend; i++) {
- msg ("Initial availability of back end %s: %s, "
- "initial server:port: %s:%d",
- activeservice->backend[i].name,
- state_to_string(activeservice->backend[i].initial_avail),
- activeservice->backend[i].initial_server,
- activeservice->backend[i].initial_port);
- servicereport->backendstate[i].actual_avail =
- activeservice->backend[i].initial_avail;
- servicereport->backendstate[i].actual_port =
- activeservice->backend[i].initial_port;
- strncpy (servicereport->backendstate[i].actual_server,
- activeservice->backend[i].initial_server,
- FQDN_LENGTH - 1);
- }
-
- /* Start the listener. */
- msg ("awaiting activity on port %d (socket fd %d)",
- activeservice->port, server_sock);
- if (listen (server_sock, activeservice->backlog + 1) < 0)
- error ("failed to listen to server_socket: %s", strerror(errno));
-
- /* We're a service now. Never return, never exit
- * (unless something is REALLY wrong).
- */
- while (1) {
- /* Reload allow/deny files if requested so due to SIGHUP. */
- if (reload_allow_deny) {
- reload_allow_deny = 0;
- if (ipf_loadfile (activeservice->allowfile,
- &(activeservice->allowchain),
- &(activeservice->nallowchain)))
- warning ("Bad syntax in allow file");
- if (ipf_loadfile (activeservice->denyfile,
- &(activeservice->denychain),
- &(activeservice->ndenychain)))
- warning ("Bad syntax in deny file");
- msg ("allow chain has %d entries, "
- "deny chain has %d entries",
- activeservice->nallowchain, activeservice->ndenychain);
- }
-
- /* Block until we get a connection. */
- FD_ZERO (&set);
- FD_SET (server_sock, &set);
- if (select (FD_SETSIZE, &set, 0, 0, 0) < 0) {
- msg ("interrupt while waiting for activity: %d (%s)",
- errno, strerror(errno));
- continue;
- }
-
- /* Accept the client-side connection. */
- size = sizeof(clientname);
- if ( (new = accept (server_sock, (struct sockaddr *) &clientname,
- (socklen_t *) &size)) < 0 ) {
- warning ("failure while accepting on server socket: %s",
- strerror(errno));
- continue;
- }
-
- /* Store client IP, it's used for lots of logging. */
- client_ip = inet_ntoa (clientname.sin_addr);
- msg ("connection from %s, socket %d", client_ip, new);
-
- /* Leave it alone if there are no back ends or if we exceed
- * the max allowed clients. IN THAT CASE WE RETURN so that
- * runservice() may close the listener socket, sleep, and
- * create a new one. Exception is when the service has configured an
- * external dispatcher: in that case our backend count is not
- * reliable, and the external dispatcher may decide otherwise..
- */
- if (activeservice->dispatchtype != ds_externalhandler &&
- backend_count() == 0) {
- warning ("no back ends available");
- close (new);
- return;
- }
-
- /* Build up the actual client IP as an int.
- * We need to do this in reverse order; e.g. 1.2.3.4 needs to become
- * 4<<24 | 3<<16 | 2<<8 | 1. Reason is that when mask /16 applies,
- * we can OR this value with 16, and we'll keep 2<<8 | 1, the only
- * significant digits. */
- tmp = xstrdup (client_ip);
- client_ip_nr = 0;
- counter = 0;
- for (counter = 0, cp = strtok_r (tmp, ".", &last);
- cp;
- counter += 8, cp = strtok_r (0, ".", &last)) {
- if (sscanf (cp, "%u", &octet) > 0) {
- client_ip_nr |= (octet << counter);
- /*
- msg ("Client IP part 0x%2.2x (%d), "
- "hex client so far: 0x%8.8x",
- octet, octet, client_ip_nr);
- */
- }
- }
- free (tmp);
-
- /* Check allow/deny lists. */
- if (ipf_denied ()) {
- warning ("%s matches deny list, terminating connection", client_ip);
- close (new);
- continue;
- }
- if (!ipf_allowed ()) {
- warning ("%s failes to match allow list, terminating connection",
- client_ip);
- close (new);
- continue;
- }
-
- /* All dispatching below is done in a separate fork.
- * Dispatching delays (eg. external handlers) won't therefore
- * hinder the listener.
- */
- if ( (pid = fork()) < 0)
- error ("Fork failed: %s", strerror(errno));
- else if (pid) {
- msg ("Dispatching phase started as pid %d", pid);
- close (new);
- continue;
- }
-
- /* Here's the child process as dispatcher. The backend has yet
- * to be defined.
- * NOTE NOTE NOTE No continue's below this point - EXIT! */
-
- /* ALF support */
- #ifdef ALF
- {
- char file[80];
-
- snprintf (file, 80, "/tmp/xd-%d.alf", getpid());
- close (alf_fd);
- alf_fd = open (file, O_WRONLY);
- msg ("Service handler: alf logging to '%s', fd %d", file, alf_fd);
- }
- #endif
-
- current_backend = -1;
-
- /* Incase of a http type service: handle separately. */
- if (activeservice->type == type_http) {
- http_serve (new);
- exit (0);
- }
-
- /* Retry back ends until we succeed. */
- while (1) {
- msg ("About to choose a back end");
- choose_backend();
- if (current_backend < 0) {
- error ("Could not select a back end");
- close (new);
- }
-
- /* Connect to the backend. If this fails then we'll sleep
- * and re-enter the backend selection loop instead of returning.
- * In the loop we may need to decide to quit after all. */
- msg ("trying back end %s, port %d",
- servicereport->backendstate[current_backend].actual_server,
- servicereport->backendstate[current_backend].actual_port);
- if ( (backend_sock = backend_connect()) < 0 ) {
- warning ("failed to connect to server %s:%d (ret %d)",
- servicereport->backendstate[current_backend].actual_server,
- servicereport->backendstate[current_backend].actual_port,
- backend_sock);
- continue;
- }
-
- /* Got a live one! */
- program_stage = stage_serving;
- for (i = 0; relevant_sigs[i]; i++)
- signal (relevant_sigs[i], interrupt);
- set_program_title ("crossroads - Service %s: serving %s to %s",
- activeservice->name, client_ip,
- activeservice->backend[current_backend].name);
-
- /* Child branch: piggyback to and fro.
- * This one never returns. */
- incr_client_count();
- log_activity_start ();
- flag_verbose = activeservice->backend[current_backend].verbosity;
- copysockets (new, backend_sock);
-
- exit (0); /* superfluous, but what the heck */
- }
- }
-}
diff --git a/src/lib/thruputlog.c b/src/lib/thruputlog.c
@@ -1,58 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void thruputlog (unsigned char const *buf, int len, CopyDirection dir) {
- static double d_start = 0;
- double d_now;
- int i;
- FILE *f;
-
- if (current_backend < 0 ||
- ! activeservice->backend[current_backend].thruputfile ||
- ! *activeservice->backend[current_backend].thruputfile)
- return;
-
- /* Initialize timer if necessary. Get current time. */
- if (!d_start)
- d_start = timeofday();
- d_now = timeofday();
-
- /* Get a handle on the reporting log. */
- if ( (! (f = fopen (activeservice->backend[current_backend].thruputfile,
- "a"))) &&
- (! (f = fopen (activeservice->backend[current_backend].thruputfile,
- "w"))) ) {
- warning ("Cannot write %s: %s",
- activeservice->backend[current_backend].thruputfile,
- strerror(errno));
- return;
- }
-
-#if HAVE_FLOCK == 1
- flock (fileno(f), LOCK_EX);
-#elif HAVE_LOCKF == 1
- lockf (fileno(f), F_LOCK, 0);
-#endif
-
- /* Report the activity. */
- fprintf (f, "%7.7d %15f %c %8d ",
- getpid(),
- d_now - d_start,
- dir == dir_client_to_server ? 'C' : 'B',
- len);
- for (i = 0; i < 100 && i < len; i++)
- fputc (isprint (buf[i]) ? buf[i] : '.', f);
- fputc ('\n', f);
-
-#if defined HAVE_FLOCK
- flock (fileno(f), LOCK_UN);
-#elif defined HAVE_LOCKF
- lockf (fileno(f), F_ULOCK, 0);
-#endif
-
- fclose (f);
-}
diff --git a/src/lib/timeofday.c b/src/lib/timeofday.c
@@ -1,17 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-double timeofday () {
- struct timeval tv;
- double ret;
-
- if (gettimeofday (&tv, 0))
- error ("Failed to get the time of day: %s", strerror(errno));
- ret = (double)tv.tv_sec + (double)tv.tv_usec / 1000000;
- return (ret);
-}
diff --git a/src/lib/trafficlog.c b/src/lib/trafficlog.c
@@ -1,66 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void trafficlog (unsigned char const *buf, int len, CopyDirection dir) {
- int i, j, n = 0;
- char disp[17];
- FILE *f;
-
- if (current_backend < 0 ||
- ! activeservice->backend[current_backend].dumpfile ||
- ! *activeservice->backend[current_backend].dumpfile)
- return;
-
- if ( (! (f = fopen (activeservice->backend[current_backend].dumpfile,
- "a"))) &&
- (! (f = fopen (activeservice->backend[current_backend].dumpfile,
- "w"))) ) {
- warning ("Cannot write %s: %s",
- activeservice->backend[current_backend].dumpfile,
- strerror(errno));
- return;
- }
-
-#if HAVE_FLOCK == 1
- flock (fileno(f), LOCK_EX);
-#elif HAVE_LOCKF == 1
- lockf (fileno(f), F_LOCK, 0);
-#endif
-
- for (i = 0; i < len; i++) {
- if (! n)
- fprintf (f, "%4.4d %c %4.4x ", getpid(),
- dir == dir_client_to_server ? 'C' : 'B', i);
- fprintf (f, " %2.2x", buf[i]);
- disp[n] = isprint(buf[i]) ? buf[i] : '.';
-
- n++;
-
- if (n == 16) {
- fputc (' ', f);
- for (j = 0; j < n; j++)
- fputc (disp[j], f);
- fputc ('\n', f);
- n = 0;
- }
- }
-
- for (j = n; j < 16; j++)
- fprintf (f, " ");
- fputc (' ', f);
- for (j = 0; j < n; j++)
- fputc (disp[j], f);
- fputc ('\n', f);
-
-#if defined HAVE_FLOCK
- flock (fileno(f), LOCK_UN);
-#elif defined HAVE_LOCKF
- lockf (fileno(f), F_ULOCK, 0);
-#endif
-
- fclose (f);
-}
diff --git a/src/lib/uidassume.c b/src/lib/uidassume.c
@@ -1,28 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void uid_assume() {
- uid_set = 0;
- gid_set = 0;
-
- if (activeservice->uid) {
- if (activeservice->gid) {
- gid_org = getgid();
- if (setegid (activeservice->gid))
- error ("cannot set effective gid to %d: %s",
- activeservice->gid,
- strerror(errno));
- gid_set++;
- }
- uid_org = getuid();
- if (seteuid (activeservice->uid))
- error ("cannot set effective uid to %d: %s",
- activeservice->uid, strerror(errno));
- uid_set++;
- }
-}
diff --git a/src/lib/uidrestore.c b/src/lib/uidrestore.c
@@ -1,13 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void uid_restore () {
- if (uid_set)
- seteuid (uid_org);
- if (gid_set)
- setegid (gid_org);
-}
diff --git a/src/lib/unlockreporter.c b/src/lib/unlockreporter.c
@@ -1,26 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void unlock_reporter() {
- static int warning_issued = 0;
-
- struct sembuf buf = {
- 0, /* semaphore number */
- -1, /* subtract 1 */
- 0, /* no special flags */
- };
-
- /* msg ("UnLocking reporter memory"); */
- if ( (! warning_issued++) && (semop (semid, &buf, 1) < 0) ) {
- warning ("Failed to unlock reporter memory (stage %s): %s",
- stage_to_string (program_stage), strerror(errno));
- if (program_stage != stage_serving)
- _exit (1);
- else
- warning (".. but continuing serving this TCP connection");
- }
-}
diff --git a/src/lib/usage.c b/src/lib/usage.c
@@ -1,16 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-
-#include "../crossroads.h"
-#include "usage.h"
-
-void usage () {
- fprintf (stderr, "\n" USAGETEXT "\n", VER, AUTHORNAME, YEARS,
- MAINTAINERNAME, MAINTAINEREMAIL,
- DEFAULT_TCP_BUFSZ, DNS_CACHETTL);
- exit (1);
-}
diff --git a/src/lib/usage.txt b/src/lib/usage.txt
@@ -1,49 +0,0 @@
-This is Crossroads %s, a load balancer and fail-over utility for TCP.
-Copyright (c) %s / e-tunity %s ff. All rights reserved.
-Maintained by %s / %s.
-For distributions and updates, visit http://crossroads.e-tunity.com.
-
-Usage:
- ** Controlling the daemon: **
- crossroads [flags] start: start all services
- crossroads [flags] status [SERVICE [BACKEND]]: show the services
- and their status, optionally of stated service and/or back end
- crossroads [flags] stop: stop all services
- crossroads [flags] restart: stop and then start
- crossroads [flags] tell SERVICE BACKEND ACTION ARGS
- Backend BACKEND of service SERVICE is controlled. The ACTION
- and ARGS can be:
- 'state' NEWSTATE: Sets the state of the back end. The NEWSTATE
- must be 'available'/'up', 'unavailable', or 'down'.
- 'server' ADDRESS: Sets the back end address, which must be a
- hostname, colon, and a port.
- ** Configuration related: **
- crossroads [flags] configtest: verify that the config is OK
- crossroads [flags] services: show the configured services
-
-Supported flags:
- -a: Logs starting and finishing activity to syslog
- -b: Writes binary options and configuration to stdout (debugging only)
- -B BUFSZ Defines the network buffer size, default %d bytes
- -C: Shows compile-time configuration and stops
- -c CONFIG: Uses the named configuration
- -d TTL: Specifies the time to live of cached DNS entries,
- default %d (seconds, 0 is no caching)
- -h: Logs timings of HTTP processing to syslog
- -l FAC: Specifies the openlog(3) facility to use when logging. Default
- is LOG_DAEMON. Allowed values are 0..7 for LOG_LOCAL0 to
- LOG_LOCAL7.
- -m PERM: Sets permissions for shm access to PERM, which is an
- octal number. Defaults to 0644.
- -P: Parser and lexer actions will be verbose (debugging only)
- -p: Process title will not be altered; 'ps' will show
- 'crossroads-daemon' instead of custom title
- -s: Sloppy binding to the listen port of each service (if the port
- is busy, Crossroads will wait for it to become free).
- -t: 'status' output is shown as a tabular availability view
- -x: 'status' output is shown as an XML document
- -X XSLT: Embed reference to XSLT in 'crossroads -x status'
- -v: Enables verbosity upon startup. Other verbosity (services
- and back ends) is controlled in the configuration.
- -V: Shows the version ID and stops.
- -?: Shows this message.
diff --git a/src/lib/vsyslog.c b/src/lib/vsyslog.c
@@ -1,16 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-#if HAVE_VSYSLOG == 0
-void vsyslog (int pri, char const *fmt, va_list args) {
- char *msg;
-
- msg = str_vprintf (fmt, args);
- syslog (pri, "%s", msg);
- free (msg);
-}
-#endif
diff --git a/src/lib/wakeuphandler.c b/src/lib/wakeuphandler.c
@@ -1,93 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-/* For more verbosity of the wake up handler, undefine: */
-/* #define DEBUG */
-
-void wakeup_handler () {
- int sock, i;
- Backendavail av, prev;
-
-
- /* Set the stage and any signals that we want. */
- program_stage = stage_retrying;
- for (i = 0; relevant_sigs[i]; i++)
- signal (relevant_sigs[i], interrupt);
-
- /* Forever, until a signal kills us, or Sol explodes, causing
- * massive electromagnetic pulses that fry my CPU.
- */
- while (1) {
- /* Wait for the alarm to go off. */
- if (activeservice->rev_interval)
- sleep (activeservice->rev_interval);
- else
- sleep (activeservice->check_interval);
-
- /* Now do our stuff. */
- for (current_backend = 0;
- current_backend < activeservice->nbackend;
- current_backend++) {
-
- /* If we're in the REVIVING mode and the back end isn't
- * unavailable, then we don't need to check it. Also,
- * back ends marked DOWN on purpose are skipped. */
- prev = servicereport->backendstate[current_backend].actual_avail;
- if ( (prev == st_down) ||
- (activeservice->rev_interval && prev != st_unavailable) )
- continue;
-
-# ifdef DEBUG
- msg ("verifying back end %s, old state %s",
- activeservice->backend[current_backend].name,
- state_to_string(prev));
-# endif
-
- /* Mark state as WAKING */
- lock_reporter();
- servicereport->backendstate[current_backend].actual_avail =
- st_waking;
- unlock_reporter();
-
- if (! activeservice->check_cmd) {
- /* In TCP-only mode: do the connect */
- if ( (sock = backend_connect()) >= 0 ) {
- close (sock);
- av = st_available;
- } else
- av = st_unavailable;
- } else {
- /* In checkscript mode: do the checking */
- if (!sysrun (activeservice->check_cmd))
- av = st_available;
- else
- av = st_unavailable;
- }
-
- /* Set state accordingly */
- if (prev != av) {
- if (av == st_available)
- warning ("Backend %s of service %s has woken up",
- activeservice->backend[current_backend].name,
- activeservice->name);
- else
- warning ("Backend %s of service %s has died",
- activeservice->backend[current_backend].name,
- activeservice->name);
- }
-
- /* Store the new state. If the new state is AVAILABLE
- * then reset the error count (used by retries config value). */
- lock_reporter();
- servicereport->backendstate[current_backend].actual_avail = av;
- if (av == st_available)
- servicereport->backendstate[current_backend].fail = 0;
- unlock_reporter();
- }
- }
-}
diff --git a/src/lib/warning.c b/src/lib/warning.c
@@ -1,32 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void warning (char const *fmt, ...) {
- va_list args;
- char *str;
-
- if (!fmt || !*fmt)
- return;
-
- va_start (args, fmt);
- str = str_vprintf (fmt, args);
- if (!daemonized) {
- if (activeservice)
- fprintf (stderr, "WARNING, Service %s: %s",
- activeservice->name, str);
- else
- fprintf (stderr, "WARNING: %s\n", str);
- } else {
- if (activeservice)
- writelog (LOG_ERR, "WARNING, Service %s: %s",
- activeservice->name, str);
- else
- writelog (LOG_ERR, "WARNING: %s", str);
- }
- free (str);
-}
diff --git a/src/lib/writelog.c b/src/lib/writelog.c
@@ -1,15 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void writelog (int prio, char const *fmt, ...) {
- va_list args;
-
- va_start (args, fmt);
- if (!logstarted++)
- openlog ("crossroads", LOG_PID, opt.log_facility);
- vsyslog (prio, fmt, args);
-}
diff --git a/src/lib/xcalloc.c b/src/lib/xcalloc.c
@@ -1,18 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-
-#include "../crossroads.h"
-
-void *xcalloc (unsigned sz) {
- void *ret;
-
- if (!sz)
- return (0);
-
- ret = xmalloc (sz);
- memset (ret, 0, sz);
- return (ret);
-}
diff --git a/src/lib/xmalloc.c b/src/lib/xmalloc.c
@@ -1,10 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void *xmalloc (unsigned sz) {
- return (xrealloc (0, sz));
-}
diff --git a/src/lib/xrealloc.c b/src/lib/xrealloc.c
@@ -1,27 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-void *xrealloc (void *block, unsigned sz) {
- void *newblock;
-
- /* msg ("Realloc: block=%x, sz=%u", block, sz); */
- if (! sz) {
- free (block);
- newblock = 0;
- /* msg ("Realloc: freed %x", block); */
- } else if (!block) {
- if (! (newblock = malloc (sz)) )
- error ("Out of memory (while allocating %u bytes)", sz);
- /* msg ("Realloc: malloc'd %x (%u bytes)", newblock, sz); */
- } else {
- if (! (newblock = realloc (block, sz)) )
- error ("Out of memory (while increasing block to %u bytes)", sz);
- /* msg ("Realloc'd %x to %x (%u bytes)", block, newblock, sz); */
- }
- return (newblock);
-}
-
diff --git a/src/lib/xstrcat.c b/src/lib/xstrcat.c
@@ -1,19 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-char *xstrcat (char *what, char const *rest) {
- if (!what || !*what)
- return (xstrdup (rest));
- if (!rest || !*rest)
- return (what);
-
- if (! (what = realloc (what, strlen(what) + strlen(rest) + 1)) )
- error ("Out of memory (while adding '%s' to '%s'",
- rest, what);
- strlcat (what, rest, strlen(what) + strlen(rest) + 1);
- return (what);
-}
diff --git a/src/lib/xstrcatch.c b/src/lib/xstrcatch.c
@@ -1,14 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-char *xstrcatch (char *what, char ch) {
- char buf[2];
-
- buf[0] = ch;
- buf[1] = 0;
- return (xstrcat (what, buf));
-}
diff --git a/src/lib/xstrdup.c b/src/lib/xstrdup.c
@@ -1,16 +0,0 @@
-/*************************************************************************
- * This file is part of Crosroads 1.81, a load balancer and fail over
- * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
- * Visit http://crossroads.e-tunity.com for information.
- *************************************************************************/
-#include "../crossroads.h"
-
-char *xstrdup (char const *what) {
- char *ret;
-
- if (!what)
- return (0);
- if (! (ret = strdup (what)) )
- error ("Out of memory (while copying '%s')", what);
- return (ret);
-}
diff --git a/test/Makefile b/test/Makefile
@@ -1,30 +0,0 @@
-include $(BASE)/etc/Makefile.def
-include $(BASE)/etc/Makefile.conf
-
-foo: hashtest
- @echo 'Running simplistic tests...'
- @echo
- @for f in t*.conf ; do \
- echo "Testing $$f: should succeed" ; \
- echo "TEST: ../src/crossroads/crossroads -vc $$f services" ; \
- ../src/crossroads/crossroads -vc $$f services || exit 1 ; \
- echo "$$f succeeded, good." ; \
- echo ; \
- done
- @for f in bad*.conf ; do \
- echo "Testing $$f: should fail" ; \
- echo "TEST: ../src/crossroads/crossroads -vc $$f services" ; \
- ../src/crossroads/crossroads -vc $$f services && exit 1 ; \
- echo "$$f failed, good." ; \
- echo ; \
- done
- @echo
- @echo 'All tests have completed successfully.'
- @echo 'Run test/hashtest to test the hashing algorithm.'
- @echo
-
-hashtest: hashtest.c
- $(CC) $(DEFS) -o hashtest hashtest.c -L../src/lib -lcrossroads
-
-clean:
- rm -f *.o hashtest
diff --git a/test/allowfrom.conf b/test/allowfrom.conf
@@ -1,15 +0,0 @@
-/* Test of 'allow from' on a client level. */
-
-#define DEBUG on
-
-service testservice {
- port 2222;
- verbosity DEBUG;
- revivinginterval 3;
- allowfrom 127/8;
-
- backend sshd {
- server localhost:22;
- verbosity DEBUG;
- }
-}
diff --git a/test/bad01.conf b/test/bad01.conf
@@ -1,16 +0,0 @@
-/* Bad configuration
- * multiple service 'bla' definitions */
-service bla {
- port 10000;
- backend one {
- server x:80;
- }
-}
-
-service bla {
- port 10001;
- backend one {
- server x:80;
- }
-}
-
diff --git a/test/bad02.conf b/test/bad02.conf
@@ -1,11 +0,0 @@
-/* Bad configuration
- * multiple backend 'one' definitions */
-service bla {
- port 10000;
- backend one {
- server x:80;
- }
- backend one {
- server x:80;
- }
-}
diff --git a/test/bad03.conf b/test/bad03.conf
@@ -1,3 +0,0 @@
-/* Bad configuration
- * no services */
-
diff --git a/test/bad04.conf b/test/bad04.conf
@@ -1,5 +0,0 @@
-/* Bad configuration
- * no back ends */
-service bla {
- port 10000;
-}
diff --git a/test/bad05.conf b/test/bad05.conf
@@ -1,9 +0,0 @@
-/* Bad configuration
- * no back end port */
-service bla {
- port 10000;
- backend one {
- server x;
- }
-}
-
diff --git a/test/bad06.conf b/test/bad06.conf
@@ -1,8 +0,0 @@
-/* Bad configuration
- * no service port */
-service bla {
- backend one {
- server x:10000;
- }
-}
-
diff --git a/test/bad07.conf b/test/bad07.conf
@@ -1,11 +0,0 @@
-/* Bad configuration
- * bad define 1 */
-
-#define
-service bla {
- port 80;
- backend one {
- server x:10000;
- }
-}
-
diff --git a/test/bad08.conf b/test/bad08.conf
@@ -1,11 +0,0 @@
-/* Bad configuration
- * bad define 2 */
-
-#define bla
-service bla {
- port 80;
- backend one {
- server x:10000;
- }
-}
-
diff --git a/test/bad09.conf b/test/bad09.conf
@@ -1,5 +0,0 @@
-/* Bad configuration
- * bad define 3 */
-
-#define
-
diff --git a/test/bad10.conf b/test/bad10.conf
@@ -1,6 +0,0 @@
-/* Bad configuration
- * bad include */
-
-#include
-
-
diff --git a/test/bad11.conf b/test/bad11.conf
@@ -1,12 +0,0 @@
-/* Bad configuration
- * bad statement in bad11a.inc */
-
-#include "bad11a.inc"
-
-service bla {
- port 80;
- backend one {
- server localhost:91;
- }
-}
-
diff --git a/test/bad11a.inc b/test/bad11a.inc
@@ -1,6 +0,0 @@
-service tester {
- port xyzzy;
- backend two {
- server localhost:80;
- }
-}
diff --git a/test/bad12.conf b/test/bad12.conf
@@ -1,12 +0,0 @@
-/* Bad configuration
- * bad statement in bad12.inc */
-
-#include "bad12a.inc"
-
-service bla {
- port xyzzy;
- backend one {
- server localhost:91;
- }
-}
-
diff --git a/test/bad12a.inc b/test/bad12a.inc
@@ -1,6 +0,0 @@
-service tester {
- port 10000;
- backend two {
- server localhost:80;
- }
-}
diff --git a/test/bad13.conf b/test/bad13.conf
@@ -1,40 +0,0 @@
-/* Bad configuration
- simple parse error */
-
-service test {
- port 10001;
- type http;
- bindto any;
- dispatchmode bysize;
- connectiontimeout 600;
- verbosity on;
-
- backend a {
- server localhost;
- port 10000;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_A;
- addclientheader "Set-Cookie: BalancerID=Backend_A; Path=/";
- }
-
- backend b {
- server localhost;
- port 10000;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_B;
- addclientheader "Set-Cookie: BalancerID=Backend_B; Path=/";
- }
-
- backend c {
- server localhost;
- port 10000;
- weight 3;
- decay 5;
- stickycookie BalancerID=Backend_C;
- addclientheader "Set-Cookie: BalancerID=Backend_C; Path=/";
- }
-}
-
-error is here
diff --git a/test/bad14.conf b/test/bad14.conf
@@ -1,40 +0,0 @@
-/* Bad configuration
- both revivinginterval and checkinterval present */
-
-service test {
- port 10001;
- type http;
- bindto any;
- dispatchmode bysize;
- connectiontimeout 600;
- verbosity on;
- revivinginterval 12;
- checkinterval 13;
-
- backend a {
- server localhost;
- port 10000;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_A;
- addclientheader "Set-Cookie: BalancerID=Backend_A; Path=/";
- }
-
- backend b {
- server localhost;
- port 10000;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_B;
- addclientheader "Set-Cookie: BalancerID=Backend_B; Path=/";
- }
-
- backend c {
- server localhost;
- port 10000;
- weight 3;
- decay 5;
- stickycookie BalancerID=Backend_C;
- addclientheader "Set-Cookie: BalancerID=Backend_C; Path=/";
- }
-}
diff --git a/test/bad15.conf b/test/bad15.conf
@@ -1,39 +0,0 @@
-/* Bad configuration
- syntax error in checkinterval */
-
-service test {
- port 10001;
- type http;
- bindto any;
- dispatchmode bysize;
- connectiontimeout 600;
- verbosity on;
- checkinterval 13 xyzzy;
-
- backend a {
- server localhost;
- port 10000;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_A;
- addclientheader "Set-Cookie: BalancerID=Backend_A; Path=/";
- }
-
- backend b {
- server localhost;
- port 10000;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_B;
- addclientheader "Set-Cookie: BalancerID=Backend_B; Path=/";
- }
-
- backend c {
- server localhost;
- port 10000;
- weight 3;
- decay 5;
- stickycookie BalancerID=Backend_C;
- addclientheader "Set-Cookie: BalancerID=Backend_C; Path=/";
- }
-}
diff --git a/test/bad16.conf b/test/bad16.conf
@@ -1,44 +0,0 @@
-/* bad state def */
-
-#define SERVICENAME test
-#define SERVICEPORT 10001
-#define BACKENDSERVER localhost
-#define BACKPORT 80
-
-service test {
- port SERVICEPORT;
- type http;
- bindto any;
- dispatchmode bysize;
- connectiontimeout 600;
- verbosity on;
- checkinterval 5 externalhandler "myscript";
-
- backend a {
- server BACKENDSERVER;
- port BACKPORT;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_A;
- addclientheader "Set-Cookie: BalancerID=Backend_A; Path=/";
- }
-
- backend b {
- server BACKENDSERVER:BACKPORT;
- port BACKPORT;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_B;
- addclientheader "Set-Cookie: BalancerID=Backend_B; Path=/";
- }
-
- backend c {
- server BACKENDSERVER;
- port BACKPORT;
- weight 3;
- decay 5;
- stickycookie BalancerID=Backend_C;
- addclientheader "Set-Cookie: BalancerID=Backend_C; Path=/";
- state blabla;
- }
-}
diff --git a/test/bad17.conf b/test/bad17.conf
@@ -1,14 +0,0 @@
-/*
- * Two service statements with same ports and same bindto's.
- */
-service one {
- port 80;
- bindto 1.2.3.4;
- backend one { server 10.1.1.1:80; }
-}
-
-service two {
- port 80;
- bindto 1.2.3.4;
- backend two { server 10.1.1.1:80; }
-}
diff --git a/test/bad18.conf b/test/bad18.conf
@@ -1,13 +0,0 @@
-/*
- * Two service statements with same ports and only one has a bindto.
- */
-service one {
- port 80;
- bindto 1.2.3.4;
- backend one { server 10.1.1.1:80; }
-}
-
-service two {
- port 80;
- backend two { server 10.1.1.1:80; }
-}
diff --git a/test/bad19.conf b/test/bad19.conf
@@ -1,12 +0,0 @@
-/*
- * Two service statements with same ports and no bindto's.
- */
-service one {
- port 80;
- backend one { server 10.1.1.1:80; }
-}
-
-service two {
- port 80;
- backend two { server 10.1.1.1:80; }
-}
diff --git a/test/bad20.conf b/test/bad20.conf
@@ -1,13 +0,0 @@
-/*
- * Two service statements with same ports and only one has a bindto.
- */
-service one {
- port 80;
- backend one { server 10.1.1.1:80; }
-}
-
-service two {
- port 80;
- bindto 1.2.3.4;
- backend two { server 10.1.1.1:80; }
-}
diff --git a/test/bad21.conf b/test/bad21.conf
@@ -1,9 +0,0 @@
-/* HTTP commands with 'type any' */
-service one {
- port 80;
- backend one {
- server 10.1.1.1:80;
- addclientheader "X-bla: blerk";
- }
-}
-
diff --git a/test/bad22.conf b/test/bad22.conf
@@ -1,8 +0,0 @@
-/* A back end with a httptiminglog directive, but the service isn't http */
-service test {
- port 2000;
- backend one {
- server localhost:2001;
- httptiminglog /tmp/logfile;
- }
-}
diff --git a/test/bad23.conf b/test/bad23.conf
@@ -1,9 +0,0 @@
-/* A back end with maxconnctions, but there is an external handler */
-service test {
- port 2000;
- dispatchmode externalhandler 'bla';
- backend one {
- server localhost:2001;
- maxconnections 20;
- }
-}
diff --git a/test/breakingclient b/test/breakingclient
@@ -1,58 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-$|++;
-
-sub sigcatcher {
- # warn ("$$: Stopping wgets\n");
- system ("killall -9 wget");
- exit (0);
-}
-
-$SIG{HUP} = \&sigcatcher;
-
-system ("mkdir -p /tmp/$$") and die ("Cannot mkdir $$");
-chdir ("/tmp/$$") or die ("Cannot chdir to /tmp/$$: $!\n");
-my $run = 0;
-while (1) {
- print ("$$ Run: ", ++$run);
- system ("rm -rf /tmp/$$/localhost* >/dev/null 2>&1");
- my $pid = fork();
- die ("Fork failed: $!\n") unless (defined ($pid));
- if ($pid) {
- sleep (3);
- system ("killall -9 wget");
- kill ('HUP', $pid);
- wait();
- my @fls = glob ("/tmp/$$/localhost:10000/~karel/imagepage/img*png");
- print (" ", $#fls + 1, " images retrieved\n");
- sleep (1);
- } else {
- open (my $if,
- "wget -r -S --http-user=user --http-password=password " .
- "--no-cache " .
- "http://localhost:10000/~karel/imagepage/index.php 2>&1 |")
- or die ("Cannot start wget\n");
- my $via = '';
- while (my $line = <$if>) {
- # print ($line);
- chomp ($line);
- if ($line =~ /Set-Cookie/ and $line =~ /XRID/) {
- $line =~ s{.*XRID=}{};
- $line =~ s{;.*}{};
- if ($via eq '') {
- $via = $line;
- } elsif ($via ne $line) {
- warn ("Warning: via changed from $via to $line\n");
- }
- } elsif ($line =~ /HTTP\//) {
- $line =~ s{.*HTTP/[01. ]*}{};
- $line =~ s{ .*}{};
- warn ("Warning: got status $line\n")
- if ($line != 200 and $line != 404);
- }
- }
- close ($if);
- exit(0);
- }
-}
diff --git a/test/chunkedserver b/test/chunkedserver
@@ -1,110 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use Socket;
-use POSIX;
-
-# Verbose messaging
-sub msg {
- print STDERR ("chunkedserver: ", @_);
-}
-
-# Child process catcher
-sub reaper {
- while ((my $waitedpid = waitpid(-1,WNOHANG)) > 0) {
- msg ("Child $waitedpid done",
- ($? ? " with exit $?" : ''),
- "\n");
- }
- $SIG{CHLD} = \&reaper;
-}
-
-# Connection handler
-sub handleconnection () {
- my $pid;
-
- # Daemonize
- if (!defined ($pid = fork())) {
- msg ("Can't fork: $!\n");
- return;
- } elsif ($pid) {
- # Parent branch
- msg ("Connection handler started as pid $pid\n");
- return;
- }
-
- # Child branch
- while (defined (my $line = <Client>)) {
- chomp ($line);
- $line =~ s/\r//;
- last if ($line eq '');
- msg ("Client says: [$line]\n");
- }
-
- msg ("Sending response\n");
- print Client ("HTTP/1.1 200 OK\r\n",
- "Connection: close\r\n",
- "Transfer-Encoding: chunked\r\n",
- "Content-Type: text/plain\r\n",
- "\r\n",
- "5\r\n",
- "Hello\r\n",
- "1\r\n",
- " \r\n",
- "5\r\n",
- "World\r\n",
- "2\r\n",
- "!\n\r\n",
- "0\r\n",
- "\r\n");
- exit (0);
-}
-
-# Daemon server
-sub serve ($) {
- my $port = shift;
-
- # Create the tcp service.
- socket (Server, PF_INET, SOCK_STREAM, getprotobyname ('tcp'))
- or die ("Can't create chunkedserver socket: $!\n");
- setsockopt (Server, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))
- or die ("Can't set socket options: $!\n");
- bind (Server, sockaddr_in ($port, INADDR_ANY))
- or die ("Can't bind to port: $!\n");
- listen (Server, SOMAXCONN)
- or die ("Can't listen to socket: $!\n");
- msg ("Chunkedserver started on port $port.\n");
-
- $SIG{CHLD} = \&reaper;
- $SIG{INT} = sub {
- msg ("Interrupt caught, terminating..\n");
- exit(0);
- };
-
- while (1) {
- for (my $waitedpid = 0;
- (my $paddr = accept (Client, Server)) || $waitedpid;
- $waitedpid = 0, close (Client)) {
- next if ($waitedpid and not $paddr);
- my ($port, $iaddr) = sockaddr_in ($paddr);
- my $name = gethostbyaddr ($iaddr, AF_INET);
-
- msg ("Connection from $name/", inet_ntoa ($iaddr), ":$port\n");
-
- handleconnection ();
- }
- }
-}
-
-# Main starts here
-if ($#ARGV != 1) {
- die <<"ENDUSAGE";
-
-Usage: chunkedserver nsec portnr
-
-ENDUSAGE
-}
-
-alarm (shift (@ARGV));
-serve (shift (@ARGV));
-
diff --git a/test/client b/test/client
@@ -1,55 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use Socket;
-
-if ($#ARGV != 2) {
- die <<"ENDUSAGE";
-
-Usage: client ntimes host port
-
-ENDUSAGE
-}
-
-my ($ntimes, $host, $port) = @ARGV;
-
-print ("Starting client loop to query $host:$port..\n");
-select (undef, undef, undef, 0.2);
-
-my %hits = (a => 0, b => 0, c => 0, unknown => 0, errors => 0);
-
-for my $n (1..$ntimes) {
- open (my $if, "wget -vSO- http://$host:$port 2>&1 |")
- or die ("Can't start wget: $!\n");
- my ($a, $b, $c, $unk, $err);
- $err = 1;
- while (my $msg = <$if>) {
- chomp ($msg);
- # print ("Server says: [$msg]\n");
- if ($msg =~ /HTTP.*200 OK/ or $msg =~ /Hello World/) {
- $err = 0;
- } elsif ($msg =~ /Backend_A/) {
- $a = 1;
- } elsif ($msg =~ /Backend_B/) {
- $b = 1;
- } elsif ($msg =~ /Backend_C/) {
- $c = 1;
- }
- }
- close ($if);
-
- $unk = 1 if ($a == 0 and $b == 0 and $c == 0);
-
- $hits{a} += $a;
- $hits{b} += $b;
- $hits{c} += $c;
- $hits{unknown} += $unk;
- $hits{errors} += $err;
-
- for my $k (sort (keys (%hits))) {
- print ("$k=$hits{$k} ");
- }
- print ("\n");
-
- # select (undef, undef, undef, 0.2);
-};
diff --git a/test/extcheck.conf b/test/extcheck.conf
@@ -1,14 +0,0 @@
-/* This verifies an externalhandler for backend availability checks.
- * After hitting XR on port 30000, the test-backend will be marked
- * available. Within 5 secs, XR will decide that it's up after all,
- * cuz the externalhandler says so. */
-
-service test {
- verbosity on;
- port 30000;
- checkinterval 5 externalhandler "echo up | grep up";
- backend test {
- verbosity on;
- server localhost:30001;
- }
-}
diff --git a/test/extdispatcher b/test/extdispatcher
@@ -1,14 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-
-sub msg {
- open (my $of, ">>/tmp/extdispatcher.log") or return;
- print $of (@_);
-}
-
-# Main
-msg ("Run started, arguments: @ARGV\n");
-
-# Reply that backend "one" is the right one to choose.
-print ("one\n");
diff --git a/test/extdispatcher.conf b/test/extdispatcher.conf
@@ -1,19 +0,0 @@
-/* Test of an external dispatcher */
-
-#define DEBUG on
-
-service test {
- port 20000;
- verbosity DEBUG;
- dispatchmode externalhandler
- "/usr/local/src/crossroads/test/extdispatcher %r %s";
-
- backend one {
- server localhost:20001;
- verbosity DEBUG;
- }
- backend two {
- server localhost:20002;
- verbosity DEBUG;
- }
-}
diff --git a/test/hashtest.c b/test/hashtest.c
@@ -1,45 +0,0 @@
-#include "../src/crossroads.h"
-
-int hits[100];
-
-int main (int argc, char **argv) {
- int max, b1, b2, b3, b4, index, n = 0;
- char buf[255];
-
- if (argc == 2) {
- if (! (max = atoi (argv[1])) ) {
- fprintf (stderr, "%s is not a number (1..100 required)\n", argv[1]);
- exit (1);
- }
- for (b1 = 1; b1 <= 255; b1++)
- for (b2 = 1; b2 <= 255; b2++)
- for (b3 = 1; b3 <= 255; b3++)
- for (b4 = 1; b4 <= 255; b4++) {
- sprintf (buf, "%d.%d.%d.%d", b1, b2, b3, b4);
- index = hashpjw (buf) % max;
- hits[index]++;
- if (! (n % 100000)) {
- printf ("\r%-30s %d", buf, index);
- fflush (stdout);
- n = 0;
- }
- n++;
- }
-
- for (index = 0; index < max; index++)
- printf ("\n\ndone\n"
- "index %d: %d hits\n", index, hits[index]);
- } else if (argc == 3) {
- if (! (max = atoi (argv[1])) ) {
- fprintf (stderr, "%s is not a number (1..100 required)\n", argv[1]);
- exit (1);
- }
- printf ("%d\n", hashpjw (argv[2]) % max);
- } else {
- fprintf (stderr, "Usage: hashtest nbackends [ip-address]\n");
- exit (1);
- }
-
- return (0);
-}
-
diff --git a/test/maxcon.conf b/test/maxcon.conf
@@ -1,27 +0,0 @@
-/* Test of 'maxconnections' on a client level.
- * Each new connection must be handled by a different client, until
- * the connections are exhausted. */
-
-#define DEBUG on
-
-service threeallowed {
- port 2222;
- verbosity DEBUG;
- revivinginterval 3;
-
- backend v01 {
- server localhost:22;
- maxconnections 1;
- verbosity DEBUG;
- }
- backend v02 {
- server localhost:22;
- maxconnections 1;
- verbosity DEBUG;
- }
- backend v03 {
- server localhost:22;
- maxconnections 1;
- verbosity DEBUG;
- }
-}
diff --git a/test/runtest b/test/runtest
@@ -1,65 +0,0 @@
-#!/usr/bin/perl
-
-
-# Small test runner. For debugging only.
-
-use strict;
-
-my $tests = <<'ENDTEST';
- ../src/crossroads/crossroads -c t01.conf start
- ./server 12 10000 &
- ./client 200 localhost 10001
- sleep 5
- ../src/crossroads/crossroads -c t01.conf status
- ../src/crossroads/crossroads -c t01.conf stop
-
- ../src/crossroads/crossroads -c t02.conf start
- ./server 12 10000 &
- ./client 200 localhost 10001
- sleep 5
- ../src/crossroads/crossroads -c t02.conf status
- ../src/crossroads/crossroads -c t02.conf stop
-
- ../src/crossroads/crossroads -c t03.conf start
- time ssh -p23 root@localhost; true
- ../src/crossroads/crossroads -c t03.conf status
- ../src/crossroads/crossroads -c t03.conf stop
-
- ../src/crossroads/crossroads -c t04.conf start
- ./server 12 10000 &
- ./client 200 localhost 10001
- sleep 5
- ../src/crossroads/crossroads -c t04.conf status
- ../src/crossroads/crossroads -c t04.conf stop
-
- ../src/crossroads/crossroads -c t06.conf start
- ./server 12 10000 &
- ./client 200 localhost 10001
- sleep 5
- ../src/crossroads/crossroads -c t06.conf status
- ../src/crossroads/crossroads -c t06.conf stop
-
-ENDTEST
-
-sub runtest {
- for my $cmd (@_) {
- $cmd =~ s/^ *//;
- print STDERR ("runtest: [$cmd]\n");
- system ($cmd) and die ("runtest: [$cmd] has failed\n");
- }
- print ("Press ENTER for next test\n");
- <STDIN>;
-}
-
-# Main
-my @cmds = ();
-for my $s (split (/\n/, $tests)) {
- if ($s ne '') {
- push (@cmds, $s);
- } else {
- if ($#cmds > -1) {
- runtest (@cmds);
- @cmds = ();
- }
- }
-}
diff --git a/test/server b/test/server
@@ -1,100 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use Socket;
-use POSIX;
-
-# Verbose messaging
-sub msg {
- # print STDERR ("server: ", @_);
-}
-
-# Child process catcher
-sub reaper {
- while ((my $waitedpid = waitpid(-1,WNOHANG)) > 0) {
- msg ("Child $waitedpid done",
- ($? ? " with exit $?" : ''),
- "\n");
- }
- $SIG{CHLD} = \&reaper;
-}
-
-# Connection handler
-sub handleconnection () {
- my $pid;
-
- # Daemonize
- if (!defined ($pid = fork())) {
- msg ("Can't fork: $!\n");
- return;
- } elsif ($pid) {
- # Parent branch
- msg ("Connection handler started as pid $pid\n");
- return;
- }
-
- # Child branch
- 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 Client ("HTTP/1.0 200 OK\r\n",
- "Content-length: ", length($msg), "\r\n",
- "\r\n",
- $msg);
- exit (0);
-}
-
-# Daemon server
-sub serve ($) {
- my $port = shift;
-
- # Create the tcp service.
- socket (Server, PF_INET, SOCK_STREAM, getprotobyname ('tcp'))
- or die ("Can't create server socket: $!\n");
- setsockopt (Server, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))
- or die ("Can't set socket options: $!\n");
- bind (Server, sockaddr_in ($port, INADDR_ANY))
- or die ("Can't bind to port: $!\n");
- listen (Server, SOMAXCONN)
- or die ("Can't listen to socket: $!\n");
- msg ("Server started on port $port.\n");
-
- $SIG{CHLD} = \&reaper;
- $SIG{INT} = sub {
- msg ("Interrupt caught, terminating..\n");
- exit(0);
- };
-
- while (1) {
- for (my $waitedpid = 0;
- (my $paddr = accept (Client, Server)) || $waitedpid;
- $waitedpid = 0, close (Client)) {
- next if ($waitedpid and not $paddr);
- my ($port, $iaddr) = sockaddr_in ($paddr);
- my $name = gethostbyaddr ($iaddr, AF_INET);
-
- msg ("Connection from $name/", inet_ntoa ($iaddr), ":$port\n");
-
- handleconnection ();
- }
- }
-}
-
-# Main starts here
-if ($#ARGV != 1) {
- die <<"ENDUSAGE";
-
-Usage: server nsec portnr
-
-ENDUSAGE
-}
-
-alarm (shift (@ARGV));
-serve (shift (@ARGV));
-
diff --git a/test/t01.conf b/test/t01.conf
@@ -1,35 +0,0 @@
-service test {
- port 10001;
- type http;
- bindto any;
- dispatchmode bysize;
- connectiontimeout 600;
- verbosity on;
-
- backend a {
- server localhost;
- port 10000;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_A;
- addclientheader "Set-Cookie: BalancerID=Backend_A; Path=/";
- }
-
- backend b {
- server localhost;
- port 10000;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_B;
- addclientheader "Set-Cookie: BalancerID=Backend_B; Path=/";
- }
-
- backend c {
- server localhost;
- port 10000;
- weight 3;
- decay 5;
- stickycookie BalancerID=Backend_C;
- addclientheader "Set-Cookie: BalancerID=Backend_C; Path=/";
- }
-}
diff --git a/test/t02.conf b/test/t02.conf
@@ -1,36 +0,0 @@
-service test {
- port 10001;
- type http;
- bindto any;
- revivinginterval 5;
- dispatchmode random;
- connectiontimeout 600;
- verbosity on;
-
- backend a {
- server localhost;
- verbosity on;
- port 10000;
- weight 2;
- stickycookie BalancerID=Backend_A;
- addclientheader "Set-Cookie: BalancerID=Backend_A; Path=/";
- }
-
- backend b {
- server localhost;
- verbosity on;
- port 10000;
- weight 3;
- stickycookie BalancerID=Backend_B;
- addclientheader "Set-Cookie: BalancerID=Backend_B; Path=/";
- }
-
- backend c {
- server localhost;
- verbosity on;
- port 10000;
- weight 3;
- stickycookie BalancerID=Backend_C;
- addclientheader "Set-Cookie: BalancerID=Backend_C; Path=/";
- }
-}
diff --git a/test/t03.conf b/test/t03.conf
@@ -1,13 +0,0 @@
-/* Another testing scenario.
- * This one forwards port 23 to localhost:22 (sshd), and logs out
- * after 10 secs of inactivity. */
-
-service ssh {
- port 23;
- connectiontimeout 10;
- verbosity true;
- backend a {
- verbosity true;
- server localhost:22;
- }
-}
diff --git a/test/t04.conf b/test/t04.conf
@@ -1,35 +0,0 @@
-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;
- addclientheader "Set-Cookie: BalancerID=Backend_A; Path=/";
- addserverheader "X-Real-IP: %r";
- }
-
- backend b {
- server localhost;
- port 10000;
- verbosity on;
- stickycookie BalancerID=Backend_B;
- addclientheader "Set-Cookie: BalancerID=Backend_B; Path=/";
- addserverheader "X-Real-IP: %r";
- }
-
- backend c {
- server localhost;
- port 10000;
- verbosity on;
- stickycookie BalancerID=Backend_C;
- addclientheader "Set-Cookie: BalancerID=Backend_C; Path=/";
- addserverheader "X-Real-IP: %r";
- }
-}
diff --git a/test/t05.conf b/test/t05.conf
@@ -1,31 +0,0 @@
-service test {
- port 10001;
- type http;
- bindto any;
- revivinginterval 5;
- dispatchmode bysize;
- connectiontimeout 600;
- verbosity on;
-
- backend a {
- server localhost;
- port 10000;
- weight 2;
- decay 5;
- }
-
- backend b {
- server localhost;
- port 10000;
- weight 2;
- decay 5;
- }
-
- backend c {
- server localhost;
- port 10000;
- weight 3;
- decay 5;
-
- }
-}
diff --git a/test/t06.conf b/test/t06.conf
@@ -1,44 +0,0 @@
-service test {
- port 10001;
- type http;
- bindto any;
- dispatchmode bysize;
- connectiontimeout 600;
- verbosity on;
-
- backend a {
- server localhost;
- port 10000;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_A;
- addclientheader "Set-Cookie: BalancerID=Backend_A; Path=/";
- setclientheader "Host: undisclosed-webserver";
- setclientheader "X-Timestamp: %t";
- setserverheader "X-Real-IP: %r";
- }
-
- backend b {
- server localhost;
- port 10000;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_B;
- setclientheader "Host: undisclosed-webserver";
- addclientheader "Set-Cookie: BalancerID=Backend_B; Path=/";
- setclientheader "X-Timestamp: %t";
- setserverheader "X-Real-IP: %r";
- }
-
- backend c {
- server localhost;
- port 10000;
- weight 3;
- decay 5;
- stickycookie BalancerID=Backend_C;
- setclientheader "Host: undisclosed-webserver";
- addclientheader "Set-Cookie: BalancerID=Backend_C; Path=/";
- setclientheader "X-Timestamp: %t";
- setserverheader "X-Real-IP: %r";
- }
-}
diff --git a/test/t07.conf b/test/t07.conf
@@ -1,13 +0,0 @@
-service t7 {
- port 10000;
- type http;
- verbosity on;
- backend t7a {
- server localhost:3128;
- verbosity on;
- }
- backend t7b {
- server localhost:3128;
- verbosity on;
- }
-}
diff --git a/test/t08.conf b/test/t08.conf
@@ -1,32 +0,0 @@
-service test {
- port 10000;
- type http;
- bindto any;
- dispatchmode bysize;
- connectiontimeout 600;
- verbosity on;
-
- backend a {
- server localhost:80;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_A;
- addclientheader "Set-Cookie: BalancerID=Backend_A; Path=/";
- }
-
- backend b {
- server localhost:80;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_B;
- addclientheader "Set-Cookie: BalancerID=Backend_B; Path=/";
- }
-
- backend c {
- server localhost:80;
- weight 3;
- decay 5;
- stickycookie BalancerID=Backend_C;
- addclientheader "Set-Cookie: BalancerID=Backend_C; Path=/";
- }
-}
diff --git a/test/t09.conf b/test/t09.conf
@@ -1,13 +0,0 @@
-#include t09a.inc
-
-service second {
- port 10001;
- backend one {
- server localhost:80;
- }
- backend two {
- server localhost:80;
- }
-}
-
-#include t09b.inc
diff --git a/test/t09a.inc b/test/t09a.inc
@@ -1,10 +0,0 @@
-service first {
- port 10000;
- backend one {
- server localhost:80;
- }
- backend two {
- server localhost:80;
- }
-}
-
diff --git a/test/t09b.inc b/test/t09b.inc
@@ -1,10 +0,0 @@
-service third {
- port 10002;
- backend one {
- server localhost:80;
- }
- backend two {
- server localhost:80;
- }
-}
-
-\ No newline at end of file
diff --git a/test/t10.conf b/test/t10.conf
@@ -1,40 +0,0 @@
-#define SERVICENAME test
-#define SERVICEPORT 10001
-#define BACKENDSERVER localhost
-#define BACKPORT 80
-
-service test {
- port SERVICEPORT;
- type http;
- bindto any;
- dispatchmode bysize;
- connectiontimeout 600;
- verbosity on;
-
- backend a {
- server BACKENDSERVER;
- port BACKPORT;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_A;
- addclientheader "Set-Cookie: BalancerID=Backend_A; Path=/";
- }
-
- backend b {
- server BACKENDSERVER:BACKPORT;
- port BACKPORT;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_B;
- addclientheader "Set-Cookie: BalancerID=Backend_B; Path=/";
- }
-
- backend c {
- server BACKENDSERVER;
- port BACKPORT;
- weight 3;
- decay 5;
- stickycookie BalancerID=Backend_C;
- addclientheader "Set-Cookie: BalancerID=Backend_C; Path=/";
- }
-}
diff --git a/test/t11.conf b/test/t11.conf
@@ -1,41 +0,0 @@
-#define SERVICENAME test
-#define SERVICEPORT 10001
-#define BACKENDSERVER localhost
-#define BACKPORT 80
-
-service test {
- port SERVICEPORT;
- type http;
- bindto any;
- dispatchmode bysize;
- connectiontimeout 600;
- verbosity on;
- checkinterval 5;
-
- backend a {
- server BACKENDSERVER;
- port BACKPORT;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_A;
- addclientheader "Set-Cookie: BalancerID=Backend_A; Path=/";
- }
-
- backend b {
- server BACKENDSERVER:BACKPORT;
- port BACKPORT;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_B;
- addclientheader "Set-Cookie: BalancerID=Backend_B; Path=/";
- }
-
- backend c {
- server BACKENDSERVER;
- port BACKPORT;
- weight 3;
- decay 5;
- stickycookie BalancerID=Backend_C;
- addclientheader "Set-Cookie: BalancerID=Backend_C; Path=/";
- }
-}
diff --git a/test/t12.conf b/test/t12.conf
@@ -1,41 +0,0 @@
-#define SERVICENAME test
-#define SERVICEPORT 10001
-#define BACKENDSERVER localhost
-#define BACKPORT 80
-
-service test {
- port SERVICEPORT;
- type http;
- bindto any;
- dispatchmode bysize;
- connectiontimeout 600;
- verbosity on;
- checkinterval 5 externalhandler "myscript";
-
- backend a {
- server BACKENDSERVER;
- port BACKPORT;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_A;
- addclientheader "Set-Cookie: BalancerID=Backend_A; Path=/";
- }
-
- backend b {
- server BACKENDSERVER:BACKPORT;
- port BACKPORT;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_B;
- addclientheader "Set-Cookie: BalancerID=Backend_B; Path=/";
- }
-
- backend c {
- server BACKENDSERVER;
- port BACKPORT;
- weight 3;
- decay 5;
- stickycookie BalancerID=Backend_C;
- addclientheader "Set-Cookie: BalancerID=Backend_C; Path=/";
- }
-}
diff --git a/test/t13.conf b/test/t13.conf
@@ -1,43 +0,0 @@
-#define SERVICENAME test
-#define SERVICEPORT 10001
-#define BACKENDSERVER localhost
-#define BACKPORT 80
-
-service test {
- port SERVICEPORT;
- type http;
- bindto any;
- dispatchmode bysize;
- connectiontimeout 600;
- verbosity on;
- checkinterval 5 externalhandler "myscript";
-
- backend a {
- server BACKENDSERVER;
- port BACKPORT;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_A;
- addclientheader "Set-Cookie: BalancerID=Backend_A; Path=/";
- state down;
- }
-
- backend b {
- server BACKENDSERVER:BACKPORT;
- port BACKPORT;
- weight 2;
- decay 5;
- stickycookie BalancerID=Backend_B;
- addclientheader "Set-Cookie: BalancerID=Backend_B; Path=/";
- state unavailable;
- }
-
- backend c {
- server BACKENDSERVER;
- port BACKPORT;
- weight 3;
- decay 5;
- stickycookie BalancerID=Backend_C;
- addclientheader "Set-Cookie: BalancerID=Backend_C; Path=/";
- }
-}
diff --git a/test/t14.conf b/test/t14.conf
@@ -1,42 +0,0 @@
-/* Example of a virtual server pool - see also virtpoolmgr */
-
-service vpool {
- port 80;
- dispatchmode byconnections;
- revivinginterval 3;
-
- /* Backend on localhost, always present */
- backend real {
- server localhost:8000;
- }
-
- /* The virtual pool: 30 on standby. The initial server setting
- * is but a dymmy, it will get set using virtpoolmgr */
- backend v00 { server localhost:8000; state down; }
- backend v02 { server localhost:8000; state down; }
- backend v03 { server localhost:8000; state down; }
- backend v04 { server localhost:8000; state down; }
- backend v05 { server localhost:8000; state down; }
- backend v06 { server localhost:8000; state down; }
- backend v07 { server localhost:8000; state down; }
- backend v08 { server localhost:8000; state down; }
- backend v09 { server localhost:8000; state down; }
- backend v10 { server localhost:8000; state down; }
- backend v12 { server localhost:8000; state down; }
- backend v13 { server localhost:8000; state down; }
- backend v14 { server localhost:8000; state down; }
- backend v15 { server localhost:8000; state down; }
- backend v16 { server localhost:8000; state down; }
- backend v17 { server localhost:8000; state down; }
- backend v18 { server localhost:8000; state down; }
- backend v19 { server localhost:8000; state down; }
- backend v20 { server localhost:8000; state down; }
- backend v22 { server localhost:8000; state down; }
- backend v23 { server localhost:8000; state down; }
- backend v24 { server localhost:8000; state down; }
- backend v25 { server localhost:8000; state down; }
- backend v26 { server localhost:8000; state down; }
- backend v27 { server localhost:8000; state down; }
- backend v28 { server localhost:8000; state down; }
- backend v29 { server localhost:8000; state down; }
-}
diff --git a/test/t15.conf b/test/t15.conf
@@ -1,14 +0,0 @@
-/*
- * Two service statements with same ports but different bindto's.
- */
-service one {
- port 80;
- bindto 1.2.3.4;
- backend one { server 10.1.1.1:80; }
-}
-
-service two {
- port 80;
- bindto 5.6.7.8;
- backend two { server 10.1.1.1:80; }
-}
diff --git a/test/t16.conf b/test/t16.conf
@@ -1,8 +0,0 @@
-/*
- * 'any' binding
- */
-service one {
- port 25000;
- bindto any;
- backend one { server 10.1.1.1:80; }
-}
diff --git a/test/t20.conf b/test/t20.conf
@@ -1,14 +0,0 @@
-/* Allow from test. Not used in the regression script, except that it must
- * pass parsing. */
-
-service ssh {
- port 2222;
- allowfrom 192.168.2.203 127/8;
- // denyfrom 127.0.0.1;
- verbose yes;
-
- backend a {
- server localhost:22;
- verbose yes;
- }
-}
diff --git a/test/virtpoolmgr b/test/virtpoolmgr
@@ -1,139 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-
-# Crossroads control package
-# --------------------------
-package Crossroads;
-
-# Instantiate object. Argument can be a Crossroads calling command, defaults
-# to plain 'crossroads'.
-sub new {
- my ($proto, $xrbin) = @_;
- my $self = {};
-
- # Get a snapshot of the state.
- $self->{xrbin} = $xrbin || "crossroads";
- my $cmd = $self->{xrbin} . ' -x status |';
- open (my $if, $cmd) or die ("Cannot run '$cmd'");
- my ($curservice, $curbackend,
- %service, %servicedata, %backend, %backenddata, @services, @backends);
- while (my $line = <$if>) {
- chomp ($line);
- my $tag = _xtag($line);
- if ($tag eq 'service') {
- $curservice = _xatt ($line, "name");
- push (@services, $curservice);
- @backends = ();
- %backenddata = ();
- } elsif ($tag eq 'connections') {
- if ($curbackend eq '') {
- $service{connections} = _xdata($line);
- } else {
- $backend{connections} = _xdata($line);
- }
- } elsif ($tag =~ /^backends_/) {
- $service{$tag} = _xdata($line);
- } elsif ($tag eq 'backend') {
- $curbackend = _xatt ($line, 'name');
- push (@backends, $curbackend);
- %backend = ();
- } elsif ($tag eq 'availability') {
- $backend{availability} = _xdata($line);
- $backend{availability_id} = _xatt($line, 'id');
- } elsif ($tag eq '/backend') {
- $backenddata{$curbackend} = \%backend;
- } elsif ($tag eq '/service') {
- $servicedata{$curservice} = [ \@backends, \%backenddata ];
- }
- }
-
- $self->{services} = \@services;
- $self->{servicedata} = \%servicedata;
-
- bless ($self, $proto);
- return ($self);
-}
-
-# Return array of available services.
-sub services {
- return ( @{ $_[0]->{services} } );
-}
-
-# Return back ends of a given service.
-sub backends {
- my %servicedata = %{ $_[0]->{servicedata} };
- my $data = $servicedata{$_[1]};
- return (undef) unless ($data);
- my ($backendsref, $backenddataref) = @{ $data };
- return (@{ $backendsref });
-}
-
-# Wrappers for back end details of a given service.
-sub availability { _backenddata(@_, 'availability'); }
-
-# Access stored data from XML document
-sub _backenddata {
- my ($self, $service, $backend, $detail) = @_;
- my %servicedata = %{ $self->{servicedata} } or return (undef);
- my $data = $servicedata{$service} or return (undef);
- my ($backendsref, $backenddataref) = @{ $data };
- my %backenddata = %{ $backenddataref } or return (undef);
- my %backenddetail = %{ $backenddata{$backend} } or return (undef);
- return ($backenddetail{$detail});
-}
-
-# Simple XML support functions. All classless!
-sub _xtag ($) {
- my $line = shift;
- for my $p (split (/[ <>]/, $line)) {
- if ($p ne '') {
- # print ("tag of $line: $p\n");
- return ($p);
- }
- }
- return (undef);
-}
-sub _xatt ($$) {
- my ($line, $att) = @_;
- my $ret = $line;
- $ret =~ s/.*$att=\"//;
- $ret =~ s/\".*//;
- # print ("att $att of $line: $ret\n");
- return ($ret);
-}
-sub _xdata ($) {
- my $line = shift;
- my $ret = $line;
- $ret =~ s/<\/.*//;
- $ret =~ s/.*>//;
- # print ("data of $line: $ret\n");
- return ($ret);
-}
-
-
-# Main programs is below here
-# ---------------------------
-
-package main;
-
-# Configuration:
-# --------------
-
-# What to call when requesting a pool worker. This program is expected
-# to output an IP address, a : and a port.
-my $getip = "/usr/local/src/crossroads/test/virtpoolhelper get";
-
-# What to call when returning (deactivating) a pool worker. This
-# program gets an IP address, a : and a port as its only argument.
-my $releaseip = "/usr/local/src/crossroads/test/virtpoolhelper release";
-
-print ("Start of run at ", scalar(localtime()), "\n");
-my $xr = new Crossroads ('crossroads -c /sw/src/crossroads/test/t14.conf');
-
-for my $s ($xr->services()) {
- print ("Service: $s\n");
- for my $b ($xr->backends ($s)) {
- print (" Back end: $b, ", $xr->availability ($s, $b), "\n");
- }
-}
diff --git a/tools/getkeywords b/tools/getkeywords
@@ -1,23 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-
-# Filter that reads parser.y and dumps the keywords on stdout.
-# Each keyword appears in tt(..) for Yodl.
-
-my $active = 0;
-while (my $line = <STDIN>) {
- chomp ($line);
- if ($active == 0 and $line =~ /Tokens/ and $line =~ /literal/) {
- $active++;
- } elsif ($line =~ /^\s*$/) {
- $active = 0;
- } elsif ($active) {
- for my $k (split /\s+/, $line) {
- next if ($k eq '' or $k =~ /%/);
- print ("tt(", lc($k), ")\n");
- }
- }
-}
-
-
diff --git a/tools/gettools b/tools/gettools
@@ -1,24 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-
-my $base = $0;
-$base =~ s{gettools$}{};
-$base = './' if ($base eq '');
-
-foreach my $f (@ARGV) {
- my $srcfound = 0;
- my ($src, $dst);
- foreach my $srcdir ("$ENV{EBASE}/bin", "$ENV{EBASE}/etc") {
- $src = "$srcdir/$f";
- next unless (-f $src);
- $dst = "$base/../tools/$f";
-
- if (! -f $dst or
- (stat($src))[9] > (stat($dst))[9]) {
- print ("gettools: $src -> $dst\n");
- system ("cp $src $dst") == 0
- or die ("gettools: copying of '$src' to '$dst' failed\n");
- }
- }
-}
diff --git a/tools/installdoc b/tools/installdoc
@@ -1,34 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-
-sub basename ($) {
- my $f = shift;
- $f =~ s{^.*/}{};
- return ($f);
-}
-
-die ("Usage: installdoc PREFIX MANFILES\n") if ($#ARGV < 1);
-my $prefix = shift (@ARGV);
-die ("Prefix directory '$prefix' not accessible\n") unless (-d $prefix);
-for my $f (@ARGV) {
- die ("Cannot see man page '$f' to install\n") unless (-f $f);
- my $targetdir = '';
- my $sect = $f;
- $sect =~ s{.*(\d)}{$1};
- for my $d ("$prefix/share/man", "$prefix/man") {
- if (-d "$d/man$sect") {
- $targetdir = "$d/man$sect";
- last;
- }
- }
- if ($targetdir eq '') {
- print STDERR ("No suitable man/ subdir found under $prefix,\n",
- "manual pages not installed\n");
- exit (0);
- }
- my $dest = "$targetdir/" . basename($f);
- next if (stat($dest) and (stat($dest))[9] >= (stat($f))[9]);
- print ("$f -> $dest\n");
- system ("cp $f $dest") and die ("Failed to copy $f to $dest\n");
-}
diff --git a/tools/makedist b/tools/makedist
@@ -1,44 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-
-sub run ($) {
- my $cmd = shift;
- print ("RUN> $cmd\n");
- system ($cmd) == 0
- or die ("Command [$cmd] failed\n");
-}
-
-my $ver = $ARGV[0]
- or die ("Version argument required.\n",
- "You can only run this from 'make dist'!\n");
-
-print ("Making crossroads distribution.. version is $ver\n");
-
-my $distdir = "/tmp/crossroads-$ver";
-if (-d $distdir) {
- print ("Removing old dist dir $distdir\n");
- run ("rm -rf $distdir");
-}
-print ("Preparing for distro (make documentation, make clean)\n");
-run ("make documentation");
-run ("make clean");
-mkdir ($distdir)
- or die ("Cannot makedir $distdir: $!\n");
-
-print ("Copying all...\n");
-run ("cp -r * $distdir");
-print ("Removing CVS entries in dist dir\n");
-run ("find $distdir -type d -name CVS -exec rm -rf {} \\; || true");
-print ("Removing SVN entries in dist dir\n");
-run ("find $distdir -type d -name .svn -exec rm -rf {} \\; || true");
-
-print ("Making archive...\n");
-chdir ("/tmp")
- or die ("Hm.. /tmp is gone\n");
-run ("tar czf crossroads-$ver.tar.gz crossroads-$ver");
-
-print ("----------------------------------------------------------\n",
- " Distro archive is now in /tmp/crossroads-$ver.tar.gz\n",
- "----------------------------------------------------------\n");
-
diff --git a/tools/patch-header b/tools/patch-header
@@ -1,87 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-
-sub diff ($$) {
- my ($a, $b) = @_;
-
- open (my $fa, $a) or die ("Cannot read $a: $!\n");
- open (my $fb, $b) or die ("Cannot read $b: $!\n");
-
- while (1) {
- my $la = <$fa>;
- my $lb = <$fb>;
-
- if (defined ($la)) {
- return (1)
- if ( (defined ($lb) and $la ne $lb) or
- (! defined ($lb)) );
- } else {
- return (1)
- if (defined ($lb));
- return (0);
- }
- }
-}
-
-die ("Usage: patch-header header-template version file(s)\n")
- if ($#ARGV < 2);
-my $hdrfile = shift (@ARGV);
-my $ver = shift (@ARGV);
-my ($header, $firstline, $lastline);
-open (my $if, $hdrfile)
- or die ("Can't read header file $hdrfile: $!\n");
-while (my $line = <$if>) {
- chomp ($line);
-
- $line =~ s/__VER__/$ver/g;
- $header .= "$line\n";
-
- $firstline = $line if ($firstline eq '');
- $lastline = $line if ($line ne '');
-}
-close ($if);
-
-for my $src (@ARGV) {
- my $dst = "$src.new";
- open (my $of, ">$dst")
- or die ("Can't write $dst: $!\n");
- print $of ($header);
-
- open (my $if, $src)
- or die ("Can't read $src: $!\n");
- my $state = 0;
- while (my $line = <$if>) {
- chomp ($line);
- # print ("Line: [$line], first: [$firstline], state: [$state]\n");
- if ($state == 2) {
- print $of ("$line\n");
- next;
- }
- if ($state == 0 and $line eq $firstline) {
- $state = 1;
- next;
- }
- if ($state == 1 and $line eq $lastline) {
- $state = 2;
- next;
- }
- if ($state == 0) {
- print $of ("$line\n");
- next;
- }
- }
- close ($of);
- close ($if);
-
- if (diff ($src, $dst)) {
- unlink ($src)
- or die ("Cannot unlink $src: $!\n");
- rename ($dst, $src)
- or die ("Cannot rename $dst to $src: $!\n");
- print ("patch-header: $ver $src\n");
- } else {
- unlink ($dst)
- or die ("Cannot unlink $dst: $!\n");
- }
-}
diff --git a/tools/patch-mgr b/tools/patch-mgr
@@ -1,30 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-
-die ("Usage: $0 <version> <xsltfile> <usageblock> <input >output\n")
- if ($#ARGV != 2);
-
-while (my $line = <STDIN>) {
- if ($line =~ /__XSLT__/) {
- open (my $if, $ARGV[1]) or die ("Cannot read $ARGV[1]: $!\n");
- while (my $x = <$if>) {
- $x =~ s/__VER__/$ARGV[0]/;
- print ($x);
- }
- } elsif ($line =~ /__USAGE__/) {
- open (my $if, $ARGV[2]) or die ("Cannot read $ARGV[2]: $!\n");
- while (my $x = <$if>) {
- $x =~ s/__VER__/$ARGV[0]/;
- print ($x);
- }
- } elsif ($line =~ /__WARNING__/) {
- print ("# Do not make changes in this file.\n",
- "# They will be overwritten in the next installation.\n",
- "# For changes, see crossroads-mgr.in in the Crossroads ",
- "source tree.\n");
- } else {
- $line =~ s/__VER__/$ARGV[0]/;
- print ($line);
- }
-}
diff --git a/tools/untab b/tools/untab
@@ -1,32 +0,0 @@
-#!/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");
- }
-}
-
diff --git a/xr/Makefile b/xr/Makefile
@@ -0,0 +1,42 @@
+
+# Configuration
+DIRS = $(shell find . -type d -mindepth 1 -maxdepth 1)
+BUILDDIR = build
+BIN = $(BUILDDIR)/xr
+LIB = $(BUILDDIR)/libxr.a
+CC = $(shell etc/c-conf -vc $(BUILDDIR)/config.cache c++-compiler)
+TMPXR = /tmp/xr-$(shell whoami)
+
+foo:
+ $(MAKE) subdirs
+ $(MAKE) $(BIN)
+
+install: $(BINDIR)/xr
+$(BINDIR)/xr: $(BUILDDIR)/xr
+ cp $(BUILDDIR)/xr $(TMPXR)
+ strip $(TMPXR)
+ install $(TMPXR) $(BINDIR)/xr
+ rm -f $(TMPXR)
+
+subdirs: $(BUILDDIR)/usage.h
+ @for f in $(DIRS) ; \
+ do \
+ echo "Making: $$f"; \
+ CC=$(CC) BUILDDIR=$(BUILDDIR) VER='$(VER)' \
+ AUTHOR='$(AUTHOR)' MAINTAINER='$(MAINTAINER)' \
+ $(MAKE) -C $$f -f ../etc/Makefile.class \
+ || exit 1; \
+ done
+ ar rs $(LIB) */*.o
+ ranlib $(LIB)
+$(BUILDDIR)/usage.h: etc/usage.txt
+ etc/e-txt2c USAGE <etc/usage.txt >$(BUILDDIR)/usage.h
+
+$(BIN): $(BUILDDIR)/libxr.a
+ $(CC) -g -o $(BIN) -L$(BUILDDIR) -lxr \
+ $(shell etc/c-conf -vc $(BUILDIR)/config.cache lib \
+ ucb nsl pthread socket m alf)
+
+clean:
+ rm -f $(BIN) $(LIB) core obj/*.o etc/usage.h $(BUILDDIR)/config.cache
+ find . -name \*.bak -exec rm {} \;
diff --git a/xr/algorithm/algorithm b/xr/algorithm/algorithm
@@ -0,0 +1,12 @@
+#ifndef _ALGORITHM_
+#define _ALGORITHM_
+
+#include "../thread/thread"
+
+class Algorithm: public Thread {
+public:
+ virtual ~Algorithm();
+ virtual int target() = 0;
+};
+
+#endif
diff --git a/xr/algorithm/algorithm.cc b/xr/algorithm/algorithm.cc
@@ -0,0 +1,4 @@
+#include "algorithm"
+
+Algorithm::~Algorithm() {
+}
diff --git a/xr/backend/available.cc b/xr/backend/available.cc
@@ -0,0 +1,7 @@
+#include "backend"
+
+bool Backend::available() const {
+ if (!maxconn())
+ return (islive);
+ return (islive && connections() < maxconn());
+}
diff --git a/xr/backend/availablestr.cc b/xr/backend/availablestr.cc
@@ -0,0 +1,5 @@
+#include "backend"
+
+string Backend::availablestr() const {
+ return (available() ? "available" : "unavailable");
+}
diff --git a/xr/backend/backend b/xr/backend/backend
@@ -0,0 +1,49 @@
+#ifndef _BACKEND_
+#define _BACKEND_
+
+#include "../sys/sys"
+#include "../backenddef/backenddef"
+#include "../fdset/fdset"
+#include "../error/error"
+
+using namespace std;
+
+class Backend {
+public:
+ Backend ();
+ Backend (BackendDef const &b);
+ virtual ~Backend();
+ bool connect();
+ void check();
+ string description() const;
+ bool available() const;
+ string availablestr() const;
+ string livestr() const;
+ void live (bool state);
+
+ bool live() const { return (islive); };
+ int sock() const { return (clsocket); }
+ string server() const { return (bdef.server()); }
+ int port() const { return (bdef.port()); }
+ unsigned maxconn() const { return (bdef.maxconn()); }
+ unsigned connections() const { return (nconn); }
+ void startconnection() { nconn++; totconn++; }
+ void endconnection() { nconn--; }
+ void addbytes (unsigned n) { bytes_served += n; }
+ double bytesserved() const { return (bytes_served); }
+ unsigned clientsserved() const { return (totconn); }
+
+ BackendDef const &backenddef() const {
+ return (bdef);
+ }
+
+private:
+ BackendDef bdef;
+ bool islive;
+ int clsocket;
+ unsigned nconn;
+ unsigned totconn;
+ double bytes_served;
+};
+
+#endif
diff --git a/xr/backend/backend1.cc b/xr/backend/backend1.cc
@@ -0,0 +1,5 @@
+#include "backend"
+
+Backend::Backend () :
+ islive(true), clsocket(-1), nconn(0), totconn(0), bytes_served(0) {
+}
diff --git a/xr/backend/backend2.cc b/xr/backend/backend2.cc
@@ -0,0 +1,5 @@
+#include "backend"
+
+Backend::Backend (BackendDef const &b) :
+ bdef(b), islive(true), clsocket(-1), nconn(0), totconn(0), bytes_served(0) {
+}
diff --git a/xr/backend/backend3.cc b/xr/backend/backend3.cc
@@ -0,0 +1,4 @@
+#include "backend"
+
+Backend::~Backend() {
+}
diff --git a/xr/backend/check.cc b/xr/backend/check.cc
@@ -0,0 +1,6 @@
+#include "backend"
+
+void Backend::check() {
+ connect();
+ close (clsocket);
+}
diff --git a/xr/backend/connect.cc b/xr/backend/connect.cc
@@ -0,0 +1,57 @@
+#include "backend"
+
+bool Backend::connect() {
+ // Assume the backend is dead
+ islive = false;
+
+ // Create client socket
+ if ( (clsocket = socket (PF_INET, SOCK_STREAM, 0)) < 0 )
+ throw ((Error)"Failed to create client socket: " + strerror(errno));
+
+ // Resolve hostname, prepare binding
+ struct hostent *hostaddr;
+ if (! (hostaddr = gethostbyname(bdef.server().c_str())) )
+ throw ((Error)"Failed to resolve backend host '" + bdef.server());
+ struct sockaddr_in backendaddr;
+ backendaddr.sin_family = AF_INET;
+ backendaddr.sin_port = htons(bdef.port());
+ memcpy ((char *) &backendaddr.sin_addr.s_addr,
+ hostaddr->h_addr_list[0], hostaddr->h_length);
+
+ // Client socket goes into nonblocking mode, so we can connect
+ // and enforce a timeout later.
+ int flags;
+ if ( (flags = fcntl (clsocket, F_GETFL, 0)) == -1 )
+ throw ((Error) "Failed to get fd flags: " + strerror(errno));
+ if (fcntl (clsocket, F_SETFL, flags | O_NONBLOCK) == -1)
+ throw ((Error) "Failed to fd in nonblocking mode: " + strerror(errno));
+
+ // Do the connect
+ int conres = ::connect (clsocket, (struct sockaddr *)&backendaddr,
+ sizeof(backendaddr));
+ int conerrno = errno;
+
+ // Put socket again in blocking mode.
+ if (fcntl (clsocket, F_SETFL, flags) == -1)
+ throw ((Error) "Failed to put fd in blocking mode: " +
+ strerror(errno));
+
+ // Check on the outcome of the connect
+ if (!conres || conerrno == EINPROGRESS) {
+ // Wait for socket to go writable.
+ Fdset fdset (config.backend_timeout());
+ fdset.add (clsocket);
+ if (fdset.readwriteable() == -1 && fdset.writeable() == clsocket)
+ islive = true;
+ }
+
+ /*
+ msg << "Back end " << bdef.server() << ":" << bdef.port();
+ if (islive)
+ msg << " is live on socket " << clsocket << "\n";
+ else
+ msg << " is NOT live\n";
+ */
+
+ return (islive);
+}
diff --git a/xr/backend/description.cc b/xr/backend/description.cc
@@ -0,0 +1,7 @@
+#include "backend"
+
+string Backend::description() const {
+ ostringstream o;
+ o << server() << ":" << port();
+ return (o.str());
+}
diff --git a/xr/backend/live.cc b/xr/backend/live.cc
@@ -0,0 +1,8 @@
+#include "backend"
+
+void Backend::live (bool state) {
+ bool oldstate = islive;
+ islive = state;
+ if (oldstate != state)
+ msg ("Marking back end " + description() + " as " + livestr() + "\n");
+}
diff --git a/xr/backend/livestr.cc b/xr/backend/livestr.cc
@@ -0,0 +1,5 @@
+#include "backend"
+
+string Backend::livestr() const {
+ return (live() ? "alive" : "dead");
+}
diff --git a/xr/backenddef/backenddef b/xr/backenddef/backenddef
@@ -0,0 +1,26 @@
+#ifndef _BACKENDDEF_
+#define _BACKENDDEF_
+
+#include "../sys/sys"
+#include "../error/error"
+
+using namespace std;
+
+class BackendDef {
+public:
+ BackendDef();
+ BackendDef (string s, string p, string m = "");
+
+ void server(string s) { srv = s; }
+ string server() const { return (srv); }
+ void port (int p) { prt = p; }
+ int port() const { return (prt); }
+ unsigned maxconn() const { return (max); }
+
+private:
+ string srv;
+ int prt;
+ unsigned max;
+};
+
+#endif
diff --git a/xr/backenddef/backenddef1.cc b/xr/backenddef/backenddef1.cc
@@ -0,0 +1,13 @@
+#include "backenddef"
+
+BackendDef::BackendDef (string server, string port, string maxclients) :
+ srv(server), prt(0), max(0) {
+
+ if (sscanf (port.c_str(), "%d", &prt) < 1)
+ throw ((Error) "Bad backend port specifier: '" + port +
+ "' is not a number");
+ if (maxclients.size() &&
+ sscanf (maxclients.c_str(), "%u", &max) < 1)
+ throw ((Error) "Bad maximum connections specifier: '" +
+ maxclients + "' is not a number");
+}
diff --git a/xr/backenddef/backenddef2.cc b/xr/backenddef/backenddef2.cc
@@ -0,0 +1,4 @@
+#include "backenddef"
+
+BackendDef::BackendDef () : srv(""), prt(-1) {
+}
diff --git a/xr/balancer/addbackend.cc b/xr/balancer/addbackend.cc
@@ -0,0 +1,7 @@
+#include "balancer"
+
+void Balancer::addbackend (BackendDef const &b) {
+ Backend newb (b);
+ backends.push_back (newb);
+ backends[backends.size() - 1].check();
+}
diff --git a/xr/balancer/balancer b/xr/balancer/balancer
@@ -0,0 +1,44 @@
+#ifndef _BALANCER_
+#define _BALANCER_
+
+#include "../sys/sys"
+
+#include "../backend/backend"
+#include "../backenddef/backenddef"
+#include "../config/config"
+#include "../wakeupthread/wakeupthread"
+#include "../checkupthread/checkupthread"
+#include "../fdset/fdset"
+#include "../error/error"
+
+using namespace std;
+
+class Balancer {
+public:
+ Balancer ();
+ void init();
+ void addbackend (BackendDef const &b);
+ void serve();
+
+ unsigned nbackends() { return (backends.size()); }
+ Backend &backend (unsigned i) { return (backends[i]); }
+ bool terminate() const { return (term); }
+ void terminate (bool t) { term = t; }
+ bool report() const { return (rep); }
+ void report (bool r) { rep = r; }
+
+ unsigned connections();
+
+private:
+ void init_tcp ();
+ void init_fd ();
+
+ int server_fd;
+ vector<Backend> backends;
+ bool term;
+ bool rep;
+};
+
+extern Balancer balancer;
+
+#endif
diff --git a/xr/balancer/balancer1.cc b/xr/balancer/balancer1.cc
@@ -0,0 +1,4 @@
+#include "balancer"
+
+Balancer::Balancer () : server_fd(-1), backends(), term(false), rep(false) {
+}
diff --git a/xr/balancer/connections.cc b/xr/balancer/connections.cc
@@ -0,0 +1,9 @@
+#include "balancer"
+
+unsigned Balancer::connections() {
+ unsigned ret = 0;
+
+ for (unsigned i = 0; i < nbackends(); i++)
+ ret += backend(i).connections();
+ return (ret);
+}
diff --git a/xr/balancer/init.cc b/xr/balancer/init.cc
@@ -0,0 +1,18 @@
+#include "balancer"
+
+void Balancer::init() {
+ // Set the listening socket.
+ if (config.sport())
+ server_fd = serversocket (config.sipaddr(), config.sport(),
+ "balancer");
+ else
+ server_fd = 0;
+
+ // Add workable back ends, display initial states.
+ for (int i = 0; i < config.backends(); i++)
+ addbackend (config.backend(i));
+
+ for (unsigned i = 0; i < nbackends(); i++)
+ msg ("Initial backend state: " + backend(i).description() + " is " +
+ backend(i).availablestr() + "\n");
+}
diff --git a/xr/balancer/serve.cc b/xr/balancer/serve.cc
@@ -0,0 +1,207 @@
+#include "balancer"
+#include "../tcpdispatcher/tcpdispatcher"
+#include "../httpdispatcher/httpdispatcher"
+
+void Balancer::serve() {
+ int clsock;
+
+ // Start up wakeup/checkup handlers.
+ if (config.wakeupsec() && !config.foregroundmode() && config.sport()) {
+ msg ("Starting wakeup thread.\n");
+ Wakeupthread *wt = new Wakeupthread();
+ wt->start();
+ }
+ if (config.checkupsec() && !config.foregroundmode() && config.sport()) {
+ msg ("Starting checkup thread.\n");
+ Checkupthread *ct = new Checkupthread();
+ ct->start();
+ }
+
+ // Write the PID file.
+ if (config.pidfile() != "") {
+ FILE *f;
+ if (! (f = fopen (config.pidfile().c_str(), "w")) )
+ throw ((Error) "Cannot write pid file " + config.pidfile() +
+ ": " + strerror(errno));
+ fprintf (f, "%u\n", getpid());
+ fclose (f);
+ }
+
+ // Wait for activity, serve it.
+ ostringstream o;
+ o << server_fd;
+ msg ("Awaiting activity on fd " + o.str() +"\n");
+ while (1) {
+ Fdset fdset(0);
+ fdset.add (server_fd);
+ if (fdset.readable() < 0) {
+ // We caught a signal. Either a request to report status,
+ // or to terminate.
+ msg ("Interrupt seen\n");
+ if (terminate()) {
+ msg ("Termination requested, XR will stop.\n");
+ close (server_fd);
+ shutdown (server_fd, SHUT_RDWR);
+ unsigned prev_conn = 0x19081962;
+ while (1) {
+ unsigned curr_conn = balancer.connections();
+ if (!curr_conn)
+ break;
+ if (curr_conn != prev_conn) {
+ ostringstream o;
+ o << curr_conn;
+ msg ("There are still " + o.str() + " connections\n");
+ prev_conn = curr_conn;
+ }
+ sleep (1);
+ }
+ msg ("XR is idle, stopping.\n");
+ break;
+ } else if (report()) {
+ msg ("Report requested\n");
+ reportmsg ("*** XR STATUS REPORT STARTS ***\n");
+ for (unsigned i = 0; i < nbackends(); i++) {
+ reportmsg ("Back end " + backend(i).description() + ":\n");
+ reportmsg (" Status: " + backend(i).availablestr() +
+ ", " + backend(i).livestr() + "\n");
+ ostringstream o;
+ o << backend(i).connections() << " (max "
+ << backend(i).maxconn() << ")";
+ reportmsg (" Connections: " + o.str() + "\n");
+ ostringstream b;
+ b << backend(i).bytesserved() << " bytes, "
+ << backend(i).clientsserved() << " clients";
+ reportmsg (" Served: " + b.str() + "\n");
+ }
+ report (false);
+ reportmsg ("*** XR STATUS REPORT ENDS ***\n");
+ continue;
+ } else {
+ msg ("Non-meaningful interrupt, resuming\n");
+ continue;
+ }
+ }
+
+ if (server_fd) {
+ // If tcp-serving: server_fd > 0; serve and loop again
+ int size;
+ struct sockaddr_in clname;
+
+ size = sizeof(clname);
+ if ( (clsock = accept (server_fd, (struct sockaddr *) &clname,
+ (socklen_t*) &size)) < 0 )
+ throw ((Error)"Failed to accept network connection");
+
+ string clientip = inet_ntoa(clname.sin_addr);
+
+ // If there is an allow list, the client must match it.
+ if (config.nallow()) {
+ debugmsg ("Matching " + clientip + " against allow list\n");
+ bool allowed = false;
+ for (unsigned n = 0; n < config.nallow(); n++) {
+ if (ipmatch (clname.sin_addr, config.allow(n))) {
+ allowed = true;
+ break;
+ }
+ }
+ if (!allowed) {
+ msg ("Not serving client " + clientip +
+ ": no match in allow list\n");
+ close (clsock);
+ continue;
+ }
+ }
+ // If the client is in the deny list, deny it.
+ debugmsg ("Matching " + clientip + " against deny list\n");
+ bool denied = false;
+ for (unsigned n = 0; n < config.ndeny(); n++)
+ if (ipmatch (clname.sin_addr, config.deny(n))) {
+ denied = true;
+ break;
+ }
+ if (denied) {
+ msg ("Not serving client " + clientip +
+ ": match in deny list\n");
+ close (clsock);
+ continue;
+ }
+
+ // Show whom we've accepted
+ if (config.verbose()) {
+ ostringstream o;
+ o << clsock;
+ msg ("Accepted connection from " + clientip +
+ " as client fd " + o.str() +"\n");
+ msg ("Current back end states:\n");
+ for (unsigned i = 0; i < nbackends(); i++) {
+ ostringstream status;
+ status << backend(i).connections() << " connections";
+ if (backend(i).maxconn())
+ status << " (max " << backend(i).maxconn() << ")";
+ status << ", status " << backend(i).availablestr();
+ msg ("Back end " + backend(i).description() + ": " +
+ status.str() + "\n");
+ ostringstream n;
+ n << connections();
+ msg ("Balancer is serving " + n.str() + " clients\n");
+ }
+ }
+
+ // We got action! Check if the total connections to the
+ // balancer doesn't exceed the max.
+ if (config.maxconn() && connections() >= config.maxconn()) {
+ ostringstream o;
+ o << connections() << " connections (max "
+ << config.maxconn() << ")";
+ msg ("Not serving client: already " + o.str() + "\n");
+ close (clsock);
+ continue;
+ }
+
+ TcpDispatcher *d;
+ switch (config.stype()) {
+ case Servertype::t_tcp:
+ d = new TcpDispatcher (clsock, clientip);
+ break;
+ case Servertype::t_http:
+ d = new HttpDispatcher (clsock, clientip);
+ break;
+ default:
+ throw ((Error) "Internal error, can't choose dispatcher");
+ break;
+ }
+
+ // Allocation boundary printout
+ if (config.debug()) {
+ void *mem = malloc(16);
+ free (mem);
+ ostringstream o;
+ o << mem;
+ debugmsg ("Allocation boundary at dispatcher start: " +
+ o.str() + "\n");
+ }
+
+ d->start();
+ } else {
+ // If fd-serving, serve and close. Don't thread it up.
+ TcpDispatcher *d;
+ switch (config.stype()) {
+ case Servertype::t_tcp:
+ d = new TcpDispatcher (server_fd, "0.0.0.0");
+ break;
+ case Servertype::t_http:
+ d = new HttpDispatcher (server_fd, "0.0.0.0");
+ break;
+ default:
+ throw ((Error) "Internal error, can't choose dispatcher");
+ break;
+ }
+ d->execute();
+ break;
+ }
+ }
+
+ // If a PID stamp was created, remove it now.
+ if (config.pidfile() != "")
+ unlink (config.pidfile().c_str());
+}
diff --git a/xr/buffer/add.cc b/xr/buffer/add.cc
@@ -0,0 +1,12 @@
+#include "buffer"
+
+void Buffer::add (char const *b, unsigned len) {
+ if (!buf_data)
+ set (b, len);
+ else {
+ if (! (buf_data = (char*)realloc (buf_data, buf_len + len)) )
+ throw ((Error) "Memory fault in Buffer::add");
+ memcpy (buf_data + buf_len, b, len);
+ buf_len += len;
+ }
+}
diff --git a/xr/buffer/buffer b/xr/buffer/buffer
@@ -0,0 +1,34 @@
+#ifndef _BUFFER_
+#define _BUFFER_
+
+#include "../error/error"
+
+class Buffer {
+public:
+ Buffer();
+ Buffer(Buffer const &other);
+ ~Buffer();
+
+ Buffer &operator= (Buffer const &other);
+ Buffer &operator= (char const *b);
+
+ void set (char const *b, unsigned len);
+ void add (char const *b, unsigned len);
+ unsigned size() const;
+ char const *data() const;
+ char charat (unsigned index) const;
+ char &operator[] (unsigned index);
+ string stringat (unsigned index, unsigned len) const;
+ void removeat (unsigned index, unsigned len = 1);
+ void insertat (unsigned index, char const *s, unsigned len);
+ void insertat (unsigned index, string s);
+
+private:
+ void copy (Buffer const &other);
+ void destroy();
+
+ char *buf_data;
+ unsigned buf_len;
+};
+
+#endif
diff --git a/xr/buffer/buffer1.cc b/xr/buffer/buffer1.cc
@@ -0,0 +1,4 @@
+#include "buffer"
+
+Buffer::Buffer(): buf_data(0), buf_len(0) {
+}
diff --git a/xr/buffer/buffer2.cc b/xr/buffer/buffer2.cc
@@ -0,0 +1,5 @@
+#include "buffer"
+
+Buffer::Buffer (Buffer const &other): buf_data(0), buf_len(0){
+ copy(other);
+}
diff --git a/xr/buffer/buffer3.cc b/xr/buffer/buffer3.cc
@@ -0,0 +1,5 @@
+#include "buffer"
+
+Buffer::~Buffer() {
+ destroy();
+}
diff --git a/xr/buffer/charat.cc b/xr/buffer/charat.cc
@@ -0,0 +1,7 @@
+#include "buffer"
+
+char Buffer::charat (unsigned index) const {
+ if (index >= buf_len)
+ return (0);
+ return (buf_data[index]);
+}
diff --git a/xr/buffer/copy.cc b/xr/buffer/copy.cc
@@ -0,0 +1,13 @@
+#include "buffer"
+
+void Buffer::copy (Buffer const &other) {
+ if (! other.buf_len) {
+ buf_data = 0;
+ buf_len = 0;
+ } else {
+ if (! (buf_data = (char*)malloc (other.buf_len)) )
+ throw ((Error) "Memory fault in Buffer::copy");
+ memcpy (buf_data, other.buf_data, other.buf_len);
+ buf_len = other.buf_len;
+ }
+}
diff --git a/xr/buffer/data.cc b/xr/buffer/data.cc
@@ -0,0 +1,5 @@
+#include "buffer"
+
+char const *Buffer::data() const {
+ return (buf_data);
+}
diff --git a/xr/buffer/destroy.cc b/xr/buffer/destroy.cc
@@ -0,0 +1,7 @@
+#include "buffer"
+
+void Buffer::destroy() {
+ free (buf_data);
+ buf_data = 0;
+ buf_len = 0;
+}
diff --git a/xr/buffer/insertat1.cc b/xr/buffer/insertat1.cc
@@ -0,0 +1,5 @@
+#include "buffer"
+
+void Buffer::insertat (unsigned index, string s) {
+ insertat (index, s.c_str(), s.size());
+}
diff --git a/xr/buffer/insertat2.cc b/xr/buffer/insertat2.cc
@@ -0,0 +1,13 @@
+#include "buffer"
+
+void Buffer::insertat (unsigned index, char const *s, unsigned len) {
+ if (index >= buf_len)
+ return;
+ if (! (buf_data = (char*)realloc (buf_data, buf_len + len)) )
+ throw ((Error) "Memory fault in Buffer::insertat");
+ memmove (buf_data + index + len,
+ buf_data + index,
+ buf_len - index);
+ memcpy (buf_data + index, s, len);
+ buf_len += len;
+}
diff --git a/xr/buffer/oparray.cc b/xr/buffer/oparray.cc
@@ -0,0 +1,9 @@
+#include "buffer"
+
+char &Buffer::operator[] (unsigned index) {
+ static char dummy = 0;
+
+ if (index >= buf_len)
+ return (dummy);
+ return (buf_data[index]);
+}
diff --git a/xr/buffer/opequal.cc b/xr/buffer/opequal.cc
@@ -0,0 +1,9 @@
+#include "buffer"
+
+Buffer &Buffer::operator= (Buffer const &other) {
+ if (this != &other) {
+ destroy();
+ copy (other);
+ }
+ return (*this);
+}
diff --git a/xr/buffer/removeat.cc b/xr/buffer/removeat.cc
@@ -0,0 +1,14 @@
+#include "buffer"
+
+void Buffer::removeat (unsigned index, unsigned len) {
+ if (!buf_data || index >= buf_len)
+ return;
+ if (index + len >= buf_len) {
+ buf_len = index;
+ return;
+ }
+ memcpy (buf_data + index, buf_data + index + len,
+ buf_len - index - len);
+ buf_len -= len;
+}
+
diff --git a/xr/buffer/set.cc b/xr/buffer/set.cc
@@ -0,0 +1,9 @@
+#include "buffer"
+
+void Buffer::set (char const *b, unsigned len) {
+ destroy();
+ if (! (buf_data = (char*)malloc (len)) )
+ throw ((Error) "Memory fault in Buffer::set");
+ memcpy (buf_data, b, len);
+ buf_len = len;
+}
diff --git a/xr/buffer/size.cc b/xr/buffer/size.cc
@@ -0,0 +1,5 @@
+#include "buffer"
+
+unsigned Buffer::size() const {
+ return (buf_len);
+}
diff --git a/xr/buffer/stringat.cc b/xr/buffer/stringat.cc
@@ -0,0 +1,14 @@
+#include "buffer"
+
+string Buffer::stringat (unsigned index, unsigned len) const {
+ string ret;
+
+ for (unsigned int i = index; i < index + len; i++) {
+ char ch = charat(i);
+ if (!ch)
+ break;
+ ret += ch;
+ }
+
+ return (ret);
+}
diff --git a/xr/checkupthread/checkupthread b/xr/checkupthread/checkupthread
@@ -0,0 +1,14 @@
+#ifndef _CHECKUPTHREAD_
+#define _CHECKUPTHREAD_
+
+#include "../sys/sys"
+#include "../thread/thread"
+#include "../balancer/balancer"
+#include "../error/error"
+
+class Checkupthread: public Thread {
+public:
+ void execute();
+};
+
+#endif
diff --git a/xr/checkupthread/execute.cc b/xr/checkupthread/execute.cc
@@ -0,0 +1,23 @@
+#include "checkupthread"
+
+void Checkupthread::execute() {
+ while (1) {
+ for (unsigned i = 0; i < balancer.nbackends(); i++) {
+ Backend target(balancer.backend(i).backenddef());
+ target.check();
+ if (! balancer.backend(i).live() &&
+ target.live() ) {
+ balancer.backend(i).live(true);
+ msg ("Checkup call: backend " + target.description() +
+ " has awoken\n");
+ } else if (balancer.backend(i).live() &&
+ ! target.live()) {
+ balancer.backend(i).live(false);
+ msg ("Checkup call: backend " + target.description() +
+ " has gone asleep\n");
+ }
+ }
+ sleep (config.checkupsec());
+ }
+}
+
diff --git a/xr/config/Makefile.lib b/xr/config/Makefile.lib
@@ -0,0 +1,2 @@
+DIR = config
+include ../etc/Makefile.lib
diff --git a/xr/config/addallow.cc b/xr/config/addallow.cc
@@ -0,0 +1,8 @@
+#include "config"
+
+void Config::addallow (string a) {
+ struct in_addr in;
+ if (!inet_aton (a.c_str(), &in))
+ throw ((Error) "Bad allow-from specfier '" + a + "'");
+ allowlist.push_back (in);
+}
diff --git a/xr/config/adddeny.cc b/xr/config/adddeny.cc
@@ -0,0 +1,8 @@
+#include "config"
+
+void Config::adddeny (string d) {
+ struct in_addr in;
+ if (!inet_aton (d.c_str(), &in))
+ throw ((Error) "Bad deny-from specfier '" + d + "'");
+ denylist.push_back (in);
+}
diff --git a/xr/config/config b/xr/config/config
@@ -0,0 +1,97 @@
+#ifndef _CMDLINE_
+#define _CMDLINE_
+
+#include "../sys/sys"
+#include "../backenddef/backenddef"
+#include "../servertype/servertype"
+#include "../dispatchmode/dispatchmode"
+#include "../error/error"
+
+using namespace std;
+
+class Config {
+public:
+ Config ();
+
+ // Init by cmdline
+ void parsecmdline (int ac, char **av);
+
+ // Accessors
+ bool verbose() const { return (verbose_flag); }
+ Servertype::Type stype() const { return (styp.type()); }
+ string sipaddr() const { return (sip); }
+ int sport() const { return (lport); }
+ int backends() const { return (blist.size()); }
+ int client_timeout() const { return (c_timeout); }
+ int backend_timeout() const { return (b_timeout); }
+ int wakeupsec() const { return (wakeup); }
+ int checkupsec() const { return (checkup); }
+ unsigned buffersize() const { return (bufsize); }
+ void buffersize (unsigned b) { bufsize = b; }
+ bool foregroundmode() const { return (foreground_mode); }
+ bool addxrversion() const { return (add_xr_version); }
+ bool debug() const { return (debug_flag); }
+ bool addxforwardedfor() const { return (add_x_forwarded_for); }
+ bool stickyhttp() const { return (sticky_http); }
+ unsigned maxconn() const { return (max_conn); }
+ string externalalgorithm() const { return (external_algorithm); }
+ string pidfile() const { return (pid_file); }
+ void pidfile (string p) { pid_file = p; }
+ bool prefixtimestamp() const { return (prefix_timestamp); }
+ void prefixtimestamp (bool p) { prefix_timestamp = p; }
+ void addserverheader (string s) { serverheaders.push_back(s); }
+ unsigned nserverheaders() const { return (serverheaders.size()); }
+ string serverheader (unsigned n) { return (serverheaders[n]); }
+ unsigned nallow() const { return (allowlist.size()); }
+ unsigned ndeny() const { return (denylist.size()); }
+
+ struct in_addr allow(unsigned n) const {
+ return (allowlist[n]);
+ }
+ struct in_addr deny(unsigned n) const {
+ return (denylist[n]);
+ }
+
+ BackendDef const &backend (int i) const {
+ return (blist[i]);
+ }
+ Dispatchmode::Mode dispatchmode() const {
+ return (dmode.mode());
+ }
+
+private:
+ void setbackend (string s);
+ void setserver (string s);
+ void setdispatchmode (string s);
+ int setinteger (string s) const;
+ void addallow (string a);
+ void adddeny (string d);
+
+ static bool verbose_flag;
+ static int lport;
+ static Servertype styp;
+ static string sip;
+ static vector<BackendDef> blist;
+ static Dispatchmode dmode;
+ static int c_timeout;
+ static int b_timeout;
+ static int wakeup;
+ static int checkup;
+ static unsigned bufsize;
+ static bool foreground_mode;
+ static bool add_xr_version;
+ static bool debug_flag;
+ static bool add_x_forwarded_for;
+ static bool sticky_http;
+ static unsigned max_conn;
+ static string external_algorithm;
+ static string pid_file;
+ static bool prefix_timestamp;
+ static vector<string> serverheaders;
+ static vector<struct in_addr> allowlist;
+ static vector<struct in_addr> denylist;
+};
+
+extern Config config;
+
+#endif
diff --git a/xr/config/config1.cc b/xr/config/config1.cc
@@ -0,0 +1,28 @@
+#include "config"
+
+bool Config::verbose_flag = false;
+int Config::lport = 10000;
+Servertype Config::styp;
+string Config::sip = "0";
+vector<BackendDef> Config::blist;
+Dispatchmode Config::dmode;
+int Config::c_timeout = 30;
+int Config::b_timeout = 30;
+int Config::wakeup = 5;
+int Config::checkup = 0;
+unsigned Config::bufsize = 2048;
+bool Config::foreground_mode = false;
+bool Config::add_xr_version = false;
+bool Config::debug_flag = false;
+bool Config::add_x_forwarded_for = false;
+bool Config::sticky_http = false;
+unsigned Config::max_conn = 0;
+string Config::external_algorithm = "";
+string Config::pid_file = "";
+bool Config::prefix_timestamp = false;
+vector<string> Config::serverheaders;
+vector<struct in_addr> Config::allowlist;
+vector<struct in_addr> Config::denylist;
+
+Config::Config () {
+}
diff --git a/xr/config/parsecmdline.cc b/xr/config/parsecmdline.cc
@@ -0,0 +1,141 @@
+#include "config"
+#include "../build/usage.h"
+
+using namespace std;
+
+void Config::parsecmdline (int ac, char **av) {
+ // Prepare invoking command line.
+ string cmdline;
+ for (int i = 0; i < ac; i++) {
+ if (i)
+ cmdline += ' ';
+ cmdline += av[i];
+ }
+ // Not a single argument? Usage.
+ if (ac == 1)
+ throw ((Error) "Bad command line '" + cmdline + "'\n" + USAGE);
+
+ static struct option longopts[] = {
+ { "allow-from", required_argument, 0, 'a' },
+ { "deny-from", required_argument, 0, 'A' },
+ { "backend", required_argument, 0, 'b' },
+ { "buffer-size", required_argument, 0, 'B' },
+ { "checkup-interval", required_argument, 0, 'c' },
+ { "debug", no_argument, 0, 'D' },
+ { "dispatch-mode", required_argument, 0, 'd' },
+ { "foreground", no_argument, 0, 'f' },
+ { "help", no_argument, 0, 'h' },
+ { "add-server-header", required_argument, 0, 'H' },
+ { "max-connections", required_argument, 0, 'm' },
+ { "prefix-timestamp", no_argument, 0, 'P' },
+ { "pidfile", required_argument, 0, 'p' },
+ { "server", required_argument, 0, 's' },
+ { "sticky-http", no_argument, 0, 'S' },
+ { "backend-timeout", required_argument, 0, 't' },
+ { "client-timeout", required_argument, 0, 'T' },
+ { "verbose", no_argument, 0, 'v' },
+ { "version", no_argument, 0, 'V' },
+ { "wakeup-interval", required_argument, 0, 'w' },
+ { "add-xr-version", no_argument, 0, 'X' },
+ { "add-x-forwarded-for", no_argument, 0, 'x' },
+ { 0, 0, 0, 0 }
+ };
+
+ int opt;
+ bool backend_set = false;
+ while ( (opt = getopt_long (ac, av, "?a:A:B:b:c:Dd:fhH:m:p:Ss:t:T:vVw:xX",
+ longopts, 0)) > 0) {
+ switch (opt) {
+ case 'a':
+ addallow (optarg);
+ break;
+ case 'A':
+ adddeny (optarg);
+ break;
+ case 'b':
+ setbackend (optarg);
+ backend_set = true;
+ break;
+ case 'B':
+ bufsize = (unsigned)setinteger (optarg);
+ break;
+ case 'c':
+ checkup = setinteger (optarg);
+ break;
+ case 'D':
+ verbose_flag = true;
+ debug_flag = true;
+ break;
+ case 'd':
+ setdispatchmode (optarg);
+ break;
+ case 'f':
+ foreground_mode = true;
+ break;
+ case 'h':
+ throw ((Error) USAGE);
+ break;
+ case 'H':
+ addserverheader (optarg);
+ break;
+ case 'm':
+ max_conn = (unsigned)setinteger (optarg);
+ break;
+ case 'P':
+ prefix_timestamp = true;
+ break;
+ case 'p':
+ pid_file = optarg;
+ break;
+ case 's':
+ setserver (optarg);
+ break;
+ case 'S':
+ sticky_http = true;
+ break;
+ case 't':
+ b_timeout = setinteger (optarg);
+ break;
+ case 'T':
+ c_timeout = setinteger (optarg);
+ break;
+ case 'v':
+ verbose_flag = true;
+ break;
+ case 'V':
+ cout << "This is XR V" << VER << "\n"
+ << "Written by: " << AUTHOR << "\n"
+ << "Maintained by: " << MAINTAINER << "\n"
+ << "Please report bugs to the maintainer.\n";
+ exit (0);
+ case 'w':
+ wakeup = setinteger (optarg);
+ break;
+ case 'X':
+ add_xr_version = true;
+ break;
+ case 'x':
+ add_x_forwarded_for = true;
+ break;
+ default:
+ throw ((Error) "Unknown flag, try 'xr -h' for usage");
+ break;
+ }
+ }
+
+ if (ac != optind)
+ throw ((Error) "Bad command line '" + cmdline + "'\n" + USAGE);
+
+ if (!backend_set)
+ throw ((Error)
+ "No backend defined, use '-b...' at least once, "
+ "or try 'xr -h' for usage");
+
+ msg ("+--------------------------------------------+\n");
+ msg ("| Welcome to xr V" VER " |\n");
+ msg ("| Copyright (c) Karel Kubat <karel@kubat.nl> |\n");
+ msg ("| Distributed under GPLV3. |\n");
+ msg ("+--------------------------------------------+\n");
+
+ msg ("Invoking command line: '" + cmdline + "'\n");
+}
diff --git a/xr/config/setbackend.cc b/xr/config/setbackend.cc
@@ -0,0 +1,23 @@
+#include "config"
+
+void Config::setbackend (string str) {
+ vector<string> parts;
+ int pos;
+ while ( (pos = str.find_first_of(":")) > 0) {
+ if (pos > 0)
+ parts.push_back (str.substr(0, pos));
+ str = str.substr(pos + 1);
+ }
+ if (str.length() > 0)
+ parts.push_back (str);
+ if (parts.size() < 2 || parts.size() > 3)
+ throw((Error) "Bad back end specifier in '-b" + str +
+ "', expected: SERVER:PORT or SERVER:PORT:MAXCONNECTIONS");
+ if (parts.size() == 2) {
+ BackendDef bd (parts[0], parts[1]);
+ blist.push_back (bd);
+ } else {
+ BackendDef bd (parts[0], parts[1], parts[2]);
+ blist.push_back (bd);
+ }
+}
diff --git a/xr/config/setdispatcmode.cc b/xr/config/setdispatcmode.cc
@@ -0,0 +1,23 @@
+#include "config"
+
+void Config::setdispatchmode (string s) {
+ if (s == "r" || s == "round-robin")
+ dmode.mode (Dispatchmode::m_roundrobin);
+ else if (s == "l" || s == "least-connections")
+ dmode.mode (Dispatchmode::m_leastconn);
+ else if (s == "f" || s == "first-available")
+ dmode.mode (Dispatchmode::m_firstactive);
+ else if (s.substr(0, 2) == "e:") {
+ dmode.mode (Dispatchmode::m_external);
+ external_algorithm = s.substr (2);
+ } else if (s.substr (0, 9) == "external:") {
+ dmode.mode (Dispatchmode::m_external);
+ external_algorithm = s.substr(9);
+ }
+ else
+ throw ((Error) "Bad dispatch mode -d" + s);
+
+ if (dmode.mode() == Dispatchmode::m_external &&
+ external_algorithm.size() < 1)
+ throw ((Error) "External algorithm handler missing");
+}
diff --git a/xr/config/setinteger.cc b/xr/config/setinteger.cc
@@ -0,0 +1,9 @@
+#include "config"
+
+int Config::setinteger (string s) const {
+ int ret;
+ if (sscanf (s.c_str(), "%d", &ret) < 1)
+ throw ((Error) "Bad numeric specifier in '" + s +
+ ": not a number");
+ return (ret);
+}
diff --git a/xr/config/setserver.cc b/xr/config/setserver.cc
@@ -0,0 +1,21 @@
+#include "config"
+
+void Config::setserver (string str) {
+ // Split into 3 parts
+ vector<string> parts;
+ int pos;
+ while ( (pos = str.find_first_of(":")) > 0) {
+ if (pos > 0)
+ parts.push_back (str.substr(0, pos));
+ str = str.substr(pos + 1);
+ }
+ if (str.length() > 0)
+ parts.push_back (str);
+ if (parts.size() != 3)
+ throw((Error) "Bad server specifier, expected: TYPE:IPADDRESS:PORT");
+
+ // Store type, IP and port
+ styp.type (parts[0]);
+ sip = parts[1];
+ lport = setinteger (parts[2]);
+}
diff --git a/xr/dispatchmode/dispatchmode b/xr/dispatchmode/dispatchmode
@@ -0,0 +1,28 @@
+#ifndef _DISPATCHMODE_
+#define _DISPATCHMODE_
+
+#include "../sys/sys"
+
+using namespace std;
+
+class Dispatchmode {
+public:
+
+ enum Mode {
+ m_leastconn,
+ m_roundrobin,
+ m_firstactive,
+ m_external,
+ };
+
+ Dispatchmode() : mymode(m_leastconn) {
+ }
+
+ void mode (Mode m) { mymode = m; }
+ Mode mode() const { return (mymode); }
+
+private:
+ Mode mymode;
+};
+
+#endif
diff --git a/xr/error/error b/xr/error/error
@@ -0,0 +1,21 @@
+#ifndef _ERROR_
+#define _ERROR_
+
+#include "../sys/sys"
+
+using namespace std;
+
+class Error {
+public:
+ Error (string s);
+ Error (int i);
+ Error &operator+ (Error const &other);
+ Error &operator+ (string const s);
+ Error &operator+ (int i);
+ string txt() const;
+
+private:
+ string desc;
+};
+
+#endif
diff --git a/xr/error/error1.cc b/xr/error/error1.cc
@@ -0,0 +1,4 @@
+#include "error"
+
+Error::Error (string s): desc(s) {
+}
diff --git a/xr/error/error2.cc b/xr/error/error2.cc
@@ -0,0 +1,7 @@
+#include "error"
+
+Error::Error (int i) {
+ ostringstream o;
+ o << i;
+ desc = o.str();
+}
diff --git a/xr/error/opplus1.cc b/xr/error/opplus1.cc
@@ -0,0 +1,6 @@
+#include "error"
+
+Error &Error::operator+ (Error const &other) {
+ desc += other.desc;
+ return (*this);
+}
diff --git a/xr/error/opplus2.cc b/xr/error/opplus2.cc
@@ -0,0 +1,6 @@
+#include "error"
+
+Error &Error::operator+ (string s) {
+ desc += s;
+ return (*this);
+}
diff --git a/xr/error/opplus3.cc b/xr/error/opplus3.cc
@@ -0,0 +1,10 @@
+#include "error"
+
+Error &Error::operator+ (int i) {
+ ostringstream o;
+
+ o << i;
+ desc += o.str();
+
+ return (*this);
+}
diff --git a/xr/error/txt.cc b/xr/error/txt.cc
@@ -0,0 +1,10 @@
+#include "error"
+#include "../config/config"
+
+string Error::txt() const {
+ ostringstream o;
+ if (config.prefixtimestamp())
+ o << timestamp() << ' ';
+ o << pthread_self() << " ERROR: " << desc;
+ return (o.str());
+}
diff --git a/xr/etc/Makefile.class b/xr/etc/Makefile.class
@@ -0,0 +1,9 @@
+SRC = $(wildcard *.cc)
+OBJ = $(patsubst %.cc, ../$(BUILDDIR)/$(DIR)_%.o, $(SRC))
+DIR = $(shell pwd | sed 's:.*/::')
+
+class-compile: $(OBJ)
+
+../$(BUILDDIR)/$(DIR)_%.o: %.cc
+ $(CC) -DVER='"$(VER)"' -DAUTHOR='"$(AUTHOR)"' \
+ -DMAINTAINER='"$(MAINTAINER)"' -c -g -Wall -o $@ $<
diff --git a/tools/c-conf b/xr/etc/c-conf
diff --git a/tools/e-txt2c b/xr/etc/e-txt2c
diff --git a/tools/e-ver b/xr/etc/e-ver
diff --git a/xr/etc/firstav.pl b/xr/etc/firstav.pl
@@ -0,0 +1,21 @@
+# firstav.pl - sample "first available" dispatching algorithm,
+# implemented as an external Perl program
+
+#!/usr/bin/perl
+
+use strict;
+
+print STDERR ("firstav.pl: Invocation: @ARGV\n");
+my $n = shift (@ARGV);
+for my $i (0..$n - 1) {
+ my $addr = shift (@ARGV);
+ my $av = shift (@ARGV);
+ my $conn = shift (@ARGV);
+ print STDERR ("firstav.pl: $i: backend at $addr, $av, $conn connections\n");
+ if ($av eq 'available') {
+ print ("$i\n");
+ exit (0);
+ }
+}
+print STDERR ("firstav.pl: Nothing available!\n");
+exit (1);
diff --git a/xr/etc/gettools b/xr/etc/gettools
@@ -0,0 +1,26 @@
+#!/usr/bin/perl
+
+use strict;
+
+die ("Usage: gettools SRCDIR DSTDIR TOOL [TOOL...]\n")
+ if ($#ARGV < 2);
+
+my $srcdir = shift (@ARGV);
+die ("gettools: source dir $srcdir not found\n") unless (-d $srcdir);
+my $dstdir = shift (@ARGV);
+die ("gettools: dest dir $dstdir not found\n") unless (-d $dstdir);
+for my $t (@ARGV) {
+ gettool ($srcdir, $dstdir, $t);
+}
+
+sub gettool ($$$) {
+ my ($sd, $dd, $t) = @_;
+ my $src = "$sd/$t";
+ return unless (-f $src);
+ my $dst = "$dd/$t";
+
+ if (! -f $dst or
+ (stat($src))[9] > (stat($dst))[9]) {
+ system ("cp '$src' '$dst'") and die ("gettools: cp failed\n");
+ }
+}
diff --git a/xr/etc/usage.txt b/xr/etc/usage.txt
@@ -0,0 +1,76 @@
+
+This is XR, a load balancer and failover utility for TCP/HTTP services.
+Usage: xr [flags], where the flags may be:
+ -a MASK, --allow-from MASK
+ Allow only clients that match MASK. MASK is e.g. 192.168.255.255, which
+ would allow the class B network 192.168.*.*
+ -A MASK, --deny-from MASK
+ Deny clients that match MASK.
+ -b ADDRESS:PORT[:MAX], --backend ADDRESS:PORT[:MAX]
+ Specifies a back end, use multiple -b... to specify several back ends.
+ At least one -b... must be given. Specifier MAX is optional: when given,
+ defines the maximum connections for the back end.
+ -b SIZE, --buffer-size SIZE
+ Sets the network buffer size, default is 2048 (in bytes)
+ -c SEC, --checkup-interval SEC
+ Defines the back end checking period. Each SEC seconds, every back end
+ is checked whether it is alive. Default is 0 (off).
+ -D, --debug
+ Sets debugging on, more verbosity on top of -v
+ -d METHOD, --dispatch-mode METHOD
+ Defines how to dispatch over back ends, the method may be:
+ r, round-robin - back ends take turns
+ l, least-connections - back end with least TCP connections is taken
+ f, first-active - first live back end gets all traffic
+ e:EXT, external:EXT - external program EXT is queried
+ Default method is l (least-connections). When external mode is selected,
+ program EXT is started with arguments <nbackends> <b0> <b0-availability>
+ <b0-connections> (b0 repeated for all back ends). Here <b0> is the back
+ end definition, eg. "10.1.1.1:80"; <b0-availablility> is "available" or
+ "unavailable", <b0-connections> is the nr. of connections. The program
+ must reply with a back end number (0..max) on stdout.
+ -f, --foreground
+ Suppresses forking/threading, useful for debugging. Also suppresses
+ wakeup (-w) and checkup (-c) threads.
+ -h, -?, --help
+ This text.
+ -H HDR, --add-server-header HDR
+ Inserts HDR into back end bound HTTP messages.
+ -m MAX, --max-connections MAX
+ Sets the maximum number of connections to the balancer. Default is 0,
+ no maximum.
+ -P, --prefix-timestamp
+ Messages (verbose, debug, error etc.) are prefixed with a time stamp.
+ -p FILE, --pidfile FILE
+ FILE is written with the PID of XR upon startup
+ -S, --sticky-http
+ Enables sticky HTTP sessions by injecting XRTarget cookies into HTTP
+ streams. Only effective with -s http:....
+ -s TYPE:IPADDRESS:PORT, --server TYPE:IPADDRESS:PORT
+ Specifies the server. TYPE is tcp or http. IPADDRESS is the IP address
+ to listen to. PORT defines the TCP port to listen (for type tcp or
+ http); when port is 0, XR will listen to stdin (inetd-mode).
+ Default: tcp:0:10000 (TCP balancing, on all interfaces, via port 10000).
+ -t SEC, --backend-timeout SEC
+ Defines network timeouts for back ends, default 3 sec. Use 0 to
+ prevent timing out.
+ -T SEC, --client-timeout SEC
+ Defines network timeouts for clients, default 30 sec. Use 0 to
+ prevent timing out.
+ -v, --verbose
+ Increases verbosity, default is silent operation.
+ -V, --version
+ Shows the version info, and author/maintainer contacts (for reporting
+ bugs).
+ -w SEC, --wakeup-interval SEC
+ Defines wakeup period (rechecking) in seconds, of unavailable back
+ ends. Default is 5. Use -w0 to suppress.
+ -X, --add-xr-version
+ Adds an XR version header to client and back end streams in HTTP
+ messages.
+ -x, --add-x-forwarded-for
+ Adds X-Forwarded-For with external IP address to back end streams in
+ HTTP messages.
+XR's messages are sent to stderr. Invoke XR daemons using something like
+"xr -b ... [other flags] 2>&1 | logger &", or use xrctl.
+
diff --git a/xr/etc/xr-test b/xr/etc/xr-test
@@ -0,0 +1,36 @@
+#!/usr/bin/perl
+
+use strict;
+use LWP::UserAgent;
+use Time::HiRes qw(sleep gettimeofday tv_interval);
+
+die ("Usage: $0 URL TRIALS\n") if ($#ARGV != 1);
+$|++;
+
+my $n = 0;
+my $totaltime = 0;
+
+my $ua = LWP::UserAgent->new();
+$ua->timeout(5);
+while ($n < $ARGV[1]) {
+ my $success = 0;
+ for my $i (1..10) {
+ my $t0 = [ gettimeofday() ];
+ my $resp = $ua->get($ARGV[0]);
+ if ($resp->is_success()) {
+ $success++;
+ $n++;
+ $totaltime += tv_interval ($t0);
+ last;
+ }
+ if ($i == 3) {
+ die ($resp->status_line(), "\n");
+ }
+ sleep (1);
+ }
+ sleep (0.1);
+ printf ("\rN: %5d Tot:%8.3g Avg:%8.3g", $n, $totaltime, $totaltime / $n)
+ if (! ($n % 50));
+}
+
+print ("\n");
diff --git a/xr/external/external b/xr/external/external
@@ -0,0 +1,14 @@
+#ifndef _EXTERNAL_
+#define _EXTERNAL_
+
+#include "../sys/sys"
+#include "../error/error"
+#include "../algorithm/algorithm"
+#include "../balancer/balancer"
+#include "../config/config"
+
+class External: public Algorithm {
+ int target();
+};
+
+#endif
diff --git a/xr/external/target.cc b/xr/external/target.cc
@@ -0,0 +1,33 @@
+#include "external"
+
+int External::target() {
+ // Prepare command to run
+ ostringstream o;
+ o << config.externalalgorithm() << ' ' << balancer.nbackends();
+ for (unsigned i = 0; i < balancer.nbackends(); i++)
+ o << ' ' << balancer.backend(i).description() << ' '
+ << balancer.backend(i).availablestr()
+ << ' ' << balancer.backend(i).connections();
+ msg ("External algorithm: invoking '" + o.str() + "'\n");
+
+ FILE *f;
+ if (! (f = popen (o.str().c_str(), "r")) )
+ throw ((Error) "Cannot start '" + o.str() + "': " + strerror(errno));
+ int i;
+ if (fscanf (f, "%d", &i) < 1)
+ throw ((Error) "External algorithm '" + o.str() + "' did not reply "
+ "with a number");
+
+ ostringstream n;
+ n << i;
+ msg ("External algorithm says: " + n.str() + "\n");
+
+ if (i < 0 || i >= (int)balancer.nbackends())
+ throw ((Error) "External algorithm '" + o.str() + "': answer " +
+ n.str() + " out of bounds");
+ if (pclose (f))
+ throw ((Error) "External algorithm '" + o.str() + "' terminated "
+ "with error");
+
+ return (i);
+}
diff --git a/xr/fdset/fdset b/xr/fdset/fdset
@@ -0,0 +1,40 @@
+#ifndef _FDSET_
+#define _FDSET_
+
+#include "../sys/sys"
+#include "../error/error"
+#include "../config/config"
+
+using namespace std;
+
+class Fdset {
+public:
+ Fdset(int t);
+
+ int timeout() const {
+ return (tsec);
+ }
+ void timeout (int t) {
+ tsec = t;
+ }
+ void add (int fd) {
+ set.push_back(fd);
+ }
+ unsigned size() const {
+ return (set.size());
+ }
+ int fd (unsigned index) const {
+ return (set[index]);
+ }
+
+ int readable() const;
+ int writeable() const;
+ int readwriteable() const;
+
+
+private:
+ int tsec;
+ vector<int> set;
+};
+
+#endif
diff --git a/xr/fdset/fdset1.cc b/xr/fdset/fdset1.cc
@@ -0,0 +1,4 @@
+#include "fdset"
+
+Fdset::Fdset (int t) : tsec(t), set() {
+}
diff --git a/xr/fdset/readable.cc b/xr/fdset/readable.cc
@@ -0,0 +1,57 @@
+#include "fdset"
+
+int Fdset::readable() const {
+ fd_set readset, exceptset;
+ struct timeval tv, *tvp;
+
+ // No fd's? Nothing is readable.
+ if (set.size() < 1)
+ return (-1);
+
+ // Prepare select sets.
+ FD_ZERO (&readset);
+ FD_ZERO (&exceptset);
+ for (unsigned i = 0; i < set.size(); i++) {
+ FD_SET (set[i], &readset);
+ FD_SET (set[i], &exceptset);
+ }
+
+ // Prepare timout specifier.
+ if (tsec) {
+ tv.tv_sec = tsec;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ } else
+ tvp = 0;
+
+ // Run the select. Signal interrupts are returned as -1, so that
+ // the caller can handle them gracefully.
+ if (select (FD_SETSIZE, &readset, 0, &exceptset, tvp) < 0) {
+ if (errno != EINTR)
+ throw ((Error) "Select failure: "
+ "failed to wait for readable state: " + strerror(errno));
+ else
+ return (-1);
+ }
+
+ // Check for exceptions.
+ for (unsigned i = 0; i < set.size(); i++)
+ if (FD_ISSET (set[i], &exceptset))
+ throw ((Error) "Exception on fd/socket " + set[i]);
+
+ // Check what's readable.
+ for (unsigned i = 0; i < set.size(); i++)
+ if (FD_ISSET (set[i], &readset)) {
+ if (config.debug()) {
+ ostringstream o;
+ o << set[i];
+ debugmsg ("Fd " + o.str() + " has become readable\n");
+ }
+ return (set[i]);
+ }
+
+ // Nothing..
+ debugmsg ("No readable fd's at this time\n");
+ return (-1);
+}
+
diff --git a/xr/fdset/readwriteable.cc b/xr/fdset/readwriteable.cc
@@ -0,0 +1,46 @@
+#include "fdset"
+
+int Fdset::readwriteable() const {
+ fd_set readset, writeset, exceptset;
+ struct timeval tv, *tvp;
+
+ // No fd's? Nothing is readable.
+ if (set.size() < 1)
+ return (-1);
+
+ // Prepare select sets.
+ FD_ZERO (&readset);
+ FD_ZERO (&writeset);
+ FD_ZERO (&exceptset);
+ for (unsigned i = 0; i < set.size(); i++) {
+ FD_SET (set[i], &readset);
+ FD_SET (set[i], &writeset);
+ FD_SET (set[i], &exceptset);
+ }
+
+ // Prepare timout specifier.
+ if (tsec) {
+ tv.tv_sec = tsec;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ } else
+ tvp = 0;
+
+ // Run the select.
+ if (select (FD_SETSIZE, &readset, &writeset, &exceptset, tvp) < 0)
+ throw ((Error) "Select failure: failed to wait for rw state");
+
+ // Check for exceptions.
+ for (unsigned i = 0; i < set.size(); i++)
+ if (FD_ISSET (set[i], &exceptset))
+ throw ((Error) "Exception on fd/socket " + set[i]);
+
+ // Check what's active.
+ for (unsigned i = 0; i < set.size(); i++)
+ if (FD_ISSET (set[i], &readset) && FD_ISSET (set[i], &writeset))
+ return (set[i]);
+
+ // Nothing..
+ return (-1);
+}
+
diff --git a/xr/fdset/writeable.cc b/xr/fdset/writeable.cc
@@ -0,0 +1,51 @@
+#include "fdset"
+
+int Fdset::writeable() const {
+ fd_set writeset, exceptset;
+ struct timeval tv, *tvp;
+
+ // No fd's? Nothing is writeable.
+ if (set.size() < 1)
+ return (-1);
+
+ // Prepare select sets.
+ FD_ZERO (&writeset);
+ FD_ZERO (&exceptset);
+ for (unsigned i = 0; i < set.size(); i++) {
+ FD_SET (set[i], &writeset);
+ FD_SET (set[i], &exceptset);
+ }
+
+ // Prepare timout specifier.
+ if (tsec) {
+ tv.tv_sec = tsec;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ } else
+ tvp = 0;
+
+ // Run the select.
+ if (select (FD_SETSIZE, 0, &writeset, &exceptset, tvp) < 0)
+ throw ((Error) "Select failure: failed to wait for writable state");
+
+ // Check for exceptions.
+ for (unsigned i = 0; i < set.size(); i++)
+ if (FD_ISSET (set[i], &exceptset))
+ throw ((Error) "Exception on fd/socket " + set[i]);
+
+ // Check what's writeable.
+ for (unsigned i = 0; i < set.size(); i++)
+ if (FD_ISSET (set[i], &writeset)) {
+ if (config.debug()) {
+ ostringstream o;
+ o << set[i];
+ debugmsg ("Fd " + o.str() + " has become writeable\n");
+ }
+ return (set[i]);
+ }
+
+ // Nothing..
+ debugmsg ("No writeable fd's at this time\n");
+ return (-1);
+}
+
diff --git a/xr/firstactive/firstactive b/xr/firstactive/firstactive
@@ -0,0 +1,13 @@
+#ifndef _FIRSTACTIVE_
+#define _FIRSTACTIVE_
+
+#include "../sys/sys"
+#include "../error/error"
+#include "../algorithm/algorithm"
+#include "../balancer/balancer"
+
+class Firstactive: public Algorithm {
+ int target();
+};
+
+#endif
diff --git a/xr/firstactive/target.cc b/xr/firstactive/target.cc
@@ -0,0 +1,9 @@
+#include "firstactive"
+
+int Firstactive::target() {
+ for (unsigned i = 0; i < balancer.nbackends(); i++)
+ if (balancer.backend(i).available())
+ return ( (int) i);
+ throw ((Error) "First-active algorithm: no available back ends");
+}
+
diff --git a/xr/httpbuffer/addheader.cc b/xr/httpbuffer/addheader.cc
@@ -0,0 +1,10 @@
+#include "httpbuffer"
+
+void Httpbuffer::addheader (string var, string val) {
+ string old = headerval(var);
+ if (old.size()) {
+ old += ", " + val;
+ setheader(var, old);
+ } else
+ setheader (var, val);
+}
diff --git a/xr/httpbuffer/addheader1.cc b/xr/httpbuffer/addheader1.cc
@@ -0,0 +1,14 @@
+#include "httpbuffer"
+
+void Httpbuffer::addheader (string h) {
+ unsigned i;
+ for (i = 0; i < h.size(); i++)
+ if (h[i] == ':') {
+ string var = h.substr(0, i);
+ i++;
+ while (isspace(h[i]))
+ i++;
+ string val = h.substr(i);
+ addheader (var, val);
+ }
+}
diff --git a/xr/httpbuffer/bodyreceived.cc b/xr/httpbuffer/bodyreceived.cc
@@ -0,0 +1,46 @@
+#include "httpbuffer"
+
+static bool ishex (char ch) {
+ return (ch >= '0' && ch <= '9' ||
+ ch >= 'a' && ch <= 'f' ||
+ ch >= 'A' && ch <= 'F');
+}
+
+Httpbuffer::Bodystatus Httpbuffer::bodyreceived() {
+ // No headers? Not done.
+ if (!headersdone())
+ return (b_is_not_received);
+
+ // If we have a content length, the body must match it.
+ string str = headerval("Content-Length");
+ unsigned clen;
+ if (sscanf (str.c_str(), "%d", &clen) > 0) {
+ if (size() - bodystart >= clen)
+ return (b_is_received);
+ else
+ return (b_is_not_received);
+ }
+
+ // If we have chunks, then the last chunk must be zero.
+ str = headerval ("Transfer-Encoding");
+ if (!strcasecmp (str.c_str(), "chunked")) {
+ for (unsigned i = bodystart; i < size(); /* increment below */ ) {
+ unsigned chunk;
+ if (sscanf (data() + i, "%x", &chunk) < 1)
+ return (b_is_not_received);
+ if (!chunk)
+ return (b_is_received);
+ while (ishex(charat(i)) && i < size())
+ i++;
+ if (charat(i) == '\r')
+ i++;
+ if (charat(i) == '\n')
+ i++;
+ i += chunk;
+ }
+ }
+
+ // No content length, no chunks... We just dunno.
+ return (b_unknown);
+}
+
diff --git a/xr/httpbuffer/cookievalue.cc b/xr/httpbuffer/cookievalue.cc
@@ -0,0 +1,17 @@
+#include "httpbuffer"
+
+string Httpbuffer::cookievalue (string c) {
+ string cval = headerval ("Cookie");
+ size_t pos;
+ string ret = "";
+ if ( (pos = cval.find (c)) != string::npos) {
+ pos++;
+ pos += c.size();
+ for (char ch = cval[pos];
+ pos < cval.size() && ch != ';' && ch != ',' && ch;
+ ch = cval[++pos]) {
+ ret += ch;
+ }
+ }
+ return (ret);
+}
diff --git a/xr/httpbuffer/findheader.cc b/xr/httpbuffer/findheader.cc
@@ -0,0 +1,25 @@
+#include "httpbuffer"
+
+unsigned Httpbuffer::findheader(string h) {
+ if (!headersdone())
+ return (0);
+
+ for (unsigned int i = 0; i < bodystart - h.size(); ) {
+ // At header?
+ if (stringat(i, h.size()) == h)
+ return (i);
+ // No, advance beyond next \n
+ while (1) {
+ char ch = charat(i);
+ if (!ch)
+ return (0);
+ if (ch == '\n') {
+ i++;
+ break;
+ }
+ i++;
+ }
+ }
+
+ return (0);
+}
diff --git a/xr/httpbuffer/firstline.cc b/xr/httpbuffer/firstline.cc
@@ -0,0 +1,12 @@
+#include "httpbuffer"
+
+string Httpbuffer::firstline() const {
+ string ret;
+ for (unsigned i = 0; i < size(); i++) {
+ char ch = charat(i);
+ if (ch == '\n' || ch == '\r')
+ break;
+ ret += ch;
+ }
+ return (ret);
+}
diff --git a/xr/httpbuffer/headersdone.cc b/xr/httpbuffer/headersdone.cc
@@ -0,0 +1,22 @@
+#include "httpbuffer"
+
+bool Httpbuffer::headersdone() {
+ if (bodystart)
+ return (true);
+
+ bool prevnl = false;
+ for (unsigned i = 0; i < size(); i++) {
+ if (charat(i) == '\n') {
+ if (prevnl) {
+ bodystart = i + 1;
+ return (true);
+ }
+ prevnl = true;
+ } else {
+ if (charat(i) != '\r')
+ prevnl = false;
+ }
+ }
+
+ return (false);
+}
diff --git a/xr/httpbuffer/headerval.cc b/xr/httpbuffer/headerval.cc
@@ -0,0 +1,26 @@
+#include "httpbuffer"
+
+string Httpbuffer::headerval (string var) {
+ string ret;
+
+ if (!headersdone())
+ return ("");
+
+ if (var[var.size() - 1] != ':')
+ var += ":";
+
+ unsigned int start;
+ if (! (start = findheader(var)) )
+ ret = "";
+ else {
+ start += var.size();
+ for (char ch = charat(start); ch && isspace(ch); ch = charat(++start))
+ ;
+ for (char ch = charat(start); ch && ch != '\r' && ch != '\n';
+ ch = charat(++start))
+ ret += ch;
+ }
+
+ debugmsg ("Header " + var + " '" + ret + "'\n");
+ return (ret);
+}
diff --git a/xr/httpbuffer/httpbuffer b/xr/httpbuffer/httpbuffer
@@ -0,0 +1,32 @@
+#ifndef _HTTPBUFFER_
+#define _HTTPBUFFER_
+
+#include "../sys/sys"
+#include "../buffer/buffer"
+#include "../config/config"
+
+class Httpbuffer: public Buffer {
+public:
+ enum Bodystatus {
+ b_is_received,
+ b_is_not_received,
+ b_unknown,
+ };
+
+ Httpbuffer();
+ bool headersdone();
+ string headerval (string var);
+ Bodystatus bodyreceived();
+ string firstline() const;
+ bool setversion(string v);
+ void setheader (string var, string val);
+ void addheader (string var, string val);
+ void addheader (string h);
+ string cookievalue (string var);
+
+private:
+ unsigned findheader (string h);
+ unsigned bodystart;
+};
+
+#endif
diff --git a/xr/httpbuffer/httpbuffer1.cc b/xr/httpbuffer/httpbuffer1.cc
@@ -0,0 +1,4 @@
+#include "httpbuffer"
+
+Httpbuffer::Httpbuffer(): bodystart(0) {
+}
diff --git a/xr/httpbuffer/setheader.cc b/xr/httpbuffer/setheader.cc
@@ -0,0 +1,26 @@
+#include "httpbuffer"
+
+void Httpbuffer::setheader (string var, string val) {
+ if (!bodystart)
+ return;
+ if (var[var.size() - 1] != ':')
+ var += ':';
+
+ unsigned i;
+ if (! (i = findheader (var)) ) {
+ while (charat(i) && charat(i) != '\n')
+ i++;
+ i++;
+ insertat (i, var + " " + val + "\r\n");
+ } else {
+ i += var.size();
+ while (isspace(charat(i)))
+ i++;
+ unsigned len = i;
+ while (charat(len) && charat(len) != '\r' && charat(len) != '\n')
+ len++;
+ len -= i;
+ removeat (i, len);
+ insertat (i, val);
+ }
+}
diff --git a/xr/httpbuffer/setversion.cc b/xr/httpbuffer/setversion.cc
@@ -0,0 +1,20 @@
+#include "httpbuffer"
+
+bool Httpbuffer::setversion (string v) {
+ if (!headersdone())
+ return (false);
+
+ // Find "HTTP/" in the first line. Add the version there.
+ for (unsigned int i = 0; ; i++) {
+ if (charat(i) == '\r' || charat(i) == '\n')
+ return (false);
+ if (stringat(i, 5) == "HTTP/") {
+ i ++;
+ while (charat(i) != '\n' && charat(i) != '\r')
+ removeat(i);
+ insertat(i, v);
+ }
+ return (true);
+ }
+ return (false);
+}
diff --git a/xr/httpdispatcher/dispatch.cc b/xr/httpdispatcher/dispatch.cc
@@ -0,0 +1,38 @@
+#include "httpdispatcher"
+
+void HttpDispatcher::dispatch() {
+ unsigned stickytarget;
+
+ // Get the client's request. May need for cookie inspection.
+ if (!getclientrequest())
+ throw ((Error) "Didn't receive a valid client request.\n");
+
+ // Dispatch as a normal backend if sticky HTTP is off, or if the
+ // sticky target is badly specified.
+ if (!config.stickyhttp() ||
+ sscanf (clientrequest.cookievalue ("XRTarget").c_str(),
+ "%d", &stickytarget) < 1 ||
+ stickytarget >= balancer.nbackends()) {
+ issticky(false);
+ TcpDispatcher::dispatch();
+ } else {
+ // Got a sticky target. Try to connect. If that fails, fallback
+ // to non-sticky dispatching.
+ targetbackend(stickytarget);
+ Backend tb = balancer.backend(stickytarget);
+ msg ("Sticky HTTP request for " + tb.description() + "\n");
+ if (! tb.connect()) {
+ lock();
+ balancer.backend(stickytarget).live(false);
+ unlock();
+ msg ("Failed to connect to back end " + tb.description() +
+ ", trying to dispatch to other\n");
+ issticky(false);
+ TcpDispatcher::dispatch();
+ } else {
+ backendfd(tb.sock());
+ issticky(true);
+ }
+ }
+}
+
diff --git a/xr/httpdispatcher/getclientrequest.cc b/xr/httpdispatcher/getclientrequest.cc
@@ -0,0 +1,16 @@
+#include "httpdispatcher"
+
+bool HttpDispatcher::getclientrequest() {
+ do {
+ Fdset set (config.client_timeout());
+ set.add (clientfd());
+ int s;
+ if ( (s = set.readable()) < 0 || !readchunk(clientfd()) )
+ return (false);
+ clientrequest.add (databuf(), databufsize());
+ } while (clientrequest.bodyreceived() == Httpbuffer::b_is_not_received);
+
+ msg ("Received client request: '" + clientrequest.firstline() + "'\n");
+ return (true);
+}
+
diff --git a/xr/httpdispatcher/getserverresponse.cc b/xr/httpdispatcher/getserverresponse.cc
@@ -0,0 +1,17 @@
+#include "httpdispatcher"
+
+bool HttpDispatcher::getserverresponse() {
+ msg ("Reading back end response.\n");
+
+ do {
+ Fdset set (config.backend_timeout());
+ set.add (backendfd());
+ int s;
+ if ( (s = set.readable() < 0) || !readchunk(backendfd()) )
+ return (false);
+ serverresponse.add (databuf(), databufsize());
+ } while (! serverresponse.headersdone());
+
+ msg ("Received back end response: '" + serverresponse.firstline() + "'\n");
+ return (true);
+}
diff --git a/xr/httpdispatcher/handle.cc b/xr/httpdispatcher/handle.cc
@@ -0,0 +1,45 @@
+#include "httpdispatcher"
+
+void HttpDispatcher::handle() {
+
+ // The client request was already retrieved before starting the
+ // dispatcher. We can continue by applying server-directed headers.
+ clientrequest.setversion("1.0");
+ clientrequest.setheader ("Connection", "close");
+ clientrequest.setheader ("Proxy-Connection", "close");
+
+ // Apply other server-side directed info
+ if (config.addxrversion())
+ clientrequest.setheader ("XR", VER);
+ if (config.addxforwardedfor())
+ clientrequest.addheader ("X-Forwarded-For", clientip());
+ for (unsigned n = 0; n < config.nserverheaders(); n++)
+ clientrequest.addheader (config.serverheader(n));
+
+ // Send to server
+ if (!sendclientrequest() ) {
+ msg ("Failed to send client request to back end, not processing\n");
+ return;
+ }
+
+ // Get server's response
+ if (!getserverresponse()) {
+ msg ("Failed to receive a valid back end response, not processing\n");
+ return;
+ }
+
+ // Apply client-side directed info. Smuggle in stickiness if required.
+ if (config.addxrversion())
+ serverresponse.setheader ("XR", VER);
+ if (config.stickyhttp() && !issticky()) {
+ ostringstream o;
+ o << targetbackend();
+ serverresponse.setheader ("Set-Cookie", "XRTarget=" + o.str());
+ }
+
+ // Flush server buffer to the client
+ writechunk (clientfd(), serverresponse.data(), serverresponse.size());
+
+ // Then switch to the TCP copy/thru protocol.
+ TcpDispatcher::handle();
+}
diff --git a/xr/httpdispatcher/httpdispatcher b/xr/httpdispatcher/httpdispatcher
@@ -0,0 +1,28 @@
+#ifndef _HTTPDISPATCHER_
+#define _HTTPDISPATCHER_
+
+#include "../sys/sys"
+#include "../tcpdispatcher/tcpdispatcher"
+#include "../httpbuffer/httpbuffer"
+
+class HttpDispatcher: public TcpDispatcher {
+public:
+ HttpDispatcher (int fd, string ip);
+
+ void dispatch();
+ void handle();
+ bool issticky() const { return (is_sticky); }
+ void issticky (bool s) { is_sticky = s; }
+
+private:
+private:
+ bool getclientrequest();
+ bool sendclientrequest();
+ bool getserverresponse();
+ bool sendserverresponse();
+
+ Httpbuffer clientrequest, serverresponse;
+ bool is_sticky;
+};
+
+#endif
diff --git a/xr/httpdispatcher/httpdispatcher1.cc b/xr/httpdispatcher/httpdispatcher1.cc
@@ -0,0 +1,5 @@
+#include "httpdispatcher"
+
+HttpDispatcher::HttpDispatcher (int fd, string ip) :
+ TcpDispatcher (fd, ip), clientrequest(), serverresponse() {
+}
diff --git a/xr/httpdispatcher/sendclientrequest.cc b/xr/httpdispatcher/sendclientrequest.cc
@@ -0,0 +1,10 @@
+#include "httpdispatcher"
+
+bool HttpDispatcher::sendclientrequest() {
+ Fdset set (config.backend_timeout());
+ set.add (backendfd());
+ return ( (set.writeable() == backendfd()) &&
+ (writechunk (backendfd(),
+ clientrequest.data(), clientrequest.size()) ==
+ clientrequest.size()) );
+}
diff --git a/xr/httpdispatcher/sendserverresponse.cc b/xr/httpdispatcher/sendserverresponse.cc
@@ -0,0 +1,12 @@
+#include "httpdispatcher"
+
+bool HttpDispatcher::sendserverresponse() {
+ msg ("Sending server response '" + serverresponse.firstline() +
+ "' to client.\n");
+ Fdset set (config.client_timeout());
+ set.add (clientfd());
+ return ( (set.writeable() == clientfd()) &&
+ (writechunk (clientfd(),
+ serverresponse.data(), serverresponse.size()) ==
+ serverresponse.size()) );
+}
diff --git a/xr/leastconn/leastconn b/xr/leastconn/leastconn
@@ -0,0 +1,13 @@
+#ifndef _LEASTCONN_
+#define _LEASTCONN_
+
+#include "../sys/sys"
+#include "../error/error"
+#include "../algorithm/algorithm"
+#include "../balancer/balancer"
+
+class Leastconn: public Algorithm {
+ int target();
+};
+
+#endif
diff --git a/xr/leastconn/target.cc b/xr/leastconn/target.cc
@@ -0,0 +1,23 @@
+#include "leastconn"
+
+int Leastconn::target() {
+ bool found = false;
+ unsigned nconn;
+ int t;
+
+ for (unsigned i = 0; i < balancer.nbackends(); i++) {
+ if (!balancer.backend(i).available())
+ continue;
+ if (!found ||
+ balancer.backend(i).connections() < nconn) {
+ nconn = balancer.backend(i).connections();
+ t = i;
+ found = true;
+ }
+ }
+
+ if (!found)
+ throw ((Error) "Least-connections algorithm: "
+ "no available back ends");
+ return (t);
+}
diff --git a/xr/roundrobin/roundrobin b/xr/roundrobin/roundrobin
@@ -0,0 +1,13 @@
+#ifndef _ROUNDROBIN_
+#define _ROUNDROBIN_
+
+#include "../sys/sys"
+#include "../error/error"
+#include "../algorithm/algorithm"
+#include "../balancer/balancer"
+
+class Roundrobin: public Algorithm {
+ int target();
+};
+
+#endif
diff --git a/xr/roundrobin/target.cc b/xr/roundrobin/target.cc
@@ -0,0 +1,26 @@
+#include "roundrobin"
+
+int Roundrobin::target() {
+ static int last = -1;
+ int t = last + 1;
+
+ if (last == -1) {
+ lock();
+ last = 0;
+ unlock();
+ }
+
+ while (1) {
+ if (balancer.backend(t).available()) {
+ lock();
+ last = t;
+ unlock();
+ return (t);
+ }
+ t++;
+ t %= balancer.nbackends();
+ if (t == last)
+ throw ((Error) "Round-robin algorithm: no available back ends");
+ }
+}
+
diff --git a/xr/servertype/servertype b/xr/servertype/servertype
@@ -0,0 +1,31 @@
+#ifndef _SERVERTYPE_
+#define _SERVERTYPE_
+
+#include "../sys/sys"
+#include "../error/error"
+
+using namespace std;
+
+class Servertype {
+public:
+ enum Type {
+ t_tcp,
+ t_http,
+ };
+
+ Servertype() : t(t_tcp) {
+ }
+ Servertype (string id) {
+ type (id);
+ }
+
+ void type (string id);
+ Type type() const {
+ return (t);
+ }
+
+private:
+ Type t;
+};
+
+#endif
diff --git a/xr/servertype/type1.cc b/xr/servertype/type1.cc
@@ -0,0 +1,11 @@
+#include "servertype"
+
+void Servertype::type (string id) {
+ if (id == "tcp")
+ t = t_tcp;
+ else if (id == "http")
+ t = t_http;
+ else
+ throw ((Error) "Bad server type '" + id +
+ "', supported are 'tcp' or 'http'");
+}
diff --git a/xr/stopthread/execute.cc b/xr/stopthread/execute.cc
@@ -0,0 +1,30 @@
+#include "stopthread"
+
+void Stopthread::execute() {
+ static int stopping;
+ static int last_connections;
+ int loc_stopping;
+
+ if ( (loc_stopping = stopping) ) {
+ msg ("XR is waiting to shut down.\n");
+ return;
+ }
+
+ lock();
+ stopping++;
+ unlock();
+ msg ("XR will shut down.\n");
+
+ while (1) {
+ if (balancer.connections()) {
+ ostringstream o;
+ o << balancer.connections();
+ msg ("There are still " + o.str() + " connections, "
+ "XR will stop when they do.\n");
+ sleep (1);
+ continue;
+ }
+ msg ("No active connections, terminating XR.\n");
+ exit (0);
+ }
+}
diff --git a/xr/stopthread/stopthread b/xr/stopthread/stopthread
@@ -0,0 +1,13 @@
+#ifndef _STOPTHREAD_
+#define _STOPTHREAD_
+
+#include "../sys/sys"
+#include "../thread/thread"
+#include "../balancer/balancer"
+
+class Stopthread: public Thread {
+public:
+ void execute();
+};
+
+#endif
diff --git a/xr/sys/debugmsg.cc b/xr/sys/debugmsg.cc
@@ -0,0 +1,15 @@
+#include "sys"
+#include "../config/config"
+#include "../thread/thread"
+
+void debugmsg (string const &s) {
+ if (config.debug()) {
+ Thread th;
+ th.lock();
+ if (config.prefixtimestamp())
+ cerr << timestamp() << ' ';
+ cerr << pthread_self() << " DEBUG: " << s;
+ cerr.flush();
+ th.unlock();
+ }
+}
diff --git a/xr/sys/ipmatch.cc b/xr/sys/ipmatch.cc
@@ -0,0 +1,14 @@
+#include "sys"
+#include "../config/config"
+
+bool ipmatch (struct in_addr adr, struct in_addr mask) {
+ long laddr = * ((long*)&adr);
+ long lmask = * ((long*)&mask);
+ bool match = laddr & lmask == laddr;
+
+ if (config.debug())
+ debugmsg ("Matching ip " + (string)inet_ntoa(adr) + " against mask " +
+ (string)inet_ntoa(mask) + ": " +
+ (match ? "match" : "miss") + "\n");
+ return (match);
+}
diff --git a/xr/sys/main.cc b/xr/sys/main.cc
@@ -0,0 +1,53 @@
+
+#include "../sys/sys"
+#include "../config/config"
+#include "../balancer/balancer"
+#include "../error/error"
+#include "../stopthread/stopthread"
+
+using namespace std;
+
+Config config;
+Balancer balancer;
+
+static void sigcatcher (int sig) {
+ if (sig == SIGHUP)
+ balancer.report(true);
+ else if (sig != SIGPIPE)
+ balancer.terminate(true);
+}
+
+static void out_of_memory() {
+ cerr << "ERROR: Out of memory\n";
+ exit (1);
+}
+
+int main (int argc, char **argv) {
+ static int relevant_sig[] = {
+ SIGHUP, SIGINT, SIGQUIT, SIGABRT, SIGTERM, SIGSTOP, SIGPIPE
+ };
+
+ try {
+ // Load configuration from the commandline, promote verbosity
+ config.parsecmdline (argc, argv);
+
+ ostringstream o;
+ o << getpid();
+ msg ("XR running as PID " + o.str() + "\n");
+
+ // Load the signal handler.
+ for (unsigned i = 0; i < sizeof(relevant_sig); i++)
+ signal (relevant_sig[i], sigcatcher);
+
+ // Configure the balancer and start serving.
+ balancer.init();
+ balancer.serve();
+ } catch (Error e) {
+ cerr << e.txt() << endl;
+ return (1);
+ } catch (...) {
+ cerr << "ERROR: Unidentified exception caught" << endl;
+ }
+
+ return (0);
+}
diff --git a/xr/sys/msg.cc b/xr/sys/msg.cc
@@ -0,0 +1,15 @@
+#include "sys"
+#include "../config/config"
+#include "../thread/thread"
+
+void msg (string const &s) {
+ if (config.verbose()) {
+ Thread th;
+ th.lock();
+ if (config.prefixtimestamp())
+ cerr << timestamp() << ' ';
+ cerr << pthread_self() << " INFO: " << s;
+ cerr.flush();
+ th.unlock();
+ }
+}
diff --git a/xr/sys/reportmsg.cc b/xr/sys/reportmsg.cc
@@ -0,0 +1,13 @@
+#include "sys"
+#include "../config/config"
+#include "../thread/thread"
+
+void reportmsg (string const &s) {
+ Thread th;
+ th.lock();
+ if (config.prefixtimestamp())
+ cerr << timestamp() << ' ';
+ cerr << pthread_self() << " REPORT: " << s;
+ cerr.flush();
+ th.unlock();
+}
diff --git a/xr/sys/serversocket.cc b/xr/sys/serversocket.cc
@@ -0,0 +1,48 @@
+#include "sys"
+#include "../error/error"
+
+int serversocket (string addr, int port, string desc) {
+ int sock;
+
+ // Create the server socket, set options
+ if ( (sock = socket (PF_INET, SOCK_STREAM, 0)) < 0 )
+ throw ((Error) "Failed to create " + desc + " socket: " +
+ strerror(errno));
+ int val = 1;
+ if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)))
+ throw ((Error) "Failed to set socket options for " + desc + ": " +
+ strerror(errno));
+
+ // Prepare binding
+ struct sockaddr_in saddr;
+ memset (&saddr, 0, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = htons(port);
+
+ // Assign interface to listen to
+ ostringstream display_ip;
+ if (addr[0] != '0') {
+ msg ("Binding balancer to specific IP address " + addr + "\n");
+ if ( (saddr.sin_addr.s_addr = inet_addr (addr.c_str())) == INADDR_NONE )
+ throw ((Error) "Cannot convert " + desc + " IP '" + addr +
+ "' to network bytes");
+ display_ip << addr;
+ } else {
+ saddr.sin_addr.s_addr = htonl (INADDR_ANY);
+ display_ip << "0.0.0.0";
+ }
+ display_ip << ":" << port;
+
+ // Bind and listen
+ if (bind (sock, (sockaddr*) &saddr, sizeof(saddr)) < 0)
+ throw ((Error) "Failed to bind " + desc + " to " + display_ip.str() +
+ ": " + strerror(errno));
+ if (listen (sock, 5) < 0)
+ throw ((Error) "Failed to listen to " + desc + " IP " +
+ display_ip.str() + ": " + strerror(errno));
+
+ msg ("TCP server for " + desc + " listening to " + display_ip.str() + "\n");
+
+ return (sock);
+}
+
diff --git a/xr/sys/sys b/xr/sys/sys
@@ -0,0 +1,44 @@
+#ifndef _SYS_
+#define _SYS_
+
+/* System-wide includes, 'cuz I'm too lazy to repeat them throughout
+ * the entire source tree.
+ */
+
+// C
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+// C++
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+/* Generic functions */
+
+using namespace std;
+
+void msg (string const &s);
+void debugmsg (string const &s);
+void reportmsg (string const &s);
+int serversocket (string addr, int port, string description);
+string timestamp();
+bool ipmatch (struct in_addr addr, struct in_addr mask);
+
+#endif
diff --git a/xr/sys/timestamp.cc b/xr/sys/timestamp.cc
@@ -0,0 +1,15 @@
+#include "sys"
+
+string timestamp() {
+ struct timeval tv;
+ gettimeofday (&tv, 0);
+
+ struct tm *tmp = localtime(&tv.tv_sec);
+
+ char buf[80];
+ sprintf (buf, "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d,%3.3d",
+ tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec,
+ tv.tv_usec / 1000);
+ return (buf);
+}
diff --git a/xr/tcpdispatcher/dispatch.cc b/xr/tcpdispatcher/dispatch.cc
@@ -0,0 +1,28 @@
+#include "tcpdispatcher"
+
+void TcpDispatcher::dispatch() {
+ Backend tb;
+ bool connected = false;
+
+ while (!connected) {
+ target_backend = algorithm->target();
+ tb = balancer.backend(target_backend);
+ if (!tb.connect()) {
+ lock();
+ balancer.backend(target_backend).live(false);
+ unlock();
+ msg ("Failed to connect to back end " + tb.description() +
+ ", trying to dispatch to other\n");
+ } else {
+ connected = true;
+ backendfd(tb.sock());
+
+ ostringstream o;
+ o << target_backend;
+ msg ("Dispatching client to back end " + o.str() + " " +
+ tb.description() + "\n");
+
+ break;
+ }
+ }
+}
diff --git a/xr/tcpdispatcher/execute.cc b/xr/tcpdispatcher/execute.cc
@@ -0,0 +1,43 @@
+#include "tcpdispatcher"
+
+void TcpDispatcher::execute() {
+ ostringstream o;
+ o << clientfd();
+ msg ("Dispatch request for client fd " + o.str() + "\n");
+
+ try {
+ dispatch();
+ } catch (Error e) {
+ cerr << e.txt() << "\n";
+ close (clientfd());
+ return;
+ }
+
+ ostringstream co;
+ co << clientfd();
+ ostringstream bo;
+ bo << balancer.backend(target_backend).sock();
+ msg ("Dispatching client fd " + co.str() + " to " +
+ balancer.backend(target_backend).description() +
+ ", fd " + bo.str() + "\n");
+
+ lock();
+ balancer.backend(target_backend).startconnection();
+ unlock();
+
+ try {
+ handle();
+ } catch (Error e) {
+ cerr << e.txt() << "\n";
+ }
+
+ lock();
+ balancer.backend(target_backend).endconnection();
+ unlock();
+
+ close (clientfd());
+ close (backendfd());
+ msg ("Done dispatching client fd " + co.str() + " at " +
+ balancer.backend(target_backend).description() + "\n");
+
+}
diff --git a/xr/tcpdispatcher/handle.cc b/xr/tcpdispatcher/handle.cc
@@ -0,0 +1,15 @@
+#include "tcpdispatcher"
+
+void TcpDispatcher::handle() {
+ while (1) {
+ Fdset readset (config.client_timeout());
+ readset.add (clientfd());
+ readset.add (backendfd());
+
+ int s;
+ if ((s = readset.readable()) < 0 || !readchunk(s))
+ break;
+ writechunk (s == clientfd() ? backendfd() : clientfd(),
+ databuf(), databufsize());
+ }
+}
diff --git a/xr/tcpdispatcher/printable.cc b/xr/tcpdispatcher/printable.cc
@@ -0,0 +1,24 @@
+#include "tcpdispatcher"
+
+string TcpDispatcher::printable (char ch) const {
+ ostringstream o;
+
+ if (isprint(ch) && ch != '\\') {
+ o << ch;
+ return (o.str());
+ } else if (ch == '\n')
+ return ("\\n");
+ else if (ch == '\r')
+ return ("\\r");
+ else if (ch == '\t')
+ return ("\\t");
+ else {
+ char buf[10];
+ sprintf (buf, "%3.3o", ch & 0xff);
+ o << "\\" << buf;
+ return (o.str());
+ }
+
+ // Avoid warnings
+ return (".");
+}
diff --git a/xr/tcpdispatcher/readchunk.cc b/xr/tcpdispatcher/readchunk.cc
@@ -0,0 +1,20 @@
+#include "tcpdispatcher"
+
+unsigned TcpDispatcher::readchunk (int src) {
+ ssize_t nread = read (src, data_buf, config.buffersize());
+ if (nread < 0)
+ throw ((Error) "Read failed on fd " + src);
+
+ balancer.backend(targetbackend()).addbytes (databufsize());
+
+ if (config.debug() && nread) {
+ ostringstream o;
+ o << "Got " << nread << " bytes from fd " << src << ": ";
+ for (unsigned i = 0; i < (unsigned)nread; i++)
+ o << printable(data_buf[i]);
+ o << "\n";
+ debugmsg (o.str());
+ }
+
+ return (data_bufsz = nread);
+}
diff --git a/xr/tcpdispatcher/tcpdispatcher b/xr/tcpdispatcher/tcpdispatcher
@@ -0,0 +1,47 @@
+#ifndef _TCPDISPATCHER_
+#define _TCPDISPATCHER_
+
+#include "../sys/sys"
+#include "../balancer/balancer"
+#include "../config/config"
+#include "../thread/thread"
+#include "../algorithm/algorithm"
+#include "../roundrobin/roundrobin"
+#include "../firstactive/firstactive"
+#include "../leastconn/leastconn"
+#include "../external/external"
+
+class TcpDispatcher: public Thread {
+public:
+
+ TcpDispatcher (int fd, string ip);
+ virtual ~TcpDispatcher();
+
+ virtual void execute();
+
+ virtual void dispatch();
+ virtual void handle();
+
+ int targetbackend() const { return target_backend; }
+ void targetbackend(int t) { target_backend = t; }
+ string clientip() const { return client_ip; }
+ int clientfd() const { return client_fd; }
+ void clientfd(int c) { client_fd = c; }
+ int backendfd() const { return backend_fd; }
+ void backendfd(int b) { backend_fd = b; }
+ char const *databuf() const { return data_buf; }
+ unsigned databufsize() const { return data_bufsz; }
+
+ unsigned readchunk (int src);
+ unsigned writechunk (int dst, char const *b, unsigned blen);
+
+private:
+ string printable (char ch) const;
+ string client_ip;
+ int target_backend, client_fd, backend_fd;
+ char *data_buf;
+ unsigned data_bufsz;
+ Algorithm *algorithm;
+};
+
+#endif
diff --git a/xr/tcpdispatcher/tcpdispatcher1.cc b/xr/tcpdispatcher/tcpdispatcher1.cc
@@ -0,0 +1,25 @@
+#include "tcpdispatcher"
+
+TcpDispatcher::TcpDispatcher(int cfd, string cip):
+ Thread(), client_ip(cip), target_backend(-1), client_fd(cfd),
+ backend_fd(-1), data_bufsz(0) {
+
+ // Set up a data buffer for network transfers
+ data_buf = new char[config.buffersize()];
+
+ // Instantiate dispatchmode algorithm
+ switch (config.dispatchmode()) {
+ case Dispatchmode::m_roundrobin:
+ algorithm = new Roundrobin;
+ break;
+ case Dispatchmode::m_leastconn:
+ algorithm = new Leastconn;
+ break;
+ case Dispatchmode::m_firstactive:
+ algorithm = new Firstactive;
+ break;
+ case Dispatchmode::m_external:
+ algorithm = new External;
+ break;
+ }
+}
diff --git a/xr/tcpdispatcher/tcpdispatcher2.cc b/xr/tcpdispatcher/tcpdispatcher2.cc
@@ -0,0 +1,7 @@
+#include "tcpdispatcher"
+
+TcpDispatcher::~TcpDispatcher() {
+ delete data_buf;
+ delete algorithm;
+ debugmsg ("TCP dispatcher finished\n");
+}
diff --git a/xr/tcpdispatcher/writechunk.cc b/xr/tcpdispatcher/writechunk.cc
@@ -0,0 +1,27 @@
+#include "tcpdispatcher"
+
+unsigned TcpDispatcher::writechunk (int dst, char const *b, unsigned blen) {
+ // Client fd 0 (stdin) gets written to stdout.
+ if (!dst)
+ dst = 1;
+
+ unsigned totwritten = 0;
+ while (totwritten < blen) {
+ ssize_t nwritten = write (dst, (void*) (b + totwritten),
+ blen - totwritten);
+ if (nwritten < 1)
+ throw ((Error) "Write failed");
+
+ if (config.debug()) {
+ ostringstream o;
+ o << "Sent " << nwritten << " bytes to fd " << dst << ": ";
+ for (unsigned i = 0; i < (unsigned) nwritten; i++)
+ o << printable(b[totwritten + i]);
+ o << "\n";
+ debugmsg (o.str());
+ }
+
+ totwritten += nwritten;
+ }
+ return (totwritten);
+}
diff --git a/xr/thread/execute.cc b/xr/thread/execute.cc
@@ -0,0 +1,5 @@
+#include "thread"
+
+// Dummy incase the derived class doesn't define one
+void Thread::execute() {
+}
diff --git a/xr/thread/lock.cc b/xr/thread/lock.cc
@@ -0,0 +1,7 @@
+#include "thread"
+
+void Thread::lock() {
+ int res;
+ if ( (res = pthread_mutex_lock (&thread_mutex)) )
+ throw ((Error) "Failed to obtain mutex lock: " + strerror(res));
+}
diff --git a/xr/thread/start.cc b/xr/thread/start.cc
@@ -0,0 +1,51 @@
+#include "thread"
+
+static void *_run (void *data) {
+ Thread *t = (Thread*) data;
+
+ try {
+ t->execute();
+ } catch (Error e) {
+ cerr << e.txt() << "\n";
+ }
+
+ // Cleanups
+ delete (t);
+
+ // To satisfy the prototype
+ return (0);
+}
+
+void Thread::start() {
+
+ if (config.foregroundmode())
+ _run ((void*)this);
+ else {
+ pthread_t th;
+ pthread_attr_t attr;
+ int res;
+
+ if (pthread_attr_init (&attr))
+ throw ((Error) "Cannot initialize thread attributes");
+ if (pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED))
+ throw ((Error) "Cannot set thread state as detached");
+ for (int i = 0; i < 3; i++) {
+ res = pthread_create (&th, &attr, _run, (void*) this);
+ if (!res) {
+ pthread_attr_destroy (&attr);
+ return;
+ } else if (res == EAGAIN) {
+ msg ("Failed to start thread: " + (string)strerror(res) +
+ ", retrying\n");
+ sleep (1);
+ continue;
+ } else {
+ pthread_attr_destroy (&attr);
+ throw ((Error) "Failed to start thread: " + strerror(res));
+ }
+ }
+
+ throw ((Error) "Failed to start thread: "
+ "Resources unavailable after 3 tries, giving up");
+ }
+}
diff --git a/xr/thread/thread b/xr/thread/thread
@@ -0,0 +1,22 @@
+#ifndef _THREAD_
+#define _THREAD_
+
+#include "../sys/sys"
+#include "../error/error"
+#include "../config/config"
+
+using namespace std;
+
+class Thread {
+public:
+ Thread();
+ virtual ~Thread();
+ void start();
+ void lock();
+ void unlock();
+ virtual void execute();
+private:
+ pthread_mutex_t thread_mutex;
+};
+
+#endif
diff --git a/xr/thread/thread1.cc b/xr/thread/thread1.cc
@@ -0,0 +1,8 @@
+#include "thread"
+
+Thread::Thread() {
+ int res;
+
+ if ( (res = pthread_mutex_init (&thread_mutex, 0)) )
+ throw ((Error) "Failed to initialize mutex: " + strerror(res));
+}
diff --git a/xr/thread/thread2.cc b/xr/thread/thread2.cc
@@ -0,0 +1,4 @@
+#include "thread"
+
+Thread::~Thread() {
+}
diff --git a/xr/thread/unlock.cc b/xr/thread/unlock.cc
@@ -0,0 +1,7 @@
+#include "thread"
+
+void Thread::unlock() {
+ int res;
+ if ( (res = pthread_mutex_unlock (&thread_mutex)) )
+ throw ((Error) "Failed to release mutex lock: " + strerror(res));
+}
diff --git a/xr/wakeupthread/execute.cc b/xr/wakeupthread/execute.cc
@@ -0,0 +1,19 @@
+#include "wakeupthread"
+
+void Wakeupthread::execute() {
+ while (1) {
+ for (unsigned i = 0; i < balancer.nbackends(); i++) {
+ if (! balancer.backend(i).live()) {
+ Backend target(balancer.backend(i).backenddef());
+ target.check();
+ if (target.live()) {
+ msg ("Wakeup call: backend " + target.description() +
+ " has awoken\n");
+ balancer.backend(i).live(true);
+ }
+ }
+ }
+ sleep (config.wakeupsec());
+ }
+}
+
diff --git a/xr/wakeupthread/wakeupthread b/xr/wakeupthread/wakeupthread
@@ -0,0 +1,14 @@
+#ifndef _WAKEUPTHREAD_
+#define _WAKEUPTHREAD_
+
+#include "../sys/sys"
+#include "../thread/thread"
+#include "../balancer/balancer"
+#include "../error/error"
+
+class Wakeupthread: public Thread {
+public:
+ void execute();
+};
+
+#endif
diff --git a/xrctl/xrctl b/xrctl/xrctl
@@ -0,0 +1,465 @@
+#!/usr/bin/perl
+use strict;
+
+# Configuration section. Enter your favorite values here.
+# -------------------------------------------------------
+
+# Directory where PID stamp files are stored, named xr-{service}.pid
+my $piddir = '/var/run';
+
+# 'ps' command that prints a process ID and the invoking command
+my $pscmd = '/bin/ps ax -o pid,command';
+
+# Use 'logger' to send output to syslog? 0 means no.
+my $use_logger = 1;
+
+# Directory where log files are stored, named xr-{service}.log. Used
+# when logger isn't available or wanted.
+my $logdir = '/var/log';
+
+# Max log file size in bytes (used by xrctl rotate). Used when logger isn't
+# available or wanted.
+my $maxlogsize = 100000;
+
+# Nr. of historical log files to keep (used by xrctl rotate). Used when logger
+# isn't available or wanted.
+my $loghistory = 10;
+
+# Paths where executables are searched.
+my @bindirs = qw(/bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin
+ /opt/local/bin /opt/local/sbin);
+
+# Services to balance. All non-default flags for XR must be specified. The
+# primary key into hash %services is a self-chosen name. xrctl will supply
+# --prefix-timestamp when logging to a bare file (when logger isn't used).
+# Also xrctl will supply --pidfile for run control purposes.
+# See the examples below to help you model your favorite dispatcher.
+my %services =
+ (
+
+ # Basically just a port forwarder to localhost:80. I use it for
+ # benchmarking.
+ 'fwd1' =>
+ { '--server' => [ qw(tcp:0:10000) ],
+ '--backend' => [ qw(localhost:80) ],
+ # '--verbose' => undef,
+ # '--debug' => undef,
+ },
+
+ # Same thing, but a HTTP forwarder that adds X-Forwarded-For headers.
+ # I use it for benchmarking HTTP handling.
+ 'fwd2' =>
+ { '--server' => [ qw(http:0:10001) ],
+ '--backend' => [ qw(localhost:80) ],
+ # '--verbose' => undef,
+ },
+
+
+ # Web servers balancing to 3 back ends at 10.0.0.1 thru 3. The
+ # balancer will use HTTP mode and add X-Forwarded-For headers.
+ 'webone' =>
+ { '--server' => [ qw(http:0:80) ],
+ '--backend' => [ qw(10.0.0.1:80 10.0.0.2:80 10.0.0.3:80) ],
+ '--verbose' => undef,
+ '--add-x-forwarded-for' => undef,
+ },
+
+ # Web servers balancing to 3 back ends at 10.1.1.1 thru 3. The
+ # balancer will use HTTP mode, add X-Forwarded-For headers, and make the
+ # HTTP sessions sticky to their back ends. NOTE - this server starts on
+ # port 81 for demo purposes (or it would interfere with webone above).
+ 'webtwo' =>
+ { '--server' => [ qw(http:0:81) ],
+ '--backend' => [ qw(10.1.1.1:80 10.1.1.2:80 10.1.1.3:80) ],
+ '--verbose' => undef,
+ '--add-x-forwarded-for' => undef,
+ '--sticky-http' => undef,
+ },
+
+ # An Access Control List (ACL) example, again using web balancing.
+ # Allowed clients are 127.0.0.1 (localhost) and 192.168.*.*, except
+ # for 192.168.1.250.
+ 'webthree' =>
+ { '--server' => [ qw(http:0:82) ],
+ '--backend' => [ qw(10.1.1.1:80 10.1.1.2:80 10.1.1.3:80) ],
+ '--verbose' => undef,
+ '--add-x-forwarded-for' => undef,
+ '--allow-from' => [ qw(127.0.0.1 192.168.255.255) ],
+ '--deny-from' => [ qw(192.168.1.250) ],
+ },
+
+
+ # An SSH session balancer on port 2222. We set the client time out
+ # to 2 hours. Requests are balanced to server1, server2 and server3,
+ # all to port 22.
+ 'ssh' =>
+ { '--server' => [ qw(tcp:0:2222) ],
+ '--backend' => [ qw(server1:22 server2:22 server3:22) ],
+ '--verbose' => undef,
+ '--client-timeout' => [ qw(7200) ],
+ },
+
+ # Windows Remote Desktop Protocol (RDP) balancing. Windows supports
+ # only one concurrent client, and we don't want new connections to 'steal'
+ # existing sessions - so we set the max connections of each back end to 1.
+ 'rdp' =>
+ { '--server' => [ qw(tcp:0:3389) ],
+ '--backend' => [ qw(win1:3389:1 win2:3389:1 win33:3389:1) ],
+ '--verbose' => undef,
+ '--client-timeout' => [ qw(7200) ],
+ },
+
+ # A HTTP forwarder for travelling. Depending on the site where I plug
+ # in, this reaches some proxy - or localhost:3128, which is a local squid.
+ # I configure my browser to use localhost:8080 as proxy, and don't have
+ # to reconfigure browsers anymore. Note the dispatch method which is
+ # first-active, the first downstream proxy that works is OK for me.
+ # Note also that the server type is TCP, I don't need HTTP goodies.
+ # Also the server listens to 127.0.0.1 - only for localhost usage.
+ 'proxy' =>
+ { '--server' => [ qw(tcp:127.0.0.1:8080) ],
+ '--backend' => [ qw(10.120.114.2:8080 192.168.1.250:80
+ localhost:3128) ],
+ '--dispatch-mode' => [ qw(first-active) ],
+ '--verbose' => undef,
+ },
+
+ # Simple tunnel to easily access an external proxy at 10.1.1.250. The
+ # proxy requires authentication, user 'user', password 'secret', which
+ # is base64-encoded: dXNlcjpzZWNyZXQ=
+ # Next I can "export http_proxy localhost:8090" and use wget etc. without
+ # typing the proxy credentials.
+ 'authproxy' =>
+ { '--server' => [ qw(http:127.0.0.1:8090) ],
+ '--backend' => [ qw(10.1.1.250:80) ],
+ '--add-server-header' => [ 'Proxy-Authorization: '.
+ 'Basic dXNlcjpzZWNyZXQ=' ],
+ '--verbose' => undef,
+ '--debug' => undef,
+ },
+ );
+
+# Main starts here, configuration ends.
+# -------------------------------------
+
+# Get the action
+my $action = shift (@ARGV);
+
+# Prepare service list unless given on the command line
+if ($#ARGV == -1) {
+ push (@ARGV, sort (keys (%services)));
+} else {
+ for my $s (@ARGV) {
+ die ("xrctl: No such service $s\n") unless ($services{$s});
+ }
+}
+
+# Take appropriate action
+if ($action eq 'list') {
+ list(@ARGV);
+} elsif ($action eq 'status') {
+ status(@ARGV);
+} elsif ($action eq 'start') {
+ start(@ARGV);
+} elsif ($action eq 'stop') {
+ stop(@ARGV);
+} elsif ($action eq 'force') {
+ force(@ARGV);
+} elsif ($action eq 'rotate') {
+ rotate(@ARGV);
+} elsif ($action eq 'restart') {
+ restart(@ARGV);
+} else {
+ usage();
+}
+
+# Show usage and stop
+# -------------------
+sub usage() {
+ die <<"ENDUSAGE";
+
+Usage: xrctl list [SERVICE] - show configuration of a service, or of all
+ xrctl start [SERVICE] - start a service, or all configured services
+ xrctl stop [SERVICE] - stop a service, or all configured services
+ xrctl force [SERVICE] - start a service (or all) if not running
+ xrctl restart [SERVICE] - stop and start a service, or all
+ xrctl status [SERVICE] - show running status of a service, or of all
+ xrctl rotate [SERVICE] - rotate logs of a service or of all
+
+ENDUSAGE
+}
+
+# List services and command lines
+# -------------------------------
+sub list {
+ print ("Configured services: ",
+ join (', ', sort (keys (%services))),
+ "\n");
+ for my $s (@_) {
+ print ("Service $s:\n",
+ " Process : ", "xr-$s\n",
+ " PID file : ", pidfile($s), "\n",
+ " Log file : ", logfile($s), "\n",
+ " XR command:");
+ my @parts = xrcommand($s);
+ for (my $i = 0; $i <= $#parts; $i++) {
+ next if ($i == 1);
+ my $p = $parts[$i];
+ $p = "'$p'" if ($p =~ /\s/);
+ print (" $p");
+ }
+ print ("\n");
+ }
+}
+
+# Show the status of the commands
+# -------------------------------
+sub status {
+ for my $s (@_) {
+ die ("xrctl: No such service '$s'\n") unless ($services{$s});
+ print ("Service $s: ", getstatus($s), "\n");
+ }
+}
+
+# Start service(s)
+# ----------------
+sub start {
+ for my $s (@_) {
+ print ("Service $s: ");
+ my $status = getstatus($s);
+ if ($status !~ /^not/) {
+ print ("already $status\n");
+ } else {
+ rundaemon ($s, xrcommand($s));
+ print ("started\n");
+ }
+ }
+}
+
+# Stop service(s)
+# ---------------
+sub stop {
+ for my $s (@_) {
+ print ("Service $s: ");
+ my $status = getstatus($s);
+ if ($status =~ /^not/) {
+ print ($status, "\n");
+ } else {
+ my $pid = servicebypidfile($s);
+ $pid = servicebypslist($s) unless ($pid);
+ die ("Failed to get PID\n") unless ($pid);
+ kill (15, $pid);
+ print ("stopping\n");
+ }
+ }
+}
+
+# Restart service(s)
+# ------------------
+sub restart {
+ for my $s (@_) {
+ print ("Service $s: ");
+ my $status = getstatus($s);
+ if ($status =~ /^not/) {
+ print ($status, "\n");
+ } else {
+ my $pid = servicebypidfile($s);
+ $pid = servicebypslist($s) unless ($pid);
+ die ("Failed to get PID\n") unless ($pid);
+ kill (15, $pid);
+ rundaemon ($s, xrcommand($s));
+ print ("restarted\n");
+ }
+ }
+}
+
+# Force service(s) up
+# -------------------
+sub force {
+ for my $s (@_) {
+ print ("Service $s: ");
+ my $status = getstatus($s);
+ if ($status =~ /^not/) {
+ rundaemon ($s, xrcommand($s));
+ print ("started\n");
+ } else {
+ print ($status, "\n");
+ }
+ }
+}
+
+# Rotate logs
+# -----------
+sub rotate {
+ if ($use_logger and findbin('logger')) {
+ print ("Rotating disabled, logging via logger/syslog\n");
+ return;
+ }
+ for my $s (@_) {
+ print ("Service $s: ");
+ my $f = logfile($s);
+ if (! -f $f) {
+ print ("no logfile $f\n");
+ } elsif ((stat($f))[7] < $maxlogsize) {
+ print ("no rotation necessary\n");
+ } else {
+ unlink ("$f.$loghistory", "$f.$loghistory.bz2",
+ "$f.$loghistory.gz");
+ for (my $i = $loghistory - 1; $i >= 0; $i--) {
+ my $src = "$f.$i";
+ my $dst = sprintf ("$f.%d", $i + 1);
+ rename ($src, $dst);
+ rename ("$src.bz2", "$dst.bz2");
+ rename ("$src.gz", "$dst.gz");
+ }
+ rename ($f, "$f.0");
+ print ("rotated");
+ my $zipper;
+ if ($zipper = findbin("bzip2") or
+ $zipper = findbin("gzip")) {
+ system ("$zipper $f.0");
+ print (", zipped");
+ }
+ print ("\n");
+ restart($s);
+ }
+ }
+}
+
+# Get the status of one balancer service
+# --------------------------------------
+sub getstatus($) {
+ my $s = shift;
+ die ("xrctl: No such service '$s'\n") unless ($services{$s});
+ my $fpid = servicebypidfile($s);
+ my $ppid = servicebypslist($s);
+
+ # print ("getstatus: fpid=$fpid, ppid=$ppid\n");
+
+ if (! $fpid and ! $ppid) {
+ return ("not running");
+ } elsif ($fpid == $ppid) {
+ return ("running");
+ } elsif ($fpid and ! $ppid) {
+ return ("not running (stale pidfile found)");
+ } elsif (! $fpid and $ppid) {
+ return ("running (but no pidfile found)");
+ } else {
+ return ("running (stale pidfile found)");
+ }
+}
+
+# Return a command to start XR
+# ----------------------------
+sub xrcommand ($) {
+ my $s = shift;
+ my $xr = findbin('xr') or die ("xrctl: Failed to find xr along @bindirs\n");
+ my %opts = %{ $services{$s} };
+ my @ret = ($xr, "xr-$s", "--pidfile", pidfile($s));
+ push (@ret, "--prefix-timestamp") if (! $use_logger or
+ ! findbin('logger'));
+ for my $o (sort (keys (%opts))) {
+ if (! $opts{$o}) {
+ push (@ret, $o);
+ } else {
+ my @args = @{ $opts{$o} };
+ if ($#args == -1) {
+ push (@ret, $o);
+ } else {
+ for my $arg (@args) {
+ push (@ret, $o);
+ push (@ret, $arg);
+ }
+ }
+ }
+ }
+ return (@ret);
+}
+
+# Return the PID file of a given service
+# --------------------------------------
+sub pidfile ($) {
+ my $s = shift;
+ return ("$piddir/xr-$s.pid");
+}
+
+# Examine the contents of a PID file
+# ----------------------------------
+sub servicebypidfile($) {
+ my $s = shift;
+ my $p = pidfile($s);
+ if (open (my $f, $p)) {
+ my $pid = <$f>;
+ chomp ($pid);
+ return ($pid);
+ } else {
+ return (undef);
+ }
+}
+
+# Get the PID of a service using the PS list
+# -------------------------------------------
+sub servicebypslist($) {
+ my $s = shift;
+ open (my $if, "$pscmd |") or die ("xrctl: Cannot start '$pscmd': $!\n");
+ while (my $line = <$if>) {
+ chomp ($line);
+ my $p = sprintf ("%d", $line);
+ next unless ($p);
+ my $c = $line;
+ $c =~ s/^[\d\s]*//;
+ # print ("LF [$s], p=[$p], c=[$c]\n");
+ return ($p) if ($c =~ /^[^\s]*xr-$s/);
+ }
+ return (undef);
+}
+
+# Return the log file of a given service
+# --------------------------------------
+sub logfile($) {
+ my $s = shift;
+ return ('logger') if ($use_logger and findbin('logger'));
+ return ("$logdir/xr-$s.log");
+}
+
+# Find a binary along the path
+# -----------------------------
+sub findbin ($) {
+ my $b = shift;
+ for my $d (@bindirs) {
+ return ("$d/$b") if (-x "$d/$b");
+ }
+ return (undef);
+}
+
+# Run a command as a daemon
+# -------------------------
+sub rundaemon {
+ my $s = shift;
+ my @args = @_;
+
+ my $logger = findbin('logger');
+ my $outfile = logfile($s);
+
+ my $pid = fork();
+ return if ($pid > 0);
+
+ # Child branch
+ close (STDIN);
+ open (STDIN, "/dev/null")
+ or die ("xrctl (daemon): Can not reopen stdin to /dev/null: $!\n");
+ if ($use_logger and $logger) {
+ open (STDOUT, "|$logger -t xr-$s")
+ or die ("xrctl (daemon): Cannot reopen stdout to logger: $!\n");
+ open (STDERR, "|$logger -t xr-$s")
+ or die ("xrctl (daemon): Cannot reopen stdout to logger: $!\n");
+ } else {
+ open (STDOUT, ">>$outfile")
+ or die ("xrctl (deamon): Cannot reopen stdout to $outfile: $!\n");
+ open (STDERR, ">>$outfile")
+ or die ("xrctl (deamon): Cannot reopen stderr to $outfile: $!\n");
+ }
+ my $truecmd = shift (@args);
+ exec ({ $truecmd } @args);
+ exit (1);
+}