summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--test/.indent.pro54
-rw-r--r--test/Makefile.in20
-rw-r--r--test/README3
-rw-r--r--test/check_chunked58
-rw-r--r--test/cls.c182
-rw-r--r--test/make_sni.sh396
-rw-r--r--test/tcpdumpscii.txt50
-rw-r--r--test/test-writev.c101
-rw-r--r--test/test_find.c78
-rw-r--r--test/test_limits.c200
-rw-r--r--test/test_parser.c75
-rw-r--r--test/test_select.c46
-rw-r--r--test/time-sem.c591
13 files changed, 1854 insertions, 0 deletions
diff --git a/test/.indent.pro b/test/.indent.pro
new file mode 100644
index 0000000..a9fbe9f
--- /dev/null
+++ b/test/.indent.pro
@@ -0,0 +1,54 @@
+-i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1
+-TBUFF
+-TFILE
+-TTRANS
+-TUINT4
+-T_trans
+-Tallow_options_t
+-Tapache_sfio
+-Tarray_header
+-Tbool_int
+-Tbuf_area
+-Tbuff_struct
+-Tbuffy
+-Tcmd_how
+-Tcmd_parms
+-Tcommand_rec
+-Tcommand_struct
+-Tconn_rec
+-Tcore_dir_config
+-Tcore_server_config
+-Tdir_maker_func
+-Tevent
+-Tglobals_s
+-Thandler_func
+-Thandler_rec
+-Tjoblist_s
+-Tlisten_rec
+-Tmerger_func
+-Tmode_t
+-Tmodule
+-Tmodule_struct
+-Tmutex
+-Tn_long
+-Tother_child_rec
+-Toverrides_t
+-Tparent_score
+-Tpid_t
+-Tpiped_log
+-Tpool
+-Trequest_rec
+-Trequire_line
+-Trlim_t
+-Tscoreboard
+-Tsemaphore
+-Tserver_addr_rec
+-Tserver_rec
+-Tserver_rec_chain
+-Tshort_score
+-Ttable
+-Ttable_entry
+-Tthread
+-Tu_wide_int
+-Tvtime_t
+-Twide_int
diff --git a/test/Makefile.in b/test/Makefile.in
new file mode 100644
index 0000000..15d404d
--- /dev/null
+++ b/test/Makefile.in
@@ -0,0 +1,20 @@
+
+# no targets: we don't want to build anything by default. if you want the
+# test programs, then "make test"
+TARGETS =
+
+bin_PROGRAMS =
+
+PROGRAM_LDADD = $(EXTRA_LDFLAGS) $(PROGRAM_DEPENDENCIES) $(EXTRA_LIBS)
+PROGRAM_DEPENDENCIES = \
+ $(top_srcdir)/srclib/apr-util/libaprutil.la \
+ $(top_srcdir)/srclib/apr/libapr.la
+
+include $(top_builddir)/build/rules.mk
+
+test: $(bin_PROGRAMS)
+
+# example for building a test proggie
+# dbu_OBJECTS = dbu.lo
+# dbu: $(dbu_OBJECTS)
+# $(LINK) $(dbu_OBJECTS) $(PROGRAM_LDADD)
diff --git a/test/README b/test/README
new file mode 100644
index 0000000..9f8be50
--- /dev/null
+++ b/test/README
@@ -0,0 +1,3 @@
+This directory contains useful test code for testing various bits
+of Apache functionality. This stuff is for the developers only,
+so we might remove it on public releases.
diff --git a/test/check_chunked b/test/check_chunked
new file mode 100644
index 0000000..50c56eb
--- /dev/null
+++ b/test/check_chunked
@@ -0,0 +1,58 @@
+#!/usr/bin/perl -w
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+# This is meant to be used on the raw output of an HTTP/1.1 connection
+# to check that the chunks are all correctly laid out. It's easiest
+# to use a tool like netcat to generate the output. This script
+# *insists* that \r exist in the output.
+#
+# You can find netcat at avian.org:/src/hacks/nc110.tgz.
+
+use strict;
+
+my $is_chunked = 0;
+
+# must toss headers
+while(<>) {
+ if (/^Transfer-Encoding:\s+chunked/i) {
+ $is_chunked = 1;
+ }
+ last if ($_ eq "\r\n");
+}
+
+$is_chunked || die "wasn't chunked\n";
+
+for(;;) {
+ $_ = <> || die "unexpected end of file!\n";
+
+ m#^([0-9a-f]+) *\r$#i || die "bogus chunklen: $_";
+
+ my $chunklen = hex($1);
+
+ exit 0 if ($chunklen == 0);
+
+ chop; chop;
+ print "$_ ";
+
+ my $data = '';
+ read(ARGV, $data, $chunklen) == $chunklen || die "short read!\n";
+
+ $_ = <> || die "unexpected end of file!\n";
+
+ $_ eq "\r\n" || die "missing chunk trailer!\n";
+}
diff --git a/test/cls.c b/test/cls.c
new file mode 100644
index 0000000..1ee6ac7
--- /dev/null
+++ b/test/cls.c
@@ -0,0 +1,182 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ctype.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+/*
+ * Compare a string to a mask
+ * Mask characters:
+ * @ - uppercase letter
+ * # - lowercase letter
+ * & - hex digit
+ * # - digit
+ * * - swallow remaining characters
+ * <x> - exact match for any other character
+ */
+static int checkmask(const char *data, const char *mask)
+{
+ int i, ch, d;
+
+ for (i = 0; mask[i] != '\0' && mask[i] != '*'; i++) {
+ ch = mask[i];
+ d = data[i];
+ if (ch == '@') {
+ if (!isupper(d))
+ return 0;
+ }
+ else if (ch == '$') {
+ if (!islower(d))
+ return 0;
+ }
+ else if (ch == '#') {
+ if (!isdigit(d))
+ return 0;
+ }
+ else if (ch == '&') {
+ if (!isxdigit(d))
+ return 0;
+ }
+ else if (ch != d)
+ return 0;
+ }
+
+ if (mask[i] == '*')
+ return 1;
+ else
+ return (data[i] == '\0');
+}
+
+/*
+ * Converts 8 hex digits to a time integer
+ */
+static int hex2sec(const char *x)
+{
+ int i, ch;
+ unsigned int j;
+
+ for (i = 0, j = 0; i < 8; i++) {
+ ch = x[i];
+ j <<= 4;
+ if (isdigit(ch))
+ j |= ch - '0';
+ else if (isupper(ch))
+ j |= ch - ('A' - 10);
+ else
+ j |= ch - ('a' - 10);
+ }
+ if (j == 0xffffffff)
+ return -1; /* so that it works with 8-byte ints */
+ else
+ return j;
+}
+
+int main(int argc, char **argv)
+{
+ int i, ver;
+ DIR *d;
+ struct dirent *e;
+ const char *s;
+ FILE *fp;
+ char path[FILENAME_MAX + 1];
+ char line[1035];
+ time_t date, lmod, expire;
+ unsigned int len;
+ struct tm ts;
+ char sdate[30], slmod[30], sexpire[30];
+ const char time_format[] = "%e %b %Y %R";
+
+ if (argc != 2) {
+ printf("Usage: cls directory\n");
+ exit(0);
+ }
+
+ d = opendir(argv[1]);
+ if (d == NULL) {
+ perror("opendir");
+ exit(1);
+ }
+
+ for (;;) {
+ e = readdir(d);
+ if (e == NULL)
+ break;
+ s = e->d_name;
+ if (s[0] == '.' || s[0] == '#')
+ continue;
+ sprintf(path, "%s/%s", argv[1], s);
+ fp = fopen(path, "r");
+ if (fp == NULL) {
+ perror("fopen");
+ continue;
+ }
+ if (fgets(line, 1034, fp) == NULL) {
+ perror("fgets");
+ fclose(fp);
+ continue;
+ }
+ if (!checkmask(line, "&&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&&\n")) {
+ fprintf(stderr, "Bad cache file\n");
+ fclose(fp);
+ continue;
+ }
+ date = hex2sec(line);
+ lmod = hex2sec(line + 9);
+ expire = hex2sec(line + 18);
+ ver = hex2sec(line + 27);
+ len = hex2sec(line + 35);
+ if (fgets(line, 1034, fp) == NULL) {
+ perror("fgets");
+ fclose(fp);
+ continue;
+ }
+ fclose(fp);
+ i = strlen(line);
+ if (strncmp(line, "X-URL: ", 7) != 0 || line[i - 1] != '\n') {
+ fprintf(stderr, "Bad cache file\n");
+ continue;
+ }
+ line[i - 1] = '\0';
+ if (date != -1) {
+ ts = *gmtime(&date);
+ strftime(sdate, 30, time_format, &ts);
+ }
+ else
+ strcpy(sdate, "-");
+
+ if (lmod != -1) {
+ ts = *gmtime(&lmod);
+ strftime(slmod, 30, time_format, &ts);
+ }
+ else
+ strcpy(slmod, "-");
+
+ if (expire != -1) {
+ ts = *gmtime(&expire);
+ strftime(sexpire, 30, time_format, &ts);
+ }
+ else
+ strcpy(sexpire, "-");
+
+ printf("%s: %d; %s %s %s\n", line + 7, ver, sdate, slmod, sexpire);
+ }
+
+ closedir(d);
+ return 0;
+}
diff --git a/test/make_sni.sh b/test/make_sni.sh
new file mode 100644
index 0000000..b8b651d
--- /dev/null
+++ b/test/make_sni.sh
@@ -0,0 +1,396 @@
+#!/bin/sh
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script will populate a directory 'sni' with 3 sites, httpd.conf
+# and certificates as to facilitate testing of TLS server name
+# indication support (RFC 4366) or SNI.
+#
+#
+OPENSSL=${OPENSSL:-openssl}
+DOMAIN=${DOMAIN:-my-sni-test.org}
+DIR=${DIR:-$PWD/sni}
+
+# List of hostnames automatically created by default.
+NAMES=${NAMES:-ape nut pear apple banana}
+
+# IP address these hostnames are bound to.
+IP=${IP:-127.0.0.1}
+
+# A certificate password for the .p12 files of the client
+# authentication test. Normally not set. However some browsers
+# require a password of at least 4 characters.
+#
+PASSWD=${PASSWD:-}
+
+args=`getopt a:fd:D:p: $*`
+if [ $? != 0 ]; then
+ echo "Syntax: $0 [-f] [-a IPaddress] [-d outdir] [-D domain ] [two or more vhost names ]"
+ echo " -f Force overwriting of outdir (default is $DIR)"
+ echo " -d dir Directory to create the SNI test server in (default is $DIR)"
+ echo " -D domain Domain name to use for this test (default is $DOMAIN)"
+ echo " -a IP IP address to use for this virtual host (default is $IP)"
+ echo " -p str Password for the client certificate test (some browsers require a set password)"
+ echo " [names] List of optional vhost names (default is $NAMES)"
+ echo
+ echo "Example:"
+ echo " $0 -D SecureBlogsAreUs.com peter fred mary jane ardy"
+ echo
+ echo "Which will create peter.SecureBlogsAreUs.com, fred.SecureBlogsAreUs.com and"
+ echo "so on. Note that the _first_ FQDN is also the default for non SNI hosts. It"
+ echo "may make sense to give this host a generic name - and allow each of the real"
+ echo "SNI site as sub directories/URI's of this generic name; thus allowing the "
+ echo "few non-SNI browsers access."
+ exit 1
+fi
+set -- $args
+for i
+do
+ case "$i"
+ in
+ -f)
+ FORCE=1
+ shift;;
+ -a)
+ IP=$2; shift
+ shift;;
+ -d)
+ DIR=$2; shift
+ shift;;
+ -p)
+ PASSWD=$2; shift
+ shift;;
+ -D)
+ DOMAIN=$2; shift
+ shift;;
+ --)
+ shift; break;
+ esac
+done
+
+if [ $# = 1 ]; then
+ echo "Aborted - just specifying one vhost makes no sense for SNI testing. Go wild !"
+ exit 1
+fi
+
+if [ $# -gt 0 ]; then
+ NAMES=$*
+fi
+
+if ! openssl version | grep -q OpenSSL; then
+ echo Aborted - your openssl is very old or misconfigured.
+ exit 1
+fi
+
+set `openssl version`
+if test "0$2" \< "00.9"; then
+ echo Aborted - version of openssl too old, 0.9 or up required.
+ exit 1
+fi
+
+if test -d ${DIR} -a "x$FORCE" != "x1"; then
+ echo Aborted - already an ${DIR} directory. Use the -f flag to overwrite.
+ exit 1
+fi
+
+mkdir -p ${DIR} || exit 1
+mkdir -p ${DIR}/ssl ${DIR}/htdocs ${DIR}/logs || exit 1
+
+# Create a 'CA' - keep using different serial numbers
+# as the browsers get upset if they see an identical
+# serial with a different pub-key.
+#
+# Note that we're not relying on the 'v3_ca' section as
+# in the default openssl.conf file - so the certificate
+# will be without the basicConstraints = CA:true and
+# keyUsage = cRLSign, keyCertSign values. This is fine
+# for most browsers.
+#
+serial=$RANDOM$$
+
+openssl req -new -nodes -batch \
+ -x509 \
+ -days 10 -subj '/CN=Da Root/O=SNI testing/' -set_serial $serial \
+ -keyout ${DIR}/root.key -out ${DIR}/root.pem \
+ || exit 2
+
+CDIR=${DIR}/client-xs-control
+mkdir -p ${CDIR}
+# Create some certificate authorities for testing client controls
+#
+openssl req -new -nodes -batch \
+ -x509 \
+ -days 10 -subj '/CN=Da Second Root/O=SNI user access I/' -set_serial 2$serial$$\
+ -keyout ${CDIR}/xs-root-1.key -out ${CDIR}/xs-root-1.pem \
+ || exit 2
+
+openssl req -new -nodes -batch \
+ -x509 \
+ -days 10 -subj '/CN=Da Second Root/O=SNI user access II/' -set_serial 3$serial$$ \
+ -keyout ${CDIR}/xs-root-2.key -out ${CDIR}/xs-root-2.pem \
+ || exit 2
+
+# Create a chain of just the two access authorites:
+cat ${CDIR}/xs-root-2.pem ${CDIR}/xs-root-1.pem > ${CDIR}/xs-root-chain.pem
+
+# And likewise a directory with the same information (using the
+# required 'hash' naming format
+#
+mkdir -p ${CDIR}/xs-root-dir || exit 1
+rm -f {$CDIR}/*.0
+ln ${CDIR}/xs-root-1.pem ${CDIR}/xs-root-dir/`openssl x509 -noout -hash -in ${CDIR}/xs-root-1.pem`.0
+ln ${CDIR}/xs-root-2.pem ${CDIR}/xs-root-dir/`openssl x509 -noout -hash -in ${CDIR}/xs-root-2.pem`.0
+
+# Use the above two client certificate authorities to make a few users
+for i in 1 2
+do
+ # Create a certificate request for a test user.
+ #
+ openssl req -new -nodes -batch \
+ -days 9 -subj "/CN=User $i/O=SNI Test Crash Dummy Dept/" \
+ -keyout ${CDIR}/client-$i.key -out ${CDIR}/client-$i.req -batch \
+ || exit 3
+
+ # And get it signed by either our client cert issuing root authority.
+ #
+ openssl x509 -text -req \
+ -CA ${CDIR}/xs-root-$i.pem -CAkey ${CDIR}/xs-root-$i.key \
+ -set_serial 3$serial$$ -in ${CDIR}/client-$i.req -out ${CDIR}/client-$i.pem \
+ || exit 4
+
+ # And create a pkcs#12 version for easy browser import.
+ #
+ openssl pkcs12 -export \
+ -inkey ${CDIR}/client-$i.key -in ${CDIR}/client-$i.pem -name "Client $i" \
+ -caname "Issuing client root $i" -certfile ${CDIR}/xs-root-$i.pem \
+ -out ${CDIR}/client.p12 -passout pass:"$PASSWD" || exit 5
+
+ rm ${CDIR}/client-$i.req
+done
+
+# Create the header for the example '/etc/hosts' file.
+#
+echo '# To append to your hosts file' > ${DIR}/hosts
+
+# Create a header for the httpd.conf snipped.
+#
+cat > ${DIR}/httpd-sni.conf << EOM
+# To append to your httpd.conf file'
+Listen ${IP}:443
+NameVirtualHost ${IP}:443
+
+LoadModule ssl_module modules/mod_ssl.so
+
+SSLRandomSeed startup builtin
+SSLRandomSeed connect builtin
+
+LogLevel debug
+TransferLog ${DIR}/logs/access_log
+ErrorLog ${DIR}/logs/error_log
+
+# You'll get a warning about this.
+#
+SSLSessionCache none
+
+# Note that this SSL configuration is far
+# from complete - you propably will want
+# to configure SSLSession Caches at the
+# very least.
+
+<Directory />
+ Options None
+ AllowOverride None
+ Require all denied
+</Directory>
+
+<Directory "${DIR}/htdocs">
+ allow from all
+ Require all granted
+</Directory>
+
+# This first entry is also the default for non SNI
+# supporting clients.
+#
+EOM
+
+# Create the header of a sample BIND zone file.
+#
+(
+ echo "; Configuration sample to be added to the $DOMAIN zone file of BIND."
+ echo "\$ORIGIN $DOMAIN."
+) > ${DIR}/zone-file
+
+ZADD="IN A $IP"
+INFO="and also the site you see when the browser does not support SNI."
+
+set -- ${NAMES}
+DEFAULT=$1
+
+for n in ${NAMES}
+do
+ FQDN=$n.$DOMAIN
+ serial=`expr $serial + 1`
+
+ # Create a certificate request for this host.
+ #
+ openssl req -new -nodes -batch \
+ -days 9 -subj "/CN=$FQDN/O=SNI Testing/" \
+ -keyout ${DIR}/$n.key -out ${DIR}/$n.req -batch \
+ || exit 3
+
+ # And get it signed by our root authority.
+ #
+ openssl x509 -text -req \
+ -CA ${DIR}/root.pem -CAkey ${DIR}/root.key \
+ -set_serial $serial -in ${DIR}/$n.req -out ${DIR}/$n.pem \
+ || exit 4
+
+ # Combine the key and certificate in one file.
+ #
+ cat ${DIR}/$n.pem ${DIR}/$n.key > ${DIR}/ssl/$n.crt
+ rm ${DIR}/$n.req ${DIR}/$n.key ${DIR}/$n.pem
+
+ LST="$LST
+ https://$FQDN/index.html"
+
+ # Create a /etc/host and bind-zone file example
+ #
+ echo "${IP} $FQDN $n" >> ${DIR}/hosts
+ echo "$n $ZADD" >> ${DIR}/zone-file
+ ZADD="IN CNAME $DEFAULT"
+
+ # Create and populate a docroot for this host.
+ #
+ mkdir -p ${DIR}/htdocs/$n || exit 1
+ echo We are $FQDN $INFO > ${DIR}/htdocs/$n/index.html || exit 1
+
+ # And change the info text - so that only the default/fallback site
+ # gets marked as such.
+ #
+ INFO="and you'd normally only see this site when there is proper SNI support."
+
+ # And create a configuration snipped.
+ #
+ cat >> ${DIR}/httpd-sni.conf << EOM
+<VirtualHost ${IP}:443>
+ SSLEngine On
+ ServerName $FQDN:443
+ DocumentRoot ${DIR}/htdocs/$n
+ SSLCertificateChainFile ${DIR}/root.pem
+ SSLCertificateFile ${DIR}/ssl/$n.crt
+
+ # Uncomment the following lines if you
+ # want to only allow access to clients with
+ # a certificate issued/signed by some
+ # selection of the issuing authorites
+ #
+ # SSLCACertificate ${CDIR}/xs-root-1.pem # just root 1
+ # SSLCACertificate ${CDIR}/xs-root-2.pem # just root 2
+ # SSLCACertificate ${CDIR}/xs-root-chain.pem # 1 & 2
+ # SSLCACertificateDir ${CDIR}/xs-root-dir # 1 & 2 - but as a directory.
+ #
+ # SSLVerifyClient require
+ # SSLVerifyDepth 2
+ #
+ TransferLog ${DIR}/logs/access_$n
+</VirtualHost>
+
+EOM
+
+done
+
+cat << EOM
+SNI Files generated
+===================
+
+The directory ${DIR}/sni has been populated with the following
+
+- root.key|pem Certificate authority root and key. (You could
+ import the root.pem key into your browser to
+ quell warnings about an unknown authority).
+
+- hosts /etc/hosts file with fake entries for the hosts
+
+- htdocs directory with one docroot for each domain,
+ each with a small sample file.
+
+- ssl directory with an ssl cert (signed by root)
+ for each of the domains).
+
+- logs logfiles, one for each domain and an
+ access_log for any misses.
+
+The directory ${CDIR} contains optional test files to allow client
+authentication testing:
+
+- client*pem/p12 Files for client authentication testing. These
+ need to be imported into the browser.
+
+- xs-root-1/2 Certificate authority which has issued above
+ client authentication certificates.
+
+- xs-root-dir A directory specific for the SSLCACertificateDir
+ directive.
+
+- xs-root-chain A chain of the two client xs authorities for the
+ SSLCACertificate directive.
+
+SNI Test
+========
+
+A directory ${DIR}/sni has been created. Run an apache
+server against it with
+
+ .../httpd -f ${DIR}/httpd-sni.conf
+
+and keep an eye on ${DIR}/logs/error_log. When everything
+is fine you will see entries like:
+
+ Feb 11 16:12:26 2008] [debug] Init:
+ SSL server IP/port overlap: ape.*:443 (httpd-sni.conf:24) vs. jane.*:443 (httpd-sni.conf:42)
+
+for each vhost configured and a concluding warning:
+
+ [Mon Feb 11 16:12:26 2008] [warn] Init:
+ Name-based SSL virtual hosts only work for clients with TLS server name indication support (RFC 4366)
+
+HOWEVER - If you see an entry like:
+
+ [Mon Feb 11 15:41:41 2008] [warn] Init:
+ You should not use name-based virtual hosts in conjunction with SSL!!
+
+then you are either using an OpenSSL which is too old and/or you need to ensure that the
+TLS Extensions are compiled into openssl with the 'enable-tlsext' flag. Once you have
+recompiled or reinstalled OpenSSL with TLS Extensions you will have to recompile mod_ssl
+to allow it to recognize SNI support.
+
+Meanwhile add 'hosts' to your c:\windows\system32\drivers\etc\hosts
+or /etc/hosts file as to point the various URL's to your server:
+$LST
+
+and verify that each returns its own name (and an entry in its
+own ${DIR}/logs) file).
+
+NOTE
+====
+
+Note that in the generated example the 'first' domain is special - and is the
+catch all for non-SNI browsers. Depending on your circumstances it may make
+sense to use a generic name - and have each of the SNI domains as subdirectories
+(and hence URI's under this generic name). Thus allowing non SNI browsers also
+access to those sites.
+EOM
+exit 0
diff --git a/test/tcpdumpscii.txt b/test/tcpdumpscii.txt
new file mode 100644
index 0000000..9c1060e
--- /dev/null
+++ b/test/tcpdumpscii.txt
@@ -0,0 +1,50 @@
+
+From marcs@znep.com Fri Apr 17 15:16:16 1998
+Date: Sat, 22 Nov 1997 20:44:10 -0700 (MST)
+From: Marc Slemko <marcs@znep.com>
+To: TLOSAP <new-httpd@apache.org>
+Subject: Re: Getting ethernet packets content under FreeBSD? (fwd)
+Reply-To: new-httpd@apache.org
+
+Anyone too lazy to hack tcpdump (eg. my tcpdump has a -X option to display
+the data in ASCII) can use something like the below to grab HTTP headers
+when debugging broken clients.
+
+Nothing complicated, but handy.
+
+---------- Forwarded message ----------
+Date: Sat, 22 Nov 1997 14:35:23 PST
+From: Bill Fenner <fenner@parc.xerox.com>
+To: Nate Williams <nate@mt.sri.com>
+Cc: bmah@ca.sandia.gov, hackers@FreeBSD.ORG
+Subject: Re: Getting ethernet packets content under FreeBSD?
+
+I usually just use this perl script, which I call "tcpdumpscii".
+Then run "tcpdumpscii -s 1500 -x [other tcpdump args]".
+
+ Bill
+
+#!/import/misc/bin/perl
+#
+#
+open(TCPDUMP,"tcpdump -l @ARGV|");
+while (<TCPDUMP>) {
+ if (/^\s+(\S\S)+/) {
+ $sav = $_;
+ $asc = "";
+ while (s/\s*(\S\S)\s*//) {
+ $i = hex($1);
+ if ($i < 32 || $i > 126) {
+ $asc .= ".";
+ } else {
+ $asc .= pack(C,hex($1));
+ }
+ }
+ $foo = "." x length($asc);
+ $_ = $sav;
+ s/\t/ /g;
+ s/^$foo/$asc/;
+ }
+ print;
+}
+
diff --git a/test/test-writev.c b/test/test-writev.c
new file mode 100644
index 0000000..83b6503
--- /dev/null
+++ b/test/test-writev.c
@@ -0,0 +1,101 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ test-writev: use this to figure out if your writev() does intelligent
+ things on the network. Some writev()s when given multiple buffers
+ will break them up into multiple packets, which is a waste.
+
+ Linux prior to 2.0.31 has this problem.
+
+ Solaris 2.5, 2.5.1 doesn't appear to, 2.6 hasn't been tested.
+
+ IRIX 5.3 doesn't have this problem.
+
+ To use this you want to snoop the wire with tcpdump, and then run
+ "test-writev a.b.c.d port#" ... against some TCP service on another
+ box. For example you can run it against port 80 on another server.
+ You want to look to see how many data packets are sent, you're hoping
+ only one of size 300 is sent.
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/uio.h>
+#include <errno.h>
+
+#ifndef INADDR_NONE
+#define INADDR_NONE (-1ul)
+#endif
+
+void main( int argc, char **argv )
+{
+ struct sockaddr_in server_addr;
+ int s;
+ struct iovec vector[3];
+ char buf[100];
+ int i;
+ const int just_say_no = 1;
+
+ if( argc != 3 ) {
+usage:
+ fprintf( stderr, "usage: test-writev a.b.c.d port#\n" );
+ exit( 1 );
+ }
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_addr.s_addr = inet_addr( argv[1] );
+ if( server_addr.sin_addr.s_addr == INADDR_NONE ) {
+ fprintf( stderr, "bogus address\n" );
+ goto usage;
+ }
+ server_addr.sin_port = htons( atoi( argv[2] ) );
+
+ s = socket( AF_INET, SOCK_STREAM, 0 );
+ if( s < 0 ) {
+ perror("socket");
+ exit(1);
+ }
+ if( connect( s, (struct sockaddr *)&server_addr, sizeof( server_addr ) )
+ != 0 ) {
+ perror("connect");
+ exit(1);
+ }
+
+ if( setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&just_say_no,
+ sizeof(just_say_no)) != 0 ) {
+ perror( "TCP_NODELAY" );
+ exit(1);
+ }
+ /* now build up a two part writev and write it out */
+ for( i = 0; i < sizeof( buf ); ++i ) {
+ buf[i] = 'x';
+ }
+ vector[0].iov_base = buf;
+ vector[0].iov_len = sizeof(buf);
+ vector[1].iov_base = buf;
+ vector[1].iov_len = sizeof(buf);
+ vector[2].iov_base = buf;
+ vector[2].iov_len = sizeof(buf);
+
+ i = writev( s, &vector[0], 3 );
+ fprintf( stdout, "i=%d, errno=%d\n", i, errno );
+ exit(0);
+}
diff --git a/test/test_find.c b/test/test_find.c
new file mode 100644
index 0000000..5019331
--- /dev/null
+++ b/test/test_find.c
@@ -0,0 +1,78 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This program tests the ap_find_list_item routine in ../main/util.c.
+ *
+ * The defines in this sample compile line are specific to Roy's system.
+ * They should match whatever was used to compile Apache first.
+ *
+ gcc -g -O2 -I../os/unix -I../include -o test_find \
+ -DSOLARIS2=250 -Wall -DALLOC_DEBUG -DPOOL_DEBUG \
+ ../main/alloc.o ../main/buff.o ../main/util.o \
+ ../ap/libap.a -lsocket -lnsl test_find.c
+ *
+ * Roy Fielding, 1999
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include "httpd.h"
+#include "apr_general.h"
+
+/*
+ * Dummy a bunch of stuff just to get a compile
+ */
+uid_t ap_user_id;
+gid_t ap_group_id;
+void *ap_dummy_mutex = &ap_dummy_mutex;
+char *ap_server_argv0;
+
+AP_DECLARE(void) ap_block_alarms(void)
+{
+ ;
+}
+
+AP_DECLARE(void) ap_unblock_alarms(void)
+{
+ ;
+}
+
+AP_DECLARE(void) ap_log_error(const char *file, int line, int level,
+ const request_rec *r, const char *fmt, ...)
+{
+ ;
+}
+
+int main (void)
+{
+ apr_pool_t *p;
+ char line[512];
+ char tok[512];
+
+ p = apr_pool_alloc_init();
+
+ printf("Enter field value to find items within:\n");
+ if (!gets(line))
+ exit(0);
+
+ printf("Enter search item:\n");
+ while (gets(tok)) {
+ printf(" [%s] == %s\n", tok, ap_find_list_item(p, line, tok)
+ ? "Yes" : "No");
+ printf("Enter search item:\n");
+ }
+
+ exit(0);
+}
diff --git a/test/test_limits.c b/test/test_limits.c
new file mode 100644
index 0000000..70b8098
--- /dev/null
+++ b/test/test_limits.c
@@ -0,0 +1,200 @@
+/**************************************************************
+ * test_limits.c
+ *
+ * A simple program for sending abusive requests to a server, based
+ * on the sioux.c exploit code that this nimrod posted (see below).
+ * Roy added options for testing long header fieldsize (-t h), long
+ * request-lines (-t r), and a long request body (-t b).
+ *
+ * FreeBSD 2.2.x, FreeBSD 3.0, IRIX 5.3, IRIX 6.2:
+ * gcc -o test_limits test_limits.c
+ *
+ * Solaris 2.5.1:
+ * gcc -o test_limits test_limits.c -lsocket -lnsl
+ *
+ *
+ * Message-ID: <861zqspvtw.fsf@niobe.ewox.org>
+ * Date: Fri, 7 Aug 1998 19:04:27 +0200
+ * Sender: Bugtraq List <BUGTRAQ@netspace.org>
+ * From: Dag-Erling Coidan =?ISO-8859-1?Q?Sm=F8rgrav?= <finrod@EWOX.ORG>
+ * Subject: YA Apache DoS attack
+ *
+ * Copyright (c) 1998 Dag-Erling Codan Smrgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * Kudos to Mark Huizer who originally suggested this on freebsd-current
+ */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define TEST_LONG_REQUEST_LINE 1
+#define TEST_LONG_REQUEST_FIELDS 2
+#define TEST_LONG_REQUEST_FIELDSIZE 3
+#define TEST_LONG_REQUEST_BODY 4
+
+void
+usage(void)
+{
+ fprintf(stderr,
+ "usage: test_limits [-t (r|n|h|b)] [-a address] [-p port] [-n num]\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct sockaddr_in sin;
+ struct hostent *he;
+ FILE *f;
+ int o, sd;
+
+ /* default parameters */
+ char *addr = "localhost";
+ int port = 80;
+ int num = 1000;
+ int testtype = TEST_LONG_REQUEST_FIELDS;
+
+ /* get options */
+ while ((o = getopt(argc, argv, "t:a:p:n:")) != EOF)
+ switch (o) {
+ case 't':
+ if (*optarg == 'r')
+ testtype = TEST_LONG_REQUEST_LINE;
+ else if (*optarg == 'n')
+ testtype = TEST_LONG_REQUEST_FIELDS;
+ else if (*optarg == 'h')
+ testtype = TEST_LONG_REQUEST_FIELDSIZE;
+ else if (*optarg == 'b')
+ testtype = TEST_LONG_REQUEST_BODY;
+ break;
+ case 'a':
+ addr = optarg;
+ break;
+ case 'p':
+ port = atoi(optarg);
+ break;
+ case 'n':
+ num = atoi(optarg);
+ break;
+ default:
+ usage();
+ }
+
+ if (argc != optind)
+ usage();
+
+ /* connect */
+ if ((he = gethostbyname(addr)) == NULL) {
+ perror("gethostbyname");
+ exit(1);
+ }
+ memset(&sin, sizeof(sin));
+ memcpy((char *)&sin.sin_addr, he->h_addr, he->h_length);
+ sin.sin_family = he->h_addrtype;
+ sin.sin_port = htons(port);
+
+ if ((sd = socket(sin.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
+ perror("socket");
+ exit(1);
+ }
+
+ if (connect(sd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
+ perror("connect");
+ exit(1);
+ }
+
+ if ((f = fdopen(sd, "r+")) == NULL) {
+ perror("fdopen");
+ exit(1);
+ }
+
+ /* attack! */
+ fprintf(stderr, "Testing like a plague of locusts on %s\n", addr);
+
+ if (testtype == TEST_LONG_REQUEST_LINE) {
+ fprintf(f, "GET ");
+ while (num-- && !ferror(f)) {
+ fprintf(f, "/123456789");
+ fflush(f);
+ }
+ fprintf(f, " HTTP/1.0\r\n\r\n");
+ }
+ else {
+ fprintf(f, "GET /fred/foo HTTP/1.0\r\n");
+
+ if (testtype == TEST_LONG_REQUEST_FIELDSIZE) {
+ while (num-- && !ferror(f)) {
+ fprintf(f, "User-Agent: sioux");
+ fflush(f);
+ }
+ fprintf(f, "\r\n");
+ }
+ else if (testtype == TEST_LONG_REQUEST_FIELDS) {
+ while (num-- && !ferror(f))
+ fprintf(f, "User-Agent: sioux\r\n");
+ fprintf(f, "\r\n");
+ }
+ else if (testtype == TEST_LONG_REQUEST_BODY) {
+ fprintf(f, "User-Agent: sioux\r\n");
+ fprintf(f, "Content-Length: 33554433\r\n");
+ fprintf(f, "\r\n");
+ while (num-- && !ferror(f))
+ fprintf(f, "User-Agent: sioux\r\n");
+ }
+ else {
+ fprintf(f, "\r\n");
+ }
+ }
+ fflush(f);
+
+ {
+ apr_ssize_t len;
+ char buff[512];
+
+ while ((len = read(sd, buff, 512)) > 0)
+ len = write(1, buff, len);
+ }
+ if (ferror(f)) {
+ perror("fprintf");
+ exit(1);
+ }
+
+ fclose(f);
+ exit(0);
+}
diff --git a/test/test_parser.c b/test/test_parser.c
new file mode 100644
index 0000000..bc5207d
--- /dev/null
+++ b/test/test_parser.c
@@ -0,0 +1,75 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This program tests the ap_get_list_item routine in ../main/util.c.
+ *
+ * The defines in this sample compile line are specific to Roy's system.
+ * They should match whatever was used to compile Apache first.
+ *
+ gcc -g -O2 -I../os/unix -I../include -o test_parser \
+ -DSOLARIS2=250 -Wall -DALLOC_DEBUG -DPOOL_DEBUG \
+ ../main/alloc.o ../main/buff.o ../main/util.o \
+ ../ap/libap.a -lsocket -lnsl test_parser.c
+ *
+ * Roy Fielding, 1999
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include "httpd.h"
+#include "apr_general.h"
+
+/*
+ * Dummy a bunch of stuff just to get a compile
+ */
+uid_t ap_user_id;
+gid_t ap_group_id;
+void *ap_dummy_mutex = &ap_dummy_mutex;
+char *ap_server_argv0;
+
+AP_DECLARE(void) ap_block_alarms(void)
+{
+ ;
+}
+
+AP_DECLARE(void) ap_unblock_alarms(void)
+{
+ ;
+}
+
+AP_DECLARE(void) ap_log_error(const char *file, int line, int level,
+ const request_rec *r, const char *fmt, ...)
+{
+ ;
+}
+
+int main (void)
+{
+ apr_pool_t *p;
+ const char *field;
+ char *newstr;
+ char instr[512];
+
+ p = apr_pool_alloc_init();
+
+ while (gets(instr)) {
+ printf(" [%s] ==\n", instr);
+ field = instr;
+ while ((newstr = ap_get_list_item(p, &field)) != NULL)
+ printf(" <%s> ..\n", newstr);
+ }
+
+ exit(0);
+}
diff --git a/test/test_select.c b/test/test_select.c
new file mode 100644
index 0000000..af11035
--- /dev/null
+++ b/test/test_select.c
@@ -0,0 +1,46 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This is just a quick test program to see how long a wait is
+ * produced by a select loop with an exponential backoff.
+ *
+ * gcc -g -O2 -o test_select test_select.c
+ * test_select
+ *
+ * Roy Fielding, 1996
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+int main (void)
+{
+ int srv;
+ long waittime = 4096;
+ struct timeval tv;
+
+ printf("Start\n");
+ while ((waittime > 0) && (waittime < 3000000)) {
+ printf("%d\n", waittime);
+ tv.tv_sec = waittime/1000000;
+ tv.tv_usec = waittime%1000000;
+ waittime <<= 1;
+ srv = select(0, NULL, NULL, NULL, &tv);
+ }
+ printf("End\n");
+ exit(0);
+}
diff --git a/test/time-sem.c b/test/time-sem.c
new file mode 100644
index 0000000..7bd0501
--- /dev/null
+++ b/test/time-sem.c
@@ -0,0 +1,591 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+time-sem.c has the basics of the semaphores we use in http_main.c. It's
+intended for timing differences between various methods on an
+architecture. In practice we've found many things affect which semaphore
+to be used:
+
+ - NFS filesystems absolutely suck for fcntl() and flock()
+
+ - uslock absolutely sucks on single-processor IRIX boxes, but
+ absolutely rocks on multi-processor boxes. The converse
+ is true for fcntl. sysvsem seems a moderate balance.
+
+ - Under Solaris you can't have too many processes use SEM_UNDO, there
+ might be a tuneable somewhere that increases the limit from 29.
+ We're not sure what the tunable is, so there's a define
+ NO_SEM_UNDO which can be used to simulate us trapping/blocking
+ signals to be able to properly release the semaphore on a clean
+ child death. You'll also need to define NEED_UNION_SEMUN
+ under solaris.
+
+You'll need to define USE_SHMGET_SCOREBOARD if anonymous shared mmap()
+doesn't work on your system (i.e. linux).
+
+argv[1] is the #children, argv[2] is the #iterations per child
+
+You should run each over many different #children inputs, and choose
+#iter such that the program runs for at least a second or so... or even
+longer depending on your patience.
+
+compile with:
+
+gcc -o time-FCNTL -Wall -O time-sem.c -DUSE_FCNTL_SERIALIZED_ACCEPT
+gcc -o time-FLOCK -Wall -O time-sem.c -DUSE_FLOCK_SERIALIZED_ACCEPT
+gcc -o time-SYSVSEM -Wall -O time-sem.c -DUSE_SYSVSEM_SERIALIZED_ACCEPT
+gcc -o time-SYSVSEM2 -Wall -O time-sem.c -DUSE_SYSVSEM_SERIALIZED_ACCEPT -DNO_SEM_UNDO
+gcc -o time-PTHREAD -Wall -O time-sem.c -DUSE_PTHREAD_SERIALIZED_ACCEPT -lpthread
+gcc -o time-USLOCK -Wall -O time-sem.c -DUSE_USLOCK_SERIALIZED_ACCEPT
+
+not all versions work on all systems.
+*/
+
+#include <errno.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <signal.h>
+
+#if defined(USE_FCNTL_SERIALIZED_ACCEPT)
+
+static struct flock lock_it;
+static struct flock unlock_it;
+
+static int fcntl_fd=-1;
+
+#define accept_mutex_child_init()
+#define accept_mutex_cleanup()
+
+/*
+ * Initialize mutex lock.
+ * Must be safe to call this on a restart.
+ */
+void
+accept_mutex_init(void)
+{
+
+ lock_it.l_whence = SEEK_SET; /* from current point */
+ lock_it.l_start = 0; /* -"- */
+ lock_it.l_len = 0; /* until end of file */
+ lock_it.l_type = F_WRLCK; /* set exclusive/write lock */
+ lock_it.l_pid = 0; /* pid not actually interesting */
+ unlock_it.l_whence = SEEK_SET; /* from current point */
+ unlock_it.l_start = 0; /* -"- */
+ unlock_it.l_len = 0; /* until end of file */
+ unlock_it.l_type = F_UNLCK; /* set exclusive/write lock */
+ unlock_it.l_pid = 0; /* pid not actually interesting */
+
+ printf("opening test-lock-thing in current directory\n");
+ fcntl_fd = open("test-lock-thing", O_CREAT | O_WRONLY | O_EXCL, 0644);
+ if (fcntl_fd == -1)
+ {
+ perror ("open");
+ fprintf (stderr, "Cannot open lock file: %s\n", "test-lock-thing");
+ exit (1);
+ }
+ unlink("test-lock-thing");
+}
+
+void accept_mutex_on(void)
+{
+ int ret;
+
+ while ((ret = fcntl(fcntl_fd, F_SETLKW, &lock_it)) < 0 && errno == EINTR)
+ continue;
+
+ if (ret < 0) {
+ perror ("fcntl lock_it");
+ exit(1);
+ }
+}
+
+void accept_mutex_off(void)
+{
+ if (fcntl (fcntl_fd, F_SETLKW, &unlock_it) < 0)
+ {
+ perror ("fcntl unlock_it");
+ exit(1);
+ }
+}
+
+#elif defined(USE_FLOCK_SERIALIZED_ACCEPT)
+
+#include <sys/file.h>
+
+static int flock_fd=-1;
+
+#define FNAME "test-lock-thing"
+
+/*
+ * Initialize mutex lock.
+ * Must be safe to call this on a restart.
+ */
+void accept_mutex_init(void)
+{
+
+ printf("opening " FNAME " in current directory\n");
+ flock_fd = open(FNAME, O_CREAT | O_WRONLY | O_EXCL, 0644);
+ if (flock_fd == -1)
+ {
+ perror ("open");
+ fprintf (stderr, "Cannot open lock file: %s\n", "test-lock-thing");
+ exit (1);
+ }
+}
+
+void accept_mutex_child_init(void)
+{
+ flock_fd = open(FNAME, O_WRONLY, 0600);
+ if (flock_fd == -1) {
+ perror("open");
+ exit(1);
+ }
+}
+
+void accept_mutex_cleanup(void)
+{
+ unlink(FNAME);
+}
+
+void accept_mutex_on(void)
+{
+ int ret;
+
+ while ((ret = flock(flock_fd, LOCK_EX)) < 0 && errno == EINTR)
+ continue;
+
+ if (ret < 0) {
+ perror ("flock(LOCK_EX)");
+ exit(1);
+ }
+}
+
+void accept_mutex_off(void)
+{
+ if (flock (flock_fd, LOCK_UN) < 0)
+ {
+ perror ("flock(LOCK_UN)");
+ exit(1);
+ }
+}
+
+#elif defined (USE_SYSVSEM_SERIALIZED_ACCEPT)
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+
+static int sem_id = -1;
+#ifdef NO_SEM_UNDO
+static sigset_t accept_block_mask;
+static sigset_t accept_previous_mask;
+#endif
+
+#define accept_mutex_child_init()
+#define accept_mutex_cleanup()
+
+void accept_mutex_init(void)
+{
+#ifdef NEED_UNION_SEMUN
+ /* believe it or not, you need to define this under solaris */
+ union semun {
+ int val;
+ struct semid_ds *buf;
+ ushort *array;
+ };
+#endif
+
+ union semun ick;
+
+ sem_id = semget(999, 1, IPC_CREAT | 0666);
+ if (sem_id < 0) {
+ perror ("semget");
+ exit (1);
+ }
+ ick.val = 1;
+ if (semctl(sem_id, 0, SETVAL, ick) < 0) {
+ perror ("semctl");
+ exit(1);
+ }
+#ifdef NO_SEM_UNDO
+ sigfillset(&accept_block_mask);
+ sigdelset(&accept_block_mask, SIGHUP);
+ sigdelset(&accept_block_mask, SIGTERM);
+ sigdelset(&accept_block_mask, SIGUSR1);
+#endif
+}
+
+void accept_mutex_on()
+{
+ struct sembuf op;
+
+#ifdef NO_SEM_UNDO
+ if (sigprocmask(SIG_BLOCK, &accept_block_mask, &accept_previous_mask)) {
+ perror("sigprocmask(SIG_BLOCK)");
+ exit (1);
+ }
+ op.sem_flg = 0;
+#else
+ op.sem_flg = SEM_UNDO;
+#endif
+ op.sem_num = 0;
+ op.sem_op = -1;
+ if (semop(sem_id, &op, 1) < 0) {
+ perror ("accept_mutex_on");
+ exit (1);
+ }
+}
+
+void accept_mutex_off()
+{
+ struct sembuf op;
+
+ op.sem_num = 0;
+ op.sem_op = 1;
+#ifdef NO_SEM_UNDO
+ op.sem_flg = 0;
+#else
+ op.sem_flg = SEM_UNDO;
+#endif
+ if (semop(sem_id, &op, 1) < 0) {
+ perror ("accept_mutex_off");
+ exit (1);
+ }
+#ifdef NO_SEM_UNDO
+ if (sigprocmask(SIG_SETMASK, &accept_previous_mask, NULL)) {
+ perror("sigprocmask(SIG_SETMASK)");
+ exit (1);
+ }
+#endif
+}
+
+#elif defined (USE_PTHREAD_SERIALIZED_ACCEPT)
+
+/* note: pthread mutexes aren't released on child death, hence the
+ * signal goop ... in a real implementation we'd do special things
+ * during hup, term, usr1.
+ */
+
+#include <pthread.h>
+
+static pthread_mutex_t *mutex;
+static sigset_t accept_block_mask;
+static sigset_t accept_previous_mask;
+
+#define accept_mutex_child_init()
+#define accept_mutex_cleanup()
+
+void accept_mutex_init(void)
+{
+ pthread_mutexattr_t mattr;
+ int fd;
+
+ fd = open ("/dev/zero", O_RDWR);
+ if (fd == -1) {
+ perror ("open(/dev/zero)");
+ exit (1);
+ }
+ mutex = (pthread_mutex_t *)mmap ((caddr_t)0, sizeof (*mutex),
+ PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if (mutex == (void *)(caddr_t)-1) {
+ perror ("mmap");
+ exit (1);
+ }
+ close (fd);
+ if (pthread_mutexattr_init(&mattr)) {
+ perror ("pthread_mutexattr_init");
+ exit (1);
+ }
+ if (pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED)) {
+ perror ("pthread_mutexattr_setpshared");
+ exit (1);
+ }
+ if (pthread_mutex_init(mutex, &mattr)) {
+ perror ("pthread_mutex_init");
+ exit (1);
+ }
+ sigfillset(&accept_block_mask);
+ sigdelset(&accept_block_mask, SIGHUP);
+ sigdelset(&accept_block_mask, SIGTERM);
+ sigdelset(&accept_block_mask, SIGUSR1);
+}
+
+void accept_mutex_on()
+{
+ if (sigprocmask(SIG_BLOCK, &accept_block_mask, &accept_previous_mask)) {
+ perror("sigprocmask(SIG_BLOCK)");
+ exit (1);
+ }
+ if (pthread_mutex_lock (mutex)) {
+ perror ("pthread_mutex_lock");
+ exit (1);
+ }
+}
+
+void accept_mutex_off()
+{
+ if (pthread_mutex_unlock (mutex)) {
+ perror ("pthread_mutex_unlock");
+ exit (1);
+ }
+ if (sigprocmask(SIG_SETMASK, &accept_previous_mask, NULL)) {
+ perror("sigprocmask(SIG_SETMASK)");
+ exit (1);
+ }
+}
+
+#elif defined (USE_USLOCK_SERIALIZED_ACCEPT)
+
+#include <ulocks.h>
+
+static usptr_t *us = NULL;
+static ulock_t uslock = NULL;
+
+#define accept_mutex_child_init()
+#define accept_mutex_cleanup()
+
+void accept_mutex_init(void)
+{
+ ptrdiff_t old;
+ /* default is 8 */
+#define CONF_INITUSERS_MAX 15
+ if ((old = usconfig(CONF_INITUSERS, CONF_INITUSERS_MAX)) == -1) {
+ perror("usconfig");
+ exit(-1);
+ }
+ if ((old = usconfig(CONF_LOCKTYPE, US_NODEBUG)) == -1) {
+ perror("usconfig");
+ exit(-1);
+ }
+ if ((old = usconfig(CONF_ARENATYPE, US_SHAREDONLY)) == -1) {
+ perror("usconfig");
+ exit(-1);
+ }
+ if ((us = usinit("/dev/zero")) == NULL) {
+ perror("usinit");
+ exit(-1);
+ }
+ if ((uslock = usnewlock(us)) == NULL) {
+ perror("usnewlock");
+ exit(-1);
+ }
+}
+void accept_mutex_on()
+{
+ switch(ussetlock(uslock)) {
+ case 1:
+ /* got lock */
+ break;
+ case 0:
+ fprintf(stderr, "didn't get lock\n");
+ exit(-1);
+ case -1:
+ perror("ussetlock");
+ exit(-1);
+ }
+}
+void accept_mutex_off()
+{
+ if (usunsetlock(uslock) == -1) {
+ perror("usunsetlock");
+ exit(-1);
+ }
+}
+#endif
+
+
+#ifndef USE_SHMGET_SCOREBOARD
+static void *get_shared_mem(apr_size_t size)
+{
+ void *result;
+
+ /* allocate shared memory for the shared_counter */
+ result = (unsigned long *)mmap ((caddr_t)0, size,
+ PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
+ if (result == (void *)(caddr_t)-1) {
+ perror ("mmap");
+ exit (1);
+ }
+ return result;
+}
+#else
+#include <sys/types.h>
+#include <sys/ipc.h>
+#ifdef HAVE_SYS_MUTEX_H
+#include <sys/mutex.h>
+#endif
+#include <sys/shm.h>
+
+static void *get_shared_mem(apr_size_t size)
+{
+ key_t shmkey = IPC_PRIVATE;
+ int shmid = -1;
+ void *result;
+#ifdef MOVEBREAK
+ char *obrk;
+#endif
+
+ if ((shmid = shmget(shmkey, size, IPC_CREAT | SHM_R | SHM_W)) == -1) {
+ perror("shmget");
+ exit(1);
+ }
+
+#ifdef MOVEBREAK
+ /*
+ * Some SysV systems place the shared segment WAY too close
+ * to the dynamic memory break point (sbrk(0)). This severely
+ * limits the use of malloc/sbrk in the program since sbrk will
+ * refuse to move past that point.
+ *
+ * To get around this, we move the break point "way up there",
+ * attach the segment and then move break back down. Ugly
+ */
+ if ((obrk = sbrk(MOVEBREAK)) == (char *) -1) {
+ perror("sbrk");
+ }
+#endif
+
+#define BADSHMAT ((void *)(-1))
+ if ((result = shmat(shmid, 0, 0)) == BADSHMAT) {
+ perror("shmat");
+ }
+ /*
+ * We must avoid leaving segments in the kernel's
+ * (small) tables.
+ */
+ if (shmctl(shmid, IPC_RMID, NULL) != 0) {
+ perror("shmctl(IPC_RMID)");
+ }
+ if (result == BADSHMAT) /* now bailout */
+ exit(1);
+
+#ifdef MOVEBREAK
+ if (obrk == (char *) -1)
+ return; /* nothing else to do */
+ if (sbrk(-(MOVEBREAK)) == (char *) -1) {
+ perror("sbrk 2");
+ }
+#endif
+ return result;
+}
+#endif
+
+#ifdef _POSIX_PRIORITY_SCHEDULING
+/* don't ask */
+#define _P __P
+#include <sched.h>
+#define YIELD sched_yield()
+#else
+#define YIELD do { struct timeval zero; zero.tv_sec = zero.tv_usec = 0; select(0,0,0,0,&zero); } while(0)
+#endif
+
+void main (int argc, char **argv)
+{
+ int num_iter;
+ int num_child;
+ int i;
+ struct timeval first;
+ struct timeval last;
+ long ms;
+ int pid;
+ unsigned long *shared_counter;
+
+ if (argc != 3) {
+ fprintf (stderr, "Usage: time-sem num-child num iter\n");
+ exit (1);
+ }
+
+ num_child = atoi (argv[1]);
+ num_iter = atoi (argv[2]);
+
+ /* allocate shared memory for the shared_counter */
+ shared_counter = get_shared_mem(sizeof(*shared_counter));
+
+ /* initialize counter to 0 */
+ *shared_counter = 0;
+
+ accept_mutex_init ();
+
+ /* parent grabs mutex until done spawning children */
+ accept_mutex_on ();
+
+ for (i = 0; i < num_child; ++i) {
+ pid = fork();
+ if (pid == 0) {
+ /* child, do our thing */
+ accept_mutex_child_init();
+ for (i = 0; i < num_iter; ++i) {
+ unsigned long tmp;
+
+ accept_mutex_on ();
+ tmp = *shared_counter;
+ YIELD;
+ *shared_counter = tmp + 1;
+ accept_mutex_off ();
+ }
+ exit (0);
+ } else if (pid == -1) {
+ perror ("fork");
+ exit (1);
+ }
+ }
+
+ /* a quick test to see that nothing is screwed up */
+ if (*shared_counter != 0) {
+ puts ("WTF! shared_counter != 0 before the children have been started!");
+ exit (1);
+ }
+
+ gettimeofday (&first, NULL);
+ /* launch children into action */
+ accept_mutex_off ();
+ for (i = 0; i < num_child; ++i) {
+ if (wait(NULL) == -1) {
+ perror ("wait");
+ }
+ }
+ gettimeofday (&last, NULL);
+
+ if (*shared_counter != num_child * num_iter) {
+ printf ("WTF! shared_counter != num_child * num_iter!\n"
+ "shared_counter = %lu\nnum_child = %d\nnum_iter=%d\n",
+ *shared_counter,
+ num_child, num_iter);
+ }
+
+ last.tv_sec -= first.tv_sec;
+ ms = last.tv_usec - first.tv_usec;
+ if (ms < 0) {
+ --last.tv_sec;
+ ms += 1000000;
+ }
+ last.tv_usec = ms;
+ printf ("%8lu.%06lu\n", last.tv_sec, last.tv_usec);
+
+ accept_mutex_cleanup();
+
+ exit(0);
+}
+