commit ef4ca38c2c1690a176c16ad85b07087adda25611
parent b0e25a43f1b1e512bd14012439d987f2f65c48c7
Author: finwo <finwo@pm.me>
Date: Sat, 3 Jan 2026 19:31:35 +0100
1.40
Diffstat:
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: (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'. (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 (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\" %>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 <<"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");
+}
+</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>
+<?xml version="1.0" encoding="UTF-8"?>
+<status>
+ <service id="1" name="smtp">
+ <connections>1</connections>
+ <lastbackend>0</lastbackend>
+ <backend id="0" name="first">
+ <availability id="0">available</availability>
+ <clients>0</clients>
+ <failures>0</failures>
+ <connections>2</connections>
+ <duration sec="0.559882">0.56s</duration>
+ <throughput bytes="3564">3.48Kb</throughput>
+ </backend>
+ <backend id="1" name="second">
+ <availability id="0">available</availability>
+ <clients>0</clients>
+ <failures>0</failures>
+ <connections>2</connections>
+ <duration sec="23.7636">23.76s</duration>
+ <throughput bytes="9055">8.84Kb</throughput>
+ </backend>
+ </service>
+</status>
+</pre>
+
+<p>
+A custom-made XSLT transformation stylesheet can be used to convert
+this to any output format - and also to HTML. Such a style sheet is
+included in the Crossroads distribution as
+<code>etc/xml-status-to-html.xslt</code>. The sheet is lengthy, and is
+therefore not included in this document. (You're welcome to modify it
+to suit your specific needs. If you have cool tips, send them along to
+me and I'll include them in the next distribution!)
+<p>
+If you want to show this output in a webpage which is generated on
+demand by a webserver, then you might run into the following
+problem. The status reporter (<code>crossroads -x status</code>)
+ must be able to access the shared memory segment of the running
+Crossroads instance. By default, the shared memory is protected for
+the user that started Crossroads, which will often not be the user who
+runs the webserver. Under the auspices of the webserver user,
+<code>crossroads status</code> might abort with a message: "ERROR: Cannot get
+shared memory for service <em>name</em>, key <em>number</em>: Permission denied."
+<p>
+The solution for this problem is to make the shared memory access
+somewhat more liberal. There are basically two options:
+<p>
+<ul>
+ <li> Start Crossroads with the flag <code>-m 0666</code>, which makes
+ the shared memory segment available to all. The octal number
+ 0666 works just like a file permission setting under
+ Unix. Now, any user can run <code>crossroads status</code>.
+<p>
+<li> If you want to make the access to Crossroads' shared
+ memory somewhat stricter, then make the user who starts
+ Crossroads and the user who runs the webserver member of a new
+ Unix group. Start Crossroads with the flag <code>-m 0664</code>. Now,
+ users belonging to the same group as the Crossroads starter
+ can run <code>crossroads status</code>.</ul>
+<p>
+<a name="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]) {