commit 74ff0e3e4cc89d484a9c98aeda1b2e2380e64091
parent 5c6aaa5c2c76faffd499a2aa7fb6d31988d16a45
Author: finwo <finwo@pm.me>
Date: Sat, 3 Jan 2026 19:11:51 +0100
1.15
Diffstat:
32 files changed, 5577 insertions(+), 588 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -1,6 +1,23 @@
ChangeLog for Crossroads
------------------------------------------------------------------------------
+1.15 [KK 2006-10-23] Speedup in the handling of chunked HTTP message
+ transfer. Furthermore, chunked messages are treated as
+ single-shot actions (see RFC2616, liberally explained by yours
+ truly).
+ [KK 2006-11-01] Bison- and flex-generated files are no longer
+ removed in 'make clean'. This helps folks who want to build
+ Crossroads but don't have these tools.
+ Version 1.15 marked as 'stable'.
+
+1.14 [KK 2006-10-19] Bugfix in chunked transfer encoding (yeah I
+ know.. yet again.. hopefully the last time). This was a
+ particularly nasty one.
+
+1.13 [KK 2006-09-26] Next development release.
+ [KK 2006-10-03] Porting issues for Solaris 9: localtime() issues
+ fixed, cp/strip used instead of install -s, ctype.h macro's avoided.
+
1.12 [KK 2006-09-13] Small changes in wakeup handler. Timeout handling
in HTTP service processing slightly changed.
[KK 2006-09-15] Added checks whether both client and server want
diff --git a/doc/compiling.yo b/doc/compiling.yo
@@ -8,13 +8,10 @@ itemization(
it() A POSIX-compliant C compiler;
- it() The grammar generation tools tt(bison) and tt(flex);
-
it() Support for SYSV IPC, networking and so on.
)
-Basically a Linux or Apple MacOSX box will do nicely once you make
-sure that tt(bison) and tt(flex) are installed. To compile and install
+Basically a Linux or Apple MacOSX box will do nicely. To compile and install
crossroads, follow these steps.
diff --git a/doc/config.yo b/doc/config.yo
@@ -414,128 +414,23 @@ startdit()
tt(onsuccess) em(commandline) tt(;)
it() There is no default.)
- dit(Debugging and Performance aids:) Incase the traffic between
- client and backend
- must be debugged, the statement tt(trafficlog) em(filename) can
- be issued. This causes the traffic to be dumped in hexadecimal
- format to the stated filename.
-
- Traffic sent by the client is prefixed by a bf(C), traffic sent by
- the back end is prefixed by a bf(B). Below is a sample traffic
- dump of a browser trying to get a HTML page. The server replies
- that the page was not modified.
-
- verb(\
-C 0000 47 45 54 20 68 74 74 70 3a 2f 2f 77 77 77 2e 63 GET http://www.c
-C 0010 73 2e 68 65 6c 73 69 6e 6b 69 2e 66 69 2f 6c 69 s.helsinki.fi/li
-C 0020 6e 75 78 2f 6c 69 6e 75 78 2d 6b 65 72 6e 65 6c nux/linux-kernel
-C 0030 2f 32 30 30 31 2d 34 37 2f 30 34 31 37 2e 68 74 /2001-47/0417.ht
-C 0040 6d 6c 20 48 54 54 50 2f 31 2e 31 0d 0a 43 6f 6e ml HTTP/1.1..Con
-C 0050 6e 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a nection: close..
-.
-. etcetera
-.
-B 0000 48 54 54 50 2f 31 2e 30 20 33 30 34 20 4e 6f 74 HTTP/1.0 304 Not
-B 0010 20 4d 6f 64 69 66 69 65 64 0d 0a 44 61 74 65 3a Modified..Date:
-B 0020 20 54 75 65 2c 20 31 32 20 4a 75 6c 20 32 30 30 Tue, 12 Jul 200
-B 0030 35 20 30 39 3a 34 39 3a 34 37 20 47 4d 54 0d 0a 5 09:49:47 GMT..
-B 0040 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74 65 Content-Type: te
-B 0050 78 74 2f 68 74 6d 6c 3b 20 63 68 61 72 73 65 74 xt/html; charset
-.
-. etcetera
-.)
-
- Turning on traffic dumps will em(significantly)
- slow down crossroads.
+ dit(Debugging and Performance aids:) Two directives are available
+ to log network traffic to files. They are tt(trafficlog) and
+ tt(throughputlog).
itemization(
it() Syntax: tt(trafficlog) em(filename) tt(;)
- it() There is no default. Without this directive, traffic is
- not logged.)
+ it() And: tt(throughputlog) em(filename) tt(;)
+ it() Default: none)
- Besides tt(trafficlog), there is also a directive
- tt(throughputlog). This directive also takes one argument, a
- filename. The file is appended, and the following information is
- logged:
+ The tt(trafficlog) statement causes all traffic to be logged in
+ hexadecimal format. Each line is prefixed by tt(B) or tt(C),
+ depending on whether the information was received from the back
+ end or from the client.
- itemization(
- it() The process ID of the crossroads image that serves the
- TCP connection;
- it() The time of the request, in seconds and microseconds
- since start of the run;
- it() A bf(C) when the request originated at the client, or
- bf(B) when the request originated at the back end;
- it() The first 100 bytes of the request.)
-
- As an example, consider the following (the lines are shortened for
- brevity and prefixed by line numbers for clarity):
-
- verb(
-1 0000594 0.000001 C GET http://public.e-tunity.com/index.html...
-2 0000594 0.173713 B HTTP/1.0 200 OK..Date: Fri, 18 Nov 2005 0...
-3 0000594 0.278125 B width="100" bgcolor="#e0e0e0" valign="to...
-4 0000595 0.000001 C GET http://public.e-tunity.com/css/style/...
-5 0000594 0.944339 B /a></td>.. </tr>.</table>.</td><td class...
-6 0000594 0.946356 B smallboxdownl">Download</td>.. <td class...
-7 0000594 0.961102 B td><td class="smallboxodd" valign="top"><...
-8 0000595 0.698215 B HTTP/1.0 304 Not Modified..Date: Fri, 18 ...)
-
- This tells us that:
+ The tt(throughputlog) statement writes shorthand transmissions to
+ its log, accompanied by timings.
- itemization(
- it() Line 1: PID 594 served a request that originated at
- the client. The corresponding time is (almost) 0 seconds,
- so this is really the start of the run.
- it() Line 2: A back end replied 0.17 seconds later, and
- 0.28 seconds later, it was still replying (this is the
- third line, again a bf(B)-type transmission).
- it() Line 4: PID 595 served a request that originated
- at the client. Again, the corresponding time is (almost)
- 0 seconds, since this is the first conversation part of
- this connection.
- it() Lines 5 to 7: This is the continuation of line 2. Line 7
- is the last line of the bf(B) series (not visible from
- the example, but trust me, it is), so that we may
- conclude that it took the back end 0.96 seconds to serve
- the file tt(index.html) requested in line 1.
- it() Line 8: This is the answer to the client's request of
- line 4 (you can tell by the process ID number).
- So the back end took 0.68 seconds to confirm that
- the stylesheet requested in line 4 wasn't modified.)
-
- It is also worth while remembering that the start time of a bf(C)
- request is the time that crossroads sees the activity. Any latency
- between the true client and crossroads is obviously not
- included. This is illustrated by the below simple ASCII art:
-
- verb(
-client ---->---->---->--->*crossroads ====>====>====>
- \
- back end
- /
-client ----<----<----<---< crossroads ====<====<====<
-)
-
- This simple picture shows a typical HTTP request that originates
- at a client, travels to crossroads, and is relayed via the back
- end. The bf(C) entry in a throughput log is the time when
- crossroads sees the request, indicated by an asterisk. The bf(B)
- entries are the times that it takes the back end to answer,
- indicated by tt(===) style lines. Therefore, the true roundtrip
- time will be longer than the number of seconds that are logged in
- the throughput log: the latency between client and crossroads
- isn't included in that measurement.
-
- Summarizing, the throughput times of a client-back end connection
- can be analyzed using the directive tt(throughputlog). In a
- real-world analysis, you'd probably want to write up a script to
- analyze the output and to compute round trip times. Such scripts
- are not (yet) included in Crossroads.
-
- itemization(
- it() Syntax: tt(throughputlog) em(filename) tt(;)
- it() There is no default. Without this directive, the
- throughput is not logged.)
enddit()
subsubsect(HTTP-related Backend Directives) label(httpdirectives)
@@ -694,6 +589,22 @@ service ... {
}
})
+ dit(Keep-Alive Downgrading:) The directives
+ tt(setclientheader) and tt(setserverheader) also play a key
+ role in downgrading Keep-Alive connections to
+ 'single-shot'. E.g., the following configuration makes sure
+ that no Keep-Alive connections occur.
+
+ verb(\
+service ... {
+ ...
+ backend one {
+ ...
+ setserverheader "Connection: close";
+ setclientheader "Connection: close";
+ }
+})
+
)
enddit()
diff --git a/doc/crossroads.html b/doc/crossroads.html
@@ -1,12 +1,12 @@
<a name="defs.yo"></a><html><head>
-<title>Crossroads 1.12</title>
+<title>Crossroads 1.15</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.12</h1>
+<h1>Crossroads 1.15</h1>
<h2>Karel Kubat</h2>
<h2>e-tunity</h2><h2>2005, 2006, ff.</h2>
@@ -74,35 +74,36 @@
<dt><a href="#l30">5.3.1: Sample Crossroads configuration</a></dt>
<dt><a href="#l31">5.3.2: Sample Apache configuration</a></dt>
</dl>
-<dt><a href="#l32">5.4: Configuration examples</a></dt>
+<dt><a href="#l32">5.4: Debugging network traffic</a></dt>
+<dt><a href="#l33">5.5: Configuration examples</a></dt>
<dl>
-<dt><a href="#l33">5.4.1: A load balancer for three webserver back ends</a></dt>
-<dt><a href="#l34">5.4.2: An HTTP forwarder when travelling</a></dt>
-<dt><a href="#l35">5.4.3: SSH login with enforced idle logout</a></dt>
+<dt><a href="#l34">5.5.1: A load balancer for three webserver back ends</a></dt>
+<dt><a href="#l35">5.5.2: An HTTP forwarder when travelling</a></dt>
+<dt><a href="#l36">5.5.3: SSH login with enforced idle logout</a></dt>
</dl>
</dl>
-<dt><h3><a href="#l36">6: Benchmarking</a></h3></dt>
+<dt><h3><a href="#l37">6: Benchmarking</a></h3></dt>
<dl>
-<dt><a href="#l37">6.1: Benchmark 1: Accessing a proxy via crossroads or directly</a></dt>
+<dt><a href="#l38">6.1: Benchmark 1: Accessing a proxy via crossroads or directly</a></dt>
<dl>
-<dt><a href="#l38">6.1.1: Results</a></dt>
-<dt><a href="#l39">6.1.2: Discussion</a></dt>
+<dt><a href="#l39">6.1.1: Results</a></dt>
+<dt><a href="#l40">6.1.2: Discussion</a></dt>
</dl>
-<dt><a href="#l40">6.2: Benchmark 2: Crossroads versus Linux Virtual Server (LVS)</a></dt>
+<dt><a href="#l41">6.2: Benchmark 2: Crossroads versus Linux Virtual Server (LVS)</a></dt>
<dl>
-<dt><a href="#l41">6.2.1: Environment</a></dt>
-<dt><a href="#l42">6.2.2: Tests and results</a></dt>
+<dt><a href="#l42">6.2.1: Environment</a></dt>
+<dt><a href="#l43">6.2.2: Tests and results</a></dt>
</dl>
</dl>
-<dt><h3><a href="#l43">7: Compiling and Installing</a></h3></dt>
+<dt><h3><a href="#l44">7: Compiling and Installing</a></h3></dt>
<dl>
-<dt><a href="#l44">7.1: Prerequisites</a></dt>
-<dt><a href="#l45">7.2: Compiling and installing</a></dt>
-<dt><a href="#l46">7.3: Configuring crossroads</a></dt>
-<dt><a href="#l47">7.4: A boot script</a></dt>
+<dt><a href="#l45">7.1: Prerequisites</a></dt>
+<dt><a href="#l46">7.2: Compiling and installing</a></dt>
+<dt><a href="#l47">7.3: Configuring crossroads</a></dt>
+<dt><a href="#l48">7.4: A boot script</a></dt>
<dl>
-<dt><a href="#l48">7.4.1: SysV Style Startup</a></dt>
-<dt><a href="#l49">7.4.2: BSD Style Startup</a></dt>
+<dt><a href="#l49">7.4.1: SysV Style Startup</a></dt>
+<dt><a href="#l50">7.4.2: BSD Style Startup</a></dt>
</dl>
<p><hr><p>
@@ -889,136 +890,23 @@ This means that when a given back end is hit, then its usage data
<code>onsuccess</code> <em>commandline</em> <code>;</code>
<li> There is no default.</ul>
<p>
-<p><dt><strong>Debugging and Performance aids:</strong><dd> Incase the traffic between
- client and backend
- must be debugged, the statement <code>trafficlog</code> <em>filename</em> can
- be issued. This causes the traffic to be dumped in hexadecimal
- format to the stated filename.
-<p>
-Traffic sent by the client is prefixed by a <strong>C</strong>, traffic sent by
- the back end is prefixed by a <strong>B</strong>. Below is a sample traffic
- dump of a browser trying to get a HTML page. The server replies
- that the page was not modified.
-<p>
-<pre>
-C 0000 47 45 54 20 68 74 74 70 3a 2f 2f 77 77 77 2e 63 GET http://www.c
-C 0010 73 2e 68 65 6c 73 69 6e 6b 69 2e 66 69 2f 6c 69 s.helsinki.fi/li
-C 0020 6e 75 78 2f 6c 69 6e 75 78 2d 6b 65 72 6e 65 6c nux/linux-kernel
-C 0030 2f 32 30 30 31 2d 34 37 2f 30 34 31 37 2e 68 74 /2001-47/0417.ht
-C 0040 6d 6c 20 48 54 54 50 2f 31 2e 31 0d 0a 43 6f 6e ml HTTP/1.1..Con
-C 0050 6e 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a nection: close..
-.
-. etcetera
-.
-B 0000 48 54 54 50 2f 31 2e 30 20 33 30 34 20 4e 6f 74 HTTP/1.0 304 Not
-B 0010 20 4d 6f 64 69 66 69 65 64 0d 0a 44 61 74 65 3a Modified..Date:
-B 0020 20 54 75 65 2c 20 31 32 20 4a 75 6c 20 32 30 30 Tue, 12 Jul 200
-B 0030 35 20 30 39 3a 34 39 3a 34 37 20 47 4d 54 0d 0a 5 09:49:47 GMT..
-B 0040 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74 65 Content-Type: te
-B 0050 78 74 2f 68 74 6d 6c 3b 20 63 68 61 72 73 65 74 xt/html; charset
-.
-. etcetera
-.
-</pre>
-
-<p>
-Turning on traffic dumps will <em>significantly</em>
- slow down crossroads.
+<p><dt><strong>Debugging and Performance aids:</strong><dd> Two directives are available
+ to log network traffic to files. They are <code>trafficlog</code> and
+ <code>throughputlog</code>.
<p>
<ul>
<li> Syntax: <code>trafficlog</code> <em>filename</em> <code>;</code>
- <li> There is no default. Without this directive, traffic is
- not logged.</ul>
+ <li> And: <code>throughputlog</code> <em>filename</em> <code>;</code>
+ <li> Default: none</ul>
<p>
-Besides <code>trafficlog</code>, there is also a directive
- <code>throughputlog</code>. This directive also takes one argument, a
- filename. The file is appended, and the following information is
- logged:
-<p>
-<ul>
- <li> The process ID of the crossroads image that serves the
- TCP connection;
- <li> The time of the request, in seconds and microseconds
- since start of the run;
- <li> A <strong>C</strong> when the request originated at the client, or
- <strong>B</strong> when the request originated at the back end;
- <li> The first 100 bytes of the request.</ul>
+The <code>trafficlog</code> statement causes all traffic to be logged in
+ hexadecimal format. Each line is prefixed by <code>B</code> or <code>C</code>,
+ depending on whether the information was received from the back
+ end or from the client.
<p>
-As an example, consider the following (the lines are shortened for
- brevity and prefixed by line numbers for clarity):
+The <code>throughputlog</code> statement writes shorthand transmissions to
+ its log, accompanied by timings.
<p>
-<pre>
-
-1 0000594 0.000001 C GET http://public.e-tunity.com/index.html...
-2 0000594 0.173713 B HTTP/1.0 200 OK..Date: Fri, 18 Nov 2005 0...
-3 0000594 0.278125 B width="100" bgcolor="#e0e0e0" valign="to...
-4 0000595 0.000001 C GET http://public.e-tunity.com/css/style/...
-5 0000594 0.944339 B /a></td>.. </tr>.</table>.</td><td class...
-6 0000594 0.946356 B smallboxdownl">Download</td>.. <td class...
-7 0000594 0.961102 B td><td class="smallboxodd" valign="top"><...
-8 0000595 0.698215 B HTTP/1.0 304 Not Modified..Date: Fri, 18 ...
-</pre>
-
-<p>
-This tells us that:
-<p>
-<ul>
- <li> Line 1: PID 594 served a request that originated at
- the client. The corresponding time is (almost) 0 seconds,
- so this is really the start of the run.
- <li> Line 2: A back end replied 0.17 seconds later, and
- 0.28 seconds later, it was still replying (this is the
- third line, again a <strong>B</strong>-type transmission).
- <li> Line 4: PID 595 served a request that originated
- at the client. Again, the corresponding time is (almost)
- 0 seconds, since this is the first conversation part of
- this connection.
- <li> Lines 5 to 7: This is the continuation of line 2. Line 7
- is the last line of the <strong>B</strong> series (not visible from
- the example, but trust me, it is), so that we may
- conclude that it took the back end 0.96 seconds to serve
- the file <code>index.html</code> requested in line 1.
- <li> Line 8: This is the answer to the client's request of
- line 4 (you can tell by the process ID number).
- So the back end took 0.68 seconds to confirm that
- the stylesheet requested in line 4 wasn't modified.</ul>
-<p>
-It is also worth while remembering that the start time of a <strong>C</strong>
- request is the time that crossroads sees the activity. Any latency
- between the true client and crossroads is obviously not
- included. This is illustrated by the below simple ASCII art:
-<p>
-<pre>
-
-client ---->---->---->--->*crossroads ====>====>====>
- \
- back end
- /
-client ----<----<----<---< crossroads ====<====<====<
-
-</pre>
-
-<p>
-This simple picture shows a typical HTTP request that originates
- at a client, travels to crossroads, and is relayed via the back
- end. The <strong>C</strong> entry in a throughput log is the time when
- crossroads sees the request, indicated by an asterisk. The <strong>B</strong>
- entries are the times that it takes the back end to answer,
- indicated by <code>===</code> style lines. Therefore, the true roundtrip
- time will be longer than the number of seconds that are logged in
- the throughput log: the latency between client and crossroads
- isn't included in that measurement.
-<p>
-Summarizing, the throughput times of a client-back end connection
- can be analyzed using the directive <code>throughputlog</code>. In a
- real-world analysis, you'd probably want to write up a script to
- analyze the output and to compute round trip times. Such scripts
- are not (yet) included in Crossroads.
-<p>
-<ul>
- <li> Syntax: <code>throughputlog</code> <em>filename</em> <code>;</code>
- <li> There is no default. Without this directive, the
- throughput is not logged.</ul>
</dl>
<p>
<a name="l18"></a>
@@ -1186,6 +1074,24 @@ service ... {
</pre>
<p>
+<p><dt><strong>Keep-Alive Downgrading:</strong><dd> The directives
+ <code>setclientheader</code> and <code>setserverheader</code> also play a key
+ role in downgrading Keep-Alive connections to
+ 'single-shot'. E.g., the following configuration makes sure
+ that no Keep-Alive connections occur.
+<p>
+<pre>
+service ... {
+ ...
+ backend one {
+ ...
+ setserverheader "Connection: close";
+ setclientheader "Connection: close";
+ }
+}
+</pre>
+
+<p>
</dl>
<p>
</dl>
@@ -1598,14 +1504,138 @@ LogFormat "%{X-Real-IP}i %l %u %t %D \"%r\" %>s %b" common
<p>
<a name="l32"></a>
-<h3>5.4: Configuration examples</h3>
+<h3>5.4: Debugging network traffic</h3>
+<p>
+Incase the traffic between
+ client and backend
+ must be debugged, the statement <code>trafficlog</code> <em>filename</em> can
+ be issued. This causes the traffic to be dumped in hexadecimal
+ format to the stated filename.
+<p>
+Traffic sent by the client is prefixed by a <strong>C</strong>, traffic sent by
+ the back end is prefixed by a <strong>B</strong>. Below is a sample traffic
+ dump of a browser trying to get a HTML page. The server replies
+ that the page was not modified.
+<p>
+<pre>
+C 0000 47 45 54 20 68 74 74 70 3a 2f 2f 77 77 77 2e 63 GET http://www.c
+C 0010 73 2e 68 65 6c 73 69 6e 6b 69 2e 66 69 2f 6c 69 s.helsinki.fi/li
+C 0020 6e 75 78 2f 6c 69 6e 75 78 2d 6b 65 72 6e 65 6c nux/linux-kernel
+C 0030 2f 32 30 30 31 2d 34 37 2f 30 34 31 37 2e 68 74 /2001-47/0417.ht
+C 0040 6d 6c 20 48 54 54 50 2f 31 2e 31 0d 0a 43 6f 6e ml HTTP/1.1..Con
+C 0050 6e 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a nection: close..
+.
+. etcetera
+.
+B 0000 48 54 54 50 2f 31 2e 30 20 33 30 34 20 4e 6f 74 HTTP/1.0 304 Not
+B 0010 20 4d 6f 64 69 66 69 65 64 0d 0a 44 61 74 65 3a Modified..Date:
+B 0020 20 54 75 65 2c 20 31 32 20 4a 75 6c 20 32 30 30 Tue, 12 Jul 200
+B 0030 35 20 30 39 3a 34 39 3a 34 37 20 47 4d 54 0d 0a 5 09:49:47 GMT..
+B 0040 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74 65 Content-Type: te
+B 0050 78 74 2f 68 74 6d 6c 3b 20 63 68 61 72 73 65 74 xt/html; charset
+.
+. etcetera
+.
+</pre>
+
+<p>
+Turning on traffic dumps will <em>significantly</em>
+ slow down crossroads.
+<p>
+Besides <code>trafficlog</code>, there is also a directive
+ <code>throughputlog</code>. This directive also takes one argument, a
+ filename. The file is appended, and the following information is
+ logged:
+<p>
+<ul>
+ <li> The process ID of the crossroads image that serves the
+ TCP connection;
+ <li> The time of the request, in seconds and microseconds
+ since start of the run;
+ <li> A <strong>C</strong> when the request originated at the client, or
+ <strong>B</strong> when the request originated at the back end;
+ <li> The first 100 bytes of the request.</ul>
+<p>
+As an example, consider the following (the lines are shortened for
+ brevity and prefixed by line numbers for clarity):
+<p>
+<pre>
+
+1 0000594 0.000001 C GET http://public.e-tunity.com/index.html...
+2 0000594 0.173713 B HTTP/1.0 200 OK..Date: Fri, 18 Nov 2005 0...
+3 0000594 0.278125 B width="100" bgcolor="#e0e0e0" valign="to...
+4 0000595 0.000001 C GET http://public.e-tunity.com/css/style/...
+5 0000594 0.944339 B /a></td>.. </tr>.</table>.</td><td class...
+6 0000594 0.946356 B smallboxdownl">Download</td>.. <td class...
+7 0000594 0.961102 B td><td class="smallboxodd" valign="top"><...
+8 0000595 0.698215 B HTTP/1.0 304 Not Modified..Date: Fri, 18 ...
+</pre>
+
+<p>
+This tells us that:
+<p>
+<ul>
+ <li> Line 1: PID 594 served a request that originated at
+ the client. The corresponding time is (almost) 0 seconds,
+ so this is really the start of the run.
+ <li> Line 2: A back end replied 0.17 seconds later, and
+ 0.28 seconds later, it was still replying (this is the
+ third line, again a <strong>B</strong>-type transmission).
+ <li> Line 4: PID 595 served a request that originated
+ at the client. Again, the corresponding time is (almost)
+ 0 seconds, since this is the first conversation part of
+ this connection.
+ <li> Lines 5 to 7: This is the continuation of line 2. Line 7
+ is the last line of the <strong>B</strong> series (not visible from
+ the example, but trust me, it is), so that we may
+ conclude that it took the back end 0.96 seconds to serve
+ the file <code>index.html</code> requested in line 1.
+ <li> Line 8: This is the answer to the client's request of
+ line 4 (you can tell by the process ID number).
+ So the back end took 0.68 seconds to confirm that
+ the stylesheet requested in line 4 wasn't modified.</ul>
+<p>
+It is also worth while remembering that the start time of a <strong>C</strong>
+ request is the time that crossroads sees the activity. Any latency
+ between the true client and crossroads is obviously not
+ included. This is illustrated by the below simple ASCII art:
+<p>
+<pre>
+
+client ---->---->---->--->*crossroads ====>====>====>
+ \
+ back end
+ /
+client ----<----<----<---< crossroads ====<====<====<
+
+</pre>
+
+<p>
+This simple picture shows a typical HTTP request that originates
+ at a client, travels to crossroads, and is relayed via the back
+ end. The <strong>C</strong> entry in a throughput log is the time when
+ crossroads sees the request, indicated by an asterisk. The <strong>B</strong>
+ entries are the times that it takes the back end to answer,
+ indicated by <code>===</code> style lines. Therefore, the true roundtrip
+ time will be longer than the number of seconds that are logged in
+ the throughput log: the latency between client and crossroads
+ isn't included in that measurement.
+<p>
+Summarizing, the throughput times of a client-back end connection
+ can be analyzed using the directive <code>throughputlog</code>. In a
+ real-world analysis, you'd probably want to write up a script to
+ analyze the output and to compute round trip times. Such scripts
+ are not (yet) included in Crossroads.
+<p>
+<a name="l33"></a>
+<h3>5.5: Configuration examples</h3>
<p>
As a general hint, use <code>crossroads sampleconf</code> to view the most
up-to-date examples of configurations. The description below shows a
few examples too.
<p>
-<a name="l33"></a>
-<strong>5.4.1: A load balancer for three webserver back ends</strong>
+<a name="l34"></a>
+<strong>5.5.1: A load balancer for three webserver back ends</strong>
<p>
The following configuration example binds crossroads to port 80 of the
current server, and distributes the load over three back ends. This
@@ -1733,8 +1763,8 @@ service www {
</pre>
<p>
-<a name="l34"></a>
-<strong>5.4.2: An HTTP forwarder when travelling</strong>
+<a name="l35"></a>
+<strong>5.5.2: An HTTP forwarder when travelling</strong>
<p>
As another example, here's my <code>crossroads.conf</code> that I use on my
Unix laptop. The problem that I face is that I need many HTTP proxy
@@ -1822,8 +1852,8 @@ and <code>LocalSquid</code> are both active, then <code>crossroads tell httpprox
sshtunnel down</code> will 'take down' the back end <code>SshTunnel</code> -- and
will automatically cause crossroads to switch to <code>LocalSquid</code>.
<p>
-<a name="l35"></a>
-<strong>5.4.3: SSH login with enforced idle logout</strong>
+<a name="l36"></a>
+<strong>5.5.3: SSH login with enforced idle logout</strong>
<p>
The following example shows how crossroads 'throttles' SSH
logins. Connections are accepted on port
@@ -1848,13 +1878,13 @@ service Ssh {
</pre>
<p>
-<a name="l36"></a>
+<a name="l37"></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="l37"></a>
+<a name="l38"></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:
@@ -1882,7 +1912,7 @@ service HttpProxy {
</pre>
<p>
-<a name="l38"></a>
+<a name="l39"></a>
<strong>6.1.1: Results</strong>
<p>
The results of this test are that crossroads causes a negligible
@@ -1905,7 +1935,7 @@ sys 0m0.230s
</pre>
<p>
-<a name="l39"></a>
+<a name="l40"></a>
<strong>6.1.2: Discussion</strong>
<p>
The above shown results are quite favorable to crossroads. However,
@@ -1937,7 +1967,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="l40"></a>
+<a name="l41"></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
@@ -1951,7 +1981,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="l41"></a>
+<a name="l42"></a>
<strong>6.2.1: Environment</strong>
<p>
On the balancer, LVS was run on port 80, its forwarding set up for two
@@ -1982,7 +2012,7 @@ service http {
</pre>
<p>
-<a name="l42"></a>
+<a name="l43"></a>
<strong>6.2.2: Tests and results</strong>
<p>
In the first test, ports 80 and 81 on the balancer were 'bombed' with
@@ -2061,9 +2091,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="l43"></a>
+<a name="l44"></a>
<h2>7: Compiling and Installing</h2>
-<a name="compiling"></a><a name="l44"></a>
+<a name="compiling"></a><a name="l45"></a>
<h3>7.1: Prerequisites</h3>
<p>
The creation of crossroads requires:
@@ -2074,16 +2104,13 @@ The creation of crossroads requires:
<p>
<li> A POSIX-compliant C compiler;
<p>
-<li> The grammar generation tools <code>bison</code> and <code>flex</code>;
-<p>
<li> Support for SYSV IPC, networking and so on.
</ul>
<p>
-Basically a Linux or Apple MacOSX box will do nicely once you make
-sure that <code>bison</code> and <code>flex</code> are installed. To compile and install
+Basically a Linux or Apple MacOSX box will do nicely. To compile and install
crossroads, follow these steps.
<p>
-<a name="l45"></a>
+<a name="l46"></a>
<h3>7.2: Compiling and installing</h3>
<p>
<ul>
@@ -2141,7 +2168,7 @@ crossroads, follow these steps.
<p>
</ul>
<p>
-<a name="l46"></a>
+<a name="l47"></a>
<h3>7.3: Configuring crossroads</h3>
<p>
Now that the binary is available on your system, you need to create a
@@ -2190,13 +2217,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="l47"></a>
+<a name="l48"></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="l48"></a>
+<a name="l49"></a>
<strong>7.4.1: SysV Style Startup</strong>
<p>
On SysV style systems, there's a startup script directory
@@ -2238,7 +2265,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="l49"></a>
+<a name="l50"></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\&.12" "2005, 2006, ff\&."
+.TH "Crossroads 1\&.15" "2005, 2006, ff\&."
.PP
-.SH "Crossroads 1\&.12"
+.SH "Crossroads 1\&.15"
.SH "Karel Kubat"
.SH "e-tunity"
.SH "2005, 2006, ff\&."
@@ -891,147 +891,25 @@ Syntax: \f(CWonfailure\fP \fIcommandline\fP \f(CW;\fP and
There is no default\&.
.IP
.IP "Debugging and Performance aids:"
-Incase the traffic between
-client and backend
-must be debugged, the statement \f(CWtrafficlog\fP \fIfilename\fP can
-be issued\&. This causes the traffic to be dumped in hexadecimal
-format to the stated filename\&.
-.IP
-Traffic sent by the client is prefixed by a \fBC\fP, traffic sent by
-the back end is prefixed by a \fBB\fP\&. Below is a sample traffic
-dump of a browser trying to get a HTML page\&. The server replies
-that the page was not modified\&.
-.IP
-.nf
-C 0000 47 45 54 20 68 74 74 70 3a 2f 2f 77 77 77 2e 63 GET http://www\&.c
-C 0010 73 2e 68 65 6c 73 69 6e 6b 69 2e 66 69 2f 6c 69 s\&.helsinki\&.fi/li
-C 0020 6e 75 78 2f 6c 69 6e 75 78 2d 6b 65 72 6e 65 6c nux/linux-kernel
-C 0030 2f 32 30 30 31 2d 34 37 2f 30 34 31 37 2e 68 74 /2001-47/0417\&.ht
-C 0040 6d 6c 20 48 54 54 50 2f 31 2e 31 0d 0a 43 6f 6e ml HTTP/1\&.1\&.\&.Con
-C 0050 6e 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a nection: close\&.\&.
-\&.
-\&. etcetera
-\&.
-B 0000 48 54 54 50 2f 31 2e 30 20 33 30 34 20 4e 6f 74 HTTP/1\&.0 304 Not
-B 0010 20 4d 6f 64 69 66 69 65 64 0d 0a 44 61 74 65 3a Modified\&.\&.Date:
-B 0020 20 54 75 65 2c 20 31 32 20 4a 75 6c 20 32 30 30 Tue, 12 Jul 200
-B 0030 35 20 30 39 3a 34 39 3a 34 37 20 47 4d 54 0d 0a 5 09:49:47 GMT\&.\&.
-B 0040 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74 65 Content-Type: te
-B 0050 78 74 2f 68 74 6d 6c 3b 20 63 68 61 72 73 65 74 xt/html; charset
-\&.
-\&. etcetera
-\&.
-.fi
-
-.IP
-Turning on traffic dumps will \fIsignificantly\fP
-slow down crossroads\&.
+Two directives are available
+to log network traffic to files\&. They are \f(CWtrafficlog\fP and
+\f(CWthroughputlog\fP\&.
.IP
.IP o
Syntax: \f(CWtrafficlog\fP \fIfilename\fP \f(CW;\fP
.IP o
-There is no default\&. Without this directive, traffic is
-not logged\&.
-.IP
-Besides \f(CWtrafficlog\fP, there is also a directive
-\f(CWthroughputlog\fP\&. This directive also takes one argument, a
-filename\&. The file is appended, and the following information is
-logged:
-.IP
-.IP o
-The process ID of the crossroads image that serves the
-TCP connection;
-.IP o
-The time of the request, in seconds and microseconds
-since start of the run;
-.IP o
-A \fBC\fP when the request originated at the client, or
-\fBB\fP when the request originated at the back end;
-.IP o
-The first 100 bytes of the request\&.
-.IP
-As an example, consider the following (the lines are shortened for
-brevity and prefixed by line numbers for clarity):
-.IP
-.nf
-
-1 0000594 0\&.000001 C GET http://public\&.e-tunity\&.com/index\&.html\&.\&.\&.
-2 0000594 0\&.173713 B HTTP/1\&.0 200 OK\&.\&.Date: Fri, 18 Nov 2005 0\&.\&.\&.
-3 0000594 0\&.278125 B width="100" bgcolor="#e0e0e0" valign="to\&.\&.\&.
-4 0000595 0\&.000001 C GET http://public\&.e-tunity\&.com/css/style/\&.\&.\&.
-5 0000594 0\&.944339 B /a></td>\&.\&. </tr>\&.</table>\&.</td><td class\&.\&.\&.
-6 0000594 0\&.946356 B smallboxdownl">Download</td>\&.\&. <td class\&.\&.\&.
-7 0000594 0\&.961102 B td><td class="smallboxodd" valign="top"><\&.\&.\&.
-8 0000595 0\&.698215 B HTTP/1\&.0 304 Not Modified\&.\&.Date: Fri, 18 \&.\&.\&.
-.fi
-
-.IP
-This tells us that:
-.IP
-.IP o
-Line 1: PID 594 served a request that originated at
-the client\&. The corresponding time is (almost) 0 seconds,
-so this is really the start of the run\&.
-.IP o
-Line 2: A back end replied 0\&.17 seconds later, and
-0\&.28 seconds later, it was still replying (this is the
-third line, again a \fBB\fP-type transmission)\&.
-.IP o
-Line 4: PID 595 served a request that originated
-at the client\&. Again, the corresponding time is (almost)
-0 seconds, since this is the first conversation part of
-this connection\&.
-.IP o
-Lines 5 to 7: This is the continuation of line 2\&. Line 7
-is the last line of the \fBB\fP series (not visible from
-the example, but trust me, it is), so that we may
-conclude that it took the back end 0\&.96 seconds to serve
-the file \f(CWindex\&.html\fP requested in line 1\&.
+And: \f(CWthroughputlog\fP \fIfilename\fP \f(CW;\fP
.IP o
-Line 8: This is the answer to the client\&'s request of
-line 4 (you can tell by the process ID number)\&.
-So the back end took 0\&.68 seconds to confirm that
-the stylesheet requested in line 4 wasn\&'t modified\&.
-.IP
-It is also worth while remembering that the start time of a \fBC\fP
-request is the time that crossroads sees the activity\&. Any latency
-between the true client and crossroads is obviously not
-included\&. This is illustrated by the below simple ASCII art:
-.IP
-.nf
-
-client ---->---->---->--->*crossroads ====>====>====>
- \e
- back end
- /
-client ----<----<----<---< crossroads ====<====<====<
-
-.fi
-
+Default: none
.IP
-This simple picture shows a typical HTTP request that originates
-at a client, travels to crossroads, and is relayed via the back
-end\&. The \fBC\fP entry in a throughput log is the time when
-crossroads sees the request, indicated by an asterisk\&. The \fBB\fP
-entries are the times that it takes the back end to answer,
-indicated by \f(CW===\fP style lines\&. Therefore, the true roundtrip
-time will be longer than the number of seconds that are logged in
-the throughput log: the latency between client and crossroads
-isn\&'t included in that measurement\&.
+The \f(CWtrafficlog\fP statement causes all traffic to be logged in
+hexadecimal format\&. Each line is prefixed by \f(CWB\fP or \f(CWC\fP,
+depending on whether the information was received from the back
+end or from the client\&.
.IP
-Summarizing, the throughput times of a client-back end connection
-can be analyzed using the directive \f(CWthroughputlog\fP\&. In a
-real-world analysis, you\&'d probably want to write up a script to
-analyze the output and to compute round trip times\&. Such scripts
-are not (yet) included in Crossroads\&.
+The \f(CWthroughputlog\fP statement writes shorthand transmissions to
+its log, accompanied by timings\&.
.IP
-.IP o
-Syntax: \f(CWthroughputlog\fP \fIfilename\fP \f(CW;\fP
-.IP o
-There is no default\&. Without this directive, the
-throughput is not logged\&.
-
-.PP
.SH "4\&.3\&.2: HTTP-related Backend Directives"
@@ -1208,6 +1086,25 @@ service \&.\&.\&. {
.fi
.IP
+.IP "Keep-Alive Downgrading:"
+The directives
+\f(CWsetclientheader\fP and \f(CWsetserverheader\fP also play a key
+role in downgrading Keep-Alive connections to
+\&'single-shot\&'\&. E\&.g\&., the following configuration makes sure
+that no Keep-Alive connections occur\&.
+.IP
+.nf
+service \&.\&.\&. {
+ \&.\&.\&.
+ backend one {
+ \&.\&.\&.
+ setserverheader "Connection: close";
+ setclientheader "Connection: close";
+ }
+}
+.fi
+
+.IP
.SH "5: Tips, Tricks and Remarks"
@@ -1639,7 +1536,139 @@ LogFormat "%{X-Real-IP}i %l %u %t %D \e"%r\e" %>s %b" common
.PP
-.SH "5\&.4: Configuration examples"
+.SH "5\&.4: Debugging network traffic"
+
+.PP
+Incase the traffic between
+client and backend
+must be debugged, the statement \f(CWtrafficlog\fP \fIfilename\fP can
+be issued\&. This causes the traffic to be dumped in hexadecimal
+format to the stated filename\&.
+.PP
+Traffic sent by the client is prefixed by a \fBC\fP, traffic sent by
+the back end is prefixed by a \fBB\fP\&. Below is a sample traffic
+dump of a browser trying to get a HTML page\&. The server replies
+that the page was not modified\&.
+.PP
+.nf
+C 0000 47 45 54 20 68 74 74 70 3a 2f 2f 77 77 77 2e 63 GET http://www\&.c
+C 0010 73 2e 68 65 6c 73 69 6e 6b 69 2e 66 69 2f 6c 69 s\&.helsinki\&.fi/li
+C 0020 6e 75 78 2f 6c 69 6e 75 78 2d 6b 65 72 6e 65 6c nux/linux-kernel
+C 0030 2f 32 30 30 31 2d 34 37 2f 30 34 31 37 2e 68 74 /2001-47/0417\&.ht
+C 0040 6d 6c 20 48 54 54 50 2f 31 2e 31 0d 0a 43 6f 6e ml HTTP/1\&.1\&.\&.Con
+C 0050 6e 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a nection: close\&.\&.
+\&.
+\&. etcetera
+\&.
+B 0000 48 54 54 50 2f 31 2e 30 20 33 30 34 20 4e 6f 74 HTTP/1\&.0 304 Not
+B 0010 20 4d 6f 64 69 66 69 65 64 0d 0a 44 61 74 65 3a Modified\&.\&.Date:
+B 0020 20 54 75 65 2c 20 31 32 20 4a 75 6c 20 32 30 30 Tue, 12 Jul 200
+B 0030 35 20 30 39 3a 34 39 3a 34 37 20 47 4d 54 0d 0a 5 09:49:47 GMT\&.\&.
+B 0040 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74 65 Content-Type: te
+B 0050 78 74 2f 68 74 6d 6c 3b 20 63 68 61 72 73 65 74 xt/html; charset
+\&.
+\&. etcetera
+\&.
+.fi
+
+.PP
+Turning on traffic dumps will \fIsignificantly\fP
+slow down crossroads\&.
+.PP
+Besides \f(CWtrafficlog\fP, there is also a directive
+\f(CWthroughputlog\fP\&. This directive also takes one argument, a
+filename\&. The file is appended, and the following information is
+logged:
+.PP
+.IP o
+The process ID of the crossroads image that serves the
+TCP connection;
+.IP o
+The time of the request, in seconds and microseconds
+since start of the run;
+.IP o
+A \fBC\fP when the request originated at the client, or
+\fBB\fP when the request originated at the back end;
+.IP o
+The first 100 bytes of the request\&.
+.PP
+As an example, consider the following (the lines are shortened for
+brevity and prefixed by line numbers for clarity):
+.PP
+.nf
+
+1 0000594 0\&.000001 C GET http://public\&.e-tunity\&.com/index\&.html\&.\&.\&.
+2 0000594 0\&.173713 B HTTP/1\&.0 200 OK\&.\&.Date: Fri, 18 Nov 2005 0\&.\&.\&.
+3 0000594 0\&.278125 B width="100" bgcolor="#e0e0e0" valign="to\&.\&.\&.
+4 0000595 0\&.000001 C GET http://public\&.e-tunity\&.com/css/style/\&.\&.\&.
+5 0000594 0\&.944339 B /a></td>\&.\&. </tr>\&.</table>\&.</td><td class\&.\&.\&.
+6 0000594 0\&.946356 B smallboxdownl">Download</td>\&.\&. <td class\&.\&.\&.
+7 0000594 0\&.961102 B td><td class="smallboxodd" valign="top"><\&.\&.\&.
+8 0000595 0\&.698215 B HTTP/1\&.0 304 Not Modified\&.\&.Date: Fri, 18 \&.\&.\&.
+.fi
+
+.PP
+This tells us that:
+.PP
+.IP o
+Line 1: PID 594 served a request that originated at
+the client\&. The corresponding time is (almost) 0 seconds,
+so this is really the start of the run\&.
+.IP o
+Line 2: A back end replied 0\&.17 seconds later, and
+0\&.28 seconds later, it was still replying (this is the
+third line, again a \fBB\fP-type transmission)\&.
+.IP o
+Line 4: PID 595 served a request that originated
+at the client\&. Again, the corresponding time is (almost)
+0 seconds, since this is the first conversation part of
+this connection\&.
+.IP o
+Lines 5 to 7: This is the continuation of line 2\&. Line 7
+is the last line of the \fBB\fP series (not visible from
+the example, but trust me, it is), so that we may
+conclude that it took the back end 0\&.96 seconds to serve
+the file \f(CWindex\&.html\fP requested in line 1\&.
+.IP o
+Line 8: This is the answer to the client\&'s request of
+line 4 (you can tell by the process ID number)\&.
+So the back end took 0\&.68 seconds to confirm that
+the stylesheet requested in line 4 wasn\&'t modified\&.
+.PP
+It is also worth while remembering that the start time of a \fBC\fP
+request is the time that crossroads sees the activity\&. Any latency
+between the true client and crossroads is obviously not
+included\&. This is illustrated by the below simple ASCII art:
+.PP
+.nf
+
+client ---->---->---->--->*crossroads ====>====>====>
+ \e
+ back end
+ /
+client ----<----<----<---< crossroads ====<====<====<
+
+.fi
+
+.PP
+This simple picture shows a typical HTTP request that originates
+at a client, travels to crossroads, and is relayed via the back
+end\&. The \fBC\fP entry in a throughput log is the time when
+crossroads sees the request, indicated by an asterisk\&. The \fBB\fP
+entries are the times that it takes the back end to answer,
+indicated by \f(CW===\fP style lines\&. Therefore, the true roundtrip
+time will be longer than the number of seconds that are logged in
+the throughput log: the latency between client and crossroads
+isn\&'t included in that measurement\&.
+.PP
+Summarizing, the throughput times of a client-back end connection
+can be analyzed using the directive \f(CWthroughputlog\fP\&. In a
+real-world analysis, you\&'d probably want to write up a script to
+analyze the output and to compute round trip times\&. Such scripts
+are not (yet) included in Crossroads\&.
+.PP
+
+.SH "5\&.5: Configuration examples"
.PP
As a general hint, use \f(CWcrossroads sampleconf\fP to view the most
@@ -1647,7 +1676,7 @@ up-to-date examples of configurations\&. The description below shows a
few examples too\&.
.PP
-.SH "5\&.4\&.1: A load balancer for three webserver back ends"
+.SH "5\&.5\&.1: A load balancer for three webserver back ends"
.PP
The following configuration example binds crossroads to port 80 of the
@@ -1777,7 +1806,7 @@ service www {
.PP
-.SH "5\&.4\&.2: An HTTP forwarder when travelling"
+.SH "5\&.5\&.2: An HTTP forwarder when travelling"
.PP
As another example, here\&'s my \f(CWcrossroads\&.conf\fP that I use on my
@@ -1872,7 +1901,7 @@ sshtunnel down\fP will \&'take down\&' the back end \f(CWSshTunnel\fP -- and
will automatically cause crossroads to switch to \f(CWLocalSquid\fP\&.
.PP
-.SH "5\&.4\&.3: SSH login with enforced idle logout"
+.SH "5\&.5\&.3: SSH login with enforced idle logout"
.PP
The following example shows how crossroads \&'throttles\&' SSH
@@ -2125,14 +2154,10 @@ Standard Unix tools, such as \f(CWsed\fP, \f(CWawk\fP, \f(CWPerl\fP
A POSIX-compliant C compiler;
.IP
.IP o
-The grammar generation tools \f(CWbison\fP and \f(CWflex\fP;
-.IP
-.IP o
Support for SYSV IPC, networking and so on\&.
.PP
-Basically a Linux or Apple MacOSX box will do nicely once you make
-sure that \f(CWbison\fP and \f(CWflex\fP are installed\&. To compile and install
+Basically a Linux or Apple MacOSX box will do nicely\&. To compile and install
crossroads, follow these steps\&.
.PP
diff --git a/doc/crossroads.pdf b/doc/crossroads.pdf
Binary files differ.
diff --git a/doc/tips.yo b/doc/tips.yo
@@ -386,6 +386,122 @@ verb(\
LogFormat "%{X-Real-IP}i %l %u %t %D \"%r\" %>s %b" common)
+subsect(Debugging network traffic)
+
+ Incase the traffic between
+ client and backend
+ must be debugged, the statement tt(trafficlog) em(filename) can
+ be issued. This causes the traffic to be dumped in hexadecimal
+ format to the stated filename.
+
+ Traffic sent by the client is prefixed by a bf(C), traffic sent by
+ the back end is prefixed by a bf(B). Below is a sample traffic
+ dump of a browser trying to get a HTML page. The server replies
+ that the page was not modified.
+
+ verb(\
+C 0000 47 45 54 20 68 74 74 70 3a 2f 2f 77 77 77 2e 63 GET http://www.c
+C 0010 73 2e 68 65 6c 73 69 6e 6b 69 2e 66 69 2f 6c 69 s.helsinki.fi/li
+C 0020 6e 75 78 2f 6c 69 6e 75 78 2d 6b 65 72 6e 65 6c nux/linux-kernel
+C 0030 2f 32 30 30 31 2d 34 37 2f 30 34 31 37 2e 68 74 /2001-47/0417.ht
+C 0040 6d 6c 20 48 54 54 50 2f 31 2e 31 0d 0a 43 6f 6e ml HTTP/1.1..Con
+C 0050 6e 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a nection: close..
+.
+. etcetera
+.
+B 0000 48 54 54 50 2f 31 2e 30 20 33 30 34 20 4e 6f 74 HTTP/1.0 304 Not
+B 0010 20 4d 6f 64 69 66 69 65 64 0d 0a 44 61 74 65 3a Modified..Date:
+B 0020 20 54 75 65 2c 20 31 32 20 4a 75 6c 20 32 30 30 Tue, 12 Jul 200
+B 0030 35 20 30 39 3a 34 39 3a 34 37 20 47 4d 54 0d 0a 5 09:49:47 GMT..
+B 0040 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74 65 Content-Type: te
+B 0050 78 74 2f 68 74 6d 6c 3b 20 63 68 61 72 73 65 74 xt/html; charset
+.
+. etcetera
+.)
+
+ Turning on traffic dumps will em(significantly)
+ slow down crossroads.
+
+ Besides tt(trafficlog), there is also a directive
+ tt(throughputlog). This directive also takes one argument, a
+ filename. The file is appended, and the following information is
+ logged:
+
+ itemization(
+ it() The process ID of the crossroads image that serves the
+ TCP connection;
+ it() The time of the request, in seconds and microseconds
+ since start of the run;
+ it() A bf(C) when the request originated at the client, or
+ bf(B) when the request originated at the back end;
+ it() The first 100 bytes of the request.)
+
+ As an example, consider the following (the lines are shortened for
+ brevity and prefixed by line numbers for clarity):
+
+ verb(
+1 0000594 0.000001 C GET http://public.e-tunity.com/index.html...
+2 0000594 0.173713 B HTTP/1.0 200 OK..Date: Fri, 18 Nov 2005 0...
+3 0000594 0.278125 B width="100" bgcolor="#e0e0e0" valign="to...
+4 0000595 0.000001 C GET http://public.e-tunity.com/css/style/...
+5 0000594 0.944339 B /a></td>.. </tr>.</table>.</td><td class...
+6 0000594 0.946356 B smallboxdownl">Download</td>.. <td class...
+7 0000594 0.961102 B td><td class="smallboxodd" valign="top"><...
+8 0000595 0.698215 B HTTP/1.0 304 Not Modified..Date: Fri, 18 ...)
+
+ This tells us that:
+
+ itemization(
+ it() Line 1: PID 594 served a request that originated at
+ the client. The corresponding time is (almost) 0 seconds,
+ so this is really the start of the run.
+ it() Line 2: A back end replied 0.17 seconds later, and
+ 0.28 seconds later, it was still replying (this is the
+ third line, again a bf(B)-type transmission).
+ it() Line 4: PID 595 served a request that originated
+ at the client. Again, the corresponding time is (almost)
+ 0 seconds, since this is the first conversation part of
+ this connection.
+ it() Lines 5 to 7: This is the continuation of line 2. Line 7
+ is the last line of the bf(B) series (not visible from
+ the example, but trust me, it is), so that we may
+ conclude that it took the back end 0.96 seconds to serve
+ the file tt(index.html) requested in line 1.
+ it() Line 8: This is the answer to the client's request of
+ line 4 (you can tell by the process ID number).
+ So the back end took 0.68 seconds to confirm that
+ the stylesheet requested in line 4 wasn't modified.)
+
+ It is also worth while remembering that the start time of a bf(C)
+ request is the time that crossroads sees the activity. Any latency
+ between the true client and crossroads is obviously not
+ included. This is illustrated by the below simple ASCII art:
+
+ verb(
+client ---->---->---->--->*crossroads ====>====>====>
+ \
+ back end
+ /
+client ----<----<----<---< crossroads ====<====<====<
+)
+
+ This simple picture shows a typical HTTP request that originates
+ at a client, travels to crossroads, and is relayed via the back
+ end. The bf(C) entry in a throughput log is the time when
+ crossroads sees the request, indicated by an asterisk. The bf(B)
+ entries are the times that it takes the back end to answer,
+ indicated by tt(===) style lines. Therefore, the true roundtrip
+ time will be longer than the number of seconds that are logged in
+ the throughput log: the latency between client and crossroads
+ isn't included in that measurement.
+
+ Summarizing, the throughput times of a client-back end connection
+ can be analyzed using the directive tt(throughputlog). In a
+ real-world analysis, you'd probably want to write up a script to
+ analyze the output and to compute round trip times. Such scripts
+ are not (yet) included in Crossroads.
+
+
subsect(Configuration examples)
As a general hint, use tt(crossroads sampleconf) to view the most
diff --git a/etc/Makefile.def b/etc/Makefile.def
@@ -3,7 +3,7 @@
# Versioning. This defines the overall version ID and must match the topmost
# entry in the ChangeLog.
-VER = 1.12
+VER = 1.15
# Default config
DEFAULT_CONF = /etc/crossroads.conf
diff --git a/src/Makefile b/src/Makefile
@@ -11,7 +11,8 @@ all:
install: all $(BINDIR)/crossroads
$(BINDIR)/crossroads: crossroads
- install -s crossroads $(BINDIR)
+ cp crossroads $(BINDIR)/
+ strip $(BINDIR)/crossroads
samplerun: all
-./crossroads -c sample.conf stop
@@ -73,8 +74,8 @@ libcrossroads.a: $(OBJ)
distclean: clean
clean:
- rm -f $(OBJ) lexer.c parser.c parser.h libcrossroads.a crossroads \
- usage.h sampleconf.h proxyerror.h
+ rm -f $(OBJ) libcrossroads.a crossroads \
+ usage.h sampleconf.h proxyerror.h
# Extra deps:
usage.o: usage.c usage.h ../etc/Makefile.def
diff --git a/src/ansistamp.c b/src/ansistamp.c
@@ -4,22 +4,17 @@ char *ansistamp (TmType t) {
static char buf[80];
time_t now;
struct tm *tmp;
- double hrs_off;
time (&now);
- if (t == tm_localtime) {
+ if (t == tm_localtime)
tmp = localtime (&now);
- hrs_off = tmp->tm_gmtoff / 3600;
- snprintf (buf, sizeof(buf),
- "%4.4d-%2.2d-%2.2d/%2.2d:%2.2d:%2.2d(%.1f,%s)",
- tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec,
- hrs_off, tmp->tm_zone ? tmp->tm_zone : "UNK");
- } else {
+ 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);
- }
+
+ 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/copysockets.c b/src/copysockets.c
@@ -7,5 +7,5 @@ void copysockets (int clientsock, int serversock) {
* stop itself when either an error is seen, or when no more
* data are there. */
while (1)
- net_copy (clientsock, serversock, TCP_BUFSZ, buf, 1);
+ net_copy (clientsock, serversock, TCP_BUFSZ, buf);
}
diff --git a/src/crossroads.h b/src/crossroads.h
@@ -133,7 +133,7 @@ typedef struct { /* Backend description */
char **setserverheader; /* .. server hdrs to SET */
int nsetserverheader; /* .. table size */
char **appendserverheader; /* .. server hdrs to APPEND */
- int nappendserverheader;
+ int nappendserverheader; /* .. table size */
} Backend;
typedef struct { /* Service description */
@@ -218,6 +218,8 @@ typedef enum { /* HTTP version */
#endif
EXTERN Service *activeservice; /* target service of a daemon */
+EXTERN unsigned char *clbuf; /* client socket input buffer */
+EXTERN unsigned clbufpos, clbufmax; /* .. position & bytes */
EXTERN char *client_ip; /* connected client */
EXTERN char *config_file; /* config to parse */
EXTERN int current_backend; /* of a given service */
@@ -238,6 +240,8 @@ EXTERN int relevant_sigs[]; /* relevant signals */
EXTERN int semid; /* semaphore ID */
EXTERN Service *service; /* service descriptions */
EXTERN Servicereport *servicereport; /* reporter in shared mem */
+EXTERN unsigned char *srbuf; /* server socket input buffer */
+EXTERN unsigned srbufpos, srbufmax; /* .. position & bytes */
EXTERN char *state_to_string_map[]; /* backend states as strings */
EXTERN FILE *yyin; /* config file handle */
EXTERN int yylineno; /* input line number */
@@ -266,17 +270,19 @@ extern HttpConnectionType http_header_connectiontype (HttpHeader *h);
extern void http_header_free (HttpHeader *msg);
extern int http_header_hascookie (HttpHeader *m, char const *cookie);
extern double http_header_httpver (HttpHeader *h);
-extern unsigned char const *http_header_val (HttpHeader *m, char const *hdr);
+extern void http_header_removeheader (HttpHeader *h, char const *hdr);
+extern unsigned char const *http_header_val (HttpHeader *h, char const *hdr);
extern HttpHeader *http_header_new (void);
-extern void http_header_read (HttpHeader *m, int srcsock, int dstsock,
- CopyDirection dir);
+extern void http_header_read (HttpHeader *m, int srcsock, CopyDirection dir);
extern void http_header_setheader (HttpHeader *m, char const *hdr);
-extern void http_header_write (HttpHeader *m, int sock, int isclient);
+extern void http_header_write (HttpHeader *m, int sock, CopyDirection dir);
extern void http_serve (int clientsock);
extern int http_serversocket (HttpHeader *m, int *is_continuation);
-extern int http_write (int sock, int isclient, unsigned char const *buf,
+extern int http_write (int sock, CopyDirection dir, unsigned char const *buf,
unsigned buflen);
extern void incr_client_count (void);
+extern int is_hex_digit (char ch);
+extern int is_space (char ch);
extern int init_sockaddr (struct sockaddr_in *name,
const char *hostname, int port);
extern void interrupt (int sig);
@@ -292,7 +298,12 @@ extern void mark_activity (unsigned long long nbytes,
extern void msg (char const *fmt, ...);
extern void msgdumpbuf (unsigned char const *buf, int buflen);
extern unsigned net_copy (int clientsock, int serversock, unsigned maxbytes,
- unsigned char *buf, int write_too);
+ unsigned char *buf);
+extern unsigned net_read (int sock, unsigned maxbytes, unsigned char *buf,
+ int is_client);
+extern unsigned char *net_buffer (CopyDirection dir, unsigned *sz);
+extern unsigned char *net_bufread (int sock, unsigned maxbytes,
+ unsigned *nreadp, int is_client);
extern int net_write (int sock, unsigned char const *buf, unsigned len,
int is_client);
extern void restart (int ac, char **av);
diff --git a/src/httpcopy.c b/src/httpcopy.c
@@ -1,35 +1,53 @@
#include "crossroads.h"
static void copy (int src, int dst, int dir, unsigned tot) {
- unsigned ncopied = 0;
- unsigned char buf[TCP_BUFSZ];
+ unsigned ncopied = 0, to_copy, bytes;
+ unsigned char *buf;
while (ncopied < tot) {
- if (dir == dir_client_to_server)
- ncopied += net_copy (src, dst, TCP_BUFSZ, buf, 1);
- else
- ncopied += net_copy (dst, src, TCP_BUFSZ, buf, 1);
+ /* 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, int isclient) {
+unsigned getchunk (int sock, int dest, CopyDirection dir) {
unsigned ret = 0;
- unsigned char ch;
- char *buf = 0;
+ unsigned char *cp;
+ char *hexbuf = 0;
+ int in_number = 1;
- /* We match <hex-chunksize> <any-mush> [\r] \n
+ /* We match
+ * <hex-chunksize> <any-mush> [\r] \n
* while copying all to the other socket, and return the
* chunk size */
while (1) {
- net_copy (sock, dest, 1, &ch, 1);
-
- if (ch == '\n') {
- sscanf (buf, "%x", &ret);
- free (buf);
+ 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);
}
- else
- buf = xstrcatch (buf, ch);
+ if (in_number) {
+ if (is_hex_digit (*cp))
+ hexbuf = xstrcatch (hexbuf, *cp);
+ else
+ in_number = 0;
+ }
}
}
@@ -44,28 +62,38 @@ void http_copy (HttpHeader *h, int src, int dst, CopyDirection dir) {
/* Check in what 'mode' we are.
* We know 3 modes:
- * - Content-Length is supplied: we copy that # of bytes
* - Transfer-Encoding is chunked: we copy chunks
- * - None of the above: cpio back/forth until one stops
+ * - 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, "content-length")) &&
- 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 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);
- while ( (nbytes = getchunk(src, dst, dir == dir_client_to_server)) )
- /* Copy the chunk, then copy \r\n */
- copy (src, dst, dir, nbytes + 2);
} else
msg ("Service %s: no body to send", activeservice->name);
}
diff --git a/src/httpheaderappendheader.c b/src/httpheaderappendheader.c
@@ -12,7 +12,7 @@ void http_header_appendheader (HttpHeader *m, char const *h) {
*cp = 0;
cp++;
- while (isspace (*cp) || *cp == ':')
+ while (is_space (*cp) || *cp == ':')
cp++;
exp = http_expand_header (cp);
diff --git a/src/httpheaderread.c b/src/httpheaderread.c
@@ -16,20 +16,20 @@ static void debughdr (HttpHeader *h) {
#define SHOWHEADERS(h)
#endif
-void http_header_read (HttpHeader *h, int srcsock, int dstsock,
- CopyDirection dir) {
- unsigned char ch;
+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);
- net_copy (srcsock, dstsock, 1, &ch, 0);
- if (ch == '\r')
+ if (*cp == '\r')
continue;
- if (ch == '\n') {
+ if (*cp == '\n') {
if (last_is_nl && h->nheader)
break;
last_is_nl++;
@@ -41,8 +41,8 @@ void http_header_read (HttpHeader *h, int srcsock, int dstsock,
h->nheader++;
at_start = 0;
}
- h->header[h->nheader - 1] = xstrcatch (h->header[h->nheader - 1], ch); last_is_nl = 0;
- // SHOWHEADERS(h);
+ 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
@@ -0,0 +1,17 @@
+#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/httpheaderval.c b/src/httpheaderval.c
@@ -11,7 +11,7 @@ unsigned char const *http_header_val (HttpHeader *m, char const *what) {
ret = (unsigned char const *) m->header[i] + strlen(what);
if (*ret == ':') {
ret++;
- while (isspace (*ret))
+ while (is_space (*ret))
ret++;
return (ret);
}
diff --git a/src/httpheaderwrite.c b/src/httpheaderwrite.c
@@ -1,19 +1,20 @@
#include "crossroads.h"
-void http_header_write (HttpHeader *m, int sock, int isclient) {
+void http_header_write (HttpHeader *m, int sock, CopyDirection dir) {
int i;
msg ("Service %s: Sending HTTP headers to %s",
- activeservice->name, isclient ? "client" : "server");
+ activeservice->name,
+ 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, isclient, (unsigned char const *) m->header[i],
+ http_write (sock, dir, (unsigned char const *) m->header[i],
strlen(m->header[i]));
- http_write (sock, isclient, (unsigned char const *) "\r\n", 2);
+ http_write (sock, dir, (unsigned char const *) "\r\n", 2);
}
- http_write (sock, isclient, (unsigned char const *) "\r\n", 2);
+ http_write (sock, dir, (unsigned char const *) "\r\n", 2);
}
diff --git a/src/httpserve.c b/src/httpserve.c
@@ -3,7 +3,9 @@
void http_serve (int clientsock) {
int serversock = -1, is_continuation, i;
HttpHeader *clientreq, *serverresp;
- int client_persisting = 1, server_persisting = 1;
+ int client_persisting, server_persisting;
+ unsigned char *cp;
+ unsigned size;
/* Fork off a servicer if we're in daemon mode. */
if (fork_tcp_servicer(-1))
@@ -23,10 +25,12 @@ void http_serve (int clientsock) {
*/
while (1) {
+ /* 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, serversock,
- dir_client_to_server);
+ http_header_read (clientreq, clientsock, dir_client_to_server);
/* Determine the back end if necessary. */
if (serversock == -1) {
@@ -73,17 +77,31 @@ void http_serve (int clientsock) {
}
/* Send client's headers to the back end. */
- http_header_write (clientreq, serversock, 0);
+ 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, clientsock,
- dir_server_to_client);
+ http_header_read (serverresp, serversock, dir_server_to_client);
- /* Put all client-directed headers in place. */
+ /* 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++)
@@ -100,6 +118,20 @@ void http_serve (int clientsock) {
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) {
@@ -119,27 +151,35 @@ void http_serve (int clientsock) {
}
/* Send server headers to the client. */
- http_header_write (serverresp, clientsock, 1);
+ http_header_write (serverresp, clientsock, dir_server_to_client);
- /* Copy body from 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 (serverresp);
http_header_free (clientreq);
+ http_header_free (serverresp);
- /* Should we loop around? */
- if (!client_persisting || !server_persisting)
+ /* 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..",
+ }
+
+ msg ("Service %s: Analyzing following requests over same TCP link",
activeservice->name);
}
/* Copy through all that arrives on back end or client.
* This doesn't return... */
- msg ("Service %s: HTTP service now TCP copying",
+ msg ("Service %s: HTTP service done analyzing, entering copy-thru mode",
activeservice->name);
+
+ /* This doesn't return */
copysockets (clientsock, serversock);
+
}
diff --git a/src/httpwrite.c b/src/httpwrite.c
@@ -1,12 +1,12 @@
#include "crossroads.h"
-int http_write (int sock, int isclient, unsigned char const *buf,
+int http_write (int sock, CopyDirection dir, unsigned char const *buf,
unsigned buflen) {
int nwritten, totwritten = 0;
while (totwritten < buflen) {
nwritten = net_write (sock, buf + totwritten, buflen - totwritten,
- isclient);
+ dir == dir_client_to_server);
totwritten += nwritten;
}
return (0);
diff --git a/src/ishexdigit.c b/src/ishexdigit.c
@@ -0,0 +1,10 @@
+#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
@@ -0,0 +1,10 @@
+#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
@@ -0,0 +1,2233 @@
+#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 57
+#define YY_END_OF_BUFFER 58
+static yyconst short int yy_accept[360] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 58, 46, 44, 45,
+ 46, 46, 43, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 55, 56, 54, 55, 55, 53, 50, 49, 50, 44,
+ 0, 1, 47, 0, 43, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 41,
+ 42, 40, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 0, 51, 0, 52,
+ 48, 0, 2, 42, 25, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 40, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 27, 42, 42, 42, 6, 5, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 24, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 14, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 4, 42, 42, 42, 20,
+ 42, 42, 42, 42, 42, 42, 18, 42, 42, 15,
+
+ 42, 42, 42, 7, 42, 42, 42, 42, 13, 42,
+ 42, 42, 42, 8, 9, 42, 42, 21, 42, 42,
+ 42, 42, 42, 42, 42, 42, 3, 42, 42, 42,
+ 42, 42, 42, 10, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 32, 31, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 19, 42, 42, 42, 42, 42, 17, 42, 42,
+ 42, 26, 42, 29, 42, 42, 42, 42, 42, 42,
+
+ 42, 30, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 16, 42, 42, 42, 42, 33,
+ 42, 42, 42, 42, 42, 22, 42, 42, 42, 42,
+ 42, 28, 42, 42, 42, 42, 42, 12, 42, 42,
+ 42, 34, 37, 42, 42, 42, 42, 35, 38, 42,
+ 42, 42, 23, 42, 42, 11, 36, 39, 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[367] =
+ { 0,
+ 0, 0, 34, 39, 44, 45, 390, 391, 47, 391,
+ 386, 46, 378, 0, 40, 45, 361, 40, 373, 355,
+ 371, 357, 44, 356, 46, 53, 40, 364, 363, 362,
+ 391, 391, 391, 373, 370, 391, 391, 391, 367, 75,
+ 372, 391, 391, 371, 363, 0, 356, 336, 343, 354,
+ 343, 66, 342, 351, 336, 340, 340, 332, 327, 0,
+ 342, 56, 342, 330, 332, 324, 324, 56, 330, 332,
+ 324, 65, 324, 322, 328, 319, 342, 391, 339, 391,
+ 391, 342, 391, 72, 0, 327, 321, 326, 315, 309,
+ 311, 317, 312, 323, 308, 307, 304, 305, 316, 317,
+
+ 298, 300, 297, 310, 304, 299, 291, 73, 300, 306,
+ 294, 301, 301, 300, 302, 296, 0, 291, 296, 287,
+ 74, 281, 285, 281, 292, 271, 289, 270, 291, 273,
+ 285, 0, 275, 279, 284, 0, 0, 272, 265, 280,
+ 72, 272, 277, 276, 270, 260, 272, 0, 263, 268,
+ 266, 258, 269, 259, 257, 256, 256, 267, 262, 261,
+ 262, 0, 246, 247, 249, 250, 257, 247, 249, 241,
+ 240, 252, 245, 237, 229, 228, 243, 240, 231, 229,
+ 241, 225, 75, 240, 236, 0, 237, 223, 224, 0,
+ 221, 235, 236, 223, 216, 229, 0, 220, 218, 0,
+
+ 226, 225, 209, 0, 79, 220, 224, 86, 0, 213,
+ 220, 213, 218, 0, 0, 219, 212, 0, 211, 211,
+ 212, 212, 200, 198, 207, 211, 0, 199, 206, 196,
+ 191, 193, 196, 0, 188, 187, 188, 194, 186, 183,
+ 186, 185, 186, 191, 193, 190, 177, 184, 183, 173,
+ 174, 175, 170, 168, 172, 162, 176, 175, 177, 161,
+ 171, 166, 165, 163, 167, 157, 0, 0, 161, 160,
+ 164, 163, 160, 154, 150, 160, 161, 160, 151, 158,
+ 148, 0, 143, 156, 156, 149, 139, 0, 151, 150,
+ 145, 0, 142, 0, 151, 150, 132, 133, 135, 138,
+
+ 141, 0, 131, 139, 142, 141, 136, 126, 135, 134,
+ 129, 128, 118, 122, 0, 120, 116, 127, 126, 0,
+ 122, 123, 122, 121, 120, 0, 119, 106, 102, 116,
+ 115, 0, 103, 102, 116, 115, 101, 0, 113, 97,
+ 96, 0, 0, 107, 106, 90, 97, 0, 0, 89,
+ 88, 70, 0, 70, 36, 0, 0, 0, 391, 107,
+ 109, 111, 38, 113, 115, 117
+ } ;
+
+static yyconst short int yy_def[367] =
+ { 0,
+ 359, 1, 360, 360, 361, 361, 359, 359, 359, 359,
+ 362, 359, 359, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 359, 359, 359, 364, 365, 359, 359, 359, 359, 359,
+ 362, 359, 359, 366, 359, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 364, 359, 365, 359,
+ 359, 366, 359, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 0, 359,
+ 359, 359, 359, 359, 359, 359
+ } ;
+
+static yyconst short int yy_nxt[428] =
+ { 0,
+ 8, 9, 10, 9, 8, 11, 8, 8, 12, 13,
+ 8, 14, 15, 16, 17, 18, 14, 19, 14, 20,
+ 14, 14, 14, 21, 22, 23, 24, 25, 26, 27,
+ 14, 28, 29, 14, 30, 14, 32, 33, 34, 46,
+ 35, 32, 33, 34, 36, 35, 38, 38, 40, 36,
+ 40, 39, 39, 43, 44, 47, 54, 50, 65, 71,
+ 55, 61, 66, 358, 48, 51, 49, 72, 62, 68,
+ 56, 67, 69, 100, 73, 63, 40, 112, 40, 52,
+ 89, 90, 70, 107, 101, 108, 118, 142, 171, 212,
+ 154, 91, 172, 230, 92, 113, 155, 357, 231, 356,
+
+ 119, 143, 234, 213, 355, 354, 235, 31, 31, 37,
+ 37, 41, 41, 77, 77, 79, 79, 82, 82, 353,
+ 352, 351, 350, 349, 348, 347, 346, 345, 344, 343,
+ 342, 341, 340, 339, 338, 337, 336, 335, 334, 333,
+ 332, 331, 330, 329, 328, 327, 326, 325, 324, 323,
+ 322, 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, 234, 276, 275, 274,
+
+ 273, 272, 271, 270, 269, 268, 267, 266, 265, 264,
+ 263, 262, 261, 260, 259, 258, 257, 256, 255, 254,
+ 253, 252, 251, 250, 249, 248, 247, 246, 245, 244,
+ 243, 242, 241, 240, 239, 238, 237, 236, 233, 232,
+ 229, 228, 227, 226, 225, 224, 223, 222, 221, 220,
+ 219, 218, 217, 216, 215, 214, 211, 210, 209, 208,
+ 207, 206, 205, 204, 203, 202, 201, 200, 199, 198,
+ 197, 196, 195, 194, 193, 192, 191, 190, 189, 188,
+ 187, 186, 185, 184, 183, 182, 181, 180, 179, 178,
+ 177, 176, 175, 174, 173, 170, 169, 168, 167, 166,
+
+ 165, 60, 164, 163, 162, 161, 160, 159, 158, 157,
+ 156, 153, 152, 151, 150, 149, 148, 117, 147, 146,
+ 145, 144, 141, 140, 139, 138, 137, 136, 135, 134,
+ 133, 132, 131, 130, 129, 128, 127, 126, 125, 124,
+ 123, 122, 121, 120, 83, 80, 78, 117, 116, 115,
+ 114, 111, 110, 109, 106, 105, 104, 103, 102, 60,
+ 99, 98, 97, 96, 95, 94, 93, 88, 87, 86,
+ 85, 84, 45, 83, 42, 81, 80, 78, 76, 75,
+ 74, 64, 60, 59, 58, 57, 53, 45, 42, 359,
+ 7, 359, 359, 359, 359, 359, 359, 359, 359, 359,
+
+ 359, 359, 359, 359, 359, 359, 359, 359, 359, 359,
+ 359, 359, 359, 359, 359, 359, 359, 359, 359, 359,
+ 359, 359, 359, 359, 359, 359, 359
+ } ;
+
+static yyconst short int yy_chk[428] =
+ { 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, 363,
+ 3, 4, 4, 4, 3, 4, 5, 6, 9, 4,
+ 9, 5, 6, 12, 12, 15, 18, 16, 25, 27,
+ 18, 23, 25, 355, 15, 16, 15, 27, 23, 26,
+ 18, 25, 26, 62, 27, 23, 40, 72, 40, 16,
+ 52, 52, 26, 68, 62, 68, 84, 108, 141, 183,
+ 121, 52, 141, 205, 52, 72, 121, 354, 205, 352,
+
+ 84, 108, 208, 183, 351, 350, 208, 360, 360, 361,
+ 361, 362, 362, 364, 364, 365, 365, 366, 366, 347,
+ 346, 345, 344, 341, 340, 339, 337, 336, 335, 334,
+ 333, 331, 330, 329, 328, 327, 325, 324, 323, 322,
+ 321, 319, 318, 317, 316, 314, 313, 312, 311, 310,
+ 309, 308, 307, 306, 305, 304, 303, 301, 300, 299,
+ 298, 297, 296, 295, 293, 291, 290, 289, 287, 286,
+ 285, 284, 283, 281, 280, 279, 278, 277, 276, 275,
+ 274, 273, 272, 271, 270, 269, 266, 265, 264, 263,
+ 262, 261, 260, 259, 258, 257, 256, 255, 254, 253,
+
+ 252, 251, 250, 249, 248, 247, 246, 245, 244, 243,
+ 242, 241, 240, 239, 238, 237, 236, 235, 233, 232,
+ 231, 230, 229, 228, 226, 225, 224, 223, 222, 221,
+ 220, 219, 217, 216, 213, 212, 211, 210, 207, 206,
+ 203, 202, 201, 199, 198, 196, 195, 194, 193, 192,
+ 191, 189, 188, 187, 185, 184, 182, 181, 180, 179,
+ 178, 177, 176, 175, 174, 173, 172, 171, 170, 169,
+ 168, 167, 166, 165, 164, 163, 161, 160, 159, 158,
+ 157, 156, 155, 154, 153, 152, 151, 150, 149, 147,
+ 146, 145, 144, 143, 142, 140, 139, 138, 135, 134,
+
+ 133, 131, 130, 129, 128, 127, 126, 125, 124, 123,
+ 122, 120, 119, 118, 116, 115, 114, 113, 112, 111,
+ 110, 109, 107, 106, 105, 104, 103, 102, 101, 100,
+ 99, 98, 97, 96, 95, 94, 93, 92, 91, 90,
+ 89, 88, 87, 86, 82, 79, 77, 76, 75, 74,
+ 73, 71, 70, 69, 67, 66, 65, 64, 63, 61,
+ 59, 58, 57, 56, 55, 54, 53, 51, 50, 49,
+ 48, 47, 45, 44, 41, 39, 35, 34, 30, 29,
+ 28, 24, 22, 21, 20, 19, 17, 13, 11, 7,
+ 359, 359, 359, 359, 359, 359, 359, 359, 359, 359,
+
+ 359, 359, 359, 359, 359, 359, 359, 359, 359, 359,
+ 359, 359, 359, 359, 359, 359, 359, 359, 359, 359,
+ 359, 359, 359, 359, 359, 359, 359
+ } ;
+
+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 600 "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 754 "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 >= 360 )
+ 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] != 391 );
+
+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 33 "lexer.l"
+{
+ lmsg ("comment");
+ yylineno++;
+ }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 37 "lexer.l"
+{
+ lmsg ("service");
+ return (SERVICE);
+ }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 41 "lexer.l"
+{
+ lmsg ("bindto");
+ BEGIN (stringstate);
+ free (laststring);
+ laststring = 0;
+ return (BINDTO);
+ }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 48 "lexer.l"
+{
+ lmsg ("port");
+ return (PORT);
+ }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 52 "lexer.l"
+{
+ lmsg ("over");
+ return (OVER);
+ }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 56 "lexer.l"
+{
+ lmsg ("shmkey");
+ return (SHMKEY);
+ }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 60 "lexer.l"
+{
+ lmsg ("backend");
+ return (BACKEND);
+ }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 64 "lexer.l"
+{
+ lmsg ("backlog");
+ return (BACKLOG);
+ }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 68 "lexer.l"
+{
+ lmsg ("verbosity");
+ return (VERBOSITY);
+ }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 72 "lexer.l"
+{
+ lmsg ("connectiontimeout");
+ return (CONNECTIONTIMEOUT);
+ }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 76 "lexer.l"
+{
+ lmsg ("maxconnections");
+ return (MAXCONNECTIONS);
+ }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 80 "lexer.l"
+{
+ lmsg ("weight");
+ return (WEIGHT);
+ }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 84 "lexer.l"
+{
+ lmsg ("decay");
+ return (DECAY);
+ }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 88 "lexer.l"
+{
+ lmsg ("server");
+ BEGIN (stringstate);
+ free (laststring);
+ laststring = 0;
+ return (SERVER);
+ }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 95 "lexer.l"
+{
+ lmsg ("dispatchmode");
+ return (DISPATCHMODE);
+ }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 99 "lexer.l"
+{
+ lmsg ("roundrobin");
+ return (ROUNDROBIN);
+ }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 103 "lexer.l"
+{
+ lmsg ("random");
+ return (RANDOM);
+ }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 107 "lexer.l"
+{
+ lmsg ("byduration");
+ return (BYDURATION);
+ }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 111 "lexer.l"
+{
+ lmsg ("bysize");
+ return (BYSIZE);
+ }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 115 "lexer.l"
+{
+ lmsg ("byorder");
+ return (BYORDER);
+ }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 119 "lexer.l"
+{
+ lmsg ("byconnections");
+ return (BYCONNECTIONS);
+ }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 123 "lexer.l"
+{
+ lmsg ("revivinginterval");
+ return (REVIVINGINTERVAL);
+ }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 127 "lexer.l"
+{
+ lmsg ("type");
+ return (TYPE);
+ }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 131 "lexer.l"
+{
+ lmsg ("any");
+ return (ANY);
+ }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 135 "lexer.l"
+{
+ lmsg ("stickyhttp");
+ warning ("The 'stickyhttp protocol "
+ "is obsolte.\n"
+ "You should change to 'http'.");
+ return (HTTP);
+ }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 142 "lexer.l"
+{
+ lmsg ("http");
+ return (HTTP);
+ }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 146 "lexer.l"
+{
+ lmsg ("throughputlog");
+ BEGIN (stringstate);
+ free (laststring);
+ laststring = 0;
+ return (THROUGHPUTLOG);
+ }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 153 "lexer.l"
+{
+ lmsg ("trafficlog");
+ BEGIN (stringstate);
+ free (laststring);
+ laststring = 0;
+ return (TRAFFICLOG);
+ }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 160 "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 31:
+YY_RULE_SETUP
+#line 171 "lexer.l"
+{
+ lmsg ("onsuccess");
+ BEGIN (stringstate);
+ free (laststring);
+ laststring = 0;
+ return (ONSUCCESS);
+ }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 178 "lexer.l"
+{
+ lmsg ("onfailure");
+ BEGIN (stringstate);
+ free (laststring);
+ laststring = 0;
+ return (ONFAILURE);
+ }
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 185 "lexer.l"
+{
+ lmsg ("stickycookie");
+ BEGIN (stringstate);
+ free (laststring);
+ laststring = 0;
+ return (STICKYCOOKIE);
+ }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 192 "lexer.l"
+{
+ lmsg ("addclientheader");
+ BEGIN (stringstate);
+ free (laststring);
+ laststring = 0;
+ return (ADDCLIENTHEADER);
+ }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 199 "lexer.l"
+{
+ lmsg ("setclientheader");
+ BEGIN (stringstate);
+ free (laststring);
+ laststring = 0;
+ return (SETCLIENTHEADER);
+ }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 206 "lexer.l"
+{
+ lmsg ("appendclientheader");
+ BEGIN (stringstate);
+ free (laststring);
+ laststring = 0;
+ return (APPENDCLIENTHEADER);
+ }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 213 "lexer.l"
+{
+ lmsg ("addserverheader");
+ BEGIN (stringstate);
+ free (laststring);
+ laststring = 0;
+ return (ADDSERVERHEADER);
+ }
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 220 "lexer.l"
+{
+ lmsg ("setserverheader");
+ BEGIN (stringstate);
+ free (laststring);
+ laststring = 0;
+ return (SETSERVERHEADER);
+ }
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 227 "lexer.l"
+{
+ lmsg ("appendserverheader");
+ BEGIN (stringstate);
+ free (laststring);
+ laststring = 0;
+ return (APPENDSERVERHEADER);
+ }
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 234 "lexer.l"
+{
+ lmsg ("on");
+ return (ON);
+ }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 238 "lexer.l"
+{
+ lmsg ("off");
+ return (OFF);
+ }
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 242 "lexer.l"
+{
+ llmsg ("identifier", yytext);
+ return (IDENTIFIER);
+ }
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 246 "lexer.l"
+{
+ llmsg ("number", yytext);
+ return (NUMBER);
+ }
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 250 "lexer.l"
+{
+ lmsg ("space(s)");
+ }
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 253 "lexer.l"
+{
+ lmsg ("newline");
+ yylineno++;
+ }
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 257 "lexer.l"
+{
+ llmsg ("lone char", yytext);
+ return (*yytext);
+ }
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 261 "lexer.l"
+{
+ lmsg ("C-comment starts");
+ BEGIN(commentstate);
+ }
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 265 "lexer.l"
+{
+ lmsg ("C-comment ends");
+ BEGIN(0);
+ }
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 269 "lexer.l"
+{
+ yylineno++;
+ }
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 272 "lexer.l"
+;
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 274 "lexer.l"
+{
+ llmsg ("string part", yytext);
+ laststring = xstrcat (laststring,
+ yytext + 1);
+ laststring[strlen(laststring) - 1] = 0;
+ }
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 280 "lexer.l"
+{
+ llmsg ("string part", yytext);
+ laststring = xstrcat (laststring,
+ yytext + 1);
+ laststring[strlen(laststring) - 1] = 0;
+ }
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 286 "lexer.l"
+{
+ BEGIN (0);
+ unput (';');
+ llmsg ("string", laststring);
+ return (STRING);
+ }
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 292 "lexer.l"
+{
+ if (laststring) {
+ laststring = xstrcat (laststring,
+ yytext);
+ llmsg ("string part", yytext);
+ }
+ }
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 299 "lexer.l"
+{
+ llmsg ("string part", yytext);
+ laststring = xstrcat (laststring,
+ yytext);
+ }
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 304 "lexer.l"
+{
+ lmsg ("string part: ERROR - newline");
+ error ("Parse eror at line %d: "
+ "unterminated string, ';' "
+ "expected\n", yylineno + 1);
+ }
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 310 "lexer.l"
+ECHO;
+ YY_BREAK
+#line 1346 "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 >= 360 )
+ 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 >= 360 )
+ 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 == 359);
+
+ 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 310 "lexer.l"
diff --git a/src/netbuffer.c b/src/netbuffer.c
@@ -0,0 +1,29 @@
+#include "crossroads.h"
+
+unsigned char *net_buffer (CopyDirection dir, unsigned *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
@@ -0,0 +1,55 @@
+#include "crossroads.h"
+
+unsigned char *net_bufread (int sock, unsigned max, unsigned *nread,
+ int is_client) {
+ unsigned char *buf;
+ unsigned *bufpos, *bufmax, rest;
+ unsigned char *ret;
+
+ /* Make sure we have the buffers. */
+ if (!clbuf) {
+ clbuf = xmalloc (TCP_BUFSZ);
+ srbuf = xmalloc (TCP_BUFSZ);
+ clbufmax = srbufmax = 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 %u 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 = 0;
+ }
+
+ return (ret);
+}
diff --git a/src/netcopy.c b/src/netcopy.c
@@ -1,7 +1,6 @@
#include "crossroads.h"
-unsigned net_copy (int cl, int sr, unsigned max, unsigned char *buf,
- int write_too) {
+unsigned net_copy (int cl, int sr, unsigned max, unsigned char *buf) {
fd_set readset, exset;
struct timeval tv, *tvp, tv1, tv2;
int nfd;
@@ -9,23 +8,15 @@ unsigned net_copy (int cl, int sr, unsigned max, unsigned char *buf,
CopyDirection dir;
double microsec;
- /*
- msg ("Service %s: Network copy between sockets %d and %d (%u bytes max), "
- "write flag: %d",
- activeservice->name, cl, sr, max, write_too);
- */
-
/* Prepare select() sets */
FD_ZERO (&readset);
FD_ZERO (&exset);
FD_SET (cl, &readset);
FD_SET (cl, &exset);
- if (sr > 0) {
- FD_SET (sr, &readset);
- FD_SET (sr, &exset);
- }
-
+ FD_SET (sr, &readset);
+ FD_SET (sr, &exset);
+
/* Prepare timout state */
if (activeservice->connectiontimeout) {
tv.tv_sec = activeservice->connectiontimeout;
@@ -51,7 +42,7 @@ unsigned net_copy (int cl, int sr, unsigned max, unsigned char *buf,
log_activity_end();
error ("Service %s: client exception", activeservice->name);
}
- if (sr > 0 && FD_ISSET (sr, &exset)) {
+ if (FD_ISSET (sr, &exset)) {
decr_client_count();
log_activity_end();
mark_activity (0, 0, st_unavailable);
@@ -59,14 +50,12 @@ unsigned net_copy (int cl, int sr, unsigned max, unsigned char *buf,
}
/* Do the read. */
- if (sr > 0 && FD_ISSET (sr, &readset))
+ 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);
+ nread = read (dir == dir_client_to_server ? cl : sr, buf, max);
if (nread < 1) {
if (nread < 0) {
if (dir == dir_server_to_client)
@@ -76,46 +65,38 @@ unsigned net_copy (int cl, int sr, unsigned max, unsigned char *buf,
dir == dir_client_to_server ? "client" : "server");
} else {
msg ("Service %s: %s signals end of data",
- activeservice->name,
+ 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. */
- if (write_too) {
- totwritten = 0;
- while (totwritten < nread) {
- nwritten = write (dir == dir_client_to_server ? sr : cl,
- buf + totwritten,
- nread - totwritten);
- if (nwritten < 1) {
- if (dir == dir_client_to_server)
- mark_activity (0, 0, st_unavailable);
- decr_client_count();
- log_activity_end();
- error ("Service %s: write error when sending data to %s",
- dir == dir_client_to_server ? "server" : "client");
- }
- totwritten += nwritten;
+ totwritten = 0;
+ while (totwritten < nread) {
+ nwritten = write (dir == dir_client_to_server ? sr : cl,
+ buf + totwritten,
+ nread - totwritten);
+ if (nwritten < 1) {
+ if (dir == dir_client_to_server)
+ mark_activity (0, 0, st_unavailable);
+ decr_client_count();
+ log_activity_end();
+ error ("Service %s: write error when sending data to %s",
+ dir == dir_client_to_server ? "server" : "client");
}
+ totwritten += nwritten;
}
-
+
gettimeofday (&tv2, 0);
microsec = ( (tv2.tv_sec * 1000000 + tv2.tv_usec) -
(tv1.tv_sec * 1000000 + tv1.tv_usec) );
- /*
- msg ("Service %s: shuttled %u bytes in %g sec",
- activeservice->name,
- totwritten, microsec / 1000000);
- */
-
+
mark_activity (totwritten, microsec / 1000000, st_intermediate);
return (nread);
-}
-
+}
diff --git a/src/netread.c b/src/netread.c
@@ -0,0 +1,75 @@
+#include "crossroads.h"
+
+unsigned net_read (int sock, unsigned max, unsigned char *buf, int is_client) {
+ fd_set readset, exset;
+ struct timeval tv, *tvp, tv1, tv2;
+ int nfd;
+ unsigned 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 - 1);
+ if (nread < 1) {
+ if (nread < 0) {
+ mark_activity (0, 0, is_client ? st_available : st_unavailable);
+ error ("Service %s: read error when getting data from %s",
+ activeservice->name, desc);
+ } 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,5 +1,12 @@
#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, unsigned buflen,
int is_client) {
int ret, nfd;
@@ -7,6 +14,23 @@ int net_write (int sock, unsigned char const *buf, unsigned buflen,
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);
@@ -49,11 +73,6 @@ int net_write (int sock, unsigned char const *buf, unsigned buflen,
/* We can write! */
ret = write (sock, buf, buflen);
- /*
- msg ("Network write (status %d): tried to send %u bytes to %s",
- ret, buflen, is_client ? "client" : "server");
- */
-
/* Check for finished / errors */
if (ret < 1) {
if (ret < 0 && !is_client)
@@ -71,11 +90,6 @@ int net_write (int sock, unsigned char const *buf, unsigned buflen,
(tv1.tv_sec * 1000000 + tv1.tv_usec) );
mark_activity (ret, microsec / 1000000, st_intermediate);
- /*
- msg ("Service %s: sent %u bytes to %s (%-10s...)",
- activeservice->name, ret, is_client ? "client" : "server", buf);
- */
-
/* Signal caller how many bytes were written. */
return (ret);
}
diff --git a/src/parser.c b/src/parser.c
@@ -0,0 +1,2231 @@
+/* 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 ONSUCCESS 271
+# define ONFAILURE 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
+
+#line 3 "parser.y"
+
+/* Prologue */
+#include "crossroads.h"
+
+#define YYSTYPE Confsets
+
+/* 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);
+}
+
+/* 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);
+}
+
+/* Temp vars */
+static int i; /* Loop counter */
+static Backend cur_backend; /* Storage for a handled backend */
+static Service cur_service; /* Storage for a handled service */
+#ifndef YYSTYPE
+# define YYSTYPE int
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+
+
+#define YYFINAL 165
+#define YYFLAG -32768
+#define YYNTBASE 46
+
+/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */
+#define YYTRANSLATE(x) ((unsigned)(x) <= 296 ? yytranslate[x] : 113)
+
+/* 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, 45,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 43, 2, 44, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 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
+};
+
+#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, 51, 55, 58, 61, 64, 69, 71, 73, 78,
+ 81, 82, 85, 88, 90, 92, 94, 96, 98, 100,
+ 104, 108, 112, 116, 120, 124, 127, 129, 131, 137,
+ 140, 143, 145, 148, 150, 152, 154, 156, 158, 160,
+ 162, 164, 166, 168, 170, 172, 174, 176, 178, 180,
+ 182, 187, 191, 195, 197, 201, 205, 209, 213, 216,
+ 219, 223, 226, 230, 234, 238, 242, 246, 250, 253,
+ 254, 255, 256, 257, 258, 259, 260, 261, 262, 263,
+ 264, 265, 266, 267, 268
+};
+static const short yyrhs[] =
+{
+ 47, 46, 0, 47, 0, 48, 49, 43, 50, 44,
+ 0, 101, 3, 0, 109, 4, 0, 50, 51, 0,
+ 51, 0, 103, 52, 0, 53, 0, 54, 0, 58,
+ 0, 60, 0, 65, 0, 66, 0, 67, 0, 68,
+ 0, 69, 0, 70, 0, 73, 0, 5, 56, 57,
+ 0, 31, 55, 57, 0, 111, 19, 0, 99, 6,
+ 0, 104, 45, 0, 8, 105, 59, 57, 0, 10,
+ 0, 11, 0, 12, 63, 61, 57, 0, 29, 62,
+ 0, 0, 99, 6, 0, 106, 64, 0, 13, 0,
+ 21, 0, 22, 0, 23, 0, 27, 0, 24, 0,
+ 14, 56, 57, 0, 20, 56, 57, 0, 15, 56,
+ 57, 0, 25, 56, 57, 0, 26, 56, 57, 0,
+ 33, 71, 57, 0, 112, 72, 0, 34, 0, 35,
+ 0, 7, 74, 43, 75, 44, 0, 110, 4, 0,
+ 75, 76, 0, 76, 0, 102, 77, 0, 78, 0,
+ 53, 0, 58, 0, 82, 0, 83, 0, 84, 0,
+ 85, 0, 79, 0, 80, 0, 69, 0, 88, 0,
+ 90, 0, 91, 0, 92, 0, 93, 0, 94, 0,
+ 95, 0, 9, 100, 81, 57, 0, 16, 56, 57,
+ 0, 30, 56, 57, 0, 19, 0, 17, 86, 57,
+ 0, 18, 86, 57, 0, 28, 87, 57, 0, 32,
+ 87, 57, 0, 107, 19, 0, 108, 19, 0, 36,
+ 89, 57, 0, 98, 19, 0, 37, 96, 57, 0,
+ 38, 96, 57, 0, 39, 96, 57, 0, 40, 96,
+ 57, 0, 41, 96, 57, 0, 42, 96, 57, 0,
+ 97, 19, 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, 89, 92, 96, 125, 130, 138, 141, 145, 150,
+ 156, 162, 168, 176, 182, 188, 194, 200, 206, 212,
+ 361, 373, 385, 394, 401, 406, 419, 423, 429, 448,
+ 451, 457, 464, 469, 473, 477, 481, 485, 489, 495,
+ 507, 519, 531, 543, 555, 567, 572, 576, 582, 592,
+ 600, 608, 614, 621, 626, 631, 636, 641, 646, 651,
+ 656, 661, 666, 671, 676, 681, 686, 691, 696, 701,
+ 708, 721, 733, 745, 751, 763, 775, 787, 799, 808,
+ 817, 829, 838, 850, 862, 874, 886, 898, 910, 919,
+ 924, 929, 934, 939, 944, 949, 954, 959, 964, 969,
+ 974, 979, 984, 989, 994
+};
+#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", "ONSUCCESS",
+ "ONFAILURE", "STRING", "BACKLOG", "RANDOM", "BYDURATION", "BYSIZE",
+ "BYCONNECTIONS", "CONNECTIONTIMEOUT", "MAXCONNECTIONS", "BYORDER",
+ "TRAFFICLOG", "OVER", "DECAY", "BINDTO", "THROUGHPUTLOG", "TYPE", "ANY",
+ "HTTP", "STICKYCOOKIE", "ADDCLIENTHEADER", "SETCLIENTHEADER",
+ "APPENDCLIENTHEADER", "ADDSERVERHEADER", "SETSERVERHEADER",
+ "APPENDSERVERHEADER", "'{'", "'}'", "';'", "input", "element",
+ "service", "servicename", "servicestatements", "servicestatement",
+ "servicebody", "portstatement", "bindstatement", "ipaddress", "number",
+ "semicol", "verbositystatement", "onoff", "dispatchmodestatement",
+ "opt_over", "overnumber", "dispatchmethod", "dispatchmethodspec",
+ "revivingintervalstatement", "backlogstatement", "shmkeystatement",
+ "connectiontimeoutstatement", "maxconnectionsstatement",
+ "typestatement", "typespec", "typespecifier", "backendblock",
+ "backendname", "backenddefinitions", "backenddefinition",
+ "backendstatement", "serverstatement", "weightstatement",
+ "decaystatement", "serveraddress", "onsuccessstatement",
+ "onfailurestatement", "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", 0
+};
+#endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const short yyr1[] =
+{
+ 0, 46, 46, 47, 48, 49, 50, 50, 51, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 53, 54, 55, 56, 57, 58, 59, 59, 60, 61,
+ 61, 62, 63, 64, 64, 64, 64, 64, 64, 65,
+ 66, 67, 68, 69, 70, 71, 72, 72, 73, 74,
+ 75, 75, 76, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
+ 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, 112
+};
+
+/* 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,
+ 3, 3, 2, 2, 2, 4, 1, 1, 4, 2,
+ 0, 2, 2, 1, 1, 1, 1, 1, 1, 3,
+ 3, 3, 3, 3, 3, 2, 1, 1, 5, 2,
+ 2, 1, 2, 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, 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
+};
+
+/* 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[] =
+{
+ 93, 2, 101, 0, 1, 0, 0, 4, 95, 5,
+ 95, 7, 0, 3, 6, 91, 102, 97, 98, 91,
+ 91, 91, 91, 91, 103, 104, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 96, 0,
+ 0, 0, 0, 30, 0, 96, 96, 96, 96, 96,
+ 96, 0, 96, 0, 20, 0, 23, 94, 49, 26,
+ 27, 96, 91, 96, 33, 34, 35, 36, 38, 37,
+ 32, 39, 41, 40, 42, 43, 21, 22, 44, 46,
+ 47, 45, 24, 94, 51, 0, 25, 29, 0, 28,
+ 48, 50, 92, 91, 99, 99, 100, 91, 100, 90,
+ 89, 89, 89, 89, 89, 89, 54, 55, 62, 52,
+ 53, 60, 61, 56, 57, 58, 59, 63, 64, 65,
+ 66, 67, 68, 69, 31, 0, 96, 96, 0, 96,
+ 96, 0, 96, 96, 96, 0, 96, 0, 96, 96,
+ 96, 96, 96, 73, 96, 71, 74, 78, 75, 76,
+ 79, 72, 77, 80, 81, 82, 88, 83, 84, 85,
+ 86, 87, 70, 0, 0, 0
+};
+
+static const short yydefgoto[] =
+{
+ 4, 1, 2, 5, 10, 11, 26, 27, 28, 50,
+ 38, 54, 29, 61, 30, 63, 87, 43, 70, 31,
+ 32, 33, 34, 35, 36, 52, 81, 37, 40, 83,
+ 84, 109, 110, 111, 112, 144, 113, 114, 115, 116,
+ 127, 130, 117, 134, 118, 119, 120, 121, 122, 123,
+ 136, 137, 135, 39, 125, 3, 85, 12, 55, 42,
+ 44, 128, 131, 6, 41, 51, 53
+};
+
+static const short yypact[] =
+{
+ -32768, 12,-32768, 14,-32768, -37, 18,-32768,-32768,-32768,
+ -14,-32768, 41,-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, 17,
+ -11, 30, -1, 7, 56,-32768,-32768,-32768,-32768,-32768,
+ -32768, 19,-32768, -21,-32768, -8,-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, 6,-32768, 3,-32768,-32768, 45,-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, 28,-32768,-32768, 33,-32768,
+ -32768, 35,-32768,-32768,-32768, 38,-32768, 39,-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, 59, 60,-32768
+};
+
+static const short yypgoto[] =
+{
+ 62,-32768,-32768,-32768,-32768, 53,-32768, -20,-32768,-32768,
+ 5, -45, -17,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+ -32768,-32768,-32768, -15,-32768,-32768,-32768,-32768,-32768,-32768,
+ -19,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+ -24, -25,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+ 2,-32768,-32768, 13,-32768,-32768,-32768,-32768,-32768,-32768,
+ -32768,-32768,-32768,-32768,-32768,-32768,-32768
+};
+
+
+#define YYLAST 107
+
+
+static const short yytable[] =
+{
+ 71, 72, 73, 74, 75, 76, 8, 78, 15, 59,
+ 60, 17, 92, 79, 80, -93, 86, 7, 89, 93,
+ 94, 95, 9, 56, 45, 46, 47, 48, 49, 23,
+ 13, 96, 57, 97, 58, 98, 62, 82, 77, 99,
+ 100, 101, 102, 103, 104, 105, 15, 143, 16, 17,
+ 90, 124, 147, 18, 150, 19, 20, 154, 156, 164,
+ 165, 21, 163, 14, 91, 106, 22, 23, 107, 64,
+ 108, 129, 24, 133, 25, 88, 0, 65, 66, 67,
+ 68, 145, 146, 69, 148, 149, 0, 151, 152, 153,
+ 0, 155, 0, 157, 158, 159, 160, 161, 126, 162,
+ 0, 0, 132, 138, 139, 140, 141, 142
+};
+
+static const short yycheck[] =
+{
+ 45, 46, 47, 48, 49, 50, 43, 52, 5, 10,
+ 11, 8, 9, 34, 35, 3, 61, 3, 63, 16,
+ 17, 18, 4, 6, 19, 20, 21, 22, 23, 26,
+ 44, 28, 43, 30, 4, 32, 29, 45, 19, 36,
+ 37, 38, 39, 40, 41, 42, 5, 19, 7, 8,
+ 44, 6, 19, 12, 19, 14, 15, 19, 19, 0,
+ 0, 20, 0, 10, 83, 85, 25, 26, 85, 13,
+ 85, 95, 31, 98, 33, 62, -1, 21, 22, 23,
+ 24, 126, 127, 27, 129, 130, -1, 132, 133, 134,
+ -1, 136, -1, 138, 139, 140, 141, 142, 93, 144,
+ -1, -1, 97, 101, 102, 103, 104, 105
+};
+/* -*-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 101 "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 132 "parser.y"
+{
+ psmsg ("service:", yytext);
+ cur_service.name = xstrdup(yytext);
+ ;
+ break;}
+case 9:
+#line 151 "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 157 "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 163 "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 169 "parser.y"
+{
+ pimsg ("service dispatch mode:", yyvsp[0].set[0].v.ival);
+ pimsg ("service dispatch over:", lastovernr);
+ cur_service.dispatchtype = yyvsp[0].set[0].v.ival;
+ cur_service.dispatchover = lastovernr;
+ free (yyvsp[0].set);
+ ;
+ break;}
+case 13:
+#line 177 "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 183 "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 189 "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 195 "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 201 "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 207 "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 213 "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_onsuccspec:
+ psmsg ("backend block onsuccess:", yyvsp[0].set[i].v.sval);
+ cur_backend.onsuccess = yyvsp[0].set[i].v.sval;
+ break;
+ case cf_onfailspec:
+ psmsg ("backend block onfailure:", yyvsp[0].set[i].v.sval);
+ cur_backend.onfailure = 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;
+ 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)
+ cur_backend.weight = 1;
+
+ /* Add to the list. */
+ cur_service.backend = xrealloc (cur_service.backend,
+ ++cur_service.nbackend *
+ sizeof(Backend));
+ cur_service.backend[cur_service.nbackend - 1] =
+ cur_backend;
+ pimsg ("this was backend defintion", cur_service.nbackend);
+ memset (&cur_backend, 0, sizeof(cur_backend));
+ ;
+ break;}
+case 20:
+#line 364 "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 21:
+#line 376 "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 22:
+#line 387 "parser.y"
+{
+ setlaststr (laststring);
+ free (laststring);
+ laststring = 0;
+ ;
+ break;}
+case 23:
+#line 396 "parser.y"
+{
+ setlastnr (yytext);
+ ;
+ break;}
+case 25:
+#line 410 "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 26:
+#line 420 "parser.y"
+{
+ lastnr = 1;
+ ;
+ break;}
+case 27:
+#line 424 "parser.y"
+{
+ lastnr = 0;
+ ;
+ break;}
+case 28:
+#line 433 "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 30:
+#line 452 "parser.y"
+{
+ lastovernr = 0;
+ ;
+ break;}
+case 31:
+#line 459 "parser.y"
+{
+ setlastovernr (yytext);
+ ;
+ break;}
+case 33:
+#line 470 "parser.y"
+{
+ lastnr = ds_roundrobin;
+ ;
+ break;}
+case 34:
+#line 474 "parser.y"
+{
+ lastnr = ds_random;
+ ;
+ break;}
+case 35:
+#line 478 "parser.y"
+{
+ lastnr = ds_byduration;
+ ;
+ break;}
+case 36:
+#line 482 "parser.y"
+{
+ lastnr = ds_bysize;
+ ;
+ break;}
+case 37:
+#line 486 "parser.y"
+{
+ lastnr = ds_byorder;
+ ;
+ break;}
+case 38:
+#line 490 "parser.y"
+{
+ lastnr = ds_byconnections;
+ ;
+ break;}
+case 39:
+#line 498 "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 40:
+#line 510 "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 41:
+#line 522 "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 42:
+#line 534 "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 43:
+#line 546 "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 44:
+#line 558 "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 46:
+#line 573 "parser.y"
+{
+ lastnr = type_any;
+ ;
+ break;}
+case 47:
+#line 577 "parser.y"
+{
+ lastnr = type_http;
+ ;
+ break;}
+case 48:
+#line 587 "parser.y"
+{
+ yyval = yyvsp[-1];
+ ;
+ break;}
+case 49:
+#line 594 "parser.y"
+{
+ psmsg ("backend name:", yytext);
+ cur_backend.name = xstrdup (yytext);
+ ;
+ break;}
+case 50:
+#line 602 "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 51:
+#line 609 "parser.y"
+{
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 52:
+#line 616 "parser.y"
+{
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 53:
+#line 622 "parser.y"
+{
+ psmsg ("backend server:", yyvsp[0].set[0].v.sval);
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 54:
+#line 627 "parser.y"
+{
+ pimsg ("backend port:", yyvsp[0].set[0].v.ival);
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 55:
+#line 632 "parser.y"
+{
+ pimsg ("backend verbosity:", yyvsp[0].set[0].v.ival);
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 56:
+#line 637 "parser.y"
+{
+ psmsg ("backend onsuccess:", yyvsp[0].set[0].v.sval);
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 57:
+#line 642 "parser.y"
+{
+ psmsg ("backend onfailure:", yyvsp[0].set[0].v.sval);
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 58:
+#line 647 "parser.y"
+{
+ psmsg ("backend trafficlog:", yyvsp[0].set[0].v.sval);
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 59:
+#line 652 "parser.y"
+{
+ psmsg ("backend trafficlog:", yyvsp[0].set[0].v.sval);
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 60:
+#line 657 "parser.y"
+{
+ pimsg ("backend weight:", yyvsp[0].set[0].v.ival);
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 61:
+#line 662 "parser.y"
+{
+ pimsg ("backend decay:", yyvsp[0].set[0].v.ival);
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 62:
+#line 667 "parser.y"
+{
+ pimsg ("backend maxconnections:", yyvsp[0].set[0].v.ival);
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 63:
+#line 672 "parser.y"
+{
+ psmsg ("backend sticky cookie:", yyvsp[0].set[0].v.sval);
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 64:
+#line 677 "parser.y"
+{
+ psmsg ("addclientheader:", yyvsp[0].set[0].v.sval);
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 65:
+#line 682 "parser.y"
+{
+ psmsg ("setclientheader:", yyvsp[0].set[0].v.sval);
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 66:
+#line 687 "parser.y"
+{
+ psmsg ("appendclientheader:", yyvsp[0].set[0].v.sval);
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 67:
+#line 692 "parser.y"
+{
+ psmsg ("addserverheader:", yyvsp[0].set[0].v.sval);
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 68:
+#line 697 "parser.y"
+{
+ psmsg ("setserverheader:", yyvsp[0].set[0].v.sval);
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 69:
+#line 702 "parser.y"
+{
+ psmsg ("appendserverheader:", yyvsp[0].set[0].v.sval);
+ yyval = yyvsp[0];
+ ;
+ break;}
+case 70:
+#line 712 "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 71:
+#line 724 "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 72:
+#line 736 "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 73:
+#line 746 "parser.y"
+{
+ setlaststr (laststring);
+ ;
+ break;}
+case 74:
+#line 754 "parser.y"
+{
+ psmsg ("onsuccess statement:", laststr);
+ yyval.n = 1;
+ yyval.set = xmalloc (sizeof (Confset));
+ yyval.set[0].cf = cf_onsuccspec;
+ yyval.set[0].v.sval = xstrdup (laststr);
+ ;
+ break;}
+case 75:
+#line 766 "parser.y"
+{
+ psmsg ("onfailure 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 76:
+#line 778 "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 77:
+#line 790 "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 78:
+#line 801 "parser.y"
+{
+ setlaststr (laststring);
+ free (laststring);
+ laststring = 0;
+ ;
+ break;}
+case 79:
+#line 810 "parser.y"
+{
+ setlaststr (laststring);
+ free (laststring);
+ laststring = 0;
+ ;
+ break;}
+case 80:
+#line 820 "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 81:
+#line 831 "parser.y"
+{
+ setlaststr (laststring);
+ free (laststring);
+ laststring = 0;
+ ;
+ break;}
+case 82:
+#line 841 "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 83:
+#line 853 "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 84:
+#line 865 "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 85:
+#line 877 "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 86:
+#line 889 "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 87:
+#line 901 "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 88:
+#line 912 "parser.y"
+{
+ setlaststr (laststring);
+ free (laststring);
+ laststring = 0;
+ ;
+ break;}
+case 89:
+#line 919 "parser.y"
+{
+ yyerrmsg = "HTTP header specifier expected";
+;
+ break;}
+case 90:
+#line 924 "parser.y"
+{
+ yyerrmsg = "cookie specifier expected";
+;
+ break;}
+case 91:
+#line 929 "parser.y"
+{
+ yyerrmsg = "number expected";
+;
+ break;}
+case 92:
+#line 934 "parser.y"
+{
+ yyerrmsg = "hostname or IP address expected";
+;
+ break;}
+case 93:
+#line 939 "parser.y"
+{
+ yyerrmsg = "'service' expected";
+;
+ break;}
+case 94:
+#line 944 "parser.y"
+{
+ yyerrmsg = "backend definition statement expected";
+;
+ break;}
+case 95:
+#line 949 "parser.y"
+{
+ yyerrmsg = "service body statement expected";
+;
+ break;}
+case 96:
+#line 954 "parser.y"
+{
+ yyerrmsg = "semicolon (;) expected";
+;
+ break;}
+case 97:
+#line 959 "parser.y"
+{
+ yyerrmsg = "'on' or 'off' expetcted";
+;
+ break;}
+case 98:
+#line 964 "parser.y"
+{
+ yyerrmsg = "dispatch method expected";
+;
+ break;}
+case 99:
+#line 969 "parser.y"
+{
+ yyerrmsg = "command line expected";
+;
+ break;}
+case 100:
+#line 974 "parser.y"
+{
+ yyerrmsg = "file name expected";
+;
+ break;}
+case 101:
+#line 979 "parser.y"
+{
+ yyerrmsg = "service name (identifier) expected";
+;
+ break;}
+case 102:
+#line 984 "parser.y"
+{
+ yyerrmsg = "backend name (identifier) expected";
+;
+ break;}
+case 103:
+#line 989 "parser.y"
+{
+ yyerrmsg = "IP address or 'any' expected";
+;
+ break;}
+case 104:
+#line 994 "parser.y"
+{
+ yyerrmsg = "Service type expected ('any', 'stickyhttp', ...)";
+;
+ 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 998 "parser.y"
diff --git a/src/parser.h b/src/parser.h
@@ -0,0 +1,52 @@
+#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 ONSUCCESS 271
+# define ONFAILURE 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
+
+
+extern YYSTYPE yylval;
+
+#endif /* not BISON_PARSER_H */
diff --git a/test/chunkedserver b/test/chunkedserver
@@ -0,0 +1,110 @@
+#!/usr/bin/perl
+
+use strict;
+use Socket;
+use POSIX;
+
+# Verbose messaging
+sub msg {
+ print STDERR ("chunkedserver: ", @_);
+}
+
+# Child process catcher
+sub reaper {
+ while ((my $waitedpid = waitpid(-1,WNOHANG)) > 0) {
+ msg ("Child $waitedpid done",
+ ($? ? " with exit $?" : ''),
+ "\n");
+ }
+ $SIG{CHLD} = \&reaper;
+}
+
+# Connection handler
+sub handleconnection () {
+ my $pid;
+
+ # Daemonize
+ if (!defined ($pid = fork())) {
+ msg ("Can't fork: $!\n");
+ return;
+ } elsif ($pid) {
+ # Parent branch
+ msg ("Connection handler started as pid $pid\n");
+ return;
+ }
+
+ # Child branch
+ while (defined (my $line = <Client>)) {
+ chomp ($line);
+ $line =~ s/\r//;
+ last if ($line eq '');
+ msg ("Client says: [$line]\n");
+ }
+
+ msg ("Sending response\n");
+ print Client ("HTTP/1.1 200 OK\r\n",
+ "Connection: close\r\n",
+ "Transfer-Encoding: chunked\r\n",
+ "Content-Type: text/plain\r\n",
+ "\r\n",
+ "5\r\n",
+ "Hello\r\n",
+ "1\r\n",
+ " \r\n",
+ "5\r\n",
+ "World\r\n",
+ "2\r\n",
+ "!\n\r\n",
+ "0\r\n",
+ "\r\n");
+ exit (0);
+}
+
+# Daemon server
+sub serve ($) {
+ my $port = shift;
+
+ # Create the tcp service.
+ socket (Server, PF_INET, SOCK_STREAM, getprotobyname ('tcp'))
+ or die ("Can't create chunkedserver socket: $!\n");
+ setsockopt (Server, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))
+ or die ("Can't set socket options: $!\n");
+ bind (Server, sockaddr_in ($port, INADDR_ANY))
+ or die ("Can't bind to port: $!\n");
+ listen (Server, SOMAXCONN)
+ or die ("Can't listen to socket: $!\n");
+ msg ("Chunkedserver started on port $port.\n");
+
+ $SIG{CHLD} = \&reaper;
+ $SIG{INT} = sub {
+ msg ("Interrupt caught, terminating..\n");
+ exit(0);
+ };
+
+ while (1) {
+ for (my $waitedpid = 0;
+ (my $paddr = accept (Client, Server)) || $waitedpid;
+ $waitedpid = 0, close (Client)) {
+ next if ($waitedpid and not $paddr);
+ my ($port, $iaddr) = sockaddr_in ($paddr);
+ my $name = gethostbyaddr ($iaddr, AF_INET);
+
+ msg ("Connection from $name/", inet_ntoa ($iaddr), ":$port\n");
+
+ handleconnection ();
+ }
+ }
+}
+
+# Main starts here
+if ($#ARGV != 1) {
+ die <<"ENDUSAGE";
+
+Usage: chunkedserver nsec portnr
+
+ENDUSAGE
+}
+
+alarm (shift (@ARGV));
+serve (shift (@ARGV));
+
diff --git a/tools/c-conf b/tools/c-conf
@@ -4,7 +4,8 @@ use strict;
use Getopt::Std;
# Globals
-my $VER = "1.04";
+my $VER = "1.05";
+# 1.05 [KK 2006-09-28] Flag -s (silent) implemented. Usage text updated.
# 1.04 [KK 2006-09-05] C-compilers: gcc/g++ get selected first, instead of
# cc/c++. Helps HP-UX ports. [Thanks, Bernd Krumboeck.]
# 1.03 [KK 2006-07-19] 'subfiles' keeps track of visited dirs incase of
@@ -46,7 +47,7 @@ Usage:
$base [flags] header FILE.H [FILE.H...] Searches for directories
containing the named header(s), returns appropriate -I flags.
$base [flags] headerdir DIR [DIR...]: Searches for directory
- containing headers, returns appropriate -I flag.
+ containing headers, returns appropriate -I flags.
$base [flags] ifheader FILE.H DEFINE Searches for the named header.
If found, a compilation flag -DDEFINE is returned, indicating that
the header is found.
@@ -54,16 +55,18 @@ Usage:
tries to use FUNC. If this succeeds, a -DDEFINE=1 flag is returned.
$base [flags] lib NAME [NAME...]: Searches for libNAME.{a,so,...},
returns appropriate -L and -l flags.
- $base [flags] so-name LIB: Returns filename of a shared-object for LIB
- $base [flags] so-cflags: Returns flags to compile for shared-object
- ready objects.
- $base [flags] so-lflags: Returns flags to produce a shared-object
+ $base [flags] so-name NAME: Returns filename of a shared-object for NAME,
+ e.g. libNAME.so
+ $base [flags] so-cflags: Returns compilation flags to build shared
+ objects
+ $base [flags] so-lflags: Returns linkage flags to produce a shared-object
library
- $base [flags] c-compiler: Returns absolute path to C compiler
- $base [flags] c++-compiler: Returns absolute path to C++ compiler
+ $base [flags] c-compiler: Returns name of C compiler
+ $base [flags] c++-compiler: Returns name of C++ compiler
Optional flags:
-h: to show short help for an action, e.g. try '$base -h so-name'
+ -s: to suppress showing of warnings
-v: to show verbose messages
-I DIR[,DIR..]: to add DIR(s) to the searchpath for headers, default
searchpath is @headerdirs
@@ -447,7 +450,7 @@ ENDHELP
$base = $0;
$base =~ s{.*/}{};
-usage () unless (getopts ('vhI:L:', \%opts));
+usage () unless (getopts ('vhI:L:s', \%opts));
foreach my $d (split (/,/, $opts{L})) {
push (@libdirs, $d);
}
@@ -483,10 +486,10 @@ if ($action eq 'header') {
usage ();
}
-print ("\n") if ($printed);
+print ("\n") if ($printed);
if ($#warnings > -1) {
foreach my $w (@warnings) {
- print STDERR ("$base WARNING: $w");
+ print STDERR ("$base WARNING: $w") unless ($opts{s});
}
exit (1);
}