crossroads

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

commit ef4ca38c2c1690a176c16ad85b07087adda25611
parent b0e25a43f1b1e512bd14012439d987f2f65c48c7
Author: finwo <finwo@pm.me>
Date:   Sat,  3 Jan 2026 19:31:35 +0100

1.40

Diffstat:
MChangeLog | 11++++++++++-
MMakefile | 28+++++++++++++++-------------
Mdoc/compiling.yo | 4++--
Mdoc/crossroads.html | 605+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Mdoc/crossroads.man | 293++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mdoc/crossroads.pdf | 0
Mdoc/crossroads.yo | 2+-
Mdoc/intro.yo | 21+++++++++++++++++++++
Mdoc/tips.yo | 5+++++
Adoc/tips/rendering.yo | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/tips/scripting.yo | 152+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdoc/using.yo | 10++++++++++
Aetc/Makefile.conf | 23+++++++++++++++++++++++
Metc/Makefile.def | 6++++--
Aetc/healthcheck | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Metc/svnrev.txt | 2+-
Aetc/xml-status-to-html.xslt | 131+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/Makefile | 109+++++++++++++++++++++++--------------------------------------------------------
Dsrc/allocreporter.c | 65-----------------------------------------------------------------
Dsrc/ansistamp.c | 26--------------------------
Dsrc/backendavailable.c | 26--------------------------
Dsrc/backendconnect.c | 108-------------------------------------------------------------------------------
Dsrc/backendcount.c | 16----------------
Dsrc/choosebackend.c | 377-------------------------------------------------------------------------------
Dsrc/configtest.c | 12------------
Dsrc/copysockets.c | 16----------------
Dsrc/createcommandlinespace.c | 37-------------------------------------
Msrc/crossroads.h | 27+++++++++++++++++++--------
Asrc/crossroads/Makefile | 23+++++++++++++++++++++++
Asrc/crossroads/main.c | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/deallocreporter.c | 39---------------------------------------
Dsrc/decrclientcount.c | 43-------------------------------------------
Dsrc/error.c | 23-----------------------
Dsrc/forktcpservicer.c | 48------------------------------------------------
Dsrc/hashpjw.c | 25-------------------------
Dsrc/httpcopy.c | 105-------------------------------------------------------------------------------
Dsrc/httperror.c | 18------------------
Dsrc/httpheaderaddheader.c | 33---------------------------------
Dsrc/httpheaderappendheader.c | 44--------------------------------------------
Dsrc/httpheaderconnectiontype.c | 31-------------------------------
Dsrc/httpheaderfree.c | 16----------------
Dsrc/httpheaderhascookie.c | 34----------------------------------
Dsrc/httpheaderhttpver.c | 36------------------------------------
Dsrc/httpheadernew.c | 16----------------
Dsrc/httpheaderread.c | 55-------------------------------------------------------
Dsrc/httpheaderremoveheader.c | 22----------------------
Dsrc/httpheadersetheader.c | 37-------------------------------------
Dsrc/httpheaderval.c | 27---------------------------
Dsrc/httpheaderwrite.c | 25-------------------------
Dsrc/httpinsertheader.c | 55-------------------------------------------------------
Dsrc/httpserve.c | 213-------------------------------------------------------------------------------
Dsrc/httpserversocket.c | 76----------------------------------------------------------------------------
Dsrc/httpwrite.c | 18------------------
Dsrc/incrclientcount.c | 40----------------------------------------
Dsrc/initsockaddr.c | 21---------------------
Dsrc/interrupt.c | 55-------------------------------------------------------
Dsrc/ipfaddallow.c | 17-----------------
Dsrc/ipfadddeny.c | 17-----------------
Dsrc/ipfallowed.c | 22----------------------
Dsrc/ipfdenied.c | 22----------------------
Dsrc/ipfloadfile.c | 53-----------------------------------------------------
Dsrc/ipfmatch.c | 43-------------------------------------------
Dsrc/ipfparse.c | 51---------------------------------------------------
Dsrc/ishexdigit.c | 15---------------
Dsrc/isspace.c | 15---------------
Dsrc/lexer.c | 2358-------------------------------------------------------------------------------
Dsrc/lexer.l | 415-------------------------------------------------------------------------------
Asrc/lib/Makefile | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/allocreporter.c | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/ansistamp.c | 26++++++++++++++++++++++++++
Asrc/lib/backendavailable.c | 26++++++++++++++++++++++++++
Asrc/lib/backendconnect.c | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/backendcount.c | 16++++++++++++++++
Asrc/lib/choosebackend.c | 377+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/configtest.c | 12++++++++++++
Asrc/lib/copysockets.c | 16++++++++++++++++
Asrc/lib/createcommandlinespace.c | 38++++++++++++++++++++++++++++++++++++++
Asrc/lib/deallocreporter.c | 39+++++++++++++++++++++++++++++++++++++++
Asrc/lib/decrclientcount.c | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/error.c | 23+++++++++++++++++++++++
Asrc/lib/forktcpservicer.c | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/hashpjw.c | 25+++++++++++++++++++++++++
Asrc/lib/httpcopy.c | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/httperror.c | 18++++++++++++++++++
Asrc/lib/httpheaderaddheader.c | 33+++++++++++++++++++++++++++++++++
Asrc/lib/httpheaderappendheader.c | 44++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/httpheaderconnectiontype.c | 31+++++++++++++++++++++++++++++++
Asrc/lib/httpheaderfree.c | 16++++++++++++++++
Asrc/lib/httpheaderhascookie.c | 34++++++++++++++++++++++++++++++++++
Asrc/lib/httpheaderhttpver.c | 36++++++++++++++++++++++++++++++++++++
Asrc/lib/httpheadernew.c | 16++++++++++++++++
Asrc/lib/httpheaderread.c | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/httpheaderremoveheader.c | 22++++++++++++++++++++++
Asrc/lib/httpheadersetheader.c | 37+++++++++++++++++++++++++++++++++++++
Asrc/lib/httpheaderval.c | 27+++++++++++++++++++++++++++
Asrc/lib/httpheaderwrite.c | 25+++++++++++++++++++++++++
Asrc/lib/httpinsertheader.c | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/httpserve.c | 213+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/httpserversocket.c | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/httpwrite.c | 18++++++++++++++++++
Asrc/lib/incrclientcount.c | 40++++++++++++++++++++++++++++++++++++++++
Asrc/lib/initsockaddr.c | 21+++++++++++++++++++++
Asrc/lib/interrupt.c | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/ipfaddallow.c | 17+++++++++++++++++
Asrc/lib/ipfadddeny.c | 17+++++++++++++++++
Asrc/lib/ipfallowed.c | 22++++++++++++++++++++++
Asrc/lib/ipfdenied.c | 22++++++++++++++++++++++
Asrc/lib/ipfloadfile.c | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/ipfmatch.c | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/ipfparse.c | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/ishexdigit.c | 15+++++++++++++++
Asrc/lib/isspace.c | 15+++++++++++++++
Asrc/lib/lexer.c | 2358+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/lexer.l | 415+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/lockreporter.c | 32++++++++++++++++++++++++++++++++
Asrc/lib/logactivityany.c | 16++++++++++++++++
Asrc/lib/logactivitycontinuation.c | 10++++++++++
Asrc/lib/logactivityend.c | 10++++++++++
Asrc/lib/logactivitystart.c | 10++++++++++
Asrc/lib/makesocket.c | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/markactivity.c | 143+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/msg.c | 23+++++++++++++++++++++++
Asrc/lib/msgdumpbuf.c | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/netbuffer.c | 35+++++++++++++++++++++++++++++++++++
Asrc/lib/netbufread.c | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/netcopy.c | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/netread.c | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/netwrite.c | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/parser.c | 2533+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/parser.h | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/parser.y | 1243+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rsrc/proxyerror.txt -> src/lib/proxyerror.txt | 0
Asrc/lib/restart.c | 24++++++++++++++++++++++++
Asrc/lib/runservice.c | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/serve.c | 29+++++++++++++++++++++++++++++
Asrc/lib/setprogramtitle.c | 42++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/showconfig.c | 38++++++++++++++++++++++++++++++++++++++
Asrc/lib/showservices.c | 25+++++++++++++++++++++++++
Asrc/lib/showstatus.c | 153+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/stagetostring.c | 21+++++++++++++++++++++
Asrc/lib/statetostring.c | 16++++++++++++++++
Asrc/lib/stopdaemon.c | 35+++++++++++++++++++++++++++++++++++
Asrc/lib/strcasestr.c | 25+++++++++++++++++++++++++
Asrc/lib/strexpandformat.c | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/stringtostate.c | 16++++++++++++++++
Asrc/lib/strlcat.c | 30++++++++++++++++++++++++++++++
Asrc/lib/strprintf.c | 13+++++++++++++
Asrc/lib/strvprintf.c | 32++++++++++++++++++++++++++++++++
Asrc/lib/sysrun.c | 24++++++++++++++++++++++++
Asrc/lib/tcpserve.c | 170+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/tellservice.c | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/thruputlog.c | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/trafficlog.c | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/uidassume.c | 28++++++++++++++++++++++++++++
Asrc/lib/uidrestore.c | 13+++++++++++++
Asrc/lib/unlockreporter.c | 26++++++++++++++++++++++++++
Asrc/lib/usage.c | 13+++++++++++++
Asrc/lib/usage.txt | 39+++++++++++++++++++++++++++++++++++++++
Asrc/lib/vsyslog.c | 16++++++++++++++++
Asrc/lib/wakeuphandler.c | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/warning.c | 23+++++++++++++++++++++++
Asrc/lib/writelog.c | 15+++++++++++++++
Asrc/lib/xmalloc.c | 10++++++++++
Asrc/lib/xrealloc.c | 27+++++++++++++++++++++++++++
Asrc/lib/xstrcat.c | 19+++++++++++++++++++
Asrc/lib/xstrcatch.c | 14++++++++++++++
Asrc/lib/xstrdup.c | 16++++++++++++++++
Dsrc/lockreporter.c | 32--------------------------------
Dsrc/logactivityany.c | 16----------------
Dsrc/logactivitycontinuation.c | 10----------
Dsrc/logactivityend.c | 10----------
Dsrc/logactivitystart.c | 10----------
Dsrc/main.c | 155-------------------------------------------------------------------------------
Dsrc/makesocket.c | 62--------------------------------------------------------------
Dsrc/markactivity.c | 143-------------------------------------------------------------------------------
Dsrc/msg.c | 23-----------------------
Dsrc/msgdumpbuf.c | 48------------------------------------------------
Dsrc/netbuffer.c | 35-----------------------------------
Dsrc/netbufread.c | 60------------------------------------------------------------
Dsrc/netcopy.c | 116-------------------------------------------------------------------------------
Dsrc/netread.c | 101-------------------------------------------------------------------------------
Dsrc/netwrite.c | 101-------------------------------------------------------------------------------
Dsrc/parser.c | 2533-------------------------------------------------------------------------------
Dsrc/parser.h | 66------------------------------------------------------------------
Dsrc/parser.y | 1243-------------------------------------------------------------------------------
Dsrc/restart.c | 24------------------------
Dsrc/runservice.c | 122-------------------------------------------------------------------------------
Dsrc/serve.c | 21---------------------
Dsrc/setprogramtitle.c | 42------------------------------------------
Dsrc/showconfig.c | 38--------------------------------------
Dsrc/showservices.c | 25-------------------------
Dsrc/showstatus.c | 111-------------------------------------------------------------------------------
Dsrc/stagetostring.c | 21---------------------
Dsrc/statetostring.c | 16----------------
Dsrc/stopdaemon.c | 35-----------------------------------
Dsrc/strcasestr.c | 25-------------------------
Dsrc/strexpandformat.c | 105-------------------------------------------------------------------------------
Dsrc/stringtostate.c | 16----------------
Dsrc/strlcat.c | 30------------------------------
Dsrc/strprintf.c | 13-------------
Dsrc/strvprintf.c | 32--------------------------------
Dsrc/sysrun.c | 24------------------------
Dsrc/tcpserve.c | 170-------------------------------------------------------------------------------
Dsrc/tellservice.c | 43-------------------------------------------
Dsrc/thruputlog.c | 64----------------------------------------------------------------
Dsrc/trafficlog.c | 66------------------------------------------------------------------
Dsrc/uidassume.c | 28----------------------------
Dsrc/uidrestore.c | 13-------------
Dsrc/unlockreporter.c | 26--------------------------
Dsrc/usage.c | 13-------------
Dsrc/usage.txt | 35-----------------------------------
Dsrc/vsyslog.c | 16----------------
Dsrc/wakeuphandler.c | 56--------------------------------------------------------
Dsrc/warning.c | 23-----------------------
Dsrc/writelog.c | 15---------------
Dsrc/xmalloc.c | 10----------
Dsrc/xrealloc.c | 27---------------------------
Dsrc/xstrcat.c | 19-------------------
Dsrc/xstrcatch.c | 14--------------
Dsrc/xstrdup.c | 16----------------
Mtools/gettools | 6+++++-
221 files changed, 12375 insertions(+), 11270 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,10 +1,19 @@ ChangeLog for Crossroads ------------------------------------------------------------------------------ +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). + to be fatal). 1.38 [KK 2007-04-26] Many changes: - 'crossroads status' now supports optional service/backend arguments. diff --git a/Makefile b/Makefile @@ -1,37 +1,39 @@ # Central Makefile for crossroads # ------------------------------- +BASE = $(shell sh -c pwd) include etc/Makefile.def foo: @cat etc/Makefile.help local: - $(MAKE) -C src + BASE=$(BASE) $(MAKE) -C src install: - $(MAKE) -C src install + BASE=$(BASE) $(MAKE) -C src install documentation: - $(MAKE) -C doc + BASE=$(BASE) $(MAKE) -C doc clean: - $(MAKE) -C src clean - $(MAKE) -C doc clean - find . -type f -name '*~' -exec rm {} \; - find . -type f -name .gdb_history -exec rm {} \; + BASE=$(BASE) $(MAKE) -C src clean + BASE=$(BASE) $(MAKE) -C doc clean + find $(BASE) -type f -name '*~' -exec rm {} \; + find $(BASE) -type f -name .gdb_history -exec rm {} \; distclean: - $(MAKE) -C src distclean - $(MAKE) -C doc distclean + BASE=$(BASE) $(MAKE) -C src distclean + BASE=$(BASE) $(MAKE) -C doc distclean dist: documentation - tools/e-ver ChangeLog $(VER) - tools/makedist $(VER) + $(BASE)/tools/e-ver ChangeLog $(VER) + $(BASE)/tools/makedist $(VER) commit: clean headers documentation local clean svn commit - svn commit -m 'Revision number update' etc/svnrev.txt + svn commit -m 'Revision number update' $(BASE)/etc/svnrev.txt headers: - tools/patch-header etc/hdr.template $(VER) src/*.c src/*.h + $(BASE)/tools/patch-header $(BASE)/etc/hdr.template $(VER) \ + src/*/*.c src/*.h diff --git a/doc/compiling.yo b/doc/compiling.yo @@ -35,8 +35,8 @@ itemization( of tt(Makefile.def) is suited for Linux or Apple MacOSX systems. On other Unices, or on non-Unix systems, you must particularly pay attention to tt(SET_PROC_TITLE_BY...). When - in doubt, comment out all tt(SET_PROC_TITLE...) - settings. Crossroads will work nevertheless, but it won't show + 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). diff --git a/doc/crossroads.html b/doc/crossroads.html @@ -1,12 +1,12 @@ <a name="defs.yo"></a><html><head> -<title>Crossroads 1.39</title> +<title>Crossroads 1.40</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.39</h1> +<h1>Crossroads 1.40</h1> <h2>Karel Kubat</h2> <h2>e-tunity</h2><h2>2005, 2006, ff.</h2> @@ -28,119 +28,122 @@ <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: Copyright and Disclaimer</a></dt> -<dt><a href="#l4">1.3: Terminology</a></dt> -<dt><a href="#l5">1.4: Porting issues for pre-1.21 installations</a></dt> -<dt><a href="#l6">1.5: Porting issues for pre-0.26 installations</a></dt> -<dt><a href="#l7">1.6: Porting issues for pre-1.08 installations</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 for pre-1.21 installations</a></dt> +<dt><a href="#l7">1.6: Porting issues for pre-0.26 installations</a></dt> +<dt><a href="#l8">1.7: Porting issues for pre-1.08 installations</a></dt> </dl> -<dt><h3><a href="#l8">2: Installation for the impatient</a></h3></dt> -<dt><h3><a href="#l9">3: Using Crossroads</a></h3></dt> +<dt><h3><a href="#l9">2: Installation for the impatient</a></h3></dt> +<dt><h3><a href="#l10">3: Using Crossroads</a></h3></dt> <dl> -<dt><a href="#l10">3.1: General Commandline Syntax</a></dt> -<dt><a href="#l11">3.2: Status Reporting</a></dt> -<dt><a href="#l12">3.3: Logging-related options</a></dt> -<dt><a href="#l13">3.4: Reloading Configurations</a></dt> +<dt><a href="#l11">3.1: General Commandline Syntax</a></dt> +<dt><a href="#l12">3.2: Status Reporting</a></dt> +<dt><a href="#l13">3.3: Logging-related options</a></dt> +<dt><a href="#l14">3.4: Reloading Configurations</a></dt> </dl> -<dt><h3><a href="#l14">4: The configuration</a></h3></dt> +<dt><h3><a href="#l15">4: The configuration</a></h3></dt> <dl> -<dt><a href="#l15">4.1: General language elements</a></dt> +<dt><a href="#l16">4.1: General language elements</a></dt> <dl> -<dt><a href="#l16">4.1.1: Empty lines and comments</a></dt> -<dt><a href="#l17">4.1.2: Keywords, numbers, identifiers, generic strings</a></dt> +<dt><a href="#l17">4.1.1: Empty lines and comments</a></dt> +<dt><a href="#l18">4.1.2: Keywords, numbers, identifiers, generic strings</a></dt> </dl> -<dt><a href="#l18">4.2: Service definitions</a></dt> +<dt><a href="#l19">4.2: Service definitions</a></dt> <dl> -<dt><a href="#l19">4.2.1: type - Defining the service type</a></dt> -<dt><a href="#l20">4.2.2: port - Specifying the listen port</a></dt> -<dt><a href="#l21">4.2.3: bindto - Binding to a specific IP address</a></dt> -<dt><a href="#l22">4.2.4: verbosity - Controlling debug output</a></dt> -<dt><a href="#l23">4.2.5: dispatchmode - How are back ends selected</a></dt> -<dt><a href="#l24">4.2.6: revivinginterval - Back end wakeup calls</a></dt> -<dt><a href="#l25">4.2.7: maxconnections - Limiting concurrent clients at service level</a></dt> -<dt><a href="#l26">4.2.8: backlog - The TCP Back Log size</a></dt> -<dt><a href="#l27">4.2.9: shmkey - Shared Memory Access</a></dt> -<dt><a href="#l28">4.2.10: allow* and deny* - Allowing or denying connections</a></dt> -<dt><a href="#l29">4.2.11: useraccount - Limiting the effective ID of external processes</a></dt> +<dt><a href="#l20">4.2.1: type - Defining the service type</a></dt> +<dt><a href="#l21">4.2.2: port - Specifying the listen port</a></dt> +<dt><a href="#l22">4.2.3: bindto - Binding to a specific IP address</a></dt> +<dt><a href="#l23">4.2.4: verbosity - Controlling debug output</a></dt> +<dt><a href="#l24">4.2.5: dispatchmode - How are back ends selected</a></dt> +<dt><a href="#l25">4.2.6: revivinginterval - Back end wakeup calls</a></dt> +<dt><a href="#l26">4.2.7: maxconnections - Limiting concurrent clients at service level</a></dt> +<dt><a href="#l27">4.2.8: backlog - The TCP Back Log size</a></dt> +<dt><a href="#l28">4.2.9: shmkey - Shared Memory Access</a></dt> +<dt><a href="#l29">4.2.10: allow* and deny* - Allowing or denying connections</a></dt> +<dt><a href="#l30">4.2.11: useraccount - Limiting the effective ID of external processes</a></dt> </dl> -<dt><a href="#l30">4.3: Backend definitions</a></dt> +<dt><a href="#l31">4.3: Backend definitions</a></dt> <dl> -<dt><a href="#l31">4.3.1: server - Specifying the back end address</a></dt> -<dt><a href="#l32">4.3.2: verbosity - Controlling verbosity at the back end level</a></dt> -<dt><a href="#l33">4.3.3: retries - Specifying allowed failures</a></dt> -<dt><a href="#l34">4.3.4: weight - When a back end is more equal than others</a></dt> -<dt><a href="#l35">4.3.5: decay - Levelling out activity of a back end</a></dt> -<dt><a href="#l36">4.3.6: onstart, onend, onfail - Action Hooks</a></dt> -<dt><a href="#l37">4.3.7: trafficlog and throughputlog - Debugging and Performance Aids</a></dt> -<dt><a href="#l38">4.3.8: stickycookie - Back end selection with an HTTP cookie</a></dt> -<dt><a href="#l39">4.3.9: HTTP Header Modification Directives</a></dt> +<dt><a href="#l32">4.3.1: server - Specifying the back end address</a></dt> +<dt><a href="#l33">4.3.2: verbosity - Controlling verbosity at the back end level</a></dt> +<dt><a href="#l34">4.3.3: retries - Specifying allowed failures</a></dt> +<dt><a href="#l35">4.3.4: weight - When a back end is more equal than others</a></dt> +<dt><a href="#l36">4.3.5: decay - Levelling out activity of a back end</a></dt> +<dt><a href="#l37">4.3.6: onstart, onend, onfail - Action Hooks</a></dt> +<dt><a href="#l38">4.3.7: trafficlog and throughputlog - Debugging and Performance Aids</a></dt> +<dt><a href="#l39">4.3.8: stickycookie - Back end selection with an HTTP cookie</a></dt> +<dt><a href="#l40">4.3.9: HTTP Header Modification Directives</a></dt> </dl> </dl> -<dt><h3><a href="#l40">5: Tips, Tricks and Random Remarks</a></h3></dt> +<dt><h3><a href="#l41">5: Tips, Tricks and Random Remarks</a></h3></dt> <dl> -<dt><a href="#l41">5.1: How back ends are selected in load balancing</a></dt> +<dt><a href="#l42">5.1: How back ends are selected in load balancing</a></dt> <dl> -<dt><a href="#l42">5.1.1: Bysize, byduration or byconnections?</a></dt> -<dt><a href="#l43">5.1.2: Averaging size and duration</a></dt> -<dt><a href="#l44">5.1.3: Specifying decays</a></dt> -<dt><a href="#l45">5.1.4: Adjusting the weights</a></dt> +<dt><a href="#l43">5.1.1: Bysize, byduration or byconnections?</a></dt> +<dt><a href="#l44">5.1.2: Averaging size and duration</a></dt> +<dt><a href="#l45">5.1.3: Specifying decays</a></dt> +<dt><a href="#l46">5.1.4: Adjusting the weights</a></dt> </dl> -<dt><a href="#l46">5.2: Throttling the number of concurrent connections</a></dt> -<dt><a href="#l47">5.3: Using an external program to dispatch</a></dt> +<dt><a href="#l47">5.2: Throttling the number of concurrent connections</a></dt> +<dt><a href="#l48">5.3: Using an external program to dispatch</a></dt> <dl> -<dt><a href="#l48">5.3.1: Configuring the external handler</a></dt> -<dt><a href="#l49">5.3.2: Writing the external handler</a></dt> -<dt><a href="#l50">5.3.3: Examples of external handlers</a></dt> +<dt><a href="#l49">5.3.1: Configuring the external handler</a></dt> +<dt><a href="#l50">5.3.2: Writing the external handler</a></dt> +<dt><a href="#l51">5.3.3: Examples of external handlers</a></dt> </dl> -<dt><a href="#l51">5.4: TCP Session Stickiness</a></dt> -<dt><a href="#l52">5.5: HTTP Session Stickiness</a></dt> +<dt><a href="#l52">5.4: TCP Session Stickiness</a></dt> +<dt><a href="#l53">5.5: HTTP Session Stickiness</a></dt> <dl> -<dt><a href="#l53">5.5.1: Don't use stickiness!</a></dt> -<dt><a href="#l54">5.5.2: But if you must..</a></dt> +<dt><a href="#l54">5.5.1: Don't use stickiness!</a></dt> +<dt><a href="#l55">5.5.2: But if you must..</a></dt> </dl> -<dt><a href="#l55">5.6: Passing the client's IP address</a></dt> +<dt><a href="#l56">5.6: Passing the client's IP address</a></dt> <dl> -<dt><a href="#l56">5.6.1: Sample Crossroads configuration</a></dt> -<dt><a href="#l57">5.6.2: Sample Apache configuration</a></dt> +<dt><a href="#l57">5.6.1: Sample Crossroads configuration</a></dt> +<dt><a href="#l58">5.6.2: Sample Apache configuration</a></dt> </dl> -<dt><a href="#l58">5.7: Debugging network traffic</a></dt> -<dt><a href="#l59">5.8: IP filtering: Limiting Access by Client IP Address</a></dt> +<dt><a href="#l59">5.7: Debugging network traffic</a></dt> +<dt><a href="#l60">5.8: IP filtering: Limiting Access by Client IP Address</a></dt> <dl> -<dt><a href="#l60">5.8.1: General Examples</a></dt> -<dt><a href="#l61">5.8.2: Using External Files</a></dt> -<dt><a href="#l62">5.8.3: Mixing Directives</a></dt> +<dt><a href="#l61">5.8.1: General Examples</a></dt> +<dt><a href="#l62">5.8.2: Using External Files</a></dt> +<dt><a href="#l63">5.8.3: Mixing Directives</a></dt> </dl> -<dt><a href="#l63">5.9: Configuration examples</a></dt> +<dt><a href="#l64">5.9: Configuration examples</a></dt> <dl> -<dt><a href="#l64">5.9.1: A load balancer for three webserver back ends</a></dt> -<dt><a href="#l65">5.9.2: An HTTP forwarder when travelling</a></dt> -<dt><a href="#l66">5.9.3: SSH login with enforced idle logout</a></dt> +<dt><a href="#l65">5.9.1: A load balancer for three webserver back ends</a></dt> +<dt><a href="#l66">5.9.2: An HTTP forwarder when travelling</a></dt> +<dt><a href="#l67">5.9.3: SSH login with enforced idle logout</a></dt> </dl> -<dt><a href="#l67">5.10: Linux and ip_conntrack_max</a></dt> -<dt><a href="#l68">5.11: Marking back ends as bad after more than one try</a></dt> +<dt><a href="#l68">5.10: Linux and ip_conntrack_max</a></dt> +<dt><a href="#l69">5.11: Marking back ends as bad after more than one try</a></dt> +<dt><a href="#l70">5.12: Scripting Crossroads' back end availability</a></dt> +<dt><a href="#l71">5.13: Rendering Crossroads' status in a web page</a></dt> </dl> -<dt><h3><a href="#l69">6: Benchmarking</a></h3></dt> +<dt><h3><a href="#l72">6: Benchmarking</a></h3></dt> <dl> -<dt><a href="#l70">6.1: Benchmark 1: Accessing a proxy via crossroads or directly</a></dt> +<dt><a href="#l73">6.1: Benchmark 1: Accessing a proxy via crossroads or directly</a></dt> <dl> -<dt><a href="#l71">6.1.1: Results</a></dt> -<dt><a href="#l72">6.1.2: Discussion</a></dt> +<dt><a href="#l74">6.1.1: Results</a></dt> +<dt><a href="#l75">6.1.2: Discussion</a></dt> </dl> -<dt><a href="#l73">6.2: Benchmark 2: Crossroads versus Linux Virtual Server (LVS)</a></dt> +<dt><a href="#l76">6.2: Benchmark 2: Crossroads versus Linux Virtual Server (LVS)</a></dt> <dl> -<dt><a href="#l74">6.2.1: Environment</a></dt> -<dt><a href="#l75">6.2.2: Tests and results</a></dt> +<dt><a href="#l77">6.2.1: Environment</a></dt> +<dt><a href="#l78">6.2.2: Tests and results</a></dt> </dl> </dl> -<dt><h3><a href="#l76">7: Compiling and Installing</a></h3></dt> +<dt><h3><a href="#l79">7: Compiling and Installing</a></h3></dt> <dl> -<dt><a href="#l77">7.1: Prerequisites</a></dt> -<dt><a href="#l78">7.2: Compiling and installing</a></dt> -<dt><a href="#l79">7.3: Configuring crossroads</a></dt> -<dt><a href="#l80">7.4: A boot script</a></dt> +<dt><a href="#l80">7.1: Prerequisites</a></dt> +<dt><a href="#l81">7.2: Compiling and installing</a></dt> +<dt><a href="#l82">7.3: Configuring crossroads</a></dt> +<dt><a href="#l83">7.4: A boot script</a></dt> <dl> -<dt><a href="#l81">7.4.1: SysV Style Startup</a></dt> -<dt><a href="#l82">7.4.2: BSD Style Startup</a></dt> +<dt><a href="#l84">7.4.1: SysV Style Startup</a></dt> +<dt><a href="#l85">7.4.2: BSD Style Startup</a></dt> </dl> <p><hr><p> @@ -193,7 +196,29 @@ As quick reference, here are some important URL's for Crossroads: credentials.</ul> <p> <a name="l3"></a> -<h3>1.2: Copyright and Disclaimer</h3> +<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 (normally + <code>/etc/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 @@ -213,8 +238,8 @@ 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="l4"></a> -<h3>1.3: Terminology</h3> +<a name="l5"></a> +<h3>1.4: Terminology</h3> <p> Throughout this document, the following terms are used: &nbsp;(Many more meanings of the terms will exist -- yes, I am aware of that. I'm @@ -305,8 +330,8 @@ using the terms here in a very strict sense.) controlled manner, without any client noticing it. </dl> <p> -<a name="l5"></a> -<h3>1.4: Porting issues for pre-1.21 installations</h3> +<a name="l6"></a> +<h3>1.5: Porting issues for pre-1.21 installations</h3> <p> As of version 1.21, the event-hook directives <code>onsuccess</code> and <code>onfailure</code> no longer exists. @@ -320,8 +345,8 @@ The commands that are run via <code>onstart</code>, <code>onend</code> or <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="l6"></a> -<h3>1.5: Porting issues for pre-0.26 installations</h3> +<a name="l7"></a> +<h3>1.6: Porting issues for pre-0.26 installations</h3> <p> As of version 0.26 the syntax of the configuration file has changed. In particular: @@ -339,8 +364,8 @@ Therefore when converting configuration files to the new syntax, <em>session</em> is used strictly in that sense -- and no longer for a TCP connection.) <p> -<a name="l7"></a> -<h3>1.6: Porting issues for pre-1.08 installations</h3> +<a name="l8"></a> +<h3>1.7: Porting issues for pre-1.08 installations</h3> <p> As of version 1.08, the following directives no longer are supported: @@ -360,7 +385,7 @@ As of version 1.08, the following directives no longer are This incidentally also makes it possible to change the header name (here: <code>XR-Real-IP</code>).</ul> <p> -<a name="l8"></a> +<a name="l9"></a> <h2>2: Installation for the impatient</h2> <a name="impatient"></a> For the impatient, here's the very-quick-but-very-superficial recipy @@ -430,7 +455,7 @@ That's off course assuming that you want to balance HTTP on status</code>. </ul> <p> -<a name="l9"></a> +<a name="l10"></a> <h2>3: Using Crossroads</h2> <a name="using"></a>Crossroads is started from the commandline, and highly depends on <code>/etc/crossroads.conf</code> (the default configuration file). It @@ -439,7 +464,12 @@ configuration file). The actual usage information is always obtained by typing <code>crossroads</code> without any arguments. Crossroads then displays the allowed arguments. <p> -<a name="l10"></a> +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="l11"></a> <h3>3.1: General Commandline Syntax</h3> <p> This section shows the most basic usage. As said above, start @@ -475,7 +505,7 @@ This section shows the most basic usage. As said above, start configuration <code>/etc/crossroads.conf</code>. </ul> <p> -<a name="l11"></a> +<a name="l12"></a> <h3>3.2: Status Reporting</h3> <p> The command <code>crossroads status</code> shows a verbose human-readable @@ -505,7 +535,11 @@ follows: Crossroads not to use the back end are in caps. The series is repeated for all back ends of the given service.</ul> <p> -<a name="l12"></a> +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. +<p> +<a name="l13"></a> <h3>3.3: Logging-related options</h3> <p> Two 'flags' of Crossroads are specifically logging-related. This @@ -548,7 +582,7 @@ That instructs <code>syslogd</code> to send <code>LOG_LOCAL7</code> requests to <li> Finally, monitor <code>/var/log/crossroads.log</code> for Crossroads' messages.</ul> <p> -<a name="l13"></a> +<a name="l14"></a> <h3>3.4: Reloading Configurations</h3> <p> Crossroads doesn't support the reloading of a configuration while @@ -559,7 +593,7 @@ However, external lists of allowed or denied IP addresses can be reloaded by sending a signal -1 (<code>SIGHUP</code>) to Crossroads. See section <a href="crossroads.html#servicedef">4.2</a> for the details. <p> -<a name="l14"></a> +<a name="l15"></a> <h2>4: The configuration</h2> <a name="config"></a>The configuration that crossroads uses is normally stored in the file <code>/etc/crossroads.conf</code>. This location can be overruled using the @@ -568,13 +602,13 @@ command line flag <code>-c</code>. This section explains the syntax of the configuration file, and what all settings do. <p> -<a name="l15"></a> +<a name="l16"></a> <h3>4.1: General language elements</h3> <p> This section describes the general elements of the crossroads configuration language. <p> -<a name="l16"></a> +<a name="l17"></a> <strong>4.1.1: Empty lines and comments</strong> <p> Empty lines are of course allowed in the @@ -592,7 +626,7 @@ best'.&nbsp;(I favor C or C++ comment. My favorite editor <em>emacs</em> can be put in <code>cmode</code> and nicely highlight what's comment and what's not. And as a bonus it will auto-indent the configuration!) <p> -<a name="l17"></a> +<a name="l18"></a> <strong>4.1.2: Keywords, numbers, identifiers, generic strings</strong> <p> In a configuration file, statements are identified by <em>keywords</em>, @@ -627,7 +661,7 @@ Finally, an argument can be a 'boolean' value. Crossroads knows <code>true</code>, <code>yes</code> and <code>on</code> all mean the same and can be used interchangeably; as can the keywords <code>false</code>, <code>no</code> and <code>off</code>. <p> -<a name="l18"></a> +<a name="l19"></a> <h3>4.2: Service definitions</h3> <a name="servicedef"></a> <p> Service definitions are blocks in the configuration file that @@ -651,7 +685,7 @@ identifying names differ. The following list shows possible statements. Each statement must end with a semicolon, except for the <code>backend</code> statement, which has is own block (more on this later). <p> -<a name="conf/type"></a><a name="l19"></a> +<a name="conf/type"></a><a name="l20"></a> <strong>4.2.1: type - Defining the service type</strong> <a name="conftype - Defining the service type"></a> <dl> <p><dt><strong>Description:</strong><dd> The <code>type</code> statement defines how crossroads handles the stated @@ -671,7 +705,7 @@ Unless you really need such special features, use the type <code>any</code> (the <p><dt><strong>Default:</strong><dd> <code>any</code> </dl> <p> -<a name="conf/port"></a><a name="l20"></a> +<a name="conf/port"></a><a name="l21"></a> <strong>4.2.2: port - Specifying the listen port</strong> <a name="confport - Specifying the listen port"></a> <dl> <p><dt><strong>Description:</strong><dd> The <code>port</code> statement defines to which TCP port a service @@ -681,7 +715,7 @@ Unless you really need such special features, use the type <code>any</code> (the <p><dt><strong>Default:</strong><dd> There is no default. This is a required setting. </dl> <p> -<a name="conf/bindto"></a><a name="l21"></a> +<a name="conf/bindto"></a><a name="l22"></a> <strong>4.2.3: bindto - Binding to a specific IP address</strong> <a name="confbindto - Binding to a specific IP address"></a> <dl> <p><dt><strong>Description:</strong><dd> The <code>bindto</code> statement is used in situations where crossroads @@ -695,7 +729,7 @@ Unless you really need such special features, use the type <code>any</code> (the <p><dt><strong>Default:</strong><dd> <code>any</code> </dl> <p> -<a name="conf/verbose"></a><a name="l22"></a> +<a name="conf/verbose"></a><a name="l23"></a> <strong>4.2.4: verbosity - Controlling debug output</strong> <a name="confverbosity - Controlling debug output"></a> <dl> <p><dt><strong>Description:</strong><dd> Verbosity statements come in two forms: <code>verbosity on</code> or @@ -712,7 +746,7 @@ Unless you really need such special features, use the type <code>any</code> (the <p><dt><strong>Default:</strong><dd> <code>off</code> </dl> <p> -<a name="conf/dispatchmode"></a><a name="l23"></a> +<a name="conf/dispatchmode"></a><a name="l24"></a> <strong>4.2.5: dispatchmode - How are back ends selected</strong> <a name="confdispatchmode - How are back ends selected"></a> <dl> <p><dt><strong>Description:</strong><dd> The dispatch mode controls how crossroads selects a back end from @@ -799,7 +833,7 @@ Your 'right' dispatch mode will depend on the type of service. Given <p><dt><strong>Default:</strong><dd> <code>roundrobin</code> </dl> <p> -<a name="conf/revivinginterval"></a><a name="l24"></a> +<a name="conf/revivinginterval"></a><a name="l25"></a> <strong>4.2.6: revivinginterval - Back end wakeup calls</strong> <a name="confrevivinginterval - Back end wakeup calls"></a> <dl> <p><dt><strong>Description:</strong><dd> A reviving interval definition is needed when crossroads @@ -821,7 +855,7 @@ An example of the definition is <code>revivinginterval 10</code>. When this <p><dt><strong>Default:</strong><dd> 0 (no wakeup calls) </dl> <p> -<a name="conf/maxconnections"></a><a name="l25"></a> +<a name="conf/maxconnections"></a><a name="l26"></a> <strong>4.2.7: maxconnections - Limiting concurrent clients at service level</strong> <a name="confmaxconnections - Limiting concurrent clients at service level"></a> <dl> <p><dt><strong>Description:</strong><dd> The maximum number of connections is specified using @@ -837,7 +871,7 @@ An example of the definition is <code>revivinginterval 10</code>. When this <p><dt><strong>Default:</strong><dd> 0, meaning that all connections will be accepted. </dl> <p> -<a name="conf/backlog"></a><a name="l26"></a> +<a name="conf/backlog"></a><a name="l27"></a> <strong>4.2.8: backlog - The TCP Back Log size</strong> <a name="confbacklog - The TCP Back Log size"></a> <dl> <p><dt><strong>Description:</strong><dd> The TCP back log size is a number that controls how many @@ -853,7 +887,7 @@ An example of the definition is <code>revivinginterval 10</code>. When this value for socket back log size. </dl> <p> -<a name="conf/shmkey"></a><a name="l27"></a> +<a name="conf/shmkey"></a><a name="l28"></a> <strong>4.2.9: shmkey - Shared Memory Access</strong> <a name="confshmkey - Shared Memory Access"></a> <dl> <p><dt><strong>Description:</strong><dd> Different Crossroads @@ -874,7 +908,7 @@ The actual key value doesn't matter much, as long as it's unique own key, based on TCP port and a magic number. </dl> <p> -<a name="conf/allow"></a><a name="l28"></a> +<a name="conf/allow"></a><a name="l29"></a> <strong>4.2.10: allow* and deny* - Allowing or denying connections</strong> <a name="confallow* and deny* - Allowing or denying connections"></a> <dl> <p><dt><strong>Description:</strong><dd> Crossroads can allow or deny @@ -943,7 +977,7 @@ This is probably best explained by a few examples: <p><dt><strong>Default:</strong><dd> In absence of these statements, all client IP's are accepted. </dl> <p> -<a name="conf/useraccount"></a><a name="l29"></a> +<a name="conf/useraccount"></a><a name="l30"></a> <strong>4.2.11: useraccount - Limiting the effective ID of external processes</strong> <a name="confuseraccount - Limiting the effective ID of external processes"></a> <dl> <p><dt><strong>Description:</strong><dd> Using the directive <code>useraccount</code>, the effective user and group @@ -961,7 +995,7 @@ This is probably best explained by a few examples: ID that was in effect when Crossroads was started. </dl> <p> -<a name="l30"></a> +<a name="l31"></a> <h3>4.3: Backend definitions</h3> <p> Inside the service definitions as are described in the previous @@ -997,7 +1031,7 @@ Crossroads treats the network traffic as a stream of HTTP messages; i.e., when the service is declared with <code>type http</code>. Incase of <code>type any</code>, the HTTP-specific directives have no effect. <p> -<a name="conf/server.yo"></a><a name="l31"></a> +<a name="conf/server.yo"></a><a name="l32"></a> <strong>4.3.1: server - Specifying the back end address</strong> <a name="confserver - Specifying the back end address"></a> <dl> <p><dt><strong>Description:</strong><dd> Each back end must be identified by the network name @@ -1011,7 +1045,7 @@ i.e., when the service is declared with <code>type http</code>. Incase of <p><dt><strong>Default:</strong><dd> There is no default. This is a required setting. </dl> <p> -<a name="conf/verbose-backend.yo"></a><a name="l32"></a> +<a name="conf/verbose-backend.yo"></a><a name="l33"></a> <strong>4.3.2: verbosity - Controlling verbosity at the back end level</strong> <a name="confverbosity - Controlling verbosity at the back end level"></a> <dl> <p><dt><strong>Description:</strong><dd> Similar to <code>service</code> specifications, a @@ -1025,7 +1059,7 @@ i.e., when the service is declared with <code>type http</code>. Incase of <p><dt><strong>Default:</strong><dd> <code>off</code> </dl> <p> -<a name="conf/retries.yo"></a><a name="l33"></a> +<a name="conf/retries.yo"></a><a name="l34"></a> <strong>4.3.3: retries - Specifying allowed failures</strong> <a name="confretries - Specifying allowed failures"></a> <dl> <p><dt><strong>Description:</strong><dd> Back ends that are 'flaky' or on a less reliable network can be @@ -1040,7 +1074,7 @@ i.e., when the service is declared with <code>type http</code>. Incase of connection. </dl> <p> -<a name="conf/weight"></a><a name="l34"></a> +<a name="conf/weight"></a><a name="l35"></a> <strong>4.3.4: weight - When a back end is more equal than others</strong> <a name="confweight - When a back end is more equal than others"></a> <dl> <p><dt><strong>Description:</strong><dd> To influence how backends are selected, a backend can specify its @@ -1059,7 +1093,7 @@ The weighing mechanism only applies to the dispatch modes <p><dt><strong>Default:</strong><dd> 1; all back ends have equal weight. </dl> <p> -<a name="conf/decay"></a><a name="l35"></a> +<a name="conf/decay"></a><a name="l36"></a> <strong>4.3.5: decay - Levelling out activity of a back end</strong> <a name="confdecay - Levelling out activity of a back end"></a> <dl> <p><dt><strong>Description:</strong><dd> To make sure that a 'spike' of activity doesn't @@ -1081,7 +1115,7 @@ This means that when a given back end is hit, then its usage data <p><dt><strong>Default:</strong><dd> 0, meaning that no decay is applied to usage statistics. </dl> <p> -<a name="conf/onhooks"></a><a name="l36"></a> +<a name="conf/onhooks"></a><a name="l37"></a> <strong>4.3.6: onstart, onend, onfail - Action Hooks</strong> <a name="confonstart, onend, onfail - Action Hooks"></a> <dl> <p><dt><strong>Description:</strong><dd> The three directives <code>onstart</code>, <code>onend</code> and <code>onfail</code> can be @@ -1133,7 +1167,7 @@ The format is always <code>on</code><em>type</em> <em>command</em>. The <em>comm connection, success or failure of a back end. </dl> <p> -<a name="conf/trafficlog"></a><a name="l37"></a> +<a name="conf/trafficlog"></a><a name="l38"></a> <strong>4.3.7: trafficlog and throughputlog - Debugging and Performance Aids</strong> <a name="conftrafficlog and throughputlog - Debugging and Performance Aids"></a> <dl> <p><dt><strong>Description:</strong><dd> Two directives are available @@ -1153,7 +1187,7 @@ The <code>throughputlog</code> statement writes shorthand transmissions to <p><dt><strong>Default:</strong><dd> none </dl> <p> -<a name="conf/stickycookie"></a><a name="l38"></a> +<a name="conf/stickycookie"></a><a name="l39"></a> <strong>4.3.8: stickycookie - Back end selection with an HTTP cookie</strong> <a name="confstickycookie - Back end selection with an HTTP cookie"></a> <dl> <p><dt><strong>Description:</strong><dd> The directive <code>stickycookie</code> <em>value</em> @@ -1193,7 +1227,7 @@ There are basically to provide such cookies to a browser. First, a <p><dt><strong>Default:</strong><dd> There is no default. </dl> <p> -<a name="conf/addclientheader"></a><a name="l39"></a> +<a name="conf/addclientheader"></a><a name="l40"></a> <strong>4.3.9: HTTP Header Modification Directives</strong> <a name="confHTTP Header Modification Directives"></a> <dl> <p><dt><strong>Description:</strong><dd> Crossroads understands the following @@ -1369,13 +1403,13 @@ service ... { <p><dt><strong>Default:</strong><dd> There is no default. </dl> <p> -<a name="l40"></a> +<a name="l41"></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="l41"></a> +<a name="l42"></a> <h3>5.1: How back ends are selected in load balancing</h3> <a name="howselected"></a> <a name="tips/howselected"></a>In order to tune your load balancing, you'll need to understand how crossroads computes usage, how weighing works, and so on. In this @@ -1383,7 +1417,7 @@ section we'll focus on the dispatching modes <code>bysize</code>, <code>bydurati and <code>byconnections</code> only. The other dispatching types are self-explanatory. <p> -<a name="l42"></a> +<a name="l43"></a> <strong>5.1.1: Bysize, byduration or byconnections?</strong> <p> As stated before, crossroads doesn't know 'what a service does' and @@ -1433,7 +1467,7 @@ E.g., consider a database connection. What's <p> </ul> <p> -<a name="l43"></a> +<a name="l44"></a> <strong>5.1.2: Averaging size and duration</strong> <p> The configuration statement <code>dispatchmode bysize</code> or <code>byduration</code> @@ -1454,7 +1488,7 @@ In contrast, when e.g. <code>over 3</code> is in effect, then a sudden load does show up -- because it highly contributes to the average of three connections. <p> -<a name="l44"></a> +<a name="l45"></a> <strong>5.1.3: Specifying decays</strong> <p> Decays are also only relevant when crossroads computes the 'next best @@ -1508,7 +1542,7 @@ service soap { </pre> <p> -<a name="l45"></a> +<a name="l46"></a> <strong>5.1.4: Adjusting the weights</strong> <p> The back end modifier <code>weight</code> is useful in situations where your @@ -1562,7 +1596,7 @@ both A and B crash). Note also that A's usage data decay much faster than B's and C's: we're assuming that this big server recovers quicker than its smaller siblings. <p> -<a name="l46"></a> +<a name="l47"></a> <h3>5.2: Throttling the number of concurrent connections</h3> <a name="tips/throttling"></a>If you suspect that your service may occasionally receive 'spikes' of activity&nbsp;(which you should always assume), then it might be a @@ -1591,14 +1625,14 @@ 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="l47"></a> +<a name="l48"></a> <h3>5.3: Using an external program to dispatch</h3> <a name="externalhandler"></a> <a name="tips/externalhandler"></a>As mentioned before, Crossroads supports several built-in dispatch modes. However, you are always free to hook-in your own dispatch mode that determines the next back end using your own specific algorithm. This section explains how to do it. <p> -<a name="l48"></a> +<a name="l49"></a> <strong>5.3.1: Configuring the external handler</strong> <p> First, the <code>dispatchmode</code> statement needs to inform Crossroads that @@ -1637,7 +1671,7 @@ Note that the format specifiers such as <code>%b</code> don't make sense in the phase in which an external handler is called, since there is no current back end yet (the job of the handler is to supply one). <p> -<a name="l49"></a> +<a name="l50"></a> <strong>5.3.2: Writing the external handler</strong> <p> The external handler is activated using the arguments that are @@ -1646,7 +1680,7 @@ 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="l50"></a> +<a name="l51"></a> <strong>5.3.3: Examples of external handlers</strong> <p> This section shows some examples of Crossroads configurations @@ -2075,7 +2109,7 @@ if ($action eq 'dispatch') { </pre> <p> -<a name="l51"></a> +<a name="l52"></a> <h3>5.4: TCP Session Stickiness</h3> <a name="tips/tcpstickiness"></a>If you need to make sure that a client that once gets dispatched to a given back end keeps re-visiting the back end, then Crossroads offers @@ -2100,7 +2134,7 @@ 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="l52"></a> +<a name="l53"></a> <h3>5.5: HTTP Session Stickiness</h3> <a name="tips/httpstickiness"></a>This section focuses on HTTP session stickiness. This term refers to the ability of a balancer to route a conversation between browser and @@ -2108,7 +2142,7 @@ 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="l53"></a> +<a name="l54"></a> <strong>5.5.1: Don't use stickiness!</strong> <p> The rule of thumb as far as the balancer is concerned, is: <strong>Do not @@ -2140,7 +2174,7 @@ that all PHP applications have access to these data. Application servers such as Websphere can be configured to replicate session data between nodes. <p> -<a name="l54"></a> +<a name="l55"></a> <strong>5.5.2: But if you must..</strong> <p> If you really need stickiness, think first whether you might use TCP @@ -2218,7 +2252,7 @@ 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="l55"></a> +<a name="l56"></a> <h3>5.6: Passing the client's IP address</h3> <a name="tips/clientip"></a>Since Crossroads just shuttles bytes to and fro, meta-information of network connections is lost. As far as the back ends are concerned, @@ -2245,7 +2279,7 @@ header: <code>X-Real-IP</code>, holding the client's IP address. performance will be hampered -- all passing messages will have to be unpacked and analyzed. <p> -<a name="l56"></a> +<a name="l57"></a> <strong>5.6.1: Sample Crossroads configuration</strong> <p> The below sample configuration shows two HTTP back ends that receive @@ -2272,7 +2306,7 @@ service www { </pre> <p> -<a name="l57"></a> +<a name="l58"></a> <strong>5.6.2: Sample Apache configuration</strong> <p> The method by which each back end analyzes the header <code>X-Real-IP</code> @@ -2304,7 +2338,7 @@ LogFormat "%{X-Real-IP}i %l %u %t %D \"%r\" %&gt;s %b" common </pre> <p> -<a name="l58"></a> +<a name="l59"></a> <h3>5.7: Debugging network traffic</h3> <a name="tips/debugging"></a> Incase the traffic between client and backend @@ -2427,9 +2461,9 @@ Summarizing, the throughput times of a client-back end connection analyze the output and to compute round trip times. Such scripts are not (yet) included in Crossroads. <p> -<a name="l59"></a> +<a name="l60"></a> <h3>5.8: IP filtering: Limiting Access by Client IP Address</h3> -<a name="tips/ipfiltering"></a><a name="l60"></a> +<a name="tips/ipfiltering"></a><a name="l61"></a> <strong>5.8.1: General Examples</strong> <p> The directives <code>allowfrom</code>, <code>denyfrom</code>, <code>allowfile</code> and @@ -2466,7 +2500,7 @@ 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="l61"></a> +<a name="l62"></a> <strong>5.8.2: Using External Files</strong> <p> The directives <code>allowfile</code> and <code>denyfile</code> allow you to specify IP @@ -2498,7 +2532,7 @@ is running, you may edit <code>/tmp/allow.txt</code>, and then issue <code>killa -1 crossroads</code>. The new contents of <code>/tmp/allow.txt</code> will be reloaded. <p> -<a name="l62"></a> +<a name="l63"></a> <strong>5.8.3: Mixing Directives</strong> <p> Crossroads allows to mix all directives in one service @@ -2565,10 +2599,10 @@ Crossroads only performs syntactic checking of the configuration. Some of the above samples are syntactically correct, but make no semantic sense: Crossroads doesn't warn for such situations. <p> -<a name="l63"></a> +<a name="l64"></a> <h3>5.9: Configuration examples</h3> <a name="tips/examples"></a> -<a name="l64"></a> +<a name="l65"></a> <strong>5.9.1: A load balancer for three webserver back ends</strong> <p> The following configuration example binds crossroads to port 80 of the @@ -2697,7 +2731,7 @@ service www { </pre> <p> -<a name="l65"></a> +<a name="l66"></a> <strong>5.9.2: An HTTP forwarder when travelling</strong> <p> As another example, here's my <code>crossroads.conf</code> that I use on my @@ -2786,7 +2820,7 @@ and <code>LocalSquid</code> are both active, then <code>crossroads tell httpprox sshtunnel down</code> will 'take down' the back end <code>SshTunnel</code> -- and will automatically cause crossroads to switch to <code>LocalSquid</code>. <p> -<a name="l66"></a> +<a name="l67"></a> <strong>5.9.3: SSH login with enforced idle logout</strong> <p> The following example shows how crossroads 'throttles' SSH @@ -2812,7 +2846,7 @@ service Ssh { </pre> <p> -<a name="l67"></a> +<a name="l68"></a> <h3>5.10: Linux and ip_conntrack_max</h3> <a name="tips/ipconntrackmax"></a>The kernel value of <code>ip_conntrack_max</code> is important for routers and balancers under Linux. Basically it's the maximum number of tracked @@ -2849,7 +2883,7 @@ out yourself. Note however that each count will cause the kernel to reserve 350 bytes. So if you set <code>ip_conntrack_max</code> to 100.000, then you're already taking 33.3Mb off the total available memory. <p> -<a name="l68"></a> +<a name="l69"></a> <h3>5.11: Marking back ends as bad after more than one try</h3> <a name="tips/retries"></a>Crossroads allows you to specify on a per-back end basis how many retries are needed before a back end is considered unavailable. The @@ -2894,13 +2928,246 @@ retry connecting with a small one-second delay in between. A high <code>retries</code> number means also lots of one-second delays, in which time a client is kept waiting. <p> -<a name="l69"></a> +<a name="l70"></a> +<h3>5.12: Scripting Crossroads' back end availability</h3> +<a name="tips/scripting"></a>The internal reviving model of Crossroads can periodically check +whether back ends that are unavailable have woken up yet. The checker +is triggered by a <code>revivinginterval</code> statement of a service +description, as in: +<p> +<pre> +service web { + port 80; + revivinginterval 5; + + backend one { + server 10.1.1.1:80; + } + + backend two { + server 10.1.1.2:80; + } +} +</pre> + +<p> +This instructs Crossroads to check back ends <code>one</code> or <code>two</code> each 5 +seconds. A back end is considered available when it accepts TCP +connections on the given IP address and port. +<p> +This approach may not be sufficient in all situations. E.g., a web +server may 'hang': it might accept a connection, but never serve +it. Or, an application server may serve simple connections, but if its +database is offline, it will generate internal server errors on pages +that try to access data. +<p> +In such situations you may want to replace the internal wakeup service +with your own scripted 'health check'. Here's how: +<p> +<ul> + <li> First of all, you take out the <code>revivinginterval</code> + statement of <code>/etc/crossroads.conf</code>, so that Crossroads' + internal check which only verifies TCP connectivity is + disabled. +<p> +<li> You determine a suitable URL in the applications that can + be queried for the health. In our example this will be + <code>/areyouthere.jsp</code>, a hypothetical page that does some + database access. It doesn't even need to return output; just + succeed, or fail. +<p> +<li> You devise a small script that asks Crossroads the status + of back ends of a given service (in our example, service + <code>web</code>). +<p> +<li> The health check script starts by querying Crossroads to + determine whether a given back end is available or not. This + can be done via <code>crossroads -t status</code>; the flag <code>-t</code> + causes Crossroads to emit easily parsable output. +<p> +<li> When the service is available, the health check script + hits a given URL and expects an answer <code>HTTP/1.x 200 + OK</code>. When this answer is not present, the back end is marked + unavailable. (The reason for e.g. <code>HTTP/1.x 500</code> might be a + database failure, as described above.) Marking a back end as + unavailable can be done via <code>crossroads tell</code> <em>service</em> + <em>backend</em> <code>unavailable</code>. +<p> +<li> When the service is unavailable, then the health check + script hits the same given URL. When a <code>HTTP/1.x 200 OK</code> + answer is returned, then the back end has 'woken up' and can + be marked available (using <code>crossroads tell</code>).</ul> +<p> +A sample health check script that does this, is shown below. It is +also in the Crossroads distribution as <code>etc/healthcheck</code>. It expects +three arguments: a testing URL, a service name, and a back end name. +<p> +<pre> +#!/usr/bin/perl + +use strict; +use LWP::UserAgent; + +# Show usage and stop +sub usage () { + die &lt;&lt;"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-&gt;new(); + my $req = HTTP::Request-&gt;new(GET =&gt; $ARGV[0]); + my $res = $ua-&gt;request($req); + + if ($res-&gt;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 = &lt;$if&gt;; +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"); +} +</pre> + +<p> +Once you have the health checker in place, it can be run e.g. each 10 +seconds in a mini-daemon for back end <code>one</code>: +<p> +<pre> +while [ 1 ] ; do + healthcheck http://10.1.1.1/areyouthere.jsp web one + sleep 10 +done +</pre> + +<p> +The same is run for back end <code>two</code>: +<p> +<pre> +while [ 1 ] ; do + healthcheck http://10.1.1.2/areyouthere.jsp web two + sleep 10 +done +</pre> + +<p> +The further implementation of such a mini-daemon that fires up +<code>healthcheck</code> is left to the reader. +<p> +<a name="l71"></a> +<h3>5.13: Rendering Crossroads' status in a web page</h3> +<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: +<p> +<pre> +&lt;?xml version="1.0" encoding="UTF-8"?&gt; +&lt;status&gt; + &lt;service id="1" name="smtp"&gt; + &lt;connections&gt;1&lt;/connections&gt; + &lt;lastbackend&gt;0&lt;/lastbackend&gt; + &lt;backend id="0" name="first"&gt; + &lt;availability id="0"&gt;available&lt;/availability&gt; + &lt;clients&gt;0&lt;/clients&gt; + &lt;failures&gt;0&lt;/failures&gt; + &lt;connections&gt;2&lt;/connections&gt; + &lt;duration sec="0.559882"&gt;0.56s&lt;/duration&gt; + &lt;throughput bytes="3564"&gt;3.48Kb&lt;/throughput&gt; + &lt;/backend&gt; + &lt;backend id="1" name="second"&gt; + &lt;availability id="0"&gt;available&lt;/availability&gt; + &lt;clients&gt;0&lt;/clients&gt; + &lt;failures&gt;0&lt;/failures&gt; + &lt;connections&gt;2&lt;/connections&gt; + &lt;duration sec="23.7636"&gt;23.76s&lt;/duration&gt; + &lt;throughput bytes="9055"&gt;8.84Kb&lt;/throughput&gt; + &lt;/backend&gt; + &lt;/service&gt; +&lt;/status&gt; +</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="l72"></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="l70"></a> +<a name="l73"></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: @@ -2928,7 +3195,7 @@ service HttpProxy { </pre> <p> -<a name="l71"></a> +<a name="l74"></a> <strong>6.1.1: Results</strong> <p> The results of this test are that crossroads causes a negligible @@ -2951,7 +3218,7 @@ sys 0m0.230s </pre> <p> -<a name="l72"></a> +<a name="l75"></a> <strong>6.1.2: Discussion</strong> <p> The above shown results are quite favorable to crossroads. However, @@ -2983,7 +3250,7 @@ seldom in the real world: back end). Again, this processing time will weigh much heavier than the multiple read/writes.</ul> <p> -<a name="l73"></a> +<a name="l76"></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 @@ -2997,7 +3264,7 @@ LVS isn't aware of downtime of back ends (unless one implements an external heartbeat). Also, crossroads offers more complex balancing than LVS. <p> -<a name="l74"></a> +<a name="l77"></a> <strong>6.2.1: Environment</strong> <p> On the balancer, LVS was run on port 80, its forwarding set up for two @@ -3028,7 +3295,7 @@ service http { </pre> <p> -<a name="l75"></a> +<a name="l78"></a> <strong>6.2.2: Tests and results</strong> <p> In the first test, ports 80 and 81 on the balancer were 'bombed' with @@ -3107,9 +3374,9 @@ are shown in the below table: Again, the results show that crossroads performs just as effectively as LVS, even with large data chunks! <p> -<a name="l76"></a> -<h2>7: Compiling and Installing</h2> -<a name="compiling"></a><a name="l77"></a> +<a name="l79"></a> +<h2>7: Compiling and Installing</h2> <a name="installation"></a> +<a name="compiling"></a><a name="l80"></a> <h3>7.1: Prerequisites</h3> <p> The creation of crossroads requires: @@ -3126,7 +3393,7 @@ The creation of crossroads requires: Basically a Linux or Apple MacOSX box will do nicely. To compile and install crossroads, follow these steps. <p> -<a name="l78"></a> +<a name="l81"></a> <h3>7.2: Compiling and installing</h3> <p> <ul> @@ -3147,8 +3414,8 @@ crossroads, follow these steps. of <code>Makefile.def</code> is suited for Linux or Apple MacOSX systems. On other Unices, or on non-Unix systems, you must particularly pay attention to <code>SET_PROC_TITLE_BY...</code>. When - in doubt, comment out all <code>SET_PROC_TITLE...</code> - settings. Crossroads will work nevertheless, but it won't show + 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). @@ -3184,7 +3451,7 @@ crossroads, follow these steps. <p> </ul> <p> -<a name="l79"></a> +<a name="l82"></a> <h3>7.3: Configuring crossroads</h3> <p> Now that the binary is available on your system, you need to create a @@ -3233,13 +3500,13 @@ which crossroads daemons are running. Finally, the tailing of <code>/var/log/messages</code> shows what's going on -- especially if you have <code>verbosity true</code> statements in the configuration. <p> -<a name="l80"></a> +<a name="l83"></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="l81"></a> +<a name="l84"></a> <strong>7.4.1: SysV Style Startup</strong> <p> On SysV style systems, there's a startup script directory @@ -3281,7 +3548,7 @@ If your runlevel is 5, then the right <code>cd</code> command is to <code>/etc/rc.d/rc5.d</code>. Alternatively, you can create the symlinks in both runlevel directories.</ul> <p> -<a name="l82"></a> +<a name="l85"></a> <strong>7.4.2: BSD Style Startup</strong> <p> On BSD style systems, daemons are booted directly from <code>/etc/rc</code> and diff --git a/doc/crossroads.man b/doc/crossroads.man @@ -1,6 +1,6 @@ -.TH "Crossroads 1\&.39" "2005, 2006, ff\&." +.TH "Crossroads 1\&.40" "2005, 2006, ff\&." .PP -.SH "Crossroads 1\&.39" +.SH "Crossroads 1\&.40" .SH "Karel Kubat" .SH "e-tunity" .SH "2005, 2006, ff\&." @@ -56,7 +56,32 @@ to commit changes, mail me for credentials\&. .PP -.SH "1\&.2: Copyright and Disclaimer" +.SH "1\&.2: Reporting bugs" + +.PP +Crossroads was thoroughly tested and proven to work\&. However, on +particular Unices with particular needs and network particularities, +bugs may occur\&. +.PP +In such cases you can contact the maintainer to ask for +assistance\&. Visit the site http://crossroads\&.e-tunity\&.com for contact information\&. In questions +or bug reports, always include the following: +.PP +.IP o +A description of the bug: when does it occur, what are +the circumstances, what is the expected behavior, what is the +observed behavior\&. +.IP +.IP o +The Crossroads configuration (normally +\f(CW/etc/crossroads\&.conf\fP) +.IP +.IP o +The version of Crossroads and all compile-time settings, +obtained via \f(CWcrossroads -C\fP\&. +.PP + +.SH "1\&.3: Copyright and Disclaimer" .PP Crossroads is distributed as-is, without assumptions of fitness @@ -78,7 +103,7 @@ access to the Crossroads SVN repository, so that you can update and commit as you like\&. .PP -.SH "1\&.3: Terminology" +.SH "1\&.4: Terminology" .PP Throughout this document, the following terms are used: \e (Many @@ -184,7 +209,7 @@ controlled manner, without any client noticing it\&. .PP -.SH "1\&.4: Porting issues for pre-1\&.21 installations" +.SH "1\&.5: Porting issues for pre-1\&.21 installations" .PP As of version 1\&.21, the event-hook directives \f(CWonsuccess\fP and @@ -202,7 +227,7 @@ The commands that are run via \f(CWonstart\fP, \f(CWonend\fP or \f(CWonfail\fP weight of the first back end, etc\&.\&. See section ?? for details\&. .PP -.SH "1\&.5: Porting issues for pre-0\&.26 installations" +.SH "1\&.6: Porting issues for pre-0\&.26 installations" .PP As of version 0\&.26 the syntax of the configuration file has @@ -223,7 +248,7 @@ multiple TCP connections, and the term TCP connection\&.) .PP -.SH "1\&.6: Porting issues for pre-1\&.08 installations" +.SH "1\&.7: Porting issues for pre-1\&.08 installations" .PP As of version 1\&.08, the following directives no longer are @@ -340,6 +365,11 @@ configuration file)\&. The actual usage information is always obtained by typing \f(CWcrossroads\fP without any arguments\&. Crossroads then displays the allowed arguments\&. .PP +The installation (see section ??) installs also a +second program called \f(CWcrossroads-daemon\fP\&. This program is not meant +to be started from the command line; it is administered through the +front end \f(CWcrossroads\fP\&. +.PP .SH "3\&.1: General Commandline Syntax" @@ -416,6 +446,10 @@ end, and where state is e\&.g\&. \f(CWavailable\fP, \f(CWDOWN\fP, Crossroads not to use the back end are in caps\&. The series is repeated for all back ends of the given service\&. .PP +The flag \f(CW-x\fP 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\&. +.PP .SH "3\&.3: Logging-related options" @@ -2992,6 +3026,245 @@ retry connecting with a small one-second delay in between\&. A high a client is kept waiting\&. .PP +.SH "5\&.12: Scripting Crossroads\&' back end availability" +The internal reviving model of Crossroads can periodically check +whether back ends that are unavailable have woken up yet\&. The checker +is triggered by a \f(CWrevivinginterval\fP statement of a service +description, as in: +.PP +.nf +service web { + port 80; + revivinginterval 5; + + backend one { + server 10\&.1\&.1\&.1:80; + } + + backend two { + server 10\&.1\&.1\&.2:80; + } +} +.fi + +.PP +This instructs Crossroads to check back ends \f(CWone\fP or \f(CWtwo\fP each 5 +seconds\&. A back end is considered available when it accepts TCP +connections on the given IP address and port\&. +.PP +This approach may not be sufficient in all situations\&. E\&.g\&., a web +server may \&'hang\&': it might accept a connection, but never serve +it\&. Or, an application server may serve simple connections, but if its +database is offline, it will generate internal server errors on pages +that try to access data\&. +.PP +In such situations you may want to replace the internal wakeup service +with your own scripted \&'health check\&'\&. Here\&'s how: +.PP +.IP o +First of all, you take out the \f(CWrevivinginterval\fP +statement of \f(CW/etc/crossroads\&.conf\fP, so that Crossroads\&' +internal check which only verifies TCP connectivity is +disabled\&. +.IP +.IP o +You determine a suitable URL in the applications that can +be queried for the health\&. In our example this will be +\f(CW/areyouthere\&.jsp\fP, a hypothetical page that does some +database access\&. It doesn\&'t even need to return output; just +succeed, or fail\&. +.IP +.IP o +You devise a small script that asks Crossroads the status +of back ends of a given service (in our example, service +\f(CWweb\fP)\&. +.IP +.IP o +The health check script starts by querying Crossroads to +determine whether a given back end is available or not\&. This +can be done via \f(CWcrossroads -t status\fP; the flag \f(CW-t\fP +causes Crossroads to emit easily parsable output\&. +.IP +.IP o +When the service is available, the health check script +hits a given URL and expects an answer \f(CWHTTP/1\&.x 200 +OK\fP\&. When this answer is not present, the back end is marked +unavailable\&. (The reason for e\&.g\&. \f(CWHTTP/1\&.x 500\fP might be a +database failure, as described above\&.) Marking a back end as +unavailable can be done via \f(CWcrossroads tell\fP \fIservice\fP +\fIbackend\fP \f(CWunavailable\fP\&. +.IP +.IP o +When the service is unavailable, then the health check +script hits the same given URL\&. When a \f(CWHTTP/1\&.x 200 OK\fP +answer is returned, then the back end has \&'woken up\&' and can +be marked available (using \f(CWcrossroads tell\fP)\&. +.PP +A sample health check script that does this, is shown below\&. It is +also in the Crossroads distribution as \f(CWetc/healthcheck\fP\&. It expects +three arguments: a testing URL, a service name, and a back end name\&. +.PP +.nf +#!/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\en"); + return (1); + } else { + print ("URL $ARGV[0] indicates failure\en"); + 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\&'\en"); +my $status = <$if>; +close ($if) or die ("\&'crossroads status\&' terminated with error\en"); +chomp ($status); +$status =~ s{\&.*=}{}; +$status =~ s{\es+}{}; + +print ("Back end $ARGV[2] has status $status\en"); +if ($status eq \&'UNAVAILABLE\&') { + if (testurl()) { + print ("Back end $ARGV[2] is now available\en"); + system ("crossroads tell $ARGV[1] $ARGV[2] available") + and die ("\&'crossroads tell\&' terminated with error\en"); + } +} elsif ($status eq \&'available\&') { + if (!testurl()) { + print ("Back end $ARGV[2] is is now UNAVAILABLE\en"); + system ("crossroads tell $ARGV[1] $ARGV[2] UNAVAILABLE") + and die ("\&'crossroads tell\&' terminated with error\en"); + } +} else { + print ("No action given status \&'$status\&'\en"); +} +.fi + +.PP +Once you have the health checker in place, it can be run e\&.g\&. each 10 +seconds in a mini-daemon for back end \f(CWone\fP: +.PP +.nf +while [ 1 ] ; do + healthcheck http://10\&.1\&.1\&.1/areyouthere\&.jsp web one + sleep 10 +done +.fi + +.PP +The same is run for back end \f(CWtwo\fP: +.PP +.nf +while [ 1 ] ; do + healthcheck http://10\&.1\&.1\&.2/areyouthere\&.jsp web two + sleep 10 +done +.fi + +.PP +The further implementation of such a mini-daemon that fires up +\f(CWhealthcheck\fP is left to the reader\&. +.PP + +.SH "5\&.13: Rendering Crossroads\&' status in a web page" +The Crossroads flag \f(CW-x\fP 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\&. +.PP +E\&.g\&., the following sample shows how Crossroads reports its status in +XML format: +.PP +.nf +<?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> +.fi + +.PP +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 +\f(CWetc/xml-status-to-html\&.xslt\fP\&. 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!) +.PP +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 (\f(CWcrossroads -x status\fP) +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, +\f(CWcrossroads status\fP might abort with a message: "ERROR: Cannot get +shared memory for service \fIname\fP, key \fInumber\fP: Permission denied\&." +.PP +The solution for this problem is to make the shared memory access +somewhat more liberal\&. There are basically two options: +.PP +.IP o +Start Crossroads with the flag \f(CW-m 0666\fP, 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 \f(CWcrossroads status\fP\&. +.IP +.IP o +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 \f(CW-m 0664\fP\&. Now, +users belonging to the same group as the Crossroads starter +can run \f(CWcrossroads status\fP\&. +.PP + .SH "6: Benchmarking" This section shows how crossroads affects the transmitting of HTML data when used as an intermediate \&'station\&' @@ -3204,7 +3477,7 @@ as LVS, even with large data chunks! .PP .SH "7: Compiling and Installing" - + .SH "7\&.1: Prerequisites" @@ -3250,8 +3523,8 @@ explained in the file\&. \fBNote that\fP the default distribution of \f(CWMakefile\&.def\fP is suited for Linux or Apple MacOSX systems\&. On other Unices, or on non-Unix systems, you must particularly pay attention to \f(CWSET_PROC_TITLE_BY\&.\&.\&.\fP\&. When -in doubt, comment out all \f(CWSET_PROC_TITLE\&.\&.\&.\fP -settings\&. Crossroads will work nevertheless, but it won\&'t show +in doubt, set the \f(CWSET_PROC_TITLE\&.\&.\&.\fP +settings to 0\&. Crossroads will work nevertheless, but it won\&'t show nice titles in \f(CWps\fP listings\&. Also there\&'s a macro \f(CWEXTRA_LIBS\fP to add linkage flags (an example for a Solaris build is included)\&. diff --git a/doc/crossroads.pdf b/doc/crossroads.pdf Binary files differ. diff --git a/doc/crossroads.yo b/doc/crossroads.yo @@ -33,6 +33,6 @@ includefile(tips) sect(Benchmarking) includefile(benchmarking) -sect(Compiling and Installing) +sect(Compiling and Installing) label(installation) includefile(compiling) diff --git a/doc/intro.yo b/doc/intro.yo @@ -42,6 +42,27 @@ itemization( to commit changes, url(mail me)(mailto:karel@e-tunity.com) 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 (normally + tt(/etc/crossroads.conf)) + + it() The version of Crossroads and all compile-time settings, + obtained via tt(crossroads -C).) subsect(Copyright and Disclaimer) diff --git a/doc/tips.yo b/doc/tips.yo @@ -35,3 +35,8 @@ includefile(tips/ipconntrackmax) subsect(Marking back ends as bad after more than one try) includefile(tips/retries) +subsect(Scripting Crossroads' back end availability) +includefile(tips/scripting) + +subsect(Rendering Crossroads' status in a web page) +includefile(tips/rendering) diff --git a/doc/tips/rendering.yo b/doc/tips/rendering.yo @@ -0,0 +1,65 @@ +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: + +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/tips/scripting.yo b/doc/tips/scripting.yo @@ -0,0 +1,152 @@ +The internal reviving model of Crossroads can periodically check +whether back ends that are unavailable have woken up yet. The checker +is triggered by a tt(revivinginterval) statement of a service +description, as in: + +verb(\ +service web { + port 80; + revivinginterval 5; + + backend one { + server 10.1.1.1:80; + } + + backend two { + server 10.1.1.2:80; + } +}) + +This instructs Crossroads to check back ends tt(one) or tt(two) each 5 +seconds. A back end is considered available when it accepts TCP +connections on the given IP address and port. + +This approach may not be sufficient in all situations. E.g., a web +server may 'hang': it might accept a connection, but never serve +it. Or, an application server may serve simple connections, but if its +database is offline, it will generate internal server errors on pages +that try to access data. + +In such situations you may want to replace the internal wakeup service +with your own scripted 'health check'. Here's how: + +itemization( + it() First of all, you take out the tt(revivinginterval) + statement of tt(/etc/crossroads.conf), so that Crossroads' + internal check which only verifies TCP connectivity is + disabled. + + it() You determine a suitable URL in the applications that can + be queried for the health. In our example this will be + tt(/areyouthere.jsp), a hypothetical page that does some + database access. It doesn't even need to return output; just + succeed, or fail. + + it() You devise a small script that asks Crossroads the status + of back ends of a given service (in our example, service + tt(web)). + + it() The health check script starts by querying Crossroads to + determine whether a given back end is available or not. This + can be done via tt(crossroads -t status); the flag tt(-t) + causes Crossroads to emit easily parsable output. + + it() When the service is available, the health check script + hits a given URL and expects an answer tt(HTTP/1.x 200 + OK). When this answer is not present, the back end is marked + unavailable. (The reason for e.g. tt(HTTP/1.x 500) might be a + database failure, as described above.) Marking a back end as + unavailable can be done via tt(crossroads tell) em(service) + em(backend) tt(unavailable). + + it() When the service is unavailable, then the health check + script hits the same given URL. When a tt(HTTP/1.x 200 OK) + answer is returned, then the back end has 'woken up' and can + be marked available (using tt(crossroads tell)).) + +A sample health check script that does this, is shown below. It is +also in the Crossroads distribution as tt(etc/healthcheck). It expects +three arguments: a testing URL, a service name, and a back end name. + +verb(\ +#!/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"); +}) + +Once you have the health checker in place, it can be run e.g. each 10 +seconds in a mini-daemon for back end tt(one): + +verb(\ +while [ 1 ] ; do + healthcheck http://10.1.1.1/areyouthere.jsp web one + sleep 10 +done) + +The same is run for back end tt(two): + +verb(\ +while [ 1 ] ; do + healthcheck http://10.1.1.2/areyouthere.jsp web two + sleep 10 +done) + +The further implementation of such a mini-daemon that fires up +tt(healthcheck) is left to the reader. diff --git a/doc/using.yo b/doc/using.yo @@ -5,6 +5,11 @@ 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). + subsect(General Commandline Syntax) This section shows the most basic usage. As said above, start @@ -69,6 +74,11 @@ itemization( Crossroads not to use the back end are 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. + + subsect(Logging-related options) Two 'flags' of Crossroads are specifically logging-related. This diff --git a/etc/Makefile.conf b/etc/Makefile.conf @@ -0,0 +1,23 @@ +# The used C compiler. +CC := $(shell $(BASE)/tools/c-conf c-compiler) + +# Link time libraries. +LIBS := $(shell $(BASE)/tools/c-conf lib ucb nsl pthread socket 2>/dev/null) + +# Compiletime defines. Remember to update show_config() when changing +# this list! +DEFS := -DDEFAULT_CONF='"$(DEFAULT_CONF)"' -DMAX_BACKEND=$(MAX_BACKEND) \ + -DSHM_MASK=$(SHM_MASK) -DSLEEP_TIME=$(SLEEP_TIME) \ + -DCONNECT_TIMEOUT=$(CONNECT_TIMEOUT) -DVER='"$(VER)/$(REVVER)"' \ + -DSET_PROC_TITLE_BY_ARGV=$(SET_PROC_TITLE_BY_ARGV) \ + -DTCP_BUFSZ=$(TCP_BUFSZ) -DRETRY_WAIT=$(RETRY_WAIT) \ + -DREVVER='"$(REVVER)"' -DBINDIR='"$(BINDIR)"' \ + -DEXTRALIBS='"$(EXTRALIBS)"' -DLIBS='"$(LIBS)"' \ + $(shell $(BASE)/tools/c-conf ifheader01 malloc.h HAVE_MALLOC_H) \ + $(shell $(BASE)/tools/c-conf ifheader01 stdint.h HAVE_STDINT_H) \ + $(shell $(BASE)/tools/c-conf libfunction01 flock HAVE_FLOCK) \ + $(shell $(BASE)/tools/c-conf libfunction01 lockf HAVE_LOCKF) \ + $(shell $(BASE)/tools/c-conf libfunction01 strlcat HAVE_STRLCAT) \ + $(shell $(BASE)/tools/c-conf libfunction01 sranddev HAVE_SRANDDEV) \ + $(shell $(BASE)/tools/c-conf libfunction01 vsyslog HAVE_VSYSLOG) \ + $(shell $(BASE)/tools/c-conf libfunction01 strcasestr HAVE_STRCASESTR) diff --git a/etc/Makefile.def b/etc/Makefile.def @@ -1,14 +1,15 @@ # 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.39 +VER = 1.40 # Revision version, auto-detected. -REVVER = $(shell ../etc/svnrev ../ChangeLog ../etc/svnrev.txt) +REVVER = $(shell $(BASE)/etc/svnrev $(BASE)/ChangeLog $(BASE)/etc/svnrev.txt) # Default config DEFAULT_CONF = /etc/crossroads.conf @@ -56,3 +57,4 @@ SET_PROC_TITLE_BY_ARGV = 1 # fiddle with LD_LIBRARY_PATH or crle (yuk!) # EXTRALIBS = -R/usr/ucblib EXTRALIBS = + diff --git a/etc/healthcheck b/etc/healthcheck @@ -0,0 +1,63 @@ +#!/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/svnrev.txt b/etc/svnrev.txt @@ -1 +1 @@ -150 +152 diff --git a/etc/xml-status-to-html.xslt b/etc/xml-status-to-html.xslt @@ -0,0 +1,131 @@ +<?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,81 +1,35 @@ include ../etc/Makefile.def -all: - ../tools/gettools e-ver e-txt2c c-conf - ../tools/e-ver ../ChangeLog $(VER) - $(MAKE) textconv - $(MAKE) grammar - $(MAKE) objects - $(MAKE) crossroads - -install: all $(BINDIR)/crossroads - -$(BINDIR)/crossroads: crossroads - cp crossroads $(BINDIR)/ - strip $(BINDIR)/crossroads - -textconv: usage.h proxyerror.h -usage.h: usage.txt - ../tools/untab usage.txt - ../tools/e-txt2c USAGETEXT <usage.txt >usage.h -proxyerror.h: proxyerror.txt - ../tools/untab proxyerror.txt - ../tools/e-txt2c ERRORTEXT <proxyerror.txt >proxyerror.h - -grammar: parser.c lexer.c -lexer.c: lexer.l - flex -o$@ $< -parser.c: parser.y - bison -d -o $@ $< - -SRC := $(wildcard *.c) -OBJ := $(patsubst %.c, %.o, $(SRC)) -objects: $(OBJ) - -CC := $(shell ../tools/c-conf c-compiler) - -LIBS := $(shell ../tools/c-conf lib ucb nsl pthread socket 2>/dev/null) +DIRS = lib crossroads crossroads-daemon + +all: prep + for d in ${DIRS}; do \ + echo "Making all in $$d"; \ + echo BASE=$(BASE) make -C $$d all; \ + BASE=$(BASE) make -C $$d all || exit 1; \ + done + +install: prep + for d in ${DIRS}; do \ + echo "Making install in $$d"; \ + echo BASE=$(BASE) make -C $$d install; \ + BASE=$(BASE) make -C $$d install || exit 1; \ + done -# Compiletime defines. Remember to update show_config() when changing -# this list! -DEFS := -DDEFAULT_CONF='"$(DEFAULT_CONF)"' -DMAX_BACKEND=$(MAX_BACKEND) \ - -DSHM_MASK=$(SHM_MASK) -DSLEEP_TIME=$(SLEEP_TIME) \ - -DCONNECT_TIMEOUT=$(CONNECT_TIMEOUT) -DVER='"$(VER)/$(REVVER)"' \ - -DSET_PROC_TITLE_BY_ARGV=$(SET_PROC_TITLE_BY_ARGV) \ - -DTCP_BUFSZ=$(TCP_BUFSZ) -DRETRY_WAIT=$(RETRY_WAIT) \ - -DREVVER='"$(REVVER)"' -DBINDIR='"$(BINDIR)"' \ - -DEXTRALIBS='"$(EXTRALIBS)"' -DLIBS='"$(LIBS)"' \ - $(shell ../tools/c-conf ifheader01 malloc.h HAVE_MALLOC_H) \ - $(shell ../tools/c-conf ifheader01 stdint.h HAVE_STDINT_H) \ - $(shell ../tools/c-conf libfunction01 flock HAVE_FLOCK) \ - $(shell ../tools/c-conf libfunction01 lockf HAVE_LOCKF) \ - $(shell ../tools/c-conf libfunction01 strlcat HAVE_STRLCAT) \ - $(shell ../tools/c-conf libfunction01 sranddev HAVE_SRANDDEV) \ - $(shell ../tools/c-conf libfunction01 vsyslog HAVE_VSYSLOG) \ - $(shell ../tools/c-conf libfunction01 strcasestr HAVE_STRCASESTR) - -parser.o: parser.c - $(CC) $(DEFS) -c -g $< - -lexer.o: lexer.c - $(CC) $(DEFS) -c -g $< - -%.o: %.c - $(CC) $(DEFS) -c -g -W -Wall $< - -crossroads: libcrossroads.a - $(CC) $(EXTRALIBS) -g -L. -lcrossroads $(LIBS) -o $@ -lm - -libcrossroads.a: $(OBJ) - ar rs libcrossroads.a $(OBJ) - -distclean: clean clean: - rm -f $(OBJ) libcrossroads.a crossroads \ - usage.h proxyerror.h - -# Extra deps: -usage.o: usage.c usage.h ../etc/Makefile.def -main.o: main.c crossroads.h ../etc/Makefile.def -strexpandformat.o: strexpandformat.c ../etc/Makefile.def -showconfig.o: showconfig.c ../etc/Makefile.def Makefile -\ No newline at end of file + 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 + +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 + +prep: + ../tools/gettools e-ver e-txt2c c-conf + ../tools/e-ver ../ChangeLog $(VER) diff --git a/src/allocreporter.c b/src/allocreporter.c @@ -1,65 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 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, sizeof(Servicereport), - 0644 | 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, 0644 | 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, sizeof(Servicereport), - 0644) ) >= 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, 0644)) >= 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/ansistamp.c b/src/ansistamp.c @@ -1,26 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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) { - static char buf[80]; - time_t now; - struct tm *tmp; - - time (&now); - 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/backendavailable.c b/src/backendavailable.c @@ -1,26 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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].avail == st_available && - (activeservice->backend[target].maxconnections == 0 || - activeservice->backend[target].maxconnections > - servicereport->backendstate[target].nclients)) { - msg ("Service %s: target nr %d is available", - activeservice->name, target); - return (1); - } - - msg ("Service %s: target nr %d is unavailable", - activeservice->name, target); - return (0); -} diff --git a/src/backendconnect.c b/src/backendconnect.c @@ -1,108 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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; - - /* Create the socket. */ - if ( (sock = socket (PF_INET, SOCK_STREAM, 0)) < 0 ) { - if (program_stage != stage_retrying) { - error ("Service %s: failed to create socket " - "for backend communication: %s", - activeservice->name, strerror(errno)); - } else { - warning ("Service %s: 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 ("Service %s: cannot set backend socket options " - "(nosigpipe): %s", activeservice->name, strerror(errno)); - close (sock); - return (-2); - } -#endif - - /* Assign to back end server address. */ - if (init_sockaddr (&servername, - activeservice->backend[current_backend].server, - activeservice->backend[current_backend].port)) { - /* The hostname is unusable.. */ - warning ("Service %s: unknown host %s", - activeservice->name, - activeservice->backend[current_backend].server); - close (sock); - mark_activity (0, 0, st_unavailable); - return (-3); - } - if (program_stage != stage_retrying) - msg ("Service %s: Network socket to %s:%d created", - activeservice->name, - activeservice->backend[current_backend].server, - activeservice->backend[current_backend].port); - - /* If retrying, delay a bit */ - if (servicereport->backendstate[current_backend].fail > 0) { - msg ("Service %s: Seen %d retries, waiting a bit", - activeservice->name, - servicereport->backendstate[current_backend].fail); - sleep (RETRY_WAIT); - } - - /* Set up the connect interruption */ - signal (SIGALRM, alarmhandler); - timed_out = 0; - alarm (CONNECT_TIMEOUT); - - /* Try connecting */ - if (connect (sock, (struct sockaddr *) &servername, - sizeof(servername)) < 0) { - /* This backend is unusable. - * Either connect() has failed (connection refused) or it got - * interrupted by the SIGALRM, or another signal went off. - */ - close (sock); - alarm(0); - signal (SIGALRM, SIG_DFL); - - if (program_stage != stage_retrying) { - if (timed_out) - warning ("Service %s: server %s:%d not usable" - " due to timeout", - activeservice->name, - activeservice->backend[current_backend].server, - activeservice->backend[current_backend].port); - else - warning ("Service %s: server %s:%d: cannot connect: %s", - activeservice->name, - activeservice->backend[current_backend].server, - activeservice->backend[current_backend].port, - strerror(errno)); - } - mark_activity (0, 0, st_unavailable); - return (-3); - } - alarm(0); - signal (SIGALRM, SIG_DFL); - return (sock); -} - diff --git a/src/backendcount.c b/src/backendcount.c @@ -1,16 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 ("Service %s: %d backend(s) available", activeservice->name, n); - return (n); -} diff --git a/src/choosebackend.c b/src/choosebackend.c @@ -1,377 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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[MAX_BACKEND], nbackends = 0, h, i, j, k, - target_set = 0, flat_weights = 1, weights[MAX_BACKEND], *sel_weights, - tot_weights, lo_val, hi_val, done; - double values [MAX_BACKEND], 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 ("Service %s: max clients %d exceeded", - activeservice->name, - 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 ("Service %s: Client IP %s hashed to back end index %d", - activeservice->name, client_ip, h); - if (servicereport->backendstate[h].avail == st_available && - (activeservice->backend[h].maxconnections == 0 || - activeservice->backend[h].maxconnections > - servicereport->backendstate[h].nclients)) { - msg ("Service %s: Hashed back end %d is acceptable", - activeservice->name, h); - current_backend = h; - return; - } else - msg ("Service %s: Hashed back end %d is not available, " - "re-dispatching", activeservice->name, 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].avail == st_available && - (activeservice->backend[i].maxconnections == 0 || - activeservice->backend[i].maxconnections > - servicereport->backendstate[i].nclients)) { - msg ("Service %s: " - "candidate back end: %d (max clients %d, active %d, " - "state %s)", - activeservice->name, - i, activeservice->backend[i].maxconnections, - servicereport->backendstate[i].nclients, - state_to_string(servicereport->backendstate[i].avail)); - backends[nbackends++] = i; - } - } - - /* No backends? Nogo. */ - if (!nbackends) { - current_backend = -1; - warning ("No active backends to select!"); - return; - } - - /* Only one backend? Then it's always the first one, - * whatever you do. */ - if (nbackends == 1) { - current_backend = backends[0]; - servicereport->last_backend = current_backend; - msg ("Service %s: only 1 backend to select (%d)", - activeservice->name, current_backend); - return; - } - - /* More than 1 backend available.. make a wise choice. */ - switch (activeservice->dispatchtype) { - - case ds_roundrobin: - /* Find the currently used backend, go one forward. */ - msg ("Service %s: last roundrobin back end was %d", - activeservice->name, 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 ("Service %s: next roundrobin back end is %d", - activeservice->name, current_backend); - return; - } - /* None found.. try the first one (run to momma). */ - current_backend = backends[0]; - servicereport->last_backend = current_backend; - msg ("Service %s: " - "chosen backend (roundrobin, without historical info): %d", - activeservice->name, current_backend); - return; - - case ds_random: - /* Re-randomize. */ -# if HAVE_SRANDDEV == 1 - sranddev(); - msg ("Service %s: randomier seeded with randdev", activeservice->name); -# else - gettimeofday (&tv, 0); - srand ((unsigned) tv.tv_usec); - msg ("Service %s: randomizer seeded with %u", - activeservice->name, (unsigned) tv.tv_usec); -# endif - - /* First of all let's see if all the weights are the same. */ - 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 ("Service %s: " - "chosen backend (weighted random): %d at index %d", - activeservice->name, current_backend, i); - return; - } - - /* ELSE: Choose a random one of the availables. */ - current_backend = backends[rand() % nbackends]; - servicereport->last_backend = current_backend; - msg ("Service %s: chosen backend (flat-weight random): %d", - activeservice->name, current_backend); - return; - - case ds_bysize: - /* Fill the values */ - 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 ("Service %s: " - "by size weighing backend %d has weight %d, value %u" - " (bytes=%u, avgbytes=%u)", - activeservice->name, - 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 ("Service %s: " - "by size weighing: best so far is %d (value %g)", - activeservice->name, current_backend, nbest); - } - msg ("Service %s: chosen backend (by size): %d", - activeservice->name, current_backend); - return; - - case ds_byduration: - /* Fill the values */ - 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 ("Service %s: By duration weighing: backend %d has value %g" - " (sec=%g, avgsec=%g, weight=%d)", - activeservice->name, - 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 ("Service %s: " - "by duration weighing: best so far is %d (value %g)", - activeservice->name, current_backend, nbest); - } - msg ("Service %s: chosen backend (by duration): %d", - activeservice->name, current_backend); - return; - - case ds_byorder: - /* Get the first available back end in line. */ - current_backend = backends[0]; - servicereport->last_backend = current_backend; - msg ("Service %s: chosen backend (by order): %d", - activeservice->name, current_backend); - return; - - case ds_byconnections: - case ds_byclientip: - /* Note: this serves byconnections dispatching, plus byclientip - * when the actual back end has gone down. */ - for (i = 0; i < nbackends; i++) { - values[i] = - servicereport->backendstate[backends[i]].nclients * - activeservice->backend[backends[i]].weight; - msg ("Service %s: " - "by connections weighing: backend %d has value %g", - activeservice->name, 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 ("Service %s: " - "by connections weighing: best so far is %d (value %u)", - activeservice->name, current_backend, nclients); - } - msg ("Service %s: chosen backend (by connections): %d", - activeservice->name, current_backend); - return; - - case ds_externalhandler: - /* External handler to be called */ - exthandler = str_expand_format (activeservice->dispatchext); - msg ("Service %s: calling external handler '%s'", - activeservice->name, exthandler); - uid_assume(); - if (! (f = popen (exthandler, "r")) ) { - warning ("Service %s: failed to start external handler '%s': %s", - activeservice->name, exthandler, strerror(errno)); - current_backend = backends[0]; - servicereport->last_backend = current_backend; - uid_restore(); - return; - } - while (1) { - if (fscanf (f, " %80s ", buf) < 1) { - msg ("Service %s: external handler signals end", - activeservice->name); - pclose (f); - uid_restore(); - break; - } - msg ("Service %s: external handler says '%s'", - activeservice->name, buf); - for (i = 0; i < nbackends; i++) - if (!strcmp (buf, activeservice->backend[backends[i]].name)) { - msg ("Service %s: selecting back end %s due to " - "external handler", activeservice->name, buf); - current_backend = backends[i]; - servicereport->last_backend = current_backend; - pclose (f); - uid_restore(); - return; - } - } - warning ("Service %s: external handler didn't reply with " - "a selectable back end", activeservice->name); - current_backend = backends[0]; - servicereport->last_backend = current_backend; - return; - - default: - /* Internal fry.. */ - error ("Service %s: internal error: unhandled dispatch type %d", - activeservice->name, activeservice->dispatchtype); - } -} diff --git a/src/configtest.c b/src/configtest.c @@ -1,12 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 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/copysockets.c b/src/copysockets.c @@ -1,16 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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[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. */ - while (1) - net_copy (clientsock, serversock, TCP_BUFSZ, buf); -} diff --git a/src/createcommandlinespace.c b/src/createcommandlinespace.c @@ -1,37 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 create_commandline_space () { - char **argv; - int i; - - /* Here's a dirty hack for Linux systems. We're going to get - * daemonized (unless -f was given) and we'll want to change the - * program name as it appears in the ps list. - * So we re-exec ourselves with a dummy -i flag that creates - * space on the commanedline. - */ -# if SET_PROC_TITLE_BY_ARGV == 1 - if (! iflag_present) { - argv = xmalloc ( (org_argc + 2) * sizeof(char*)); - - argv[0] = org_argv[0]; - argv[1] = "-ixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; - argv[org_argc + 1] = 0; - - for (i = 1; i < org_argc; i++) - argv[i + 1] = org_argv[i]; - argv[org_argc + 1] = 0; - - execv (argv[0], argv); - execvp (argv[0], argv); - error ("Failed to re-exec program: %s", - strerror(errno)); - } -# endif -} diff --git a/src/crossroads.h b/src/crossroads.h @@ -1,5 +1,5 @@ /************************************************************************* - * This file is part of Crosroads 1.39, a load balancer and fail over + * This file is part of Crosroads 1.40, a load balancer and fail over * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. * Visit http://crossroads.e-tunity.com for information. *************************************************************************/ @@ -138,6 +138,7 @@ typedef struct { /* Backend description */ char *thruputfile; /* .. traffic throughput file */ 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 */ @@ -150,7 +151,6 @@ typedef struct { /* Backend description */ int nsetserverheader; /* .. table size */ char **appendserverheader; /* .. server hdrs to APPEND */ int nappendserverheader; /* .. table size */ - int retries; /* .. # retries before unavailable */ } Backend; typedef struct { /* Filtering information: */ @@ -158,7 +158,10 @@ typedef struct { /* Filtering information: */ unsigned mask; /* .. netmask */ } IpFilter; +/* The configuration in internal representation. When changing, remember + * to change config_write() and config_read()! */ typedef struct { /* Service description */ + /* Basic stuff */ char *name; /* .. service name */ char *bind; /* .. address to bind to */ unsigned port; /* .. listening port */ @@ -172,16 +175,19 @@ typedef struct { /* Service description */ unsigned connectiontimeout; /* .. # secs for timeout handling */ unsigned maxconnections; /* .. max # of allowed connections */ Servicetype type; /* .. type of the service */ - Backend *backend; /* .. the back ends */ - int nbackend; /* .. size of backend array */ char *allowfile; /* .. file with allowed IP filters */ char *denyfile; /* .. and denied */ - IpFilter *allowchain; /* .. chain of allowed IP's */ - int nallowchain; /* .. size of chain */ - IpFilter *denychain; /* .. chain of denied IP's */ - int ndenychain; /* .. size of chain */ 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 enum { /* Backend availability */ @@ -279,6 +285,7 @@ EXTERN int reload_allow_deny; /* flag to reload spec files */ EXTERN int semid; /* semaphore ID */ EXTERN Service *service; /* service descriptions */ EXTERN Servicereport *servicereport; /* reporter in shared mem */ +EXTERN int shmperm; /* shm permissions, default 0644 */ EXTERN int sloppyportbind; /* -s flag present */ EXTERN unsigned char *srbuf; /* server socket input buffer */ EXTERN int srbufpos, srbufmax; /* .. position & bytes */ @@ -286,6 +293,7 @@ EXTERN StateStringMap /* state/string map */ statestringmap[]; /* .. and vv */ 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 FILE *yyin; /* config file handle */ EXTERN int yylineno; /* input line number */ EXTERN char *yyerrmsg; /* parsing error msg */ @@ -301,6 +309,8 @@ extern int backend_available (int target); extern int backend_count(void); extern int backend_connect (void); extern void choose_backend (void); +extern void config_read (int fd); +extern void config_write (int fd); extern void copysockets (int clientsock, int serversock); extern int configtest (int ac, char **av); extern void create_commandline_space (void); @@ -392,6 +402,7 @@ extern void warning (char const *fmt, ...) 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); diff --git a/src/crossroads/Makefile b/src/crossroads/Makefile @@ -0,0 +1,23 @@ +include $(BASE)/etc/Makefile.def +include $(BASE)/etc/Makefile.conf + +BIN = crossroads +all: $(BIN) + +install: all $(BINDIR)/$(BIN) + +clean: + rm -f *.o $(BIN) + +$(BINDIR)/$(BIN): $(BIN) + cp $(BIN) $(BINDIR)/$(BIN) + strip $(BINDIR)/$(BIN) + +main.o: main.c + $(CC) -c -g -W -Wall $(DEFS) main.c + +$(BIN): main.o ../lib/libcrossroads.a + $(CC) -o $(BIN) main.o -L$(BASE)/src/lib -lcrossroads + +# 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 @@ -0,0 +1,144 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 opt; + unsigned i; + static Handler handler[] = { + /* Argument Nr.args Needconf Handler function */ + /* -1=no check */ + { "services", 0, 1, show_services }, + { "status", -1, 1, show_status }, + { "stop", 0, 1, stop_daemon }, + { "start", 0, 1, serve }, + { "restart", 0, 1, restart }, + { "tell", 3, 1, tell_service }, + { "configtest", 0, 1, configtest }, + }; + + /* Remember original ac/av/ep */ + org_argc = argc; + org_argv = argv; + + /* Parse options. */ + config_file = DEFAULT_CONF; + while ( (opt = getopt (argc, argv, "b?c:fhvi:Val:stCm:x")) > 0 ) + switch (opt) { + case 'a': + log_activity++; + break; + case 'b': + msg ("Parsing configuration %s", config_file); + if (! (yyin = fopen (config_file, "r")) ) + error ("Cannot read configuration %s: %s", + config_file, strerror(errno)); + yyparse (); + fclose (yyin); + config_write (1); + exit (0); + break; + case 'c': + config_file = optarg; + break; + case 'v': + flag_verbose++; + break; + case 'i': + iflag_present++; + break; + case 'l': + switch (atoi (optarg)) { + case 0: + log_facility = LOG_LOCAL0; + break; + case 1: + log_facility = LOG_LOCAL1; + break; + case 2: + log_facility = LOG_LOCAL2; + break; + case 3: + log_facility = LOG_LOCAL3; + break; + case 4: + log_facility = LOG_LOCAL4; + break; + case 5: + log_facility = LOG_LOCAL5; + break; + case 6: + log_facility = LOG_LOCAL6; + break; + case 7: + log_facility = LOG_LOCAL7; + break; + default: + usage(); + } + break; + case 'm': + shmperm = strtol (optarg, 0, 8); + break; + case 's': + sloppyportbind++; + break; + case 't': + tabular_status++; + break; + case 'x': + xml_status++; + break; + case 'C': + show_config(); + exit (0); + case 'V': + puts (VER); + exit (0); + case '?': + case 'h': + default: + usage (); + } + + /* We need at last one argument: the action */ + if (optind >= argc) + usage(); + + /* 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) { + msg ("Parsing configuration %s", config_file); + if (! (yyin = fopen (config_file, "r")) ) + error ("Cannot read configuration %s: %s", + config_file, strerror(errno)); + yyparse(); + fclose (yyin); + } + if (!handler[i].handler (argc - optind, argv + optind + 1)) + error ("'%s' failed", argv[optind]); + return (0); + } + } + + usage(); + return (1); +} diff --git a/src/deallocreporter.c b/src/deallocreporter.c @@ -1,39 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/decrclientcount.c b/src/decrclientcount.c @@ -1,43 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 ("Service %s: total active clients now %u", - activeservice->name, totclients); - - /* Warning: Use current_backend as index only if >= 0; it - * may be -1 when still searching for an HTTP back end */ - if (current_backend >= 0 && - servicereport->backendstate[current_backend].nclients > 0) - servicereport->backendstate[current_backend].nclients--; - - unlock_reporter(); - - if (current_backend >= 0) { - msg ("Service %s: extcmd-onend: " - " current_backend = %d, clients = %d, " - "totclients = %d, cmd = %s", - activeservice->name, current_backend, - servicereport->backendstate[current_backend].nclients, - servicereport->nclients, - activeservice->backend[current_backend].onend); - - sysrun (activeservice->backend[current_backend].onend); - } -} diff --git a/src/error.c b/src/error.c @@ -1,23 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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) - fprintf (stderr, "ERROR: %s\n", str); - else - writelog (LOG_ERR, "ERROR: %s", str); - free (str); - } - _exit (1); -} diff --git a/src/forktcpservicer.c b/src/forktcpservicer.c @@ -1,48 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 fork_tcp_servicer (int to_backend) { - int pid, i; - - msg ("Service %s: Forking TCP servicer (to back end: %d)", - activeservice->name, to_backend); - - if ( (pid = fork()) < 0 ) { - /* Fork failure. Return nonzero so that caller thinks they're - * the parent. */ - warning ("Service %s: failed to fork: %s", - activeservice->name, strerror(errno)); - return (-1); - } else if (pid) { - /* Parent branch */ - msg ("Service %s: communications will be handled by pid %d", - activeservice->name, pid); - return (pid); - } else { - /* Child branch: here we will serve the socket pair. - * We want to catch interrupts, but not die. */ - for (i = 0; relevant_sigs[i]; i++) - signal (relevant_sigs[i], interrupt); - - /* Forked for the second time... */ - program_stage = stage_serving; - - if (to_backend >= 0) - set_program_title ("Service %s: serving %s to %s", - client_ip, - activeservice->name, - activeservice->backend [current_backend].name); - else - set_program_title ("Service %s: serving %s", - activeservice->name, client_ip); - return (0); - } - - /* To satisfy the prototype... */ - return (0); -} diff --git a/src/hashpjw.c b/src/hashpjw.c @@ -1,25 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 hashpjw (char const *str) { - int 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/httpcopy.c b/src/httpcopy.c @@ -1,105 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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; - - 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 > TCP_BUFSZ) - to_copy = 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 ("Got chunk size 0x%x (%d)", ret, ret); */ - 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; - unsigned nbytes; - - msg ("Service %s: copying HTTP body from %s", - activeservice->name, - dir == dir_client_to_server ? - "client to server" : "server to client"); - - /* Check in what 'mode' we are. - * We know 3 modes: - * - Transfer-Encoding is chunked: we copy chunks - * - Content-Length is supplied: we copy that # of bytes - * - None of the above: don't do anything, http_serve() will go - * into copy-thru mode - */ - - if ( (mode = http_header_val (h, "transfer-encoding")) && *mode ) { - if (strncasecmp ( (char const *) mode, "chunked", 7)) - error ("Service %s: can't handle transfer-encoding '%s'", - activeservice->name, mode); - msg ("Service %s: copying chunks from %s", - activeservice->name, 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 ("Service %s: Next chunk is 0x%x (%d) bytes", - activeservice->name, 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 ) { - nbytes = atoi ( (char const *) mode ); - msg ("Service %s: copying %u bytes of content from %s", - activeservice->name, nbytes, - dir == dir_client_to_server ? - "client to server" : "server to client"); - copy (src, dst, dir, nbytes); - } else - msg ("Service %s: no body to send", activeservice->name); -} diff --git a/src/httperror.c b/src/httperror.c @@ -1,18 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/httpheaderaddheader.c b/src/httpheaderaddheader.c @@ -1,33 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 ("Service %s: adding header '%s'", activeservice->name, exp); - m->header = xrealloc (m->header, (m->nheader + 1) * sizeof(char*)); - m->header[m->nheader++] = exp; - SHOWHEADERS(m); -} diff --git a/src/httpheaderappendheader.c b/src/httpheaderappendheader.c @@ -1,44 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 ("Service %s: appending (after existing) header, now '%s'", - activeservice->name, m->header[i]); */ - free (hname); - return; - } - } - - /* msg ("Service %s: appending (setting) header '%s'", - activeservice->name, h); */ - - http_header_addheader (m, h); -} diff --git a/src/httpheaderconnectiontype.c b/src/httpheaderconnectiontype.c @@ -1,31 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 ("Service %s: Cannot determine connection type, " - "no such header", activeservice->name); - return (con_unknown); - } - if (strcasestr ((char const *)val, "close")) { - msg ("Service %s: Connection-Type is CLOSE", - activeservice->name); - return (con_close); - } else if (strcasestr ((char const *)val, "keep-alive")) { - msg ("Service %s: Connection-Type is KEEP-ALIVE", - activeservice->name); - return (con_keepalive); - } - warning ("Service %s: Unsupported Connection-Type '%s'", - activeservice->name, val); - return (con_unknown); -} diff --git a/src/httpheaderfree.c b/src/httpheaderfree.c @@ -1,16 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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]); -} diff --git a/src/httpheaderhascookie.c b/src/httpheaderhascookie.c @@ -1,34 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 ("Service %s: no cookies in HTTP message", activeservice->name); - 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 ("Service %s: found cookie '%s' in '%s'", - activeservice->name, cookie, buf); - free (buf); - return (1); - } - } - msg ("Service %s: cookie '%s' not present in '%s'", - activeservice->name, cookie, buf); - free (buf); - return (0); -} diff --git a/src/httpheaderhttpver.c b/src/httpheaderhttpver.c @@ -1,36 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 ("Service %s: cannot get HTTP version, no headers", - activeservice->name); - return (0.9); - } - - /* We need HTTP/1.? length */ - if (strlen (h->header[0]) < 8) { - warning ("Service %s: cannot get HTTP version, header line '%s'", - activeservice->name, 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 ("Service %s: HTTP version is %g (headerline %s)", - activeservice->name, ret, h->header[0]); - return (ret); -} - diff --git a/src/httpheadernew.c b/src/httpheadernew.c @@ -1,16 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/httpheaderread.c b/src/httpheaderread.c @@ -1,55 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 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)) -#else -#define SHOWHEADERS(h) -#endif - -void http_header_read (HttpHeader *h, int sock, CopyDirection dir) { - unsigned char *cp; - int last_is_nl = 0, at_start = 1; - - msg ("Service %s: reading HTTP headers from %s", - activeservice->name, - dir == dir_client_to_server ? "client" : "server"); - while (1) { - cp = net_bufread (sock, 1, 0, dir == dir_client_to_server); - /* msg ("http header read: got char %d (%c)", *cp, *cp); */ - /* SHOWHEADERS(h); */ - if (*cp == '\r') - continue; - if (*cp == '\n') { - if (last_is_nl && h->nheader) - break; - last_is_nl++; - continue; - } - if (at_start || last_is_nl) { - h->header = xrealloc (h->header, (h->nheader + 1) * sizeof(char*)); - h->header[h->nheader] = 0; - h->nheader++; - at_start = 0; - } - h->header[h->nheader - 1] = xstrcatch (h->header[h->nheader - 1], *cp); - last_is_nl = 0; - } - - SHOWHEADERS(h); -} diff --git a/src/httpheaderremoveheader.c b/src/httpheaderremoveheader.c @@ -1,22 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 ("Service %s: removing header '%s'", - activeservice->name, hdr); - free (h->header[i]); - h->header[i] = 0; - } - } -} diff --git a/src/httpheadersetheader.c b/src/httpheadersetheader.c @@ -1,37 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 ("Service %s: setting (replacing) header '%s'", - activeservice->name, exp); - m->header[i] = exp; - free (hname); - return; - } - } - - msg ("Service %s: setting (adding) header '%s'", activeservice->name, exp); - m->header = xrealloc (m->header, (m->nheader + 1) * sizeof(char*)); - m->header[m->nheader++] = exp; - free (hname); -} diff --git a/src/httpheaderval.c b/src/httpheaderval.c @@ -1,27 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/httpheaderwrite.c b/src/httpheaderwrite.c @@ -1,25 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 ("Service %s: Sending %d HTTP headers to %s", - activeservice->name, 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 ("Service %s: sending header %d: '%s'", - activeservice->name, 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/httpinsertheader.c b/src/httpinsertheader.c @@ -1,55 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/httpserve.c b/src/httpserve.c @@ -1,213 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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; - unsigned char *cp; - int size; - - /* Fork off a servicer if we're in daemon mode. */ - if (fork_tcp_servicer(-1)) - return; - - /* 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 - */ - - while (1) { - /* 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 */ - clientreq = http_header_new(); - http_header_read (clientreq, clientsock, dir_client_to_server); - - /* Determine the back end if necessary. */ - if (serversock == -1) { - if ( (serversock = http_serversocket (clientreq, - &is_continuation)) < 1 ) - http_error (clientsock); - - 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 ("Service %s: Client talks HTTP < 1.1, forcing closing " - "connections", activeservice->name); - 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 ("Service %s: Client asks for connection closing", - activeservice->name); - client_persisting = 0; - } - - /* Send client's headers to the back end. */ - http_header_write (clientreq, serversock, dir_client_to_server); - - /* Copy body from client to server */ - http_copy (clientreq, clientsock, serversock, dir_client_to_server); - if ( (cp = net_buffer (dir_client_to_server, &size)) ) - net_write (serversock, cp, size, 0); - - /* Get server response. */ - serverresp = http_header_new(); - http_header_read (serverresp, serversock, dir_server_to_client); - - /* 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 ("Service %s: Server is sending chunks, forcing singleshot", - activeservice->name); - server_persisting = 0; - http_header_setheader (serverresp, "Connection: close"); - http_header_setheader (serverresp, "Proxy-Connection: close"); - } - - /* 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 ("Service %s: Server is sending chunks, forcing singleshot", - activeservice->name); - 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 ("Service %s: Server talks HTTP < 1.1, forcing closing " - "connections", activeservice->name); - 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 ("Service %s: Server asks for connection closing", - activeservice->name); - http_header_setheader (serverresp, "Connection: close"); - http_header_setheader (serverresp, "Proxy-Connection: close"); - server_persisting = 0; - } - } - - /* Send server headers to the client. */ - http_header_write (serverresp, clientsock, dir_server_to_client); - - /* Copy body from server to cliet and flush network buffers if any */ - http_copy (serverresp, serversock, clientsock, dir_server_to_client); - if ( (cp = net_buffer (dir_server_to_client, &size)) ) - net_write (clientsock, cp, size, 0); - - /* Free up info from this request/response chat. */ - http_header_free (clientreq); - http_header_free (serverresp); - - /* 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 ("Service %s: non-persistent connection", - activeservice->name); - break; - } - - msg ("Service %s: Analyzing following requests over same TCP link", - activeservice->name); - } - - /* We're done analyzing. If there's leftovers in the network buffers, - * then we flush them first. */ - if (clbufmax) { - msg ("Service %s: Flushing client-side buffer to server, %u bytes", - activeservice->name, clbufmax - clbufpos); - http_write (serversock, dir_client_to_server, - clbuf + clbufpos, clbufmax - clbufpos); - clbufmax = clbufpos = 0; - } - if (srbufmax) { - msg ("Service %s: Flushing server-side buffer to client, %u bytes", - activeservice->name, 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 ("Service %s: HTTP service done analyzing, entering copy-thru mode", - activeservice->name); - - /* This doesn't return */ - copysockets (clientsock, serversock); - -} diff --git a/src/httpserversocket.c b/src/httpserversocket.c @@ -1,76 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 ("Service %s: searching for back end for HTTP request.", - activeservice->name); - - /* Try to find a sticky cookie in the request. */ - for (i = 0; i < activeservice->nbackend; i++) { - if (servicereport->backendstate[i].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 ("Service %s: HTTP backend %d selected due to cookie '%s'", - activeservice->name, - 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 ("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 ("Service %s: " - "out of back ends while scanning for HTTP back end", - activeservice->name); - return (-1); - } - - /* Try one. */ - choose_backend(); - if (current_backend < 0) { - warning ("No back end for request."); - return (-2); - } - - msg ("Service %s: trying back end %d for new HTTP connection", - activeservice->name, current_backend); - if ( (sock = backend_connect ()) >= 0 ) { - servicereport->backendstate[current_backend].sessions++; - *is_continuation = 0; - set_program_title ("Service %s: serving %s to %s", - activeservice->name, - client_ip, - activeservice->backend[current_backend].name); - return (sock); - } - } -} diff --git a/src/httpwrite.c b/src/httpwrite.c @@ -1,18 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/incrclientcount.c b/src/incrclientcount.c @@ -1,40 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 ("Service %s: extcmd-onstart: " - " current_backend = %d, clients = %d, totclients = %d, cmd = %s", - activeservice->name, current_backend, - servicereport->backendstate[current_backend].nclients, - servicereport->nclients, - activeservice->backend[current_backend].onstart); - - sysrun (activeservice->backend[current_backend].onstart); - - msg ("Service %s: Activity on back end %d now %d, total %d", - activeservice->name, current_backend, - servicereport->backendstate[current_backend].nclients, - totclients); - } -} diff --git a/src/initsockaddr.c b/src/initsockaddr.c @@ -1,21 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 hostent *hostinfo; - - if (program_stage != stage_retrying) - msg ("Service %s: trying to connect to backend %s:%d", - activeservice->name, hostname, port); - name->sin_family = AF_INET; - name->sin_port = htons (port); - if (! (hostinfo = gethostbyname (hostname)) ) - return (1); - name->sin_addr = *(struct in_addr *) hostinfo->h_addr; - return (0); -} diff --git a/src/interrupt.c b/src/interrupt.c @@ -1,55 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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: - interrupted++; - - switch (program_stage) { - case stage_waiting: - warning ("Service %s: listener caught signal %d, " - "closing socket %d and exiting", - activeservice->name, sig, listen_sock); - shutdown (listen_sock, SHUT_RDWR); - close (listen_sock); - exit (0); - break; - - case stage_serving: - /* This will serve the current connection and then stop. */ - break; - - case stage_retrying: - warning ("Service %s: wakeup handler caught signal %d, " - "stopping wake ups and exiting", - activeservice->name, sig); - exit (0); - - default: - msg ("Caught signal %d in program stage %s, exiting", sig, - stage_to_string (program_stage)); - exit (0); - } - } -} diff --git a/src/ipfaddallow.c b/src/ipfaddallow.c @@ -1,17 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/ipfadddeny.c b/src/ipfadddeny.c @@ -1,17 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/ipfallowed.c b/src/ipfallowed.c @@ -1,22 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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) - return (1); - - /* Try all in the chain. */ - for (i = 0; i < activeservice->nallowchain; i++) - if (ipf_match (activeservice->allowchain[i])) - return (1); - - /* Allow chain doesn't match */ - return (0); -} diff --git a/src/ipfdenied.c b/src/ipfdenied.c @@ -1,22 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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) - return (0); - - /* Try all in the chain. */ - for (i = 0; i < activeservice->ndenychain; i++) - if (ipf_match (activeservice->denychain[i])) - return (1); - - /* Deny chain doesn't match */ - return (0); -} diff --git a/src/ipfloadfile.c b/src/ipfloadfile.c @@ -1,53 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 ("Service %s: loading IP filter file: '%s'", - activeservice->name, fname); - - if (! (f = fopen (fname, "r")) ) { - warning ("Service %s: can't read filter file '%s': %s", - activeservice->name, 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 ("Service %s: bad ip filter in file '%s'", - activeservice->name, fname); - ret++; - } else { - msg ("Service %s: got ip filter specifier '%s'", - activeservice->name, buf); - *chain = xrealloc (*chain, (*nchain + 1) * sizeof(IpFilter)); - (*chain)[*nchain] = filter; - (*nchain)++; - nloaded++; - } - } - - msg ("Service %s: loaded IP filter file '%s': %d successfully loaded", - activeservice->name, fname, nloaded); - - fclose (f); - return (ret); -} diff --git a/src/ipfmatch.c b/src/ipfmatch.c @@ -1,43 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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) { - static int client_ip_nr; - int counter, val; - char *tmp, *cp; - - /* 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. */ - if (!client_ip_nr) { - tmp = xstrdup (client_ip); - counter = 0; - for (counter = 0, cp = strtok (tmp, "."); - cp; - counter += 8, cp = strtok (0, ".")) { - if (sscanf (cp, "%d", &val) < 1) { - free (tmp); - return (1); - } - val <<= counter; - client_ip_nr |= val; - /* msg ("ipf_match: val 0x%x, client_ip_nr 0x%x", - * val, client_ip_nr); */ - } - } - free (tmp); - - /* Here's the comparison. */ - /* msg ("ipf_match: filter ip/mask 0x%x/0x%x, " - * "filter res 0x%x, client res 0x%x", - * f.ip, f.mask, - * (f.ip & f.mask), (client_ip_nr & f.mask)); - */ - return ( (f.ip & f.mask) == (client_ip_nr & f.mask) ); -} diff --git a/src/ipfparse.c b/src/ipfparse.c @@ -1,51 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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; - int counter, nr, i; - - memset (res, 0, sizeof(IpFilter)); - str = xstrdup (val); - - for (counter = 0, cp = strtok (str, "."); - cp; - counter += 8, cp = strtok (0, ".")) { - 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/ishexdigit.c b/src/ishexdigit.c @@ -1,15 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/isspace.c b/src/isspace.c @@ -1,15 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/lexer.c b/src/lexer.c @@ -1,2358 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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" -/* A lexical scanner generated by flex */ - -/* Scanner skeleton version: - * $Header: /cvs/root/flex/flex/skel.c,v 1.2 2004/05/07 00:28:17 jkh Exp $ - */ - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 - -#include <stdio.h> - - -/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ -#ifdef c_plusplus -#ifndef __cplusplus -#define __cplusplus -#endif -#endif - - -#ifdef __cplusplus - -#include <stdlib.h> -#include <unistd.h> - -/* Use prototypes in function declarations. */ -#define YY_USE_PROTOS - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -#if __STDC__ - -#define YY_USE_PROTOS -#define YY_USE_CONST - -#endif /* __STDC__ */ -#endif /* ! __cplusplus */ - -#ifdef __TURBOC__ - #pragma warn -rch - #pragma warn -use -#include <io.h> -#include <stdlib.h> -#define YY_USE_CONST -#define YY_USE_PROTOS -#endif - -#ifdef YY_USE_CONST -#define yyconst const -#else -#define yyconst -#endif - - -#ifdef YY_USE_PROTOS -#define YY_PROTO(proto) proto -#else -#define YY_PROTO(proto) () -#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. */ -#define YY_BUF_SIZE 16384 - -typedef struct yy_buffer_state *YY_BUFFER_STATE; - -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 - -/* The funky do-while in the following #define is used to turn the definition - * int a single C statement (which needs a semi-colon terminator). This - * avoids problems with code like: - * - * if ( condition_holds ) - * yyless( 5 ); - * else - * do_something_else(); - * - * Prior to using the do-while the compiler would get upset at the - * "else" because it interpreted the "if" statement as being all - * done when it reached the ';' after the yyless() call. - */ - -/* Return all but the first 'n' matched characters back to the input stream. */ - -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - *yy_cp = yy_hold_char; \ - YY_RESTORE_YY_MORE_OFFSET \ - yy_c_buf_p = yy_cp = yy_bp + n - 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). - */ -typedef unsigned int yy_size_t; - - -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; - - /* 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 - }; - -static YY_BUFFER_STATE yy_current_buffer = 0; - -/* 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". - */ -#define YY_CURRENT_BUFFER yy_current_buffer - - -/* 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 = 1; /* 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 YY_PROTO(( FILE *input_file )); - -void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); -void yy_load_buffer_state YY_PROTO(( void )); -YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); -void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); -void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); -void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); -#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) - -YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); -YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); -YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); - -static void *yy_flex_alloc YY_PROTO(( yy_size_t )); -static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); -static void yy_flex_free YY_PROTO(( void * )); - -#define yy_new_buffer yy_create_buffer - -#define yy_set_interactive(is_interactive) \ - { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_is_interactive = is_interactive; \ - } - -#define yy_set_bol(at_bol) \ - { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_at_bol = at_bol; \ - } - -#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) - -typedef unsigned char YY_CHAR; -FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; -typedef int yy_state_type; -extern char *yytext; -#define yytext_ptr yytext - -static yy_state_type yy_get_previous_state YY_PROTO(( void )); -static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); -static int yy_get_next_buffer YY_PROTO(( void )); -static void yy_fatal_error YY_PROTO(( 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 = (int) (yy_cp - yy_bp); \ - yy_hold_char = *yy_cp; \ - *yy_cp = '\0'; \ - yy_c_buf_p = yy_cp; - -#define YY_NUM_RULES 66 -#define YY_END_OF_BUFFER 67 -static yyconst short int yy_accept[416] = - { 0, - 0, 0, 0, 0, 0, 0, 67, 55, 53, 54, - 55, 55, 52, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 64, 65, 63, 64, 64, 62, 59, 58, - 59, 53, 0, 1, 56, 0, 52, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 50, 51, 49, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 0, 60, 0, 61, 57, 0, 2, 51, 51, - 29, 51, 51, 51, 51, 51, 51, 51, 51, 51, - - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 49, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 31, 51, 51, 51, - 51, 6, 5, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 28, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 15, 51, 51, 51, 51, 51, 37, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 4, 51, 51, 51, 51, 21, 51, 51, 51, - 51, 51, 51, 51, 36, 51, 19, 51, 51, 51, - 16, 51, 51, 51, 7, 51, 51, 51, 51, 51, - 14, 51, 51, 51, 51, 51, 51, 8, 9, 51, - 51, 51, 22, 51, 51, 51, 51, 51, 51, 51, - 35, 10, 51, 51, 3, 51, 51, 51, 51, 51, - 51, 51, 11, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 48, 46, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - - 51, 51, 47, 45, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 25, 51, 20, - 51, 51, 51, 51, 51, 51, 18, 51, 51, 51, - 30, 51, 33, 51, 51, 51, 51, 51, 51, 51, - 51, 34, 51, 51, 51, 51, 51, 51, 51, 26, - 51, 51, 51, 51, 51, 51, 17, 51, 51, 51, - 51, 51, 38, 51, 51, 51, 51, 51, 23, 51, - 51, 51, 51, 51, 51, 32, 51, 51, 51, 51, - 51, 51, 13, 51, 51, 51, 39, 42, 51, 51, - - 51, 24, 51, 40, 43, 51, 51, 51, 27, 51, - 51, 12, 41, 44, 0 - } ; - -static yyconst int yy_ec[256] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 4, 1, 5, 6, 1, 1, 1, 7, 1, - 1, 8, 1, 1, 1, 1, 9, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 1, 11, 1, - 1, 1, 1, 1, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 1, 1, 1, 1, 12, 1, 13, 14, 15, 16, - - 17, 18, 19, 20, 21, 12, 22, 23, 24, 25, - 26, 27, 12, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 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 int yy_meta[37] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, - 1, 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 - } ; - -static yyconst short int yy_base[423] = - { 0, - 0, 0, 34, 39, 44, 45, 444, 445, 47, 445, - 440, 46, 432, 0, 40, 45, 415, 40, 406, 426, - 408, 424, 410, 44, 409, 47, 55, 54, 405, 416, - 415, 414, 445, 445, 445, 425, 422, 445, 445, 445, - 419, 66, 424, 445, 445, 423, 415, 0, 408, 400, - 387, 394, 405, 394, 62, 393, 68, 388, 392, 385, - 391, 383, 378, 0, 393, 69, 393, 381, 383, 49, - 376, 62, 382, 384, 376, 71, 376, 385, 373, 379, - 370, 393, 445, 390, 445, 445, 393, 445, 79, 369, - 0, 377, 371, 376, 73, 360, 362, 368, 363, 374, - - 351, 358, 357, 366, 353, 354, 365, 354, 365, 347, - 348, 345, 358, 345, 351, 346, 338, 80, 347, 353, - 341, 348, 348, 347, 335, 348, 342, 0, 337, 342, - 325, 332, 80, 326, 334, 329, 325, 336, 315, 333, - 314, 330, 334, 316, 317, 327, 0, 317, 326, 320, - 327, 0, 0, 313, 317, 305, 320, 83, 312, 317, - 316, 310, 300, 312, 0, 316, 302, 307, 305, 297, - 306, 307, 297, 295, 294, 302, 293, 304, 299, 298, - 299, 0, 84, 283, 284, 286, 285, 0, 286, 280, - 283, 289, 284, 276, 275, 287, 280, 272, 264, 263, - - 278, 275, 280, 265, 263, 275, 259, 85, 86, 274, - 270, 0, 263, 270, 256, 257, 0, 254, 260, 256, - 266, 267, 266, 253, 0, 247, 0, 247, 250, 248, - 0, 256, 255, 239, 0, 96, 250, 254, 253, 93, - 0, 242, 249, 242, 238, 240, 245, 0, 0, 231, - 245, 238, 0, 237, 240, 232, 235, 236, 230, 235, - 0, 0, 232, 236, 0, 224, 231, 221, 216, 218, - 221, 217, 0, 212, 211, 212, 222, 214, 216, 208, - 214, 204, 207, 206, 0, 0, 207, 212, 209, 213, - 206, 205, 195, 196, 197, 192, 190, 194, 188, 183, - - 197, 196, 0, 0, 198, 182, 186, 191, 186, 185, - 183, 187, 194, 176, 180, 179, 183, 182, 179, 173, - 169, 179, 172, 179, 178, 169, 176, 0, 166, 0, - 161, 174, 174, 163, 166, 156, 0, 168, 167, 162, - 0, 159, 0, 151, 167, 166, 148, 149, 151, 154, - 157, 0, 157, 146, 154, 157, 156, 151, 141, 0, - 150, 149, 144, 143, 133, 137, 0, 137, 134, 130, - 141, 140, 0, 136, 137, 136, 135, 134, 0, 133, - 132, 119, 115, 129, 128, 0, 116, 115, 129, 128, - 114, 111, 0, 125, 109, 108, 0, 0, 119, 118, - - 102, 0, 109, 0, 0, 114, 113, 99, 0, 79, - 31, 0, 0, 0, 445, 116, 118, 120, 38, 122, - 124, 126 - } ; - -static yyconst short int yy_def[423] = - { 0, - 415, 1, 416, 416, 417, 417, 415, 415, 415, 415, - 418, 415, 415, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 415, 415, 415, 420, 421, 415, 415, 415, - 415, 415, 418, 415, 415, 422, 415, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 420, 415, 421, 415, 415, 422, 415, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - - 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 419, 0, 415, 415, 415, 415, 415, - 415, 415 - } ; - -static yyconst short int yy_nxt[482] = - { 0, - 8, 9, 10, 9, 8, 11, 8, 8, 12, 13, - 8, 14, 15, 16, 17, 18, 19, 20, 14, 21, - 14, 14, 14, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 14, 32, 14, 34, 35, 36, 48, - 37, 34, 35, 36, 38, 37, 40, 40, 42, 38, - 42, 41, 41, 45, 46, 49, 57, 53, 414, 69, - 58, 65, 50, 70, 51, 54, 52, 42, 66, 42, - 59, 72, 71, 75, 73, 67, 95, 96, 114, 55, - 115, 76, 100, 122, 74, 108, 109, 97, 77, 117, - 98, 118, 101, 129, 159, 135, 173, 110, 136, 195, - - 246, 123, 174, 196, 219, 244, 413, 130, 160, 273, - 268, 220, 245, 274, 247, 269, 33, 33, 39, 39, - 43, 43, 82, 82, 84, 84, 87, 87, 412, 411, - 410, 409, 408, 407, 406, 405, 404, 403, 402, 401, - 400, 399, 398, 397, 396, 395, 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, 362, 361, - 360, 359, 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, 273, 323, 322, - 321, 320, 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, 287, 286, 285, 284, 283, 282, - 281, 280, 279, 278, 277, 276, 275, 272, 271, 270, - 267, 266, 265, 264, 263, 262, 261, 260, 259, 258, - 257, 256, 255, 254, 253, 252, 251, 250, 249, 248, - 243, 242, 241, 240, 239, 238, 237, 236, 235, 234, - - 233, 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, - 201, 200, 199, 198, 197, 194, 193, 192, 191, 190, - 189, 188, 187, 64, 186, 185, 184, 183, 182, 181, - 180, 179, 178, 177, 176, 175, 172, 171, 170, 169, - 168, 167, 166, 165, 128, 164, 163, 162, 161, 158, - 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, - 147, 146, 145, 144, 143, 142, 141, 140, 139, 138, - 137, 134, 133, 132, 131, 88, 85, 83, 128, 127, - - 126, 125, 124, 121, 120, 119, 116, 113, 112, 111, - 64, 107, 106, 105, 104, 103, 102, 99, 94, 93, - 92, 91, 90, 89, 47, 88, 44, 86, 85, 83, - 81, 80, 79, 78, 68, 64, 63, 62, 61, 60, - 56, 47, 44, 415, 7, 415, 415, 415, 415, 415, - 415, 415, 415, 415, 415, 415, 415, 415, 415, 415, - 415, 415, 415, 415, 415, 415, 415, 415, 415, 415, - 415, 415, 415, 415, 415, 415, 415, 415, 415, 415, - 415 - } ; - -static yyconst short int yy_chk[482] = - { 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, 3, 3, 3, 419, - 3, 4, 4, 4, 3, 4, 5, 6, 9, 4, - 9, 5, 6, 12, 12, 15, 18, 16, 411, 26, - 18, 24, 15, 26, 15, 16, 15, 42, 24, 42, - 18, 27, 26, 28, 27, 24, 55, 55, 70, 16, - 70, 28, 57, 76, 27, 66, 66, 55, 28, 72, - 55, 72, 57, 89, 118, 95, 133, 66, 95, 158, - - 209, 76, 133, 158, 183, 208, 410, 89, 118, 240, - 236, 183, 208, 240, 209, 236, 416, 416, 417, 417, - 418, 418, 420, 420, 421, 421, 422, 422, 408, 407, - 406, 403, 401, 400, 399, 396, 395, 394, 392, 391, - 390, 389, 388, 387, 385, 384, 383, 382, 381, 380, - 378, 377, 376, 375, 374, 372, 371, 370, 369, 368, - 366, 365, 364, 363, 362, 361, 359, 358, 357, 356, - 355, 354, 353, 351, 350, 349, 348, 347, 346, 345, - 344, 342, 340, 339, 338, 336, 335, 334, 333, 332, - 331, 329, 327, 326, 325, 324, 323, 322, 321, 320, - - 319, 318, 317, 316, 315, 314, 313, 312, 311, 310, - 309, 308, 307, 306, 305, 302, 301, 300, 299, 298, - 297, 296, 295, 294, 293, 292, 291, 290, 289, 288, - 287, 284, 283, 282, 281, 280, 279, 278, 277, 276, - 275, 274, 272, 271, 270, 269, 268, 267, 266, 264, - 263, 260, 259, 258, 257, 256, 255, 254, 252, 251, - 250, 247, 246, 245, 244, 243, 242, 239, 238, 237, - 234, 233, 232, 230, 229, 228, 226, 224, 223, 222, - 221, 220, 219, 218, 216, 215, 214, 213, 211, 210, - 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, - - 197, 196, 195, 194, 193, 192, 191, 190, 189, 187, - 186, 185, 184, 181, 180, 179, 178, 177, 176, 175, - 174, 173, 172, 171, 170, 169, 168, 167, 166, 164, - 163, 162, 161, 160, 159, 157, 156, 155, 154, 151, - 150, 149, 148, 146, 145, 144, 143, 142, 141, 140, - 139, 138, 137, 136, 135, 134, 132, 131, 130, 129, - 127, 126, 125, 124, 123, 122, 121, 120, 119, 117, - 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, - 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, - 96, 94, 93, 92, 90, 87, 84, 82, 81, 80, - - 79, 78, 77, 75, 74, 73, 71, 69, 68, 67, - 65, 63, 62, 61, 60, 59, 58, 56, 54, 53, - 52, 51, 50, 49, 47, 46, 43, 41, 37, 36, - 32, 31, 30, 29, 25, 23, 22, 21, 20, 19, - 17, 13, 11, 7, 415, 415, 415, 415, 415, 415, - 415, 415, 415, 415, 415, 415, 415, 415, 415, 415, - 415, 415, 415, 415, 415, 415, 415, 415, 415, 415, - 415, 415, 415, 415, 415, 415, 415, 415, 415, 415, - 415 - } ; - -static yy_state_type yy_last_accepting_state; -static char *yy_last_accepting_cpos; - -/* 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" -#define INITIAL 0 -#line 2 "lexer.l" -#include "crossroads.h" -#include "parser.h" - -/* Required by flex */ -static int yywrap () { - return (1); -} - -/* Lexer debugging related */ -// #define LEXER_DEBUG -#ifdef LEXER_DEBUG - static void lmsg (char const *x) { - printf ("L: %s\n", x); - } - static void llmsg (char const *x, char const *y) { - printf ("L: %s %s\n", x, y); - } -#else -# define lmsg(x) -# define llmsg(x,y) -#endif -#define stringstate 1 -#define commentstate 2 - -#line 633 "lexer.c" - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int yywrap YY_PROTO(( void )); -#else -extern int yywrap YY_PROTO(( void )); -#endif -#endif - -#ifndef YY_NO_UNPUT -static void yyunput YY_PROTO(( int c, char *buf_ptr )); -#endif - -#ifndef yytext_ptr -static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen YY_PROTO(( yyconst char * )); -#endif - -#ifndef YY_NO_INPUT -#ifdef __cplusplus -static int yyinput YY_PROTO(( void )); -#else -static int input YY_PROTO(( void )); -#endif -#endif - -#if YY_STACK_USED -static int yy_start_stack_ptr = 0; -static int yy_start_stack_depth = 0; -static int *yy_start_stack = 0; -#ifndef YY_NO_PUSH_STATE -static void yy_push_state YY_PROTO(( int new_state )); -#endif -#ifndef YY_NO_POP_STATE -static void yy_pop_state YY_PROTO(( void )); -#endif -#ifndef YY_NO_TOP_STATE -static int yy_top_state YY_PROTO(( void )); -#endif - -#else -#define YY_NO_PUSH_STATE 1 -#define YY_NO_POP_STATE 1 -#define YY_NO_TOP_STATE 1 -#endif - -#ifdef YY_MALLOC_DECL -YY_MALLOC_DECL -#else -#if __STDC__ -#ifndef __cplusplus -#include <stdlib.h> -#endif -#else -/* Just try to get by without declaring the routines. This will fail - * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) - * or sizeof(void*) != sizeof(int). - */ -#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->yy_is_interactive ) \ - { \ - int c = '*', 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 if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ - && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); -#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 - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL int yylex YY_PROTO(( void )) -#endif - -/* 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 \ - YY_USER_ACTION - -YY_DECL - { - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; - -#line 27 "lexer.l" - - -#line 787 "lexer.c" - - if ( yy_init ) - { - yy_init = 0; - -#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 ) - yy_current_buffer = - 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_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 >= 416 ) - 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] != 445 ); - -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 ("comment"); - yylineno++; -} - YY_BREAK -case 2: -YY_RULE_SETUP -#line 34 "lexer.l" -{ - lmsg ("comment"); - yylineno++; -} - YY_BREAK -case 3: -YY_RULE_SETUP -#line 39 "lexer.l" -{ - lmsg ("service"); - return (SERVICE); -} - YY_BREAK -case 4: -YY_RULE_SETUP -#line 44 "lexer.l" -{ - lmsg ("bindto"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (BINDTO); -} - YY_BREAK -case 5: -YY_RULE_SETUP -#line 52 "lexer.l" -{ - lmsg ("port"); - return (PORT); -} - YY_BREAK -case 6: -YY_RULE_SETUP -#line 57 "lexer.l" -{ - lmsg ("over"); - return (OVER); -} - YY_BREAK -case 7: -YY_RULE_SETUP -#line 62 "lexer.l" -{ - lmsg ("shmkey"); - return (SHMKEY); -} - YY_BREAK -case 8: -YY_RULE_SETUP -#line 67 "lexer.l" -{ - lmsg ("backend"); - return (BACKEND); -} - YY_BREAK -case 9: -YY_RULE_SETUP -#line 72 "lexer.l" -{ - lmsg ("backlog"); - return (BACKLOG); -} - YY_BREAK -case 10: -YY_RULE_SETUP -#line 77 "lexer.l" -{ - lmsg ("retries"); - return (RETRIES); -} - YY_BREAK -case 11: -YY_RULE_SETUP -#line 82 "lexer.l" -{ - lmsg ("verbosity"); - return (VERBOSITY); -} - YY_BREAK -case 12: -YY_RULE_SETUP -#line 87 "lexer.l" -{ - lmsg ("connectiontimeout"); - return (CONNECTIONTIMEOUT); -} - YY_BREAK -case 13: -YY_RULE_SETUP -#line 92 "lexer.l" -{ - lmsg ("maxconnections"); - return (MAXCONNECTIONS); -} - YY_BREAK -case 14: -YY_RULE_SETUP -#line 97 "lexer.l" -{ - lmsg ("weight"); - return (WEIGHT); -} - YY_BREAK -case 15: -YY_RULE_SETUP -#line 102 "lexer.l" -{ - lmsg ("decay"); - return (DECAY); -} - YY_BREAK -case 16: -YY_RULE_SETUP -#line 107 "lexer.l" -{ - lmsg ("server"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (SERVER); -} - YY_BREAK -case 17: -YY_RULE_SETUP -#line 115 "lexer.l" -{ - lmsg ("dispatchmode"); - return (DISPATCHMODE); -} - YY_BREAK -case 18: -YY_RULE_SETUP -#line 120 "lexer.l" -{ - lmsg ("roundrobin"); - return (ROUNDROBIN); -} - YY_BREAK -case 19: -YY_RULE_SETUP -#line 125 "lexer.l" -{ - lmsg ("random"); - return (RANDOM); -} - YY_BREAK -case 20: -YY_RULE_SETUP -#line 130 "lexer.l" -{ - lmsg ("byduration"); - return (BYDURATION); -} - YY_BREAK -case 21: -YY_RULE_SETUP -#line 135 "lexer.l" -{ - lmsg ("bysize"); - return (BYSIZE); -} - YY_BREAK -case 22: -YY_RULE_SETUP -#line 140 "lexer.l" -{ - lmsg ("byorder"); - return (BYORDER); -} - YY_BREAK -case 23: -YY_RULE_SETUP -#line 145 "lexer.l" -{ - lmsg ("byconnections"); - return (BYCONNECTIONS); -} - YY_BREAK -case 24: -YY_RULE_SETUP -#line 150 "lexer.l" -{ - lmsg ("externalhandler"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (EXTERNALHANDLER); -} - YY_BREAK -case 25: -YY_RULE_SETUP -#line 158 "lexer.l" -{ - lmsg ("byclientip"); - return (BYCLIENTIP); -} - YY_BREAK -case 26: -YY_RULE_SETUP -#line 163 "lexer.l" -{ - lmsg ("useraccount"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (USERACCOUNT); -} - YY_BREAK -case 27: -YY_RULE_SETUP -#line 171 "lexer.l" -{ - lmsg ("revivinginterval"); - return (REVIVINGINTERVAL); -} - YY_BREAK -case 28: -YY_RULE_SETUP -#line 176 "lexer.l" -{ - lmsg ("type"); - return (TYPE); -} - YY_BREAK -case 29: -YY_RULE_SETUP -#line 181 "lexer.l" -{ - lmsg ("any"); - return (ANY); -} - YY_BREAK -case 30: -YY_RULE_SETUP -#line 186 "lexer.l" -{ - lmsg ("stickyhttp"); - warning ("The 'stickyhttp protocol is obsolte.\n" - "You should change to 'http'."); - return (HTTP); -} - YY_BREAK -case 31: -YY_RULE_SETUP -#line 193 "lexer.l" -{ - lmsg ("http"); - return (HTTP); -} - YY_BREAK -case 32: -YY_RULE_SETUP -#line 198 "lexer.l" -{ - lmsg ("throughputlog"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (THROUGHPUTLOG); -} - YY_BREAK -case 33: -YY_RULE_SETUP -#line 206 "lexer.l" -{ - lmsg ("trafficlog"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (TRAFFICLOG); -} - YY_BREAK -case 34: -YY_RULE_SETUP -#line 214 "lexer.l" -{ - lmsg ("dumptraffic"); - warning ("The 'dumptraffic' statement is obsolete.\n" - "You should change to 'trafficlog'."); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (TRAFFICLOG); -} - YY_BREAK -case 35: -YY_RULE_SETUP -#line 224 "lexer.l" -{ - lmsg ("onstart"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (ONSTART); -} - YY_BREAK -case 36: -YY_RULE_SETUP -#line 232 "lexer.l" -{ - lmsg ("onfail"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (ONFAIL); -} - YY_BREAK -case 37: -YY_RULE_SETUP -#line 240 "lexer.l" -{ - lmsg ("onend"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (ONEND); -} - YY_BREAK -case 38: -YY_RULE_SETUP -#line 248 "lexer.l" -{ - lmsg ("stickycookie"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (STICKYCOOKIE); -} - YY_BREAK -case 39: -YY_RULE_SETUP -#line 256 "lexer.l" -{ - lmsg ("addclientheader"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (ADDCLIENTHEADER); -} - YY_BREAK -case 40: -YY_RULE_SETUP -#line 264 "lexer.l" -{ - lmsg ("setclientheader"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (SETCLIENTHEADER); -} - YY_BREAK -case 41: -YY_RULE_SETUP -#line 272 "lexer.l" -{ - lmsg ("appendclientheader"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (APPENDCLIENTHEADER); -} - YY_BREAK -case 42: -YY_RULE_SETUP -#line 280 "lexer.l" -{ - lmsg ("addserverheader"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (ADDSERVERHEADER); -} - YY_BREAK -case 43: -YY_RULE_SETUP -#line 288 "lexer.l" -{ - lmsg ("setserverheader"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (SETSERVERHEADER); -} - YY_BREAK -case 44: -YY_RULE_SETUP -#line 296 "lexer.l" -{ - lmsg ("appendserverheader"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (APPENDSERVERHEADER); -} - YY_BREAK -case 45: -YY_RULE_SETUP -#line 304 "lexer.l" -{ - lmsg ("allowfrom"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (ALLOWFROM); -} - YY_BREAK -case 46: -YY_RULE_SETUP -#line 312 "lexer.l" -{ - lmsg ("denyfrom"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (DENYFROM); -} - YY_BREAK -case 47: -YY_RULE_SETUP -#line 320 "lexer.l" -{ - lmsg ("allowfile"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (ALLOWFILE); -} - YY_BREAK -case 48: -YY_RULE_SETUP -#line 328 "lexer.l" -{ - lmsg ("denyfile"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (DENYFILE); -} - YY_BREAK -case 49: -YY_RULE_SETUP -#line 336 "lexer.l" -{ - lmsg ("on"); - return (ON); -} - YY_BREAK -case 50: -YY_RULE_SETUP -#line 341 "lexer.l" -{ - lmsg ("off"); - return (OFF); -} - YY_BREAK -case 51: -YY_RULE_SETUP -#line 346 "lexer.l" -{ - llmsg ("identifier", yytext); - return (IDENTIFIER); -} - YY_BREAK -case 52: -YY_RULE_SETUP -#line 351 "lexer.l" -{ - llmsg ("number", yytext); - return (NUMBER); -} - YY_BREAK -case 53: -YY_RULE_SETUP -#line 356 "lexer.l" -{ - lmsg ("space(s)"); -} - YY_BREAK -case 54: -YY_RULE_SETUP -#line 360 "lexer.l" -{ - lmsg ("newline"); - yylineno++; -} - YY_BREAK -case 55: -YY_RULE_SETUP -#line 365 "lexer.l" -{ - llmsg ("lone char", yytext); - return (*yytext); -} - YY_BREAK -case 56: -YY_RULE_SETUP -#line 370 "lexer.l" -{ - lmsg ("C-comment starts"); - BEGIN(commentstate); -} - YY_BREAK -case 57: -YY_RULE_SETUP -#line 374 "lexer.l" -{ - lmsg ("C-comment ends"); - BEGIN(0); -} - YY_BREAK -case 58: -YY_RULE_SETUP -#line 378 "lexer.l" -{ - yylineno++; -} - YY_BREAK -case 59: -YY_RULE_SETUP -#line 381 "lexer.l" -; - YY_BREAK -case 60: -YY_RULE_SETUP -#line 383 "lexer.l" -{ - llmsg ("string part", yytext); - laststring = xstrcat (laststring, yytext + 1); - laststring[strlen(laststring) - 1] = 0; -} - YY_BREAK -case 61: -YY_RULE_SETUP -#line 388 "lexer.l" -{ - llmsg ("string part", yytext); - laststring = xstrcat (laststring, yytext + 1); - laststring[strlen(laststring) - 1] = 0; -} - YY_BREAK -case 62: -YY_RULE_SETUP -#line 393 "lexer.l" -{ - BEGIN (0); - unput (';'); - llmsg ("string", laststring); - return (STRING); -} - YY_BREAK -case 63: -YY_RULE_SETUP -#line 399 "lexer.l" -{ - if (laststring) { - laststring = xstrcat (laststring, yytext); - llmsg ("string part", yytext); - } -} - YY_BREAK -case 64: -YY_RULE_SETUP -#line 405 "lexer.l" -{ - llmsg ("string part", yytext); - laststring = xstrcat (laststring, yytext); -} - YY_BREAK -case 65: -YY_RULE_SETUP -#line 409 "lexer.l" -{ - if (laststring) { - laststring = xstrcat (laststring, " "); - lmsg ("string part: newline, now space"); - } - yylineno++; -} - YY_BREAK -case 66: -YY_RULE_SETUP -#line 416 "lexer.l" -ECHO; - YY_BREAK -#line 1466 "lexer.c" -case YY_STATE_EOF(INITIAL): -case YY_STATE_EOF(stringstate): -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->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->yy_n_chars; - yy_current_buffer->yy_input_file = yyin; - yy_current_buffer->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->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->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() - { - register char *dest = yy_current_buffer->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->yy_ch_buf[yy_n_chars + 1] ) - YY_FATAL_ERROR( - "fatal flex scanner internal error--end of buffer missed" ); - - if ( yy_current_buffer->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->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->yy_n_chars = yy_n_chars = 0; - - else - { - int num_to_read = - yy_current_buffer->yy_buf_size - number_to_move - 1; - - while ( num_to_read <= 0 ) - { /* Not enough room in the buffer - grow it. */ -#ifdef YY_USES_REJECT - YY_FATAL_ERROR( -"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); -#else - - /* 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. */ - yy_flex_realloc( (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->yy_buf_size - - number_to_move - 1; -#endif - } - - if ( num_to_read > YY_READ_BUF_SIZE ) - num_to_read = YY_READ_BUF_SIZE; - - /* Read in more data. */ - YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), - yy_n_chars, num_to_read ); - - yy_current_buffer->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->yy_buffer_status = - YY_BUFFER_EOF_PENDING; - } - } - - else - ret_val = EOB_ACT_CONTINUE_SCAN; - - yy_n_chars += number_to_move; - yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; - yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; - - yytext_ptr = &yy_current_buffer->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() - { - register yy_state_type yy_current_state; - register char *yy_cp; - - yy_current_state = yy_start; - - 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 >= 416 ) - 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 ); - */ - -#ifdef YY_USE_PROTOS -static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) -#else -static yy_state_type yy_try_NUL_trans( yy_current_state ) -yy_state_type yy_current_state; -#endif - { - 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 >= 416 ) - 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 == 415); - - return yy_is_jam ? 0 : yy_current_state; - } - - -#ifndef YY_NO_UNPUT -#ifdef YY_USE_PROTOS -static void yyunput( int c, register char *yy_bp ) -#else -static void yyunput( c, yy_bp ) -int c; -register char *yy_bp; -#endif - { - register char *yy_cp = yy_c_buf_p; - - /* undo effects of setting up yytext */ - *yy_cp = yy_hold_char; - - if ( yy_cp < yy_current_buffer->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->yy_ch_buf[ - yy_current_buffer->yy_buf_size + 2]; - register char *source = - &yy_current_buffer->yy_ch_buf[number_to_move]; - - while ( source > yy_current_buffer->yy_ch_buf ) - *--dest = *--source; - - yy_cp += (int) (dest - source); - yy_bp += (int) (dest - source); - yy_current_buffer->yy_n_chars = - yy_n_chars = yy_current_buffer->yy_buf_size; - - if ( yy_cp < yy_current_buffer->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; - } -#endif /* ifndef YY_NO_UNPUT */ - - -#ifdef __cplusplus -static int yyinput() -#else -static int input() -#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->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 ); - - /* fall through */ - - case EOB_ACT_END_OF_FILE: - { - if ( yywrap() ) - return EOF; - - 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; - - - return c; - } - - -#ifdef YY_USE_PROTOS -void yyrestart( FILE *input_file ) -#else -void yyrestart( input_file ) -FILE *input_file; -#endif - { - if ( ! yy_current_buffer ) - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); - - yy_init_buffer( yy_current_buffer, input_file ); - yy_load_buffer_state(); - } - - -#ifdef YY_USE_PROTOS -void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) -#else -void yy_switch_to_buffer( new_buffer ) -YY_BUFFER_STATE new_buffer; -#endif - { - 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->yy_buf_pos = yy_c_buf_p; - yy_current_buffer->yy_n_chars = yy_n_chars; - } - - yy_current_buffer = 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; - } - - -#ifdef YY_USE_PROTOS -void yy_load_buffer_state( void ) -#else -void yy_load_buffer_state() -#endif - { - yy_n_chars = yy_current_buffer->yy_n_chars; - yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; - yyin = yy_current_buffer->yy_input_file; - yy_hold_char = *yy_c_buf_p; - } - - -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) -#else -YY_BUFFER_STATE yy_create_buffer( file, size ) -FILE *file; -int size; -#endif - { - YY_BUFFER_STATE b; - - b = (YY_BUFFER_STATE) yy_flex_alloc( 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 *) yy_flex_alloc( 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; - } - - -#ifdef YY_USE_PROTOS -void yy_delete_buffer( YY_BUFFER_STATE b ) -#else -void yy_delete_buffer( b ) -YY_BUFFER_STATE b; -#endif - { - if ( ! b ) - return; - - if ( b == yy_current_buffer ) - yy_current_buffer = (YY_BUFFER_STATE) 0; - - if ( b->yy_is_our_buffer ) - yy_flex_free( (void *) b->yy_ch_buf ); - - yy_flex_free( (void *) b ); - } - - -#ifndef YY_ALWAYS_INTERACTIVE -#ifndef YY_NEVER_INTERACTIVE -extern int isatty YY_PROTO(( int )); -#endif -#endif - -#ifdef YY_USE_PROTOS -void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) -#else -void yy_init_buffer( b, file ) -YY_BUFFER_STATE b; -FILE *file; -#endif - - - { - yy_flush_buffer( b ); - - b->yy_input_file = file; - b->yy_fill_buffer = 1; - -#if YY_ALWAYS_INTERACTIVE - b->yy_is_interactive = 1; -#else -#if YY_NEVER_INTERACTIVE - b->yy_is_interactive = 0; -#else - b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; -#endif -#endif - } - - -#ifdef YY_USE_PROTOS -void yy_flush_buffer( YY_BUFFER_STATE b ) -#else -void yy_flush_buffer( b ) -YY_BUFFER_STATE b; -#endif - - { - 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(); - } - - -#ifndef YY_NO_SCAN_BUFFER -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) -#else -YY_BUFFER_STATE yy_scan_buffer( base, size ) -char *base; -yy_size_t size; -#endif - { - 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) yy_flex_alloc( 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; - } -#endif - - -#ifndef YY_NO_SCAN_STRING -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) -#else -YY_BUFFER_STATE yy_scan_string( yy_str ) -yyconst char *yy_str; -#endif - { - int len; - for ( len = 0; yy_str[len]; ++len ) - ; - - return yy_scan_bytes( yy_str, len ); - } -#endif - - -#ifndef YY_NO_SCAN_BYTES -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) -#else -YY_BUFFER_STATE yy_scan_bytes( bytes, len ) -yyconst char *bytes; -int len; -#endif - { - YY_BUFFER_STATE b; - char *buf; - yy_size_t n; - int i; - - /* Get memory for full buffer, including space for trailing EOB's. */ - n = len + 2; - buf = (char *) yy_flex_alloc( n ); - if ( ! buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); - - for ( i = 0; i < len; ++i ) - buf[i] = bytes[i]; - - buf[len] = buf[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; - } -#endif - - -#ifndef YY_NO_PUSH_STATE -#ifdef YY_USE_PROTOS -static void yy_push_state( int new_state ) -#else -static void yy_push_state( new_state ) -int new_state; -#endif - { - if ( yy_start_stack_ptr >= yy_start_stack_depth ) - { - yy_size_t new_size; - - yy_start_stack_depth += YY_START_STACK_INCR; - new_size = yy_start_stack_depth * sizeof( int ); - - if ( ! yy_start_stack ) - yy_start_stack = (int *) yy_flex_alloc( new_size ); - - else - yy_start_stack = (int *) yy_flex_realloc( - (void *) yy_start_stack, new_size ); - - if ( ! yy_start_stack ) - YY_FATAL_ERROR( - "out of memory expanding start-condition stack" ); - } - - yy_start_stack[yy_start_stack_ptr++] = YY_START; - - BEGIN(new_state); - } -#endif - - -#ifndef YY_NO_POP_STATE -static void yy_pop_state() - { - if ( --yy_start_stack_ptr < 0 ) - YY_FATAL_ERROR( "start-condition stack underflow" ); - - BEGIN(yy_start_stack[yy_start_stack_ptr]); - } -#endif - - -#ifndef YY_NO_TOP_STATE -static int yy_top_state() - { - return yy_start_stack[yy_start_stack_ptr - 1]; - } -#endif - -#ifndef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#endif - -#ifdef YY_USE_PROTOS -static void yy_fatal_error( yyconst char msg[] ) -#else -static void yy_fatal_error( msg ) -char msg[]; -#endif - { - (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. */ \ - yytext[yyleng] = yy_hold_char; \ - yy_c_buf_p = yytext + n; \ - yy_hold_char = *yy_c_buf_p; \ - *yy_c_buf_p = '\0'; \ - yyleng = n; \ - } \ - while ( 0 ) - - -/* Internal utility routines. */ - -#ifndef yytext_ptr -#ifdef YY_USE_PROTOS -static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) -#else -static void yy_flex_strncpy( s1, s2, n ) -char *s1; -yyconst char *s2; -int n; -#endif - { - register int i; - for ( i = 0; i < n; ++i ) - s1[i] = s2[i]; - } -#endif - -#ifdef YY_NEED_STRLEN -#ifdef YY_USE_PROTOS -static int yy_flex_strlen( yyconst char *s ) -#else -static int yy_flex_strlen( s ) -yyconst char *s; -#endif - { - register int n; - for ( n = 0; s[n]; ++n ) - ; - - return n; - } -#endif - - -#ifdef YY_USE_PROTOS -static void *yy_flex_alloc( yy_size_t size ) -#else -static void *yy_flex_alloc( size ) -yy_size_t size; -#endif - { - return (void *) malloc( size ); - } - -#ifdef YY_USE_PROTOS -static void *yy_flex_realloc( void *ptr, yy_size_t size ) -#else -static void *yy_flex_realloc( ptr, size ) -void *ptr; -yy_size_t size; -#endif - { - /* 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 ); - } - -#ifdef YY_USE_PROTOS -static void yy_flex_free( void *ptr ) -#else -static void yy_flex_free( ptr ) -void *ptr; -#endif - { - free( ptr ); - } - -#if YY_MAIN -int main() - { - yylex(); - return 0; - } -#endif -#line 416 "lexer.l" diff --git a/src/lexer.l b/src/lexer.l @@ -1,415 +0,0 @@ -%{ -#include "crossroads.h" -#include "parser.h" - -/* Required by flex */ -static int yywrap () { - return (1); -} - -/* Lexer debugging related */ -// #define LEXER_DEBUG -#ifdef LEXER_DEBUG - static void lmsg (char const *x) { - printf ("L: %s\n", x); - } - static void llmsg (char const *x, char const *y) { - printf ("L: %s %s\n", x, y); - } -#else -# define lmsg(x) -# define llmsg(x,y) -#endif -%} - -%x stringstate commentstate - -%% - -#.*\n { - lmsg ("comment"); - yylineno++; -} - -\/\/.*\n { - lmsg ("comment"); - yylineno++; -} - -service { - lmsg ("service"); - return (SERVICE); -} - -bindto { - lmsg ("bindto"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (BINDTO); -} - -port { - lmsg ("port"); - return (PORT); -} - -over { - lmsg ("over"); - return (OVER); -} - -shmkey { - lmsg ("shmkey"); - return (SHMKEY); -} - -backend { - lmsg ("backend"); - return (BACKEND); -} - -backlog { - lmsg ("backlog"); - return (BACKLOG); -} - -retries { - lmsg ("retries"); - return (RETRIES); -} - -(verbosity)|(verbose) { - lmsg ("verbosity"); - return (VERBOSITY); -} - -connectiontimeout { - lmsg ("connectiontimeout"); - return (CONNECTIONTIMEOUT); -} - -maxconnections { - lmsg ("maxconnections"); - return (MAXCONNECTIONS); -} - -weight { - lmsg ("weight"); - return (WEIGHT); -} - -decay { - lmsg ("decay"); - return (DECAY); -} - -server { - lmsg ("server"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (SERVER); -} - -dispatchmode { - lmsg ("dispatchmode"); - return (DISPATCHMODE); -} - -roundrobin { - lmsg ("roundrobin"); - return (ROUNDROBIN); -} - -random { - lmsg ("random"); - return (RANDOM); -} - -byduration { - lmsg ("byduration"); - return (BYDURATION); -} - -bysize { - lmsg ("bysize"); - return (BYSIZE); -} - -byorder { - lmsg ("byorder"); - return (BYORDER); -} - -byconnections { - lmsg ("byconnections"); - return (BYCONNECTIONS); -} - -externalhandler { - lmsg ("externalhandler"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (EXTERNALHANDLER); -} - -byclientip { - lmsg ("byclientip"); - return (BYCLIENTIP); -} - -useraccount { - lmsg ("useraccount"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (USERACCOUNT); -} - -revivinginterval { - lmsg ("revivinginterval"); - return (REVIVINGINTERVAL); -} - -type { - lmsg ("type"); - return (TYPE); -} - -any { - lmsg ("any"); - return (ANY); -} - -stickyhttp { - lmsg ("stickyhttp"); - warning ("The 'stickyhttp protocol is obsolte.\n" - "You should change to 'http'."); - return (HTTP); -} - -http { - lmsg ("http"); - return (HTTP); -} - -throughputlog { - lmsg ("throughputlog"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (THROUGHPUTLOG); -} - -trafficlog { - lmsg ("trafficlog"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (TRAFFICLOG); -} - -dumptraffic { - lmsg ("dumptraffic"); - warning ("The 'dumptraffic' statement is obsolete.\n" - "You should change to 'trafficlog'."); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (TRAFFICLOG); -} - -onstart { - lmsg ("onstart"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (ONSTART); -} - -onfail { - lmsg ("onfail"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (ONFAIL); -} - -onend { - lmsg ("onend"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (ONEND); -} - -stickycookie { - lmsg ("stickycookie"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (STICKYCOOKIE); -} - -addclientheader { - lmsg ("addclientheader"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (ADDCLIENTHEADER); -} - -setclientheader { - lmsg ("setclientheader"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (SETCLIENTHEADER); -} - -appendclientheader { - lmsg ("appendclientheader"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (APPENDCLIENTHEADER); -} - -addserverheader { - lmsg ("addserverheader"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (ADDSERVERHEADER); -} - -setserverheader { - lmsg ("setserverheader"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (SETSERVERHEADER); -} - -appendserverheader { - lmsg ("appendserverheader"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (APPENDSERVERHEADER); -} - -allowfrom { - lmsg ("allowfrom"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (ALLOWFROM); -} - -denyfrom { - lmsg ("denyfrom"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (DENYFROM); -} - -allowfile { - lmsg ("allowfile"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (ALLOWFILE); -} - -denyfile { - lmsg ("denyfile"); - BEGIN (stringstate); - free (laststring); - laststring = 0; - return (DENYFILE); -} - -on|true|yes { - lmsg ("on"); - return (ON); -} - -off|false|no { - lmsg ("off"); - return (OFF); -} - -[a-zA-Z_][a-zA-Z0-9_]* { - llmsg ("identifier", yytext); - return (IDENTIFIER); -} - -[0-9]+ { - llmsg ("number", yytext); - return (NUMBER); -} - -[ \t]+ { - lmsg ("space(s)"); -} - -\n { - lmsg ("newline"); - yylineno++; -} - -. { - llmsg ("lone char", yytext); - return (*yytext); -} - -\/\* { - lmsg ("C-comment starts"); - BEGIN(commentstate); -} -<commentstate>\*\/ { - lmsg ("C-comment ends"); - BEGIN(0); -} -<commentstate>\n { - yylineno++; -} -<commentstate>. ; - -<stringstate>\"[^\"]*\" { - llmsg ("string part", yytext); - laststring = xstrcat (laststring, yytext + 1); - laststring[strlen(laststring) - 1] = 0; -} -<stringstate>\'[^\']*\' { - llmsg ("string part", yytext); - laststring = xstrcat (laststring, yytext + 1); - laststring[strlen(laststring) - 1] = 0; -} -<stringstate>; { - BEGIN (0); - unput (';'); - llmsg ("string", laststring); - return (STRING); -} -<stringstate>" " { - if (laststring) { - laststring = xstrcat (laststring, yytext); - llmsg ("string part", yytext); - } -} -<stringstate>. { - llmsg ("string part", yytext); - laststring = xstrcat (laststring, yytext); -} -<stringstate>\n { - if (laststring) { - laststring = xstrcat (laststring, " "); - lmsg ("string part: newline, now space"); - } - yylineno++; -} diff --git a/src/lib/Makefile b/src/lib/Makefile @@ -0,0 +1,53 @@ +include $(BASE)/etc/Makefile.def +include $(BASE)/etc/Makefile.conf + +LIB = libcrossroads.a + +all: + BASE=$(BASE) make textconv + BASE=$(BASE) make grammar + BASE=$(BASE) make lib + +install: all + +lib: $(LIB) + +$(LIB): objects + 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 -o$@ $< +parser.c: parser.y + bison -d -o $@ $< + +SRC := $(wildcard *.c) +OBJ := $(patsubst %.c, %.o, $(SRC)) +objects: $(OBJ) + + +parser.o: parser.c + $(CC) $(DEFS) -c -g $< + +lexer.o: lexer.c + $(CC) $(DEFS) -c -g $< + +%.o: %.c + $(CC) $(DEFS) -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 diff --git a/src/lib/allocreporter.c b/src/lib/allocreporter.c @@ -0,0 +1,64 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 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, sizeof(Servicereport), + 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, 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, sizeof(Servicereport), + 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, 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 @@ -0,0 +1,26 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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) { + static char buf[80]; + time_t now; + struct tm *tmp; + + time (&now); + 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 @@ -0,0 +1,26 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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].avail == st_available && + (activeservice->backend[target].maxconnections == 0 || + activeservice->backend[target].maxconnections > + servicereport->backendstate[target].nclients)) { + msg ("Service %s: target nr %d is available", + activeservice->name, target); + return (1); + } + + msg ("Service %s: target nr %d is unavailable", + activeservice->name, target); + return (0); +} diff --git a/src/lib/backendconnect.c b/src/lib/backendconnect.c @@ -0,0 +1,108 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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; + + /* Create the socket. */ + if ( (sock = socket (PF_INET, SOCK_STREAM, 0)) < 0 ) { + if (program_stage != stage_retrying) { + error ("Service %s: failed to create socket " + "for backend communication: %s", + activeservice->name, strerror(errno)); + } else { + warning ("Service %s: 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 ("Service %s: cannot set backend socket options " + "(nosigpipe): %s", activeservice->name, strerror(errno)); + close (sock); + return (-2); + } +#endif + + /* Assign to back end server address. */ + if (init_sockaddr (&servername, + activeservice->backend[current_backend].server, + activeservice->backend[current_backend].port)) { + /* The hostname is unusable.. */ + warning ("Service %s: unknown host %s", + activeservice->name, + activeservice->backend[current_backend].server); + close (sock); + mark_activity (0, 0, st_unavailable); + return (-3); + } + if (program_stage != stage_retrying) + msg ("Service %s: Network socket to %s:%d created", + activeservice->name, + activeservice->backend[current_backend].server, + activeservice->backend[current_backend].port); + + /* If retrying, delay a bit */ + if (servicereport->backendstate[current_backend].fail > 0) { + msg ("Service %s: Seen %d retries, waiting a bit", + activeservice->name, + servicereport->backendstate[current_backend].fail); + sleep (RETRY_WAIT); + } + + /* Set up the connect interruption */ + signal (SIGALRM, alarmhandler); + timed_out = 0; + alarm (CONNECT_TIMEOUT); + + /* Try connecting */ + if (connect (sock, (struct sockaddr *) &servername, + sizeof(servername)) < 0) { + /* This backend is unusable. + * Either connect() has failed (connection refused) or it got + * interrupted by the SIGALRM, or another signal went off. + */ + close (sock); + alarm(0); + signal (SIGALRM, SIG_DFL); + + if (program_stage != stage_retrying) { + if (timed_out) + warning ("Service %s: server %s:%d not usable" + " due to timeout", + activeservice->name, + activeservice->backend[current_backend].server, + activeservice->backend[current_backend].port); + else + warning ("Service %s: server %s:%d: cannot connect: %s", + activeservice->name, + activeservice->backend[current_backend].server, + activeservice->backend[current_backend].port, + strerror(errno)); + } + mark_activity (0, 0, st_unavailable); + return (-3); + } + alarm(0); + signal (SIGALRM, SIG_DFL); + return (sock); +} + diff --git a/src/lib/backendcount.c b/src/lib/backendcount.c @@ -0,0 +1,16 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 ("Service %s: %d backend(s) available", activeservice->name, n); + return (n); +} diff --git a/src/lib/choosebackend.c b/src/lib/choosebackend.c @@ -0,0 +1,377 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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[MAX_BACKEND], nbackends = 0, h, i, j, k, + target_set = 0, flat_weights = 1, weights[MAX_BACKEND], *sel_weights, + tot_weights, lo_val, hi_val, done; + double values [MAX_BACKEND], 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 ("Service %s: max clients %d exceeded", + activeservice->name, + 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 ("Service %s: Client IP %s hashed to back end index %d", + activeservice->name, client_ip, h); + if (servicereport->backendstate[h].avail == st_available && + (activeservice->backend[h].maxconnections == 0 || + activeservice->backend[h].maxconnections > + servicereport->backendstate[h].nclients)) { + msg ("Service %s: Hashed back end %d is acceptable", + activeservice->name, h); + current_backend = h; + return; + } else + msg ("Service %s: Hashed back end %d is not available, " + "re-dispatching", activeservice->name, 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].avail == st_available && + (activeservice->backend[i].maxconnections == 0 || + activeservice->backend[i].maxconnections > + servicereport->backendstate[i].nclients)) { + msg ("Service %s: " + "candidate back end: %d (max clients %d, active %d, " + "state %s)", + activeservice->name, + i, activeservice->backend[i].maxconnections, + servicereport->backendstate[i].nclients, + state_to_string(servicereport->backendstate[i].avail)); + backends[nbackends++] = i; + } + } + + /* No backends? Nogo. */ + if (!nbackends) { + current_backend = -1; + warning ("No active backends to select!"); + return; + } + + /* Only one backend? Then it's always the first one, + * whatever you do. */ + if (nbackends == 1) { + current_backend = backends[0]; + servicereport->last_backend = current_backend; + msg ("Service %s: only 1 backend to select (%d)", + activeservice->name, current_backend); + return; + } + + /* More than 1 backend available.. make a wise choice. */ + switch (activeservice->dispatchtype) { + + case ds_roundrobin: + /* Find the currently used backend, go one forward. */ + msg ("Service %s: last roundrobin back end was %d", + activeservice->name, 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 ("Service %s: next roundrobin back end is %d", + activeservice->name, current_backend); + return; + } + /* None found.. try the first one (run to momma). */ + current_backend = backends[0]; + servicereport->last_backend = current_backend; + msg ("Service %s: " + "chosen backend (roundrobin, without historical info): %d", + activeservice->name, current_backend); + return; + + case ds_random: + /* Re-randomize. */ +# if HAVE_SRANDDEV == 1 + sranddev(); + msg ("Service %s: randomier seeded with randdev", activeservice->name); +# else + gettimeofday (&tv, 0); + srand ((unsigned) tv.tv_usec); + msg ("Service %s: randomizer seeded with %u", + activeservice->name, (unsigned) tv.tv_usec); +# endif + + /* First of all let's see if all the weights are the same. */ + 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 ("Service %s: " + "chosen backend (weighted random): %d at index %d", + activeservice->name, current_backend, i); + return; + } + + /* ELSE: Choose a random one of the availables. */ + current_backend = backends[rand() % nbackends]; + servicereport->last_backend = current_backend; + msg ("Service %s: chosen backend (flat-weight random): %d", + activeservice->name, current_backend); + return; + + case ds_bysize: + /* Fill the values */ + 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 ("Service %s: " + "by size weighing backend %d has weight %d, value %u" + " (bytes=%u, avgbytes=%u)", + activeservice->name, + 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 ("Service %s: " + "by size weighing: best so far is %d (value %g)", + activeservice->name, current_backend, nbest); + } + msg ("Service %s: chosen backend (by size): %d", + activeservice->name, current_backend); + return; + + case ds_byduration: + /* Fill the values */ + 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 ("Service %s: By duration weighing: backend %d has value %g" + " (sec=%g, avgsec=%g, weight=%d)", + activeservice->name, + 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 ("Service %s: " + "by duration weighing: best so far is %d (value %g)", + activeservice->name, current_backend, nbest); + } + msg ("Service %s: chosen backend (by duration): %d", + activeservice->name, current_backend); + return; + + case ds_byorder: + /* Get the first available back end in line. */ + current_backend = backends[0]; + servicereport->last_backend = current_backend; + msg ("Service %s: chosen backend (by order): %d", + activeservice->name, current_backend); + return; + + case ds_byconnections: + case ds_byclientip: + /* Note: this serves byconnections dispatching, plus byclientip + * when the actual back end has gone down. */ + for (i = 0; i < nbackends; i++) { + values[i] = + servicereport->backendstate[backends[i]].nclients * + activeservice->backend[backends[i]].weight; + msg ("Service %s: " + "by connections weighing: backend %d has value %g", + activeservice->name, 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 ("Service %s: " + "by connections weighing: best so far is %d (value %u)", + activeservice->name, current_backend, nclients); + } + msg ("Service %s: chosen backend (by connections): %d", + activeservice->name, current_backend); + return; + + case ds_externalhandler: + /* External handler to be called */ + exthandler = str_expand_format (activeservice->dispatchext); + msg ("Service %s: calling external handler '%s'", + activeservice->name, exthandler); + uid_assume(); + if (! (f = popen (exthandler, "r")) ) { + warning ("Service %s: failed to start external handler '%s': %s", + activeservice->name, exthandler, strerror(errno)); + current_backend = backends[0]; + servicereport->last_backend = current_backend; + uid_restore(); + return; + } + while (1) { + if (fscanf (f, " %80s ", buf) < 1) { + msg ("Service %s: external handler signals end", + activeservice->name); + pclose (f); + uid_restore(); + break; + } + msg ("Service %s: external handler says '%s'", + activeservice->name, buf); + for (i = 0; i < nbackends; i++) + if (!strcmp (buf, activeservice->backend[backends[i]].name)) { + msg ("Service %s: selecting back end %s due to " + "external handler", activeservice->name, buf); + current_backend = backends[i]; + servicereport->last_backend = current_backend; + pclose (f); + uid_restore(); + return; + } + } + warning ("Service %s: external handler didn't reply with " + "a selectable back end", activeservice->name); + current_backend = backends[0]; + servicereport->last_backend = current_backend; + return; + + default: + /* Internal fry.. */ + error ("Service %s: internal error: unhandled dispatch type %d", + activeservice->name, activeservice->dispatchtype); + } +} diff --git a/src/lib/configtest.c b/src/lib/configtest.c @@ -0,0 +1,12 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 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/copysockets.c b/src/lib/copysockets.c @@ -0,0 +1,16 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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[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. */ + while (1) + net_copy (clientsock, serversock, TCP_BUFSZ, buf); +} diff --git a/src/lib/createcommandlinespace.c b/src/lib/createcommandlinespace.c @@ -0,0 +1,38 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 create_commandline_space () { + char **argv; + int i; + + /* Here's a dirty hack for Linux systems. We're going to get + * daemonized (unless -f was given) and we'll want to change the + * program name as it appears in the ps list. + * So we re-exec ourselves with a dummy -i flag that creates + * space on the commanedline. + */ +# if SET_PROC_TITLE_BY_ARGV == 1 + if (! iflag_present) { + msg ("Re-execing for command line space"); + argv = xmalloc ( (org_argc + 2) * sizeof(char*)); + + argv[0] = org_argv[0]; + argv[1] = "-ixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; + argv[org_argc + 1] = 0; + + for (i = 1; i < org_argc; i++) + argv[i + 1] = org_argv[i]; + argv[org_argc + 1] = 0; + + execv (argv[0], argv); + execvp (argv[0], argv); + error ("Failed to re-exec program: %s", + strerror(errno)); + } +# endif +} diff --git a/src/lib/deallocreporter.c b/src/lib/deallocreporter.c @@ -0,0 +1,39 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,43 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 ("Service %s: total active clients now %u", + activeservice->name, totclients); + + /* Warning: Use current_backend as index only if >= 0; it + * may be -1 when still searching for an HTTP back end */ + if (current_backend >= 0 && + servicereport->backendstate[current_backend].nclients > 0) + servicereport->backendstate[current_backend].nclients--; + + unlock_reporter(); + + if (current_backend >= 0) { + msg ("Service %s: extcmd-onend: " + " current_backend = %d, clients = %d, " + "totclients = %d, cmd = %s", + activeservice->name, current_backend, + servicereport->backendstate[current_backend].nclients, + servicereport->nclients, + activeservice->backend[current_backend].onend); + + sysrun (activeservice->backend[current_backend].onend); + } +} diff --git a/src/lib/error.c b/src/lib/error.c @@ -0,0 +1,23 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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) + fprintf (stderr, "ERROR: %s\n", str); + else + writelog (LOG_ERR, "ERROR: %s", str); + free (str); + } + exit (1); +} diff --git a/src/lib/forktcpservicer.c b/src/lib/forktcpservicer.c @@ -0,0 +1,48 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 fork_tcp_servicer (int to_backend) { + int pid, i; + + msg ("Service %s: Forking TCP servicer (to back end: %d)", + activeservice->name, to_backend); + + if ( (pid = fork()) < 0 ) { + /* Fork failure. Return nonzero so that caller thinks they're + * the parent. */ + warning ("Service %s: failed to fork: %s", + activeservice->name, strerror(errno)); + return (-1); + } else if (pid) { + /* Parent branch */ + msg ("Service %s: communications will be handled by pid %d", + activeservice->name, pid); + return (pid); + } else { + /* Child branch: here we will serve the socket pair. + * We want to catch interrupts, but not die. */ + for (i = 0; relevant_sigs[i]; i++) + signal (relevant_sigs[i], interrupt); + + /* Forked for the second time... */ + program_stage = stage_serving; + + if (to_backend >= 0) + set_program_title ("Service %s: serving %s to %s", + client_ip, + activeservice->name, + activeservice->backend [current_backend].name); + else + set_program_title ("Service %s: serving %s", + activeservice->name, client_ip); + return (0); + } + + /* To satisfy the prototype... */ + return (0); +} diff --git a/src/lib/hashpjw.c b/src/lib/hashpjw.c @@ -0,0 +1,25 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 hashpjw (char const *str) { + int 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 @@ -0,0 +1,105 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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; + + 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 > TCP_BUFSZ) + to_copy = 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 ("Got chunk size 0x%x (%d)", ret, ret); */ + 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; + unsigned nbytes; + + msg ("Service %s: copying HTTP body from %s", + activeservice->name, + dir == dir_client_to_server ? + "client to server" : "server to client"); + + /* Check in what 'mode' we are. + * We know 3 modes: + * - Transfer-Encoding is chunked: we copy chunks + * - Content-Length is supplied: we copy that # of bytes + * - None of the above: don't do anything, http_serve() will go + * into copy-thru mode + */ + + if ( (mode = http_header_val (h, "transfer-encoding")) && *mode ) { + if (strncasecmp ( (char const *) mode, "chunked", 7)) + error ("Service %s: can't handle transfer-encoding '%s'", + activeservice->name, mode); + msg ("Service %s: copying chunks from %s", + activeservice->name, 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 ("Service %s: Next chunk is 0x%x (%d) bytes", + activeservice->name, 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 ) { + nbytes = atoi ( (char const *) mode ); + msg ("Service %s: copying %u bytes of content from %s", + activeservice->name, nbytes, + dir == dir_client_to_server ? + "client to server" : "server to client"); + copy (src, dst, dir, nbytes); + } else + msg ("Service %s: no body to send", activeservice->name); +} diff --git a/src/lib/httperror.c b/src/lib/httperror.c @@ -0,0 +1,18 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,33 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 ("Service %s: adding header '%s'", activeservice->name, 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 @@ -0,0 +1,44 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 ("Service %s: appending (after existing) header, now '%s'", + activeservice->name, m->header[i]); */ + free (hname); + return; + } + } + + /* msg ("Service %s: appending (setting) header '%s'", + activeservice->name, h); */ + + http_header_addheader (m, h); +} diff --git a/src/lib/httpheaderconnectiontype.c b/src/lib/httpheaderconnectiontype.c @@ -0,0 +1,31 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 ("Service %s: Cannot determine connection type, " + "no such header", activeservice->name); + return (con_unknown); + } + if (strcasestr ((char const *)val, "close")) { + msg ("Service %s: Connection-Type is CLOSE", + activeservice->name); + return (con_close); + } else if (strcasestr ((char const *)val, "keep-alive")) { + msg ("Service %s: Connection-Type is KEEP-ALIVE", + activeservice->name); + return (con_keepalive); + } + warning ("Service %s: Unsupported Connection-Type '%s'", + activeservice->name, val); + return (con_unknown); +} diff --git a/src/lib/httpheaderfree.c b/src/lib/httpheaderfree.c @@ -0,0 +1,16 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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]); +} diff --git a/src/lib/httpheaderhascookie.c b/src/lib/httpheaderhascookie.c @@ -0,0 +1,34 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 ("Service %s: no cookies in HTTP message", activeservice->name); + 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 ("Service %s: found cookie '%s' in '%s'", + activeservice->name, cookie, buf); + free (buf); + return (1); + } + } + msg ("Service %s: cookie '%s' not present in '%s'", + activeservice->name, cookie, buf); + free (buf); + return (0); +} diff --git a/src/lib/httpheaderhttpver.c b/src/lib/httpheaderhttpver.c @@ -0,0 +1,36 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 ("Service %s: cannot get HTTP version, no headers", + activeservice->name); + return (0.9); + } + + /* We need HTTP/1.? length */ + if (strlen (h->header[0]) < 8) { + warning ("Service %s: cannot get HTTP version, header line '%s'", + activeservice->name, 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 ("Service %s: HTTP version is %g (headerline %s)", + activeservice->name, ret, h->header[0]); + return (ret); +} + diff --git a/src/lib/httpheadernew.c b/src/lib/httpheadernew.c @@ -0,0 +1,16 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,55 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 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)) +#else +#define SHOWHEADERS(h) +#endif + +void http_header_read (HttpHeader *h, int sock, CopyDirection dir) { + unsigned char *cp; + int last_is_nl = 0, at_start = 1; + + msg ("Service %s: reading HTTP headers from %s", + activeservice->name, + dir == dir_client_to_server ? "client" : "server"); + while (1) { + cp = net_bufread (sock, 1, 0, dir == dir_client_to_server); + /* msg ("http header read: got char %d (%c)", *cp, *cp); */ + /* SHOWHEADERS(h); */ + if (*cp == '\r') + continue; + if (*cp == '\n') { + if (last_is_nl && h->nheader) + break; + last_is_nl++; + continue; + } + if (at_start || last_is_nl) { + h->header = xrealloc (h->header, (h->nheader + 1) * sizeof(char*)); + h->header[h->nheader] = 0; + h->nheader++; + at_start = 0; + } + h->header[h->nheader - 1] = xstrcatch (h->header[h->nheader - 1], *cp); + last_is_nl = 0; + } + + SHOWHEADERS(h); +} diff --git a/src/lib/httpheaderremoveheader.c b/src/lib/httpheaderremoveheader.c @@ -0,0 +1,22 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 ("Service %s: removing header '%s'", + activeservice->name, hdr); + free (h->header[i]); + h->header[i] = 0; + } + } +} diff --git a/src/lib/httpheadersetheader.c b/src/lib/httpheadersetheader.c @@ -0,0 +1,37 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 ("Service %s: setting (replacing) header '%s'", + activeservice->name, exp); + m->header[i] = exp; + free (hname); + return; + } + } + + msg ("Service %s: setting (adding) header '%s'", activeservice->name, 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 @@ -0,0 +1,27 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,25 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 ("Service %s: Sending %d HTTP headers to %s", + activeservice->name, 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 ("Service %s: sending header %d: '%s'", + activeservice->name, 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 @@ -0,0 +1,55 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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/httpserve.c b/src/lib/httpserve.c @@ -0,0 +1,213 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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; + unsigned char *cp; + int size; + + /* Fork off a servicer if we're in daemon mode. */ + if (fork_tcp_servicer(-1)) + return; + + /* 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 + */ + + while (1) { + /* 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 */ + clientreq = http_header_new(); + http_header_read (clientreq, clientsock, dir_client_to_server); + + /* Determine the back end if necessary. */ + if (serversock == -1) { + if ( (serversock = http_serversocket (clientreq, + &is_continuation)) < 1 ) + http_error (clientsock); + + 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 ("Service %s: Client talks HTTP < 1.1, forcing closing " + "connections", activeservice->name); + 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 ("Service %s: Client asks for connection closing", + activeservice->name); + client_persisting = 0; + } + + /* Send client's headers to the back end. */ + http_header_write (clientreq, serversock, dir_client_to_server); + + /* Copy body from client to server */ + http_copy (clientreq, clientsock, serversock, dir_client_to_server); + if ( (cp = net_buffer (dir_client_to_server, &size)) ) + net_write (serversock, cp, size, 0); + + /* Get server response. */ + serverresp = http_header_new(); + http_header_read (serverresp, serversock, dir_server_to_client); + + /* 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 ("Service %s: Server is sending chunks, forcing singleshot", + activeservice->name); + server_persisting = 0; + http_header_setheader (serverresp, "Connection: close"); + http_header_setheader (serverresp, "Proxy-Connection: close"); + } + + /* 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 ("Service %s: Server is sending chunks, forcing singleshot", + activeservice->name); + 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 ("Service %s: Server talks HTTP < 1.1, forcing closing " + "connections", activeservice->name); + 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 ("Service %s: Server asks for connection closing", + activeservice->name); + http_header_setheader (serverresp, "Connection: close"); + http_header_setheader (serverresp, "Proxy-Connection: close"); + server_persisting = 0; + } + } + + /* Send server headers to the client. */ + http_header_write (serverresp, clientsock, dir_server_to_client); + + /* Copy body from server to cliet and flush network buffers if any */ + http_copy (serverresp, serversock, clientsock, dir_server_to_client); + if ( (cp = net_buffer (dir_server_to_client, &size)) ) + net_write (clientsock, cp, size, 0); + + /* Free up info from this request/response chat. */ + http_header_free (clientreq); + http_header_free (serverresp); + + /* 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 ("Service %s: non-persistent connection", + activeservice->name); + break; + } + + msg ("Service %s: Analyzing following requests over same TCP link", + activeservice->name); + } + + /* We're done analyzing. If there's leftovers in the network buffers, + * then we flush them first. */ + if (clbufmax) { + msg ("Service %s: Flushing client-side buffer to server, %u bytes", + activeservice->name, clbufmax - clbufpos); + http_write (serversock, dir_client_to_server, + clbuf + clbufpos, clbufmax - clbufpos); + clbufmax = clbufpos = 0; + } + if (srbufmax) { + msg ("Service %s: Flushing server-side buffer to client, %u bytes", + activeservice->name, 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 ("Service %s: HTTP service done analyzing, entering copy-thru mode", + activeservice->name); + + /* This doesn't return */ + copysockets (clientsock, serversock); + +} diff --git a/src/lib/httpserversocket.c b/src/lib/httpserversocket.c @@ -0,0 +1,76 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 ("Service %s: searching for back end for HTTP request.", + activeservice->name); + + /* Try to find a sticky cookie in the request. */ + for (i = 0; i < activeservice->nbackend; i++) { + if (servicereport->backendstate[i].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 ("Service %s: HTTP backend %d selected due to cookie '%s'", + activeservice->name, + 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 ("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 ("Service %s: " + "out of back ends while scanning for HTTP back end", + activeservice->name); + return (-1); + } + + /* Try one. */ + choose_backend(); + if (current_backend < 0) { + warning ("No back end for request."); + return (-2); + } + + msg ("Service %s: trying back end %d for new HTTP connection", + activeservice->name, current_backend); + if ( (sock = backend_connect ()) >= 0 ) { + servicereport->backendstate[current_backend].sessions++; + *is_continuation = 0; + set_program_title ("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 @@ -0,0 +1,18 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,40 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 ("Service %s: extcmd-onstart: " + " current_backend = %d, clients = %d, totclients = %d, cmd = %s", + activeservice->name, current_backend, + servicereport->backendstate[current_backend].nclients, + servicereport->nclients, + activeservice->backend[current_backend].onstart); + + sysrun (activeservice->backend[current_backend].onstart); + + msg ("Service %s: Activity on back end %d now %d, total %d", + activeservice->name, current_backend, + servicereport->backendstate[current_backend].nclients, + totclients); + } +} diff --git a/src/lib/initsockaddr.c b/src/lib/initsockaddr.c @@ -0,0 +1,21 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 hostent *hostinfo; + + if (program_stage != stage_retrying) + msg ("Service %s: trying to connect to backend %s:%d", + activeservice->name, hostname, port); + name->sin_family = AF_INET; + name->sin_port = htons (port); + if (! (hostinfo = gethostbyname (hostname)) ) + return (1); + name->sin_addr = *(struct in_addr *) hostinfo->h_addr; + return (0); +} diff --git a/src/lib/interrupt.c b/src/lib/interrupt.c @@ -0,0 +1,55 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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: + interrupted++; + + switch (program_stage) { + case stage_waiting: + warning ("Service %s: listener caught signal %d, " + "closing socket %d and exiting", + activeservice->name, sig, listen_sock); + shutdown (listen_sock, SHUT_RDWR); + close (listen_sock); + exit (0); + break; + + case stage_serving: + /* This will serve the current connection and then stop. */ + break; + + case stage_retrying: + warning ("Service %s: wakeup handler caught signal %d, " + "stopping wake ups and exiting", + activeservice->name, sig); + exit (0); + + default: + msg ("Caught signal %d in program stage %s, exiting", sig, + stage_to_string (program_stage)); + exit (0); + } + } +} diff --git a/src/lib/ipfaddallow.c b/src/lib/ipfaddallow.c @@ -0,0 +1,17 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,17 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,22 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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) + return (1); + + /* Try all in the chain. */ + for (i = 0; i < activeservice->nallowchain; i++) + if (ipf_match (activeservice->allowchain[i])) + return (1); + + /* Allow chain doesn't match */ + return (0); +} diff --git a/src/lib/ipfdenied.c b/src/lib/ipfdenied.c @@ -0,0 +1,22 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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) + return (0); + + /* Try all in the chain. */ + for (i = 0; i < activeservice->ndenychain; i++) + if (ipf_match (activeservice->denychain[i])) + return (1); + + /* Deny chain doesn't match */ + return (0); +} diff --git a/src/lib/ipfloadfile.c b/src/lib/ipfloadfile.c @@ -0,0 +1,53 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 ("Service %s: loading IP filter file: '%s'", + activeservice->name, fname); + + if (! (f = fopen (fname, "r")) ) { + warning ("Service %s: can't read filter file '%s': %s", + activeservice->name, 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 ("Service %s: bad ip filter in file '%s'", + activeservice->name, fname); + ret++; + } else { + msg ("Service %s: got ip filter specifier '%s'", + activeservice->name, buf); + *chain = xrealloc (*chain, (*nchain + 1) * sizeof(IpFilter)); + (*chain)[*nchain] = filter; + (*nchain)++; + nloaded++; + } + } + + msg ("Service %s: loaded IP filter file '%s': %d successfully loaded", + activeservice->name, fname, nloaded); + + fclose (f); + return (ret); +} diff --git a/src/lib/ipfmatch.c b/src/lib/ipfmatch.c @@ -0,0 +1,43 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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) { + static int client_ip_nr; + int counter, val; + char *tmp, *cp; + + /* 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. */ + if (!client_ip_nr) { + tmp = xstrdup (client_ip); + counter = 0; + for (counter = 0, cp = strtok (tmp, "."); + cp; + counter += 8, cp = strtok (0, ".")) { + if (sscanf (cp, "%d", &val) < 1) { + free (tmp); + return (1); + } + val <<= counter; + client_ip_nr |= val; + /* msg ("ipf_match: val 0x%x, client_ip_nr 0x%x", + * val, client_ip_nr); */ + } + } + free (tmp); + + /* Here's the comparison. */ + /* msg ("ipf_match: filter ip/mask 0x%x/0x%x, " + * "filter res 0x%x, client res 0x%x", + * f.ip, f.mask, + * (f.ip & f.mask), (client_ip_nr & f.mask)); + */ + return ( (f.ip & f.mask) == (client_ip_nr & f.mask) ); +} diff --git a/src/lib/ipfparse.c b/src/lib/ipfparse.c @@ -0,0 +1,51 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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; + int counter, nr, i; + + memset (res, 0, sizeof(IpFilter)); + str = xstrdup (val); + + for (counter = 0, cp = strtok (str, "."); + cp; + counter += 8, cp = strtok (0, ".")) { + 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 @@ -0,0 +1,15 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,15 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,2358 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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" +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header: /cvs/root/flex/flex/skel.c,v 1.2 2004/05/07 00:28:17 jkh Exp $ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include <stdio.h> + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include <stdlib.h> +#include <unistd.h> + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include <io.h> +#include <stdlib.h> +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#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. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +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 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + *yy_cp = yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - 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). + */ +typedef unsigned int yy_size_t; + + +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; + + /* 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 + }; + +static YY_BUFFER_STATE yy_current_buffer = 0; + +/* 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". + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* 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 = 1; /* 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 YY_PROTO(( FILE *input_file )); + +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) + +YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); +YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); +YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + +typedef unsigned char YY_CHAR; +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +typedef int yy_state_type; +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yy_fatal_error YY_PROTO(( 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 = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 66 +#define YY_END_OF_BUFFER 67 +static yyconst short int yy_accept[416] = + { 0, + 0, 0, 0, 0, 0, 0, 67, 55, 53, 54, + 55, 55, 52, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 64, 65, 63, 64, 64, 62, 59, 58, + 59, 53, 0, 1, 56, 0, 52, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 50, 51, 49, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 0, 60, 0, 61, 57, 0, 2, 51, 51, + 29, 51, 51, 51, 51, 51, 51, 51, 51, 51, + + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 49, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 31, 51, 51, 51, + 51, 6, 5, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 28, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 15, 51, 51, 51, 51, 51, 37, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 4, 51, 51, 51, 51, 21, 51, 51, 51, + 51, 51, 51, 51, 36, 51, 19, 51, 51, 51, + 16, 51, 51, 51, 7, 51, 51, 51, 51, 51, + 14, 51, 51, 51, 51, 51, 51, 8, 9, 51, + 51, 51, 22, 51, 51, 51, 51, 51, 51, 51, + 35, 10, 51, 51, 3, 51, 51, 51, 51, 51, + 51, 51, 11, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 48, 46, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + + 51, 51, 47, 45, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 25, 51, 20, + 51, 51, 51, 51, 51, 51, 18, 51, 51, 51, + 30, 51, 33, 51, 51, 51, 51, 51, 51, 51, + 51, 34, 51, 51, 51, 51, 51, 51, 51, 26, + 51, 51, 51, 51, 51, 51, 17, 51, 51, 51, + 51, 51, 38, 51, 51, 51, 51, 51, 23, 51, + 51, 51, 51, 51, 51, 32, 51, 51, 51, 51, + 51, 51, 13, 51, 51, 51, 39, 42, 51, 51, + + 51, 24, 51, 40, 43, 51, 51, 51, 27, 51, + 51, 12, 41, 44, 0 + } ; + +static yyconst int yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4, 1, 5, 6, 1, 1, 1, 7, 1, + 1, 8, 1, 1, 1, 1, 9, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 1, 11, 1, + 1, 1, 1, 1, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 1, 1, 1, 1, 12, 1, 13, 14, 15, 16, + + 17, 18, 19, 20, 21, 12, 22, 23, 24, 25, + 26, 27, 12, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 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 int yy_meta[37] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 1, 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 + } ; + +static yyconst short int yy_base[423] = + { 0, + 0, 0, 34, 39, 44, 45, 444, 445, 47, 445, + 440, 46, 432, 0, 40, 45, 415, 40, 406, 426, + 408, 424, 410, 44, 409, 47, 55, 54, 405, 416, + 415, 414, 445, 445, 445, 425, 422, 445, 445, 445, + 419, 66, 424, 445, 445, 423, 415, 0, 408, 400, + 387, 394, 405, 394, 62, 393, 68, 388, 392, 385, + 391, 383, 378, 0, 393, 69, 393, 381, 383, 49, + 376, 62, 382, 384, 376, 71, 376, 385, 373, 379, + 370, 393, 445, 390, 445, 445, 393, 445, 79, 369, + 0, 377, 371, 376, 73, 360, 362, 368, 363, 374, + + 351, 358, 357, 366, 353, 354, 365, 354, 365, 347, + 348, 345, 358, 345, 351, 346, 338, 80, 347, 353, + 341, 348, 348, 347, 335, 348, 342, 0, 337, 342, + 325, 332, 80, 326, 334, 329, 325, 336, 315, 333, + 314, 330, 334, 316, 317, 327, 0, 317, 326, 320, + 327, 0, 0, 313, 317, 305, 320, 83, 312, 317, + 316, 310, 300, 312, 0, 316, 302, 307, 305, 297, + 306, 307, 297, 295, 294, 302, 293, 304, 299, 298, + 299, 0, 84, 283, 284, 286, 285, 0, 286, 280, + 283, 289, 284, 276, 275, 287, 280, 272, 264, 263, + + 278, 275, 280, 265, 263, 275, 259, 85, 86, 274, + 270, 0, 263, 270, 256, 257, 0, 254, 260, 256, + 266, 267, 266, 253, 0, 247, 0, 247, 250, 248, + 0, 256, 255, 239, 0, 96, 250, 254, 253, 93, + 0, 242, 249, 242, 238, 240, 245, 0, 0, 231, + 245, 238, 0, 237, 240, 232, 235, 236, 230, 235, + 0, 0, 232, 236, 0, 224, 231, 221, 216, 218, + 221, 217, 0, 212, 211, 212, 222, 214, 216, 208, + 214, 204, 207, 206, 0, 0, 207, 212, 209, 213, + 206, 205, 195, 196, 197, 192, 190, 194, 188, 183, + + 197, 196, 0, 0, 198, 182, 186, 191, 186, 185, + 183, 187, 194, 176, 180, 179, 183, 182, 179, 173, + 169, 179, 172, 179, 178, 169, 176, 0, 166, 0, + 161, 174, 174, 163, 166, 156, 0, 168, 167, 162, + 0, 159, 0, 151, 167, 166, 148, 149, 151, 154, + 157, 0, 157, 146, 154, 157, 156, 151, 141, 0, + 150, 149, 144, 143, 133, 137, 0, 137, 134, 130, + 141, 140, 0, 136, 137, 136, 135, 134, 0, 133, + 132, 119, 115, 129, 128, 0, 116, 115, 129, 128, + 114, 111, 0, 125, 109, 108, 0, 0, 119, 118, + + 102, 0, 109, 0, 0, 114, 113, 99, 0, 79, + 31, 0, 0, 0, 445, 116, 118, 120, 38, 122, + 124, 126 + } ; + +static yyconst short int yy_def[423] = + { 0, + 415, 1, 416, 416, 417, 417, 415, 415, 415, 415, + 418, 415, 415, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 415, 415, 415, 420, 421, 415, 415, 415, + 415, 415, 418, 415, 415, 422, 415, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 420, 415, 421, 415, 415, 422, 415, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + + 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, + 419, 419, 419, 419, 0, 415, 415, 415, 415, 415, + 415, 415 + } ; + +static yyconst short int yy_nxt[482] = + { 0, + 8, 9, 10, 9, 8, 11, 8, 8, 12, 13, + 8, 14, 15, 16, 17, 18, 19, 20, 14, 21, + 14, 14, 14, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 14, 32, 14, 34, 35, 36, 48, + 37, 34, 35, 36, 38, 37, 40, 40, 42, 38, + 42, 41, 41, 45, 46, 49, 57, 53, 414, 69, + 58, 65, 50, 70, 51, 54, 52, 42, 66, 42, + 59, 72, 71, 75, 73, 67, 95, 96, 114, 55, + 115, 76, 100, 122, 74, 108, 109, 97, 77, 117, + 98, 118, 101, 129, 159, 135, 173, 110, 136, 195, + + 246, 123, 174, 196, 219, 244, 413, 130, 160, 273, + 268, 220, 245, 274, 247, 269, 33, 33, 39, 39, + 43, 43, 82, 82, 84, 84, 87, 87, 412, 411, + 410, 409, 408, 407, 406, 405, 404, 403, 402, 401, + 400, 399, 398, 397, 396, 395, 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, 362, 361, + 360, 359, 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, 273, 323, 322, + 321, 320, 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, 287, 286, 285, 284, 283, 282, + 281, 280, 279, 278, 277, 276, 275, 272, 271, 270, + 267, 266, 265, 264, 263, 262, 261, 260, 259, 258, + 257, 256, 255, 254, 253, 252, 251, 250, 249, 248, + 243, 242, 241, 240, 239, 238, 237, 236, 235, 234, + + 233, 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, + 201, 200, 199, 198, 197, 194, 193, 192, 191, 190, + 189, 188, 187, 64, 186, 185, 184, 183, 182, 181, + 180, 179, 178, 177, 176, 175, 172, 171, 170, 169, + 168, 167, 166, 165, 128, 164, 163, 162, 161, 158, + 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, + 147, 146, 145, 144, 143, 142, 141, 140, 139, 138, + 137, 134, 133, 132, 131, 88, 85, 83, 128, 127, + + 126, 125, 124, 121, 120, 119, 116, 113, 112, 111, + 64, 107, 106, 105, 104, 103, 102, 99, 94, 93, + 92, 91, 90, 89, 47, 88, 44, 86, 85, 83, + 81, 80, 79, 78, 68, 64, 63, 62, 61, 60, + 56, 47, 44, 415, 7, 415, 415, 415, 415, 415, + 415, 415, 415, 415, 415, 415, 415, 415, 415, 415, + 415, 415, 415, 415, 415, 415, 415, 415, 415, 415, + 415, 415, 415, 415, 415, 415, 415, 415, 415, 415, + 415 + } ; + +static yyconst short int yy_chk[482] = + { 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, 3, 3, 3, 419, + 3, 4, 4, 4, 3, 4, 5, 6, 9, 4, + 9, 5, 6, 12, 12, 15, 18, 16, 411, 26, + 18, 24, 15, 26, 15, 16, 15, 42, 24, 42, + 18, 27, 26, 28, 27, 24, 55, 55, 70, 16, + 70, 28, 57, 76, 27, 66, 66, 55, 28, 72, + 55, 72, 57, 89, 118, 95, 133, 66, 95, 158, + + 209, 76, 133, 158, 183, 208, 410, 89, 118, 240, + 236, 183, 208, 240, 209, 236, 416, 416, 417, 417, + 418, 418, 420, 420, 421, 421, 422, 422, 408, 407, + 406, 403, 401, 400, 399, 396, 395, 394, 392, 391, + 390, 389, 388, 387, 385, 384, 383, 382, 381, 380, + 378, 377, 376, 375, 374, 372, 371, 370, 369, 368, + 366, 365, 364, 363, 362, 361, 359, 358, 357, 356, + 355, 354, 353, 351, 350, 349, 348, 347, 346, 345, + 344, 342, 340, 339, 338, 336, 335, 334, 333, 332, + 331, 329, 327, 326, 325, 324, 323, 322, 321, 320, + + 319, 318, 317, 316, 315, 314, 313, 312, 311, 310, + 309, 308, 307, 306, 305, 302, 301, 300, 299, 298, + 297, 296, 295, 294, 293, 292, 291, 290, 289, 288, + 287, 284, 283, 282, 281, 280, 279, 278, 277, 276, + 275, 274, 272, 271, 270, 269, 268, 267, 266, 264, + 263, 260, 259, 258, 257, 256, 255, 254, 252, 251, + 250, 247, 246, 245, 244, 243, 242, 239, 238, 237, + 234, 233, 232, 230, 229, 228, 226, 224, 223, 222, + 221, 220, 219, 218, 216, 215, 214, 213, 211, 210, + 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, + + 197, 196, 195, 194, 193, 192, 191, 190, 189, 187, + 186, 185, 184, 181, 180, 179, 178, 177, 176, 175, + 174, 173, 172, 171, 170, 169, 168, 167, 166, 164, + 163, 162, 161, 160, 159, 157, 156, 155, 154, 151, + 150, 149, 148, 146, 145, 144, 143, 142, 141, 140, + 139, 138, 137, 136, 135, 134, 132, 131, 130, 129, + 127, 126, 125, 124, 123, 122, 121, 120, 119, 117, + 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, + 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, + 96, 94, 93, 92, 90, 87, 84, 82, 81, 80, + + 79, 78, 77, 75, 74, 73, 71, 69, 68, 67, + 65, 63, 62, 61, 60, 59, 58, 56, 54, 53, + 52, 51, 50, 49, 47, 46, 43, 41, 37, 36, + 32, 31, 30, 29, 25, 23, 22, 21, 20, 19, + 17, 13, 11, 7, 415, 415, 415, 415, 415, 415, + 415, 415, 415, 415, 415, 415, 415, 415, 415, 415, + 415, 415, 415, 415, 415, 415, 415, 415, 415, 415, + 415, 415, 415, 415, 415, 415, 415, 415, 415, 415, + 415 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +/* 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" +#define INITIAL 0 +#line 2 "lexer.l" +#include "../crossroads.h" +#include "parser.h" + +/* Required by flex */ +static int yywrap () { + return (1); +} + +/* Lexer debugging related */ +// #define LEXER_DEBUG +#ifdef LEXER_DEBUG + static void lmsg (char const *x) { + printf ("L: %s\n", x); + } + static void llmsg (char const *x, char const *y) { + printf ("L: %s %s\n", x, y); + } +#else +# define lmsg(x) +# define llmsg(x,y) +#endif +#define stringstate 1 +#define commentstate 2 + +#line 633 "lexer.c" + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include <stdlib.h> +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#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->yy_is_interactive ) \ + { \ + int c = '*', 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 if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#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 + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yylex YY_PROTO(( void )) +#endif + +/* 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 \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 27 "lexer.l" + + +#line 787 "lexer.c" + + if ( yy_init ) + { + yy_init = 0; + +#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 ) + yy_current_buffer = + 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_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 >= 416 ) + 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] != 445 ); + +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 ("comment"); + yylineno++; +} + YY_BREAK +case 2: +YY_RULE_SETUP +#line 34 "lexer.l" +{ + lmsg ("comment"); + yylineno++; +} + YY_BREAK +case 3: +YY_RULE_SETUP +#line 39 "lexer.l" +{ + lmsg ("service"); + return (SERVICE); +} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 44 "lexer.l" +{ + lmsg ("bindto"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (BINDTO); +} + YY_BREAK +case 5: +YY_RULE_SETUP +#line 52 "lexer.l" +{ + lmsg ("port"); + return (PORT); +} + YY_BREAK +case 6: +YY_RULE_SETUP +#line 57 "lexer.l" +{ + lmsg ("over"); + return (OVER); +} + YY_BREAK +case 7: +YY_RULE_SETUP +#line 62 "lexer.l" +{ + lmsg ("shmkey"); + return (SHMKEY); +} + YY_BREAK +case 8: +YY_RULE_SETUP +#line 67 "lexer.l" +{ + lmsg ("backend"); + return (BACKEND); +} + YY_BREAK +case 9: +YY_RULE_SETUP +#line 72 "lexer.l" +{ + lmsg ("backlog"); + return (BACKLOG); +} + YY_BREAK +case 10: +YY_RULE_SETUP +#line 77 "lexer.l" +{ + lmsg ("retries"); + return (RETRIES); +} + YY_BREAK +case 11: +YY_RULE_SETUP +#line 82 "lexer.l" +{ + lmsg ("verbosity"); + return (VERBOSITY); +} + YY_BREAK +case 12: +YY_RULE_SETUP +#line 87 "lexer.l" +{ + lmsg ("connectiontimeout"); + return (CONNECTIONTIMEOUT); +} + YY_BREAK +case 13: +YY_RULE_SETUP +#line 92 "lexer.l" +{ + lmsg ("maxconnections"); + return (MAXCONNECTIONS); +} + YY_BREAK +case 14: +YY_RULE_SETUP +#line 97 "lexer.l" +{ + lmsg ("weight"); + return (WEIGHT); +} + YY_BREAK +case 15: +YY_RULE_SETUP +#line 102 "lexer.l" +{ + lmsg ("decay"); + return (DECAY); +} + YY_BREAK +case 16: +YY_RULE_SETUP +#line 107 "lexer.l" +{ + lmsg ("server"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (SERVER); +} + YY_BREAK +case 17: +YY_RULE_SETUP +#line 115 "lexer.l" +{ + lmsg ("dispatchmode"); + return (DISPATCHMODE); +} + YY_BREAK +case 18: +YY_RULE_SETUP +#line 120 "lexer.l" +{ + lmsg ("roundrobin"); + return (ROUNDROBIN); +} + YY_BREAK +case 19: +YY_RULE_SETUP +#line 125 "lexer.l" +{ + lmsg ("random"); + return (RANDOM); +} + YY_BREAK +case 20: +YY_RULE_SETUP +#line 130 "lexer.l" +{ + lmsg ("byduration"); + return (BYDURATION); +} + YY_BREAK +case 21: +YY_RULE_SETUP +#line 135 "lexer.l" +{ + lmsg ("bysize"); + return (BYSIZE); +} + YY_BREAK +case 22: +YY_RULE_SETUP +#line 140 "lexer.l" +{ + lmsg ("byorder"); + return (BYORDER); +} + YY_BREAK +case 23: +YY_RULE_SETUP +#line 145 "lexer.l" +{ + lmsg ("byconnections"); + return (BYCONNECTIONS); +} + YY_BREAK +case 24: +YY_RULE_SETUP +#line 150 "lexer.l" +{ + lmsg ("externalhandler"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (EXTERNALHANDLER); +} + YY_BREAK +case 25: +YY_RULE_SETUP +#line 158 "lexer.l" +{ + lmsg ("byclientip"); + return (BYCLIENTIP); +} + YY_BREAK +case 26: +YY_RULE_SETUP +#line 163 "lexer.l" +{ + lmsg ("useraccount"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (USERACCOUNT); +} + YY_BREAK +case 27: +YY_RULE_SETUP +#line 171 "lexer.l" +{ + lmsg ("revivinginterval"); + return (REVIVINGINTERVAL); +} + YY_BREAK +case 28: +YY_RULE_SETUP +#line 176 "lexer.l" +{ + lmsg ("type"); + return (TYPE); +} + YY_BREAK +case 29: +YY_RULE_SETUP +#line 181 "lexer.l" +{ + lmsg ("any"); + return (ANY); +} + YY_BREAK +case 30: +YY_RULE_SETUP +#line 186 "lexer.l" +{ + lmsg ("stickyhttp"); + warning ("The 'stickyhttp protocol is obsolte.\n" + "You should change to 'http'."); + return (HTTP); +} + YY_BREAK +case 31: +YY_RULE_SETUP +#line 193 "lexer.l" +{ + lmsg ("http"); + return (HTTP); +} + YY_BREAK +case 32: +YY_RULE_SETUP +#line 198 "lexer.l" +{ + lmsg ("throughputlog"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (THROUGHPUTLOG); +} + YY_BREAK +case 33: +YY_RULE_SETUP +#line 206 "lexer.l" +{ + lmsg ("trafficlog"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (TRAFFICLOG); +} + YY_BREAK +case 34: +YY_RULE_SETUP +#line 214 "lexer.l" +{ + lmsg ("dumptraffic"); + warning ("The 'dumptraffic' statement is obsolete.\n" + "You should change to 'trafficlog'."); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (TRAFFICLOG); +} + YY_BREAK +case 35: +YY_RULE_SETUP +#line 224 "lexer.l" +{ + lmsg ("onstart"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (ONSTART); +} + YY_BREAK +case 36: +YY_RULE_SETUP +#line 232 "lexer.l" +{ + lmsg ("onfail"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (ONFAIL); +} + YY_BREAK +case 37: +YY_RULE_SETUP +#line 240 "lexer.l" +{ + lmsg ("onend"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (ONEND); +} + YY_BREAK +case 38: +YY_RULE_SETUP +#line 248 "lexer.l" +{ + lmsg ("stickycookie"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (STICKYCOOKIE); +} + YY_BREAK +case 39: +YY_RULE_SETUP +#line 256 "lexer.l" +{ + lmsg ("addclientheader"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (ADDCLIENTHEADER); +} + YY_BREAK +case 40: +YY_RULE_SETUP +#line 264 "lexer.l" +{ + lmsg ("setclientheader"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (SETCLIENTHEADER); +} + YY_BREAK +case 41: +YY_RULE_SETUP +#line 272 "lexer.l" +{ + lmsg ("appendclientheader"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (APPENDCLIENTHEADER); +} + YY_BREAK +case 42: +YY_RULE_SETUP +#line 280 "lexer.l" +{ + lmsg ("addserverheader"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (ADDSERVERHEADER); +} + YY_BREAK +case 43: +YY_RULE_SETUP +#line 288 "lexer.l" +{ + lmsg ("setserverheader"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (SETSERVERHEADER); +} + YY_BREAK +case 44: +YY_RULE_SETUP +#line 296 "lexer.l" +{ + lmsg ("appendserverheader"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (APPENDSERVERHEADER); +} + YY_BREAK +case 45: +YY_RULE_SETUP +#line 304 "lexer.l" +{ + lmsg ("allowfrom"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (ALLOWFROM); +} + YY_BREAK +case 46: +YY_RULE_SETUP +#line 312 "lexer.l" +{ + lmsg ("denyfrom"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (DENYFROM); +} + YY_BREAK +case 47: +YY_RULE_SETUP +#line 320 "lexer.l" +{ + lmsg ("allowfile"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (ALLOWFILE); +} + YY_BREAK +case 48: +YY_RULE_SETUP +#line 328 "lexer.l" +{ + lmsg ("denyfile"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (DENYFILE); +} + YY_BREAK +case 49: +YY_RULE_SETUP +#line 336 "lexer.l" +{ + lmsg ("on"); + return (ON); +} + YY_BREAK +case 50: +YY_RULE_SETUP +#line 341 "lexer.l" +{ + lmsg ("off"); + return (OFF); +} + YY_BREAK +case 51: +YY_RULE_SETUP +#line 346 "lexer.l" +{ + llmsg ("identifier", yytext); + return (IDENTIFIER); +} + YY_BREAK +case 52: +YY_RULE_SETUP +#line 351 "lexer.l" +{ + llmsg ("number", yytext); + return (NUMBER); +} + YY_BREAK +case 53: +YY_RULE_SETUP +#line 356 "lexer.l" +{ + lmsg ("space(s)"); +} + YY_BREAK +case 54: +YY_RULE_SETUP +#line 360 "lexer.l" +{ + lmsg ("newline"); + yylineno++; +} + YY_BREAK +case 55: +YY_RULE_SETUP +#line 365 "lexer.l" +{ + llmsg ("lone char", yytext); + return (*yytext); +} + YY_BREAK +case 56: +YY_RULE_SETUP +#line 370 "lexer.l" +{ + lmsg ("C-comment starts"); + BEGIN(commentstate); +} + YY_BREAK +case 57: +YY_RULE_SETUP +#line 374 "lexer.l" +{ + lmsg ("C-comment ends"); + BEGIN(0); +} + YY_BREAK +case 58: +YY_RULE_SETUP +#line 378 "lexer.l" +{ + yylineno++; +} + YY_BREAK +case 59: +YY_RULE_SETUP +#line 381 "lexer.l" +; + YY_BREAK +case 60: +YY_RULE_SETUP +#line 383 "lexer.l" +{ + llmsg ("string part", yytext); + laststring = xstrcat (laststring, yytext + 1); + laststring[strlen(laststring) - 1] = 0; +} + YY_BREAK +case 61: +YY_RULE_SETUP +#line 388 "lexer.l" +{ + llmsg ("string part", yytext); + laststring = xstrcat (laststring, yytext + 1); + laststring[strlen(laststring) - 1] = 0; +} + YY_BREAK +case 62: +YY_RULE_SETUP +#line 393 "lexer.l" +{ + BEGIN (0); + unput (';'); + llmsg ("string", laststring); + return (STRING); +} + YY_BREAK +case 63: +YY_RULE_SETUP +#line 399 "lexer.l" +{ + if (laststring) { + laststring = xstrcat (laststring, yytext); + llmsg ("string part", yytext); + } +} + YY_BREAK +case 64: +YY_RULE_SETUP +#line 405 "lexer.l" +{ + llmsg ("string part", yytext); + laststring = xstrcat (laststring, yytext); +} + YY_BREAK +case 65: +YY_RULE_SETUP +#line 409 "lexer.l" +{ + if (laststring) { + laststring = xstrcat (laststring, " "); + lmsg ("string part: newline, now space"); + } + yylineno++; +} + YY_BREAK +case 66: +YY_RULE_SETUP +#line 416 "lexer.l" +ECHO; + YY_BREAK +#line 1466 "lexer.c" +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(stringstate): +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->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->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->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->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->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() + { + register char *dest = yy_current_buffer->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->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( yy_current_buffer->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->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->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* 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. */ + yy_flex_realloc( (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->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->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->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yytext_ptr = &yy_current_buffer->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() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + + 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 >= 416 ) + 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 ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +yy_state_type yy_current_state; +#endif + { + 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 >= 416 ) + 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 == 415); + + return yy_is_jam ? 0 : yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void yyunput( int c, register char *yy_bp ) +#else +static void yyunput( c, yy_bp ) +int c; +register char *yy_bp; +#endif + { + register char *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->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->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->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; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#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->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 ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + 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; + + + return c; + } + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + 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->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = 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; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yy_flex_alloc( 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 *) yy_flex_alloc( 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; + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + +#ifndef YY_ALWAYS_INTERACTIVE +#ifndef YY_NEVER_INTERACTIVE +extern int isatty YY_PROTO(( int )); +#endif +#endif + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->yy_is_interactive = 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + 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(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) +#else +YY_BUFFER_STATE yy_scan_buffer( base, size ) +char *base; +yy_size_t size; +#endif + { + 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) yy_flex_alloc( 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; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) +#else +YY_BUFFER_STATE yy_scan_string( yy_str ) +yyconst char *yy_str; +#endif + { + int len; + for ( len = 0; yy_str[len]; ++len ) + ; + + return yy_scan_bytes( yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE yy_scan_bytes( bytes, len ) +yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[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; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void yy_push_state( int new_state ) +#else +static void yy_push_state( new_state ) +int new_state; +#endif + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void yy_fatal_error( yyconst char msg[] ) +#else +static void yy_fatal_error( msg ) +char msg[]; +#endif + { + (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. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* 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 ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif +#line 416 "lexer.l" diff --git a/src/lib/lexer.l b/src/lib/lexer.l @@ -0,0 +1,415 @@ +%{ +#include "../crossroads.h" +#include "parser.h" + +/* Required by flex */ +static int yywrap () { + return (1); +} + +/* Lexer debugging related */ +// #define LEXER_DEBUG +#ifdef LEXER_DEBUG + static void lmsg (char const *x) { + printf ("L: %s\n", x); + } + static void llmsg (char const *x, char const *y) { + printf ("L: %s %s\n", x, y); + } +#else +# define lmsg(x) +# define llmsg(x,y) +#endif +%} + +%x stringstate commentstate + +%% + +#.*\n { + lmsg ("comment"); + yylineno++; +} + +\/\/.*\n { + lmsg ("comment"); + yylineno++; +} + +service { + lmsg ("service"); + return (SERVICE); +} + +bindto { + lmsg ("bindto"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (BINDTO); +} + +port { + lmsg ("port"); + return (PORT); +} + +over { + lmsg ("over"); + return (OVER); +} + +shmkey { + lmsg ("shmkey"); + return (SHMKEY); +} + +backend { + lmsg ("backend"); + return (BACKEND); +} + +backlog { + lmsg ("backlog"); + return (BACKLOG); +} + +retries { + lmsg ("retries"); + return (RETRIES); +} + +(verbosity)|(verbose) { + lmsg ("verbosity"); + return (VERBOSITY); +} + +connectiontimeout { + lmsg ("connectiontimeout"); + return (CONNECTIONTIMEOUT); +} + +maxconnections { + lmsg ("maxconnections"); + return (MAXCONNECTIONS); +} + +weight { + lmsg ("weight"); + return (WEIGHT); +} + +decay { + lmsg ("decay"); + return (DECAY); +} + +server { + lmsg ("server"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (SERVER); +} + +dispatchmode { + lmsg ("dispatchmode"); + return (DISPATCHMODE); +} + +roundrobin { + lmsg ("roundrobin"); + return (ROUNDROBIN); +} + +random { + lmsg ("random"); + return (RANDOM); +} + +byduration { + lmsg ("byduration"); + return (BYDURATION); +} + +bysize { + lmsg ("bysize"); + return (BYSIZE); +} + +byorder { + lmsg ("byorder"); + return (BYORDER); +} + +byconnections { + lmsg ("byconnections"); + return (BYCONNECTIONS); +} + +externalhandler { + lmsg ("externalhandler"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (EXTERNALHANDLER); +} + +byclientip { + lmsg ("byclientip"); + return (BYCLIENTIP); +} + +useraccount { + lmsg ("useraccount"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (USERACCOUNT); +} + +revivinginterval { + lmsg ("revivinginterval"); + return (REVIVINGINTERVAL); +} + +type { + lmsg ("type"); + return (TYPE); +} + +any { + lmsg ("any"); + return (ANY); +} + +stickyhttp { + lmsg ("stickyhttp"); + warning ("The 'stickyhttp protocol is obsolte.\n" + "You should change to 'http'."); + return (HTTP); +} + +http { + lmsg ("http"); + return (HTTP); +} + +throughputlog { + lmsg ("throughputlog"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (THROUGHPUTLOG); +} + +trafficlog { + lmsg ("trafficlog"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (TRAFFICLOG); +} + +dumptraffic { + lmsg ("dumptraffic"); + warning ("The 'dumptraffic' statement is obsolete.\n" + "You should change to 'trafficlog'."); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (TRAFFICLOG); +} + +onstart { + lmsg ("onstart"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (ONSTART); +} + +onfail { + lmsg ("onfail"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (ONFAIL); +} + +onend { + lmsg ("onend"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (ONEND); +} + +stickycookie { + lmsg ("stickycookie"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (STICKYCOOKIE); +} + +addclientheader { + lmsg ("addclientheader"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (ADDCLIENTHEADER); +} + +setclientheader { + lmsg ("setclientheader"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (SETCLIENTHEADER); +} + +appendclientheader { + lmsg ("appendclientheader"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (APPENDCLIENTHEADER); +} + +addserverheader { + lmsg ("addserverheader"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (ADDSERVERHEADER); +} + +setserverheader { + lmsg ("setserverheader"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (SETSERVERHEADER); +} + +appendserverheader { + lmsg ("appendserverheader"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (APPENDSERVERHEADER); +} + +allowfrom { + lmsg ("allowfrom"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (ALLOWFROM); +} + +denyfrom { + lmsg ("denyfrom"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (DENYFROM); +} + +allowfile { + lmsg ("allowfile"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (ALLOWFILE); +} + +denyfile { + lmsg ("denyfile"); + BEGIN (stringstate); + free (laststring); + laststring = 0; + return (DENYFILE); +} + +on|true|yes { + lmsg ("on"); + return (ON); +} + +off|false|no { + lmsg ("off"); + return (OFF); +} + +[a-zA-Z_][a-zA-Z0-9_]* { + llmsg ("identifier", yytext); + return (IDENTIFIER); +} + +[0-9]+ { + llmsg ("number", yytext); + return (NUMBER); +} + +[ \t]+ { + lmsg ("space(s)"); +} + +\n { + lmsg ("newline"); + yylineno++; +} + +. { + llmsg ("lone char", yytext); + return (*yytext); +} + +\/\* { + lmsg ("C-comment starts"); + BEGIN(commentstate); +} +<commentstate>\*\/ { + lmsg ("C-comment ends"); + BEGIN(0); +} +<commentstate>\n { + yylineno++; +} +<commentstate>. ; + +<stringstate>\"[^\"]*\" { + llmsg ("string part", yytext); + laststring = xstrcat (laststring, yytext + 1); + laststring[strlen(laststring) - 1] = 0; +} +<stringstate>\'[^\']*\' { + llmsg ("string part", yytext); + laststring = xstrcat (laststring, yytext + 1); + laststring[strlen(laststring) - 1] = 0; +} +<stringstate>; { + BEGIN (0); + unput (';'); + llmsg ("string", laststring); + return (STRING); +} +<stringstate>" " { + if (laststring) { + laststring = xstrcat (laststring, yytext); + llmsg ("string part", yytext); + } +} +<stringstate>. { + llmsg ("string part", yytext); + laststring = xstrcat (laststring, yytext); +} +<stringstate>\n { + if (laststring) { + laststring = xstrcat (laststring, " "); + lmsg ("string part: newline, now space"); + } + yylineno++; +} diff --git a/src/lib/lockreporter.c b/src/lib/lockreporter.c @@ -0,0 +1,32 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,16 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, a load balancer and fail over + * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. + * Visit http://crossroads.e-tunity.com for information. + *************************************************************************/ +#include "../crossroads.h" + +void log_activity_any (char const *action) { + if (!log_activity || current_backend < 0) + return; + if (!logstarted++) + openlog ("crossroads", LOG_PID, log_facility); + syslog (LOG_NOTICE, "%s %s %s from %s to %s", + ansistamp(tm_localtime), action, activeservice->name, + client_ip, activeservice->backend[current_backend].server); +} diff --git a/src/lib/logactivitycontinuation.c b/src/lib/logactivitycontinuation.c @@ -0,0 +1,10 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,10 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,10 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,62 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 ("Service %s: cannot create network socket: %s", + activeservice->name, strerror(errno)); + return (-1); + } + if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) { + warning ("Service %s: cannot set socket options (reuseaddr): %s", + activeservice->name, strerror(errno)); + close (sock); + return (-2); + } +#ifdef SO_NOSIGPIPE + if (setsockopt (sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val))) { + warning ("Service %s: cannot set socket options (nosigpipe): %s", + activeservice->name, strerror(errno)); + close (sock); + return (-2); + } +#endif + + /* Give the socket a name. */ + name.sin_family = AF_INET; + name.sin_port = htons (port); + + /* Propagate 'bindto' if given. */ + if (strcasecmp (ipaddr, "any")) { + msg ("Service %s: creating socket for IP address '%s'", + activeservice->name, ipaddr); + if ( (name.sin_addr.s_addr = inet_addr (ipaddr)) == INADDR_NONE ) { + close (sock); + error ("Service %s: cannot convert address '%s' to network bytes", + activeservice->name, ipaddr); + } + } else { + msg ("Service %s: creating socket for all interfaces", + activeservice->name); + name.sin_addr.s_addr = htonl (INADDR_ANY); + } + + /* Finallly, 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 @@ -0,0 +1,143 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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].avail != st_unavailable) { + servicereport->backendstate[current_backend].fail++; + // msg ("Service %s: Back end %d's unavailability increased to %d", + // activeservice->name, 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].avail != st_waking && + servicereport->backendstate[current_backend].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 ("Service %s: backend %d: %d fails, %d retries, " + "going offline", activeservice->name, current_backend, + servicereport->backendstate[current_backend].fail, + activeservice->backend[current_backend].retries); + servicereport->backendstate[current_backend].fail = 0; + servicereport->backendstate[current_backend].avail = + st_unavailable; + marked_unavailable++; + } + servicereport->backendstate[current_backend].totuses++; + } else if (newstate != st_intermediate) { + /* When applying any other state than intermediate, it's OK */ + servicereport->backendstate[current_backend].fail = 0; + servicereport->backendstate[current_backend].avail = newstate; + servicereport->backendstate[current_backend].totuses++; + } + } + + /* 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 ("Service %s: updated stats for backend %d (%s): " + "hits=%lu, " + "totfails=%lu, secs=%g, avgsecs=%g, " + "bytes=%g, avgbytes=%lu, state=%s", + activeservice->name, + 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].avail)); + + /* Run the onfailure hook if one is specified. */ + if (marked_unavailable && program_stage != stage_retrying) { + msg ("Service %s: extcmd-onfail: " + " current_backend = %d, clients = %d, totclients = %d, cmd = %s", + activeservice->name, current_backend, + 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 @@ -0,0 +1,23 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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) + fprintf (stderr, "INFO: %s\n", str); + else + writelog (LOG_NOTICE, "INFO: %s", str); + + va_end (args); +} diff --git a/src/lib/msgdumpbuf.c b/src/lib/msgdumpbuf.c @@ -0,0 +1,48 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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/netbuffer.c b/src/lib/netbuffer.c @@ -0,0 +1,35 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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, int *sz) { + if (dir == dir_server_to_client) { + if (srbufmax) { + *sz = srbufmax - srbufpos; + msg ("Service %s: %d bytes still in server buffer", + activeservice->name, *sz); + srbufmax = 0; + return (srbuf + srbufpos); + } else { + msg ("Service %s: server buffer is empty", + activeservice->name); + return (0); + } + } else { + if (clbufmax) { + *sz = clbufmax - clbufpos; + msg ("Service %s: %d bytes still in client buffer", + activeservice->name, *sz); + clbufmax = 0; + return (clbuf + clbufpos); + } else { + msg ("Service %s: client buffer is empty", + activeservice->name); + return (0); + } + } +} diff --git a/src/lib/netbufread.c b/src/lib/netbufread.c @@ -0,0 +1,60 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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. */ + if (!clbuf) { + clbuf = xmalloc (TCP_BUFSZ); + srbuf = xmalloc (TCP_BUFSZ); + clbufmax = srbufmax = clbufpos = srbufpos = 0; + msg ("Service %s: Allocated client and server buffers", + activeservice->name); + } + + 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, TCP_BUFSZ, buf, is_client); + msg ("Service %s: Got %d bytes from %s", + activeservice->name, *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 @@ -0,0 +1,116 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 ("Service %s: network copy stopped after timeout", + activeservice->name); + } + + /* Check for exceptions. */ + if (FD_ISSET (cl, &exset)) { + decr_client_count(); + log_activity_end(); + error ("Service %s: client exception", activeservice->name); + } + if (FD_ISSET (sr, &exset)) { + decr_client_count(); + log_activity_end(); + mark_activity (0, 0, st_unavailable); + error ("Service %s: server exception", activeservice->name); + } + + /* 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 ("Service %s: Read error from server", + activeservice->name); + else { + msg ("Service %s: Read error from client", + activeservice->name); + exit (0); + } + } else { + msg ("Service %s: %s signals end of data", + activeservice->name, + 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 ("Service %s: write error when sending data to %s", + activeservice->name, + 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 @@ -0,0 +1,101 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 +#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 ("Service %s: fetching atmost %u bytes from %s", + activeservice->name, 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); + error ("Service %s: read from %s timed out", + activeservice->name, 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 ("Service %s: %s exception", desc, activeservice->name); + } + + /* 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 ("Service %s: Read error from server", + activeservice->name); + else { + msg ("Service %s: Read error from client", + activeservice->name); + exit (0); + } + } else { + msg ("Service %s: %s signals end of data", + activeservice->name, 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 @@ -0,0 +1,101 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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) + warning ("Service %s: Timout while writing %s on socket %d", + activeservice->name, + is_client ? "client" : "server", sock); + else + warning ("Service %s: Failed to wait for network of %s " + "on socket %d", + activeservice->name, + is_client ? "client" : "server", sock); + + decr_client_count(); + log_activity_end(); + exit (0); + } + + if (FD_ISSET (sock, &exset)) { + decr_client_count(); + log_activity_end(); + error ("Service %s: exception on %s network", + activeservice->name, is_client ? "client" : "server"); + } + + /* We can write! */ + ret = write (sock, buf, buflen); + + /* Check for finished / errors */ + if (ret < 1) { + msg ("Service %s: failed to send to %s: %s (%d)", + activeservice->name, is_client ? "client" : "server", + strerror(errno), ret); + decr_client_count(); + log_activity_end (); + exit (0); + } + + /* 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/parser.c b/src/lib/parser.c @@ -0,0 +1,2533 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 from parser.y + by GNU bison 1.35. */ + +#define YYBISON 1 /* Identify Bison output. */ + +# define SERVICE 257 +# define IDENTIFIER 258 +# define PORT 259 +# define NUMBER 260 +# define BACKEND 261 +# define VERBOSITY 262 +# define SERVER 263 +# define ON 264 +# define OFF 265 +# define DISPATCHMODE 266 +# define ROUNDROBIN 267 +# define REVIVINGINTERVAL 268 +# define SHMKEY 269 +# define WEIGHT 270 +# define ONSTART 271 +# define ONFAIL 272 +# define STRING 273 +# define BACKLOG 274 +# define RANDOM 275 +# define BYDURATION 276 +# define BYSIZE 277 +# define BYCONNECTIONS 278 +# define CONNECTIONTIMEOUT 279 +# define MAXCONNECTIONS 280 +# define BYORDER 281 +# define TRAFFICLOG 282 +# define OVER 283 +# define DECAY 284 +# define BINDTO 285 +# define THROUGHPUTLOG 286 +# define TYPE 287 +# define ANY 288 +# define HTTP 289 +# define STICKYCOOKIE 290 +# define ADDCLIENTHEADER 291 +# define SETCLIENTHEADER 292 +# define APPENDCLIENTHEADER 293 +# define ADDSERVERHEADER 294 +# define SETSERVERHEADER 295 +# define APPENDSERVERHEADER 296 +# define ALLOWFROM 297 +# define DENYFROM 298 +# define ALLOWFILE 299 +# define DENYFILE 300 +# define EXTERNALHANDLER 301 +# define ONEND 302 +# define USERACCOUNT 303 +# define BYCLIENTIP 304 +# define RETRIES 305 + +#line 3 "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 */ +// #define PARSER_DEBUG +#ifdef PARSER_DEBUG + static void pmsg (char const *x) { + printf ("P: %s\n", x); + } + static void psmsg (char const *x, char const *y) { + printf ("P: %s %s\n", x, y); + } + static void pimsg(char const *x, int y) { + printf ("P: %s %d\n", x, y); + } +#else +# define pmsg(x) +# define psmsg(x,y) +# define pimsg(x,y) +#endif + +/* Error handler for yyparse() */ +static int yyerror (char *msg) { + error ("Parse error at line %d, '%s': %s", + yylineno + 1, yytext, 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) { + lastnr = atoi (what); +} + +/* Store an encountered 'over' number */ +static int lastovernr; +static void setlastovernr (char const *what) { + 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; + int result; + for (item = strtok (what, " "); item; item = strtok (0, " ")) { + 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; +} + +#ifndef YYSTYPE +# define YYSTYPE int +# define YYSTYPE_IS_TRIVIAL 1 +#endif +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + + + +#define YYFINAL 202 +#define YYFLAG -32768 +#define YYNTBASE 55 + +/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ +#define YYTRANSLATE(x) ((unsigned)(x) <= 305 ? yytranslate[x] : 135) + +/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ +static const char 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, 54, + 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, 52, 2, 53, 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, 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 +}; + +#if YYDEBUG +static const short yyprhs[] = +{ + 0, 0, 3, 5, 11, 14, 17, 20, 22, 25, + 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, + 47, 49, 51, 53, 55, 57, 61, 65, 68, 71, + 74, 79, 81, 83, 88, 90, 92, 93, 96, 99, + 101, 104, 106, 108, 110, 112, 114, 116, 118, 120, + 124, 127, 131, 135, 139, 143, 147, 151, 154, 156, + 158, 162, 166, 170, 174, 177, 183, 186, 189, 191, + 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, + 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, + 237, 241, 245, 247, 251, 255, 259, 263, 267, 271, + 274, 277, 281, 284, 288, 292, 296, 300, 304, 308, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 325, 326, 327, 328 +}; +static const short yyrhs[] = +{ + 55, 56, 0, 56, 0, 57, 58, 52, 59, 53, + 0, 121, 3, 0, 129, 4, 0, 59, 60, 0, + 60, 0, 123, 61, 0, 62, 0, 63, 0, 67, + 0, 69, 0, 78, 0, 79, 0, 80, 0, 81, + 0, 82, 0, 83, 0, 86, 0, 88, 0, 87, + 0, 89, 0, 76, 0, 91, 0, 5, 65, 66, + 0, 31, 64, 66, 0, 131, 19, 0, 119, 6, + 0, 124, 54, 0, 8, 125, 68, 66, 0, 10, + 0, 11, 0, 12, 74, 70, 66, 0, 71, 0, + 73, 0, 0, 29, 72, 0, 119, 6, 0, 106, + 0, 126, 75, 0, 13, 0, 21, 0, 22, 0, + 23, 0, 27, 0, 24, 0, 47, 0, 50, 0, + 49, 77, 66, 0, 134, 19, 0, 14, 65, 66, + 0, 20, 65, 66, 0, 15, 65, 66, 0, 25, + 65, 66, 0, 26, 65, 66, 0, 33, 84, 66, + 0, 132, 85, 0, 34, 0, 35, 0, 43, 90, + 66, 0, 44, 90, 66, 0, 45, 107, 66, 0, + 46, 107, 66, 0, 133, 19, 0, 7, 92, 52, + 93, 53, 0, 130, 4, 0, 93, 94, 0, 94, + 0, 122, 95, 0, 96, 0, 62, 0, 67, 0, + 101, 0, 103, 0, 102, 0, 104, 0, 105, 0, + 97, 0, 98, 0, 82, 0, 108, 0, 110, 0, + 111, 0, 112, 0, 113, 0, 114, 0, 115, 0, + 100, 0, 9, 120, 99, 66, 0, 16, 65, 66, + 0, 30, 65, 66, 0, 19, 0, 51, 65, 66, + 0, 17, 106, 66, 0, 18, 106, 66, 0, 48, + 106, 66, 0, 28, 107, 66, 0, 32, 107, 66, + 0, 127, 19, 0, 128, 19, 0, 36, 109, 66, + 0, 118, 19, 0, 37, 116, 66, 0, 38, 116, + 66, 0, 39, 116, 66, 0, 40, 116, 66, 0, + 41, 116, 66, 0, 42, 116, 66, 0, 117, 19, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +#endif + +#if YYDEBUG +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const short yyrline[] = +{ + 0, 130, 133, 137, 166, 171, 179, 182, 186, 191, + 197, 203, 209, 219, 225, 231, 237, 243, 249, 255, + 261, 267, 273, 279, 286, 457, 469, 481, 490, 497, + 502, 515, 519, 525, 534, 536, 538, 542, 559, 566, + 576, 585, 589, 593, 597, 601, 605, 609, 613, 619, + 631, 640, 652, 664, 676, 688, 700, 712, 717, 721, + 727, 739, 751, 763, 775, 784, 794, 802, 810, 816, + 823, 828, 833, 838, 843, 848, 853, 858, 863, 868, + 873, 878, 883, 888, 893, 898, 903, 908, 913, 920, + 933, 945, 957, 963, 975, 987, 999, 1011, 1023, 1035, + 1044, 1053, 1065, 1074, 1086, 1098, 1110, 1122, 1134, 1146, + 1155, 1160, 1165, 1170, 1175, 1180, 1185, 1190, 1195, 1200, + 1205, 1210, 1215, 1220, 1225, 1230, 1235, 1240 +}; +#endif + + +#if (YYDEBUG) || defined YYERROR_VERBOSE + +/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */ +static const char *const yytname[] = +{ + "$", "error", "$undefined.", "SERVICE", "IDENTIFIER", "PORT", "NUMBER", + "BACKEND", "VERBOSITY", "SERVER", "ON", "OFF", "DISPATCHMODE", + "ROUNDROBIN", "REVIVINGINTERVAL", "SHMKEY", "WEIGHT", "ONSTART", + "ONFAIL", "STRING", "BACKLOG", "RANDOM", "BYDURATION", "BYSIZE", + "BYCONNECTIONS", "CONNECTIONTIMEOUT", "MAXCONNECTIONS", "BYORDER", + "TRAFFICLOG", "OVER", "DECAY", "BINDTO", "THROUGHPUTLOG", "TYPE", "ANY", + "HTTP", "STICKYCOOKIE", "ADDCLIENTHEADER", "SETCLIENTHEADER", + "APPENDCLIENTHEADER", "ADDSERVERHEADER", "SETSERVERHEADER", + "APPENDSERVERHEADER", "ALLOWFROM", "DENYFROM", "ALLOWFILE", "DENYFILE", + "EXTERNALHANDLER", "ONEND", "USERACCOUNT", "BYCLIENTIP", "RETRIES", + "'{'", "'}'", "';'", "input", "element", "service", "servicename", + "servicestatements", "servicestatement", "servicebody", "portstatement", + "bindstatement", "ipaddress", "number", "semicol", "verbositystatement", + "onoff", "dispatchmodestatement", "dispatchtail", "dispatchover", + "overnumber", "dispatchext", "dispatchmethod", "dispatchmethodspec", + "useraccountstatement", "useraccount", "revivingintervalstatement", + "backlogstatement", "shmkeystatement", "connectiontimeoutstatement", + "maxconnectionsstatement", "typestatement", "typespec", "typespecifier", + "allowfromstatement", "denyfromstatement", "allowfilestatement", + "denyfilestatement", "ipfilters", "backendblock", "backendname", + "backenddefinitions", "backenddefinition", "backendstatement", + "serverstatement", "weightstatement", "decaystatement", "serveraddress", + "retriesstatement", "onstartstatement", "onfailstatement", + "onendstatement", "dumptrafficstatement", "throughputstatement", + "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", "ipfilters_expected", + "useraccount_expected", 0 +}; +#endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const short yyr1[] = +{ + 0, 55, 55, 56, 57, 58, 59, 59, 60, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 62, 63, 64, 65, 66, + 67, 68, 68, 69, 70, 70, 70, 71, 72, 73, + 74, 75, 75, 75, 75, 75, 75, 75, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 93, 94, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const short yyr2[] = +{ + 0, 2, 1, 5, 2, 2, 2, 1, 2, 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, 3, 3, 3, 3, 3, 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, 4, + 3, 3, 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 +}; + +/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE + doesn't specify something else to do. Zero means the default is an + error. */ +static const short yydefact[] = +{ + 114, 114, 2, 122, 0, 1, 0, 0, 4, 116, + 5, 116, 7, 0, 3, 6, 112, 123, 118, 119, + 112, 112, 112, 112, 112, 124, 125, 126, 126, 121, + 121, 127, 8, 9, 10, 11, 12, 23, 13, 14, + 15, 16, 17, 18, 19, 21, 20, 22, 24, 117, + 0, 0, 0, 0, 36, 0, 117, 117, 117, 117, + 117, 117, 0, 117, 0, 117, 0, 117, 117, 0, + 117, 117, 0, 25, 0, 28, 115, 66, 31, 32, + 117, 112, 117, 34, 35, 39, 0, 41, 42, 43, + 44, 46, 45, 47, 48, 40, 51, 53, 52, 54, + 55, 26, 27, 56, 58, 59, 57, 60, 64, 61, + 62, 100, 63, 49, 50, 29, 115, 68, 0, 30, + 37, 0, 33, 99, 65, 67, 113, 112, 120, 120, + 121, 112, 121, 111, 110, 110, 110, 110, 110, 110, + 120, 112, 71, 72, 80, 69, 70, 78, 79, 88, + 73, 75, 74, 76, 77, 81, 82, 83, 84, 85, + 86, 87, 38, 0, 117, 117, 117, 117, 117, 117, + 117, 0, 117, 0, 117, 117, 117, 117, 117, 117, + 117, 92, 117, 90, 94, 95, 97, 91, 98, 101, + 102, 103, 109, 104, 105, 106, 107, 108, 96, 93, + 89, 0, 0 +}; + +static const short yydefgoto[] = +{ + 1, 2, 3, 6, 11, 12, 32, 33, 34, 61, + 49, 73, 35, 80, 36, 82, 83, 120, 84, 54, + 95, 37, 71, 38, 39, 40, 41, 42, 43, 63, + 106, 44, 45, 46, 47, 65, 48, 51, 116, 117, + 145, 146, 147, 148, 182, 149, 150, 151, 152, 153, + 154, 85, 68, 155, 170, 156, 157, 158, 159, 160, + 161, 172, 173, 171, 50, 163, 4, 118, 13, 74, + 53, 55, 86, 69, 7, 52, 62, 64, 66, 72 +}; + +static const short yypact[] = +{ + -32768, 8,-32768,-32768, 7,-32768, -39, 13,-32768,-32768, + -32768, -30,-32768, 58,-32768,-32768,-32768,-32768,-32768,-32768, + -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + 21, -17, 37, 23, -13, 114,-32768,-32768,-32768,-32768, + -32768,-32768, 25,-32768, 5,-32768, 26,-32768,-32768, 28, + -32768,-32768, 30,-32768, -12,-32768,-32768,-32768,-32768,-32768, + -32768,-32768,-32768,-32768,-32768,-32768, 32,-32768,-32768,-32768, + -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + -32768,-32768,-32768,-32768,-32768,-32768, 1,-32768, 20,-32768, + -32768, 47,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + -32768,-32768,-32768, 36,-32768,-32768,-32768,-32768,-32768,-32768, + -32768, 45,-32768, 48,-32768,-32768,-32768,-32768,-32768,-32768, + -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + -32768, 69,-32768 +}; + +static const short yypgoto[] = +{ + -32768, 73,-32768,-32768,-32768, 64,-32768, -42,-32768,-32768, + -2, -56, -41,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + -32768,-32768,-32768,-32768,-32768,-32768,-32768, -38,-32768,-32768, + -32768,-32768,-32768,-32768,-32768, 51,-32768,-32768,-32768, -35, + -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + -32768, -97, 0,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + -32768, -43,-32768,-32768, 4,-32768,-32768,-32768,-32768,-32768, + -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768 +}; + + +#define YYLAST 164 + + +static const short yytable[] = +{ + 96, 97, 98, 99, 100, 101, -120, 103, 201, 107, + 8, 109, 110, 9, 112, 113, 81, 10, 56, 57, + 58, 59, 60, 14, 119, 16, 122, 75, 18, 126, + 70, 165, 166, 78, 79, 76, 127, 128, 129, 104, + 105, 77, 115, 179, 102, 108, 24, 111, 130, 114, + 131, 123, 132, 162, 124, 181, 133, 134, 135, 136, + 137, 138, 139, 16, 190, 17, 18, 192, 140, 202, + 19, 141, 20, 21, 5, 15, 142, 143, 22, 67, + 144, 125, 0, 23, 24, 121, 0, 0, 0, 25, + 0, 26, 174, 175, 176, 177, 178, 0, 0, 0, + 0, 27, 28, 29, 30, 0, 0, 31, 183, 184, + 185, 186, 187, 188, 189, 0, 191, 0, 193, 194, + 195, 196, 197, 198, 199, 164, 200, 87, 0, 168, + 167, 0, 169, 0, 0, 88, 89, 90, 91, 180, + 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 93, 0, 0, 94 +}; + +static const short yycheck[] = +{ + 56, 57, 58, 59, 60, 61, 19, 63, 0, 65, + 3, 67, 68, 52, 70, 71, 29, 4, 20, 21, + 22, 23, 24, 53, 80, 5, 82, 6, 8, 9, + 30, 128, 129, 10, 11, 52, 16, 17, 18, 34, + 35, 4, 54, 140, 19, 19, 26, 19, 28, 19, + 30, 19, 32, 6, 53, 19, 36, 37, 38, 39, + 40, 41, 42, 5, 19, 7, 8, 19, 48, 0, + 12, 51, 14, 15, 1, 11, 118, 118, 20, 28, + 118, 116, -1, 25, 26, 81, -1, -1, -1, 31, + -1, 33, 135, 136, 137, 138, 139, -1, -1, -1, + -1, 43, 44, 45, 46, -1, -1, 49, 164, 165, + 166, 167, 168, 169, 170, -1, 172, -1, 174, 175, + 176, 177, 178, 179, 180, 127, 182, 13, -1, 131, + 130, -1, 132, -1, -1, 21, 22, 23, 24, 141, + -1, 27, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 47, -1, -1, 50 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/sw/share/bison/bison.simple" + +/* Skeleton output parser for bison, + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* This is the parser code that is written into each bison parser when + the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* 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. */ + +#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE) + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# if YYSTACK_USE_ALLOCA +# define YYSTACK_ALLOC alloca +# else +# ifndef YYSTACK_USE_ALLOCA +# if defined (alloca) || defined (_ALLOCA_H) +# define YYSTACK_ALLOC alloca +# else +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# else +# if defined (__STDC__) || defined (__cplusplus) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +# define YYSTACK_ALLOC malloc +# define YYSTACK_FREE free +# endif +#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */ + + +#if (! defined (yyoverflow) \ + && (! defined (__cplusplus) \ + || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + short yyss; + YYSTYPE yyvs; +# if YYLSP_NEEDED + YYLTYPE yyls; +# endif +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# if YYLSP_NEEDED +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAX) +# else +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAX) +# endif + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + register YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (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_MAX; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# if defined (__STDC__) || defined (__cplusplus) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#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 yyerrlab1 +/* 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); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror ("syntax error: cannot back up"); \ + YYERROR; \ + } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Compute the default location (before the actions + are run). + + When YYLLOC_DEFAULT is run, CURRENT is set the location of the + first token. By default, to implement support for ranges, extend + its range to the last symbol. */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + Current.last_line = Rhs[N].last_line; \ + Current.last_column = Rhs[N].last_column; +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#if YYPURE +# if YYLSP_NEEDED +# ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) +# else +# define YYLEX yylex (&yylval, &yylloc) +# endif +# else /* !YYLSP_NEEDED */ +# ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +# else +# define YYLEX yylex (&yylval) +# endif +# endif /* !YYLSP_NEEDED */ +#else /* !YYPURE */ +# define YYLEX yylex () +#endif /* !YYPURE */ + + +/* 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 (0) +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +#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 + SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#if YYMAXDEPTH == 0 +# undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + +#ifdef YYERROR_VERBOSE + +# ifndef yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +yystrlen (const char *yystr) +# else +yystrlen (yystr) + const char *yystr; +# endif +{ + register const char *yys = yystr; + + while (*yys++ != '\0') + continue; + + return yys - yystr - 1; +} +# 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. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +yystpcpy (char *yydest, const char *yysrc) +# else +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +# endif +{ + register char *yyd = yydest; + register const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif +#endif + +#line 315 "/sw/share/bison/bison.simple" + + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +# define YYPARSE_PARAM_DECL +# else +# define YYPARSE_PARAM_ARG YYPARSE_PARAM +# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +# endif +#else /* !YYPARSE_PARAM */ +# define YYPARSE_PARAM_ARG +# define YYPARSE_PARAM_DECL +#endif /* !YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +# ifdef YYPARSE_PARAM +int yyparse (void *); +# else +int yyparse (void); +# endif +#endif + +/* YY_DECL_VARIABLES -- depending whether we use a pure parser, + variables are global, or local to YYPARSE. */ + +#define YY_DECL_NON_LSP_VARIABLES \ +/* The lookahead symbol. */ \ +int yychar; \ + \ +/* The semantic value of the lookahead symbol. */ \ +YYSTYPE yylval; \ + \ +/* Number of parse errors so far. */ \ +int yynerrs; + +#if YYLSP_NEEDED +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES \ + \ +/* Location data for the lookahead symbol. */ \ +YYLTYPE yylloc; +#else +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES +#endif + + +/* If nonreentrant, generate the variables here. */ + +#if !YYPURE +YY_DECL_VARIABLES +#endif /* !YYPURE */ + +int +yyparse (YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + /* If reentrant, generate the variables here. */ +#if YYPURE + YY_DECL_VARIABLES +#endif /* !YYPURE */ + + register int yystate; + register int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Lookahead token as an internal (translated) token number. */ + int yychar1 = 0; + + /* 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. */ + short yyssa[YYINITDEPTH]; + short *yyss = yyssa; + register short *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + register YYSTYPE *yyvsp; + +#if YYLSP_NEEDED + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; +#endif + +#if YYLSP_NEEDED +# define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +# define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + YYSIZE_T yystacksize = YYINITDEPTH; + + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; +#if YYLSP_NEEDED + YYLTYPE yyloc; +#endif + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int yylen; + + 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; +#if YYLSP_NEEDED + yylsp = yyls; +#endif + 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 (yyssp >= yyss + yystacksize - 1) + { + /* 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; + short *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. */ +# if YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + yyls = yyls1; +# else + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); +# endif + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyoverflowlab; +# else + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + goto yyoverflowlab; + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + + { + short *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyoverflowlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); +# if YYLSP_NEEDED + YYSTACK_RELOCATE (yyls); +# endif +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; +#if YYLSP_NEEDED + yylsp = yyls + yysize - 1; +#endif + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yychar1 = YYTRANSLATE (yychar); + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables + which are defined only if `YYDEBUG' is set. */ + if (yydebug) + { + YYFPRINTF (stderr, "Next token is %d (%s", + yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise + meaning of a token, for further debugging info. */ +# ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +# endif + YYFPRINTF (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + YYDPRINTF ((stderr, "Shifting token %d (%s), ", + yychar, yytname[yychar1])); + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#if YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + yystate = yyn; + 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 the semantic value of + the lookahead token. 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]; + +#if YYLSP_NEEDED + /* Similarly for the default location. Let the user run additional + commands if for instance locations are ranges. */ + yyloc = yylsp[1-yylen]; + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); +#endif + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables which + are defined only if `YYDEBUG' is set. */ + if (yydebug) + { + int yyi; + + YYFPRINTF (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++) + YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]); + YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + switch (yyn) { + +case 3: +#line 142 "parser.y" +{ + /* Verify the service description, supply defaults + * and so on. + */ + if (!cur_service.port) + error ("Service %s lacks a port", + cur_service.name); + if (!cur_service.nbackend) + error ("Service %s lacks back ends", + cur_service.name); + + if (!cur_service.shmkey) + cur_service.shmkey = cur_service.port | SHM_MASK; + + if (!cur_service.bind) + cur_service.bind = "any"; + + /* Add to the list. */ + service = xrealloc (service, ++nservice * sizeof(Service)); + service[nservice - 1] = cur_service; + memset (&cur_service, 0, sizeof(Service)); + ; + break;} +case 5: +#line 173 "parser.y" +{ + psmsg ("service:", yytext); + cur_service.name = xstrdup(yytext); + ; + break;} +case 9: +#line 192 "parser.y" +{ + pimsg ("sevice port:", yyvsp[0].set[0].v.ival); + cur_service.port = yyvsp[0].set[0].v.ival; + free (yyvsp[0].set); + ; + break;} +case 10: +#line 198 "parser.y" +{ + psmsg ("service binding:", yyvsp[0].set[0].v.sval); + cur_service.bind = yyvsp[0].set[0].v.sval; + free (yyvsp[0].set); + ; + break;} +case 11: +#line 204 "parser.y" +{ + pimsg ("service verbosity:", yyvsp[0].set[0].v.ival); + cur_service.verbosity = yyvsp[0].set[0].v.ival; + free (yyvsp[0].set); + ; + break;} +case 12: +#line 210 "parser.y" +{ + pimsg ("service dispatch mode:", yyvsp[0].set[0].v.ival); + pimsg ("service dispatch over:", lastovernr); + psmsg ("service dispatch exth:", lastext); + cur_service.dispatchtype = yyvsp[0].set[0].v.ival; + cur_service.dispatchover = lastovernr; + cur_service.dispatchext = lastext; + free (yyvsp[0].set); + ; + break;} +case 13: +#line 220 "parser.y" +{ + pimsg ("service revival interval:", yyvsp[0].set[0].v.ival); + cur_service.rev_interval = yyvsp[0].set[0].v.ival; + free (yyvsp[0].set); + ; + break;} +case 14: +#line 226 "parser.y" +{ + pimsg ("service backlog:", yyvsp[0].set[0].v.ival); + cur_service.backlog = yyvsp[0].set[0].v.ival; + free (yyvsp[0].set); + ; + break;} +case 15: +#line 232 "parser.y" +{ + pimsg ("service shmkey:", yyvsp[0].set[0].v.ival); + cur_service.shmkey = yyvsp[0].set[0].v.ival; + free (yyvsp[0].set); + ; + break;} +case 16: +#line 238 "parser.y" +{ + pimsg ("connection timout:", yyvsp[0].set[0].v.ival); + cur_service.connectiontimeout = yyvsp[0].set[0].v.ival; + free (yyvsp[0].set); + ; + break;} +case 17: +#line 244 "parser.y" +{ + pimsg ("max clients in service:", yyvsp[0].set[0].v.ival); + cur_service.maxconnections = yyvsp[0].set[0].v.ival; + free (yyvsp[0].set); + ; + break;} +case 18: +#line 250 "parser.y" +{ + pimsg ("service type: ", yyvsp[0].set[0].v.ival); + cur_service.type = yyvsp[0].set[0].v.ival; + free (yyvsp[0].set); + ; + break;} +case 19: +#line 256 "parser.y" +{ + psmsg ("allow from: ", yyvsp[0].set[0].v.sval); + add_allowfrom (yyvsp[0].set[0].v.sval); + free (yyvsp[0].set); + ; + break;} +case 20: +#line 262 "parser.y" +{ + psmsg ("allow file: ", yyvsp[0].set[0].v.sval); + cur_service.allowfile = yyvsp[0].set[0].v.sval; + free (yyvsp[0].set); + ; + break;} +case 21: +#line 268 "parser.y" +{ + psmsg ("deny from: ", yyvsp[0].set[0].v.sval); + add_denyfrom (yyvsp[0].set[0].v.sval); + free (yyvsp[0].set); + ; + break;} +case 22: +#line 274 "parser.y" +{ + psmsg ("deny file: ", yyvsp[0].set[0].v.sval); + cur_service.denyfile = yyvsp[0].set[0].v.sval; + free (yyvsp[0].set); + ; + break;} +case 23: +#line 280 "parser.y" +{ + psmsg ("user account: ", yyvsp[0].set[0].v.sval); + setuseraccount (yyvsp[0].set[0].v.sval); + free (yyvsp[0].set[0].v.sval); + free (yyvsp[0].set); + ; + break;} +case 24: +#line 287 "parser.y" +{ + pimsg ("converting backend statements, count is", yyvsp[0].n); + for (i = 0; i < yyvsp[0].n; i++) + switch (yyvsp[0].set[i].cf) { + case cf_portspec: + pimsg ("backend block port:", yyvsp[0].set[i].v.ival); + cur_backend.port = yyvsp[0].set[i].v.ival; + break; + case cf_serverspec: + psmsg ("backend block server:", yyvsp[0].set[i].v.sval); + cur_backend.server = serverpart (yyvsp[0].set[i].v.sval); + cur_backend.port = portpart (yyvsp[0].set[i].v.sval); + free (yyvsp[0].set[i].v.sval); + break; + case cf_verbosityspec: + pimsg ("backend block verbosity:", yyvsp[0].set[i].v.ival); + cur_backend.verbosity = yyvsp[0].set[i].v.ival; + break; + case cf_onstartspec: + psmsg ("backend block onstart:", yyvsp[0].set[i].v.sval); + cur_backend.onstart = yyvsp[0].set[i].v.sval; + break; + case cf_onfailspec: + psmsg ("backend block onfail:", yyvsp[0].set[i].v.sval); + cur_backend.onfail = yyvsp[0].set[i].v.sval; + break; + case cf_onendspec: + psmsg ("backend block onend:", yyvsp[0].set[i].v.sval); + cur_backend.onend = yyvsp[0].set[i].v.sval; + break; + case cf_dumpspec: + psmsg ("backend trafficlog:", yyvsp[0].set[i].v.sval); + cur_backend.dumpfile = yyvsp[0].set[i].v.sval; + break; + case cf_thruspec: + psmsg ("backend throughputlog:", yyvsp[0].set[i].v.sval); + cur_backend.thruputfile = yyvsp[0].set[i].v.sval; + break; + case cf_weightspec: + pimsg ("backend weight:", yyvsp[0].set[i].v.ival); + cur_backend.weight = yyvsp[0].set[i].v.ival; + break; + case cf_decayspec: + pimsg ("backend decay:", yyvsp[0].set[i].v.ival); + if (yyvsp[0].set[i].v.ival >= 100) + error ("Decay specifier %d must be a percentage, " + "never more than 99", + yyvsp[0].set[i].v.ival); + cur_backend.decay = yyvsp[0].set[i].v.ival; + break; + case cf_maxconnectionsspec: + pimsg ("backend max clients: ", yyvsp[0].set[i].v.ival); + cur_backend.maxconnections = yyvsp[0].set[i].v.ival; + break; + case cf_stickycookiespec: + psmsg ("backend sticky cookie:", + yyvsp[0].set[i].v.sval); + cur_backend.stickycookie = yyvsp[0].set[i].v.sval; + break; + case cf_addclientheaderspec: + psmsg ("client header to add:", + yyvsp[0].set[i].v.sval); + cur_backend.addclientheader = + xrealloc (cur_backend.addclientheader, + (cur_backend.naddclientheader + 1) * + sizeof(char*)); + cur_backend.addclientheader + [cur_backend.naddclientheader++] = + yyvsp[0].set[i].v.sval; + break; + case cf_setclientheaderspec: + psmsg ("client header to set:", + yyvsp[0].set[i].v.sval); + cur_backend.setclientheader = + xrealloc (cur_backend.setclientheader, + (cur_backend.nsetclientheader + 1) * + sizeof(char*)); + cur_backend.setclientheader + [cur_backend.nsetclientheader++] = + yyvsp[0].set[i].v.sval; + break; + case cf_appendclientheaderspec: + psmsg ("client header to append:", + yyvsp[0].set[i].v.sval); + cur_backend.appendclientheader = + xrealloc (cur_backend.appendclientheader, + (cur_backend.nappendclientheader + 1) * + sizeof(char*)); + cur_backend.appendclientheader + [cur_backend.nappendclientheader++] = + yyvsp[0].set[i].v.sval; + break; + case cf_addserverheaderspec: + psmsg ("server header to add:", + yyvsp[0].set[i].v.sval); + cur_backend.addserverheader = + xrealloc (cur_backend.addserverheader, + (cur_backend.naddserverheader + 1) * + sizeof(char*)); + cur_backend.addserverheader + [cur_backend.naddserverheader++] = + yyvsp[0].set[i].v.sval; + break; + case cf_setserverheaderspec: + psmsg ("server header to set:", + yyvsp[0].set[i].v.sval); + cur_backend.setserverheader = + xrealloc (cur_backend.setserverheader, + (cur_backend.nsetserverheader + 1) * + sizeof(char*)); + cur_backend.setserverheader + [cur_backend.nsetserverheader++] = + yyvsp[0].set[i].v.sval; + break; + case cf_appendserverheaderspec: + psmsg ("server header to append:", + yyvsp[0].set[i].v.sval); + cur_backend.appendserverheader = + xrealloc (cur_backend.appendserverheader, + (cur_backend.nappendserverheader + 1) * + sizeof(char*)); + cur_backend.appendserverheader + [cur_backend.nappendserverheader++] = + yyvsp[0].set[i].v.sval; + break; + case cf_retriesspec: + pimsg ("backend retries:", yyvsp[0].set[i].v.ival); + cur_backend.retries = yyvsp[0].set[i].v.ival; + break; + default: + error ("Internal jam, unhandled type %d " + "in backend specification", + yyvsp[0].set[i].cf); + } + free (yyvsp[0].set); + + /* Verify the backend block, supply defaults, + * And so on. + */ + if (!cur_service.port) + error ("Back end %s lacks port", + cur_service.port); + if (cur_backend.weight < 1) + cur_backend.weight = 1; + if (cur_backend.retries < 1) + cur_backend.retries = 1; + if (! cur_backend.onstart) + cur_backend.onstart = xstrdup (""); + if (! cur_backend.onfail) + cur_backend.onfail = xstrdup (""); + if (! cur_backend.onend) + cur_backend.onend = xstrdup (""); + if (! cur_backend.thruputfile) + cur_backend.thruputfile = xstrdup (""); + if (! cur_backend.dumpfile) + cur_backend.dumpfile = xstrdup (""); + if (! cur_backend.stickycookie) + cur_backend.stickycookie = xstrdup (""); + + /* Add to the list. */ + cur_service.backend = xrealloc (cur_service.backend, + ++cur_service.nbackend * + sizeof(Backend)); + cur_service.backend[cur_service.nbackend - 1] = + cur_backend; + pimsg ("this was backend defintion", cur_service.nbackend); + memset (&cur_backend, 0, sizeof(cur_backend)); + ; + break;} +case 25: +#line 460 "parser.y" +{ + pimsg ("port statement:", lastnr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_portspec; + yyval.set[0].v.ival = lastnr; + ; + break;} +case 26: +#line 472 "parser.y" +{ + psmsg ("bindto statement:", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_bindspec; + yyval.set[0].v.sval = xstrdup(laststr); + ; + break;} +case 27: +#line 483 "parser.y" +{ + setlaststr (laststring); + free (laststring); + laststring = 0; + ; + break;} +case 28: +#line 492 "parser.y" +{ + setlastnr (yytext); + ; + break;} +case 30: +#line 506 "parser.y" +{ + pimsg ("verbosity statement:", lastnr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_verbosityspec; + yyval.set[0].v.ival = lastnr; + ; + break;} +case 31: +#line 516 "parser.y" +{ + lastnr = 1; + ; + break;} +case 32: +#line 520 "parser.y" +{ + lastnr = 0; + ; + break;} +case 33: +#line 529 "parser.y" +{ + yyval = yyvsp[-2]; + ; + break;} +case 37: +#line 544 "parser.y" +{ + pimsg ("dispatch mode statement:", 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 38: +#line 561 "parser.y" +{ + setlastovernr (yytext); + ; + break;} +case 39: +#line 567 "parser.y" +{ + psmsg ("external handler:", laststr); + if (lastnr != ds_externalhandler) + error ("Service %s: this dispatch mode doesn't support " + "an external handler", cur_service.name); + setlastext (laststr); + ; + break;} +case 40: +#line 578 "parser.y" +{ + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].v.ival = lastnr; + ; + break;} +case 41: +#line 586 "parser.y" +{ + lastnr = ds_roundrobin; + ; + break;} +case 42: +#line 590 "parser.y" +{ + lastnr = ds_random; + ; + break;} +case 43: +#line 594 "parser.y" +{ + lastnr = ds_byduration; + ; + break;} +case 44: +#line 598 "parser.y" +{ + lastnr = ds_bysize; + ; + break;} +case 45: +#line 602 "parser.y" +{ + lastnr = ds_byorder; + ; + break;} +case 46: +#line 606 "parser.y" +{ + lastnr = ds_byconnections; + ; + break;} +case 47: +#line 610 "parser.y" +{ + lastnr = ds_externalhandler; + ; + break;} +case 48: +#line 614 "parser.y" +{ + lastnr = ds_byclientip; + ; + break;} +case 49: +#line 622 "parser.y" +{ + pimsg ("user account statement:", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_useraccountspec; + yyval.set[0].v.sval = xstrdup (laststr); + ; + break;} +case 50: +#line 633 "parser.y" +{ + setlaststr (laststring); + free (laststring); + laststring = 0; + ; + break;} +case 51: +#line 643 "parser.y" +{ + pimsg ("reviving interval statement:", lastnr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_revivespec; + yyval.set[0].v.ival = lastnr; + ; + break;} +case 52: +#line 655 "parser.y" +{ + pimsg ("backlog statement:", lastnr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_revivespec; + yyval.set[0].v.ival = lastnr; + ; + break;} +case 53: +#line 667 "parser.y" +{ + pimsg ("shmkey statement:", lastnr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_shmkeyspec; + yyval.set[0].v.ival = lastnr; + ; + break;} +case 54: +#line 679 "parser.y" +{ + pimsg ("connection timeout statement:", lastnr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_connectiontimeoutspec; + yyval.set[0].v.ival = lastnr; + ; + break;} +case 55: +#line 691 "parser.y" +{ + pimsg ("max clients statement (service):", lastnr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_maxconnectionsspec; + yyval.set[0].v.ival = lastnr; + ; + break;} +case 56: +#line 703 "parser.y" +{ + pimsg ("service type:", lastnr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_typespec; + yyval.set[0].v.ival = lastnr; + ; + break;} +case 58: +#line 718 "parser.y" +{ + lastnr = type_any; + ; + break;} +case 59: +#line 722 "parser.y" +{ + lastnr = type_http; + ; + break;} +case 60: +#line 730 "parser.y" +{ + psmsg ("allow from: ", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_allowfromspec; + yyval.set[0].v.sval = xstrdup(laststr); + ; + break;} +case 61: +#line 742 "parser.y" +{ + psmsg ("allow from: ", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_denyfromspec; + yyval.set[0].v.sval = xstrdup(laststr); + ; + break;} +case 62: +#line 754 "parser.y" +{ + psmsg ("allow file: ", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_allowfilespec; + yyval.set[0].v.sval = xstrdup(laststr); + ; + break;} +case 63: +#line 766 "parser.y" +{ + psmsg ("allow file: ", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_allowfilespec; + yyval.set[0].v.sval = xstrdup(laststr); + ; + break;} +case 64: +#line 777 "parser.y" +{ + setlaststr (laststring); + free (laststring); + laststring = 0; + ; + break;} +case 65: +#line 789 "parser.y" +{ + yyval = yyvsp[-1]; + ; + break;} +case 66: +#line 796 "parser.y" +{ + psmsg ("backend name:", yytext); + cur_backend.name = xstrdup (yytext); + ; + break;} +case 67: +#line 804 "parser.y" +{ + yyvsp[-1].n++; + yyvsp[-1].set = xrealloc (yyvsp[-1].set, yyvsp[-1].n * sizeof(Confset)); + yyvsp[-1].set[yyvsp[-1].n - 1] = yyvsp[0].set[0]; + yyval = yyvsp[-1]; + ; + break;} +case 68: +#line 811 "parser.y" +{ + yyval = yyvsp[0]; + ; + break;} +case 69: +#line 818 "parser.y" +{ + yyval = yyvsp[0]; + ; + break;} +case 70: +#line 824 "parser.y" +{ + psmsg ("backend server:", yyvsp[0].set[0].v.sval); + yyval = yyvsp[0]; + ; + break;} +case 71: +#line 829 "parser.y" +{ + pimsg ("backend port:", yyvsp[0].set[0].v.ival); + yyval = yyvsp[0]; + ; + break;} +case 72: +#line 834 "parser.y" +{ + pimsg ("backend verbosity:", yyvsp[0].set[0].v.ival); + yyval = yyvsp[0]; + ; + break;} +case 73: +#line 839 "parser.y" +{ + psmsg ("backend onstart:", yyvsp[0].set[0].v.sval); + yyval = yyvsp[0]; + ; + break;} +case 74: +#line 844 "parser.y" +{ + psmsg ("backend onend:", yyvsp[0].set[0].v.sval); + yyval = yyvsp[0]; + ; + break;} +case 75: +#line 849 "parser.y" +{ + psmsg ("backend onfail:", yyvsp[0].set[0].v.sval); + yyval = yyvsp[0]; + ; + break;} +case 76: +#line 854 "parser.y" +{ + psmsg ("backend trafficlog:", yyvsp[0].set[0].v.sval); + yyval = yyvsp[0]; + ; + break;} +case 77: +#line 859 "parser.y" +{ + psmsg ("backend trafficlog:", yyvsp[0].set[0].v.sval); + yyval = yyvsp[0]; + ; + break;} +case 78: +#line 864 "parser.y" +{ + pimsg ("backend weight:", yyvsp[0].set[0].v.ival); + yyval = yyvsp[0]; + ; + break;} +case 79: +#line 869 "parser.y" +{ + pimsg ("backend decay:", yyvsp[0].set[0].v.ival); + yyval = yyvsp[0]; + ; + break;} +case 80: +#line 874 "parser.y" +{ + pimsg ("backend maxconnections:", yyvsp[0].set[0].v.ival); + yyval = yyvsp[0]; + ; + break;} +case 81: +#line 879 "parser.y" +{ + psmsg ("backend sticky cookie:", yyvsp[0].set[0].v.sval); + yyval = yyvsp[0]; + ; + break;} +case 82: +#line 884 "parser.y" +{ + psmsg ("addclientheader:", yyvsp[0].set[0].v.sval); + yyval = yyvsp[0]; + ; + break;} +case 83: +#line 889 "parser.y" +{ + psmsg ("setclientheader:", yyvsp[0].set[0].v.sval); + yyval = yyvsp[0]; + ; + break;} +case 84: +#line 894 "parser.y" +{ + psmsg ("appendclientheader:", yyvsp[0].set[0].v.sval); + yyval = yyvsp[0]; + ; + break;} +case 85: +#line 899 "parser.y" +{ + psmsg ("addserverheader:", yyvsp[0].set[0].v.sval); + yyval = yyvsp[0]; + ; + break;} +case 86: +#line 904 "parser.y" +{ + psmsg ("setserverheader:", yyvsp[0].set[0].v.sval); + yyval = yyvsp[0]; + ; + break;} +case 87: +#line 909 "parser.y" +{ + psmsg ("appendserverheader:", yyvsp[0].set[0].v.sval); + yyval = yyvsp[0]; + ; + break;} +case 88: +#line 914 "parser.y" +{ + pimsg ("backend retries:", yyvsp[0].set[0].v.ival); + yyval = yyvsp[0]; + ; + break;} +case 89: +#line 924 "parser.y" +{ + psmsg ("server statement:", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof (Confset)); + yyval.set[0].cf = cf_serverspec; + yyval.set[0].v.sval = xstrdup (laststr); + ; + break;} +case 90: +#line 936 "parser.y" +{ + pimsg ("weight statement", lastnr); + yyval.n = 1; + yyval.set = xmalloc (sizeof (Confset)); + yyval.set[0].cf = cf_weightspec; + yyval.set[0].v.ival = lastnr; + ; + break;} +case 91: +#line 948 "parser.y" +{ + pimsg ("decay statement", lastnr); + yyval.n = 1; + yyval.set = xmalloc (sizeof (Confset)); + yyval.set[0].cf = cf_decayspec; + yyval.set[0].v.ival = lastnr; + ; + break;} +case 92: +#line 958 "parser.y" +{ + setlaststr (laststring); + ; + break;} +case 93: +#line 966 "parser.y" +{ + pimsg ("retries:", lastnr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_retriesspec; + yyval.set[0].v.ival = lastnr; + ; + break;} +case 94: +#line 978 "parser.y" +{ + psmsg ("onstart statement:", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof (Confset)); + yyval.set[0].cf = cf_onstartspec; + yyval.set[0].v.sval = xstrdup (laststr); + ; + break;} +case 95: +#line 990 "parser.y" +{ + psmsg ("onfail statement:", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof (Confset)); + yyval.set[0].cf = cf_onfailspec; + yyval.set[0].v.sval = xstrdup (laststr); + ; + break;} +case 96: +#line 1002 "parser.y" +{ + psmsg ("onend statement:", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof (Confset)); + yyval.set[0].cf = cf_onendspec; + yyval.set[0].v.sval = xstrdup (laststr); + ; + break;} +case 97: +#line 1014 "parser.y" +{ + psmsg ("trafficlog statement:", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof (Confset)); + yyval.set[0].cf = cf_dumpspec; + yyval.set[0].v.sval = xstrdup (laststr); + ; + break;} +case 98: +#line 1026 "parser.y" +{ + psmsg ("throughputlog statement:", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof (Confset)); + yyval.set[0].cf = cf_thruspec; + yyval.set[0].v.sval = xstrdup (laststr); + ; + break;} +case 99: +#line 1037 "parser.y" +{ + setlaststr (laststring); + free (laststring); + laststring = 0; + ; + break;} +case 100: +#line 1046 "parser.y" +{ + setlaststr (laststring); + free (laststring); + laststring = 0; + ; + break;} +case 101: +#line 1056 "parser.y" +{ + psmsg ("insertcookie statement:", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof (Confset)); + yyval.set[0].cf = cf_stickycookiespec; + yyval.set[0].v.sval = xstrdup (laststr); + ; + break;} +case 102: +#line 1067 "parser.y" +{ + setlaststr (laststring); + free (laststring); + laststring = 0; + ; + break;} +case 103: +#line 1077 "parser.y" +{ + psmsg ("addclientheader statement:", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_addclientheaderspec; + yyval.set[0].v.sval = xstrdup (laststr); + ; + break;} +case 104: +#line 1089 "parser.y" +{ + psmsg ("setclientheader statement:", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_setclientheaderspec; + yyval.set[0].v.sval = xstrdup (laststr); + ; + break;} +case 105: +#line 1101 "parser.y" +{ + psmsg ("appendclientheader statement:", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_appendclientheaderspec; + yyval.set[0].v.sval = xstrdup (laststr); + ; + break;} +case 106: +#line 1113 "parser.y" +{ + psmsg ("addserverheader statement:", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_addserverheaderspec; + yyval.set[0].v.sval = xstrdup (laststr); + ; + break;} +case 107: +#line 1125 "parser.y" +{ + psmsg ("setserverheader statement:", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_setserverheaderspec; + yyval.set[0].v.sval = xstrdup (laststr); + ; + break;} +case 108: +#line 1137 "parser.y" +{ + psmsg ("appendserverheader statement:", laststr); + yyval.n = 1; + yyval.set = xmalloc (sizeof(Confset)); + yyval.set[0].cf = cf_appendserverheaderspec; + yyval.set[0].v.sval = xstrdup (laststr); + ; + break;} +case 109: +#line 1148 "parser.y" +{ + setlaststr (laststring); + free (laststring); + laststring = 0; + ; + break;} +case 110: +#line 1155 "parser.y" +{ + yyerrmsg = "HTTP header specifier expected"; +; + break;} +case 111: +#line 1160 "parser.y" +{ + yyerrmsg = "cookie specifier expected"; +; + break;} +case 112: +#line 1165 "parser.y" +{ + yyerrmsg = "number expected"; +; + break;} +case 113: +#line 1170 "parser.y" +{ + yyerrmsg = "hostname or IP address expected"; +; + break;} +case 114: +#line 1175 "parser.y" +{ + yyerrmsg = "'service' expected"; +; + break;} +case 115: +#line 1180 "parser.y" +{ + yyerrmsg = "backend definition statement expected"; +; + break;} +case 116: +#line 1185 "parser.y" +{ + yyerrmsg = "service body statement expected"; +; + break;} +case 117: +#line 1190 "parser.y" +{ + yyerrmsg = "semicolon (;) expected"; +; + break;} +case 118: +#line 1195 "parser.y" +{ + yyerrmsg = "'on' or 'off' expetcted"; +; + break;} +case 119: +#line 1200 "parser.y" +{ + yyerrmsg = "dispatch method expected"; +; + break;} +case 120: +#line 1205 "parser.y" +{ + yyerrmsg = "command line expected"; +; + break;} +case 121: +#line 1210 "parser.y" +{ + yyerrmsg = "file name expected"; +; + break;} +case 122: +#line 1215 "parser.y" +{ + yyerrmsg = "service name (identifier) expected"; +; + break;} +case 123: +#line 1220 "parser.y" +{ + yyerrmsg = "backend name (identifier) expected"; +; + break;} +case 124: +#line 1225 "parser.y" +{ + yyerrmsg = "IP address or 'any' expected"; +; + break;} +case 125: +#line 1230 "parser.y" +{ + yyerrmsg = "Service type expected ('any', 'stickyhttp', ...)"; +; + break;} +case 126: +#line 1235 "parser.y" +{ + yyerrmsg = "IP filter(s) expected"; +; + break;} +case 127: +#line 1240 "parser.y" +{ + yyerrmsg = "username expected"; +; + break;} +} + +#line 705 "/sw/share/bison/bison.simple" + + + yyvsp -= yylen; + yyssp -= yylen; +#if YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG + if (yydebug) + { + short *yyssp1 = yyss - 1; + YYFPRINTF (stderr, "state stack now"); + while (yyssp1 != yyssp) + YYFPRINTF (stderr, " %d", *++yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; +#if YYLSP_NEEDED + *++yylsp = yyloc; +#endif + + /* 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 - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + YYSIZE_T yysize = 0; + char *yymsg; + int yyx, yycount; + + yycount = 0; + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) + if (yycheck[yyx + yyn] == yyx) + yysize += yystrlen (yytname[yyx]) + 15, yycount++; + yysize += yystrlen ("parse error, unexpected ") + 1; + yysize += yystrlen (yytname[YYTRANSLATE (yychar)]); + yymsg = (char *) YYSTACK_ALLOC (yysize); + if (yymsg != 0) + { + char *yyp = yystpcpy (yymsg, "parse error, unexpected "); + yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]); + + if (yycount < 5) + { + yycount = 0; + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); + yyx++) + if (yycheck[yyx + yyn] == yyx) + { + const char *yyq = ! yycount ? ", expecting " : " or "; + yyp = yystpcpy (yyp, yyq); + yyp = yystpcpy (yyp, yytname[yyx]); + yycount++; + } + } + yyerror (yymsg); + YYSTACK_FREE (yymsg); + } + else + yyerror ("parse error; also virtual memory exhausted"); + } + else +#endif /* defined (YYERROR_VERBOSE) */ + yyerror ("parse error"); + } + goto yyerrlab1; + + +/*--------------------------------------------------. +| yyerrlab1 -- error raised explicitly by an action | +`--------------------------------------------------*/ +yyerrlab1: + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + YYDPRINTF ((stderr, "Discarding token %d (%s).\n", + yychar, yytname[yychar1])); + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + + +/*-------------------------------------------------------------------. +| yyerrdefault -- current state does not do anything special for the | +| error token. | +`-------------------------------------------------------------------*/ +yyerrdefault: +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + + /* If its default is to accept any token, ok. Otherwise pop it. */ + yyn = yydefact[yystate]; + if (yyn) + goto yydefault; +#endif + + +/*---------------------------------------------------------------. +| yyerrpop -- pop the current state because it cannot handle the | +| error token | +`---------------------------------------------------------------*/ +yyerrpop: + if (yyssp == yyss) + YYABORT; + yyvsp--; + yystate = *--yyssp; +#if YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG + if (yydebug) + { + short *yyssp1 = yyss - 1; + YYFPRINTF (stderr, "Error: state stack now"); + while (yyssp1 != yyssp) + YYFPRINTF (stderr, " %d", *++yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + +/*--------------. +| yyerrhandle. | +`--------------*/ +yyerrhandle: + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + + YYDPRINTF ((stderr, "Shifting error token, ")); + + *++yyvsp = yylval; +#if YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +/*---------------------------------------------. +| yyoverflowab -- parser overflow comes here. | +`---------------------------------------------*/ +yyoverflowlab: + yyerror ("parser stack overflow"); + yyresult = 2; + /* Fall through. */ + +yyreturn: +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + return yyresult; +} +#line 1244 "parser.y" diff --git a/src/lib/parser.h b/src/lib/parser.h @@ -0,0 +1,61 @@ +#ifndef BISON_PARSER_H +# define BISON_PARSER_H + +# ifndef YYSTYPE +# define YYSTYPE int +# define YYSTYPE_IS_TRIVIAL 1 +# endif +# define SERVICE 257 +# define IDENTIFIER 258 +# define PORT 259 +# define NUMBER 260 +# define BACKEND 261 +# define VERBOSITY 262 +# define SERVER 263 +# define ON 264 +# define OFF 265 +# define DISPATCHMODE 266 +# define ROUNDROBIN 267 +# define REVIVINGINTERVAL 268 +# define SHMKEY 269 +# define WEIGHT 270 +# define ONSTART 271 +# define ONFAIL 272 +# define STRING 273 +# define BACKLOG 274 +# define RANDOM 275 +# define BYDURATION 276 +# define BYSIZE 277 +# define BYCONNECTIONS 278 +# define CONNECTIONTIMEOUT 279 +# define MAXCONNECTIONS 280 +# define BYORDER 281 +# define TRAFFICLOG 282 +# define OVER 283 +# define DECAY 284 +# define BINDTO 285 +# define THROUGHPUTLOG 286 +# define TYPE 287 +# define ANY 288 +# define HTTP 289 +# define STICKYCOOKIE 290 +# define ADDCLIENTHEADER 291 +# define SETCLIENTHEADER 292 +# define APPENDCLIENTHEADER 293 +# define ADDSERVERHEADER 294 +# define SETSERVERHEADER 295 +# define APPENDSERVERHEADER 296 +# define ALLOWFROM 297 +# define DENYFROM 298 +# define ALLOWFILE 299 +# define DENYFILE 300 +# define EXTERNALHANDLER 301 +# define ONEND 302 +# define USERACCOUNT 303 +# define BYCLIENTIP 304 +# define RETRIES 305 + + +extern YYSTYPE yylval; + +#endif /* not BISON_PARSER_H */ diff --git a/src/lib/parser.y b/src/lib/parser.y @@ -0,0 +1,1243 @@ +/* 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 */ +// #define PARSER_DEBUG +#ifdef PARSER_DEBUG + static void pmsg (char const *x) { + printf ("P: %s\n", x); + } + static void psmsg (char const *x, char const *y) { + printf ("P: %s %s\n", x, y); + } + static void pimsg(char const *x, int y) { + printf ("P: %s %d\n", x, y); + } +#else +# define pmsg(x) +# define psmsg(x,y) +# define pimsg(x,y) +#endif + +/* Error handler for yyparse() */ +static int yyerror (char *msg) { + error ("Parse error at line %d, '%s': %s", + yylineno + 1, yytext, 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) { + lastnr = atoi (what); +} + +/* Store an encountered 'over' number */ +static int lastovernr; +static void setlastovernr (char const *what) { + 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; + int result; + for (item = strtok (what, " "); item; item = strtok (0, " ")) { + 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; +} + +%} + +/* Declarations */ +%token SERVICE IDENTIFIER PORT NUMBER BACKEND VERBOSITY SERVER + ON OFF DISPATCHMODE ROUNDROBIN REVIVINGINTERVAL SHMKEY WEIGHT + ONSTART ONFAIL STRING BACKLOG RANDOM BYDURATION BYSIZE + BYCONNECTIONS CONNECTIONTIMEOUT MAXCONNECTIONS BYORDER TRAFFICLOG + OVER DECAY BINDTO THROUGHPUTLOG TYPE ANY HTTP + STICKYCOOKIE ADDCLIENTHEADER SETCLIENTHEADER APPENDCLIENTHEADER + ADDSERVERHEADER SETSERVERHEADER APPENDSERVERHEADER + ALLOWFROM DENYFROM ALLOWFILE DENYFILE EXTERNALHANDLER ONEND + USERACCOUNT BYCLIENTIP RETRIES + +%% +/* Config file grammar rules */ + +input: + input + element +| + element +; + +element: + service + servicename + '{' + servicestatements + '}' { + /* Verify the service description, supply defaults + * and so on. + */ + if (!cur_service.port) + error ("Service %s lacks a port", + cur_service.name); + if (!cur_service.nbackend) + error ("Service %s lacks back ends", + cur_service.name); + + if (!cur_service.shmkey) + cur_service.shmkey = cur_service.port | SHM_MASK; + + if (!cur_service.bind) + cur_service.bind = "any"; + + /* Add to the list. */ + service = xrealloc (service, ++nservice * sizeof(Service)); + service[nservice - 1] = cur_service; + memset (&cur_service, 0, sizeof(Service)); + } +; + +service: + service_expected + SERVICE +; + +servicename: + servicename_expected + IDENTIFIER { + psmsg ("service:", yytext); + cur_service.name = xstrdup(yytext); + } +; + +servicestatements: + servicestatements + servicestatement +| + servicestatement +; + +servicestatement: + servicebody_expected + servicebody +; + +servicebody: + portstatement { + pimsg ("sevice port:", $1.set[0].v.ival); + cur_service.port = $1.set[0].v.ival; + free ($1.set); + } +| + bindstatement { + psmsg ("service binding:", $1.set[0].v.sval); + cur_service.bind = $1.set[0].v.sval; + free ($1.set); + } +| + verbositystatement { + pimsg ("service verbosity:", $1.set[0].v.ival); + cur_service.verbosity = $1.set[0].v.ival; + free ($1.set); + } +| + dispatchmodestatement { + pimsg ("service dispatch mode:", $1.set[0].v.ival); + pimsg ("service dispatch over:", lastovernr); + psmsg ("service dispatch exth:", lastext); + cur_service.dispatchtype = $1.set[0].v.ival; + cur_service.dispatchover = lastovernr; + cur_service.dispatchext = lastext; + free ($1.set); + } +| + revivingintervalstatement { + pimsg ("service revival interval:", $1.set[0].v.ival); + cur_service.rev_interval = $1.set[0].v.ival; + free ($1.set); + } +| + backlogstatement { + pimsg ("service backlog:", $1.set[0].v.ival); + cur_service.backlog = $1.set[0].v.ival; + free ($1.set); + } +| + shmkeystatement { + pimsg ("service shmkey:", $1.set[0].v.ival); + cur_service.shmkey = $1.set[0].v.ival; + free ($1.set); + } +| + connectiontimeoutstatement { + pimsg ("connection timout:", $1.set[0].v.ival); + cur_service.connectiontimeout = $1.set[0].v.ival; + free ($1.set); + } +| + maxconnectionsstatement { + pimsg ("max clients in service:", $1.set[0].v.ival); + cur_service.maxconnections = $1.set[0].v.ival; + free ($1.set); + } +| + typestatement { + pimsg ("service type: ", $1.set[0].v.ival); + cur_service.type = $1.set[0].v.ival; + free ($1.set); + } +| + allowfromstatement { + psmsg ("allow from: ", $1.set[0].v.sval); + add_allowfrom ($1.set[0].v.sval); + free ($1.set); + } +| + allowfilestatement { + psmsg ("allow file: ", $1.set[0].v.sval); + cur_service.allowfile = $1.set[0].v.sval; + free ($1.set); + } +| + denyfromstatement { + psmsg ("deny from: ", $1.set[0].v.sval); + add_denyfrom ($1.set[0].v.sval); + free ($1.set); + } +| + denyfilestatement { + psmsg ("deny file: ", $1.set[0].v.sval); + cur_service.denyfile = $1.set[0].v.sval; + free ($1.set); + } +| + useraccountstatement { + psmsg ("user account: ", $1.set[0].v.sval); + setuseraccount ($1.set[0].v.sval); + free ($1.set[0].v.sval); + free ($1.set); + } +| + backendblock { + pimsg ("converting backend statements, count is", $1.n); + for (i = 0; i < $1.n; i++) + switch ($1.set[i].cf) { + case cf_portspec: + pimsg ("backend block port:", $1.set[i].v.ival); + cur_backend.port = $1.set[i].v.ival; + break; + case cf_serverspec: + psmsg ("backend block server:", $1.set[i].v.sval); + cur_backend.server = serverpart ($1.set[i].v.sval); + cur_backend.port = portpart ($1.set[i].v.sval); + free ($1.set[i].v.sval); + break; + case cf_verbosityspec: + pimsg ("backend block verbosity:", $1.set[i].v.ival); + cur_backend.verbosity = $1.set[i].v.ival; + break; + case cf_onstartspec: + psmsg ("backend block onstart:", $1.set[i].v.sval); + cur_backend.onstart = $1.set[i].v.sval; + break; + case cf_onfailspec: + psmsg ("backend block onfail:", $1.set[i].v.sval); + cur_backend.onfail = $1.set[i].v.sval; + break; + case cf_onendspec: + psmsg ("backend block onend:", $1.set[i].v.sval); + cur_backend.onend = $1.set[i].v.sval; + break; + case cf_dumpspec: + psmsg ("backend trafficlog:", $1.set[i].v.sval); + cur_backend.dumpfile = $1.set[i].v.sval; + break; + case cf_thruspec: + psmsg ("backend throughputlog:", $1.set[i].v.sval); + cur_backend.thruputfile = $1.set[i].v.sval; + break; + case cf_weightspec: + pimsg ("backend weight:", $1.set[i].v.ival); + cur_backend.weight = $1.set[i].v.ival; + break; + case cf_decayspec: + pimsg ("backend decay:", $1.set[i].v.ival); + if ($1.set[i].v.ival >= 100) + error ("Decay specifier %d must be a percentage, " + "never more than 99", + $1.set[i].v.ival); + cur_backend.decay = $1.set[i].v.ival; + break; + case cf_maxconnectionsspec: + pimsg ("backend max clients: ", $1.set[i].v.ival); + cur_backend.maxconnections = $1.set[i].v.ival; + break; + case cf_stickycookiespec: + psmsg ("backend sticky cookie:", + $1.set[i].v.sval); + cur_backend.stickycookie = $1.set[i].v.sval; + break; + case cf_addclientheaderspec: + psmsg ("client header to add:", + $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: + psmsg ("client header to set:", + $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: + psmsg ("client header to append:", + $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: + psmsg ("server header to add:", + $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: + psmsg ("server header to set:", + $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: + psmsg ("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: + pimsg ("backend retries:", $1.set[i].v.ival); + cur_backend.retries = $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_service.port) + error ("Back end %s lacks port", + cur_service.port); + if (cur_backend.weight < 1) + cur_backend.weight = 1; + if (cur_backend.retries < 1) + cur_backend.retries = 1; + if (! cur_backend.onstart) + cur_backend.onstart = xstrdup (""); + if (! cur_backend.onfail) + cur_backend.onfail = xstrdup (""); + if (! cur_backend.onend) + cur_backend.onend = xstrdup (""); + if (! cur_backend.thruputfile) + cur_backend.thruputfile = xstrdup (""); + if (! cur_backend.dumpfile) + cur_backend.dumpfile = xstrdup (""); + if (! cur_backend.stickycookie) + cur_backend.stickycookie = xstrdup (""); + + /* Add to the list. */ + cur_service.backend = xrealloc (cur_service.backend, + ++cur_service.nbackend * + sizeof(Backend)); + cur_service.backend[cur_service.nbackend - 1] = + cur_backend; + pimsg ("this was backend defintion", cur_service.nbackend); + memset (&cur_backend, 0, sizeof(cur_backend)); + } +; + +portstatement: + PORT + number + semicol { + pimsg ("port statement:", lastnr); + $$.n = 1; + $$.set = xmalloc (sizeof(Confset)); + $$.set[0].cf = cf_portspec; + $$.set[0].v.ival = lastnr; + } +; + +bindstatement: + BINDTO + ipaddress + semicol { + psmsg ("bindto statement:", laststr); + $$.n = 1; + $$.set = xmalloc (sizeof(Confset)); + $$.set[0].cf = cf_bindspec; + $$.set[0].v.sval = xstrdup(laststr); + } +; + +ipaddress: + ipaddress_expected + STRING { + setlaststr (laststring); + free (laststring); + laststring = 0; + } +; + +number: + number_expected + NUMBER { + setlastnr (yytext); + } +; + +semicol: + semicol_expected + ';' +; + +verbositystatement: + VERBOSITY + onoff_expected + onoff + semicol { + pimsg ("verbosity statement:", 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 */ +; + +dispatchover: + OVER + overnumber { + pimsg ("dispatch mode statement:", lastnr); + $$.n = 1; + $$.set = xmalloc (sizeof(Confset)); + $$.set[0].cf = cf_dispatchspec; + $$.set[0].v.ival = lastnr; + + if (lastovernr && + (lastnr != ds_bysize && lastnr != ds_byduration)) + error ("Service '%s': this dispatch mode " + "doesn't support 'over <connections>'", + cur_service.name); + } +; + +overnumber: + number_expected + NUMBER { + setlastovernr (yytext); + } +; + +dispatchext: + commandline { + psmsg ("external handler:", 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 { + pimsg ("user account statement:", 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 + semicol { + pimsg ("reviving interval statement:", lastnr); + $$.n = 1; + $$.set = xmalloc (sizeof(Confset)); + $$.set[0].cf = cf_revivespec; + $$.set[0].v.ival = lastnr; + } +; + +backlogstatement: + BACKLOG + number + semicol { + pimsg ("backlog statement:", lastnr); + $$.n = 1; + $$.set = xmalloc (sizeof(Confset)); + $$.set[0].cf = cf_revivespec; + $$.set[0].v.ival = lastnr; + } +; + +shmkeystatement: + SHMKEY + number + semicol { + pimsg ("shmkey statement:", lastnr); + $$.n = 1; + $$.set = xmalloc (sizeof(Confset)); + $$.set[0].cf = cf_shmkeyspec; + $$.set[0].v.ival = lastnr; + } +; + +connectiontimeoutstatement: + CONNECTIONTIMEOUT + number + semicol { + pimsg ("connection timeout statement:", lastnr); + $$.n = 1; + $$.set = xmalloc (sizeof(Confset)); + $$.set[0].cf = cf_connectiontimeoutspec; + $$.set[0].v.ival = lastnr; + } +; + +maxconnectionsstatement: + MAXCONNECTIONS + number + semicol { + pimsg ("max clients statement (service):", lastnr); + $$.n = 1; + $$.set = xmalloc (sizeof(Confset)); + $$.set[0].cf = cf_maxconnectionsspec; + $$.set[0].v.ival = lastnr; + } +; + +typestatement: + TYPE + typespec + semicol { + pimsg ("service type:", 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; + } +; + +allowfromstatement: + ALLOWFROM + ipfilters + semicol { + psmsg ("allow from: ", laststr); + $$.n = 1; + $$.set = xmalloc (sizeof(Confset)); + $$.set[0].cf = cf_allowfromspec; + $$.set[0].v.sval = xstrdup(laststr); + } +; + +denyfromstatement: + DENYFROM + ipfilters + semicol { + psmsg ("allow from: ", laststr); + $$.n = 1; + $$.set = xmalloc (sizeof(Confset)); + $$.set[0].cf = cf_denyfromspec; + $$.set[0].v.sval = xstrdup(laststr); + } +; + +allowfilestatement: + ALLOWFILE + filename + semicol { + psmsg ("allow file: ", laststr); + $$.n = 1; + $$.set = xmalloc (sizeof(Confset)); + $$.set[0].cf = cf_allowfilespec; + $$.set[0].v.sval = xstrdup(laststr); + } +; + +denyfilestatement: + DENYFILE + filename + semicol { + psmsg ("allow file: ", 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 + '{' + backenddefinitions + '}' { + $$ = $4; + } +; + +backendname: + backendname_expected + IDENTIFIER { + psmsg ("backend name:", yytext); + cur_backend.name = xstrdup (yytext); + } +; + +backenddefinitions: + backenddefinitions + backenddefinition { + $1.n++; + $1.set = xrealloc ($1.set, $1.n * sizeof(Confset)); + $1.set[$1.n - 1] = $2.set[0]; + $$ = $1; + } +| + backenddefinition { + $$ = $1; + } +; + +backenddefinition: + backendstatement_expected + backendstatement { + $$ = $2; + } +; + +backendstatement: + serverstatement { + psmsg ("backend server:", $1.set[0].v.sval); + $$ = $1; + } +| + portstatement { + pimsg ("backend port:", $1.set[0].v.ival); + $$ = $1; + } +| + verbositystatement { + pimsg ("backend verbosity:", $1.set[0].v.ival); + $$ = $1; + } +| + onstartstatement { + psmsg ("backend onstart:", $1.set[0].v.sval); + $$ = $1; + } +| + onendstatement { + psmsg ("backend onend:", $1.set[0].v.sval); + $$ = $1; + } +| + onfailstatement { + psmsg ("backend onfail:", $1.set[0].v.sval); + $$ = $1; + } +| + dumptrafficstatement { + psmsg ("backend trafficlog:", $1.set[0].v.sval); + $$ = $1; + } +| + throughputstatement { + psmsg ("backend trafficlog:", $1.set[0].v.sval); + $$ = $1; + } +| + weightstatement { + pimsg ("backend weight:", $1.set[0].v.ival); + $$ = $1; + } +| + decaystatement { + pimsg ("backend decay:", $1.set[0].v.ival); + $$ = $1; + } +| + maxconnectionsstatement { + pimsg ("backend maxconnections:", $1.set[0].v.ival); + $$ = $1; + } +| + stickycookiestatement { + psmsg ("backend sticky cookie:", $1.set[0].v.sval); + $$ = $1; + } +| + addclientheaderstatement { + psmsg ("addclientheader:", $1.set[0].v.sval); + $$ = $1; + } +| + setclientheaderstatement { + psmsg ("setclientheader:", $1.set[0].v.sval); + $$ = $1; + } +| + appendclientheaderstatement { + psmsg ("appendclientheader:", $1.set[0].v.sval); + $$ = $1; + } +| + addserverheaderstatement { + psmsg ("addserverheader:", $1.set[0].v.sval); + $$ = $1; + } +| + setserverheaderstatement { + psmsg ("setserverheader:", $1.set[0].v.sval); + $$ = $1; + } +| + appendserverheaderstatement { + psmsg ("appendserverheader:", $1.set[0].v.sval); + $$ = $1; + } +| + retriesstatement { + pimsg ("backend retries:", $1.set[0].v.ival); + $$ = $1; + } +; + +serverstatement: + SERVER + serveraddress_expected + serveraddress + semicol { + psmsg ("server statement:", laststr); + $$.n = 1; + $$.set = xmalloc (sizeof (Confset)); + $$.set[0].cf = cf_serverspec; + $$.set[0].v.sval = xstrdup (laststr); + } +; + +weightstatement: + WEIGHT + number + semicol { + pimsg ("weight statement", lastnr); + $$.n = 1; + $$.set = xmalloc (sizeof (Confset)); + $$.set[0].cf = cf_weightspec; + $$.set[0].v.ival = lastnr; + } +; + +decaystatement: + DECAY + number + semicol { + pimsg ("decay statement", 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 { + pimsg ("retries:", lastnr); + $$.n = 1; + $$.set = xmalloc (sizeof(Confset)); + $$.set[0].cf = cf_retriesspec; + $$.set[0].v.ival = lastnr; + } +; + +onstartstatement: + ONSTART + commandline + semicol { + psmsg ("onstart statement:", laststr); + $$.n = 1; + $$.set = xmalloc (sizeof (Confset)); + $$.set[0].cf = cf_onstartspec; + $$.set[0].v.sval = xstrdup (laststr); + } +; + +onfailstatement: + ONFAIL + commandline + semicol { + psmsg ("onfail statement:", laststr); + $$.n = 1; + $$.set = xmalloc (sizeof (Confset)); + $$.set[0].cf = cf_onfailspec; + $$.set[0].v.sval = xstrdup (laststr); + } +; + +onendstatement: + ONEND + commandline + semicol { + psmsg ("onend statement:", laststr); + $$.n = 1; + $$.set = xmalloc (sizeof (Confset)); + $$.set[0].cf = cf_onendspec; + $$.set[0].v.sval = xstrdup (laststr); + } +; + +dumptrafficstatement: + TRAFFICLOG + filename + semicol { + psmsg ("trafficlog statement:", laststr); + $$.n = 1; + $$.set = xmalloc (sizeof (Confset)); + $$.set[0].cf = cf_dumpspec; + $$.set[0].v.sval = xstrdup (laststr); + } +; + +throughputstatement: + THROUGHPUTLOG + filename + semicol { + psmsg ("throughputlog statement:", laststr); + $$.n = 1; + $$.set = xmalloc (sizeof (Confset)); + $$.set[0].cf = cf_thruspec; + $$.set[0].v.sval = xstrdup (laststr); + } +; + +commandline: + commandline_expected + STRING { + setlaststr (laststring); + free (laststring); + laststring = 0; + } +; + +filename: + filename_expected + STRING { + setlaststr (laststring); + free (laststring); + laststring = 0; + } +; + +stickycookiestatement: + STICKYCOOKIE + cookiespecifier + semicol { + psmsg ("insertcookie statement:", laststr); + $$.n = 1; + $$.set = xmalloc (sizeof (Confset)); + $$.set[0].cf = cf_stickycookiespec; + $$.set[0].v.sval = xstrdup (laststr); + } +; + +cookiespecifier: + cookie_expected + STRING { + setlaststr (laststring); + free (laststring); + laststring = 0; + } +; + +addclientheaderstatement: + ADDCLIENTHEADER + headerstring + semicol { + psmsg ("addclientheader statement:", laststr); + $$.n = 1; + $$.set = xmalloc (sizeof(Confset)); + $$.set[0].cf = cf_addclientheaderspec; + $$.set[0].v.sval = xstrdup (laststr); + } +; + +setclientheaderstatement: + SETCLIENTHEADER + headerstring + semicol { + psmsg ("setclientheader statement:", laststr); + $$.n = 1; + $$.set = xmalloc (sizeof(Confset)); + $$.set[0].cf = cf_setclientheaderspec; + $$.set[0].v.sval = xstrdup (laststr); + } +; + +appendclientheaderstatement: + APPENDCLIENTHEADER + headerstring + semicol { + psmsg ("appendclientheader statement:", laststr); + $$.n = 1; + $$.set = xmalloc (sizeof(Confset)); + $$.set[0].cf = cf_appendclientheaderspec; + $$.set[0].v.sval = xstrdup (laststr); + } +; + +addserverheaderstatement: + ADDSERVERHEADER + headerstring + semicol { + psmsg ("addserverheader statement:", laststr); + $$.n = 1; + $$.set = xmalloc (sizeof(Confset)); + $$.set[0].cf = cf_addserverheaderspec; + $$.set[0].v.sval = xstrdup (laststr); + } +; + +setserverheaderstatement: + SETSERVERHEADER + headerstring + semicol { + psmsg ("setserverheader statement:", laststr); + $$.n = 1; + $$.set = xmalloc (sizeof(Confset)); + $$.set[0].cf = cf_setserverheaderspec; + $$.set[0].v.sval = xstrdup (laststr); + } +; + +appendserverheaderstatement: + APPENDSERVERHEADER + headerstring + semicol { + psmsg ("appendserverheader statement:", 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 or 'any' expected"; +} +; + +type_expected: { + yyerrmsg = "Service type expected ('any', 'stickyhttp', ...)"; +} +; + +ipfilters_expected: { + yyerrmsg = "IP filter(s) expected"; +} +; + +useraccount_expected: { + yyerrmsg = "username expected"; +} +; diff --git a/src/proxyerror.txt b/src/lib/proxyerror.txt diff --git a/src/lib/restart.c b/src/lib/restart.c @@ -0,0 +1,24 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 restart (int ac, char **av) { + + create_commandline_space(); + + /* First run the 'stop' action. */ + if (!stop_daemon (ac, av)) + error ("Daemon stop failed, restart failure"); + + sleep (1); + + /* Now run 'start' */ + if (!serve (ac, av)) + error ("Daemon start failed, restart failure"); + + /* All ok.. */ + return (1); +} diff --git a/src/lib/runservice.c b/src/lib/runservice.c @@ -0,0 +1,122 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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; + + msg ("Service %s (on port %d): STARTING", + activeservice->name, activeservice->port); + + /* 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 ("Service %s: fork failure: %s", + activeservice->name, strerror(errno)); + } else if (pid) { + /* Parent branch */ + msg ("Service %s: detached as PID %d", + activeservice->name, pid); + return; + } + + /* Child branch */ + set_program_title ("Service %s: listening", activeservice->name); + close (0); + close (1); + close (2); + daemonized++; + if ( (open ("/dev/null", O_RDONLY) < 0) || + (open ("/dev/null", O_WRONLY) < 0) || + (open ("/dev/null", O_WRONLY) < 0) ) + error ("Service %s: " + "failed to reopen stdin/out/err on /dev/null", + activeservice->name); + if (setsid() < 0) + error ("Service %s: failed to become seesion leader", + activeservice->name); + + /* Promote verbosity. */ + flag_verbose = activeservice->verbosity; + + /* We've forked for the first time */ + program_stage = stage_waiting; + + /* 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 ("Service %s: taking a nap...", activeservice->name); + sleep (SLEEP_TIME); + continue; + } + + /* We have (at least) one back end. Let's run the service. + * Create the socket, bind to port. */ + if ( (listen_sock = make_socket (activeservice->port, + activeservice->bind)) < 0 ) { + if (!sloppyportbind) + error ("Service %s: failed to listen to port %d: %s", + activeservice->name, activeservice->port, + strerror(errno)); + warning ("Service %s: " + "listening socket creation failed.. will retry", + activeservice->name); + + /* We wait here for some time, to let the system regain + * equilibrium. Something's really afoot, so let's not retry + * right away. */ + sleep (SLEEP_TIME); + + continue; + } + + msg ("Service %s: server-side network socket: %d", + activeservice->name, listen_sock); + + /* Zero out the stats for first usage. */ + if (first_serving) { + first_serving = 0; + memset (servicereport, 0, sizeof(Servicereport)); + /* Store our pid, so that 'crossroads stop' may kill us. */ + lock_reporter(); + servicereport->pid = getpid(); + unlock_reporter(); + } + + /* Start serving the port! */ + tcpserve (listen_sock); + + /* tcpserve() returned -- must be because this service is out + * of back ends */ + if (shutdown (listen_sock, SHUT_RDWR)) + warning ("Service %s: " + "failed to shut down server-side socket %d: %s", + activeservice->name, listen_sock, strerror(errno)); + if (close (listen_sock)) + warning ("Service %s: " + "failed to close server-side socket %d: %s", + activeservice->name, listen_sock, strerror(errno)); + } +} diff --git a/src/lib/serve.c b/src/lib/serve.c @@ -0,0 +1,29 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 serve (int ac, char **av) { + int i; + FILE *f; + char *cmd; + + cmd = xstrdup (BINDIR "/crossroads-daemon"); + for (i = 1; i < org_argc; i++) { + cmd = xstrcatch (cmd, ' '); + cmd = xstrcat (cmd, org_argv[i]); + } + + msg ("Starting daemon"); + + if (! (f = popen (cmd, "w")) ) + error ("Failed to start %s: %s", cmd, strerror(errno)); + config_write (fileno(f)); + if (pclose (f) == -1) + error ("Crossroads daemon '%s' indicates error", cmd); + + return (1); +} diff --git a/src/lib/setprogramtitle.c b/src/lib/setprogramtitle.c @@ -0,0 +1,42 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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, ...) { +# if SET_PROC_TITLE_BY_ARGV == 1 + + static int orglen; + char *title, *name = "crossroads"; + int i, j, k; + va_list args; + + /* Make the title */ + va_start (args, fmt); + title = str_vprintf (fmt, args); + va_end (args); + + /* Reset old argv, count max length */ + if (! orglen) + for (i = 0; i < org_argc; i++) + orglen += (strlen(org_argv[i]) + 1); + + /* Paste in our program name first */ + for (i = 0; i <= (int) strlen(name) && i < orglen; i++) + org_argv[0][i] = name[i]; + + /* Paste in the new title */ + for (j = 0; j < (int) strlen(title) && i + j < orglen; j++) + org_argv[0][i + j] = title[j]; + + /* Reset remainder of old cmd line */ + for (k = i + j; k < orglen; k++) + org_argv[0][k] = 0; + + /* Free up */ + free (title); + +# endif /* SET_PROC_TITLE_BY_ARGV */ +} diff --git a/src/lib/showconfig.c b/src/lib/showconfig.c @@ -0,0 +1,38 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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" + "DEFAULT_CONF default configuration file: %s\n" + "MAX_BACKEND max nr. of backends in service: %d\n" + "SHM_MASK magic shared memory number: 0x%x\n" + "SLEEP_TIME service inactivy pause %d\n" + "CONNECT_TIMEOUT backend connect timeout %d\n" + "RETRY_WAIT backend retry pause %d\n" + "TCP_BUFSZ network buffer size %d\n" + "BINDIR installation directory %s\n" + "SET_PROC_TITLE_BY_ARGV argv assumed linear array %d\n" + "EXTRALIBS extra library dependencies %s\n" + "LIBS standard library dependencies %s\n" + , + VER, REVVER, DEFAULT_CONF, MAX_BACKEND, SHM_MASK, SLEEP_TIME, + CONNECT_TIMEOUT, RETRY_WAIT, TCP_BUFSZ, BINDIR, + SET_PROC_TITLE_BY_ARGV, EXTRALIBS, LIBS); + SHOWDEF (HAVE_MALLOC_H, "HAVE_MALLOC_H", "<malloc.h> present"); + SHOWDEF (HAVE_STDINT_H, "HAVE_STDINT_H", "<stdint.h> present"); + SHOWDEF (HAVE_FLOCK, "HAVE_FLOCK", "flock() present"); + SHOWDEF (HAVE_LOCKF, "HAVE_LOCKF", "lockf() present"); + SHOWDEF (HAVE_STRLCAT, "HAVE_STRLCAT", "strlcat() present"); + SHOWDEF (HAVE_SRANDDEV, "HAVE_SRANDDEV", "sranddev() present"); + SHOWDEF (HAVE_VSYSLOG, "HAVE_VSYSLOG", "vsyslog() present"); + SHOWDEF (HAVE_STRCASESTR, "HAVE_STRCASESTR", "strcasestr() present"); +} diff --git a/src/lib/showservices.c b/src/lib/showservices.c @@ -0,0 +1,25 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 show_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].server, + service[i].backend[j].port); + } + return (1); +} diff --git a/src/lib/showstatus.c b/src/lib/showstatus.c @@ -0,0 +1,153 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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); + 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 show_status (int ac, char **av) { + int i, j, services_shown = 0; + + if (xml_status) + printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<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); + 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", + i, service[i].name, servicereport->nclients, + servicereport->last_backend); + else + printf ("Service : %s, %d live connections, " + "last backend %d\n", + service[i].name, servicereport->nclients, + servicereport->last_backend); + for (j = 0; j < service[i].nbackend; j++) { + if (ac > 2 && strcmp (service[i].backend[j].name, av[1])) + continue; + if (tabular_status) + printf ("%s=%s ", service[i].backend[j].name, + state_to_string(servicereport->backendstate[j].avail)); + 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].avail, + state_to_string(servicereport->backendstate[j].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)); + 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].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)); + putchar ('\n'); + } + } + + 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/stagetostring.c b/src/lib/stagetostring.c @@ -0,0 +1,21 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,16 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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-STATE"); +} diff --git a/src/lib/stopdaemon.c b/src/lib/stopdaemon.c @@ -0,0 +1,35 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 stop_daemon (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 anyeay, 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/strcasestr.c b/src/lib/strcasestr.c @@ -0,0 +1,25 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 (big); + if (!big || !*big) + return (0); + + bcopy = strupr (xstrdup (big)); + lcopy = strupr (xstrdup (little)); + if ( (res = strstr (big, little)) ) + res = big + (res - bcopy); + free (bcopy); + free (lcopy); + return (res); +} +#endif diff --git a/src/lib/strexpandformat.c b/src/lib/strexpandformat.c @@ -0,0 +1,105 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 target_backend) { + static char buf[80]; + char *ret; + + /* 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 + * %n - nr of clients of current back end, %1n = first back end etc. + * %r - client IP + * %s - name of service + * %t, %T - timestamp of local or GMT time + * %v - Crossroads version + * %w - weight of current back end, %1w = first back end etc. + */ + + *skip = 1; + switch (*s) { + + case 'a': + if (backend_available (target_backend)) + return ("1"); + return ("0"); + + case 'b': + if (target_backend >= 0 && target_backend < activeservice->nbackend) + return (activeservice->backend[target_backend].name); + return ("noname"); + + case 'e': + snprintf (buf, sizeof(buf) - 1, "%u", (unsigned) time(0)); + return (buf); + + case 'n': + if (target_backend >= 0 && target_backend < activeservice->nbackend) { + snprintf (buf, sizeof(buf) - 1, "%u", + (unsigned) + servicereport->backendstate[target_backend].nclients); + return (buf); + } + return ("0"); + + 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)); + + case 'T': + return (ansistamp (tm_gmtime)); + + case 'v': + return (VER); + + case 'w': + if (target_backend >= 0 && target_backend < activeservice->nbackend) { + snprintf (buf, sizeof(buf) - 1, "%u", + (unsigned) + activeservice->backend[target_backend].weight); + return (buf); + } + return ("0"); + + default: + if (isdigit (*s)) { + ret = fmt_expand (s + 1, skip, *s - '0' - 1); + *skip += 1; + return (ret); + } else { + *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 == '%') { + ret = xstrcat (ret, fmt_expand (cp + 1, &skip, current_backend)); + cp += skip; + } else { + ret = xstrcatch (ret, *cp); + } + } + + return (ret); +} diff --git a/src/lib/stringtostate.c b/src/lib/stringtostate.c @@ -0,0 +1,16 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,30 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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/strprintf.c b/src/lib/strprintf.c @@ -0,0 +1,13 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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/strvprintf.c b/src/lib/strvprintf.c @@ -0,0 +1,32 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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/sysrun.c b/src/lib/sysrun.c @@ -0,0 +1,24 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 sysrun (char const *cmd) { + char *expanded; + int ret; + + if (!cmd || ! *cmd) + return; + + expanded = str_expand_format (cmd); + msg ("Service %s: running command: '%s'", activeservice->name, expanded); + uid_assume(); + if ( (ret = system (expanded)) ) + warning ("Service %s: command '%s' -> '%s' returned %d", + activeservice->name, cmd, expanded, ret); + uid_restore(); + free (expanded); +} diff --git a/src/lib/tcpserve.c b/src/lib/tcpserve.c @@ -0,0 +1,170 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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, backend_selected; + 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) { + if ( (pid = fork()) < 0 ) + error ("Fork failed: %s", strerror(errno)); + else if (!pid) { + set_program_title ("Service %s: wakeup", activeservice->name); + wakeup_handler(); + } else { + msg ("Service %s: started wakeup handler at pid %d", + activeservice->name, pid); + servicereport->rev_pid = pid; + } + } + } + + msg ("Service %s: awaiting activity on port %d (socket fd %d)", + activeservice->name, activeservice->port, server_sock); + + if (listen (server_sock, activeservice->backlog + 1) < 0) + error ("Service %s: failed to listen to server_socket: %s", + activeservice->name, 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 ("Service %s: allow chain has %d entries, " + "deny chain has %d entries", activeservice->name, + activeservice->nallowchain, activeservice->ndenychain); + } + + /* Block until we get a connection. */ + FD_ZERO (&set); + FD_SET (server_sock, &set); + if (select (FD_SETSIZE, &set, 0, 0, 0) < 0) { + msg ("Service %s: interrupt while waiting for activity: %d (%s)", + activeservice->name, 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 ("Service %s: failure while accepting on " + "server socket: %s", activeservice->name, + strerror(errno)); + continue; + } + + /* Store client IP, it's used for lots of logging. */ + client_ip = inet_ntoa (clientname.sin_addr); + msg ("Service %s: connection from %s, socket %d", + activeservice->name, client_ip, new); + if (ipf_denied ()) { + warning ("Service %s: %s matches deny list, " + "terminating connection", activeservice->name, client_ip); + close (new); + continue; + } + if (!ipf_allowed ()) { + warning ("Service %s: %s failes to match allow list, " + "terminating connection", activeservice->name, client_ip); + close (new); + continue; + } + + /* Backend yet to be defined. */ + current_backend = -1; + + /* Incase of a http type service: handle separately. */ + if (activeservice->type == type_http) { + http_serve (new); + close (new); + continue; + } + + /* This is an 'any' service type. + * 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. + */ + if (! backend_count()) { + warning ("Service %s: no back ends available", + activeservice->name); + close (new); + return; + } + + /* Retry back ends until we succeed. */ + backend_selected = 0; + while (!backend_selected) { + msg ("Service %s: About to choose a back end", + activeservice->name); + choose_backend(); + if (current_backend < 0) { + /* No back ends available now. NOTE: we return so that + * runservice() will retry in some time. */ + close (new); + return; + } + + /* 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 return after all. */ + msg ("Service %s: trying back end %s, port %d", + activeservice->name, + activeservice->backend[current_backend].server, + activeservice->backend[current_backend].port); + if ( (backend_sock = backend_connect()) < 0 ) { + warning ("Service %s: failed to connect to server %s:%d " + "(ret %d)", activeservice->name, + activeservice->backend[current_backend].server, + activeservice->backend[current_backend].port, + backend_sock); + continue; + } + + /* Got a live one! */ + backend_selected++; + if (fork_tcp_servicer (current_backend)) { + /* We're the parent branch here. Close sockets so that + * we don't run out of file descriptors, and loop into + * the next select/accept run. */ + close (new); + close (backend_sock); + } else { + /* 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); + } + } + } +} diff --git a/src/lib/tellservice.c b/src/lib/tellservice.c @@ -0,0 +1,43 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 tell_service (int ac, char **av) { + Service *target_service = 0; + int target_backend = -1, i; + Backendavail avail; + + + 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]); + + 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]); + + if ( (avail = string_to_state (av[2])) == st_unknown ) + error ("Incorrect state '%s'.", av[2]); + + alloc_reporter (target_service, 0); + servicereport->backendstate[target_backend].avail = avail; + servicereport->backendstate[target_backend].fail = 0; + msg ("Marked backend %s of service %s as %s.", + av[1], av[0], av[2]); + return (1); +} + diff --git a/src/lib/thruputlog.c b/src/lib/thruputlog.c @@ -0,0 +1,64 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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) { + struct timeval tv; + 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) { + if (gettimeofday (&tv, 0)) + error ("Failed to get the time of day: %s\n", + strerror(errno)); + d_start = tv.tv_sec * 1000000 + tv.tv_usec; + } + if (gettimeofday (&tv, 0)) + error ("Failed to get the time of day: %s\n", strerror(errno)); + d_now = tv.tv_sec * 1000000 + tv.tv_usec; + + /* 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 ", + getpid(), + (d_now - d_start) / 1000000, + dir == dir_client_to_server ? 'C' : 'B'); + 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/trafficlog.c b/src/lib/trafficlog.c @@ -0,0 +1,66 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,28 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 ("Service %s: cannot set effective gid to %d: %s", + activeservice->name, activeservice->gid, + strerror(errno)); + gid_set++; + } + uid_org = getuid(); + if (seteuid (activeservice->uid)) + error ("Service %s: cannot set effective uid to %d: %s", + activeservice->name, activeservice->uid, strerror(errno)); + uid_set++; + } +} diff --git a/src/lib/uidrestore.c b/src/lib/uidrestore.c @@ -0,0 +1,13 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,26 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,13 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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, DEFAULT_CONF); + exit (1); +} diff --git a/src/lib/usage.txt b/src/lib/usage.txt @@ -0,0 +1,39 @@ +This is Crossroads %s, a load balancer and fail-over utility for TCP. +Copyright (c) Karel Kubat / e-tunity 2005-2007 ff. All rights reserved. +For information, contact <info@e-tunity.com> or see <http://www.e-tunity.com>. +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 STATE: mark the named + BACKEND of the SERVICE with the STATE ('available/up', 'unavailable' + or 'down'). Use the action 'services' to determine SERVICE and + BACKEND names. + ** 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 configuration to stdout (debugging only) + -C: shows compile-time configuration and stops + -c CONFIG: Uses the named configuration, instead of the default + %s + -l FAC: Specifies the openlog(3) facility to use when + 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. + -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 + -v: Enables verbosity upon startup. Other verbosity (services + and back ends) is controlled in the configuration. + -V: Shows the version ID and stops. + -?, -h: Shows this message. diff --git a/src/lib/vsyslog.c b/src/lib/vsyslog.c @@ -0,0 +1,16 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,56 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 wakeup_handler () { + int sock, i; + + /* 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. */ + sleep (activeservice->rev_interval); + + /* Now do our stuff. */ + for (current_backend = 0; + current_backend < activeservice->nbackend; + current_backend++) { + + /* Only loop through unavailable back ends. */ + if (servicereport->backendstate[current_backend].avail != + st_unavailable) + continue; + + /* Mark state as WAKING */ + lock_reporter(); + servicereport->backendstate[current_backend].avail = st_waking; + unlock_reporter(); + + /* Try to TCP connect */ + sock = backend_connect(); + + /* Set state accordingly */ + if (sock >= 0) { + close (sock); + warning ("Backend %s of service %s has woken up", + activeservice->backend[current_backend].name, + activeservice->name); + } + lock_reporter(); + servicereport->backendstate[current_backend].avail = + sock >= 0 ? st_available : st_unavailable; + servicereport->backendstate[current_backend].fail = 0; + unlock_reporter(); + } + } +} diff --git a/src/lib/warning.c b/src/lib/warning.c @@ -0,0 +1,23 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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) + fprintf (stderr, "WARNING: %s\n", str); + else + writelog (LOG_ERR, "WARNING: %s", str); + free (str); +} diff --git a/src/lib/writelog.c b/src/lib/writelog.c @@ -0,0 +1,15 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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, log_facility); + vsyslog (prio, fmt, args); +} diff --git a/src/lib/xmalloc.c b/src/lib/xmalloc.c @@ -0,0 +1,10 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,27 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,19 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,14 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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 @@ -0,0 +1,16 @@ +/************************************************************************* + * This file is part of Crosroads 1.40, 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/src/lockreporter.c b/src/lockreporter.c @@ -1,32 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/logactivityany.c b/src/logactivityany.c @@ -1,16 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, a load balancer and fail over - * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. - * Visit http://crossroads.e-tunity.com for information. - *************************************************************************/ -#include "crossroads.h" - -void log_activity_any (char const *action) { - if (!log_activity || current_backend < 0) - return; - if (!logstarted++) - openlog ("crossroads", LOG_PID, log_facility); - syslog (LOG_NOTICE, "%s %s %s from %s to %s", - ansistamp(tm_localtime), action, activeservice->name, - client_ip, activeservice->backend[current_backend].server); -} diff --git a/src/logactivitycontinuation.c b/src/logactivitycontinuation.c @@ -1,10 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/logactivityend.c b/src/logactivityend.c @@ -1,10 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/logactivitystart.c b/src/logactivitystart.c @@ -1,10 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/main.c b/src/main.c @@ -1,155 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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" - -/* Explicit initializations. */ - -int log_facility = LOG_DAEMON; - -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, -}; - -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 opt; - unsigned i; - static Handler handler[] = { - /* Argument Nr.args Needconf Handler function */ - /* -1=no check */ - { "services", 0, 1, show_services }, - { "status", -1, 1, show_status }, - { "stop", 0, 1, stop_daemon }, - { "start", 0, 1, serve }, - { "restart", 0, 1, restart }, - { "tell", 3, 1, tell_service }, - { "configtest", 0, 1, configtest }, - }; - - /* Remember original ac/av/ep */ - org_argc = argc; - org_argv = argv; - - /* Parse options. */ - config_file = DEFAULT_CONF; - while ( (opt = getopt (argc, argv, "?c:fhvi:Val:stC")) > 0 ) - switch (opt) { - case 'a': - log_activity++; - break; - case 'c': - config_file = optarg; - break; - case 'v': - flag_verbose++; - break; - case 'i': - iflag_present++; - break; - case 'l': - switch (atoi (optarg)) { - case 0: - log_facility = LOG_LOCAL0; - break; - case 1: - log_facility = LOG_LOCAL1; - break; - case 2: - log_facility = LOG_LOCAL2; - break; - case 3: - log_facility = LOG_LOCAL3; - break; - case 4: - log_facility = LOG_LOCAL4; - break; - case 5: - log_facility = LOG_LOCAL5; - break; - case 6: - log_facility = LOG_LOCAL6; - break; - case 7: - log_facility = LOG_LOCAL7; - break; - default: - usage(); - } - break; - case 's': - sloppyportbind++; - break; - case 't': - tabular_status++; - break; - case 'C': - show_config(); - exit (0); - case 'V': - puts (VER); - exit (0); - case '?': - case 'h': - default: - usage (); - } - - /* We need at last one argument: the action */ - if (optind >= argc) - usage(); - - /* 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) { - msg ("Parsing configuration %s", config_file); - if (! (yyin = fopen (config_file, "r")) ) - error ("Cannot read configuration %s: %s", - config_file, strerror(errno)); - yyparse(); - fclose (yyin); - } - if (!handler[i].handler (argc - optind, argv + optind + 1)) - error ("'%s' failed", argv[optind]); - return (0); - } - } - - usage(); - return (1); -} diff --git a/src/makesocket.c b/src/makesocket.c @@ -1,62 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 ("Service %s: cannot create network socket: %s", - activeservice->name, strerror(errno)); - return (-1); - } - if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) { - warning ("Service %s: cannot set socket options (reuseaddr): %s", - activeservice->name, strerror(errno)); - close (sock); - return (-2); - } -#ifdef SO_NOSIGPIPE - if (setsockopt (sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val))) { - warning ("Service %s: cannot set socket options (nosigpipe): %s", - activeservice->name, strerror(errno)); - close (sock); - return (-2); - } -#endif - - /* Give the socket a name. */ - name.sin_family = AF_INET; - name.sin_port = htons (port); - - /* Propagate 'bindto' if given. */ - if (strcasecmp (ipaddr, "any")) { - msg ("Service %s: creating socket for IP address '%s'", - activeservice->name, ipaddr); - if ( (name.sin_addr.s_addr = inet_addr (ipaddr)) == INADDR_NONE ) { - close (sock); - error ("Service %s: cannot convert address '%s' to network bytes", - activeservice->name, ipaddr); - } - } else { - msg ("Service %s: creating socket for all interfaces", - activeservice->name); - name.sin_addr.s_addr = htonl (INADDR_ANY); - } - - /* Finallly, 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/markactivity.c b/src/markactivity.c @@ -1,143 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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].avail != st_unavailable) { - servicereport->backendstate[current_backend].fail++; - // msg ("Service %s: Back end %d's unavailability increased to %d", - // activeservice->name, 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].avail != st_waking && - servicereport->backendstate[current_backend].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 ("Service %s: backend %d: %d fails, %d retries, " - "going offline", activeservice->name, current_backend, - servicereport->backendstate[current_backend].fail, - activeservice->backend[current_backend].retries); - servicereport->backendstate[current_backend].fail = 0; - servicereport->backendstate[current_backend].avail = - st_unavailable; - marked_unavailable++; - } - servicereport->backendstate[current_backend].totuses++; - } else if (newstate != st_intermediate) { - /* When applying any other state than intermediate, it's OK */ - servicereport->backendstate[current_backend].fail = 0; - servicereport->backendstate[current_backend].avail = newstate; - servicereport->backendstate[current_backend].totuses++; - } - } - - /* 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 ("Service %s: updated stats for backend %d (%s): " - "hits=%lu, " - "totfails=%lu, secs=%g, avgsecs=%g, " - "bytes=%g, avgbytes=%lu, state=%s", - activeservice->name, - 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].avail)); - - /* Run the onfailure hook if one is specified. */ - if (marked_unavailable && program_stage != stage_retrying) { - msg ("Service %s: extcmd-onfail: " - " current_backend = %d, clients = %d, totclients = %d, cmd = %s", - activeservice->name, current_backend, - servicereport->backendstate[current_backend].nclients, - servicereport->nclients, - activeservice->backend[current_backend].onfail); - - sysrun (activeservice->backend[current_backend].onfail); - } -} diff --git a/src/msg.c b/src/msg.c @@ -1,23 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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) - fprintf (stderr, "INFO: %s\n", str); - else - writelog (LOG_NOTICE, "INFO: %s", str); - - va_end (args); -} diff --git a/src/msgdumpbuf.c b/src/msgdumpbuf.c @@ -1,48 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/netbuffer.c b/src/netbuffer.c @@ -1,35 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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, int *sz) { - if (dir == dir_server_to_client) { - if (srbufmax) { - *sz = srbufmax - srbufpos; - msg ("Service %s: %d bytes still in server buffer", - activeservice->name, *sz); - srbufmax = 0; - return (srbuf + srbufpos); - } else { - msg ("Service %s: server buffer is empty", - activeservice->name); - return (0); - } - } else { - if (clbufmax) { - *sz = clbufmax - clbufpos; - msg ("Service %s: %d bytes still in client buffer", - activeservice->name, *sz); - clbufmax = 0; - return (clbuf + clbufpos); - } else { - msg ("Service %s: client buffer is empty", - activeservice->name); - return (0); - } - } -} diff --git a/src/netbufread.c b/src/netbufread.c @@ -1,60 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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. */ - if (!clbuf) { - clbuf = xmalloc (TCP_BUFSZ); - srbuf = xmalloc (TCP_BUFSZ); - clbufmax = srbufmax = clbufpos = srbufpos = 0; - msg ("Service %s: Allocated client and server buffers", - activeservice->name); - } - - 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, TCP_BUFSZ, buf, is_client); - msg ("Service %s: Got %d bytes from %s", - activeservice->name, *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/netcopy.c b/src/netcopy.c @@ -1,116 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 ("Service %s: network copy stopped after timeout", - activeservice->name); - } - - /* Check for exceptions. */ - if (FD_ISSET (cl, &exset)) { - decr_client_count(); - log_activity_end(); - error ("Service %s: client exception", activeservice->name); - } - if (FD_ISSET (sr, &exset)) { - decr_client_count(); - log_activity_end(); - mark_activity (0, 0, st_unavailable); - error ("Service %s: server exception", activeservice->name); - } - - /* 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 ("Service %s: Read error from server", - activeservice->name); - else { - msg ("Service %s: Read error from client", - activeservice->name); - exit (0); - } - } else { - msg ("Service %s: %s signals end of data", - activeservice->name, - 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 ("Service %s: write error when sending data to %s", - activeservice->name, - 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/netread.c b/src/netread.c @@ -1,101 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 -#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 ("Service %s: fetching atmost %u bytes from %s", - activeservice->name, 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); - error ("Service %s: read from %s timed out", - activeservice->name, 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 ("Service %s: %s exception", desc, activeservice->name); - } - - /* 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 ("Service %s: Read error from server", - activeservice->name); - else { - msg ("Service %s: Read error from client", - activeservice->name); - exit (0); - } - } else { - msg ("Service %s: %s signals end of data", - activeservice->name, 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/netwrite.c b/src/netwrite.c @@ -1,101 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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) - warning ("Service %s: Timout while writing %s on socket %d", - activeservice->name, - is_client ? "client" : "server", sock); - else - warning ("Service %s: Failed to wait for network of %s " - "on socket %d", - activeservice->name, - is_client ? "client" : "server", sock); - - decr_client_count(); - log_activity_end(); - exit (0); - } - - if (FD_ISSET (sock, &exset)) { - decr_client_count(); - log_activity_end(); - error ("Service %s: exception on %s network", - activeservice->name, is_client ? "client" : "server"); - } - - /* We can write! */ - ret = write (sock, buf, buflen); - - /* Check for finished / errors */ - if (ret < 1) { - msg ("Service %s: failed to send to %s: %s (%d)", - activeservice->name, is_client ? "client" : "server", - strerror(errno), ret); - decr_client_count(); - log_activity_end (); - exit (0); - } - - /* 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/parser.c b/src/parser.c @@ -1,2533 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 from parser.y - by GNU bison 1.35. */ - -#define YYBISON 1 /* Identify Bison output. */ - -# define SERVICE 257 -# define IDENTIFIER 258 -# define PORT 259 -# define NUMBER 260 -# define BACKEND 261 -# define VERBOSITY 262 -# define SERVER 263 -# define ON 264 -# define OFF 265 -# define DISPATCHMODE 266 -# define ROUNDROBIN 267 -# define REVIVINGINTERVAL 268 -# define SHMKEY 269 -# define WEIGHT 270 -# define ONSTART 271 -# define ONFAIL 272 -# define STRING 273 -# define BACKLOG 274 -# define RANDOM 275 -# define BYDURATION 276 -# define BYSIZE 277 -# define BYCONNECTIONS 278 -# define CONNECTIONTIMEOUT 279 -# define MAXCONNECTIONS 280 -# define BYORDER 281 -# define TRAFFICLOG 282 -# define OVER 283 -# define DECAY 284 -# define BINDTO 285 -# define THROUGHPUTLOG 286 -# define TYPE 287 -# define ANY 288 -# define HTTP 289 -# define STICKYCOOKIE 290 -# define ADDCLIENTHEADER 291 -# define SETCLIENTHEADER 292 -# define APPENDCLIENTHEADER 293 -# define ADDSERVERHEADER 294 -# define SETSERVERHEADER 295 -# define APPENDSERVERHEADER 296 -# define ALLOWFROM 297 -# define DENYFROM 298 -# define ALLOWFILE 299 -# define DENYFILE 300 -# define EXTERNALHANDLER 301 -# define ONEND 302 -# define USERACCOUNT 303 -# define BYCLIENTIP 304 -# define RETRIES 305 - -#line 3 "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 */ -// #define PARSER_DEBUG -#ifdef PARSER_DEBUG - static void pmsg (char const *x) { - printf ("P: %s\n", x); - } - static void psmsg (char const *x, char const *y) { - printf ("P: %s %s\n", x, y); - } - static void pimsg(char const *x, int y) { - printf ("P: %s %d\n", x, y); - } -#else -# define pmsg(x) -# define psmsg(x,y) -# define pimsg(x,y) -#endif - -/* Error handler for yyparse() */ -static int yyerror (char *msg) { - error ("Parse error at line %d, '%s': %s", - yylineno + 1, yytext, 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) { - lastnr = atoi (what); -} - -/* Store an encountered 'over' number */ -static int lastovernr; -static void setlastovernr (char const *what) { - 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; - int result; - for (item = strtok (what, " "); item; item = strtok (0, " ")) { - 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; -} - -#ifndef YYSTYPE -# define YYSTYPE int -# define YYSTYPE_IS_TRIVIAL 1 -#endif -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - - - -#define YYFINAL 202 -#define YYFLAG -32768 -#define YYNTBASE 55 - -/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ -#define YYTRANSLATE(x) ((unsigned)(x) <= 305 ? yytranslate[x] : 135) - -/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ -static const char 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, 54, - 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, 52, 2, 53, 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, 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 -}; - -#if YYDEBUG -static const short yyprhs[] = -{ - 0, 0, 3, 5, 11, 14, 17, 20, 22, 25, - 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, - 47, 49, 51, 53, 55, 57, 61, 65, 68, 71, - 74, 79, 81, 83, 88, 90, 92, 93, 96, 99, - 101, 104, 106, 108, 110, 112, 114, 116, 118, 120, - 124, 127, 131, 135, 139, 143, 147, 151, 154, 156, - 158, 162, 166, 170, 174, 177, 183, 186, 189, 191, - 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, - 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, - 237, 241, 245, 247, 251, 255, 259, 263, 267, 271, - 274, 277, 281, 284, 288, 292, 296, 300, 304, 308, - 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328 -}; -static const short yyrhs[] = -{ - 56, 55, 0, 56, 0, 57, 58, 52, 59, 53, - 0, 121, 3, 0, 129, 4, 0, 59, 60, 0, - 60, 0, 123, 61, 0, 62, 0, 63, 0, 67, - 0, 69, 0, 78, 0, 79, 0, 80, 0, 81, - 0, 82, 0, 83, 0, 86, 0, 88, 0, 87, - 0, 89, 0, 76, 0, 91, 0, 5, 65, 66, - 0, 31, 64, 66, 0, 131, 19, 0, 119, 6, - 0, 124, 54, 0, 8, 125, 68, 66, 0, 10, - 0, 11, 0, 12, 74, 70, 66, 0, 71, 0, - 73, 0, 0, 29, 72, 0, 119, 6, 0, 106, - 0, 126, 75, 0, 13, 0, 21, 0, 22, 0, - 23, 0, 27, 0, 24, 0, 47, 0, 50, 0, - 49, 77, 66, 0, 134, 19, 0, 14, 65, 66, - 0, 20, 65, 66, 0, 15, 65, 66, 0, 25, - 65, 66, 0, 26, 65, 66, 0, 33, 84, 66, - 0, 132, 85, 0, 34, 0, 35, 0, 43, 90, - 66, 0, 44, 90, 66, 0, 45, 107, 66, 0, - 46, 107, 66, 0, 133, 19, 0, 7, 92, 52, - 93, 53, 0, 130, 4, 0, 93, 94, 0, 94, - 0, 122, 95, 0, 96, 0, 62, 0, 67, 0, - 101, 0, 103, 0, 102, 0, 104, 0, 105, 0, - 97, 0, 98, 0, 82, 0, 108, 0, 110, 0, - 111, 0, 112, 0, 113, 0, 114, 0, 115, 0, - 100, 0, 9, 120, 99, 66, 0, 16, 65, 66, - 0, 30, 65, 66, 0, 19, 0, 51, 65, 66, - 0, 17, 106, 66, 0, 18, 106, 66, 0, 48, - 106, 66, 0, 28, 107, 66, 0, 32, 107, 66, - 0, 127, 19, 0, 128, 19, 0, 36, 109, 66, - 0, 118, 19, 0, 37, 116, 66, 0, 38, 116, - 66, 0, 39, 116, 66, 0, 40, 116, 66, 0, - 41, 116, 66, 0, 42, 116, 66, 0, 117, 19, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -#endif - -#if YYDEBUG -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ -static const short yyrline[] = -{ - 0, 130, 133, 137, 166, 171, 179, 182, 186, 191, - 197, 203, 209, 219, 225, 231, 237, 243, 249, 255, - 261, 267, 273, 279, 286, 457, 469, 481, 490, 497, - 502, 515, 519, 525, 534, 536, 538, 542, 559, 566, - 576, 585, 589, 593, 597, 601, 605, 609, 613, 619, - 631, 640, 652, 664, 676, 688, 700, 712, 717, 721, - 727, 739, 751, 763, 775, 784, 794, 802, 810, 816, - 823, 828, 833, 838, 843, 848, 853, 858, 863, 868, - 873, 878, 883, 888, 893, 898, 903, 908, 913, 920, - 933, 945, 957, 963, 975, 987, 999, 1011, 1023, 1035, - 1044, 1053, 1065, 1074, 1086, 1098, 1110, 1122, 1134, 1146, - 1155, 1160, 1165, 1170, 1175, 1180, 1185, 1190, 1195, 1200, - 1205, 1210, 1215, 1220, 1225, 1230, 1235, 1240 -}; -#endif - - -#if (YYDEBUG) || defined YYERROR_VERBOSE - -/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */ -static const char *const yytname[] = -{ - "$", "error", "$undefined.", "SERVICE", "IDENTIFIER", "PORT", "NUMBER", - "BACKEND", "VERBOSITY", "SERVER", "ON", "OFF", "DISPATCHMODE", - "ROUNDROBIN", "REVIVINGINTERVAL", "SHMKEY", "WEIGHT", "ONSTART", - "ONFAIL", "STRING", "BACKLOG", "RANDOM", "BYDURATION", "BYSIZE", - "BYCONNECTIONS", "CONNECTIONTIMEOUT", "MAXCONNECTIONS", "BYORDER", - "TRAFFICLOG", "OVER", "DECAY", "BINDTO", "THROUGHPUTLOG", "TYPE", "ANY", - "HTTP", "STICKYCOOKIE", "ADDCLIENTHEADER", "SETCLIENTHEADER", - "APPENDCLIENTHEADER", "ADDSERVERHEADER", "SETSERVERHEADER", - "APPENDSERVERHEADER", "ALLOWFROM", "DENYFROM", "ALLOWFILE", "DENYFILE", - "EXTERNALHANDLER", "ONEND", "USERACCOUNT", "BYCLIENTIP", "RETRIES", - "'{'", "'}'", "';'", "input", "element", "service", "servicename", - "servicestatements", "servicestatement", "servicebody", "portstatement", - "bindstatement", "ipaddress", "number", "semicol", "verbositystatement", - "onoff", "dispatchmodestatement", "dispatchtail", "dispatchover", - "overnumber", "dispatchext", "dispatchmethod", "dispatchmethodspec", - "useraccountstatement", "useraccount", "revivingintervalstatement", - "backlogstatement", "shmkeystatement", "connectiontimeoutstatement", - "maxconnectionsstatement", "typestatement", "typespec", "typespecifier", - "allowfromstatement", "denyfromstatement", "allowfilestatement", - "denyfilestatement", "ipfilters", "backendblock", "backendname", - "backenddefinitions", "backenddefinition", "backendstatement", - "serverstatement", "weightstatement", "decaystatement", "serveraddress", - "retriesstatement", "onstartstatement", "onfailstatement", - "onendstatement", "dumptrafficstatement", "throughputstatement", - "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", "ipfilters_expected", - "useraccount_expected", 0 -}; -#endif - -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const short yyr1[] = -{ - 0, 55, 55, 56, 57, 58, 59, 59, 60, 61, - 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 62, 63, 64, 65, 66, - 67, 68, 68, 69, 70, 70, 70, 71, 72, 73, - 74, 75, 75, 75, 75, 75, 75, 75, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 85, - 86, 87, 88, 89, 90, 91, 92, 93, 93, 94, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134 -}; - -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const short yyr2[] = -{ - 0, 2, 1, 5, 2, 2, 2, 1, 2, 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, 3, 3, 3, 3, 3, 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, 4, - 3, 3, 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 -}; - -/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE - doesn't specify something else to do. Zero means the default is an - error. */ -static const short yydefact[] = -{ - 114, 2, 122, 0, 1, 0, 0, 4, 116, 5, - 116, 7, 0, 3, 6, 112, 123, 118, 119, 112, - 112, 112, 112, 112, 124, 125, 126, 126, 121, 121, - 127, 8, 9, 10, 11, 12, 23, 13, 14, 15, - 16, 17, 18, 19, 21, 20, 22, 24, 117, 0, - 0, 0, 0, 36, 0, 117, 117, 117, 117, 117, - 117, 0, 117, 0, 117, 0, 117, 117, 0, 117, - 117, 0, 25, 0, 28, 115, 66, 31, 32, 117, - 112, 117, 34, 35, 39, 0, 41, 42, 43, 44, - 46, 45, 47, 48, 40, 51, 53, 52, 54, 55, - 26, 27, 56, 58, 59, 57, 60, 64, 61, 62, - 100, 63, 49, 50, 29, 115, 68, 0, 30, 37, - 0, 33, 99, 65, 67, 113, 112, 120, 120, 121, - 112, 121, 111, 110, 110, 110, 110, 110, 110, 120, - 112, 71, 72, 80, 69, 70, 78, 79, 88, 73, - 75, 74, 76, 77, 81, 82, 83, 84, 85, 86, - 87, 38, 0, 117, 117, 117, 117, 117, 117, 117, - 0, 117, 0, 117, 117, 117, 117, 117, 117, 117, - 92, 117, 90, 94, 95, 97, 91, 98, 101, 102, - 103, 109, 104, 105, 106, 107, 108, 96, 93, 89, - 0, 0, 0 -}; - -static const short yydefgoto[] = -{ - 4, 1, 2, 5, 10, 11, 31, 32, 33, 60, - 48, 72, 34, 79, 35, 81, 82, 119, 83, 53, - 94, 36, 70, 37, 38, 39, 40, 41, 42, 62, - 105, 43, 44, 45, 46, 64, 47, 50, 115, 116, - 144, 145, 146, 147, 181, 148, 149, 150, 151, 152, - 153, 84, 67, 154, 169, 155, 156, 157, 158, 159, - 160, 171, 172, 170, 49, 162, 3, 117, 12, 73, - 52, 54, 85, 68, 6, 51, 61, 63, 65, 71 -}; - -static const short yypact[] = -{ - -32768, 7,-32768, 10,-32768, -44, 13,-32768,-32768,-32768, - -30,-32768, 58,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 21, - -17, 37, 23, -13, 114,-32768,-32768,-32768,-32768,-32768, - -32768, 25,-32768, 5,-32768, 26,-32768,-32768, 28,-32768, - -32768, 30,-32768, -12,-32768,-32768,-32768,-32768,-32768,-32768, - -32768,-32768,-32768,-32768,-32768, 32,-32768,-32768,-32768,-32768, - -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - -32768,-32768,-32768,-32768,-32768, 0,-32768, 20,-32768,-32768, - 48,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - -32768,-32768, 36,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - 45,-32768, 50,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - 67, 74,-32768 -}; - -static const short yypgoto[] = -{ - 75,-32768,-32768,-32768,-32768, 66,-32768, -40,-32768,-32768, - -1, -55, -38,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - -32768,-32768,-32768,-32768,-32768,-32768,-32768, -37,-32768,-32768, - -32768,-32768,-32768,-32768,-32768, 54,-32768,-32768,-32768, -33, - -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - -32768, -96, 1,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - -32768, -42,-32768,-32768, 6,-32768,-32768,-32768,-32768,-32768, - -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768 -}; - - -#define YYLAST 164 - - -static const short yytable[] = -{ - 95, 96, 97, 98, 99, 100, -120, 102, 8, 106, - -114, 108, 109, 7, 111, 112, 80, 9, 55, 56, - 57, 58, 59, 13, 118, 15, 121, 74, 17, 125, - 69, 164, 165, 77, 78, 75, 126, 127, 128, 103, - 104, 76, 114, 178, 101, 107, 23, 110, 129, 113, - 130, 122, 131, 123, 161, 180, 132, 133, 134, 135, - 136, 137, 138, 15, 189, 16, 17, 201, 139, 191, - 18, 140, 19, 20, 202, 200, 14, 141, 21, 142, - 143, 66, 124, 22, 23, 0, 120, 0, 0, 24, - 0, 25, 173, 174, 175, 176, 177, 0, 0, 0, - 0, 26, 27, 28, 29, 0, 0, 30, 182, 183, - 184, 185, 186, 187, 188, 0, 190, 0, 192, 193, - 194, 195, 196, 197, 198, 163, 199, 86, 0, 167, - 166, 0, 168, 0, 0, 87, 88, 89, 90, 179, - 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 92, 0, 0, 93 -}; - -static const short yycheck[] = -{ - 55, 56, 57, 58, 59, 60, 19, 62, 52, 64, - 3, 66, 67, 3, 69, 70, 29, 4, 19, 20, - 21, 22, 23, 53, 79, 5, 81, 6, 8, 9, - 29, 127, 128, 10, 11, 52, 16, 17, 18, 34, - 35, 4, 54, 139, 19, 19, 26, 19, 28, 19, - 30, 19, 32, 53, 6, 19, 36, 37, 38, 39, - 40, 41, 42, 5, 19, 7, 8, 0, 48, 19, - 12, 51, 14, 15, 0, 0, 10, 117, 20, 117, - 117, 27, 115, 25, 26, -1, 80, -1, -1, 31, - -1, 33, 134, 135, 136, 137, 138, -1, -1, -1, - -1, 43, 44, 45, 46, -1, -1, 49, 163, 164, - 165, 166, 167, 168, 169, -1, 171, -1, 173, 174, - 175, 176, 177, 178, 179, 126, 181, 13, -1, 130, - 129, -1, 131, -1, -1, 21, 22, 23, 24, 140, - -1, 27, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 47, -1, -1, 50 -}; -/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ -#line 3 "/sw/share/bison/bison.simple" - -/* Skeleton output parser for bison, - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 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., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ - -/* This is the parser code that is written into each bison parser when - the %semantic_parser declaration is not specified in the grammar. - It was written by Richard Stallman by simplifying the hairy parser - used when %semantic_parser is specified. */ - -/* 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. */ - -#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE) - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# if YYSTACK_USE_ALLOCA -# define YYSTACK_ALLOC alloca -# else -# ifndef YYSTACK_USE_ALLOCA -# if defined (alloca) || defined (_ALLOCA_H) -# define YYSTACK_ALLOC alloca -# else -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) -# else -# if defined (__STDC__) || defined (__cplusplus) -# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -# define YYSTACK_ALLOC malloc -# define YYSTACK_FREE free -# endif -#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */ - - -#if (! defined (yyoverflow) \ - && (! defined (__cplusplus) \ - || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - short yyss; - YYSTYPE yyvs; -# if YYLSP_NEEDED - YYLTYPE yyls; -# endif -}; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# if YYLSP_NEEDED -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ - + 2 * YYSTACK_GAP_MAX) -# else -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAX) -# endif - -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - register YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (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_MAX; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (0) - -#endif - - -#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) -# define YYSIZE_T __SIZE_TYPE__ -#endif -#if ! defined (YYSIZE_T) && defined (size_t) -# define YYSIZE_T size_t -#endif -#if ! defined (YYSIZE_T) -# if defined (__STDC__) || defined (__cplusplus) -# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -#endif -#if ! defined (YYSIZE_T) -# define YYSIZE_T unsigned int -#endif - -#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 yyerrlab1 -/* 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); \ - yychar1 = YYTRANSLATE (yychar); \ - YYPOPSTACK; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror ("syntax error: cannot back up"); \ - YYERROR; \ - } \ -while (0) - -#define YYTERROR 1 -#define YYERRCODE 256 - - -/* YYLLOC_DEFAULT -- Compute the default location (before the actions - are run). - - When YYLLOC_DEFAULT is run, CURRENT is set the location of the - first token. By default, to implement support for ranges, extend - its range to the last symbol. */ - -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - Current.last_line = Rhs[N].last_line; \ - Current.last_column = Rhs[N].last_column; -#endif - - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#if YYPURE -# if YYLSP_NEEDED -# ifdef YYLEX_PARAM -# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) -# else -# define YYLEX yylex (&yylval, &yylloc) -# endif -# else /* !YYLSP_NEEDED */ -# ifdef YYLEX_PARAM -# define YYLEX yylex (&yylval, YYLEX_PARAM) -# else -# define YYLEX yylex (&yylval) -# endif -# endif /* !YYLSP_NEEDED */ -#else /* !YYPURE */ -# define YYLEX yylex () -#endif /* !YYPURE */ - - -/* 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 (0) -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -#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 - SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#if YYMAXDEPTH == 0 -# undef YYMAXDEPTH -#endif - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - -#ifdef YYERROR_VERBOSE - -# ifndef yystrlen -# if defined (__GLIBC__) && defined (_STRING_H) -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -static YYSIZE_T -# if defined (__STDC__) || defined (__cplusplus) -yystrlen (const char *yystr) -# else -yystrlen (yystr) - const char *yystr; -# endif -{ - register const char *yys = yystr; - - while (*yys++ != '\0') - continue; - - return yys - yystr - 1; -} -# 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. */ -static char * -# if defined (__STDC__) || defined (__cplusplus) -yystpcpy (char *yydest, const char *yysrc) -# else -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -# endif -{ - register char *yyd = yydest; - register const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif -#endif - -#line 315 "/sw/share/bison/bison.simple" - - -/* The user can define YYPARSE_PARAM as the name of an argument to be passed - into yyparse. The argument should have type void *. - It should actually point to an object. - Grammar actions can access the variable by casting it - to the proper pointer type. */ - -#ifdef YYPARSE_PARAM -# if defined (__STDC__) || defined (__cplusplus) -# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM -# define YYPARSE_PARAM_DECL -# else -# define YYPARSE_PARAM_ARG YYPARSE_PARAM -# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; -# endif -#else /* !YYPARSE_PARAM */ -# define YYPARSE_PARAM_ARG -# define YYPARSE_PARAM_DECL -#endif /* !YYPARSE_PARAM */ - -/* Prevent warning if -Wstrict-prototypes. */ -#ifdef __GNUC__ -# ifdef YYPARSE_PARAM -int yyparse (void *); -# else -int yyparse (void); -# endif -#endif - -/* YY_DECL_VARIABLES -- depending whether we use a pure parser, - variables are global, or local to YYPARSE. */ - -#define YY_DECL_NON_LSP_VARIABLES \ -/* The lookahead symbol. */ \ -int yychar; \ - \ -/* The semantic value of the lookahead symbol. */ \ -YYSTYPE yylval; \ - \ -/* Number of parse errors so far. */ \ -int yynerrs; - -#if YYLSP_NEEDED -# define YY_DECL_VARIABLES \ -YY_DECL_NON_LSP_VARIABLES \ - \ -/* Location data for the lookahead symbol. */ \ -YYLTYPE yylloc; -#else -# define YY_DECL_VARIABLES \ -YY_DECL_NON_LSP_VARIABLES -#endif - - -/* If nonreentrant, generate the variables here. */ - -#if !YYPURE -YY_DECL_VARIABLES -#endif /* !YYPURE */ - -int -yyparse (YYPARSE_PARAM_ARG) - YYPARSE_PARAM_DECL -{ - /* If reentrant, generate the variables here. */ -#if YYPURE - YY_DECL_VARIABLES -#endif /* !YYPURE */ - - register int yystate; - register int yyn; - int yyresult; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - /* Lookahead token as an internal (translated) token number. */ - int yychar1 = 0; - - /* 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. */ - short yyssa[YYINITDEPTH]; - short *yyss = yyssa; - register short *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - register YYSTYPE *yyvsp; - -#if YYLSP_NEEDED - /* The location stack. */ - YYLTYPE yylsa[YYINITDEPTH]; - YYLTYPE *yyls = yylsa; - YYLTYPE *yylsp; -#endif - -#if YYLSP_NEEDED -# define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) -#else -# define YYPOPSTACK (yyvsp--, yyssp--) -#endif - - YYSIZE_T yystacksize = YYINITDEPTH; - - - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; -#if YYLSP_NEEDED - YYLTYPE yyloc; -#endif - - /* When reducing, the number of symbols on the RHS of the reduced - rule. */ - int yylen; - - 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; -#if YYLSP_NEEDED - yylsp = yyls; -#endif - 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 (yyssp >= yyss + yystacksize - 1) - { - /* 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; - short *yyss1 = yyss; - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. */ -# if YYLSP_NEEDED - YYLTYPE *yyls1 = yyls; - /* This used to be a conditional around just the two extra args, - but that might be undefined if yyoverflow is a macro. */ - yyoverflow ("parser stack overflow", - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yyls1, yysize * sizeof (*yylsp), - &yystacksize); - yyls = yyls1; -# else - yyoverflow ("parser stack overflow", - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yystacksize); -# endif - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyoverflowlab; -# else - /* Extend the stack our own way. */ - if (yystacksize >= YYMAXDEPTH) - goto yyoverflowlab; - yystacksize *= 2; - if (yystacksize > YYMAXDEPTH) - yystacksize = YYMAXDEPTH; - - { - short *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyoverflowlab; - YYSTACK_RELOCATE (yyss); - YYSTACK_RELOCATE (yyvs); -# if YYLSP_NEEDED - YYSTACK_RELOCATE (yyls); -# endif -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; -#if YYLSP_NEEDED - yylsp = yyls + yysize - 1; -#endif - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyssp >= yyss + yystacksize - 1) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - goto yybackup; - - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - -/* Do appropriate processing given the current state. */ -/* Read a lookahead token if we need one and don't already have one. */ -/* yyresume: */ - - /* First try to decide what to do without reference to lookahead token. */ - - yyn = yypact[yystate]; - if (yyn == YYFLAG) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* yychar is either YYEMPTY or YYEOF - or a valid token in external form. */ - - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; - } - - /* Convert token to internal form (in yychar1) for indexing tables with */ - - if (yychar <= 0) /* This means end of input. */ - { - yychar1 = 0; - yychar = YYEOF; /* Don't call YYLEX any more */ - - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yychar1 = YYTRANSLATE (yychar); - -#if YYDEBUG - /* We have to keep this `#if YYDEBUG', since we use variables - which are defined only if `YYDEBUG' is set. */ - if (yydebug) - { - YYFPRINTF (stderr, "Next token is %d (%s", - yychar, yytname[yychar1]); - /* Give the individual parser a way to print the precise - meaning of a token, for further debugging info. */ -# ifdef YYPRINT - YYPRINT (stderr, yychar, yylval); -# endif - YYFPRINTF (stderr, ")\n"); - } -#endif - } - - yyn += yychar1; - if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) - goto yydefault; - - yyn = yytable[yyn]; - - /* yyn is what to do for this token type in this state. - Negative => reduce, -yyn is rule number. - Positive => shift, yyn is new state. - New state is final state => don't bother to shift, - just return success. - 0, or most negative number => error. */ - - if (yyn < 0) - { - if (yyn == YYFLAG) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - else if (yyn == 0) - goto yyerrlab; - - if (yyn == YYFINAL) - YYACCEPT; - - /* Shift the lookahead token. */ - YYDPRINTF ((stderr, "Shifting token %d (%s), ", - yychar, yytname[yychar1])); - - /* Discard the token being shifted unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; - - *++yyvsp = yylval; -#if YYLSP_NEEDED - *++yylsp = yylloc; -#endif - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - yystate = yyn; - 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 the semantic value of - the lookahead token. 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]; - -#if YYLSP_NEEDED - /* Similarly for the default location. Let the user run additional - commands if for instance locations are ranges. */ - yyloc = yylsp[1-yylen]; - YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); -#endif - -#if YYDEBUG - /* We have to keep this `#if YYDEBUG', since we use variables which - are defined only if `YYDEBUG' is set. */ - if (yydebug) - { - int yyi; - - YYFPRINTF (stderr, "Reducing via rule %d (line %d), ", - yyn, yyrline[yyn]); - - /* Print the symbols being reduced, and their result. */ - for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++) - YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]); - YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]); - } -#endif - - switch (yyn) { - -case 3: -#line 142 "parser.y" -{ - /* Verify the service description, supply defaults - * and so on. - */ - if (!cur_service.port) - error ("Service %s lacks a port", - cur_service.name); - if (!cur_service.nbackend) - error ("Service %s lacks back ends", - cur_service.name); - - if (!cur_service.shmkey) - cur_service.shmkey = cur_service.port | SHM_MASK; - - if (!cur_service.bind) - cur_service.bind = "any"; - - /* Add to the list. */ - service = xrealloc (service, ++nservice * sizeof(Service)); - service[nservice - 1] = cur_service; - memset (&cur_service, 0, sizeof(Service)); - ; - break;} -case 5: -#line 173 "parser.y" -{ - psmsg ("service:", yytext); - cur_service.name = xstrdup(yytext); - ; - break;} -case 9: -#line 192 "parser.y" -{ - pimsg ("sevice port:", yyvsp[0].set[0].v.ival); - cur_service.port = yyvsp[0].set[0].v.ival; - free (yyvsp[0].set); - ; - break;} -case 10: -#line 198 "parser.y" -{ - psmsg ("service binding:", yyvsp[0].set[0].v.sval); - cur_service.bind = yyvsp[0].set[0].v.sval; - free (yyvsp[0].set); - ; - break;} -case 11: -#line 204 "parser.y" -{ - pimsg ("service verbosity:", yyvsp[0].set[0].v.ival); - cur_service.verbosity = yyvsp[0].set[0].v.ival; - free (yyvsp[0].set); - ; - break;} -case 12: -#line 210 "parser.y" -{ - pimsg ("service dispatch mode:", yyvsp[0].set[0].v.ival); - pimsg ("service dispatch over:", lastovernr); - psmsg ("service dispatch exth:", lastext); - cur_service.dispatchtype = yyvsp[0].set[0].v.ival; - cur_service.dispatchover = lastovernr; - cur_service.dispatchext = lastext; - free (yyvsp[0].set); - ; - break;} -case 13: -#line 220 "parser.y" -{ - pimsg ("service revival interval:", yyvsp[0].set[0].v.ival); - cur_service.rev_interval = yyvsp[0].set[0].v.ival; - free (yyvsp[0].set); - ; - break;} -case 14: -#line 226 "parser.y" -{ - pimsg ("service backlog:", yyvsp[0].set[0].v.ival); - cur_service.backlog = yyvsp[0].set[0].v.ival; - free (yyvsp[0].set); - ; - break;} -case 15: -#line 232 "parser.y" -{ - pimsg ("service shmkey:", yyvsp[0].set[0].v.ival); - cur_service.shmkey = yyvsp[0].set[0].v.ival; - free (yyvsp[0].set); - ; - break;} -case 16: -#line 238 "parser.y" -{ - pimsg ("connection timout:", yyvsp[0].set[0].v.ival); - cur_service.connectiontimeout = yyvsp[0].set[0].v.ival; - free (yyvsp[0].set); - ; - break;} -case 17: -#line 244 "parser.y" -{ - pimsg ("max clients in service:", yyvsp[0].set[0].v.ival); - cur_service.maxconnections = yyvsp[0].set[0].v.ival; - free (yyvsp[0].set); - ; - break;} -case 18: -#line 250 "parser.y" -{ - pimsg ("service type: ", yyvsp[0].set[0].v.ival); - cur_service.type = yyvsp[0].set[0].v.ival; - free (yyvsp[0].set); - ; - break;} -case 19: -#line 256 "parser.y" -{ - psmsg ("allow from: ", yyvsp[0].set[0].v.sval); - add_allowfrom (yyvsp[0].set[0].v.sval); - free (yyvsp[0].set); - ; - break;} -case 20: -#line 262 "parser.y" -{ - psmsg ("allow file: ", yyvsp[0].set[0].v.sval); - cur_service.allowfile = yyvsp[0].set[0].v.sval; - free (yyvsp[0].set); - ; - break;} -case 21: -#line 268 "parser.y" -{ - psmsg ("deny from: ", yyvsp[0].set[0].v.sval); - add_denyfrom (yyvsp[0].set[0].v.sval); - free (yyvsp[0].set); - ; - break;} -case 22: -#line 274 "parser.y" -{ - psmsg ("deny file: ", yyvsp[0].set[0].v.sval); - cur_service.denyfile = yyvsp[0].set[0].v.sval; - free (yyvsp[0].set); - ; - break;} -case 23: -#line 280 "parser.y" -{ - psmsg ("user account: ", yyvsp[0].set[0].v.sval); - setuseraccount (yyvsp[0].set[0].v.sval); - free (yyvsp[0].set[0].v.sval); - free (yyvsp[0].set); - ; - break;} -case 24: -#line 287 "parser.y" -{ - pimsg ("converting backend statements, count is", yyvsp[0].n); - for (i = 0; i < yyvsp[0].n; i++) - switch (yyvsp[0].set[i].cf) { - case cf_portspec: - pimsg ("backend block port:", yyvsp[0].set[i].v.ival); - cur_backend.port = yyvsp[0].set[i].v.ival; - break; - case cf_serverspec: - psmsg ("backend block server:", yyvsp[0].set[i].v.sval); - cur_backend.server = serverpart (yyvsp[0].set[i].v.sval); - cur_backend.port = portpart (yyvsp[0].set[i].v.sval); - free (yyvsp[0].set[i].v.sval); - break; - case cf_verbosityspec: - pimsg ("backend block verbosity:", yyvsp[0].set[i].v.ival); - cur_backend.verbosity = yyvsp[0].set[i].v.ival; - break; - case cf_onstartspec: - psmsg ("backend block onstart:", yyvsp[0].set[i].v.sval); - cur_backend.onstart = yyvsp[0].set[i].v.sval; - break; - case cf_onfailspec: - psmsg ("backend block onfail:", yyvsp[0].set[i].v.sval); - cur_backend.onfail = yyvsp[0].set[i].v.sval; - break; - case cf_onendspec: - psmsg ("backend block onend:", yyvsp[0].set[i].v.sval); - cur_backend.onend = yyvsp[0].set[i].v.sval; - break; - case cf_dumpspec: - psmsg ("backend trafficlog:", yyvsp[0].set[i].v.sval); - cur_backend.dumpfile = yyvsp[0].set[i].v.sval; - break; - case cf_thruspec: - psmsg ("backend throughputlog:", yyvsp[0].set[i].v.sval); - cur_backend.thruputfile = yyvsp[0].set[i].v.sval; - break; - case cf_weightspec: - pimsg ("backend weight:", yyvsp[0].set[i].v.ival); - cur_backend.weight = yyvsp[0].set[i].v.ival; - break; - case cf_decayspec: - pimsg ("backend decay:", yyvsp[0].set[i].v.ival); - if (yyvsp[0].set[i].v.ival >= 100) - error ("Decay specifier %d must be a percentage, " - "never more than 99", - yyvsp[0].set[i].v.ival); - cur_backend.decay = yyvsp[0].set[i].v.ival; - break; - case cf_maxconnectionsspec: - pimsg ("backend max clients: ", yyvsp[0].set[i].v.ival); - cur_backend.maxconnections = yyvsp[0].set[i].v.ival; - break; - case cf_stickycookiespec: - psmsg ("backend sticky cookie:", - yyvsp[0].set[i].v.sval); - cur_backend.stickycookie = yyvsp[0].set[i].v.sval; - break; - case cf_addclientheaderspec: - psmsg ("client header to add:", - yyvsp[0].set[i].v.sval); - cur_backend.addclientheader = - xrealloc (cur_backend.addclientheader, - (cur_backend.naddclientheader + 1) * - sizeof(char*)); - cur_backend.addclientheader - [cur_backend.naddclientheader++] = - yyvsp[0].set[i].v.sval; - break; - case cf_setclientheaderspec: - psmsg ("client header to set:", - yyvsp[0].set[i].v.sval); - cur_backend.setclientheader = - xrealloc (cur_backend.setclientheader, - (cur_backend.nsetclientheader + 1) * - sizeof(char*)); - cur_backend.setclientheader - [cur_backend.nsetclientheader++] = - yyvsp[0].set[i].v.sval; - break; - case cf_appendclientheaderspec: - psmsg ("client header to append:", - yyvsp[0].set[i].v.sval); - cur_backend.appendclientheader = - xrealloc (cur_backend.appendclientheader, - (cur_backend.nappendclientheader + 1) * - sizeof(char*)); - cur_backend.appendclientheader - [cur_backend.nappendclientheader++] = - yyvsp[0].set[i].v.sval; - break; - case cf_addserverheaderspec: - psmsg ("server header to add:", - yyvsp[0].set[i].v.sval); - cur_backend.addserverheader = - xrealloc (cur_backend.addserverheader, - (cur_backend.naddserverheader + 1) * - sizeof(char*)); - cur_backend.addserverheader - [cur_backend.naddserverheader++] = - yyvsp[0].set[i].v.sval; - break; - case cf_setserverheaderspec: - psmsg ("server header to set:", - yyvsp[0].set[i].v.sval); - cur_backend.setserverheader = - xrealloc (cur_backend.setserverheader, - (cur_backend.nsetserverheader + 1) * - sizeof(char*)); - cur_backend.setserverheader - [cur_backend.nsetserverheader++] = - yyvsp[0].set[i].v.sval; - break; - case cf_appendserverheaderspec: - psmsg ("server header to append:", - yyvsp[0].set[i].v.sval); - cur_backend.appendserverheader = - xrealloc (cur_backend.appendserverheader, - (cur_backend.nappendserverheader + 1) * - sizeof(char*)); - cur_backend.appendserverheader - [cur_backend.nappendserverheader++] = - yyvsp[0].set[i].v.sval; - break; - case cf_retriesspec: - pimsg ("backend retries:", yyvsp[0].set[i].v.ival); - cur_backend.retries = yyvsp[0].set[i].v.ival; - break; - default: - error ("Internal jam, unhandled type %d " - "in backend specification", - yyvsp[0].set[i].cf); - } - free (yyvsp[0].set); - - /* Verify the backend block, supply defaults, - * And so on. - */ - if (!cur_service.port) - error ("Back end %s lacks port", - cur_service.port); - if (cur_backend.weight < 1) - cur_backend.weight = 1; - if (cur_backend.retries < 1) - cur_backend.retries = 1; - if (! cur_backend.onstart) - cur_backend.onstart = xstrdup (""); - if (! cur_backend.onfail) - cur_backend.onfail = xstrdup (""); - if (! cur_backend.onend) - cur_backend.onend = xstrdup (""); - if (! cur_backend.thruputfile) - cur_backend.thruputfile = xstrdup (""); - if (! cur_backend.dumpfile) - cur_backend.dumpfile = xstrdup (""); - if (! cur_backend.stickycookie) - cur_backend.stickycookie = xstrdup (""); - - /* Add to the list. */ - cur_service.backend = xrealloc (cur_service.backend, - ++cur_service.nbackend * - sizeof(Backend)); - cur_service.backend[cur_service.nbackend - 1] = - cur_backend; - pimsg ("this was backend defintion", cur_service.nbackend); - memset (&cur_backend, 0, sizeof(cur_backend)); - ; - break;} -case 25: -#line 460 "parser.y" -{ - pimsg ("port statement:", lastnr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_portspec; - yyval.set[0].v.ival = lastnr; - ; - break;} -case 26: -#line 472 "parser.y" -{ - psmsg ("bindto statement:", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_bindspec; - yyval.set[0].v.sval = xstrdup(laststr); - ; - break;} -case 27: -#line 483 "parser.y" -{ - setlaststr (laststring); - free (laststring); - laststring = 0; - ; - break;} -case 28: -#line 492 "parser.y" -{ - setlastnr (yytext); - ; - break;} -case 30: -#line 506 "parser.y" -{ - pimsg ("verbosity statement:", lastnr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_verbosityspec; - yyval.set[0].v.ival = lastnr; - ; - break;} -case 31: -#line 516 "parser.y" -{ - lastnr = 1; - ; - break;} -case 32: -#line 520 "parser.y" -{ - lastnr = 0; - ; - break;} -case 33: -#line 529 "parser.y" -{ - yyval = yyvsp[-2]; - ; - break;} -case 37: -#line 544 "parser.y" -{ - pimsg ("dispatch mode statement:", 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 38: -#line 561 "parser.y" -{ - setlastovernr (yytext); - ; - break;} -case 39: -#line 567 "parser.y" -{ - psmsg ("external handler:", laststr); - if (lastnr != ds_externalhandler) - error ("Service %s: this dispatch mode doesn't support " - "an external handler", cur_service.name); - setlastext (laststr); - ; - break;} -case 40: -#line 578 "parser.y" -{ - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].v.ival = lastnr; - ; - break;} -case 41: -#line 586 "parser.y" -{ - lastnr = ds_roundrobin; - ; - break;} -case 42: -#line 590 "parser.y" -{ - lastnr = ds_random; - ; - break;} -case 43: -#line 594 "parser.y" -{ - lastnr = ds_byduration; - ; - break;} -case 44: -#line 598 "parser.y" -{ - lastnr = ds_bysize; - ; - break;} -case 45: -#line 602 "parser.y" -{ - lastnr = ds_byorder; - ; - break;} -case 46: -#line 606 "parser.y" -{ - lastnr = ds_byconnections; - ; - break;} -case 47: -#line 610 "parser.y" -{ - lastnr = ds_externalhandler; - ; - break;} -case 48: -#line 614 "parser.y" -{ - lastnr = ds_byclientip; - ; - break;} -case 49: -#line 622 "parser.y" -{ - pimsg ("user account statement:", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_useraccountspec; - yyval.set[0].v.sval = xstrdup (laststr); - ; - break;} -case 50: -#line 633 "parser.y" -{ - setlaststr (laststring); - free (laststring); - laststring = 0; - ; - break;} -case 51: -#line 643 "parser.y" -{ - pimsg ("reviving interval statement:", lastnr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_revivespec; - yyval.set[0].v.ival = lastnr; - ; - break;} -case 52: -#line 655 "parser.y" -{ - pimsg ("backlog statement:", lastnr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_revivespec; - yyval.set[0].v.ival = lastnr; - ; - break;} -case 53: -#line 667 "parser.y" -{ - pimsg ("shmkey statement:", lastnr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_shmkeyspec; - yyval.set[0].v.ival = lastnr; - ; - break;} -case 54: -#line 679 "parser.y" -{ - pimsg ("connection timeout statement:", lastnr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_connectiontimeoutspec; - yyval.set[0].v.ival = lastnr; - ; - break;} -case 55: -#line 691 "parser.y" -{ - pimsg ("max clients statement (service):", lastnr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_maxconnectionsspec; - yyval.set[0].v.ival = lastnr; - ; - break;} -case 56: -#line 703 "parser.y" -{ - pimsg ("service type:", lastnr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_typespec; - yyval.set[0].v.ival = lastnr; - ; - break;} -case 58: -#line 718 "parser.y" -{ - lastnr = type_any; - ; - break;} -case 59: -#line 722 "parser.y" -{ - lastnr = type_http; - ; - break;} -case 60: -#line 730 "parser.y" -{ - psmsg ("allow from: ", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_allowfromspec; - yyval.set[0].v.sval = xstrdup(laststr); - ; - break;} -case 61: -#line 742 "parser.y" -{ - psmsg ("allow from: ", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_denyfromspec; - yyval.set[0].v.sval = xstrdup(laststr); - ; - break;} -case 62: -#line 754 "parser.y" -{ - psmsg ("allow file: ", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_allowfilespec; - yyval.set[0].v.sval = xstrdup(laststr); - ; - break;} -case 63: -#line 766 "parser.y" -{ - psmsg ("allow file: ", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_allowfilespec; - yyval.set[0].v.sval = xstrdup(laststr); - ; - break;} -case 64: -#line 777 "parser.y" -{ - setlaststr (laststring); - free (laststring); - laststring = 0; - ; - break;} -case 65: -#line 789 "parser.y" -{ - yyval = yyvsp[-1]; - ; - break;} -case 66: -#line 796 "parser.y" -{ - psmsg ("backend name:", yytext); - cur_backend.name = xstrdup (yytext); - ; - break;} -case 67: -#line 804 "parser.y" -{ - yyvsp[-1].n++; - yyvsp[-1].set = xrealloc (yyvsp[-1].set, yyvsp[-1].n * sizeof(Confset)); - yyvsp[-1].set[yyvsp[-1].n - 1] = yyvsp[0].set[0]; - yyval = yyvsp[-1]; - ; - break;} -case 68: -#line 811 "parser.y" -{ - yyval = yyvsp[0]; - ; - break;} -case 69: -#line 818 "parser.y" -{ - yyval = yyvsp[0]; - ; - break;} -case 70: -#line 824 "parser.y" -{ - psmsg ("backend server:", yyvsp[0].set[0].v.sval); - yyval = yyvsp[0]; - ; - break;} -case 71: -#line 829 "parser.y" -{ - pimsg ("backend port:", yyvsp[0].set[0].v.ival); - yyval = yyvsp[0]; - ; - break;} -case 72: -#line 834 "parser.y" -{ - pimsg ("backend verbosity:", yyvsp[0].set[0].v.ival); - yyval = yyvsp[0]; - ; - break;} -case 73: -#line 839 "parser.y" -{ - psmsg ("backend onstart:", yyvsp[0].set[0].v.sval); - yyval = yyvsp[0]; - ; - break;} -case 74: -#line 844 "parser.y" -{ - psmsg ("backend onend:", yyvsp[0].set[0].v.sval); - yyval = yyvsp[0]; - ; - break;} -case 75: -#line 849 "parser.y" -{ - psmsg ("backend onfail:", yyvsp[0].set[0].v.sval); - yyval = yyvsp[0]; - ; - break;} -case 76: -#line 854 "parser.y" -{ - psmsg ("backend trafficlog:", yyvsp[0].set[0].v.sval); - yyval = yyvsp[0]; - ; - break;} -case 77: -#line 859 "parser.y" -{ - psmsg ("backend trafficlog:", yyvsp[0].set[0].v.sval); - yyval = yyvsp[0]; - ; - break;} -case 78: -#line 864 "parser.y" -{ - pimsg ("backend weight:", yyvsp[0].set[0].v.ival); - yyval = yyvsp[0]; - ; - break;} -case 79: -#line 869 "parser.y" -{ - pimsg ("backend decay:", yyvsp[0].set[0].v.ival); - yyval = yyvsp[0]; - ; - break;} -case 80: -#line 874 "parser.y" -{ - pimsg ("backend maxconnections:", yyvsp[0].set[0].v.ival); - yyval = yyvsp[0]; - ; - break;} -case 81: -#line 879 "parser.y" -{ - psmsg ("backend sticky cookie:", yyvsp[0].set[0].v.sval); - yyval = yyvsp[0]; - ; - break;} -case 82: -#line 884 "parser.y" -{ - psmsg ("addclientheader:", yyvsp[0].set[0].v.sval); - yyval = yyvsp[0]; - ; - break;} -case 83: -#line 889 "parser.y" -{ - psmsg ("setclientheader:", yyvsp[0].set[0].v.sval); - yyval = yyvsp[0]; - ; - break;} -case 84: -#line 894 "parser.y" -{ - psmsg ("appendclientheader:", yyvsp[0].set[0].v.sval); - yyval = yyvsp[0]; - ; - break;} -case 85: -#line 899 "parser.y" -{ - psmsg ("addserverheader:", yyvsp[0].set[0].v.sval); - yyval = yyvsp[0]; - ; - break;} -case 86: -#line 904 "parser.y" -{ - psmsg ("setserverheader:", yyvsp[0].set[0].v.sval); - yyval = yyvsp[0]; - ; - break;} -case 87: -#line 909 "parser.y" -{ - psmsg ("appendserverheader:", yyvsp[0].set[0].v.sval); - yyval = yyvsp[0]; - ; - break;} -case 88: -#line 914 "parser.y" -{ - pimsg ("backend retries:", yyvsp[0].set[0].v.ival); - yyval = yyvsp[0]; - ; - break;} -case 89: -#line 924 "parser.y" -{ - psmsg ("server statement:", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof (Confset)); - yyval.set[0].cf = cf_serverspec; - yyval.set[0].v.sval = xstrdup (laststr); - ; - break;} -case 90: -#line 936 "parser.y" -{ - pimsg ("weight statement", lastnr); - yyval.n = 1; - yyval.set = xmalloc (sizeof (Confset)); - yyval.set[0].cf = cf_weightspec; - yyval.set[0].v.ival = lastnr; - ; - break;} -case 91: -#line 948 "parser.y" -{ - pimsg ("decay statement", lastnr); - yyval.n = 1; - yyval.set = xmalloc (sizeof (Confset)); - yyval.set[0].cf = cf_decayspec; - yyval.set[0].v.ival = lastnr; - ; - break;} -case 92: -#line 958 "parser.y" -{ - setlaststr (laststring); - ; - break;} -case 93: -#line 966 "parser.y" -{ - pimsg ("retries:", lastnr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_retriesspec; - yyval.set[0].v.ival = lastnr; - ; - break;} -case 94: -#line 978 "parser.y" -{ - psmsg ("onstart statement:", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof (Confset)); - yyval.set[0].cf = cf_onstartspec; - yyval.set[0].v.sval = xstrdup (laststr); - ; - break;} -case 95: -#line 990 "parser.y" -{ - psmsg ("onfail statement:", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof (Confset)); - yyval.set[0].cf = cf_onfailspec; - yyval.set[0].v.sval = xstrdup (laststr); - ; - break;} -case 96: -#line 1002 "parser.y" -{ - psmsg ("onend statement:", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof (Confset)); - yyval.set[0].cf = cf_onendspec; - yyval.set[0].v.sval = xstrdup (laststr); - ; - break;} -case 97: -#line 1014 "parser.y" -{ - psmsg ("trafficlog statement:", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof (Confset)); - yyval.set[0].cf = cf_dumpspec; - yyval.set[0].v.sval = xstrdup (laststr); - ; - break;} -case 98: -#line 1026 "parser.y" -{ - psmsg ("throughputlog statement:", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof (Confset)); - yyval.set[0].cf = cf_thruspec; - yyval.set[0].v.sval = xstrdup (laststr); - ; - break;} -case 99: -#line 1037 "parser.y" -{ - setlaststr (laststring); - free (laststring); - laststring = 0; - ; - break;} -case 100: -#line 1046 "parser.y" -{ - setlaststr (laststring); - free (laststring); - laststring = 0; - ; - break;} -case 101: -#line 1056 "parser.y" -{ - psmsg ("insertcookie statement:", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof (Confset)); - yyval.set[0].cf = cf_stickycookiespec; - yyval.set[0].v.sval = xstrdup (laststr); - ; - break;} -case 102: -#line 1067 "parser.y" -{ - setlaststr (laststring); - free (laststring); - laststring = 0; - ; - break;} -case 103: -#line 1077 "parser.y" -{ - psmsg ("addclientheader statement:", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_addclientheaderspec; - yyval.set[0].v.sval = xstrdup (laststr); - ; - break;} -case 104: -#line 1089 "parser.y" -{ - psmsg ("setclientheader statement:", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_setclientheaderspec; - yyval.set[0].v.sval = xstrdup (laststr); - ; - break;} -case 105: -#line 1101 "parser.y" -{ - psmsg ("appendclientheader statement:", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_appendclientheaderspec; - yyval.set[0].v.sval = xstrdup (laststr); - ; - break;} -case 106: -#line 1113 "parser.y" -{ - psmsg ("addserverheader statement:", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_addserverheaderspec; - yyval.set[0].v.sval = xstrdup (laststr); - ; - break;} -case 107: -#line 1125 "parser.y" -{ - psmsg ("setserverheader statement:", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_setserverheaderspec; - yyval.set[0].v.sval = xstrdup (laststr); - ; - break;} -case 108: -#line 1137 "parser.y" -{ - psmsg ("appendserverheader statement:", laststr); - yyval.n = 1; - yyval.set = xmalloc (sizeof(Confset)); - yyval.set[0].cf = cf_appendserverheaderspec; - yyval.set[0].v.sval = xstrdup (laststr); - ; - break;} -case 109: -#line 1148 "parser.y" -{ - setlaststr (laststring); - free (laststring); - laststring = 0; - ; - break;} -case 110: -#line 1155 "parser.y" -{ - yyerrmsg = "HTTP header specifier expected"; -; - break;} -case 111: -#line 1160 "parser.y" -{ - yyerrmsg = "cookie specifier expected"; -; - break;} -case 112: -#line 1165 "parser.y" -{ - yyerrmsg = "number expected"; -; - break;} -case 113: -#line 1170 "parser.y" -{ - yyerrmsg = "hostname or IP address expected"; -; - break;} -case 114: -#line 1175 "parser.y" -{ - yyerrmsg = "'service' expected"; -; - break;} -case 115: -#line 1180 "parser.y" -{ - yyerrmsg = "backend definition statement expected"; -; - break;} -case 116: -#line 1185 "parser.y" -{ - yyerrmsg = "service body statement expected"; -; - break;} -case 117: -#line 1190 "parser.y" -{ - yyerrmsg = "semicolon (;) expected"; -; - break;} -case 118: -#line 1195 "parser.y" -{ - yyerrmsg = "'on' or 'off' expetcted"; -; - break;} -case 119: -#line 1200 "parser.y" -{ - yyerrmsg = "dispatch method expected"; -; - break;} -case 120: -#line 1205 "parser.y" -{ - yyerrmsg = "command line expected"; -; - break;} -case 121: -#line 1210 "parser.y" -{ - yyerrmsg = "file name expected"; -; - break;} -case 122: -#line 1215 "parser.y" -{ - yyerrmsg = "service name (identifier) expected"; -; - break;} -case 123: -#line 1220 "parser.y" -{ - yyerrmsg = "backend name (identifier) expected"; -; - break;} -case 124: -#line 1225 "parser.y" -{ - yyerrmsg = "IP address or 'any' expected"; -; - break;} -case 125: -#line 1230 "parser.y" -{ - yyerrmsg = "Service type expected ('any', 'stickyhttp', ...)"; -; - break;} -case 126: -#line 1235 "parser.y" -{ - yyerrmsg = "IP filter(s) expected"; -; - break;} -case 127: -#line 1240 "parser.y" -{ - yyerrmsg = "username expected"; -; - break;} -} - -#line 705 "/sw/share/bison/bison.simple" - - - yyvsp -= yylen; - yyssp -= yylen; -#if YYLSP_NEEDED - yylsp -= yylen; -#endif - -#if YYDEBUG - if (yydebug) - { - short *yyssp1 = yyss - 1; - YYFPRINTF (stderr, "state stack now"); - while (yyssp1 != yyssp) - YYFPRINTF (stderr, " %d", *++yyssp1); - YYFPRINTF (stderr, "\n"); - } -#endif - - *++yyvsp = yyval; -#if YYLSP_NEEDED - *++yylsp = yyloc; -#endif - - /* 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 - YYNTBASE] + *yyssp; - if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTBASE]; - - goto yynewstate; - - -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ -yyerrlab: - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; - -#ifdef YYERROR_VERBOSE - yyn = yypact[yystate]; - - if (yyn > YYFLAG && yyn < YYLAST) - { - YYSIZE_T yysize = 0; - char *yymsg; - int yyx, yycount; - - yycount = 0; - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - for (yyx = yyn < 0 ? -yyn : 0; - yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) - if (yycheck[yyx + yyn] == yyx) - yysize += yystrlen (yytname[yyx]) + 15, yycount++; - yysize += yystrlen ("parse error, unexpected ") + 1; - yysize += yystrlen (yytname[YYTRANSLATE (yychar)]); - yymsg = (char *) YYSTACK_ALLOC (yysize); - if (yymsg != 0) - { - char *yyp = yystpcpy (yymsg, "parse error, unexpected "); - yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]); - - if (yycount < 5) - { - yycount = 0; - for (yyx = yyn < 0 ? -yyn : 0; - yyx < (int) (sizeof (yytname) / sizeof (char *)); - yyx++) - if (yycheck[yyx + yyn] == yyx) - { - const char *yyq = ! yycount ? ", expecting " : " or "; - yyp = yystpcpy (yyp, yyq); - yyp = yystpcpy (yyp, yytname[yyx]); - yycount++; - } - } - yyerror (yymsg); - YYSTACK_FREE (yymsg); - } - else - yyerror ("parse error; also virtual memory exhausted"); - } - else -#endif /* defined (YYERROR_VERBOSE) */ - yyerror ("parse error"); - } - goto yyerrlab1; - - -/*--------------------------------------------------. -| yyerrlab1 -- error raised explicitly by an action | -`--------------------------------------------------*/ -yyerrlab1: - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - /* return failure if at end of input */ - if (yychar == YYEOF) - YYABORT; - YYDPRINTF ((stderr, "Discarding token %d (%s).\n", - yychar, yytname[yychar1])); - yychar = YYEMPTY; - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - - yyerrstatus = 3; /* Each real token shifted decrements this */ - - goto yyerrhandle; - - -/*-------------------------------------------------------------------. -| yyerrdefault -- current state does not do anything special for the | -| error token. | -`-------------------------------------------------------------------*/ -yyerrdefault: -#if 0 - /* This is wrong; only states that explicitly want error tokens - should shift them. */ - - /* If its default is to accept any token, ok. Otherwise pop it. */ - yyn = yydefact[yystate]; - if (yyn) - goto yydefault; -#endif - - -/*---------------------------------------------------------------. -| yyerrpop -- pop the current state because it cannot handle the | -| error token | -`---------------------------------------------------------------*/ -yyerrpop: - if (yyssp == yyss) - YYABORT; - yyvsp--; - yystate = *--yyssp; -#if YYLSP_NEEDED - yylsp--; -#endif - -#if YYDEBUG - if (yydebug) - { - short *yyssp1 = yyss - 1; - YYFPRINTF (stderr, "Error: state stack now"); - while (yyssp1 != yyssp) - YYFPRINTF (stderr, " %d", *++yyssp1); - YYFPRINTF (stderr, "\n"); - } -#endif - -/*--------------. -| yyerrhandle. | -`--------------*/ -yyerrhandle: - yyn = yypact[yystate]; - if (yyn == YYFLAG) - goto yyerrdefault; - - yyn += YYTERROR; - if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) - goto yyerrdefault; - - yyn = yytable[yyn]; - if (yyn < 0) - { - if (yyn == YYFLAG) - goto yyerrpop; - yyn = -yyn; - goto yyreduce; - } - else if (yyn == 0) - goto yyerrpop; - - if (yyn == YYFINAL) - YYACCEPT; - - YYDPRINTF ((stderr, "Shifting error token, ")); - - *++yyvsp = yylval; -#if YYLSP_NEEDED - *++yylsp = yylloc; -#endif - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -/*---------------------------------------------. -| yyoverflowab -- parser overflow comes here. | -`---------------------------------------------*/ -yyoverflowlab: - yyerror ("parser stack overflow"); - yyresult = 2; - /* Fall through. */ - -yyreturn: -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif - return yyresult; -} -#line 1244 "parser.y" diff --git a/src/parser.h b/src/parser.h @@ -1,66 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, a load balancer and fail over - * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. - * Visit http://crossroads.e-tunity.com for information. - *************************************************************************/ -#ifndef BISON_PARSER_H -# define BISON_PARSER_H - -# ifndef YYSTYPE -# define YYSTYPE int -# define YYSTYPE_IS_TRIVIAL 1 -# endif -# define SERVICE 257 -# define IDENTIFIER 258 -# define PORT 259 -# define NUMBER 260 -# define BACKEND 261 -# define VERBOSITY 262 -# define SERVER 263 -# define ON 264 -# define OFF 265 -# define DISPATCHMODE 266 -# define ROUNDROBIN 267 -# define REVIVINGINTERVAL 268 -# define SHMKEY 269 -# define WEIGHT 270 -# define ONSTART 271 -# define ONFAIL 272 -# define STRING 273 -# define BACKLOG 274 -# define RANDOM 275 -# define BYDURATION 276 -# define BYSIZE 277 -# define BYCONNECTIONS 278 -# define CONNECTIONTIMEOUT 279 -# define MAXCONNECTIONS 280 -# define BYORDER 281 -# define TRAFFICLOG 282 -# define OVER 283 -# define DECAY 284 -# define BINDTO 285 -# define THROUGHPUTLOG 286 -# define TYPE 287 -# define ANY 288 -# define HTTP 289 -# define STICKYCOOKIE 290 -# define ADDCLIENTHEADER 291 -# define SETCLIENTHEADER 292 -# define APPENDCLIENTHEADER 293 -# define ADDSERVERHEADER 294 -# define SETSERVERHEADER 295 -# define APPENDSERVERHEADER 296 -# define ALLOWFROM 297 -# define DENYFROM 298 -# define ALLOWFILE 299 -# define DENYFILE 300 -# define EXTERNALHANDLER 301 -# define ONEND 302 -# define USERACCOUNT 303 -# define BYCLIENTIP 304 -# define RETRIES 305 - - -extern YYSTYPE yylval; - -#endif /* not BISON_PARSER_H */ diff --git a/src/parser.y b/src/parser.y @@ -1,1243 +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 */ -// #define PARSER_DEBUG -#ifdef PARSER_DEBUG - static void pmsg (char const *x) { - printf ("P: %s\n", x); - } - static void psmsg (char const *x, char const *y) { - printf ("P: %s %s\n", x, y); - } - static void pimsg(char const *x, int y) { - printf ("P: %s %d\n", x, y); - } -#else -# define pmsg(x) -# define psmsg(x,y) -# define pimsg(x,y) -#endif - -/* Error handler for yyparse() */ -static int yyerror (char *msg) { - error ("Parse error at line %d, '%s': %s", - yylineno + 1, yytext, 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) { - lastnr = atoi (what); -} - -/* Store an encountered 'over' number */ -static int lastovernr; -static void setlastovernr (char const *what) { - 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; - int result; - for (item = strtok (what, " "); item; item = strtok (0, " ")) { - 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; -} - -%} - -/* Declarations */ -%token SERVICE IDENTIFIER PORT NUMBER BACKEND VERBOSITY SERVER - ON OFF DISPATCHMODE ROUNDROBIN REVIVINGINTERVAL SHMKEY WEIGHT - ONSTART ONFAIL STRING BACKLOG RANDOM BYDURATION BYSIZE - BYCONNECTIONS CONNECTIONTIMEOUT MAXCONNECTIONS BYORDER TRAFFICLOG - OVER DECAY BINDTO THROUGHPUTLOG TYPE ANY HTTP - STICKYCOOKIE ADDCLIENTHEADER SETCLIENTHEADER APPENDCLIENTHEADER - ADDSERVERHEADER SETSERVERHEADER APPENDSERVERHEADER - ALLOWFROM DENYFROM ALLOWFILE DENYFILE EXTERNALHANDLER ONEND - USERACCOUNT BYCLIENTIP RETRIES - -%% -/* Config file grammar rules */ - -input: - element - input -| - element -; - -element: - service - servicename - '{' - servicestatements - '}' { - /* Verify the service description, supply defaults - * and so on. - */ - if (!cur_service.port) - error ("Service %s lacks a port", - cur_service.name); - if (!cur_service.nbackend) - error ("Service %s lacks back ends", - cur_service.name); - - if (!cur_service.shmkey) - cur_service.shmkey = cur_service.port | SHM_MASK; - - if (!cur_service.bind) - cur_service.bind = "any"; - - /* Add to the list. */ - service = xrealloc (service, ++nservice * sizeof(Service)); - service[nservice - 1] = cur_service; - memset (&cur_service, 0, sizeof(Service)); - } -; - -service: - service_expected - SERVICE -; - -servicename: - servicename_expected - IDENTIFIER { - psmsg ("service:", yytext); - cur_service.name = xstrdup(yytext); - } -; - -servicestatements: - servicestatements - servicestatement -| - servicestatement -; - -servicestatement: - servicebody_expected - servicebody -; - -servicebody: - portstatement { - pimsg ("sevice port:", $1.set[0].v.ival); - cur_service.port = $1.set[0].v.ival; - free ($1.set); - } -| - bindstatement { - psmsg ("service binding:", $1.set[0].v.sval); - cur_service.bind = $1.set[0].v.sval; - free ($1.set); - } -| - verbositystatement { - pimsg ("service verbosity:", $1.set[0].v.ival); - cur_service.verbosity = $1.set[0].v.ival; - free ($1.set); - } -| - dispatchmodestatement { - pimsg ("service dispatch mode:", $1.set[0].v.ival); - pimsg ("service dispatch over:", lastovernr); - psmsg ("service dispatch exth:", lastext); - cur_service.dispatchtype = $1.set[0].v.ival; - cur_service.dispatchover = lastovernr; - cur_service.dispatchext = lastext; - free ($1.set); - } -| - revivingintervalstatement { - pimsg ("service revival interval:", $1.set[0].v.ival); - cur_service.rev_interval = $1.set[0].v.ival; - free ($1.set); - } -| - backlogstatement { - pimsg ("service backlog:", $1.set[0].v.ival); - cur_service.backlog = $1.set[0].v.ival; - free ($1.set); - } -| - shmkeystatement { - pimsg ("service shmkey:", $1.set[0].v.ival); - cur_service.shmkey = $1.set[0].v.ival; - free ($1.set); - } -| - connectiontimeoutstatement { - pimsg ("connection timout:", $1.set[0].v.ival); - cur_service.connectiontimeout = $1.set[0].v.ival; - free ($1.set); - } -| - maxconnectionsstatement { - pimsg ("max clients in service:", $1.set[0].v.ival); - cur_service.maxconnections = $1.set[0].v.ival; - free ($1.set); - } -| - typestatement { - pimsg ("service type: ", $1.set[0].v.ival); - cur_service.type = $1.set[0].v.ival; - free ($1.set); - } -| - allowfromstatement { - psmsg ("allow from: ", $1.set[0].v.sval); - add_allowfrom ($1.set[0].v.sval); - free ($1.set); - } -| - allowfilestatement { - psmsg ("allow file: ", $1.set[0].v.sval); - cur_service.allowfile = $1.set[0].v.sval; - free ($1.set); - } -| - denyfromstatement { - psmsg ("deny from: ", $1.set[0].v.sval); - add_denyfrom ($1.set[0].v.sval); - free ($1.set); - } -| - denyfilestatement { - psmsg ("deny file: ", $1.set[0].v.sval); - cur_service.denyfile = $1.set[0].v.sval; - free ($1.set); - } -| - useraccountstatement { - psmsg ("user account: ", $1.set[0].v.sval); - setuseraccount ($1.set[0].v.sval); - free ($1.set[0].v.sval); - free ($1.set); - } -| - backendblock { - pimsg ("converting backend statements, count is", $1.n); - for (i = 0; i < $1.n; i++) - switch ($1.set[i].cf) { - case cf_portspec: - pimsg ("backend block port:", $1.set[i].v.ival); - cur_backend.port = $1.set[i].v.ival; - break; - case cf_serverspec: - psmsg ("backend block server:", $1.set[i].v.sval); - cur_backend.server = serverpart ($1.set[i].v.sval); - cur_backend.port = portpart ($1.set[i].v.sval); - free ($1.set[i].v.sval); - break; - case cf_verbosityspec: - pimsg ("backend block verbosity:", $1.set[i].v.ival); - cur_backend.verbosity = $1.set[i].v.ival; - break; - case cf_onstartspec: - psmsg ("backend block onstart:", $1.set[i].v.sval); - cur_backend.onstart = $1.set[i].v.sval; - break; - case cf_onfailspec: - psmsg ("backend block onfail:", $1.set[i].v.sval); - cur_backend.onfail = $1.set[i].v.sval; - break; - case cf_onendspec: - psmsg ("backend block onend:", $1.set[i].v.sval); - cur_backend.onend = $1.set[i].v.sval; - break; - case cf_dumpspec: - psmsg ("backend trafficlog:", $1.set[i].v.sval); - cur_backend.dumpfile = $1.set[i].v.sval; - break; - case cf_thruspec: - psmsg ("backend throughputlog:", $1.set[i].v.sval); - cur_backend.thruputfile = $1.set[i].v.sval; - break; - case cf_weightspec: - pimsg ("backend weight:", $1.set[i].v.ival); - cur_backend.weight = $1.set[i].v.ival; - break; - case cf_decayspec: - pimsg ("backend decay:", $1.set[i].v.ival); - if ($1.set[i].v.ival >= 100) - error ("Decay specifier %d must be a percentage, " - "never more than 99", - $1.set[i].v.ival); - cur_backend.decay = $1.set[i].v.ival; - break; - case cf_maxconnectionsspec: - pimsg ("backend max clients: ", $1.set[i].v.ival); - cur_backend.maxconnections = $1.set[i].v.ival; - break; - case cf_stickycookiespec: - psmsg ("backend sticky cookie:", - $1.set[i].v.sval); - cur_backend.stickycookie = $1.set[i].v.sval; - break; - case cf_addclientheaderspec: - psmsg ("client header to add:", - $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: - psmsg ("client header to set:", - $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: - psmsg ("client header to append:", - $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: - psmsg ("server header to add:", - $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: - psmsg ("server header to set:", - $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: - psmsg ("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: - pimsg ("backend retries:", $1.set[i].v.ival); - cur_backend.retries = $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_service.port) - error ("Back end %s lacks port", - cur_service.port); - if (cur_backend.weight < 1) - cur_backend.weight = 1; - if (cur_backend.retries < 1) - cur_backend.retries = 1; - if (! cur_backend.onstart) - cur_backend.onstart = xstrdup (""); - if (! cur_backend.onfail) - cur_backend.onfail = xstrdup (""); - if (! cur_backend.onend) - cur_backend.onend = xstrdup (""); - if (! cur_backend.thruputfile) - cur_backend.thruputfile = xstrdup (""); - if (! cur_backend.dumpfile) - cur_backend.dumpfile = xstrdup (""); - if (! cur_backend.stickycookie) - cur_backend.stickycookie = xstrdup (""); - - /* Add to the list. */ - cur_service.backend = xrealloc (cur_service.backend, - ++cur_service.nbackend * - sizeof(Backend)); - cur_service.backend[cur_service.nbackend - 1] = - cur_backend; - pimsg ("this was backend defintion", cur_service.nbackend); - memset (&cur_backend, 0, sizeof(cur_backend)); - } -; - -portstatement: - PORT - number - semicol { - pimsg ("port statement:", lastnr); - $$.n = 1; - $$.set = xmalloc (sizeof(Confset)); - $$.set[0].cf = cf_portspec; - $$.set[0].v.ival = lastnr; - } -; - -bindstatement: - BINDTO - ipaddress - semicol { - psmsg ("bindto statement:", laststr); - $$.n = 1; - $$.set = xmalloc (sizeof(Confset)); - $$.set[0].cf = cf_bindspec; - $$.set[0].v.sval = xstrdup(laststr); - } -; - -ipaddress: - ipaddress_expected - STRING { - setlaststr (laststring); - free (laststring); - laststring = 0; - } -; - -number: - number_expected - NUMBER { - setlastnr (yytext); - } -; - -semicol: - semicol_expected - ';' -; - -verbositystatement: - VERBOSITY - onoff_expected - onoff - semicol { - pimsg ("verbosity statement:", 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 */ -; - -dispatchover: - OVER - overnumber { - pimsg ("dispatch mode statement:", lastnr); - $$.n = 1; - $$.set = xmalloc (sizeof(Confset)); - $$.set[0].cf = cf_dispatchspec; - $$.set[0].v.ival = lastnr; - - if (lastovernr && - (lastnr != ds_bysize && lastnr != ds_byduration)) - error ("Service '%s': this dispatch mode " - "doesn't support 'over <connections>'", - cur_service.name); - } -; - -overnumber: - number_expected - NUMBER { - setlastovernr (yytext); - } -; - -dispatchext: - commandline { - psmsg ("external handler:", 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 { - pimsg ("user account statement:", 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 - semicol { - pimsg ("reviving interval statement:", lastnr); - $$.n = 1; - $$.set = xmalloc (sizeof(Confset)); - $$.set[0].cf = cf_revivespec; - $$.set[0].v.ival = lastnr; - } -; - -backlogstatement: - BACKLOG - number - semicol { - pimsg ("backlog statement:", lastnr); - $$.n = 1; - $$.set = xmalloc (sizeof(Confset)); - $$.set[0].cf = cf_revivespec; - $$.set[0].v.ival = lastnr; - } -; - -shmkeystatement: - SHMKEY - number - semicol { - pimsg ("shmkey statement:", lastnr); - $$.n = 1; - $$.set = xmalloc (sizeof(Confset)); - $$.set[0].cf = cf_shmkeyspec; - $$.set[0].v.ival = lastnr; - } -; - -connectiontimeoutstatement: - CONNECTIONTIMEOUT - number - semicol { - pimsg ("connection timeout statement:", lastnr); - $$.n = 1; - $$.set = xmalloc (sizeof(Confset)); - $$.set[0].cf = cf_connectiontimeoutspec; - $$.set[0].v.ival = lastnr; - } -; - -maxconnectionsstatement: - MAXCONNECTIONS - number - semicol { - pimsg ("max clients statement (service):", lastnr); - $$.n = 1; - $$.set = xmalloc (sizeof(Confset)); - $$.set[0].cf = cf_maxconnectionsspec; - $$.set[0].v.ival = lastnr; - } -; - -typestatement: - TYPE - typespec - semicol { - pimsg ("service type:", 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; - } -; - -allowfromstatement: - ALLOWFROM - ipfilters - semicol { - psmsg ("allow from: ", laststr); - $$.n = 1; - $$.set = xmalloc (sizeof(Confset)); - $$.set[0].cf = cf_allowfromspec; - $$.set[0].v.sval = xstrdup(laststr); - } -; - -denyfromstatement: - DENYFROM - ipfilters - semicol { - psmsg ("allow from: ", laststr); - $$.n = 1; - $$.set = xmalloc (sizeof(Confset)); - $$.set[0].cf = cf_denyfromspec; - $$.set[0].v.sval = xstrdup(laststr); - } -; - -allowfilestatement: - ALLOWFILE - filename - semicol { - psmsg ("allow file: ", laststr); - $$.n = 1; - $$.set = xmalloc (sizeof(Confset)); - $$.set[0].cf = cf_allowfilespec; - $$.set[0].v.sval = xstrdup(laststr); - } -; - -denyfilestatement: - DENYFILE - filename - semicol { - psmsg ("allow file: ", 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 - '{' - backenddefinitions - '}' { - $$ = $4; - } -; - -backendname: - backendname_expected - IDENTIFIER { - psmsg ("backend name:", yytext); - cur_backend.name = xstrdup (yytext); - } -; - -backenddefinitions: - backenddefinitions - backenddefinition { - $1.n++; - $1.set = xrealloc ($1.set, $1.n * sizeof(Confset)); - $1.set[$1.n - 1] = $2.set[0]; - $$ = $1; - } -| - backenddefinition { - $$ = $1; - } -; - -backenddefinition: - backendstatement_expected - backendstatement { - $$ = $2; - } -; - -backendstatement: - serverstatement { - psmsg ("backend server:", $1.set[0].v.sval); - $$ = $1; - } -| - portstatement { - pimsg ("backend port:", $1.set[0].v.ival); - $$ = $1; - } -| - verbositystatement { - pimsg ("backend verbosity:", $1.set[0].v.ival); - $$ = $1; - } -| - onstartstatement { - psmsg ("backend onstart:", $1.set[0].v.sval); - $$ = $1; - } -| - onendstatement { - psmsg ("backend onend:", $1.set[0].v.sval); - $$ = $1; - } -| - onfailstatement { - psmsg ("backend onfail:", $1.set[0].v.sval); - $$ = $1; - } -| - dumptrafficstatement { - psmsg ("backend trafficlog:", $1.set[0].v.sval); - $$ = $1; - } -| - throughputstatement { - psmsg ("backend trafficlog:", $1.set[0].v.sval); - $$ = $1; - } -| - weightstatement { - pimsg ("backend weight:", $1.set[0].v.ival); - $$ = $1; - } -| - decaystatement { - pimsg ("backend decay:", $1.set[0].v.ival); - $$ = $1; - } -| - maxconnectionsstatement { - pimsg ("backend maxconnections:", $1.set[0].v.ival); - $$ = $1; - } -| - stickycookiestatement { - psmsg ("backend sticky cookie:", $1.set[0].v.sval); - $$ = $1; - } -| - addclientheaderstatement { - psmsg ("addclientheader:", $1.set[0].v.sval); - $$ = $1; - } -| - setclientheaderstatement { - psmsg ("setclientheader:", $1.set[0].v.sval); - $$ = $1; - } -| - appendclientheaderstatement { - psmsg ("appendclientheader:", $1.set[0].v.sval); - $$ = $1; - } -| - addserverheaderstatement { - psmsg ("addserverheader:", $1.set[0].v.sval); - $$ = $1; - } -| - setserverheaderstatement { - psmsg ("setserverheader:", $1.set[0].v.sval); - $$ = $1; - } -| - appendserverheaderstatement { - psmsg ("appendserverheader:", $1.set[0].v.sval); - $$ = $1; - } -| - retriesstatement { - pimsg ("backend retries:", $1.set[0].v.ival); - $$ = $1; - } -; - -serverstatement: - SERVER - serveraddress_expected - serveraddress - semicol { - psmsg ("server statement:", laststr); - $$.n = 1; - $$.set = xmalloc (sizeof (Confset)); - $$.set[0].cf = cf_serverspec; - $$.set[0].v.sval = xstrdup (laststr); - } -; - -weightstatement: - WEIGHT - number - semicol { - pimsg ("weight statement", lastnr); - $$.n = 1; - $$.set = xmalloc (sizeof (Confset)); - $$.set[0].cf = cf_weightspec; - $$.set[0].v.ival = lastnr; - } -; - -decaystatement: - DECAY - number - semicol { - pimsg ("decay statement", 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 { - pimsg ("retries:", lastnr); - $$.n = 1; - $$.set = xmalloc (sizeof(Confset)); - $$.set[0].cf = cf_retriesspec; - $$.set[0].v.ival = lastnr; - } -; - -onstartstatement: - ONSTART - commandline - semicol { - psmsg ("onstart statement:", laststr); - $$.n = 1; - $$.set = xmalloc (sizeof (Confset)); - $$.set[0].cf = cf_onstartspec; - $$.set[0].v.sval = xstrdup (laststr); - } -; - -onfailstatement: - ONFAIL - commandline - semicol { - psmsg ("onfail statement:", laststr); - $$.n = 1; - $$.set = xmalloc (sizeof (Confset)); - $$.set[0].cf = cf_onfailspec; - $$.set[0].v.sval = xstrdup (laststr); - } -; - -onendstatement: - ONEND - commandline - semicol { - psmsg ("onend statement:", laststr); - $$.n = 1; - $$.set = xmalloc (sizeof (Confset)); - $$.set[0].cf = cf_onendspec; - $$.set[0].v.sval = xstrdup (laststr); - } -; - -dumptrafficstatement: - TRAFFICLOG - filename - semicol { - psmsg ("trafficlog statement:", laststr); - $$.n = 1; - $$.set = xmalloc (sizeof (Confset)); - $$.set[0].cf = cf_dumpspec; - $$.set[0].v.sval = xstrdup (laststr); - } -; - -throughputstatement: - THROUGHPUTLOG - filename - semicol { - psmsg ("throughputlog statement:", laststr); - $$.n = 1; - $$.set = xmalloc (sizeof (Confset)); - $$.set[0].cf = cf_thruspec; - $$.set[0].v.sval = xstrdup (laststr); - } -; - -commandline: - commandline_expected - STRING { - setlaststr (laststring); - free (laststring); - laststring = 0; - } -; - -filename: - filename_expected - STRING { - setlaststr (laststring); - free (laststring); - laststring = 0; - } -; - -stickycookiestatement: - STICKYCOOKIE - cookiespecifier - semicol { - psmsg ("insertcookie statement:", laststr); - $$.n = 1; - $$.set = xmalloc (sizeof (Confset)); - $$.set[0].cf = cf_stickycookiespec; - $$.set[0].v.sval = xstrdup (laststr); - } -; - -cookiespecifier: - cookie_expected - STRING { - setlaststr (laststring); - free (laststring); - laststring = 0; - } -; - -addclientheaderstatement: - ADDCLIENTHEADER - headerstring - semicol { - psmsg ("addclientheader statement:", laststr); - $$.n = 1; - $$.set = xmalloc (sizeof(Confset)); - $$.set[0].cf = cf_addclientheaderspec; - $$.set[0].v.sval = xstrdup (laststr); - } -; - -setclientheaderstatement: - SETCLIENTHEADER - headerstring - semicol { - psmsg ("setclientheader statement:", laststr); - $$.n = 1; - $$.set = xmalloc (sizeof(Confset)); - $$.set[0].cf = cf_setclientheaderspec; - $$.set[0].v.sval = xstrdup (laststr); - } -; - -appendclientheaderstatement: - APPENDCLIENTHEADER - headerstring - semicol { - psmsg ("appendclientheader statement:", laststr); - $$.n = 1; - $$.set = xmalloc (sizeof(Confset)); - $$.set[0].cf = cf_appendclientheaderspec; - $$.set[0].v.sval = xstrdup (laststr); - } -; - -addserverheaderstatement: - ADDSERVERHEADER - headerstring - semicol { - psmsg ("addserverheader statement:", laststr); - $$.n = 1; - $$.set = xmalloc (sizeof(Confset)); - $$.set[0].cf = cf_addserverheaderspec; - $$.set[0].v.sval = xstrdup (laststr); - } -; - -setserverheaderstatement: - SETSERVERHEADER - headerstring - semicol { - psmsg ("setserverheader statement:", laststr); - $$.n = 1; - $$.set = xmalloc (sizeof(Confset)); - $$.set[0].cf = cf_setserverheaderspec; - $$.set[0].v.sval = xstrdup (laststr); - } -; - -appendserverheaderstatement: - APPENDSERVERHEADER - headerstring - semicol { - psmsg ("appendserverheader statement:", 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 or 'any' expected"; -} -; - -type_expected: { - yyerrmsg = "Service type expected ('any', 'stickyhttp', ...)"; -} -; - -ipfilters_expected: { - yyerrmsg = "IP filter(s) expected"; -} -; - -useraccount_expected: { - yyerrmsg = "username expected"; -} -; diff --git a/src/restart.c b/src/restart.c @@ -1,24 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 restart (int ac, char **av) { - - create_commandline_space(); - - /* First run the 'stop' action. */ - if (!stop_daemon (ac, av)) - error ("Daemon stop failed, restart failure"); - - sleep (1); - - /* Now run 'start' */ - if (!serve (ac, av)) - error ("Daemon start failed, restart failure"); - - /* All ok.. */ - return (1); -} diff --git a/src/runservice.c b/src/runservice.c @@ -1,122 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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; - - msg ("Service %s (on port %d): STARTING", - activeservice->name, activeservice->port); - - /* 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 ("Service %s: fork failure: %s", - activeservice->name, strerror(errno)); - } else if (pid) { - /* Parent branch */ - msg ("Service %s: detached as PID %d", - activeservice->name, pid); - return; - } - - /* Child branch */ - set_program_title ("Service %s: listening", activeservice->name); - close (0); - close (1); - close (2); - daemonized++; - if ( (open ("/dev/null", O_RDONLY) < 0) || - (open ("/dev/null", O_WRONLY) < 0) || - (open ("/dev/null", O_WRONLY) < 0) ) - error ("Service %s: " - "failed to reopen stdin/out/err on /dev/null", - activeservice->name); - if (setsid() < 0) - error ("Service %s: failed to become seesion leader", - activeservice->name); - - /* Promote verbosity. */ - flag_verbose = activeservice->verbosity; - - /* We've forked for the first time */ - program_stage = stage_waiting; - - /* 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 ("Service %s: taking a nap...", activeservice->name); - sleep (SLEEP_TIME); - continue; - } - - /* We have (at least) one back end. Let's run the service. - * Create the socket, bind to port. */ - if ( (listen_sock = make_socket (activeservice->port, - activeservice->bind)) < 0 ) { - if (!sloppyportbind) - error ("Service %s: failed to listen to port %d: %s", - activeservice->name, activeservice->port, - strerror(errno)); - warning ("Service %s: " - "listening socket creation failed.. will retry", - activeservice->name); - - /* We wait here for some time, to let the system regain - * equilibrium. Something's really afoot, so let's not retry - * right away. */ - sleep (SLEEP_TIME); - - continue; - } - - msg ("Service %s: server-side network socket: %d", - activeservice->name, listen_sock); - - /* Zero out the stats for first usage. */ - if (first_serving) { - first_serving = 0; - memset (servicereport, 0, sizeof(Servicereport)); - /* Store our pid, so that 'crossroads stop' may kill us. */ - lock_reporter(); - servicereport->pid = getpid(); - unlock_reporter(); - } - - /* Start serving the port! */ - tcpserve (listen_sock); - - /* tcpserve() returned -- must be because this service is out - * of back ends */ - if (shutdown (listen_sock, SHUT_RDWR)) - warning ("Service %s: " - "failed to shut down server-side socket %d: %s", - activeservice->name, listen_sock, strerror(errno)); - if (close (listen_sock)) - warning ("Service %s: " - "failed to close server-side socket %d: %s", - activeservice->name, listen_sock, strerror(errno)); - } -} diff --git a/src/serve.c b/src/serve.c @@ -1,21 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 serve (int ac, char **av) { - int i; - - msg ("Starting services"); - - create_commandline_space(); - - for (i = 0; i < nservice; i++) { - /* Start the service. */ - activeservice = service + i; - runservice (); - } - return (1); -} diff --git a/src/setprogramtitle.c b/src/setprogramtitle.c @@ -1,42 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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, ...) { -# if SET_PROC_TITLE_BY_ARGV == 1 - - static int orglen; - char *title, *name = "crossroads"; - int i, j, k; - va_list args; - - /* Make the title */ - va_start (args, fmt); - title = str_vprintf (fmt, args); - va_end (args); - - /* Reset old argv, count max length */ - if (! orglen) - for (i = 0; i < org_argc; i++) - orglen += (strlen(org_argv[i]) + 1); - - /* Paste in our program name first */ - for (i = 0; i <= (int) strlen(name) && i < orglen; i++) - org_argv[0][i] = name[i]; - - /* Paste in the new title */ - for (j = 0; j < (int) strlen(title) && i + j < orglen; j++) - org_argv[0][i + j] = title[j]; - - /* Reset remainder of old cmd line */ - for (k = i + j; k < orglen; k++) - org_argv[0][k] = 0; - - /* Free up */ - free (title); - -# endif /* SET_PROC_TITLE_BY_ARGV */ -} diff --git a/src/showconfig.c b/src/showconfig.c @@ -1,38 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, a load balancer and fail over - * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL. - * Visit http://crossroads.e-tunity.com for information. - *************************************************************************/ - -#include "crossroads.h" - -#define SHOWDEF(a,b,c) \ - printf ("%-22s %-31s %s \n", b, c, a ? "yes" : "no"); - -void show_config () { - printf ("VER version: %s\n" - "REVVER revision version (REVVER): %s\n" - "DEFAULT_CONF default configuration file: %s\n" - "MAX_BACKEND max nr. of backends in service: %d\n" - "SHM_MASK magic shared memory number: 0x%x\n" - "SLEEP_TIME service inactivy pause %d\n" - "CONNECT_TIMEOUT backend connect timeout %d\n" - "RETRY_WAIT backend retry pause %d\n" - "TCP_BUFSZ network buffer size %d\n" - "BINDIR installation directory %s\n" - "SET_PROC_TITLE_BY_ARGV argv assumed linear array %d\n" - "EXTRALIBS extra library dependencies %s\n" - "LIBS standard library dependencies %s\n" - , - VER, REVVER, DEFAULT_CONF, MAX_BACKEND, SHM_MASK, SLEEP_TIME, - CONNECT_TIMEOUT, RETRY_WAIT, TCP_BUFSZ, BINDIR, - SET_PROC_TITLE_BY_ARGV, EXTRALIBS, LIBS); - SHOWDEF (HAVE_MALLOC_H, "HAVE_MALLOC_H", "<malloc.h> present"); - SHOWDEF (HAVE_STDINT_H, "HAVE_STDINT_H", "<stdint.h> present"); - SHOWDEF (HAVE_FLOCK, "HAVE_FLOCK", "flock() present"); - SHOWDEF (HAVE_LOCKF, "HAVE_LOCKF", "lockf() present"); - SHOWDEF (HAVE_STRLCAT, "HAVE_STRLCAT", "strlcat() present"); - SHOWDEF (HAVE_SRANDDEV, "HAVE_SRANDDEV", "sranddev() present"); - SHOWDEF (HAVE_VSYSLOG, "HAVE_VSYSLOG", "vsyslog() present"); - SHOWDEF (HAVE_STRCASESTR, "HAVE_STRCASESTR", "strcasestr() present"); -} diff --git a/src/showservices.c b/src/showservices.c @@ -1,25 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 show_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].server, - service[i].backend[j].port); - } - return (1); -} diff --git a/src/showstatus.c b/src/showstatus.c @@ -1,111 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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); - 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 show_status (int ac, char **av) { - int i, j, services_shown = 0; - - for (i = 0; i < nservice; i++) { - if (ac > 1 && strcmp (service[i].name, av[0])) - continue; - if (services_shown++) - putchar ('\n'); - alloc_reporter (service + i, 0); - msg ("Reporting service %s (pid = %d)", - service[i].name, servicereport->pid); - if (tabular_status) - printf ("%s ", service[i].name); - else - printf ("Service : %s, %d live connections, " - "last backend %d\n", - service[i].name, servicereport->nclients, - servicereport->last_backend); - for (j = 0; j < service[i].nbackend; j++) { - if (ac > 2 && strcmp (service[i].backend[j].name, av[1])) - continue; - if (tabular_status) - printf ("%s=%s ", service[i].backend[j].name, - state_to_string(servicereport->backendstate[j].avail)); - 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].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)); - putchar ('\n'); - } - } - - if (shmdt (servicereport) < 0) - error ("Failure releasing reporter memory: %s", - strerror(errno)); - } - if (tabular_status) - putchar ('\n'); - - return (1); -} diff --git a/src/stagetostring.c b/src/stagetostring.c @@ -1,21 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/statetostring.c b/src/statetostring.c @@ -1,16 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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-STATE"); -} diff --git a/src/stopdaemon.c b/src/stopdaemon.c @@ -1,35 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 stop_daemon (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 anyeay, 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/strcasestr.c b/src/strcasestr.c @@ -1,25 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 (big); - if (!big || !*big) - return (0); - - bcopy = strupr (xstrdup (big)); - lcopy = strupr (xstrdup (little)); - if ( (res = strstr (big, little)) ) - res = big + (res - bcopy); - free (bcopy); - free (lcopy); - return (res); -} -#endif diff --git a/src/strexpandformat.c b/src/strexpandformat.c @@ -1,105 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 target_backend) { - static char buf[80]; - char *ret; - - /* 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 - * %n - nr of clients of current back end, %1n = first back end etc. - * %r - client IP - * %s - name of service - * %t, %T - timestamp of local or GMT time - * %v - Crossroads version - * %w - weight of current back end, %1w = first back end etc. - */ - - *skip = 1; - switch (*s) { - - case 'a': - if (backend_available (target_backend)) - return ("1"); - return ("0"); - - case 'b': - if (target_backend >= 0 && target_backend < activeservice->nbackend) - return (activeservice->backend[target_backend].name); - return ("noname"); - - case 'e': - snprintf (buf, sizeof(buf) - 1, "%u", (unsigned) time(0)); - return (buf); - - case 'n': - if (target_backend >= 0 && target_backend < activeservice->nbackend) { - snprintf (buf, sizeof(buf) - 1, "%u", - (unsigned) - servicereport->backendstate[target_backend].nclients); - return (buf); - } - return ("0"); - - 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)); - - case 'T': - return (ansistamp (tm_gmtime)); - - case 'v': - return (VER); - - case 'w': - if (target_backend >= 0 && target_backend < activeservice->nbackend) { - snprintf (buf, sizeof(buf) - 1, "%u", - (unsigned) - activeservice->backend[target_backend].weight); - return (buf); - } - return ("0"); - - default: - if (isdigit (*s)) { - ret = fmt_expand (s + 1, skip, *s - '0' - 1); - *skip += 1; - return (ret); - } else { - *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 == '%') { - ret = xstrcat (ret, fmt_expand (cp + 1, &skip, current_backend)); - cp += skip; - } else { - ret = xstrcatch (ret, *cp); - } - } - - return (ret); -} diff --git a/src/stringtostate.c b/src/stringtostate.c @@ -1,16 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/strlcat.c b/src/strlcat.c @@ -1,30 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/strprintf.c b/src/strprintf.c @@ -1,13 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/strvprintf.c b/src/strvprintf.c @@ -1,32 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/sysrun.c b/src/sysrun.c @@ -1,24 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 sysrun (char const *cmd) { - char *expanded; - int ret; - - if (!cmd || ! *cmd) - return; - - expanded = str_expand_format (cmd); - msg ("Service %s: running command: '%s'", activeservice->name, expanded); - uid_assume(); - if ( (ret = system (expanded)) ) - warning ("Service %s: command '%s' -> '%s' returned %d", - activeservice->name, cmd, expanded, ret); - uid_restore(); - free (expanded); -} diff --git a/src/tcpserve.c b/src/tcpserve.c @@ -1,170 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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, backend_selected; - 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) { - if ( (pid = fork()) < 0 ) - error ("Fork failed: %s", strerror(errno)); - else if (!pid) { - set_program_title ("Service %s: wakeup", activeservice->name); - wakeup_handler(); - } else { - msg ("Service %s: started wakeup handler at pid %d", - activeservice->name, pid); - servicereport->rev_pid = pid; - } - } - } - - msg ("Service %s: awaiting activity on port %d (socket fd %d)", - activeservice->name, activeservice->port, server_sock); - - if (listen (server_sock, activeservice->backlog + 1) < 0) - error ("Service %s: failed to listen to server_socket: %s", - activeservice->name, 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 ("Service %s: allow chain has %d entries, " - "deny chain has %d entries", activeservice->name, - activeservice->nallowchain, activeservice->ndenychain); - } - - /* Block until we get a connection. */ - FD_ZERO (&set); - FD_SET (server_sock, &set); - if (select (FD_SETSIZE, &set, 0, 0, 0) < 0) { - msg ("Service %s: interrupt while waiting for activity: %d (%s)", - activeservice->name, 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 ("Service %s: failure while accepting on " - "server socket: %s", activeservice->name, - strerror(errno)); - continue; - } - - /* Store client IP, it's used for lots of logging. */ - client_ip = inet_ntoa (clientname.sin_addr); - msg ("Service %s: connection from %s, socket %d", - activeservice->name, client_ip, new); - if (ipf_denied ()) { - warning ("Service %s: %s matches deny list, " - "terminating connection", activeservice->name, client_ip); - close (new); - continue; - } - if (!ipf_allowed ()) { - warning ("Service %s: %s failes to match allow list, " - "terminating connection", activeservice->name, client_ip); - close (new); - continue; - } - - /* Backend yet to be defined. */ - current_backend = -1; - - /* Incase of a http type service: handle separately. */ - if (activeservice->type == type_http) { - http_serve (new); - close (new); - continue; - } - - /* This is an 'any' service type. - * 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. - */ - if (! backend_count()) { - warning ("Service %s: no back ends available", - activeservice->name); - close (new); - return; - } - - /* Retry back ends until we succeed. */ - backend_selected = 0; - while (!backend_selected) { - msg ("Service %s: About to choose a back end", - activeservice->name); - choose_backend(); - if (current_backend < 0) { - /* No back ends available now. NOTE: we return so that - * runservice() will retry in some time. */ - close (new); - return; - } - - /* 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 return after all. */ - msg ("Service %s: trying back end %s, port %d", - activeservice->name, - activeservice->backend[current_backend].server, - activeservice->backend[current_backend].port); - if ( (backend_sock = backend_connect()) < 0 ) { - warning ("Service %s: failed to connect to server %s:%d " - "(ret %d)", activeservice->name, - activeservice->backend[current_backend].server, - activeservice->backend[current_backend].port, - backend_sock); - continue; - } - - /* Got a live one! */ - backend_selected++; - if (fork_tcp_servicer (current_backend)) { - /* We're the parent branch here. Close sockets so that - * we don't run out of file descriptors, and loop into - * the next select/accept run. */ - close (new); - close (backend_sock); - } else { - /* 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); - } - } - } -} diff --git a/src/tellservice.c b/src/tellservice.c @@ -1,43 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 tell_service (int ac, char **av) { - Service *target_service = 0; - int target_backend = -1, i; - Backendavail avail; - - - 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]); - - 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]); - - if ( (avail = string_to_state (av[2])) == st_unknown ) - error ("Incorrect state '%s'.", av[2]); - - alloc_reporter (target_service, 0); - servicereport->backendstate[target_backend].avail = avail; - servicereport->backendstate[target_backend].fail = 0; - msg ("Marked backend %s of service %s as %s.", - av[1], av[0], av[2]); - return (1); -} - diff --git a/src/thruputlog.c b/src/thruputlog.c @@ -1,64 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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) { - struct timeval tv; - 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) { - if (gettimeofday (&tv, 0)) - error ("Failed to get the time of day: %s\n", - strerror(errno)); - d_start = tv.tv_sec * 1000000 + tv.tv_usec; - } - if (gettimeofday (&tv, 0)) - error ("Failed to get the time of day: %s\n", strerror(errno)); - d_now = tv.tv_sec * 1000000 + tv.tv_usec; - - /* 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 ", - getpid(), - (d_now - d_start) / 1000000, - dir == dir_client_to_server ? 'C' : 'B'); - 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/trafficlog.c b/src/trafficlog.c @@ -1,66 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/uidassume.c b/src/uidassume.c @@ -1,28 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 ("Service %s: cannot set effective gid to %d: %s", - activeservice->name, activeservice->gid, - strerror(errno)); - gid_set++; - } - uid_org = getuid(); - if (seteuid (activeservice->uid)) - error ("Service %s: cannot set effective uid to %d: %s", - activeservice->name, activeservice->uid, strerror(errno)); - uid_set++; - } -} diff --git a/src/uidrestore.c b/src/uidrestore.c @@ -1,13 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/unlockreporter.c b/src/unlockreporter.c @@ -1,26 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/usage.c b/src/usage.c @@ -1,13 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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, DEFAULT_CONF); - exit (1); -} diff --git a/src/usage.txt b/src/usage.txt @@ -1,35 +0,0 @@ -This is Crossroads %s, a load balancer and fail-over utility for TCP. -Copyright (c) Karel Kubat / e-tunity 2005/2006 ff. All rights reserved. -For information, contact <info@e-tunity.com> or see <http://www.e-tunity.com>. -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 STATE: mark the named - BACKEND of the SERVICE with the STATE ('available/up', 'unavailable' - or 'down'). Use the action 'services' to determine SERVICE and - BACKEND names. - ** 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 - -C: shows compile-time configuration and stops - -c CONFIG: Uses the named configuration, instead of the default - %s - -l FAC: Specifies the openlog(3) facility to use when - logging. Default is LOG_DAEMON. Allowed values are 0..7 - for LOG_LOCAL0 to LOG_LOCAL7. - -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 - -v: Enables verbosity upon startup. Other verbosity (services - and back ends) is controlled in the configuration. - -V: Shows the version ID and stops. - -?, -h: Shows this message. diff --git a/src/vsyslog.c b/src/vsyslog.c @@ -1,16 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/wakeuphandler.c b/src/wakeuphandler.c @@ -1,56 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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 wakeup_handler () { - int sock, i; - - /* 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. */ - sleep (activeservice->rev_interval); - - /* Now do our stuff. */ - for (current_backend = 0; - current_backend < activeservice->nbackend; - current_backend++) { - - /* Only loop through unavailable back ends. */ - if (servicereport->backendstate[current_backend].avail != - st_unavailable) - continue; - - /* Mark state as WAKING */ - lock_reporter(); - servicereport->backendstate[current_backend].avail = st_waking; - unlock_reporter(); - - /* Try to TCP connect */ - sock = backend_connect(); - - /* Set state accordingly */ - if (sock >= 0) { - close (sock); - warning ("Backend %s of service %s has woken up", - activeservice->backend[current_backend].name, - activeservice->name); - } - lock_reporter(); - servicereport->backendstate[current_backend].avail = - sock >= 0 ? st_available : st_unavailable; - servicereport->backendstate[current_backend].fail = 0; - unlock_reporter(); - } - } -} diff --git a/src/warning.c b/src/warning.c @@ -1,23 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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) - fprintf (stderr, "WARNING: %s\n", str); - else - writelog (LOG_ERR, "WARNING: %s", str); - free (str); -} diff --git a/src/writelog.c b/src/writelog.c @@ -1,15 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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, log_facility); - vsyslog (prio, fmt, args); -} diff --git a/src/xmalloc.c b/src/xmalloc.c @@ -1,10 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/xrealloc.c b/src/xrealloc.c @@ -1,27 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/xstrcat.c b/src/xstrcat.c @@ -1,19 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/xstrcatch.c b/src/xstrcatch.c @@ -1,14 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/xstrdup.c b/src/xstrdup.c @@ -1,16 +0,0 @@ -/************************************************************************* - * This file is part of Crosroads 1.39, 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/tools/gettools b/tools/gettools @@ -2,13 +2,17 @@ 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 = "../tools/$f"; + $dst = "$base/../tools/$f"; if (! -f $dst or (stat($src))[9] > (stat($dst))[9]) {