summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2015-11-21 14:51:17 +0100
committerJörg Frings-Fürst <debian@jff-webhosting.net>2015-11-21 14:51:17 +0100
commitbb9bc9051629c3319c56785c2f4ae0e605d76329 (patch)
treeec393eb145e5a7d43909bdfc43cdeaa28c4e434a
Initial import of bitz-server version 0.1.6-1
-rw-r--r--.gitignore38
-rw-r--r--Makefile.am19
-rw-r--r--README.md168
-rw-r--r--acinclude.m4134
-rw-r--r--changelog36
-rw-r--r--conf/Makefile.am26
-rw-r--r--conf/bitz-server.conf.in56
-rw-r--r--configure.ac147
-rw-r--r--debian/README.debian12
-rw-r--r--debian/README.lintian7
-rw-r--r--debian/bitz-server-doc.dirs1
-rw-r--r--debian/bitz-server-doc.doc-base7
-rw-r--r--debian/bitz-server-doc.docs1
-rw-r--r--debian/bitz-server-doc.lintian-overrides7
-rw-r--r--debian/bitz-server.docs2
-rw-r--r--debian/bitz-server.init132
-rw-r--r--debian/bitz-server.install2
-rw-r--r--debian/bitz-server.manpages2
-rw-r--r--debian/bitz-server.postrm22
-rw-r--r--debian/bitz-server.service11
-rw-r--r--debian/bitz-server.upstart7
-rw-r--r--debian/changelog5
-rw-r--r--debian/compat1
-rw-r--r--debian/control162
-rw-r--r--debian/copyright33
-rw-r--r--debian/doc/why_delete_systemd_file_via_postrm.txt807
-rw-r--r--debian/libicap-dev.docs1
-rw-r--r--debian/libicap-dev.install2
-rw-r--r--debian/libicap0.install1
-rw-r--r--debian/libicap0.symbols193
-rw-r--r--debian/libicap0.symbols.i386187
-rw-r--r--debian/patches/0001-disable_search_doc.patch18
-rw-r--r--debian/patches/0100-python_print.patch171
-rw-r--r--debian/patches/series2
-rwxr-xr-xdebian/rules35
-rw-r--r--debian/source/format1
-rw-r--r--debian/watch5
-rw-r--r--doc/Makefile.am30
-rw-r--r--doc/bitz-server.conf.man64
-rw-r--r--doc/bitz-server.man47
-rw-r--r--doc/doxygen.cfg.in1864
-rw-r--r--include/Makefile.am1
-rw-r--r--lib/Makefile.am3
-rw-r--r--lib/icap/Makefile.am24
-rw-r--r--lib/icap/common.h41
-rw-r--r--lib/icap/header.cpp223
-rw-r--r--lib/icap/header.h168
-rw-r--r--lib/icap/request.cpp84
-rw-r--r--lib/icap/request.h72
-rw-r--r--lib/icap/request_header.cpp113
-rw-r--r--lib/icap/request_header.h84
-rw-r--r--lib/icap/response.cpp81
-rw-r--r--lib/icap/response.h65
-rw-r--r--lib/icap/response_header.cpp101
-rw-r--r--lib/icap/response_header.h78
-rw-r--r--lib/icap/util.cpp693
-rw-r--r--lib/icap/util.h265
-rw-r--r--lib/socket/Makefile.am4
-rw-r--r--lib/socket/socket.cpp472
-rw-r--r--lib/socket/socket.h427
-rw-r--r--modules/Makefile.am3
-rw-r--r--modules/echo/Makefile.am9
-rw-r--r--modules/echo/echo.cpp55
-rw-r--r--modules/echo/echo.h54
-rw-r--r--modules/modpy/Makefile.am18
-rw-r--r--modules/modpy/interface.cpp160
-rw-r--r--modules/modpy/interface.h39
-rw-r--r--modules/modpy/modules/Makefile.am11
-rw-r--r--modules/modpy/modules/modpy.py42
-rw-r--r--modules/modpy/py.cpp265
-rw-r--r--modules/modpy/py.h70
-rw-r--r--src/Makefile.am32
-rw-r--r--src/bitz-server.cpp472
-rw-r--r--src/bitz-server.h113
-rw-r--r--src/bitz/common.h40
-rw-r--r--src/bitz/config.cpp190
-rw-r--r--src/bitz/config.h95
-rw-r--r--src/bitz/exception.cpp40
-rw-r--r--src/bitz/exception.h43
-rw-r--r--src/bitz/logger.cpp98
-rw-r--r--src/bitz/logger.h62
-rw-r--r--src/bitz/manager.cpp223
-rw-r--r--src/bitz/manager.h87
-rw-r--r--src/bitz/manager_exception.cpp32
-rw-r--r--src/bitz/manager_exception.h36
-rw-r--r--src/bitz/modifier.cpp29
-rw-r--r--src/bitz/modifier.h70
-rw-r--r--src/bitz/options_request_handler.cpp57
-rw-r--r--src/bitz/options_request_handler.h51
-rw-r--r--src/bitz/reqmod_request_handler.cpp30
-rw-r--r--src/bitz/reqmod_request_handler.h41
-rw-r--r--src/bitz/request_handler.cpp401
-rw-r--r--src/bitz/request_handler.h133
-rw-r--r--src/bitz/respmod_request_handler.cpp30
-rw-r--r--src/bitz/respmod_request_handler.h41
-rw-r--r--src/bitz/util.cpp122
-rw-r--r--src/bitz/util.h92
-rw-r--r--src/bitz/worker.cpp138
-rw-r--r--src/bitz/worker.h47
-rw-r--r--src/main.cpp82
-rw-r--r--test/icap-client.py211
-rw-r--r--test/sample.txt192
-rw-r--r--test/valgrind.supp29
103 files changed, 11550 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a768d50
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,38 @@
+# Some generics first
+# Compiled Object files
+*.slo
+*.lo
+*.o
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+
+# autotools
+autom4te.cache/*
+aux-build/*
+aclocal.m4
+config.h.in
+configure
+Makefile.in
+
+# eclipse
+.project
+.cproject
+.settings/*
+.pydevproject
+
+# swap files
+*.swp
+
+# python
+*.pyc
+
+# project specific
+build/*
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..84af588
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,19 @@
+## Makefile.am -- Process this file with automake to produce Makefile.in
+
+# amflags
+ACLOCAL_AMFLAGS = -I aux-build/m4
+
+# sub dirs
+SUBDIRS = \
+ conf \
+ doc \
+ include \
+ lib \
+ modules \
+ src
+
+# extra dist files
+EXTRA_DIST = \
+ changelog \
+ README.md
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..799c2ef
--- /dev/null
+++ b/README.md
@@ -0,0 +1,168 @@
+bitz-server
+===========
+
+An ICAP server implementation in C++
+
+### Copyright and License
+
+Copyright (C) 2012-2013 Uditha Atukorala.
+
+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 3 of the License, 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](http://gnu.org/licenses/gpl.html)
+for more details.
+
+
+### The concept
+
+The main goal of this project is to create an ICAP server
+([RFC 3507](http://www.ietf.org/rfc/rfc3507.txt)) implementation in C++
+to use the power of object oriented programming.
+
+Starting from scratch, the server is developed with a modular architecture in mind.
+The server core (written in C++) will handle the client requests, manage workers
+(child processes) etc. and will provide basic handlers to serve ICAP requests.
+
+To extend this core functionality the idea is to have pluggable modules (like apache
+server modules). These modules will provide features like content filtering, anti-virus
+scanning etc. and to make it easier to write (and faster to implement) such modules
+there is hope to exploit python programming language.
+
+
+### Acknowledgements
+
+* Many thanks to Kenneth Oksanen for his support in finding and fixing bugs
+
+
+### Downloads
+You can download the source distributions from http://packages.geniusse.com/source/bitz-server/.
+
+
+#### Debian/Ubuntu packages
+First you should add the repository key to avoid warning.
+
+ $ wget -q -O - http://packages.geniusse.com/debian/packman.gpg.key | sudo apt-key add -
+
+Then add the following to your `/etc/apt/sources.list`;
+
+ $ deb http://packages.geniusse.com/debian/ [release] main
+
+where the `[release]` being wheezy, jessie, sid etc.
+
+Finally update your package list and install bitz-server;
+
+ $ sudo aptitude update
+ $ sudo aptitude install bitz-server
+
+
+### Dependencies
+
+* [libconfig++ >= 1.4](http://www.hyperrealm.com/libconfig/)
+* log4cpp >= 1.0
+* python 2.7 (for modpy module)
+
+
+### Bugs and Feature Requests
+
+Please report all bugs and feature requests [here](http://bugs.geniusse.com/) under the
+[bitz-server](http://bugs.geniusse.com/enter_bug.cgi?product=bitz-server) project.
+Known issues can be found [here](http://bugs.geniusse.com/buglist.cgi?query_format=specific&order=relevance%20desc&bug_status=__open__&product=bitz-server&list_id=36).
+
+
+### Version history
+
+__0.1.6__ - _28th September 2013_
+* Few tweaks and minor changes distribution files (no functional changes)
+
+__0.1.5__ - _11th August 2013_
+* Fixing modpy interface module string copy bug
+
+__0.1.4__ - _01st August 2013_
+* Code optimisations
+* Fixing bug [#34](http://bugs.geniusse.com/show_bug.cgi?id=34)
+
+__0.1.3__ - _29th July 2013_
+* Fixing bugs
+ [#31](http://bugs.geniusse.com/show_bug.cgi?id=31),
+ [#32](http://bugs.geniusse.com/show_bug.cgi?id=32)
+
+__0.1.2__ - _07th July 2013_
+* Added a RESPMOD handler ([bug #16](http://bugs.geniusse.com/show_bug.cgi?id=16))
+* Added Message Preview features ([bug #17](http://bugs.geniusse.com/show_bug.cgi?id=17))
+* Code cleanup and optimisations
+* Fixing bugs [#15](http://bugs.geniusse.com/show_bug.cgi?id=15),
+ [#23](http://bugs.geniusse.com/show_bug.cgi?id=23),
+ [#24](http://bugs.geniusse.com/show_bug.cgi?id=24),
+ [#25](http://bugs.geniusse.com/show_bug.cgi?id=25)
+
+__0.1.1__ - _06th March 2013_
+* Fixing bugs [#19](http://bugs.geniusse.com/show_bug.cgi?id=19) and [#22](http://bugs.geniusse.com/show_bug.cgi?id=22)
+
+__0.1.0__ - _03rd March 2013_
+
+* Daemonized version ([bug #18](http://bugs.geniusse.com/show_bug.cgi?id=18)), hence
+ the minor version bump. Server core is re-organised with bitz::server namespace to
+ be more cleaner and easier to read.
+* Make it possible to pass in command-line options
+* Closed a memory leak in modpy module
+* Fixing bugs [#20](http://bugs.geniusse.com/show_bug.cgi?id=20) and [#21](http://bugs.geniusse.com/show_bug.cgi?id=21)
+
+
+__0.0.1__ - _24th February 2013_
+
+* Proof of concept. An ICAP server with only a REQMOD handler. Includes a template
+ _echo_ module to demonstrate the pluggable module architecture and the _modpy_ module
+ to demonstrate the python interface.
+
+---------------------------------------
+
+
+### Compiling from source
+
+First you need to initialise the autotools
+
+ $ libtoolize (glibtoolize in OS X)
+ $ aclocal
+ $ autoheader
+ $ autoconf
+ $ automake --add-missing --foreign
+
+Or you can grab the latest source distribution tar from [CI artifacts](http://jenkins.geniusse.com/job/bitz-server/).
+
+After that you can use the usual `./configure && make`
+
+
+#### Notes
+##### modpy
+This is the (long awaited) python interface module. It provides a template for any
+other python interface module implementations either as C++ module template or as
+a C++ interface for python modules.
+
+
+##### Debugging
+
+Use the following to create the binaries with debug symbols
+
+ $ ./configure CXXFLAGS="-g -O0"
+
+
+##### config file
+
+The default config file location is `/etc/bitz/bitz-server.conf` but this can
+changed using the `--with-config` option when you run `configure`.
+
+e.g.
+
+ $ ./configure --with-config=/[path to source code]/conf/bitz-server.conf
+
+
+##### valgrind checks
+
+ $ valgrind --leak-check=full --read-var-info=yes --trace-children=yes --suppressions=test/valgrind.supp --log-file=valgrind.log ./src/bitz-server --debug
+
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644
index 0000000..73d421f
--- /dev/null
+++ b/acinclude.m4
@@ -0,0 +1,134 @@
+## this one is commonly used with AM_PATH_PYTHONDIR ...
+dnl AM_CHECK_PYMOD(MODNAME [,SYMBOL [,ACTION-IF-FOUND [,ACTION-IF-NOT-FOUND]]])
+dnl Check if a module containing a given symbol is visible to python.
+AC_DEFUN([AM_CHECK_PYMOD],
+[AC_REQUIRE([AM_PATH_PYTHON])
+py_mod_var=`echo $1['_']$2 | sed 'y%./+-%__p_%'`
+AC_MSG_CHECKING(for ifelse([$2],[],,[$2 in ])python module $1)
+AC_CACHE_VAL(py_cv_mod_$py_mod_var, [
+ifelse([$2],[], [prog="
+import sys
+try:
+ import $1
+except ImportError:
+ sys.exit(1)
+except:
+ sys.exit(0)
+sys.exit(0)"], [prog="
+import $1
+$1.$2"])
+if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC
+ then
+ eval "py_cv_mod_$py_mod_var=yes"
+ else
+ eval "py_cv_mod_$py_mod_var=no"
+ fi
+])
+py_val=`eval "echo \`echo '$py_cv_mod_'$py_mod_var\`"`
+if test "x$py_val" != xno; then
+ AC_MSG_RESULT(yes)
+ ifelse([$3], [],, [$3
+])dnl
+else
+ AC_MSG_RESULT(no)
+ ifelse([$4], [],, [$4
+])dnl
+fi
+])
+
+dnl a macro to check for ability to create python extensions
+dnl AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE])
+dnl function also defines PYTHON_INCLUDES
+AC_DEFUN([AM_CHECK_PYTHON_HEADERS],
+[AC_REQUIRE([AM_PATH_PYTHON])
+AC_MSG_CHECKING(for headers required to compile python extensions)
+dnl deduce PYTHON_INCLUDES
+py_prefix=`$PYTHON -c "import sys; print sys.prefix"`
+py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"`
+if $PYTHON-config --help 2>/dev/null; then
+ PYTHON_INCLUDES=`$PYTHON-config --includes 2>/dev/null`
+else
+ PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}"
+ if test "$py_prefix" != "$py_exec_prefix"; then
+ PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}"
+ fi
+fi
+AC_SUBST(PYTHON_INCLUDES)
+dnl check if the headers exist:
+save_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES"
+AC_TRY_CPP([#include <Python.h>],dnl
+[AC_MSG_RESULT(found)
+$1],dnl
+[AC_MSG_RESULT(not found)
+$2])
+CPPFLAGS="$save_CPPFLAGS"
+])
+
+dnl a macro to check for ability to embed python
+dnl AM_CHECK_PYTHON_LIBS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE])
+dnl function also defines PYTHON_LIBS
+AC_DEFUN([AM_CHECK_PYTHON_LIBS],
+[AC_REQUIRE([AM_CHECK_PYTHON_HEADERS])
+AC_MSG_CHECKING(for libraries required to embed python)
+dnl deduce PYTHON_LIBS
+py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"`
+PYTHON_LIBS="-L${py_prefix}/lib -lpython${PYTHON_VERSION}"
+PYTHON_LIB_LOC="${py_prefix}/lib"
+AC_SUBST(PYTHON_LIBS)
+AC_SUBST(PYTHON_LIB_LOC)
+dnl check if the headers exist:
+save_LIBS="$LIBS"
+LIBS="$LIBS $PYTHON_LIBS"
+AC_TRY_LINK_FUNC(Py_Initialize, dnl
+ [LIBS="$save_LIBS"; AC_MSG_RESULT(yes); $1], dnl
+ [LIBS="$save_LIBS"; AC_MSG_RESULT(no); $2])
+
+])
+
+
+dnl as-ac-expand.m4 0.2.0
+dnl autostars m4 macro for expanding directories using configure's prefix
+dnl thomas@apestaart.org
+dnl
+
+dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR)
+dnl example
+dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir)
+dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local
+
+AC_DEFUN([AS_AC_EXPAND],
+[
+ EXP_VAR=[$1]
+ FROM_VAR=[$2]
+
+ dnl first expand prefix and exec_prefix if necessary
+ prefix_save=$prefix
+ exec_prefix_save=$exec_prefix
+
+ dnl if no prefix given, then use /usr/local, the default prefix
+ if test "x$prefix" = "xNONE"; then
+ prefix="$ac_default_prefix"
+ fi
+ dnl if no exec_prefix given, then use prefix
+ if test "x$exec_prefix" = "xNONE"; then
+ exec_prefix=$prefix
+ fi
+
+ full_var="$FROM_VAR"
+ dnl loop until it doesn't change anymore
+ while true; do
+ new_full_var="`eval echo $full_var`"
+ if test "x$new_full_var" = "x$full_var"; then break; fi
+ full_var=$new_full_var
+ done
+
+ dnl clean up
+ full_var=$new_full_var
+ AC_SUBST([$1], "$full_var")
+
+ dnl restore prefix and exec_prefix
+ prefix=$prefix_save
+ exec_prefix=$exec_prefix_save
+])
+
diff --git a/changelog b/changelog
new file mode 100644
index 0000000..520a174
--- /dev/null
+++ b/changelog
@@ -0,0 +1,36 @@
+0.1.6 - 28th September 2013
+ * Few tweaks and minor changes distribution files (no functional changes)
+
+0.1.5 - 11th August 2013
+ * Fixing modpy interface module string copy bug
+
+0.1.4 - 01st August 2013
+ * Code optimisations
+ * Fixing bug #34
+
+0.1.3 - 29th July 2013
+ * Fixing bugs #31, #32
+
+0.1.2 - 07th July 2013
+ * Added a RESPMOD handler (bug #16)
+ * Added Message Preview features (bug #17)
+ * Code cleanup and optimisations
+ * Fixing bugs #15, #23, #24, #25
+
+0.1.1 - 06th March 2013
+ * Fixing bugs #19 and #22
+
+0.1.0 - 03rd March 2013
+ * Daemonized version (bug #18), hence the minor version bump. Server
+ core is re-organised with bitz::server namespace to be more cleaner
+ and easier to read.
+ * Make it possible to pass in command-line options
+ * Closed a memory leak in modpy module
+ * Fixing bugs #20, #21
+
+
+0.0.1 - 24th February 2013
+ * Proof of concept. An ICAP server with only a REQMOD handler. Includes
+ a template 'echo' module to demonstrate the pluggable module architecture
+ and the 'modpy' module to demonstrate the python interface.
+
diff --git a/conf/Makefile.am b/conf/Makefile.am
new file mode 100644
index 0000000..1dce407
--- /dev/null
+++ b/conf/Makefile.am
@@ -0,0 +1,26 @@
+## conf/
+configdir = $(sysconfdir)/bitz
+config_DATA = bitz-server.conf
+
+# extra dist files
+EXTRA_DIST = \
+ bitz-server.conf.in
+
+
+edit = sed \
+ -e 's|@sysconfdir[@]|$(sysconfdir)|g' \
+ -e 's|@localstatedir[@]|$(localstatedir)|g' \
+ -e 's|@pkglibdir[@]|$(pkglibdir)|g'
+
+bitz-server.conf: bitz-server.conf.in
+ rm -f $@ $@.tmp
+ srcdir=''; \
+ test -f ./$@.in || srcdir=$(srcdir)/; \
+ $(edit) $${srcdir}$@.in >$@.tmp
+ chmod +r $@.tmp
+ chmod og-wx $@.tmp
+ mv $@.tmp $@
+
+clean-local:
+ rm -f *.conf
+
diff --git a/conf/bitz-server.conf.in b/conf/bitz-server.conf.in
new file mode 100644
index 0000000..95083c4
--- /dev/null
+++ b/conf/bitz-server.conf.in
@@ -0,0 +1,56 @@
+#
+# @sysconfdir@/bitz/bitz-server.conf
+#
+
+port = 1344;
+
+pid_file = "@localstatedir@/run/bitz/bitz-server.pid";
+log_file = "@localstatedir@/log/bitz/bitz-server.log";
+log_category = "bitz-server";
+
+# maximum number of workers
+max_workers = 1;
+
+# maximum number of requests a worker will serve
+max_worker_requests = 100;
+
+
+# request handlers
+req_handlers :
+({
+ handler = "REQMOD";
+ class = "ReqmodRequestHandler";
+ modules :
+ (
+ {
+ name = "modpy";
+ module = "@pkglibdir@/modules/mod_py.so";
+ }
+ )
+},
+{
+ handler = "RESPMOD";
+ class = "RespmodRequestHandler";
+ modules :
+ (
+ {
+ name = "modpy";
+ module = "@pkglibdir@/modules/mod_py.so";
+ }
+ )
+});
+
+
+# module configurations
+modules :
+{
+ modpy :
+ {
+ # search path for python modules
+ module_path = "@pkglibdir@/modules/modpy";
+
+ # python module containing the interface methods
+ module_name = "modpy";
+ };
+};
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..9f43dd1
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,147 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ([2.68])
+AC_INIT([bitz-server], [0.1.6], [http://bugs.geniusse.com/])
+AC_CONFIG_AUX_DIR([aux-build])
+AC_CONFIG_MACRO_DIR([aux-build/m4])
+AC_CONFIG_HEADERS([include/config.h])
+
+# Versioning rules ( C:R:A )
+#
+# 1. Start with version 0:0:0.
+# 2. If any of the sources have changed, increment R. This is a new revision
+# of the current interface.
+# 3. If the interface has changed, increment C and set R to 0. This is the
+# first revision of a new interface.
+# 4. If the new interface is a superset of the previous interface
+# (that is, if the previous interface has not been broken by the
+# changes in this new release), increment A. This release is backwards
+# compatible with the previous release.
+# 5. If the new interface has removed elements with respect to the
+# previous interface, then backward compatibility is broken; set A to 0.
+# This release has a new, but backwards incompatible interface.
+#
+# For more info see section 6.3 of the GNU Libtool Manual.
+#
+# In short;
+# +1 : ? : +1 == new interface that does not break old one
+# +1 : ? : 0 == new interface that breaks old one
+# ? : ? : 0 == no new interfaces, but breaks apps
+# ? :+1 : ? == just some internal changes, nothing breaks but might work
+# better
+# CURRENT : REVISION : AGE
+
+# lib versions
+ICAP_LT_VERSION=0:3:0
+AC_SUBST(ICAP_LT_VERSION)
+
+# Init
+AM_INIT_AUTOMAKE([foreign])
+LT_INIT()
+
+# Check for programs
+AC_PROG_CXX
+AC_PROG_INSTALL
+AC_PROG_AWK
+AC_PROG_MKDIR_P
+AC_PROG_LIBTOOL
+
+# Language
+AC_LANG(C++)
+
+# Options
+AC_ARG_WITH([config],
+ [AS_HELP_STRING([--with-config],
+ [specify the config file to be used])],
+ [], [with_config=no])
+
+AC_ARG_ENABLE([modpy],
+ [AS_HELP_STRING([--enable-modpy],[Enable modpy module (default is yes)])],
+ [case "${enableval}" in
+ yes) modpy=true ;;
+ no) modpy=false ;;
+ *) AC_MSG_ERROR([bad value ${enableval} for --enable-modpy]) ;;
+ esac],
+ [modpy=true]
+)
+AM_CONDITIONAL([MODPY], [test x$modpy = xtrue])
+
+
+# Checks for libraries
+AM_PROG_LIBTOOL
+
+PKG_PROG_PKG_CONFIG
+PKG_CHECK_MODULES([libconfig], [libconfig++ >= 1.4],,
+ AC_MSG_ERROR([libconfig++ 1.4 or newer not found.])
+)
+PKG_CHECK_MODULES([log4cpp], [log4cpp >= 1.0],,
+ AC_MSG_ERROR([log4cpp 1.0 or newer not found.])
+)
+
+
+# Checks for header files.
+#AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stddef.h stdlib.h string.h sys/socket.h syslog.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_HEADER_STDBOOL
+AC_C_INLINE
+AC_TYPE_SIZE_T
+AC_CHECK_TYPES([ptrdiff_t])
+
+# Checks for library functions.
+AC_FUNC_ERROR_AT_LINE
+AC_FUNC_FORK
+AC_CHECK_FUNCS([gethostbyname inet_ntoa memmove memset select socket strchr strerror])
+
+# conditional statements
+AS_IF([test x$modpy = xtrue],
+ [
+ AM_PATH_PYTHON([2.7])
+ AM_CHECK_PYTHON_HEADERS
+ AM_CHECK_PYTHON_LIBS
+ ]
+)
+
+# defines / substitutes
+AS_IF([test "x$with_config" != xno],
+ AC_DEFINE_UNQUOTED([BITZ_SERVER_CONFIG_FILE],
+ ["$with_config"],
+ [server configuration file]
+ ),
+ [
+ AS_AC_EXPAND(SYSCONFDIR, $sysconfdir)
+ AC_DEFINE_UNQUOTED(
+ [BITZ_SERVER_CONFIG_FILE],
+ ["${SYSCONFDIR}/bitz/bitz-server.conf"],
+ [server configuration file]
+ )
+ ]
+)
+
+# doxygen
+AC_CHECK_PROGS([DOXYGEN], [doxygen], [false])
+AM_CONDITIONAL([HAVE_DOXYGEN], [test "x$DOXYGEN" != xfalse])
+AM_COND_IF([HAVE_DOXYGEN],,
+ AC_MSG_WARN([Doxygen not found - continuing without Doxygen support])
+)
+
+
+AC_CONFIG_FILES([ \
+ Makefile \
+ conf/Makefile \
+ doc/doxygen.cfg \
+ doc/Makefile \
+ include/Makefile \
+ lib/Makefile \
+ lib/socket/Makefile \
+ lib/icap/Makefile \
+ src/Makefile \
+ modules/Makefile \
+ modules/echo/Makefile \
+ modules/modpy/Makefile \
+ modules/modpy/modules/Makefile \
+])
+
+AC_OUTPUT
+
diff --git a/debian/README.debian b/debian/README.debian
new file mode 100644
index 0000000..4e48c83
--- /dev/null
+++ b/debian/README.debian
@@ -0,0 +1,12 @@
+bitz-server systemd notes
+-------------------------
+
+- bitz-server are not enabled on install.
+
+ To enable bitz-server in the default configuration
+ use systemctl to enable the service:
+ # systemctl enable bitz-server.service
+ To disable bitz-server, use systemctl to disable the service:
+ # systemctl disable bitz-server.service
+
+ -- Jörg Frings-Fürst <debian@jff-webhosting.net> Sat, 03 Jan 2015 15:31:04 +0100
diff --git a/debian/README.lintian b/debian/README.lintian
new file mode 100644
index 0000000..dd50e3b
--- /dev/null
+++ b/debian/README.lintian
@@ -0,0 +1,7 @@
+bitz-server lintian notes
+-------------------------
+
+- pedantic "duplicate-files" in directory usr/share/doc/bitz-server-doc/docs
+ are based on doxygen build. I don't overrides them.
+
+ -- Jörg Frings-Fürst <debian@jff-webhosting.net> Tue, 11 Nov 2014 08:50:49 +0100
diff --git a/debian/bitz-server-doc.dirs b/debian/bitz-server-doc.dirs
new file mode 100644
index 0000000..71bc8a1
--- /dev/null
+++ b/debian/bitz-server-doc.dirs
@@ -0,0 +1 @@
+/usr/share/doc/bitz-server-doc/docs/
diff --git a/debian/bitz-server-doc.doc-base b/debian/bitz-server-doc.doc-base
new file mode 100644
index 0000000..8d078b5
--- /dev/null
+++ b/debian/bitz-server-doc.doc-base
@@ -0,0 +1,7 @@
+Document: bitz-server
+Title: bitz-server Documentation
+Section: Network/Communication
+
+Format: HTML
+Index: /usr/share/doc/bitz-server-doc/docs/index.html
+Files: /usr/share/doc/bitz-server-doc/docs/*.html
diff --git a/debian/bitz-server-doc.docs b/debian/bitz-server-doc.docs
new file mode 100644
index 0000000..42061c0
--- /dev/null
+++ b/debian/bitz-server-doc.docs
@@ -0,0 +1 @@
+README.md \ No newline at end of file
diff --git a/debian/bitz-server-doc.lintian-overrides b/debian/bitz-server-doc.lintian-overrides
new file mode 100644
index 0000000..6e13e8a
--- /dev/null
+++ b/debian/bitz-server-doc.lintian-overrides
@@ -0,0 +1,7 @@
+# The lintian warning "bitz-server-doc: embedded-javascript-library
+# usr/share/doc/bitz-server-doc/docs/jquery.js please use libjs-jquery"
+# was overridden.
+# The file jquery.js comes from the with doxygen-generated documentation.
+# The built-in jquery.js in doxygen is not going to be removed (see Debian bug #736432).
+#
+bitz-server-doc binary: embedded-javascript-library
diff --git a/debian/bitz-server.docs b/debian/bitz-server.docs
new file mode 100644
index 0000000..aeb0ee7
--- /dev/null
+++ b/debian/bitz-server.docs
@@ -0,0 +1,2 @@
+README.md
+debian/doc/*.txt
diff --git a/debian/bitz-server.init b/debian/bitz-server.init
new file mode 100644
index 0000000..ade8b71
--- /dev/null
+++ b/debian/bitz-server.init
@@ -0,0 +1,132 @@
+#!/bin/sh
+
+### BEGIN INIT INFO
+# Provides: bitz-server
+# Required-Start: $remote_fs $syslog
+# Required-Stop: $local_fs $remote_fs
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Bitz ICAP server
+# Description: ICAP server (RFC 3507)
+### END INIT INFO
+#
+# Written 2014 by Jörg Frings-Fürst <debian@jff-webhosting.net>.
+# Licensed under GPL-3+.
+#
+###
+
+DESC="bitz ICAP server"
+NAME="bitz-server"
+
+DAEMON="/usr/sbin/$NAME"
+PIDFILE=/var/run/$NAME.pid
+
+PATH=/sbin:/usr/sbin:/bin:/usr/bin
+SCRIPT=/etc/init.d/$NAME
+
+BITZ-SERVER_OPTS="--config=/etc/bitz/bitz-server.conf"
+
+# Are we making sense?
+[ -x "$DAEMON" ] || exit 0
+
+# Read configuration variable file if it is present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# Define all LSB log_* functions.
+. /lib/lsb/init-functions
+
+# Start downtimed.
+do_start()
+{
+ start-stop-daemon --start --quiet --pidfile $PIDFILE \
+ --exec $DAEMON --test > /dev/null \
+ || return 1
+ start-stop-daemon --start --quiet --pidfile $PIDFILE \
+ --exec $DAEMON -- $DOWNTIMED_OPTS \
+ || return 2
+
+ # Return status:
+ # 0 daemon has been started
+ # 1 daemon was already running
+ # 2 daemon could not be started
+}
+
+# Halt downtimed.
+do_stop()
+{
+ start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 \
+ --pidfile $PIDFILE --exec $DAEMON
+ RETVAL="$?"
+ [ "$RETVAL" = 2 ] && return 2
+
+ rm -f $PIDFILE
+ return "$RETVAL"
+
+ # Return status:
+ # 0 daemon has been stopped
+ # 1 daemon was already stopped
+ # 2 daemon could not be stopped
+ # other daemon reported some other failure
+}
+
+# Reloading is a no-do in the standard case, when logging is
+# done via the syslog service. Only if $DOWNTIMED_OPTS states
+# a separate logging file, then a SIGHUP will result in the
+# daemon releasing the file for rotation, or a similar action.
+
+do_reload() {
+ start-stop-daemon --stop --signal 1 --quiet \
+ --pidfile $PIDFILE --exec $DAEMON
+ return 0
+}
+
+case "$1" in
+ start)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
+ do_start
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ stop)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ status)
+ status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
+ ;;
+ reload|force-reload)
+ log_daemon_msg "Reloading $DESC" "$NAME"
+ do_reload
+ log_end_msg $?
+ ;;
+ restart)
+ log_daemon_msg "Restarting $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1)
+ do_start
+ case "$?" in
+ 0) log_end_msg 0 ;;
+ 1) log_end_msg 1 ;; # Still running.
+ *) log_end_msg 1 ;; # Failure in starting.
+ esac
+ ;;
+ *)
+ # Failure in ending service.
+ log_end_msg 1
+ ;;
+ esac
+ ;;
+ *)
+ echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload|status}" >&2
+ exit 3
+ ;;
+esac
+
+:
diff --git a/debian/bitz-server.install b/debian/bitz-server.install
new file mode 100644
index 0000000..738bdb8
--- /dev/null
+++ b/debian/bitz-server.install
@@ -0,0 +1,2 @@
+etc/bitz/*
+usr/sbin/*
diff --git a/debian/bitz-server.manpages b/debian/bitz-server.manpages
new file mode 100644
index 0000000..1b5587e
--- /dev/null
+++ b/debian/bitz-server.manpages
@@ -0,0 +1,2 @@
+debian/tmp/usr/share/man/man1/*.1
+debian/tmp/usr/share/man/man5/*.5
diff --git a/debian/bitz-server.postrm b/debian/bitz-server.postrm
new file mode 100644
index 0000000..f172740
--- /dev/null
+++ b/debian/bitz-server.postrm
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+set -e
+
+if [ "$1" = purge ]; then
+#
+# purge systemd files
+# see ../../doc/why.txt
+#
+ rm -f /etc/systemd/system/bitz-server.service
+ rm -f /var/lib/systemd/deb-systemd-helper-enabled/bitz-server.service.dsh-also
+ rm -f /var/lib/systemd/deb-systemd-helper-masked/bitz-server.service
+ if [ -d /var/lib/systemd/deb-systemd-helper-enabled ]; then
+ rmdir --ignore-fail-on-non-empty /var/lib/systemd/deb-systemd-helper-enabled
+ fi
+ if [ -d /var/lib/systemd/deb-systemd-helper-masked ]; then
+ rmdir --ignore-fail-on-non-empty /var/lib/systemd/deb-systemd-helper-masked
+ fi
+ rm -f /etc/init/bitz-server.override
+fi
+
+#DEBHELPER#
diff --git a/debian/bitz-server.service b/debian/bitz-server.service
new file mode 100644
index 0000000..c81ddbd
--- /dev/null
+++ b/debian/bitz-server.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=bitz ICAP server
+After=network.target
+
+[Service]
+Type=simple
+ExecStart=/usr/sbin/bitz-server /etc/bitz/bitz-server.conf
+ExecReload=/bin/kill -HUP $MAINPID
+
+[Install]
+WantedBy=multi-user.target
diff --git a/debian/bitz-server.upstart b/debian/bitz-server.upstart
new file mode 100644
index 0000000..f0a3360
--- /dev/null
+++ b/debian/bitz-server.upstart
@@ -0,0 +1,7 @@
+description "bitz ICAP server"
+author "Cameron Norman <camerontnorman@gmail.com>"
+
+start on runlevel [2345]
+stop on runlevel [016]
+
+exec /usr/sbin/bitz-server /etc/bitz/bitz-server.conf
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..c7c70cb
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,5 @@
+bitz-server (0.1.6-1) unstable; urgency=low
+
+ * Initial release (Closes: #715022)
+
+ -- Jörg Frings-Fürst <debian@jff-webhosting.net> Sun, 08 Nov 2015 09:20:29 +0100
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..4aad9fd
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,162 @@
+Source: bitz-server
+Section: net
+Priority: optional
+Maintainer: Jörg Frings-Fürst <debian@jff-webhosting.net>
+Uploaders: Uditha Atukorala <ua@nuked.zone>
+Build-Depends:
+ debhelper (>= 9),
+ dh-autoreconf,
+ dh-python,
+ dh-systemd (>= 1.5),
+ libconfig++-dev,
+ liblog4cpp5-dev,
+ libpsocksxx-dev,
+ python-dev,
+ libpython-dev
+Build-Depends-Indep:
+ doxygen
+Standards-Version: 3.9.6
+Homepage: https://github.com/uditha-atukorala/bitz-server
+Vcs-Git: git://anonscm.debian.org/collab-maint/bitz-server.git
+Vcs-Browser: http://anonscm.debian.org/cgit/collab-maint/bitzserver.git
+
+Package: bitz-server
+Architecture: any
+Depends:
+ ${shlibs:Depends},
+ ${misc:Depends},
+ libicap0 (= ${binary:Version})
+Description: ICAP server (RFC 3507) implementation in C++
+ The main goal of this project is to create an ICAP server (RFC 3507)
+ implementation in C++ to use the power of object oriented programming.
+ .
+ Starting from scratch, the server is developed with a modular architecture
+ in mind. The server core (written in C++) will handle the client requests,
+ manage workers (child processes) etc. and will provide basic handlers to serve
+ ICAP requests.
+ .
+ To extend this core functionality the idea is to have pluggable modules
+ (like Apache server modules). These modules will provide features like
+ content filtering, anti-virus scanning etc. and to make it easier to write
+ (and faster to implement) such modules there is hope to exploit Python
+ programming language.
+
+Package: bitz-server-doc
+Architecture: all
+Section: doc
+Depends: ${misc:Depends}
+Description: ICAP server (RFC 3507) implementation in C++ (Documentation)
+ The main goal of this project is to create an ICAP server (RFC 3507)
+ implementation in C++ to use the power of object oriented programming.
+ .
+ Starting from scratch, the server is developed with a modular architecture
+ in mind. The server core (written in C++) will handle the client requests,
+ manage workers (child processes) etc. and will provide basic handlers to serve
+ ICAP requests.
+ .
+ To extend this core functionality the idea is to have pluggable modules
+ (like Apache server modules). These modules will provide features like
+ content filtering, anti-virus scanning etc. and to make it easier to write
+ (and faster to implement) such modules there is hope to exploit Python
+ programming language.
+ .
+ This package holds the documentation.
+
+Package: libicap-dev
+Section: libdevel
+Architecture: any
+Multi-Arch: same
+Depends:
+ libicap0 (= ${binary:Version}),
+ ${misc:Depends}
+Suggests: bitz-server-doc
+Description: ICAP server (RFC 3507) implementation in C++ (development files)
+ The main goal of this project is to create an ICAP server (RFC 3507)
+ implementation in C++ to use the power of object oriented programming.
+ .
+ Starting from scratch, the server is developed with a modular architecture
+ in mind. The server core (written in C++) will handle the client requests,
+ manage workers (child processes) etc. and will provide basic handlers to serve
+ ICAP requests.
+ .
+ To extend this core functionality the idea is to have pluggable modules
+ (like Apache server modules). These modules will provide features like
+ content filtering, anti-virus scanning etc. and to make it easier to write
+ (and faster to implement) such modules there is hope to exploit Python
+ programming language.
+ .
+ This package holds the development files.
+
+Package: libicap0
+Architecture: any
+Multi-Arch: same
+Depends:
+ ${shlibs:Depends},
+ ${misc:Depends}
+Pre-Depends:
+ ${misc:Pre-Depends}
+Description: ICAP server (RFC 3507) implementation in C++ (library files)
+ The main goal of this project is to create an ICAP server (RFC 3507)
+ implementation in C++ to use the power of object oriented programming.
+ .
+ Starting from scratch, the server is developed with a modular architecture
+ in mind. The server core (written in C++) will handle the client requests,
+ manage workers (child processes) etc. and will provide basic handlers to serve
+ ICAP requests.
+ .
+ To extend this core functionality the idea is to have pluggable modules
+ (like Apache server modules). These modules will provide features like
+ content filtering, anti-virus scanning etc. and to make it easier to write
+ (and faster to implement) such modules there is hope to exploit Python
+ programming language.
+ .
+ This package holds the library files.
+
+Package: bitz-server-dbg
+Architecture: any
+Section: debug
+Priority: extra
+Depends:
+ ${misc:Depends},
+ bitz-server (= ${binary:Version})
+Description: ICAP server (RFC 3507) implementation in C++ (server debug symbols)
+ The main goal of this project is to create an ICAP server (RFC 3507)
+ implementation in C++ to use the power of object oriented programming.
+ .
+ Starting from scratch, the server is developed with a modular architecture
+ in mind. The server core (written in C++) will handle the client requests,
+ manage workers (child processes) etc. and will provide basic handlers to serve
+ ICAP requests.
+ .
+ To extend this core functionality the idea is to have pluggable modules
+ (like Apache server modules). These modules will provide features like
+ content filtering, anti-virus scanning etc. and to make it easier to write
+ (and faster to implement) such modules there is hope to exploit Python
+ programming language.
+ .
+ This package holds the debug symbols for bitz-server.
+
+Package: libicap0-dbg
+Architecture: any
+Multi-Arch: same
+Section: debug
+Priority: extra
+Depends:
+ ${misc:Depends},
+ libicap0 (= ${binary:Version})
+Description: ICAP server (RFC 3507) implementation in C++ (library debug symbols)
+ The main goal of this project is to create an ICAP server (RFC 3507)
+ implementation in C++ to use the power of object oriented programming.
+ .
+ Starting from scratch, the server is developed with a modular architecture
+ in mind. The server core (written in C++) will handle the client requests,
+ manage workers (child processes) etc. and will provide basic handlers to serve
+ ICAP requests.
+ .
+ To extend this core functionality the idea is to have pluggable modules
+ (like Apache server modules). These modules will provide features like
+ content filtering, anti-virus scanning etc. and to make it easier to write
+ (and faster to implement) such modules there is hope to exploit Python
+ programming language.
+ .
+ This package holds the debug symbols for libicap0.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..7cf797c
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,33 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: bitz-server
+Source: https://github.com/uditha-atukorala/bitz-server
+
+Files: *
+Copyright: 2012-2014 Uditha Atukorala <ua@nuked.zone>
+License: GPL-3+
+
+Files: lib/socket/socket.*
+Copyright: 2002 <unknown>
+ 2010 Uditha Atukorala <ua@nuked.zone>
+License: GPL-3+
+
+Files: debian/*
+Copyright: 2014-2015 Jörg Frings-Fürst <debian@jff-webhosting.net>
+License: GPL-3+
+
+License: GPL-3+
+ This package 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 3 of the License, or
+ (at your option) any later version.
+ .
+ This package 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, see <http://www.gnu.org/licenses/>
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
diff --git a/debian/doc/why_delete_systemd_file_via_postrm.txt b/debian/doc/why_delete_systemd_file_via_postrm.txt
new file mode 100644
index 0000000..d76dddb
--- /dev/null
+++ b/debian/doc/why_delete_systemd_file_via_postrm.txt
@@ -0,0 +1,807 @@
+#
+# 2015-05-14
+#
+# why remove systemd over postrm
+#
+
+##########
+$ apt-cache policy piuparts
+piuparts:
+ Installiert: 0.63
+ Installationskandidat: 0.63
+ Versionstabelle:
+ *** 0.63 0
+ 900 http://mirror.1und1.de/debian/ stretch/main amd64 Packages
+ 800 http://mirror.1und1.de/debian/ sid/main amd64 Packages
+ 100 /var/lib/dpkg/status
+
+##########
+$ apt-cache policy systemd
+systemd:
+ Installiert: 215-17
+ Installationskandidat: 215-17
+ Versionstabelle:
+ 219-9 0
+ 1 http://mirror.1und1.de/debian/ experimental/main amd64 Packages
+ *** 215-17 0
+ 900 http://mirror.1und1.de/debian/ stretch/main amd64 Packages
+ 800 http://mirror.1und1.de/debian/ sid/main amd64 Packages
+ 100 /var/lib/dpkg/status
+
+##########
+log piuparts:
+
+0m0.0s INFO: ------------------------------------------------------------------------------
+0m0.0s INFO: To quickly glance what went wrong, scroll down to the bottom of this logfile.
+0m0.0s INFO: FAQ available at https://wiki.debian.org/piuparts/FAQ
+0m0.0s INFO: The FAQ also explains how to contact us in case you think piuparts is wrong.
+0m0.0s INFO: ------------------------------------------------------------------------------
+0m0.0s INFO: piuparts version 0.63 starting up.
+0m0.0s INFO: Command line arguments: /usr/sbin/piuparts --basetgz=../../sid-amd64-base.tgz bitz-server_0.1.6-1_amd64.changes
+0m0.0s INFO: Running on: Linux merkur 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt9-3 (2015-04-23) x86_64
+0m0.0s DEBUG: Starting command: ['dpkg', '--info', 'bitz-server_0.1.6-1_amd64.deb']
+0m0.0s DUMP:
+ new debian package, version 2.0.
+ size 51096 bytes: control archive=2115 bytes.
+ 78 bytes, 3 lines conffiles
+ 1144 bytes, 23 lines control
+ 643 bytes, 9 lines md5sums
+ 867 bytes, 23 lines * postinst #!/bin/sh
+ 1373 bytes, 47 lines * postrm #!/bin/sh
+ 177 bytes, 7 lines * prerm #!/bin/sh
+ Package: bitz-server
+ Version: 0.1.6-1
+ Architecture: amd64
+ Maintainer: Jörg Frings-Fürst <debian@jff-webhosting.net>
+ Installed-Size: 137
+ Depends: libc6 (>= 2.15), libconfig++9, libgcc1 (>= 1:4.1.1), libicap0 (= 0.1.6-1), liblog4cpp5, libstdc++6 (>= 4.9), init-system-helpers (>= 1.18~)
+ Section: net
+ Priority: extra
+ Homepage: https://github.com/uditha-atukorala/bitz-server
+ Description: ICAP server (RFC 3507) implementation in C++
+ The main goal of this project is to create an ICAP server (RFC 3507)
+ implementation in C++ to use the power of object oriented programming.
+ .
+ Starting from scratch, the server is developed with a modular architecture
+ in mind. The server core (written in C++) will handle the client requests,
+ manage workers (child processes) etc. and will provide basic handlers to serve
+ ICAP requests.
+ .
+ To extend this core functionality the idea is to have pluggable modules
+ (like Apache server modules). These modules will provide features like
+ content filtering, anti-virus scanning etc. and to make it easier to write
+ (and faster to implement) such modules there is hope to exploit Python
+ programming language.
+0m0.0s DEBUG: Command ok: ['dpkg', '--info', 'bitz-server_0.1.6-1_amd64.deb']
+0m0.0s DEBUG: Starting command: ['dpkg', '--info', 'bitz-server-doc_0.1.6-1_all.deb']
+0m0.0s DUMP:
+ new debian package, version 2.0.
+ size 150870 bytes: control archive=9598 bytes.
+ 1076 bytes, 25 lines control
+ 28315 bytes, 292 lines md5sums
+ Package: bitz-server-doc
+ Source: bitz-server
+ Version: 0.1.6-1
+ Architecture: all
+ Maintainer: Jörg Frings-Fürst <debian@jff-webhosting.net>
+ Installed-Size: 1657
+ Section: doc
+ Priority: extra
+ Homepage: https://github.com/uditha-atukorala/bitz-server
+ Description: ICAP server (RFC 3507) implementation in C++ (Documentation)
+ The main goal of this project is to create an ICAP server (RFC 3507)
+ implementation in C++ to use the power of object oriented programming.
+ .
+ Starting from scratch, the server is developed with a modular architecture
+ in mind. The server core (written in C++) will handle the client requests,
+ manage workers (child processes) etc. and will provide basic handlers to serve
+ ICAP requests.
+ .
+ To extend this core functionality the idea is to have pluggable modules
+ (like Apache server modules). These modules will provide features like
+ content filtering, anti-virus scanning etc. and to make it easier to write
+ (and faster to implement) such modules there is hope to exploit Python
+ programming language.
+ .
+ This package holds the documentation.
+0m0.0s DEBUG: Command ok: ['dpkg', '--info', 'bitz-server-doc_0.1.6-1_all.deb']
+0m0.0s DEBUG: Starting command: ['dpkg', '--info', 'libicap-dev_0.1.6-1_amd64.deb']
+0m0.0s DUMP:
+ new debian package, version 2.0.
+ size 10410 bytes: control archive=1342 bytes.
+ 1158 bytes, 28 lines control
+ 937 bytes, 14 lines md5sums
+ Package: libicap-dev
+ Source: bitz-server
+ Version: 0.1.6-1
+ Architecture: amd64
+ Maintainer: Jörg Frings-Fürst <debian@jff-webhosting.net>
+ Installed-Size: 33
+ Depends: libicap0 (= 0.1.6-1)
+ Suggests: bitz-server-doc
+ Section: libdevel
+ Priority: extra
+ Multi-Arch: same
+ Homepage: https://github.com/uditha-atukorala/bitz-server
+ Description: ICAP server (RFC 3507) implementation in C++ (development files)
+ The main goal of this project is to create an ICAP server (RFC 3507)
+ implementation in C++ to use the power of object oriented programming.
+ .
+ Starting from scratch, the server is developed with a modular architecture
+ in mind. The server core (written in C++) will handle the client requests,
+ manage workers (child processes) etc. and will provide basic handlers to serve
+ ICAP requests.
+ .
+ To extend this core functionality the idea is to have pluggable modules
+ (like Apache server modules). These modules will provide features like
+ content filtering, anti-virus scanning etc. and to make it easier to write
+ (and faster to implement) such modules there is hope to exploit Python
+ programming language.
+ .
+ This package holds the development files.
+0m0.0s DEBUG: Command ok: ['dpkg', '--info', 'libicap-dev_0.1.6-1_amd64.deb']
+0m0.0s DEBUG: Starting command: ['dpkg', '--info', 'libicap0_0.1.6-1_amd64.deb']
+0m0.1s DUMP:
+ new debian package, version 2.0.
+ size 46194 bytes: control archive=3642 bytes.
+ 1155 bytes, 27 lines control
+ 360 bytes, 5 lines md5sums
+ 135 bytes, 7 lines * postinst #!/bin/sh
+ 132 bytes, 7 lines * postrm #!/bin/sh
+ 19 bytes, 1 lines shlibs
+ 12433 bytes, 203 lines symbols
+ Package: libicap0
+ Source: bitz-server
+ Version: 0.1.6-1
+ Architecture: amd64
+ Maintainer: Jörg Frings-Fürst <debian@jff-webhosting.net>
+ Installed-Size: 138
+ Depends: libc6 (>= 2.15), libgcc1 (>= 1:4.1.1), libstdc++6 (>= 4.9)
+ Section: net
+ Priority: extra
+ Multi-Arch: same
+ Homepage: https://github.com/uditha-atukorala/bitz-server
+ Description: ICAP server (RFC 3507) implementation in C++ (library files)
+ The main goal of this project is to create an ICAP server (RFC 3507)
+ implementation in C++ to use the power of object oriented programming.
+ .
+ Starting from scratch, the server is developed with a modular architecture
+ in mind. The server core (written in C++) will handle the client requests,
+ manage workers (child processes) etc. and will provide basic handlers to serve
+ ICAP requests.
+ .
+ To extend this core functionality the idea is to have pluggable modules
+ (like Apache server modules). These modules will provide features like
+ content filtering, anti-virus scanning etc. and to make it easier to write
+ (and faster to implement) such modules there is hope to exploit Python
+ programming language.
+ .
+ This package holds the library files.
+0m0.1s DEBUG: Command ok: ['dpkg', '--info', 'libicap0_0.1.6-1_amd64.deb']
+0m0.1s DEBUG: Starting command: ['dpkg', '--info', 'bitz-server-dbg_0.1.6-1_amd64.deb']
+0m0.1s DUMP:
+ new debian package, version 2.0.
+ size 299412 bytes: control archive=1047 bytes.
+ 1135 bytes, 26 lines control
+ 341 bytes, 4 lines md5sums
+ Package: bitz-server-dbg
+ Source: bitz-server
+ Version: 0.1.6-1
+ Architecture: amd64
+ Maintainer: Jörg Frings-Fürst <debian@jff-webhosting.net>
+ Installed-Size: 319
+ Depends: bitz-server (= 0.1.6-1)
+ Section: debug
+ Priority: extra
+ Homepage: https://github.com/uditha-atukorala/bitz-server
+ Description: ICAP server (RFC 3507) implementation in C++ (server debug symbols)
+ The main goal of this project is to create an ICAP server (RFC 3507)
+ implementation in C++ to use the power of object oriented programming.
+ .
+ Starting from scratch, the server is developed with a modular architecture
+ in mind. The server core (written in C++) will handle the client requests,
+ manage workers (child processes) etc. and will provide basic handlers to serve
+ ICAP requests.
+ .
+ To extend this core functionality the idea is to have pluggable modules
+ (like Apache server modules). These modules will provide features like
+ content filtering, anti-virus scanning etc. and to make it easier to write
+ (and faster to implement) such modules there is hope to exploit Python
+ programming language.
+ .
+ This package holds the debug symbols for bitz-server.
+0m0.1s DEBUG: Command ok: ['dpkg', '--info', 'bitz-server-dbg_0.1.6-1_amd64.deb']
+0m0.1s DEBUG: Starting command: ['dpkg', '--info', 'libicap0-dbg_0.1.6-1_amd64.deb']
+0m0.1s DUMP:
+ new debian package, version 2.0.
+ size 334462 bytes: control archive=1066 bytes.
+ 1144 bytes, 27 lines control
+ 332 bytes, 4 lines md5sums
+ Package: libicap0-dbg
+ Source: bitz-server
+ Version: 0.1.6-1
+ Architecture: amd64
+ Maintainer: Jörg Frings-Fürst <debian@jff-webhosting.net>
+ Installed-Size: 349
+ Depends: libicap0 (= 0.1.6-1)
+ Section: debug
+ Priority: extra
+ Multi-Arch: same
+ Homepage: https://github.com/uditha-atukorala/bitz-server
+ Description: ICAP server (RFC 3507) implementation in C++ (library debug symbols)
+ The main goal of this project is to create an ICAP server (RFC 3507)
+ implementation in C++ to use the power of object oriented programming.
+ .
+ Starting from scratch, the server is developed with a modular architecture
+ in mind. The server core (written in C++) will handle the client requests,
+ manage workers (child processes) etc. and will provide basic handlers to serve
+ ICAP requests.
+ .
+ To extend this core functionality the idea is to have pluggable modules
+ (like Apache server modules). These modules will provide features like
+ content filtering, anti-virus scanning etc. and to make it easier to write
+ (and faster to implement) such modules there is hope to exploit Python
+ programming language.
+ .
+ This package holds the debug symbols for libicap0.
+0m0.1s DEBUG: Command ok: ['dpkg', '--info', 'libicap0-dbg_0.1.6-1_amd64.deb']
+0m0.1s DEBUG: Created temporary directory /tmp/tmpDXAZc1
+0m0.1s DEBUG: Unpacking ../../sid-amd64-base.tgz into /tmp/tmpDXAZc1
+0m0.1s DEBUG: Starting command: ['tar', '-C', '/tmp/tmpDXAZc1', '-zxf', '../../sid-amd64-base.tgz']
+0m3.4s DEBUG: Command ok: ['tar', '-C', '/tmp/tmpDXAZc1', '-zxf', '../../sid-amd64-base.tgz']
+0m3.4s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'mount', '-t', 'proc', 'proc', '/proc']
+0m3.4s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'mount', '-t', 'proc', 'proc', '/proc']
+0m3.4s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'mount', '-t', 'devpts', 'devpts', '/dev/pts']
+0m3.4s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'mount', '-t', 'devpts', 'devpts', '/dev/pts']
+0m3.4s DEBUG: sources.list:
+ deb http://mirror.1und1.de/debian/ sid main
+ deb http://mirror.1und1.de/debian/ sid non-free
+ deb http://mirror.1und1.de/debian/ sid contrib
+0m3.4s DEBUG: Created policy-rc.d and chmodded it.
+0m3.4s DEBUG: Created resolv.conf.
+0m3.4s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'apt-get', 'update']
+0m25.2s DUMP:
+ Get:1 http://mirror.1und1.de sid InRelease [204 kB]
+ Get:2 http://mirror.1und1.de sid/main amd64 Packages [7197 kB]
+ Get:3 http://mirror.1und1.de sid/non-free amd64 Packages [89.2 kB]
+ Get:4 http://mirror.1und1.de sid/contrib amd64 Packages [54.6 kB]
+ Get:5 http://mirror.1und1.de sid/contrib Translation-en [42.8 kB]
+ Get:6 http://mirror.1und1.de sid/main Translation-en [4883 kB]
+ Get:7 http://mirror.1und1.de sid/non-free Translation-en [77.2 kB]
+ Fetched 12.5 MB in 19s (645 kB/s)
+ Reading package lists...
+0m25.2s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'apt-get', 'update']
+0m25.2s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'apt-get', '-yf', 'dist-upgrade']
+0m25.5s DUMP:
+ Reading package lists...
+ Building dependency tree...
+ Reading state information...
+ 0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
+0m25.5s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'apt-get', '-yf', 'dist-upgrade']
+0m25.5s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'apt-get', 'clean']
+0m25.5s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'apt-get', 'clean']
+0m27.5s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'dpkg', '--get-selections', '*']
+0m27.5s DUMP:
+ acl install
+ adduser install
+ apt install
+ aptitude install
+ aptitude-common install
+ base-files install
+ base-passwd install
+ bash install
+ binutils install
+ bsdutils install
+ build-essential install
+ bzip2 install
+ coreutils install
+ cpp install
+ cpp-4.9 install
+ dash install
+ debconf install
+ debconf-i18n install
+ debian-archive-keyring install
+ debianutils install
+ diffutils install
+ dmsetup install
+ dpkg install
+ dpkg-dev install
+ e2fslibs:amd64 install
+ e2fsprogs install
+ findutils install
+ g++ install
+ g++-4.9 install
+ gcc install
+ gcc-4.7-base:amd64 install
+ gcc-4.8-base:amd64 install
+ gcc-4.9 install
+ gcc-4.9-base:amd64 install
+ gcc-5-base:amd64 install
+ gnupg install
+ gpgv install
+ grep install
+ gzip install
+ hostname install
+ init install
+ initscripts install
+ insserv install
+ libacl1:amd64 install
+ libapt-pkg4.12:amd64 install
+ libasan1:amd64 install
+ libatomic1:amd64 install
+ libattr1:amd64 install
+ libaudit-common install
+ libaudit1:amd64 install
+ libblkid1:amd64 install
+ libboost-iostreams1.55.0:amd64 install
+ libbz2-1.0:amd64 install
+ libc-bin install
+ libc-dev-bin install
+ libc6:amd64 install
+ libc6-dev:amd64 install
+ libcap2:amd64 install
+ libcap2-bin install
+ libcilkrts5:amd64 install
+ libcloog-isl4:amd64 install
+ libcomerr2:amd64 install
+ libcryptsetup4:amd64 install
+ libcwidget3:amd64 install
+ libdb5.3:amd64 install
+ libdebconfclient0:amd64 install
+ libdevmapper1.02.1:amd64 install
+ libdpkg-perl install
+ libfdisk1:amd64 install
+ libffi6:amd64 install
+ libgcc-4.9-dev:amd64 install
+ libgcc1:amd64 install
+ libgcrypt20:amd64 install
+ libgdbm3:amd64 install
+ libglib2.0-0:amd64 install
+ libgmp10:amd64 install
+ libgomp1:amd64 install
+ libgpg-error0:amd64 install
+ libgpm2:amd64 install
+ libisl10:amd64 install
+ libisl13:amd64 install
+ libitm1:amd64 install
+ libkmod2:amd64 install
+ liblocale-gettext-perl install
+ liblsan0:amd64 install
+ liblzma5:amd64 install
+ libmount1:amd64 install
+ libmpc3:amd64 install
+ libmpfr4:amd64 install
+ libncurses5:amd64 install
+ libncursesw5:amd64 install
+ libpam-modules:amd64 install
+ libpam-modules-bin install
+ libpam-runtime install
+ libpam0g:amd64 install
+ libpcre3:amd64 install
+ libprocps3:amd64 install
+ libquadmath0:amd64 install
+ libreadline6:amd64 install
+ libselinux1:amd64 install
+ libsemanage-common install
+ libsemanage1:amd64 install
+ libsepol1:amd64 install
+ libsigc++-2.0-0c2a:amd64 install
+ libslang2:amd64 install
+ libsmartcols1:amd64 install
+ libsqlite3-0:amd64 install
+ libss2:amd64 install
+ libssh2-1:amd64 install
+ libstdc++-4.9-dev:amd64 install
+ libstdc++6:amd64 install
+ libsystemd0:amd64 install
+ libtext-charwidth-perl install
+ libtext-iconv-perl install
+ libtext-wrapi18n-perl install
+ libtimedate-perl install
+ libtinfo5:amd64 install
+ libtsan0:amd64 install
+ libubsan0:amd64 install
+ libudev1:amd64 install
+ libusb-0.1-4:amd64 install
+ libustr-1.0-1:amd64 install
+ libuuid1:amd64 install
+ libxapian22 install
+ linux-libc-dev:amd64 install
+ login install
+ lsb-base install
+ make install
+ mawk install
+ mc install
+ mc-data install
+ mount install
+ multiarch-support install
+ ncurses-base install
+ ncurses-bin install
+ passwd install
+ patch install
+ perl install
+ perl-base install
+ perl-modules install
+ procps install
+ readline-common install
+ sed install
+ sensible-utils install
+ startpar install
+ systemd install
+ systemd-sysv install
+ sysv-rc install
+ sysvinit-utils install
+ tar install
+ tzdata install
+ udev install
+ util-linux install
+ xz-utils install
+ zlib1g:amd64 install
+0m27.5s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'dpkg', '--get-selections', '*']
+0m27.5s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'dpkg-divert', '--list']
+0m27.6s DUMP:
+ diversion of /usr/share/man/man1/sh.1.gz to /usr/share/man/man1/sh.distrib.1.gz by dash
+ diversion of /bin/sh to /bin/sh.distrib by dash
+0m27.6s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'dpkg-divert', '--list']
+0m27.6s INFO: apt-cache does not know about any of the requested packages
+0m27.6s DEBUG: Starting command: ['lsof', '-w', '+D', '/tmp/tmpDXAZc1']
+0m28.2s DEBUG: Command failed (status=1), but ignoring error: ['lsof', '-w', '+D', '/tmp/tmpDXAZc1']
+0m29.7s DEBUG: No broken symlinks as far as we can find.
+0m29.7s DEBUG: Starting command: ['lsof', '-w', '+D', '/tmp/tmpDXAZc1']
+0m30.4s DEBUG: Command failed (status=1), but ignoring error: ['lsof', '-w', '+D', '/tmp/tmpDXAZc1']
+0m31.9s DEBUG: No broken symlinks as far as we can find.
+0m31.9s DEBUG: Copying bitz-server_0.1.6-1_amd64.deb, bitz-server-doc_0.1.6-1_all.deb, libicap-dev_0.1.6-1_amd64.deb, libicap0_0.1.6-1_amd64.deb, bitz-server-dbg_0.1.6-1_amd64.deb, libicap0-dbg_0.1.6-1_amd64.deb to /tmp/tmpDXAZc1/tmp
+0m31.9s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'dpkg', '-i', 'tmp/bitz-server_0.1.6-1_amd64.deb', 'tmp/bitz-server-doc_0.1.6-1_all.deb', 'tmp/libicap-dev_0.1.6-1_amd64.deb', 'tmp/libicap0_0.1.6-1_amd64.deb', 'tmp/bitz-server-dbg_0.1.6-1_amd64.deb', 'tmp/libicap0-dbg_0.1.6-1_amd64.deb']
+0m39.5s DUMP:
+ Selecting previously unselected package bitz-server.
+ (Reading database ... 12464 files and directories currently installed.)
+ Preparing to unpack .../bitz-server_0.1.6-1_amd64.deb ...
+ Unpacking bitz-server (0.1.6-1) ...
+ Selecting previously unselected package bitz-server-doc.
+ Preparing to unpack .../bitz-server-doc_0.1.6-1_all.deb ...
+ Unpacking bitz-server-doc (0.1.6-1) ...
+ Selecting previously unselected package libicap-dev:amd64.
+ Preparing to unpack .../libicap-dev_0.1.6-1_amd64.deb ...
+ Unpacking libicap-dev:amd64 (0.1.6-1) ...
+ Selecting previously unselected package libicap0:amd64.
+ Preparing to unpack tmp/libicap0_0.1.6-1_amd64.deb ...
+ Unpacking libicap0:amd64 (0.1.6-1) ...
+ Selecting previously unselected package bitz-server-dbg.
+ Preparing to unpack .../bitz-server-dbg_0.1.6-1_amd64.deb ...
+ Unpacking bitz-server-dbg (0.1.6-1) ...
+ Selecting previously unselected package libicap0-dbg:amd64.
+ Preparing to unpack .../libicap0-dbg_0.1.6-1_amd64.deb ...
+ Unpacking libicap0-dbg:amd64 (0.1.6-1) ...
+ dpkg: dependency problems prevent configuration of bitz-server:
+ bitz-server depends on libconfig++9; however:
+ Package libconfig++9 is not installed.
+ bitz-server depends on liblog4cpp5; however:
+ Package liblog4cpp5 is not installed.
+ bitz-server depends on init-system-helpers (>= 1.18~); however:
+ Package init-system-helpers is not installed.
+
+ dpkg: error processing package bitz-server (--install):
+ dependency problems - leaving unconfigured
+ Setting up bitz-server-doc (0.1.6-1) ...
+ Setting up libicap0:amd64 (0.1.6-1) ...
+ dpkg: dependency problems prevent configuration of bitz-server-dbg:
+ bitz-server-dbg depends on bitz-server (= 0.1.6-1); however:
+ Package bitz-server is not configured yet.
+
+ dpkg: error processing package bitz-server-dbg (--install):
+ dependency problems - leaving unconfigured
+ Setting up libicap0-dbg:amd64 (0.1.6-1) ...
+ Setting up libicap-dev:amd64 (0.1.6-1) ...
+ Processing triggers for systemd (215-17) ...
+ Processing triggers for libc-bin (2.19-18) ...
+ Errors were encountered while processing:
+ bitz-server
+ bitz-server-dbg
+0m39.5s DEBUG: Command failed (status=1), but ignoring error: ['chroot', '/tmp/tmpDXAZc1', 'dpkg', '-i', 'tmp/bitz-server_0.1.6-1_amd64.deb', 'tmp/bitz-server-doc_0.1.6-1_all.deb', 'tmp/libicap-dev_0.1.6-1_amd64.deb', 'tmp/libicap0_0.1.6-1_amd64.deb', 'tmp/bitz-server-dbg_0.1.6-1_amd64.deb', 'tmp/libicap0-dbg_0.1.6-1_amd64.deb']
+0m39.5s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'apt-get', '-yf', 'install']
+0m45.7s DUMP:
+ Reading package lists...
+ Building dependency tree...
+ Reading state information...
+ Correcting dependencies... Done
+ The following extra packages will be installed:
+ init-system-helpers libconfig++9 liblog4cpp5
+ The following NEW packages will be installed:
+ init-system-helpers libconfig++9 liblog4cpp5
+ 0 upgraded, 3 newly installed, 0 to remove and 0 not upgraded.
+ 2 not fully installed or removed.
+ Need to get 183 kB of archives.
+ After this operation, 515 kB of additional disk space will be used.
+ Get:1 http://mirror.1und1.de/debian/ sid/main libconfig++9 amd64 1.4.9-2 [38.5 kB]
+ Get:2 http://mirror.1und1.de/debian/ sid/main liblog4cpp5 amd64 1.0-4 [129 kB]
+ Get:3 http://mirror.1und1.de/debian/ sid/main init-system-helpers all 1.23 [15.2 kB]
+ debconf: delaying package configuration, since apt-utils is not installed
+ Fetched 183 kB in 0s (366 kB/s)
+ Selecting previously unselected package libconfig++9:amd64.
+ (Reading database ... (Reading database ... 5% (Reading database ... 10% (Reading database ... 15% (Reading database ... 20% (Reading database ... 25% (Reading database ... 30% (Reading database ... 35% (Reading database ... 40% (Reading database ... 45% (Reading database ... 50% (Reading database ... 55% (Reading database ... 60% (Reading database ... 65% (Reading database ... 70% (Reading database ... 75% (Reading database ... 80% (Reading database ... 85% (Reading database ... 90% (Reading database ... 95% (Reading database ... 100% (Reading database ... 12812 files and directories currently installed.)
+ Preparing to unpack .../libconfig++9_1.4.9-2_amd64.deb ...
+ Unpacking libconfig++9:amd64 (1.4.9-2) ...
+ Selecting previously unselected package liblog4cpp5.
+ Preparing to unpack .../liblog4cpp5_1.0-4_amd64.deb ...
+ Unpacking liblog4cpp5 (1.0-4) ...
+ Selecting previously unselected package init-system-helpers.
+ Preparing to unpack .../init-system-helpers_1.23_all.deb ...
+ Unpacking init-system-helpers (1.23) ...
+ Setting up libconfig++9:amd64 (1.4.9-2) ...
+ Setting up liblog4cpp5 (1.0-4) ...
+ Setting up init-system-helpers (1.23) ...
+ Setting up bitz-server (0.1.6-1) ...
+ invoke-rc.d: policy-rc.d denied execution of start.
+ Setting up bitz-server-dbg (0.1.6-1) ...
+ Processing triggers for libc-bin (2.19-18) ...
+ Processing triggers for systemd (215-17) ...
+0m45.7s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'apt-get', '-yf', 'install']
+0m45.7s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'dpkg-query', '-f', '${Package} ${Status}\n', '-W', 'bitz-server', 'bitz-server-doc', 'libicap-dev', 'libicap0', 'bitz-server-dbg', 'libicap0-dbg']
+0m45.7s DUMP:
+ bitz-server install ok installed
+ bitz-server-dbg install ok installed
+ bitz-server-doc install ok installed
+ libicap-dev install ok installed
+ libicap0 install ok installed
+ libicap0-dbg install ok installed
+0m45.7s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'dpkg-query', '-f', '${Package} ${Status}\n', '-W', 'bitz-server', 'bitz-server-doc', 'libicap-dev', 'libicap0', 'bitz-server-dbg', 'libicap0-dbg']
+0m45.7s INFO: Installation of ['tmp/bitz-server_0.1.6-1_amd64.deb', 'tmp/bitz-server-doc_0.1.6-1_all.deb', 'tmp/libicap-dev_0.1.6-1_amd64.deb', 'tmp/libicap0_0.1.6-1_amd64.deb', 'tmp/bitz-server-dbg_0.1.6-1_amd64.deb', 'tmp/libicap0-dbg_0.1.6-1_amd64.deb'] ok
+0m45.7s DEBUG: Removing /tmp/tmpDXAZc1/tmp/bitz-server_0.1.6-1_amd64.deb
+0m45.7s DEBUG: Removing /tmp/tmpDXAZc1/tmp/bitz-server-doc_0.1.6-1_all.deb
+0m45.8s DEBUG: Removing /tmp/tmpDXAZc1/tmp/libicap-dev_0.1.6-1_amd64.deb
+0m45.8s DEBUG: Removing /tmp/tmpDXAZc1/tmp/libicap0_0.1.6-1_amd64.deb
+0m45.8s DEBUG: Removing /tmp/tmpDXAZc1/tmp/bitz-server-dbg_0.1.6-1_amd64.deb
+0m45.8s DEBUG: Removing /tmp/tmpDXAZc1/tmp/libicap0-dbg_0.1.6-1_amd64.deb
+0m45.8s DEBUG: Starting command: ['lsof', '-w', '+D', '/tmp/tmpDXAZc1']
+0m46.4s DEBUG: Command failed (status=1), but ignoring error: ['lsof', '-w', '+D', '/tmp/tmpDXAZc1']
+0m48.0s DEBUG: No broken symlinks as far as we can find.
+0m48.0s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'dpkg', '--get-selections', '*']
+0m48.1s DUMP:
+ acl install
+ adduser install
+ apt install
+ aptitude install
+ aptitude-common install
+ base-files install
+ base-passwd install
+ bash install
+ binutils install
+ bitz-server install
+ bitz-server-dbg install
+ bitz-server-doc install
+ bsdutils install
+ build-essential install
+ bzip2 install
+ coreutils install
+ cpp install
+ cpp-4.9 install
+ dash install
+ debconf install
+ debconf-i18n install
+ debian-archive-keyring install
+ debianutils install
+ diffutils install
+ dmsetup install
+ dpkg install
+ dpkg-dev install
+ e2fslibs:amd64 install
+ e2fsprogs install
+ findutils install
+ g++ install
+ g++-4.9 install
+ gcc install
+ gcc-4.7-base:amd64 install
+ gcc-4.8-base:amd64 install
+ gcc-4.9 install
+ gcc-4.9-base:amd64 install
+ gcc-5-base:amd64 install
+ gnupg install
+ gpgv install
+ grep install
+ gzip install
+ hostname install
+ init install
+ init-system-helpers install
+ initscripts install
+ insserv install
+ libacl1:amd64 install
+ libapt-pkg4.12:amd64 install
+ libasan1:amd64 install
+ libatomic1:amd64 install
+ libattr1:amd64 install
+ libaudit-common install
+ libaudit1:amd64 install
+ libblkid1:amd64 install
+ libboost-iostreams1.55.0:amd64 install
+ libbz2-1.0:amd64 install
+ libc-bin install
+ libc-dev-bin install
+ libc6:amd64 install
+ libc6-dev:amd64 install
+ libcap2:amd64 install
+ libcap2-bin install
+ libcilkrts5:amd64 install
+ libcloog-isl4:amd64 install
+ libcomerr2:amd64 install
+ libconfig++9:amd64 install
+ libcryptsetup4:amd64 install
+ libcwidget3:amd64 install
+ libdb5.3:amd64 install
+ libdebconfclient0:amd64 install
+ libdevmapper1.02.1:amd64 install
+ libdpkg-perl install
+ libfdisk1:amd64 install
+ libffi6:amd64 install
+ libgcc-4.9-dev:amd64 install
+ libgcc1:amd64 install
+ libgcrypt20:amd64 install
+ libgdbm3:amd64 install
+ libglib2.0-0:amd64 install
+ libgmp10:amd64 install
+ libgomp1:amd64 install
+ libgpg-error0:amd64 install
+ libgpm2:amd64 install
+ libicap-dev:amd64 install
+ libicap0:amd64 install
+ libicap0-dbg:amd64 install
+ libisl10:amd64 install
+ libisl13:amd64 install
+ libitm1:amd64 install
+ libkmod2:amd64 install
+ liblocale-gettext-perl install
+ liblog4cpp5 install
+ liblsan0:amd64 install
+ liblzma5:amd64 install
+ libmount1:amd64 install
+ libmpc3:amd64 install
+ libmpfr4:amd64 install
+ libncurses5:amd64 install
+ libncursesw5:amd64 install
+ libpam-modules:amd64 install
+ libpam-modules-bin install
+ libpam-runtime install
+ libpam0g:amd64 install
+ libpcre3:amd64 install
+ libprocps3:amd64 install
+ libquadmath0:amd64 install
+ libreadline6:amd64 install
+ libselinux1:amd64 install
+ libsemanage-common install
+ libsemanage1:amd64 install
+ libsepol1:amd64 install
+ libsigc++-2.0-0c2a:amd64 install
+ libslang2:amd64 install
+ libsmartcols1:amd64 install
+ libsqlite3-0:amd64 install
+ libss2:amd64 install
+ libssh2-1:amd64 install
+ libstdc++-4.9-dev:amd64 install
+ libstdc++6:amd64 install
+ libsystemd0:amd64 install
+ libtext-charwidth-perl install
+ libtext-iconv-perl install
+ libtext-wrapi18n-perl install
+ libtimedate-perl install
+ libtinfo5:amd64 install
+ libtsan0:amd64 install
+ libubsan0:amd64 install
+ libudev1:amd64 install
+ libusb-0.1-4:amd64 install
+ libustr-1.0-1:amd64 install
+ libuuid1:amd64 install
+ libxapian22 install
+ linux-libc-dev:amd64 install
+ login install
+ lsb-base install
+ make install
+ mawk install
+ mc install
+ mc-data install
+ mount install
+ multiarch-support install
+ ncurses-base install
+ ncurses-bin install
+ passwd install
+ patch install
+ perl install
+ perl-base install
+ perl-modules install
+ procps install
+ readline-common install
+ sed install
+ sensible-utils install
+ startpar install
+ systemd install
+ systemd-sysv install
+ sysv-rc install
+ sysvinit-utils install
+ tar install
+ tzdata install
+ udev install
+ util-linux install
+ xz-utils install
+ zlib1g:amd64 install
+0m48.1s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'dpkg', '--get-selections', '*']
+0m49.1s DEBUG: Starting command: ['debsums', '--root', '/tmp/tmpDXAZc1', '-ac']
+0m50.3s DEBUG: Command ok: ['debsums', '--root', '/tmp/tmpDXAZc1', '-ac']
+0m50.3s DEBUG: Starting command: ['dpkg-query', '-f', '${Version}\n', '-W', 'adequate']
+0m50.4s DUMP:
+ 0.13
+0m50.4s DEBUG: Command ok: ['dpkg-query', '-f', '${Version}\n', '-W', 'adequate']
+0m50.4s INFO: Running adequate version 0.13 now.
+0m50.4s DEBUG: Starting command: ['adequate', '--root', '/tmp/tmpDXAZc1', 'bitz-server', 'bitz-server-doc', 'libicap-dev', 'libicap0', 'bitz-server-dbg', 'libicap0-dbg']
+0m50.6s DEBUG: Command ok: ['adequate', '--root', '/tmp/tmpDXAZc1', 'bitz-server', 'bitz-server-doc', 'libicap-dev', 'libicap0', 'bitz-server-dbg', 'libicap0-dbg']
+0m50.6s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'apt-get', 'remove', '--no-install-recommends', 'libconfig++9:amd64', 'libicap-dev:amd64', 'liblog4cpp5', 'libicap0-dbg:amd64', 'libicap0:amd64', 'init-system-helpers', 'bitz-server-dbg', 'bitz-server', 'bitz-server-doc']
+0m55.5s DUMP:
+ Reading package lists...
+ Building dependency tree...
+ Reading state information...
+ The following packages will be REMOVED:
+ bitz-server bitz-server-dbg bitz-server-doc init-system-helpers libconfig++9
+ libicap-dev libicap0 libicap0-dbg liblog4cpp5
+ 0 upgraded, 0 newly installed, 9 to remove and 0 not upgraded.
+ After this operation, 3211 kB disk space will be freed.
+ (Reading database ... (Reading database ... 5% (Reading database ... 10% (Reading database ... 15% (Reading database ... 20% (Reading database ... 25% (Reading database ... 30% (Reading database ... 35% (Reading database ... 40% (Reading database ... 45% (Reading database ... 50% (Reading database ... 55% (Reading database ... 60% (Reading database ... 65% (Reading database ... 70% (Reading database ... 75% (Reading database ... 80% (Reading database ... 85% (Reading database ... 90% (Reading database ... 95% (Reading database ... 100% (Reading database ... 12837 files and directories currently installed.)
+ Removing bitz-server-dbg (0.1.6-1) ...
+ Removing bitz-server (0.1.6-1) ...
+ invoke-rc.d: policy-rc.d denied execution of stop.
+ Removing bitz-server-doc (0.1.6-1) ...
+ Removing init-system-helpers (1.23) ...
+ Removing libconfig++9:amd64 (1.4.9-2) ...
+ Removing libicap-dev:amd64 (0.1.6-1) ...
+ Removing libicap0-dbg:amd64 (0.1.6-1) ...
+ Removing libicap0:amd64 (0.1.6-1) ...
+ Removing liblog4cpp5 (1.0-4) ...
+ Processing triggers for libc-bin (2.19-18) ...
+0m55.5s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'apt-get', 'remove', '--no-install-recommends', 'libconfig++9:amd64', 'libicap-dev:amd64', 'liblog4cpp5', 'libicap0-dbg:amd64', 'libicap0:amd64', 'init-system-helpers', 'bitz-server-dbg', 'bitz-server', 'bitz-server-doc']
+0m55.5s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'dpkg', '--purge', 'libconfig++9:amd64', 'libicap-dev:amd64', 'liblog4cpp5', 'libicap0-dbg:amd64', 'libicap0:amd64', 'init-system-helpers']
+0m56.9s DUMP:
+ (Reading database ... 12468 files and directories currently installed.)
+ Removing libconfig++9:amd64 (1.4.9-2) ...
+ Purging configuration files for libconfig++9:amd64 (1.4.9-2) ...
+ dpkg: warning: ignoring request to remove libicap-dev which isn't installed
+ Removing liblog4cpp5 (1.0-4) ...
+ Purging configuration files for liblog4cpp5 (1.0-4) ...
+ dpkg: warning: ignoring request to remove libicap0-dbg which isn't installed
+ Removing libicap0:amd64 (0.1.6-1) ...
+ Purging configuration files for libicap0:amd64 (0.1.6-1) ...
+ dpkg: warning: ignoring request to remove init-system-helpers which isn't installed
+0m56.9s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'dpkg', '--purge', 'libconfig++9:amd64', 'libicap-dev:amd64', 'liblog4cpp5', 'libicap0-dbg:amd64', 'libicap0:amd64', 'init-system-helpers']
+0m56.9s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'dpkg', '--purge', 'bitz-server-dbg', 'bitz-server', 'bitz-server-doc']
+0m57.6s DUMP:
+ dpkg: warning: ignoring request to remove bitz-server-dbg which isn't installed
+ (Reading database ... 12468 files and directories currently installed.)
+ Removing bitz-server (0.1.6-1) ...
+ Purging configuration files for bitz-server (0.1.6-1) ...
+ dpkg: warning: ignoring request to remove bitz-server-doc which isn't installed
+0m57.6s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'dpkg', '--purge', 'bitz-server-dbg', 'bitz-server', 'bitz-server-doc']
+0m57.6s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'dpkg', '--purge', '--pending']
+0m57.6s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'dpkg', '--purge', '--pending']
+0m57.6s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'dpkg', '--remove', '--pending']
+0m57.7s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'dpkg', '--remove', '--pending']
+0m57.7s DEBUG: Starting command: ['lsof', '-w', '+D', '/tmp/tmpDXAZc1']
+0m58.3s DEBUG: Command failed (status=1), but ignoring error: ['lsof', '-w', '+D', '/tmp/tmpDXAZc1']
+0m59.9s DEBUG: No broken symlinks as far as we can find.
+0m59.9s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'dpkg-divert', '--list']
+0m59.9s DUMP:
+ diversion of /usr/share/man/man1/sh.1.gz to /usr/share/man/man1/sh.distrib.1.gz by dash
+ diversion of /bin/sh to /bin/sh.distrib by dash
+0m59.9s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'dpkg-divert', '--list']
+0m59.9s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'apt-get', 'clean']
+0m59.9s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'apt-get', 'clean']
+1m2.2s ERROR: FAIL: Package purging left files on system:
+ /etc/systemd/system/bitz-server.service -> /dev/null not owned
+ /var/lib/systemd/deb-systemd-helper-enabled/ not owned
+ /var/lib/systemd/deb-systemd-helper-enabled/bitz-server.service.dsh-also not owned
+ /var/lib/systemd/deb-systemd-helper-masked/ not owned
+ /var/lib/systemd/deb-systemd-helper-masked/bitz-server.service not owned
+
+1m2.3s ERROR: FAIL: Installation and purging test.
+1m2.9s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'umount', '/proc']
+1m2.9s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'umount', '/proc']
+1m2.9s DEBUG: Starting command: ['chroot', '/tmp/tmpDXAZc1', 'umount', '/dev/pts']
+1m3.0s DEBUG: Command ok: ['chroot', '/tmp/tmpDXAZc1', 'umount', '/dev/pts']
+1m3.0s DEBUG: Starting command: ['rm', '-rf', '--one-file-system', '/tmp/tmpDXAZc1']
+1m3.4s DEBUG: Command ok: ['rm', '-rf', '--one-file-system', '/tmp/tmpDXAZc1']
+1m3.4s DEBUG: Removed directory tree at /tmp/tmpDXAZc1
+1m3.4s ERROR: piuparts run ends.
diff --git a/debian/libicap-dev.docs b/debian/libicap-dev.docs
new file mode 100644
index 0000000..42061c0
--- /dev/null
+++ b/debian/libicap-dev.docs
@@ -0,0 +1 @@
+README.md \ No newline at end of file
diff --git a/debian/libicap-dev.install b/debian/libicap-dev.install
new file mode 100644
index 0000000..34bfc00
--- /dev/null
+++ b/debian/libicap-dev.install
@@ -0,0 +1,2 @@
+usr/include
+usr/lib/*/lib*.so
diff --git a/debian/libicap0.install b/debian/libicap0.install
new file mode 100644
index 0000000..3ddde58
--- /dev/null
+++ b/debian/libicap0.install
@@ -0,0 +1 @@
+usr/lib/*/lib*.so.*
diff --git a/debian/libicap0.symbols b/debian/libicap0.symbols
new file mode 100644
index 0000000..4b8c174
--- /dev/null
+++ b/debian/libicap0.symbols
@@ -0,0 +1,193 @@
+libicap.so.0 libicap0 #MINVER#
+ (c++)"socketlibrary::SocketException::SocketException(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)@Base" 0.1.6
+ (c++)"socketlibrary::SocketException::SocketException(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)@Base" 0.1.6
+ (c++)"socketlibrary::SocketException::~SocketException()@Base" 0.1.6
+ (c++)"socketlibrary::SocketException::~SocketException()@Base" 0.1.6
+ (c++)"socketlibrary::SocketException::~SocketException()@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocket::accept()@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocket::setListen(int)@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocket::TCPServerSocket(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short, int)@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocket::TCPServerSocket(unsigned short, int)@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocket::TCPServerSocket(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short, int)@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocket::TCPServerSocket(unsigned short, int)@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocketM::getWaitingClients(std::vector<socketlibrary::TCPSocket*, std::allocator<socketlibrary::TCPSocket*> >&)@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocketM::pendingConnections()@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocketM::closeClientConnection(socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocketM::accept()@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocketM::TCPServerSocketM(unsigned short, int)@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocketM::TCPServerSocketM(unsigned short, int)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::getForeignPort()@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::getForeignAddress[abi:cxx11]()@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::peek(void*, int)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::recv(void*, int)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::send(void const*, int)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::connect(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::readLine(char*, int, char)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::CommunicatingSocket(int)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::CommunicatingSocket(int, int)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::CommunicatingSocket(int)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::CommunicatingSocket(int, int)@Base" 0.1.6
+ (c++)"socketlibrary::Socket::getLocalPort()@Base" 0.1.6
+ (c++)"socketlibrary::Socket::setLocalPort(unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::Socket::resolveService(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"socketlibrary::Socket::getLocalAddress[abi:cxx11]()@Base" 0.1.6
+ (c++)"socketlibrary::Socket::setLocalAddressAndPort(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::Socket::cleanUp()@Base" 0.1.6
+ (c++)"socketlibrary::Socket::Socket(int)@Base" 0.1.6
+ (c++)"socketlibrary::Socket::Socket(int, int)@Base" 0.1.6
+ (c++)"socketlibrary::Socket::Socket(int)@Base" 0.1.6
+ (c++)"socketlibrary::Socket::Socket(int, int)@Base" 0.1.6
+ (c++)"socketlibrary::Socket::~Socket()@Base" 0.1.6
+ (c++)"socketlibrary::Socket::~Socket()@Base" 0.1.6
+ (c++)"socketlibrary::fillAddr(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short, sockaddr_in&)@Base" 0.1.6
+ (c++)"socketlibrary::TCPSocket::TCPSocket(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::TCPSocket::TCPSocket(int)@Base" 0.1.6
+ (c++)"socketlibrary::TCPSocket::TCPSocket()@Base" 0.1.6
+ (c++)"socketlibrary::TCPSocket::TCPSocket(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::TCPSocket::TCPSocket(int)@Base" 0.1.6
+ (c++)"socketlibrary::TCPSocket::TCPSocket()@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::disconnect()@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::leaveGroup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::setBroadcast()@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::setMulticastTTL(unsigned char)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::sendTo(void const*, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::recvFrom(void*, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, unsigned short&)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::joinGroup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::UDPSocket(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::UDPSocket(unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::UDPSocket()@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::UDPSocket(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::UDPSocket(unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::UDPSocket()@Base" 0.1.6
+ (c++)"icap::RequestHeader::read_header(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"icap::RequestHeader::RequestHeader(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"icap::RequestHeader::RequestHeader(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"icap::RequestHeader::~RequestHeader()@Base" 0.1.6
+ (c++)"icap::RequestHeader::~RequestHeader()@Base" 0.1.6
+ (c++)"icap::RequestHeader::~RequestHeader()@Base" 0.1.6
+ (c++)"icap::ResponseHeader::init_defaults()@Base" 0.1.6
+ (c++)"icap::ResponseHeader::generate_istag()@Base" 0.1.6
+ (c++)"icap::ResponseHeader::update_timestamp()@Base" 0.1.6
+ (c++)"icap::ResponseHeader::ResponseHeader(icap::ResponseHeader::status_t)@Base" 0.1.6
+ (c++)"icap::ResponseHeader::ResponseHeader(icap::ResponseHeader::status_t)@Base" 0.1.6
+ (c++)"icap::ResponseHeader::~ResponseHeader()@Base" 0.1.6
+ (c++)"icap::ResponseHeader::~ResponseHeader()@Base" 0.1.6
+ (c++)"icap::ResponseHeader::~ResponseHeader()@Base" 0.1.6
+ (c++)"icap::util::read_chunk(socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::read_chunked[abi:cxx11](socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::send_chunked(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::send_headers(icap::Header*, socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::read_req_data(icap::Request*, socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::send_response(icap::Response*, socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::read_chunk_size(socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::read_req_header(socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::response_status[abi:cxx11](icap::ResponseHeader::status_t const&)@Base" 0.1.6
+ (c++)"icap::util::read_chunk_header(socketlibrary::TCPSocket*, icap::util::chunk_t&)@Base" 0.1.6
+ (c++)"icap::util::read_chunked_payload(socketlibrary::TCPSocket*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)@Base" 0.1.6
+ (c++)"icap::util::read_req_continue_data(icap::Request*, socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > icap::util::itoa<int>(int)@Base" 0.1.6
+ (c++)"std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > icap::util::itoa<long>(long)@Base" 0.1.6
+ (c++)"icap::util::trim(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)@Base" 0.1.6
+ (c++)"icap::util::ltrim(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)@Base" 0.1.6
+ (c++)"icap::util::rtrim(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)@Base" 0.1.6
+ (c++)"icap::util::split(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"icap::util::chunk_t::~chunk_t()@Base" 0.1.6
+ (c++)"icap::util::chunk_t::~chunk_t()@Base" 0.1.6
+ (c++)"icap::util::dectohex[abi:cxx11](unsigned int const&)@Base" 0.1.6
+ (c++)"icap::util::hextodec(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"icap::util::read_data[abi:cxx11](socketlibrary::TCPSocket*, int)@Base" 0.1.6
+ (c++)"icap::util::read_line[abi:cxx11](socketlibrary::TCPSocket*, bool)@Base" 0.1.6
+ (c++)"icap::util::read_line(socketlibrary::TCPSocket*, char*, int, bool)@Base" 0.1.6
+ (c++)"icap::util::send_data(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::send_line(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::Header::attach_encapsulated(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)@Base" 0.1.6
+ (c++)"icap::Header::encapsulated_header(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"icap::Header::update_encapsulated(icap::payload_t const&)@Base" 0.1.6
+ (c++)"icap::Header::encapsulated_header_str[abi:cxx11]()@Base" 0.1.6
+ (c++)"icap::Header::sort_encapsulated_header[abi:cxx11]()@Base" 0.1.6
+ (c++)"icap::Header::value(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"icap::Header::attach(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)@Base" 0.1.6
+ (c++)"icap::Header::remove(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)@Base" 0.1.6
+ (c++)"icap::Header::Header()@Base" 0.1.6
+ (c++)"icap::Header::Header()@Base" 0.1.6
+ (c++)"icap::Header::~Header()@Base" 0.1.6
+ (c++)"icap::Header::~Header()@Base" 0.1.6
+ (c++)"icap::Header::~Header()@Base" 0.1.6
+ (c++)"icap::Request::preview_size()@Base" 0.1.6
+ (c++)"icap::Request::payload(icap::payload_t)@Base" 0.1.6
+ (c++)"icap::Request::Request(icap::RequestHeader*)@Base" 0.1.6
+ (c++)"icap::Request::Request(icap::RequestHeader*)@Base" 0.1.6
+ (c++)"icap::Request::~Request()@Base" 0.1.6
+ (c++)"icap::Request::~Request()@Base" 0.1.6
+ (c++)"icap::Request::~Request()@Base" 0.1.6
+ (c++)"icap::Response::payload(icap::payload_t)@Base" 0.1.6
+ (c++)"icap::Response::Response(icap::ResponseHeader::status_t)@Base" 0.1.6
+ (c++)"icap::Response::Response(icap::ResponseHeader*)@Base" 0.1.6
+ (c++)"icap::Response::Response(icap::ResponseHeader::status_t)@Base" 0.1.6
+ (c++)"icap::Response::Response(icap::ResponseHeader*)@Base" 0.1.6
+ (c++)"icap::Response::~Response()@Base" 0.1.6
+ (c++)"icap::Response::~Response()@Base" 0.1.6
+ (c++)"icap::Response::~Response()@Base" 0.1.6
+ (c++)"icap::payload_t::~payload_t()@Base" 0.1.6
+ (c++)"icap::payload_t::~payload_t()@Base" 0.1.6
+ (c++)"socketlibrary::SocketException::what() const@Base" 0.1.6
+ (c++)"icap::RequestHeader::uri[abi:cxx11]() const@Base" 0.1.6
+ (c++)"icap::RequestHeader::method[abi:cxx11]() const@Base" 0.1.6
+ (c++)"icap::RequestHeader::request() const@Base" 0.1.6
+ (c++)"icap::RequestHeader::protocol[abi:cxx11]() const@Base" 0.1.6
+ (c++)"icap::RequestHeader::raw_data[abi:cxx11]() const@Base" 0.1.6
+ (c++)"icap::ResponseHeader::status() const@Base" 0.1.6
+ (c++)"icap::ResponseHeader::protocol[abi:cxx11]() const@Base" 0.1.6
+ (c++)"icap::Header::headers[abi:cxx11]() const@Base" 0.1.6
+ (c++)"icap::Request::header() const@Base" 0.1.6
+ (c++)"icap::Request::payload() const@Base" 0.1.6
+ (c++)"icap::Response::header() const@Base" 0.1.6
+ (c++)"icap::Response::payload() const@Base" 0.1.6
+ (c++)"std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::_M_insert_aux(__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::~vector()@Base" 0.1.6
+ (c++)"std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::~vector()@Base" 0.1.6
+ (c++)"std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::operator=(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&)@Base" 0.1.6
+ (c++)"std::vector<socketlibrary::TCPSocket*, std::allocator<socketlibrary::TCPSocket*> >::_M_insert_aux(__gnu_cxx::__normal_iterator<socketlibrary::TCPSocket**, std::vector<socketlibrary::TCPSocket*, std::allocator<socketlibrary::TCPSocket*> > >, socketlibrary::TCPSocket* const&)@Base" 0.1.6
+ (c++)"std::vector<socketlibrary::TCPSocket*, std::allocator<socketlibrary::TCPSocket*> >::_M_fill_insert(__gnu_cxx::__normal_iterator<socketlibrary::TCPSocket**, std::vector<socketlibrary::TCPSocket*, std::allocator<socketlibrary::TCPSocket*> > >, unsigned long, socketlibrary::TCPSocket* const&)@Base" 0.1.6
+ (c++)"std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > >::~vector()@Base" 0.1.6
+ (c++)"std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > >::~vector()@Base" 0.1.6
+ (c++)"std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > >::operator=(std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > const&)@Base" 0.1.6
+ (c++)"std::__cxx11::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::~basic_stringbuf()@Base" 0.1.6
+ (c++)"std::__cxx11::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::~basic_stringbuf()@Base" 0.1.6
+ (c++)"std::__cxx11::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::~basic_stringbuf()@Base" 0.1.6
+ (c++)"std::_Rb_tree<icap::ResponseHeader::status_t, std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<icap::ResponseHeader::status_t>, std::allocator<std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_M_get_insert_unique_pos(icap::ResponseHeader::status_t const&)@Base" 0.1.6
+ (c++)"std::_Rb_tree<icap::ResponseHeader::status_t, std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<icap::ResponseHeader::status_t>, std::allocator<std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_M_get_insert_hint_unique_pos(std::_Rb_tree_const_iterator<std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, icap::ResponseHeader::status_t const&)@Base" 0.1.6
+ (c++)"std::_Rb_tree<icap::ResponseHeader::status_t, std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<icap::ResponseHeader::status_t>, std::allocator<std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_M_erase(std::_Rb_tree_node<std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >*)@Base" 0.1.6
+ (c++)"std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::equal_range(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_M_get_insert_unique_pos(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_M_get_insert_hint_unique_pos(std::_Rb_tree_const_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >* std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_M_copy<std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_Reuse_or_alloc_node>(std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const*, std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >*, std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_Reuse_or_alloc_node&)@Base" 0.1.6
+ (c++)"std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_M_erase(std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >*)@Base" 0.1.6
+ (c++)"std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int>, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > >::_M_get_insert_unique_pos(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int>, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > >::_M_get_insert_hint_unique_pos(std::_Rb_tree_const_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int>, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > >::find(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int>, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > >::_M_erase(std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> >*)@Base" 0.1.6
+ (c++)"void std::__make_heap<__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__ops::_Iter_comp_iter<icap::Header::encapsulated_header_compare> >(__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__ops::_Iter_comp_iter<icap::Header::encapsulated_header_compare>)@Base" 0.1.6
+ (c++)"void std::__adjust_heap<__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, long, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, __gnu_cxx::__ops::_Iter_comp_iter<icap::Header::encapsulated_header_compare> >(__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, long, long, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, __gnu_cxx::__ops::_Iter_comp_iter<icap::Header::encapsulated_header_compare>)@Base" 0.1.6
+ (c++)"void std::__insertion_sort<__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__ops::_Iter_comp_iter<icap::Header::encapsulated_header_compare> >(__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__ops::_Iter_comp_iter<icap::Header::encapsulated_header_compare>)@Base" 0.1.6
+ (c++)"void std::__introsort_loop<__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, long, __gnu_cxx::__ops::_Iter_comp_iter<icap::Header::encapsulated_header_compare> >(__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, long, __gnu_cxx::__ops::_Iter_comp_iter<icap::Header::encapsulated_header_compare>)@Base" 0.1.6
+ (c++)"void std::__unguarded_linear_insert<__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__ops::_Val_comp_iter<icap::Header::encapsulated_header_compare> >(__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__ops::_Val_comp_iter<icap::Header::encapsulated_header_compare>)@Base" 0.1.6
+ (c++)"__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > std::__find_if<__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__ops::_Iter_pred<std::unary_negate<std::pointer_to_unary_function<int, int> > > >(__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__ops::_Iter_pred<std::unary_negate<std::pointer_to_unary_function<int, int> > >, std::random_access_iterator_tag)@Base" 0.1.6
+ (c++)"typeinfo for socketlibrary::SocketException@Base" 0.1.6
+ (c++)"typeinfo for icap::RequestHeader@Base" 0.1.6
+ (c++)"typeinfo for icap::ResponseHeader@Base" 0.1.6
+ (c++)"typeinfo for icap::Header@Base" 0.1.6
+ (c++)"typeinfo for icap::Request@Base" 0.1.6
+ (c++)"typeinfo for icap::Response@Base" 0.1.6
+ (c++)"typeinfo name for socketlibrary::SocketException@Base" 0.1.6
+ (c++)"typeinfo name for icap::RequestHeader@Base" 0.1.6
+ (c++)"typeinfo name for icap::ResponseHeader@Base" 0.1.6
+ (c++)"typeinfo name for icap::Header@Base" 0.1.6
+ (c++)"typeinfo name for icap::Request@Base" 0.1.6
+ (c++)"typeinfo name for icap::Response@Base" 0.1.6
+ (c++)"vtable for socketlibrary::SocketException@Base" 0.1.6
+ (c++)"vtable for icap::RequestHeader@Base" 0.1.6
+ (c++)"vtable for icap::ResponseHeader@Base" 0.1.6
+ (c++)"vtable for icap::Header@Base" 0.1.6
+ (c++)"vtable for icap::Request@Base" 0.1.6
+ (c++)"vtable for icap::Response@Base" 0.1.6
diff --git a/debian/libicap0.symbols.i386 b/debian/libicap0.symbols.i386
new file mode 100644
index 0000000..f827875
--- /dev/null
+++ b/debian/libicap0.symbols.i386
@@ -0,0 +1,187 @@
+libicap.so.0 libicap0 #MINVER#
+ (c++)"socketlibrary::SocketException::SocketException(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)@Base" 0.1.6
+ (c++)"socketlibrary::SocketException::SocketException(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)@Base" 0.1.6
+ (c++)"socketlibrary::SocketException::~SocketException()@Base" 0.1.6
+ (c++)"socketlibrary::SocketException::~SocketException()@Base" 0.1.6
+ (c++)"socketlibrary::SocketException::~SocketException()@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocket::accept()@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocket::setListen(int)@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocket::TCPServerSocket(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short, int)@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocket::TCPServerSocket(unsigned short, int)@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocket::TCPServerSocket(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short, int)@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocket::TCPServerSocket(unsigned short, int)@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocketM::getWaitingClients(std::vector<socketlibrary::TCPSocket*, std::allocator<socketlibrary::TCPSocket*> >&)@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocketM::pendingConnections()@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocketM::closeClientConnection(socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocketM::accept()@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocketM::TCPServerSocketM(unsigned short, int)@Base" 0.1.6
+ (c++)"socketlibrary::TCPServerSocketM::TCPServerSocketM(unsigned short, int)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::getForeignPort()@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::getForeignAddress[abi:cxx11]()@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::peek(void*, int)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::recv(void*, int)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::send(void const*, int)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::connect(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::readLine(char*, int, char)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::CommunicatingSocket(int)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::CommunicatingSocket(int, int)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::CommunicatingSocket(int)@Base" 0.1.6
+ (c++)"socketlibrary::CommunicatingSocket::CommunicatingSocket(int, int)@Base" 0.1.6
+ (c++)"socketlibrary::Socket::getLocalPort()@Base" 0.1.6
+ (c++)"socketlibrary::Socket::setLocalPort(unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::Socket::resolveService(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"socketlibrary::Socket::getLocalAddress[abi:cxx11]()@Base" 0.1.6
+ (c++)"socketlibrary::Socket::setLocalAddressAndPort(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::Socket::cleanUp()@Base" 0.1.6
+ (c++)"socketlibrary::Socket::Socket(int)@Base" 0.1.6
+ (c++)"socketlibrary::Socket::Socket(int, int)@Base" 0.1.6
+ (c++)"socketlibrary::Socket::Socket(int)@Base" 0.1.6
+ (c++)"socketlibrary::Socket::Socket(int, int)@Base" 0.1.6
+ (c++)"socketlibrary::Socket::~Socket()@Base" 0.1.6
+ (c++)"socketlibrary::Socket::~Socket()@Base" 0.1.6
+ (c++)"socketlibrary::fillAddr(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short, sockaddr_in&)@Base" 0.1.6
+ (c++)"socketlibrary::TCPSocket::TCPSocket(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::TCPSocket::TCPSocket(int)@Base" 0.1.6
+ (c++)"socketlibrary::TCPSocket::TCPSocket()@Base" 0.1.6
+ (c++)"socketlibrary::TCPSocket::TCPSocket(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::TCPSocket::TCPSocket(int)@Base" 0.1.6
+ (c++)"socketlibrary::TCPSocket::TCPSocket()@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::disconnect()@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::leaveGroup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::setBroadcast()@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::setMulticastTTL(unsigned char)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::sendTo(void const*, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::recvFrom(void*, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, unsigned short&)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::joinGroup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::UDPSocket(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::UDPSocket(unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::UDPSocket()@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::UDPSocket(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::UDPSocket(unsigned short)@Base" 0.1.6
+ (c++)"socketlibrary::UDPSocket::UDPSocket()@Base" 0.1.6
+ (c++)"icap::RequestHeader::read_header(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"icap::RequestHeader::RequestHeader(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"icap::RequestHeader::RequestHeader(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"icap::RequestHeader::~RequestHeader()@Base" 0.1.6
+ (c++)"icap::RequestHeader::~RequestHeader()@Base" 0.1.6
+ (c++)"icap::RequestHeader::~RequestHeader()@Base" 0.1.6
+ (c++)"icap::ResponseHeader::init_defaults()@Base" 0.1.6
+ (c++)"icap::ResponseHeader::generate_istag()@Base" 0.1.6
+ (c++)"icap::ResponseHeader::update_timestamp()@Base" 0.1.6
+ (c++)"icap::ResponseHeader::ResponseHeader(icap::ResponseHeader::status_t)@Base" 0.1.6
+ (c++)"icap::ResponseHeader::ResponseHeader(icap::ResponseHeader::status_t)@Base" 0.1.6
+ (c++)"icap::ResponseHeader::~ResponseHeader()@Base" 0.1.6
+ (c++)"icap::ResponseHeader::~ResponseHeader()@Base" 0.1.6
+ (c++)"icap::ResponseHeader::~ResponseHeader()@Base" 0.1.6
+ (c++)"icap::util::read_chunk(socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::read_chunked[abi:cxx11](socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::send_chunked(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::send_headers(icap::Header*, socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::read_req_data(icap::Request*, socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::send_response(icap::Response*, socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::read_chunk_size(socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::read_req_header(socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::response_status[abi:cxx11](icap::ResponseHeader::status_t const&)@Base" 0.1.6
+ (c++)"icap::util::read_chunk_header(socketlibrary::TCPSocket*, icap::util::chunk_t&)@Base" 0.1.6
+ (c++)"icap::util::read_chunked_payload(socketlibrary::TCPSocket*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)@Base" 0.1.6
+ (c++)"icap::util::read_req_continue_data(icap::Request*, socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > icap::util::itoa<long>(long)@Base" 0.1.6
+ (c++)"icap::util::trim(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)@Base" 0.1.6
+ (c++)"icap::util::ltrim(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)@Base" 0.1.6
+ (c++)"icap::util::rtrim(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)@Base" 0.1.6
+ (c++)"icap::util::split(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"icap::util::chunk_t::~chunk_t()@Base" 0.1.6
+ (c++)"icap::util::chunk_t::~chunk_t()@Base" 0.1.6
+ (c++)"icap::util::dectohex[abi:cxx11](unsigned int const&)@Base" 0.1.6
+ (c++)"icap::util::hextodec(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"icap::util::read_data[abi:cxx11](socketlibrary::TCPSocket*, int)@Base" 0.1.6
+ (c++)"icap::util::read_line[abi:cxx11](socketlibrary::TCPSocket*, bool)@Base" 0.1.6
+ (c++)"icap::util::read_line(socketlibrary::TCPSocket*, char*, int, bool)@Base" 0.1.6
+ (c++)"icap::util::send_data(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::util::send_line(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, socketlibrary::TCPSocket*)@Base" 0.1.6
+ (c++)"icap::Header::attach_encapsulated(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)@Base" 0.1.6
+ (c++)"icap::Header::encapsulated_header(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"icap::Header::update_encapsulated(icap::payload_t const&)@Base" 0.1.6
+ (c++)"icap::Header::encapsulated_header_str[abi:cxx11]()@Base" 0.1.6
+ (c++)"icap::Header::sort_encapsulated_header[abi:cxx11]()@Base" 0.1.6
+ (c++)"icap::Header::value(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"icap::Header::attach(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)@Base" 0.1.6
+ (c++)"icap::Header::remove(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)@Base" 0.1.6
+ (c++)"icap::Header::Header()@Base" 0.1.6
+ (c++)"icap::Header::Header()@Base" 0.1.6
+ (c++)"icap::Header::~Header()@Base" 0.1.6
+ (c++)"icap::Header::~Header()@Base" 0.1.6
+ (c++)"icap::Header::~Header()@Base" 0.1.6
+ (c++)"icap::Request::preview_size()@Base" 0.1.6
+ (c++)"icap::Request::payload(icap::payload_t)@Base" 0.1.6
+ (c++)"icap::Request::Request(icap::RequestHeader*)@Base" 0.1.6
+ (c++)"icap::Request::Request(icap::RequestHeader*)@Base" 0.1.6
+ (c++)"icap::Request::~Request()@Base" 0.1.6
+ (c++)"icap::Request::~Request()@Base" 0.1.6
+ (c++)"icap::Request::~Request()@Base" 0.1.6
+ (c++)"icap::Response::payload(icap::payload_t)@Base" 0.1.6
+ (c++)"icap::Response::Response(icap::ResponseHeader::status_t)@Base" 0.1.6
+ (c++)"icap::Response::Response(icap::ResponseHeader*)@Base" 0.1.6
+ (c++)"icap::Response::Response(icap::ResponseHeader::status_t)@Base" 0.1.6
+ (c++)"icap::Response::Response(icap::ResponseHeader*)@Base" 0.1.6
+ (c++)"icap::Response::~Response()@Base" 0.1.6
+ (c++)"icap::Response::~Response()@Base" 0.1.6
+ (c++)"icap::Response::~Response()@Base" 0.1.6
+ (c++)"icap::payload_t::~payload_t()@Base" 0.1.6
+ (c++)"icap::payload_t::~payload_t()@Base" 0.1.6
+ (c++)"socketlibrary::SocketException::what() const@Base" 0.1.6
+ (c++)"icap::RequestHeader::uri[abi:cxx11]() const@Base" 0.1.6
+ (c++)"icap::RequestHeader::method[abi:cxx11]() const@Base" 0.1.6
+ (c++)"icap::RequestHeader::request() const@Base" 0.1.6
+ (c++)"icap::RequestHeader::protocol[abi:cxx11]() const@Base" 0.1.6
+ (c++)"icap::RequestHeader::raw_data[abi:cxx11]() const@Base" 0.1.6
+ (c++)"icap::ResponseHeader::status() const@Base" 0.1.6
+ (c++)"icap::ResponseHeader::protocol[abi:cxx11]() const@Base" 0.1.6
+ (c++)"icap::Header::headers[abi:cxx11]() const@Base" 0.1.6
+ (c++)"icap::Request::header() const@Base" 0.1.6
+ (c++)"icap::Request::payload() const@Base" 0.1.6
+ (c++)"icap::Response::header() const@Base" 0.1.6
+ (c++)"icap::Response::payload() const@Base" 0.1.6
+ (c++)"std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::_M_insert_aux(__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::~vector()@Base" 0.1.6
+ (c++)"std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::~vector()@Base" 0.1.6
+ (c++)"std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::operator=(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&)@Base" 0.1.6
+ (c++)"std::vector<socketlibrary::TCPSocket*, std::allocator<socketlibrary::TCPSocket*> >::_M_insert_aux(__gnu_cxx::__normal_iterator<socketlibrary::TCPSocket**, std::vector<socketlibrary::TCPSocket*, std::allocator<socketlibrary::TCPSocket*> > >, socketlibrary::TCPSocket* const&)@Base" 0.1.6
+ (c++)"std::vector<socketlibrary::TCPSocket*, std::allocator<socketlibrary::TCPSocket*> >::_M_fill_insert(__gnu_cxx::__normal_iterator<socketlibrary::TCPSocket**, std::vector<socketlibrary::TCPSocket*, std::allocator<socketlibrary::TCPSocket*> > >, unsigned int, socketlibrary::TCPSocket* const&)@Base" 0.1.6
+ (c++)"std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > >::~vector()@Base" 0.1.6
+ (c++)"std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > >::~vector()@Base" 0.1.6
+ (c++)"std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > >::operator=(std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > const&)@Base" 0.1.6
+ (c++)"std::__cxx11::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::~basic_stringbuf()@Base" 0.1.6
+ (c++)"std::__cxx11::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::~basic_stringbuf()@Base" 0.1.6
+ (c++)"std::__cxx11::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::~basic_stringbuf()@Base" 0.1.6
+ (c++)"std::_Rb_tree<icap::ResponseHeader::status_t, std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<icap::ResponseHeader::status_t>, std::allocator<std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_M_get_insert_unique_pos(icap::ResponseHeader::status_t const&)@Base" 0.1.6
+ (c++)"std::_Rb_tree<icap::ResponseHeader::status_t, std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<icap::ResponseHeader::status_t>, std::allocator<std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_M_erase(std::_Rb_tree_node<std::pair<icap::ResponseHeader::status_t const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >*)@Base" 0.1.6
+ (c++)"std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_M_get_insert_unique_pos(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >* std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_M_copy<std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_Reuse_or_alloc_node>(std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const*, std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >*, std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_Reuse_or_alloc_node&)@Base" 0.1.6
+ (c++)"std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_M_erase(std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >*)@Base" 0.1.6
+ (c++)"std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int>, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > >::_M_get_insert_unique_pos(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int>, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > >::find(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.1.6
+ (c++)"std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int>, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > >::_M_erase(std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> >*)@Base" 0.1.6
+ (c++)"void std::__make_heap<__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__ops::_Iter_comp_iter<icap::Header::encapsulated_header_compare> >(__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__ops::_Iter_comp_iter<icap::Header::encapsulated_header_compare>)@Base" 0.1.6
+ (c++)"void std::__adjust_heap<__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, int, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, __gnu_cxx::__ops::_Iter_comp_iter<icap::Header::encapsulated_header_compare> >(__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, int, int, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, __gnu_cxx::__ops::_Iter_comp_iter<icap::Header::encapsulated_header_compare>)@Base" 0.1.6
+ (c++)"void std::__insertion_sort<__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__ops::_Iter_comp_iter<icap::Header::encapsulated_header_compare> >(__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__ops::_Iter_comp_iter<icap::Header::encapsulated_header_compare>)@Base" 0.1.6
+ (c++)"void std::__introsort_loop<__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, int, __gnu_cxx::__ops::_Iter_comp_iter<icap::Header::encapsulated_header_compare> >(__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, int, __gnu_cxx::__ops::_Iter_comp_iter<icap::Header::encapsulated_header_compare>)@Base" 0.1.6
+ (c++)"void std::__unguarded_linear_insert<__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__ops::_Val_comp_iter<icap::Header::encapsulated_header_compare> >(__gnu_cxx::__normal_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>*, std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > >, __gnu_cxx::__ops::_Val_comp_iter<icap::Header::encapsulated_header_compare>)@Base" 0.1.6
+ (c++)"typeinfo for socketlibrary::SocketException@Base" 0.1.6
+ (c++)"typeinfo for icap::RequestHeader@Base" 0.1.6
+ (c++)"typeinfo for icap::ResponseHeader@Base" 0.1.6
+ (c++)"typeinfo for icap::Header@Base" 0.1.6
+ (c++)"typeinfo for icap::Request@Base" 0.1.6
+ (c++)"typeinfo for icap::Response@Base" 0.1.6
+ (c++)"typeinfo name for socketlibrary::SocketException@Base" 0.1.6
+ (c++)"typeinfo name for icap::RequestHeader@Base" 0.1.6
+ (c++)"typeinfo name for icap::ResponseHeader@Base" 0.1.6
+ (c++)"typeinfo name for icap::Header@Base" 0.1.6
+ (c++)"typeinfo name for icap::Request@Base" 0.1.6
+ (c++)"typeinfo name for icap::Response@Base" 0.1.6
+ (c++)"vtable for socketlibrary::SocketException@Base" 0.1.6
+ (c++)"vtable for icap::RequestHeader@Base" 0.1.6
+ (c++)"vtable for icap::ResponseHeader@Base" 0.1.6
+ (c++)"vtable for icap::Header@Base" 0.1.6
+ (c++)"vtable for icap::Request@Base" 0.1.6
+ (c++)"vtable for icap::Response@Base" 0.1.6
diff --git a/debian/patches/0001-disable_search_doc.patch b/debian/patches/0001-disable_search_doc.patch
new file mode 100644
index 0000000..0dfcdfb
--- /dev/null
+++ b/debian/patches/0001-disable_search_doc.patch
@@ -0,0 +1,18 @@
+Description: Disable search in documentation
+Author: Jörg Frings-Fürst <debian@jff-webhosting.net>
+Last-Update: 2015-05-14
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+Index: trunk/doc/doxygen.cfg.in
+===================================================================
+--- trunk.orig/doc/doxygen.cfg.in
++++ trunk/doc/doxygen.cfg.in
+@@ -1234,7 +1234,7 @@ MATHJAX_EXTENSIONS =
+ # typically be disabled. For large projects the javascript based search engine
+ # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+-SEARCHENGINE = YES
++SEARCHENGINE = NO
+
+ # When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+ # implemented using a web server instead of a web client using Javascript.
diff --git a/debian/patches/0100-python_print.patch b/debian/patches/0100-python_print.patch
new file mode 100644
index 0000000..472dc63
--- /dev/null
+++ b/debian/patches/0100-python_print.patch
@@ -0,0 +1,171 @@
+Description: Change to python3 syntacs
+Author: Jörg Frings-Fürst <debian@jff-webhosting.net>
+Forwarded: mailto:Uditha Atukorala <ua@nuked.zone>
+Last-Update: 2015-11-21
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+Index: trunk/modules/modpy/modules/modpy.py
+===================================================================
+--- trunk.orig/modules/modpy/modules/modpy.py
++++ trunk/modules/modpy/modules/modpy.py
+@@ -6,15 +6,15 @@
+ import bitz
+
+ def init():
+- print "init() called";
++ print ("init() called");
+
+ def cleanup():
+- print "cleanup() called";
++ print ("cleanup() called");
+
+ def preview( request ):
+ request = bitz.get_request( request );
+ req_payload = request['payload'];
+- print "preview payload: \r\n", req_payload;
++ print ("preview payload: \r\n", req_payload);
+
+ # response
+ if req_payload['ieof']:
+@@ -27,7 +27,7 @@ def preview( request ):
+ def modify( request ):
+ request = bitz.get_request( request );
+ req_payload = request['payload'];
+- print "modify payload: \r\n", req_payload;
++ print ("modify payload: \r\n", req_payload);
+
+ # response
+ resp_payload = {};
+Index: trunk/test/icap-client.py
+===================================================================
+--- trunk.orig/test/icap-client.py
++++ trunk/test/icap-client.py
+@@ -14,16 +14,16 @@ SERVICE = 'icap://icap.server.net/sample
+ PORT = 1344
+
+ # OPTIONS
+-print "----- OPTIONS -----"
++print ("----- OPTIONS -----")
+ try:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+-except socket.error, msg:
++except socket.error as msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(1)
+
+ try:
+ sock.connect((HOST, PORT))
+-except socket.error, msg:
++except socket.error as msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(2)
+
+@@ -40,20 +40,20 @@ while len(data):
+ data = sock.recv(1024)
+ sock.close()
+
+-print string
++print (string)
+
+
+ # REQMOD, GET
+-print "----- REQMOD - GET -----"
++print ("----- REQMOD - GET -----")
+ try:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+-except socket.error, msg:
++except socket.error as msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(1)
+
+ try:
+ sock.connect((HOST, PORT))
+-except socket.error, msg:
++except socket.error as msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(2)
+
+@@ -78,20 +78,20 @@ while len(data):
+ data = sock.recv(1024)
+ sock.close()
+
+-print string
++print (string)
+
+
+ # REQMOD, POST
+-print "----- REQMOD - POST -----"
++print ("----- REQMOD - POST -----")
+ try:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+-except socket.error, msg:
++except socket.error as msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(1)
+
+ try:
+ sock.connect((HOST, PORT))
+-except socket.error, msg:
++except socket.error as msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(2)
+
+@@ -118,20 +118,20 @@ while len(data):
+ data = sock.recv(1024)
+ sock.close()
+
+-print string
++print (string)
+
+
+ # REQMOD - Message preview
+-print "----- REQMOD - Message preview -----"
++print ("----- REQMOD - Message preview -----")
+ try:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+-except socket.error, msg:
++except socket.error as msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(1)
+
+ try:
+ sock.connect((HOST, PORT))
+-except socket.error, msg:
++except socket.error as msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(2)
+
+@@ -158,20 +158,20 @@ while len(data):
+ data = sock.recv(1024)
+ sock.close()
+
+-print string
++print (string)
+
+
+ # RESPMOD
+-print "----- RESPMOD -----"
++print ("----- RESPMOD -----")
+ try:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+-except socket.error, msg:
++except socket.error as msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(1)
+
+ try:
+ sock.connect((HOST, PORT))
+-except socket.error, msg:
++except socket.error as msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(2)
+
+@@ -204,7 +204,7 @@ while len(data):
+ data = sock.recv(1024)
+ sock.close()
+
+-print string
++print (string)
+
+
+ sys.exit(0)
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..4705ad2
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,2 @@
+0100-python_print.patch
+0001-disable_search_doc.patch
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..cf9ec8b
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,35 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+export DEB_BUILD_MAINT_OPTIONS = hardening=+all
+
+VERSION = $(shell head -n1 debian/changelog | sed -e 's/.*(//;s/-.*).*//;s/\+/\-/')
+
+%:
+ dh $@ --with systemd,autoreconf
+
+override_dh_auto_build-indep:
+ dh_auto_build
+ make -C doc doxygen-doc
+
+override_dh_installdocs-indep:
+ cp -r $(CURDIR)/doc/doxygen/html/* $(CURDIR)/debian/bitz-server-doc/usr/share/doc/bitz-server-doc/docs/
+ dh_installdocs
+
+override_dh_strip:
+ dh_strip -pbitz-server --dbg-package=bitz-server-dbg
+ dh_strip -plibicap0 --dbg-package=libicap0-dbg
+
+override_dh_makeshlibs:
+ dh_makeshlibs
+ dpkg-gensymbols -v$(VERSION) -plibicap0
+
+override_dh_systemd_enable:
+<<<<<<< HEAD
+ dh_systemd_enable -pbitz-server --no-enable bitz-server.service
+=======
+ dh_systemd_enable --no-enable bitz-server.service
+>>>>>>> 042c3255709d05a45bf08fdd0ff2f1eb4027637b
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/debian/watch b/debian/watch
new file mode 100644
index 0000000..066e65d
--- /dev/null
+++ b/debian/watch
@@ -0,0 +1,5 @@
+# Compulsory line, this is a version 3 file
+version=3
+
+opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/bitz-server-$1\.tar\.gz/ \
+ https://github.com/uditha-atukorala/bitz-server/tags .*/v?(\d\S*)\.tar\.gz
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..190a30d
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,30 @@
+# doc/
+
+# man
+man1_MANS = bitz-server.man
+man5_MANS = bitz-server.conf.man
+
+# extra dist files
+EXTRA_DIST = \
+ bitz-server.man \
+ bitz-server.conf.man
+
+
+# doxygen
+if HAVE_DOXYGEN
+
+.PHONY: doxygen-doc
+
+doxygen.stamp:
+ $(DOXYGEN) doxygen.cfg
+ echo timestamp > doxygen.stamp
+
+CLEANFILES = doxygen.stamp
+
+doxygen-doc: doxygen.stamp
+
+clean-local:
+ rm -rf $(top_builddir)/doc/doxygen
+
+endif
+
diff --git a/doc/bitz-server.conf.man b/doc/bitz-server.conf.man
new file mode 100644
index 0000000..1c9b5b0
--- /dev/null
+++ b/doc/bitz-server.conf.man
@@ -0,0 +1,64 @@
+.TH bitz-server.conf 5 "March 2013" Linux "File Formats Manual"
+.SH NAME
+bitz-server.conf \- bitz-server configuration file
+.SH SYNOPSIS
+.B /etc/bitz/bitz-server.conf
+.SH DESCRIPTION
+.BR bitz-server (1)
+obtains configuration data from a config file, the location of which is specified
+at compile-time and can be overridden by command-line options during run-time.
+.SS Grammer
+Below is the BNF grammar for configuration files. Comments and include directives
+are not part of the grammar, so they are not included here. See libconfig manual
+at http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-File-Grammar
+for more details.
+.PP
+.RS
+.nf
+configuration = setting-list | empty
+setting-list = setting | setting-list setting
+setting = name (":" | "=") value (";" | "," | empty)
+value = scalar-value | array | list | group
+value-list = value | value-list "," value
+scalar-value = boolean | integer | integer64 | hex | hex64 | float | string
+scalar-value-list = scalar-value | scalar-value-list "," scalar-value
+array = "[" (scalar-value-list | empty) "]"
+list = "(" (value-list | empty) ")"
+group = "{" (setting-list | empty) "}"
+empty =
+.fi
+.RE
+.PP
+Terminals are defined below as regular expressions:
+.TP
+.B boolean
+([Tt][Rr][Uu][Ee])|([Ff][Aa][Ll][Ss][Ee])
+.TP
+.B string
+\\"([^\\"\\\\]|\\\\.)*\\"
+.TP
+.B name
+[A-Za-z\\*][\-A-Za-z0-9_\\*]*
+.TP
+.B integer
+[\-+]?[0-9]+
+.TP
+.B integer64
+[\-+]?[0-9]+L(L)?
+.TP
+.B hex
+0[Xx][0-9A-Fa-f]+
+.TP
+.B hex64
+0[Xx][0-9A-Fa-f]+L(L)?
+.TP
+.B float
+.nf
+([\-+]?([0-9]*)?\\.[0-9]*([eE][-+]?[0-9]+)?)|
+([\-+]([0-9]+)(\\.[0-9]*)?[eE][-+]?[0-9]+)
+.fi
+.SH AUTHOR
+Uditha Atukorala <udi at geniusse dot com>
+.SH "SEE ALSO"
+.BR bitz-server (1)
+
diff --git a/doc/bitz-server.man b/doc/bitz-server.man
new file mode 100644
index 0000000..d59ffc1
--- /dev/null
+++ b/doc/bitz-server.man
@@ -0,0 +1,47 @@
+.TH bitz-server 1 "March 2013" Linux "User Manuals"
+.SH NAME
+bitz-server \- An ICAP server
+.SH SYNOPSIS
+.B bitz-server
+[\-\-version] [\-\-help] [\-\-usage] [\-\-debug] [\-\-config=<config file>]
+.SH DESCRIPTION
+.B bitz-server
+is an ICAP server implementation in C++. Starting from scratch,
+the server is developed with a modular architecture in mind.
+The server core (written in C++) will handle the client requests,
+manage workers (child processes) etc. and will provide basic handlers
+to serve ICAP requests but won't do any actual content adaptation.
+.P
+To extend this core functionality and do some actual content adaptation
+a pluggable modules architecture is used. These modules will provide
+features like content filtering, anti-virus scanning etc. and to make it
+easier to write (and faster to implement) such modules a python interface
+module is included.
+.SH OPTIONS
+.TP
+.B \-\-version, \-v
+Prints version information
+.TP
+.B \-\-help, \-\-usage, \-h
+Prints the synopsis
+.TP
+.B \-\-debug
+Run the server in debug mode. This will force the server to run in the
+terminal rather than in the background.
+.TP
+.B \-\-config=<config file>
+Set the alternative config file to use instead of the compiled default.
+.SH FILES
+.I /etc/bitz/bitz-server.conf
+.RS
+Default configuration file. See
+.BR bitz-server.conf (5)
+for further details.
+.RE
+.SH BUGS
+Please report all bugs and feature requests at <http://bugs.geniusse.com/>
+.SH AUTHOR
+Uditha Atukorala <udi at geniusse dot com>
+.SH "SEE ALSO"
+.BR bitz-server.conf (5)
+
diff --git a/doc/doxygen.cfg.in b/doc/doxygen.cfg.in
new file mode 100644
index 0000000..c4bb0e3
--- /dev/null
+++ b/doc/doxygen.cfg.in
@@ -0,0 +1,1864 @@
+# Doxyfile 1.8.3
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME = @PACKAGE_NAME@
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = @PACKAGE_VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = @top_builddir@/doc/doxygen
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip. Note that you specify absolute paths here, but also
+# relative paths, which will be relative from the directory where doxygen is
+# started.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
+# itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension,
+# and language is one of the parsers supported by doxygen: IDL, Java,
+# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C,
+# C++. For instance to make doxygen treat .inc files as Fortran files (default
+# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note
+# that for custom extensions you also need to set FILE_PATTERNS otherwise the
+# files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
+# comments according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you
+# can mix doxygen, HTML, and XML commands with Markdown formatting.
+# Disable only in case of backward compatibilities issues.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented classes,
+# or namespaces to their corresponding documentation. Such a link can be
+# prevented in individual cases by by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES (the
+# default) will make doxygen replace the get and set methods by a property in
+# the documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields will be shown inline in the documentation
+# of the scope in which they are defined (i.e. file, namespace, or group
+# documentation), provided this scope is documented. If set to NO (the default),
+# structs, classes, and unions are shown on a separate page (for HTML and Man
+# pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+SYMBOL_CACHE_SIZE = 0
+
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
+# their name and scope. Since this can be an expensive process and often the
+# same symbol appear multiple times in the code, doxygen keeps a cache of
+# pre-resolved symbols. If the cache is too small doxygen will become slower.
+# If the cache is too large, memory is wasted. The cache size is given by this
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if section-label ... \endif
+# and \cond section-label ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path. Do not use
+# file names with spaces, bibtex cannot handle them.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = @top_srcdir@
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE = @top_srcdir@/doc
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page (index.html).
+# This can be useful if you have a project on for instance GitHub and want reuse
+# the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C, C++ and Fortran comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+# for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If left blank doxygen will
+# generate a default style sheet. Note that it is recommended to use
+# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this
+# tag will in the future become obsolete.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional
+# user-defined cascading style sheet that is included after the standard
+# style sheets created by doxygen. Using this option one can overrule
+# certain style aspects. This is preferred over using HTML_STYLESHEET
+# since it does not replace the standard style sheet and is therefor more
+# robust against future updates. Doxygen will copy the style sheet file to
+# the output directory.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the style sheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
+# entries shown in the various tree structured indices initially; the user
+# can expand and collapse entries dynamically later on. Doxygen will expand
+# the tree to such a level that at most the specified number of entries are
+# visible (unless a fully collapsed tree already exceeds this amount).
+# So setting the number of entries 1 will produce a full collapsed tree by
+# default. 0 is a special value representing an infinite number of entries
+# and will result in a full expanded tree by default.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely
+# identify the documentation publisher. This should be a reverse domain-name
+# style string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
+# could consider to set DISABLE_INDEX to NO when enabling this option.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you may also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and
+# SVG. The default value is HTML-CSS, which is slower, but has the best
+# compatibility.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to
+# the MathJax Content Delivery Network so you can quickly see the result without
+# installing MathJax.
+# However, it is strongly recommended to install a local
+# copy of MathJax from http://www.mathjax.org before deployment.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript.
+# There are two flavours of web server based search depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools.
+# See the manual for details.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain
+# the search results. Doxygen ships with an example indexer (doxyindexer) and
+# search engine (doxysearch.cgi) which are based on the open source search engine
+# library Xapian. See the manual for configuration details.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will returned the search results when EXTERNAL_SEARCH is enabled.
+# Doxygen ships with an example search engine (doxysearch) which is based on
+# the open source search engine library Xapian. See the manual for configuration
+# details.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through other
+# doxygen projects that are not otherwise connected via tags files, but are
+# all added to the same search index. Each project needs to have a tag file set
+# via GENERATE_TAGFILE. The search mapping then maps the name of the tag file
+# to a relative location where the documentation can be found,
+# similar to the
+# TAGFILES option but without actually processing the tag file.
+# The format is: EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load style sheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. For each
+# tag file the location of the external documentation should be added. The
+# format of a tag file without this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths
+# or URLs. Note that each tag file must have a unique name (where the name does
+# NOT include the path). If a tag file is not located in the directory in which
+# doxygen is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS = 0
+
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# set the path where dot can find it.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside
+# the class node. If there are many fields or methods and many nodes the
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
+# threshold limits the number of items for each type to make the size more
+# managable. Set this to 0 for no limit. Note that the threshold may be
+# exceeded by 50% before the limit is enforced.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..acb92a3
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1 @@
+## include/
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..bcd3933
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,3 @@
+## [bitz-server] lib/
+SUBDIRS = socket icap
+
diff --git a/lib/icap/Makefile.am b/lib/icap/Makefile.am
new file mode 100644
index 0000000..02d8bb4
--- /dev/null
+++ b/lib/icap/Makefile.am
@@ -0,0 +1,24 @@
+## [icap-library] lib/icap/
+AM_CPPFLAGS = -I$(top_srcdir)/lib
+libicapincludedir = $(includedir)/icap
+
+lib_LTLIBRARIES = libicap.la
+libicap_la_LIBADD = $(top_builddir)/lib/socket/libsocket.la
+libicap_la_LDFLAGS = -version-info @ICAP_LT_VERSION@ -no-undefined
+libicap_la_SOURCES = \
+ header.cpp \
+ request_header.cpp \
+ response_header.cpp \
+ request.cpp \
+ response.cpp \
+ util.cpp
+
+libicapinclude_HEADERS = \
+ common.h \
+ header.h \
+ request_header.h \
+ response_header.h \
+ request.h \
+ response.h \
+ util.h
+
diff --git a/lib/icap/common.h b/lib/icap/common.h
new file mode 100644
index 0000000..65c3694
--- /dev/null
+++ b/lib/icap/common.h
@@ -0,0 +1,41 @@
+/*
+ * C++ ICAP library
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef ICAP_COMMON_H
+#define ICAP_COMMON_H
+
+#include <string>
+
+
+namespace icap {
+
+ /**
+ * Payload structure common to both requests and responses.
+ */
+ struct payload_t {
+ std::string req_header; /**< request header */
+ std::string req_body; /**< request body */
+ std::string res_header; /**< response header */
+ std::string res_body; /**< response body */
+ bool ieof; /**< boolen flag to store the presence of "ieof" */
+ };
+
+} /* end of namespace icap */
+
+#endif /* !ICAP_COMMON_H */
diff --git a/lib/icap/header.cpp b/lib/icap/header.cpp
new file mode 100644
index 0000000..493e659
--- /dev/null
+++ b/lib/icap/header.cpp
@@ -0,0 +1,223 @@
+/*
+ * C++ ICAP library
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "header.h"
+#include "util.h"
+
+#include <algorithm>
+#include <cstdlib>
+
+
+namespace icap {
+
+ Header::Header() {
+
+ // initialise defaults
+ _encapsulated["req-hdr"] = -1;
+ _encapsulated["req-body"] = -1;
+ _encapsulated["res-hdr"] = -1;
+ _encapsulated["res-body"] = -1;
+ _encapsulated["opt-body"] = -1;
+ _encapsulated["null-body"] = -1;
+
+ }
+
+ Header::~Header() {}
+
+
+ const Header::headers_t &Header::headers() const throw() {
+ return _headers;
+ }
+
+
+ const std::string Header::value( const std::string &key ) throw() {
+
+ std::string value = "";
+ Header::headers_index_t idx = _headers.find( key );
+
+ if ( idx != _headers.end() ) {
+ value = idx->second;
+ }
+
+ return value;
+
+ }
+
+
+ const int Header::encapsulated_header( const std::string &entity ) throw() {
+
+ Header::encapsulated_header_index_t idx;
+
+ idx = _encapsulated.find( entity );
+ if ( idx == _encapsulated.end() ) {
+ return -1;
+ }
+
+ return idx->second;
+
+ }
+
+
+ void Header::attach( std::string key, std::string value ) throw() {
+
+ // trim
+ key = util::trim( key );
+ value = util::trim( value );
+
+ // check for 'Encapsulated' headers
+ if ( key == "Encapsulated" ) {
+ attach_encapsulated( value );
+ } else {
+ _headers[key] = value;
+ }
+
+ }
+
+
+ bool Header::attach_encapsulated( std::string header_value ) throw() {
+
+ std::vector<std::string> list_data;
+ std::vector<std::string> entity_data;
+
+ encapsulated_header_index_t idx;
+ bool r_status = true;
+
+ // grab the entity list [ req-hdr=0, null-body=170 ]
+ list_data = util::split( util::trim( header_value ), "," );
+
+ for ( size_t i = 0; i < list_data.size(); i++ ) {
+
+ // get entity data [ req-hdr=0 ]
+ entity_data = util::split( util::trim( list_data.at( i ) ), "=" );
+
+ if ( entity_data.size() == 2 ) {
+
+ idx = _encapsulated.find( util::trim( entity_data.at( 0 ) ) );
+ if ( idx != _encapsulated.end() ) {
+ idx->second = atoi( util::trim( entity_data.at( 1 ) ).c_str() );
+ }
+
+ } else {
+ r_status = false;
+ }
+ }
+
+ return r_status;
+
+ }
+
+
+ bool Header::remove( std::string key ) throw() {
+ return ( (bool) _headers.erase( util::trim( key ) ) );
+ }
+
+
+ const std::string Header::encapsulated_header_str() throw() {
+
+ /*
+ * Encapsulated request header grammer:
+ * REQMOD request encapsulated_list: [reqhdr] reqbody
+ * REQMOD response encapsulated_list: {[reqhdr] reqbody} |
+ * {[reshdr] resbody}
+ * RESPMOD request encapsulated_list: [reqhdr] [reshdr] resbody
+ * RESPMOD response encapsulated_list: [reshdr] resbody
+ * OPTIONS response encapsulated_list: optbody
+ */
+
+ Header::encapsulated_header_index_t idx;
+ std::string encaps_header = "";
+
+ // FIXME: chances are that we will always get the correct order
+ // but should consider sorting
+ for ( idx = _encapsulated.begin(); idx != _encapsulated.end(); idx++ ) {
+
+ if ( idx->second > 0 ) {
+
+ if ( encaps_header != "" ) {
+ encaps_header.append( ", " );
+ }
+
+ encaps_header.append( idx->first ).append( "=" ).append( util::itoa( idx->second ) );
+
+ }
+
+ }
+
+ // sanity check
+ if ( encaps_header == "" ) {
+ encaps_header = "null-body=0";
+ }
+
+ return encaps_header;
+
+ }
+
+
+ void Header::update_encapsulated( const payload_t &payload ) throw() {
+
+ unsigned int data_length = 0;
+ unsigned int data_offset = 0;
+
+ // request header
+ if ( payload.req_header.size() > 0 ) {
+ _encapsulated["req-hdr"] = data_length;
+ data_offset = data_length;
+ data_length += payload.req_header.size();
+ }
+
+ // request body (POST data)
+ if ( payload.req_body.size() > 0 ) {
+ _encapsulated["req-body"] = data_length;
+ data_offset = data_length;
+ data_length += payload.req_body.size();
+ }
+
+ // response header
+ if ( payload.res_header.size() > 0 ) {
+ _encapsulated["res-hdr"] = data_length;
+ data_offset = data_length;
+ data_length += payload.res_header.size();
+ }
+
+ // response body
+ if ( payload.res_body.size() > 0 ) {
+ _encapsulated["res-body"] = data_length;
+ data_offset = data_length;
+ data_length += payload.res_body.size();
+ }
+
+ // null-body
+ if ( data_offset == 0 ) {
+ _encapsulated["null-body"] = data_length;
+ }
+
+ }
+
+
+ std::vector<Header::encapsulated_header_data_t> Header::sort_encapsulated_header() {
+
+ std::vector<Header::encapsulated_header_data_t> data( _encapsulated.begin(), _encapsulated.end() );
+ std::sort(data.begin(), data.end(), encapsulated_header_compare());
+
+ return data;
+
+ }
+
+}
+
diff --git a/lib/icap/header.h b/lib/icap/header.h
new file mode 100644
index 0000000..52a8fef
--- /dev/null
+++ b/lib/icap/header.h
@@ -0,0 +1,168 @@
+/*
+ * C++ ICAP library
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef ICAP_HEADER_H
+#define ICAP_HEADER_H
+
+#include "common.h"
+
+#include <string>
+#include <map>
+#include <vector>
+#include <functional>
+
+
+namespace icap {
+
+ class Header {
+ public:
+
+ /* headers data type */
+ typedef std::map<std::string, std::string> headers_t;
+
+ /* headers iterator type */
+ typedef headers_t::iterator headers_index_t;
+
+ /* encapsulated header type */
+ typedef std::map<std::string, int> encapsulated_header_t;
+
+ /* encapsulated header iterator type */
+ typedef encapsulated_header_t::iterator encapsulated_header_index_t;
+
+ /* encapsulated header data type */
+ typedef std::pair<std::string, int> encapsulated_header_data_t;
+
+ /**
+ * Binary compare structure to compare two encapsulated header
+ * entity (data) values. Used for sorting.
+ */
+ struct encapsulated_header_compare
+ : std::binary_function<icap::Header::encapsulated_header_data_t, icap::Header::encapsulated_header_data_t, bool> {
+ inline bool operator()( const icap::Header::encapsulated_header_data_t &lhs, const icap::Header::encapsulated_header_data_t &rhs ) {
+ return lhs.second < rhs.second;
+ }
+ };
+
+
+ Header();
+ virtual ~Header();
+
+ /**
+ * Return headers
+ * @return headers
+ */
+ const headers_t &headers() const throw();
+
+ /**
+ * Returns the header value for the given header key or an empty string
+ * if the header is not found.
+ *
+ * @param key header key
+ * @return header value
+ */
+ const std::string value( const std::string &key ) throw();
+
+ /**
+ * Return Encapsulated header value for the given entity
+ * or -1 if the given entity is invalid.
+ *
+ * @param entity encapsulated header entity
+ * @return -1 | encapsulated header value
+ */
+ const int encapsulated_header( const std::string &entity ) throw();
+
+ /**
+ * Attach header data into the header
+ *
+ * <pre>
+ * e.g.
+ * Host: icap-server.net
+ * Encapsulated: req-hdr=0, null-body=170
+ * [key]: [value]
+ * </pre>
+ *
+ * @param key header key
+ * @param value header value
+ */
+ virtual void attach( std::string key, std::string value ) throw();
+
+ /**
+ * Attach Encapsulated header data. This method should only be used
+ * when reading a raw request / response. Consider using update_encapsulated()
+ * method for other scenarios.
+ *
+ * <pre>
+ * e.g.
+ * Encapsulated: req-hdr=0, req-body=412
+ * Encapsulated: req-hdr=0, res-hdr=822, res-body=1655
+ * Encapsulated: [header_value]
+ * </pre>
+ *
+ * @param header_value Encapsulated header value
+ * @return boolean to denote success or failure
+ */
+ virtual bool attach_encapsulated( std::string header_value ) throw();
+
+
+ /**
+ * Update Encapsulated header data using the passed in (icap::payload_t) payload.
+ * When the request / response has been populated with the payload, calling this
+ * method will update the encapsulated header entities with appropriate values.
+ *
+ * This methos will always succeed.
+ *
+ * @param payload request or response payload
+ */
+ virtual void update_encapsulated( const payload_t &payload ) throw();
+
+ /**
+ * Remove header data from the header instance with the given key
+ *
+ * @param key header key
+ * @return boolean to denote success or failure
+ */
+ virtual bool remove( std::string key ) throw();
+
+ /**
+ * Return Encapsulated header as a std::string value.
+ * @return encapsulated header value (e.g. res-hdr=0, res-body=213)
+ */
+ virtual const std::string encapsulated_header_str() throw();
+
+ /**
+ * Sort the encapsulated header data and return a std::vector of
+ * encapsulated_header_data_t. The actual header data won't be changed.
+ *
+ * @return sorted encapsulated header
+ */
+ virtual std::vector<encapsulated_header_data_t> sort_encapsulated_header();
+
+
+ protected:
+ headers_t _headers;
+ encapsulated_header_t _encapsulated;
+
+ private:
+
+ };
+
+} /* end of namespace icap */
+
+#endif /* !ICAP_HEADER_H */
+
diff --git a/lib/icap/request.cpp b/lib/icap/request.cpp
new file mode 100644
index 0000000..bf80e13
--- /dev/null
+++ b/lib/icap/request.cpp
@@ -0,0 +1,84 @@
+/*
+ * C++ ICAP library
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "request.h"
+
+#include <cstdlib>
+
+
+namespace icap {
+
+ Request::Request( RequestHeader * req_header ) {
+
+ _header = req_header;
+
+ // initialise defaults
+ _payload.req_header = "";
+ _payload.req_body = "";
+ _payload.res_header = "";
+ _payload.res_body = "";
+ _payload.ieof = false;
+
+ }
+
+
+ Request::~Request() { }
+
+
+ RequestHeader * const Request::header() const throw() {
+ return _header;
+ }
+
+
+ void Request::payload( payload_t payload ) throw() {
+
+ _payload = payload;
+
+ // update encapsulated data
+ _header->update_encapsulated( _payload );
+
+ }
+
+
+ const payload_t &Request::payload() const throw() {
+ return _payload;
+ }
+
+
+ const int Request::preview_size() throw() {
+
+ int size = -1;
+
+ // grab the size from request header
+ std::string s_size = _header->value( "Preview" );
+
+ // sanity check
+ if (! s_size.empty() ) {
+
+ // convert string to integer
+ size = atoi( s_size.c_str() );
+
+ }
+
+ return size;
+
+ }
+
+} /* end of namespace icap */
+
diff --git a/lib/icap/request.h b/lib/icap/request.h
new file mode 100644
index 0000000..d5c4f69
--- /dev/null
+++ b/lib/icap/request.h
@@ -0,0 +1,72 @@
+/*
+ * C++ ICAP library
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef ICAP_REQUEST_H
+#define ICAP_REQUEST_H
+
+#include "common.h"
+#include "request_header.h"
+
+
+namespace icap {
+
+ class Request {
+ public:
+ Request( RequestHeader * req_header );
+ virtual ~Request();
+
+ /**
+ * Return the request header
+ * @return request header
+ */
+ RequestHeader * const header() const throw();
+
+ /**
+ * Set the payload data for this response instance from a
+ * icap::payload_t data structure
+ *
+ * @param payload payload data structure
+ */
+ void payload( payload_t payload ) throw();
+
+ /**
+ * Return the payload data for this response instance
+ * @return payload data
+ */
+ const payload_t &payload() const throw();
+
+ /**
+ * Returns the number of preview bytes in the request. If the preview
+ * header is not present in the request then a minus (-1) value will be
+ * returned.
+ *
+ * @return preview bytes
+ */
+ const int preview_size() throw();
+
+ private:
+ RequestHeader * _header;
+ payload_t _payload;
+
+ };
+
+} /* end of namespace icap */
+
+#endif /* !ICAP_REQUEST_H */
+
diff --git a/lib/icap/request_header.cpp b/lib/icap/request_header.cpp
new file mode 100644
index 0000000..a9b42dc
--- /dev/null
+++ b/lib/icap/request_header.cpp
@@ -0,0 +1,113 @@
+/*
+ * C++ ICAP library
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "request_header.h"
+#include "util.h"
+
+
+namespace icap {
+
+ /*
+ * sample icap request header:
+ * REQMOD icap://icap-server.net/server?arg=87 ICAP/1.0
+ * Host: icap-server.net
+ * Encapsulated: req-hdr=0, null-body=170
+ *
+ * [payload]
+ */
+ RequestHeader::RequestHeader( const std::string &raw_data ) : Header() {
+
+ // initialise defaults
+ _request.method = "";
+ _request.uri = "";
+ _request.protocol = "ICAP/1.0";
+
+ // read header
+ read_header( raw_data );
+
+ }
+
+
+ RequestHeader::~RequestHeader() { }
+
+
+ const std::string &RequestHeader::method() const throw() {
+ return _request.method;
+ }
+
+
+ const std::string &RequestHeader::uri() const throw() {
+ return _request.uri;
+ }
+
+
+ const std::string &RequestHeader::protocol() const throw() {
+ return _request.protocol;
+ }
+
+
+ const RequestHeader::request_t &RequestHeader::request() const throw() {
+ return _request;
+ }
+
+
+ const std::string &RequestHeader::raw_data() const throw() {
+ return _raw_data;
+ }
+
+
+ void RequestHeader::read_header( const std::string &raw_data ) throw() {
+
+ std::vector<std::string> data;
+
+ _raw_data = raw_data;
+ data = util::split( raw_data, "\r\n" );
+
+ if ( data.size() > 0 ) {
+
+ std::vector<std::string> header_data;
+ std::vector<std::string> request;
+
+ std::string request_data = data.at( 0 );
+ request = util::split( util::trim( request_data ) );
+
+ if ( request.size() == 3 ) {
+ _request.method = request.at(0);
+ _request.uri = request.at(1);
+ _request.protocol = request.at(2);
+ } else {
+ // TODO: error, invalid request format
+ }
+
+ for ( int i = 1; i < data.size(); i++ ) {
+ header_data = util::split( data.at( i ), ":" );
+
+ if ( header_data.size() == 2 ) {
+ this->attach( header_data.at( 0 ), header_data.at( 1 ) );
+ } else {
+ // TODO: error parsing header data
+ }
+ }
+
+ }
+
+ }
+
+} /* end of namespace icap */
+
diff --git a/lib/icap/request_header.h b/lib/icap/request_header.h
new file mode 100644
index 0000000..47978c1
--- /dev/null
+++ b/lib/icap/request_header.h
@@ -0,0 +1,84 @@
+/*
+ * C++ ICAP library
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef ICAP_REQUEST_HEADER_H
+#define ICAP_REQUEST_HEADER_H
+
+#include "header.h"
+
+#include <string>
+#include <vector>
+
+
+namespace icap {
+
+ class RequestHeader : public Header {
+ public:
+
+ struct request_t {
+ std::string method;
+ std::string uri;
+ std::string protocol;
+ };
+
+ RequestHeader( const std::string &raw_data );
+ virtual ~RequestHeader();
+
+ /**
+ * Return request method
+ * @return method
+ */
+ const std::string &method() const throw();
+
+ /**
+ * Return request URI
+ * @return URI
+ */
+ const std::string &uri() const throw();
+
+ /**
+ * Return request protocol
+ * @return protocol
+ */
+ const std::string &protocol() const throw();
+
+ /**
+ * Return request
+ * @return request
+ */
+ const request_t &request() const throw();
+
+ /**
+ * Return raw header data
+ * @return raw request header
+ */
+ const std::string &raw_data() const throw();
+
+ private:
+ request_t _request;
+ std::string _raw_data;
+
+ void read_header( const std::string &raw_data ) throw();
+
+ };
+
+} /* end of namespace icap */
+
+#endif /* !ICAP_REQUEST_HEADER_H */
+
diff --git a/lib/icap/response.cpp b/lib/icap/response.cpp
new file mode 100644
index 0000000..6bd730f
--- /dev/null
+++ b/lib/icap/response.cpp
@@ -0,0 +1,81 @@
+/*
+ * C++ ICAP library
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "response.h"
+
+
+namespace icap {
+
+ Response::Response( ResponseHeader * header ) {
+
+ if ( header != NULL ) {
+ _header = header;
+ _cleanup_header = false;
+ } else {
+ _header = new ResponseHeader( ResponseHeader::SERVER_ERROR );
+ _cleanup_header = true;
+ }
+
+ // initialise defaults
+ _payload.req_header = "";
+ _payload.req_body = "";
+ _payload.res_header = "";
+ _payload.res_body = "";
+ _payload.ieof = false;
+
+ }
+
+
+ Response::Response( ResponseHeader::status_t status ) {
+ _header = new ResponseHeader( status );
+ _cleanup_header = true;
+ }
+
+
+ Response::~Response() {
+
+ // cleanup
+ if ( _cleanup_header ) {
+ delete _header;
+ }
+
+ }
+
+
+ ResponseHeader * const Response::header() const throw() {
+ return _header;
+ }
+
+
+ void Response::payload( payload_t payload ) throw() {
+
+ _payload = payload;
+
+ // update encapsulated data
+ _header->update_encapsulated( _payload );
+
+ }
+
+
+ const payload_t &Response::payload() const throw() {
+ return _payload;
+ }
+
+} /* end of namespace icap */
+
diff --git a/lib/icap/response.h b/lib/icap/response.h
new file mode 100644
index 0000000..2977c07
--- /dev/null
+++ b/lib/icap/response.h
@@ -0,0 +1,65 @@
+/*
+ * C++ ICAP library
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef ICAP_RESPONSE_H
+#define ICAP_RESPONSE_H
+
+#include "common.h"
+#include "response_header.h"
+
+
+namespace icap {
+
+ class Response {
+ public:
+ Response( ResponseHeader * response_header = NULL );
+ Response( ResponseHeader::status_t status );
+ virtual ~Response();
+
+ /**
+ * Return the response header
+ * @return response header
+ */
+ ResponseHeader * const header() const throw();
+
+ /**
+ * Set the payload data for this response instance from a
+ * icap::payload_t data structure
+ *
+ * @param payload payload data structure
+ */
+ void payload( payload_t payload ) throw();
+
+ /**
+ * Return the payload data for this response instance
+ * @return payload data
+ */
+ const payload_t &payload() const throw();
+
+ private:
+ ResponseHeader * _header;
+ payload_t _payload;
+ bool _cleanup_header;
+
+ };
+
+} /* end of namespace icap */
+
+#endif /* !ICAP_RESPONSE_H */
+
diff --git a/lib/icap/response_header.cpp b/lib/icap/response_header.cpp
new file mode 100644
index 0000000..aa29e63
--- /dev/null
+++ b/lib/icap/response_header.cpp
@@ -0,0 +1,101 @@
+/*
+ * C++ ICAP library
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "response_header.h"
+#include "util.h"
+#include <config.h>
+
+#include <ctime>
+#include <stdlib.h>
+
+
+namespace icap {
+
+ ResponseHeader::ResponseHeader( status_t status ) : Header() {
+
+ // FIXME: protocol shouldn't be hard-coded
+ _response.protocol = "ICAP/1.0";
+ _response.status = status;
+
+ // initialise default headers
+ init_defaults();
+
+ }
+
+ ResponseHeader::~ResponseHeader() { }
+
+
+ const std::string &ResponseHeader::protocol() const throw() {
+ return _response.protocol;
+ }
+
+
+ const ResponseHeader::status_t &ResponseHeader::status() const throw() {
+ return _response.status;
+ }
+
+
+ void ResponseHeader::init_defaults() throw() {
+
+ update_timestamp();
+ generate_istag();
+ attach( "Server", PACKAGE_STRING );
+
+ // close connection header
+ if ( _response.status != ResponseHeader::CONTINUE ) {
+ attach( "Connection" , "close" );
+ }
+
+ }
+
+
+ void ResponseHeader::update_timestamp() throw() {
+
+ time_t raw_time;
+ struct tm * time_info;
+ char buffer [80];
+
+ time( &raw_time );
+ time_info = localtime( &raw_time );
+
+ strftime ( buffer, 80, "%c %Z", time_info );
+ attach( "Date", buffer );
+
+ }
+
+
+ void ResponseHeader::generate_istag() throw() {
+
+ time_t raw_time;
+ clock_t clock_time;
+ std::string istag;
+
+ time( &raw_time );
+ clock_time = clock();
+
+ istag = "BITZ-";
+ istag.append( util::itoa( raw_time ) ).append( "-" );
+ istag.append( util::itoa( clock_time) );
+
+ attach( "ISTag", istag.substr( 0, 32 ) );
+
+ }
+
+} /* end of namespace icap */
+
diff --git a/lib/icap/response_header.h b/lib/icap/response_header.h
new file mode 100644
index 0000000..48d9ddd
--- /dev/null
+++ b/lib/icap/response_header.h
@@ -0,0 +1,78 @@
+/*
+ * C++ ICAP library
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef ICAP_RESPONSE_HEADER_H
+#define ICAP_RESPONSE_HEADER_H
+
+#include "header.h"
+
+
+namespace icap {
+
+ class ResponseHeader : public Header {
+ public:
+
+ enum status_t {
+ CONTINUE = 100,
+ OK = 200,
+ NO_CONTENT = 204,
+ BAD_REQUEST = 400,
+ NOT_FOUND = 404,
+ NOT_ALLOWED = 405,
+ REQ_TIMEOUT = 408,
+ SERVER_ERROR = 500,
+ NOT_IMPLEMENTED = 501,
+ BAD_GATEWAY = 502,
+ SERVICE_OVERLOADED = 503,
+ NOT_SUPPORTED = 505
+ };
+
+ struct response_t {
+ std::string protocol;
+ status_t status;
+ };
+
+ ResponseHeader( status_t status );
+ virtual ~ResponseHeader();
+
+ /**
+ * Return the response protocol
+ * @return protocol
+ */
+ const std::string &protocol() const throw();
+
+ /**
+ * Return the response status
+ * @return status
+ */
+ const status_t &status() const throw();
+
+ private:
+ response_t _response;
+
+ void update_timestamp() throw();
+ void generate_istag() throw();
+ void init_defaults() throw();
+
+ };
+
+} /* end of namespace icap */
+
+#endif /* !ICAP_RESPONSE_HEADER_H */
+
diff --git a/lib/icap/util.cpp b/lib/icap/util.cpp
new file mode 100644
index 0000000..c383261
--- /dev/null
+++ b/lib/icap/util.cpp
@@ -0,0 +1,693 @@
+/*
+ * C++ ICAP library
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "util.h"
+
+#include <string>
+#include <algorithm>
+#include <locale>
+#include <iostream>
+
+
+namespace icap {
+
+ namespace util {
+
+ unsigned int hextodec( const std::string &hex ) throw() {
+
+ unsigned int dec;
+ std::stringstream ss;
+
+ ss << std::hex << hex;
+ ss >> dec;
+
+ return dec;
+
+ }
+
+
+ const std::string dectohex( const unsigned int &dec ) throw() {
+
+ std::string hex;
+ std::stringstream ss;
+
+ ss << std::hex << dec;
+ ss >> hex;
+
+ return hex;
+
+ }
+
+
+ int read_line( socketlibrary::TCPSocket * socket, char * buf, int buf_length, bool incl_endl ) throw() {
+
+ int i = 0, n;
+ char c = '\0';
+
+ while ( i < ( buf_length - 1 ) ) {
+
+ n = socket->recv( &c, 1 );
+
+ if ( n > 0 ) {
+ if ( c == '\r' ) {
+
+ if ( incl_endl ) {
+ buf[i] = c;
+ i++;
+ }
+
+ // peak for \n
+ n = socket->peek( &c, 1 );
+
+ if ( ( n > 0 ) && ( c == '\n' ) ) {
+
+ n = socket->recv( &c, 1 );
+
+ if ( incl_endl ) {
+ buf[i] = c;
+ i++;
+ }
+
+ break; // end of line
+ }
+ }
+
+ buf[i] = c;
+ i++;
+ } else {
+ break; // nothing read from socket
+ }
+
+ }
+
+ buf[i] = '\0';
+ return i;
+
+ }
+
+
+ std::string read_line( socketlibrary::TCPSocket * socket, bool incl_endl ) throw() {
+
+ int n;
+ std::string line;
+ char c = '\0';
+
+ try {
+
+ while ( ( n = socket->recv( &c, 1 ) ) > 0 ) {
+
+ if ( c == '\r' ) {
+
+ if ( incl_endl ) {
+ line += c;
+ }
+
+ // peak for \n
+ n = socket->peek( &c, 1 );
+
+ if ( ( n > 0 ) && ( c == '\n' ) ) {
+
+ n = socket->recv( &c, 1 );
+
+ if ( incl_endl ) {
+ line += c;
+ }
+
+ break; // end of line
+ }
+ }
+
+ line += c;
+
+ }
+
+ } catch ( socketlibrary::SocketException &sex ) {
+ // TODO: log error?
+ line = "";
+ }
+
+ return line;
+
+ }
+
+
+ std::string read_data( socketlibrary::TCPSocket * socket, int size ) throw() {
+
+ char buffer[ICAP_BUFFER_SIZE];
+ std::string data = "";
+ int n;
+
+ // loop until we have read all the bytes
+ while ( size > 0 ) {
+
+ try {
+
+ // read from socket
+ n = socket->recv( buffer, min( size, ICAP_BUFFER_SIZE ) );
+
+ // sanity check
+ if ( n == 0 ) {
+ break;
+ }
+
+ // append to data
+ data.append( buffer, n );
+
+ // update size with remaining bytes
+ size -= n;
+
+ } catch ( socketlibrary::SocketException &sex ) {
+ // TODO: log errors ??
+ }
+
+ }
+
+ return data;
+
+ }
+
+
+ unsigned int read_chunk_size( socketlibrary::TCPSocket * socket ) throw() {
+
+ std::string line;
+ std::vector<std::string> chunk_header;
+
+ line = read_line( socket );
+ chunk_header = split( line, ";" );
+
+ return hextodec( chunk_header.at( 0 ) );
+
+ }
+
+
+ void read_chunk_header( socketlibrary::TCPSocket * socket, chunk_t &chunk ) throw() {
+
+ std::string line;
+ std::vector<std::string> chunk_header;
+
+ line = read_line( socket );
+ chunk_header = split( line, ";" );
+
+ // sanity check
+ if ( chunk_header.size() > 0 ) {
+
+ // sanity check
+ if ( chunk_header.at( 0 ).size() > 0 ) {
+ chunk.size = hextodec( chunk_header.at( 0 ) );
+ }
+
+ // check for chunk-extension
+ if ( chunk_header.size() == 2 ) {
+ chunk.extention = trim( chunk_header.at( 1 ) );
+ }
+ }
+
+ return;
+
+ }
+
+
+ chunk_t read_chunk( socketlibrary::TCPSocket * socket ) throw() {
+
+ chunk_t chunk;
+ std::string line;
+ std::vector<std::string> chunk_header;
+
+ // initialise chunk
+ chunk.size = 0;
+ chunk.extention = "";
+ chunk.data = "";
+
+ // read chunk header
+ read_chunk_header( socket, chunk );
+
+ // read chunk data
+ if ( chunk.size > 0 ) {
+ chunk.data = read_data( socket, chunk.size );
+ }
+
+ // read \r\n ending for the chunk
+ read_data( socket, 2 );
+
+ return chunk;
+
+ }
+
+
+ std::string read_chunked( socketlibrary::TCPSocket * socket ) throw() {
+
+ unsigned int chunk_size = 0;
+ unsigned int offset = 0;
+ std::string chunked_data = "";
+
+ while ( ( chunk_size = read_chunk_size( socket ) ) > 0 ) {
+
+ offset = chunked_data.size();
+
+ // read chunk-data
+ chunked_data.append( read_data( socket, chunk_size ) );
+
+ // sanity check
+ if ( ( chunked_data.size() - offset ) != chunk_size ) {
+ // something went wrong
+ break;
+ }
+
+ // extra \r\n
+ read_data( socket, 2 );
+
+ }
+
+ // read until the end of chunked data
+ while ( read_line( socket, true ).size() > 2 ) ;
+
+ return chunked_data;
+
+ }
+
+
+ bool read_chunked_payload( socketlibrary::TCPSocket * socket, std::string &payload ) throw() {
+
+ chunk_t chunk;
+ bool ieof = false;
+
+ do {
+
+ // read chunk
+ chunk = read_chunk( socket );
+
+ // append to payload
+ payload.append( chunk.data );
+
+ // sanity check
+ if ( chunk.data.size() != chunk.size ) {
+ // something went wrong
+ break;
+ }
+
+ } while( chunk.size > 0 );
+
+ // check for ieof
+ if ( chunk.extention == "ieof" ) {
+ ieof = true;
+ }
+
+ return ieof;
+
+ }
+
+
+ bool send_line( const std::string &line, socketlibrary::TCPSocket * socket ) throw() {
+
+ try {
+ socket->send( line.c_str(), line.length() );
+ socket->send( "\r\n", 2 );
+ } catch ( socketlibrary::SocketException &sex ) {
+ // TODO: log errors
+ return false;
+ }
+
+ return true;
+
+ }
+
+
+ bool send_data( const std::string &data, socketlibrary::TCPSocket * socket ) throw() {
+
+ try {
+ socket->send( data.c_str(), data.size() );
+ } catch( socketlibrary::SocketException &sex ) {
+ // TODO: log errors
+ return false;
+ }
+
+ return true;
+
+ }
+
+
+ bool send_chunked( const std::string &data, socketlibrary::TCPSocket * socket ) throw() {
+
+ std::string chunked_data = "";
+ unsigned int offset = 0;
+ int chunks = 0;
+
+ // calculate the number of chunks we need
+ if ( data.size() > ICAP_BUFFER_SIZE ) {
+ chunks = ( data.size() / ICAP_BUFFER_SIZE );
+ }
+
+ try {
+
+ do {
+
+ // prepare data for this chunk
+ chunked_data = data.substr( offset, ICAP_BUFFER_SIZE );
+
+ // sanity check
+ if ( chunked_data.size() <= 0 ) {
+ // we shouldn't get here
+ break;
+ }
+
+ // update offset
+ offset += chunked_data.size();
+
+ // send chunk size
+ if (! send_line( dectohex( chunked_data.size() ), socket ) ) {
+ return false;
+ }
+
+ // send chunk
+ if (! send_data( chunked_data, socket ) ) {
+ return false;
+ }
+
+ chunks--;
+
+ } while ( chunks > 0 );
+
+ // end of chunk
+ if (! send_data( "\r\n0\r\n\r\n", socket ) ) {
+ return false;
+ }
+
+ } catch ( socketlibrary::SocketException &sex ) {
+ // TODO: log errors ??
+ return false;
+ }
+
+ return true;
+
+ }
+
+
+ std::vector<std::string> split( const std::string &str, const std::string &delimiter ) throw() {
+
+ std::vector<std::string> result;
+ size_t current;
+ size_t next = -1;
+
+ do {
+ current = next + 1;
+ next = str.find_first_of( delimiter, current );
+ result.push_back( str.substr( current, ( next - current ) ) );
+ } while ( next != std::string::npos );
+
+ return result;
+
+ }
+
+
+ std::string &ltrim( std::string &str ) throw() {
+ str.erase( str.begin(), std::find_if( str.begin(), str.end(), std::not1( std::ptr_fun<int, int>( std::isspace ) ) ) );
+ return str;
+ }
+
+
+ std::string &rtrim( std::string &str ) throw() {
+ str.erase( std::find_if( str.rbegin(), str.rend(), std::not1( std::ptr_fun<int, int>( std::isspace ) ) ).base(), str.end() );
+ return str;
+ }
+
+
+ std::string &trim( std::string &str ) throw() {
+ return ltrim( rtrim( str ) );
+ }
+
+
+ icap::RequestHeader * read_req_header( socketlibrary::TCPSocket * socket ) throw() {
+
+ char buffer[ICAP_BUFFER_SIZE];
+ int n = 0;
+ std::string data = "";
+
+ while ( ( n = read_line( socket, buffer, ICAP_BUFFER_SIZE, true ) ) > 2 ) {
+ data.append( buffer );
+ }
+
+ icap::RequestHeader * req_header = new icap::RequestHeader( data );
+ return req_header;
+
+ }
+
+
+ bool read_req_data( icap::Request * request, socketlibrary::TCPSocket * socket ) throw() {
+
+ int data_offset = 0;
+ int data_length = 0;
+ int data_read = 0;
+ std::vector<icap::Header::encapsulated_header_data_t> sorted_encaps_header;
+ std::vector<icap::Header::encapsulated_header_data_t>::iterator sorted_idx;
+
+ // payload
+ icap::payload_t payload;
+ payload.req_header = "";
+ payload.req_body = "";
+ payload.res_header = "";
+ payload.res_body = "";
+ payload.ieof = false;
+
+ // header
+ icap::Header * header = request->header();
+ sorted_encaps_header = header->sort_encapsulated_header();
+
+ // loop through the sorted header
+ for ( sorted_idx = sorted_encaps_header.begin(); sorted_idx != sorted_encaps_header.end(); sorted_idx++ ) {
+
+ // don't want to read negative headers
+ if ( sorted_idx->second < 0 ) {
+ continue;
+ }
+
+ // if this is the last header entity then check for chunked content
+ if ( sorted_idx == ( sorted_encaps_header.end() - 1 ) ) {
+
+ if ( sorted_idx->first == "req-body" ) {
+ payload.ieof = read_chunked_payload( socket, payload.req_body );
+ } else if ( sorted_idx->first == "res-body" ) {
+ payload.ieof = read_chunked_payload( socket, payload.res_body );
+ } else {
+ /*
+ * null-body is the only other legal possibility here
+ * we take that into account in the previous iterations
+ */
+ break;
+ }
+
+ } else {
+
+ data_offset = sorted_idx->second;
+ data_length = ( ( sorted_idx + 1 )->second - data_offset );
+
+
+ /* read request data */
+
+ // is there anything to read?
+ if ( data_length > 0 ) {
+
+ // update payload
+ if ( sorted_idx->first == "req-hdr" ) {
+ payload.req_header = read_data( socket, data_length );
+ } else if ( sorted_idx->first == "req-body" ) {
+ payload.req_body = read_data( socket, data_length );
+ } else if ( sorted_idx->first == "res-hdr" ) {
+ payload.res_header = read_data( socket, data_length );
+ } else if ( sorted_idx->first == "res-body" ) {
+ payload.res_body = read_data( socket, data_length );
+ } else {
+ // TODO: error?
+ }
+
+ }
+
+ }
+
+ }
+
+ // update request
+ request->payload( payload );
+
+ return true;
+
+ }
+
+
+ bool read_req_continue_data( icap::Request * request, socketlibrary::TCPSocket * socket ) throw() {
+
+ std::vector<icap::Header::encapsulated_header_data_t> sorted_encaps_header;
+ icap::Header::encapsulated_header_data_t header_idx;
+
+ // copy the payload from request so we can append to it
+ icap::payload_t payload;
+ payload.req_header = request->payload().req_header;
+ payload.req_body = request->payload().req_body;
+ payload.res_header = request->payload().res_header;
+ payload.res_body = request->payload().res_body;
+ payload.ieof = request->payload().ieof;
+
+ // header
+ icap::Header * header = request->header();
+ sorted_encaps_header = header->sort_encapsulated_header();
+
+ // sanity check
+ if ( sorted_encaps_header.size() > 0 ) {
+
+ // we are only interested in the last header entity
+ header_idx = sorted_encaps_header.back();
+
+ // read payload data
+ if ( header_idx.first == "req-body" ) {
+ payload.ieof = read_chunked_payload( socket, payload.req_body );
+ } else if ( header_idx.first == "res-body" ) {
+ payload.ieof = read_chunked_payload( socket, payload.res_body );
+ }
+
+ } else {
+
+ // something isn't quite right
+ return false;
+
+ }
+
+ // update request
+ request->payload( payload );
+
+ return true;
+
+ }
+
+
+ bool send_headers( icap::Header * header, socketlibrary::TCPSocket * socket ) throw() {
+
+ std::string line;
+ icap::Header::headers_index_t i;
+ icap::ResponseHeader::headers_t headers;
+
+ // headers
+ headers = header->headers();
+
+ for ( i = headers.begin(); i != headers.end(); i++ ) {
+
+ line = i->first;
+ line.append( ": " );
+ line.append( i->second );
+
+ if (! send_line( line, socket ) ) {
+ return false;
+ }
+
+ }
+
+ // send encapsulated header
+ line = "Encapsulated: ";
+ line.append( header->encapsulated_header_str() );
+ if (! send_line( line, socket ) ) {
+ return false;
+ }
+
+ // end of header
+ if (! send_data( "\r\n", socket ) ) {
+ return false;
+ }
+
+ return true;
+
+ }
+
+
+ bool send_response( icap::Response * response, socketlibrary::TCPSocket * socket ) throw() {
+
+ bool r_success = true;
+
+ icap::ResponseHeader * header;
+
+ // grab the response header
+ header = response->header();
+
+ // response status
+ std::string line = header->protocol();
+ line.append( " " );
+ line.append( itoa( header->status() ) );
+ line.append( " " );
+ line.append( response_status( header->status() ) );
+
+ r_success = send_line( line, socket );
+
+ // response headers
+ if ( r_success ) {
+ r_success = send_headers( header, socket );
+ }
+
+ // response content (if there are any)
+ if ( r_success ) {
+
+ // req-hdr
+ if ( response->payload().req_header.size() > 0 ) {
+ send_data( response->payload().req_header, socket );
+ }
+
+ // red-body
+ if ( response->payload().req_body.size() > 0 ) {
+ send_chunked( response->payload().req_body, socket );
+ }
+
+ // res-hdr
+ if ( response->payload().res_header.size() > 0 ) {
+ send_data( response->payload().res_header, socket );
+ }
+
+ // res-body
+ if ( response->payload().res_body.size() > 0 ) {
+ send_chunked( response->payload().res_body, socket );
+ }
+
+ }
+
+ return r_success;
+
+ }
+
+
+ const std::string response_status( const ResponseHeader::status_t &status ) throw() {
+
+ // FIXME: probably there's a better way of mapping this
+ std::map<ResponseHeader::status_t, std::string> status_text;
+
+ status_text[ResponseHeader::CONTINUE] = "Continue";
+ status_text[ResponseHeader::OK] = "OK";
+ status_text[ResponseHeader::NO_CONTENT] = "No modifications needed";
+ status_text[ResponseHeader::BAD_REQUEST] = "Bad request";
+ status_text[ResponseHeader::NOT_FOUND] = "ICAP Service not found";
+ status_text[ResponseHeader::NOT_ALLOWED] = "Method not allowed for service";
+ status_text[ResponseHeader::REQ_TIMEOUT] = "Request timeout";
+ status_text[ResponseHeader::SERVER_ERROR] = "Server error";
+ status_text[ResponseHeader::NOT_IMPLEMENTED] = "Method not implemented";
+ status_text[ResponseHeader::BAD_GATEWAY] = "Bad gateway";
+ status_text[ResponseHeader::SERVICE_OVERLOADED] = "Service overloaded";
+ status_text[ResponseHeader::NOT_SUPPORTED] = "ICAP version not supported by server";
+
+ return status_text[status];
+
+ }
+
+ } /* end of namespace util */
+
+} /* end of namespace icap */
+
diff --git a/lib/icap/util.h b/lib/icap/util.h
new file mode 100644
index 0000000..366bb9c
--- /dev/null
+++ b/lib/icap/util.h
@@ -0,0 +1,265 @@
+/*
+ * C++ ICAP library
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef ICAP_UTIL_H
+#define ICAP_UTIL_H
+
+#include <sstream>
+
+#include <socket/socket.h>
+#include "request.h"
+#include "response.h"
+
+#ifndef ICAP_BUFFER_SIZE
+#define ICAP_BUFFER_SIZE 1024
+#endif
+
+
+namespace icap {
+
+ namespace util {
+
+ struct chunk_t {
+ unsigned int size;
+ std::string extention;
+ std::string data;
+ };
+
+ /**
+ * Convert a number into a string
+ *
+ * @param number number to be converted
+ * @return converted string
+ */
+ template <typename T> std::string itoa( T number ) {
+ std::ostringstream ss;
+ ss << number;
+
+ return ss.str();
+ }
+
+ /**
+ * Convert a hexadecimal number to a decimal number.
+ *
+ * @param hex hex to convert to
+ * @return converted decimal value
+ */
+ unsigned int hextodec( const std::string &hex ) throw();
+
+ /**
+ * Convert a decimal number to its hexadecimal value
+ *
+ * @param dec decimal number
+ * @return converted hex value
+ */
+ const std::string dectohex( const unsigned int &dec ) throw();
+
+ /**
+ * Read a line (ending with \r\n) from the socket
+ *
+ * @param socket socket to read from
+ * @param buf buffer to read the data into
+ * @param buf_length length / size of the buffer data is read into
+ * @param incl_endl (optional) switch to control whether to include \r\n in the read line,
+ * default is false.
+ * @return number of bytes read
+ */
+ int read_line( socketlibrary::TCPSocket * socket, char * buf, int buf_length, bool incl_endl = false ) throw();
+
+ /**
+ * Read a line (ending with \r\n) from the socket
+ *
+ * @param socket socket instance to read data from
+ * @param incl_endl (optional) switch to control whether to include \r\n in the read line,
+ * default is false.
+ * @return read data
+ */
+ std::string read_line( socketlibrary::TCPSocket * socket, bool incl_endl = false ) throw();
+
+ /**
+ * Read data from the socket
+ *
+ * @param socket socket instance to read data from
+ * @param size size / length of data to be read
+ * @return read data
+ */
+ std::string read_data( socketlibrary::TCPSocket * socket, int size ) throw();
+
+ /**
+ * Read chunk size. This is a helper method used by read_chunked().
+ *
+ * @param socket socket instance to read from
+ * @return chunk size
+ */
+ unsigned int read_chunk_size( socketlibrary::TCPSocket * socket ) throw();
+
+ /**
+ * Read chunk header from the given socket.
+ *
+ * @param socket socket instance to read data from
+ * @param chunk chunk data structure to store header data
+ */
+ void read_chunk_header( socketlibrary::TCPSocket * socket, chunk_t &chunk ) throw();
+
+ /**
+ * Read a data chunk from a HTTP chunked transfer encoded data stream.
+ *
+ * @param socket socket instance to read data from
+ * @return chunk data structure
+ */
+ chunk_t read_chunk( socketlibrary::TCPSocket * socket ) throw();
+
+ /**
+ * Read chunked data from the given socket
+ *
+ * @param socket socket instance to read data from
+ * @return read data (without the control characters)
+ */
+ std::string read_chunked( socketlibrary::TCPSocket * socket ) throw();
+
+ /**
+ * Read chunked payload data from the given socket
+ *
+ * @param socket socket instance to read data from
+ * @param payload payload to read data into
+ * @return boolean flag to denote the presence of "ieof"
+ */
+ bool read_chunked_payload( socketlibrary::TCPSocket * socket, std::string &payload ) throw();
+
+ /**
+ * Send / write a line (ending with \r\n) to the socket
+ *
+ * @param line line to send through the socket without the line-ending chars
+ * @param socket socket object to write the data to
+ * @return boolean to denote success or failure
+ */
+ bool send_line( const std::string &line, socketlibrary::TCPSocket * socket ) throw();
+
+ /**
+ * Send / write data to the socket.
+ * If chunked is set to true then data will be transferred using
+ * "chunked" transfer-encoding.
+ *
+ * @param data data to be sent
+ * @param socket socket instance to write to
+ * @return boolean to denote success or failure
+ */
+ bool send_data( const std::string &data, socketlibrary::TCPSocket * socket ) throw();
+
+ /**
+ * Send / write data to the socket using chunked transfer encoding
+ *
+ * @param data data to be sent
+ * @param socket socket instance to write to
+ * @return boolean to denote success or failure
+ */
+ bool send_chunked( const std::string &data, socketlibrary::TCPSocket * socket ) throw();
+
+ /**
+ * split a string into a vector by the given delimiter
+ *
+ * @param str input string
+ * @param delimiter (optional) delimiter, defaults to " "
+ */
+ std::vector<std::string> split( const std::string &str, const std::string &delimiter = " " ) throw();
+
+ /**
+ * Left trim (trim from start) a passed in string
+ *
+ * @param str string to trim
+ * @return trimmed string
+ */
+ std::string &ltrim( std::string &str ) throw();
+
+ /**
+ * Right trim (trim from end) a passed in string
+ *
+ * @param str string to trim
+ * @return trimmed string
+ */
+ std::string &rtrim( std::string &str ) throw();
+
+ /**
+ * Trim (trim from both ends) a passed in string
+ *
+ * @param str string to trim
+ * @return trimmed string
+ */
+ std::string &trim( std::string &str ) throw();
+
+ /**
+ * Read icap request header from the socket passes in
+ *
+ * @param socket socket object to read data from
+ * @return icap request header object
+ */
+ icap::RequestHeader * read_req_header( socketlibrary::TCPSocket * socket ) throw();
+
+ /**
+ * Read icap request into the icap::Request instance
+ * using the socket passed in
+ *
+ * @param request request object to read data into
+ * @param socket socket object to read data from
+ * @return boolean to denote success or failure
+ */
+ bool read_req_data( icap::Request * request, socketlibrary::TCPSocket * socket ) throw();
+
+ /**
+ * Read icap request data after a '100 Continue' response. This will not look for any
+ * additional headers and will treat any data coming through the socket as payload data.
+ *
+ * @param request request object to read data into
+ * @param socket socket object to read data from
+ * @return boolean to denote success or failure
+ */
+ bool read_req_continue_data( icap::Request * request, socketlibrary::TCPSocket * socket ) throw();
+
+ /**
+ * Send / write header data to a socket
+ *
+ * @param headers headers to be sent
+ * @param socket socket object to write the data to
+ * @return boolean to denote success or failure
+ */
+ bool send_headers( icap::Header::headers_t headers, socketlibrary::TCPSocket * socket ) throw();
+
+ /**
+ * Output a response using the passed in icap::Response class to the
+ * passed in socket
+ *
+ * @param response response object to get the response data from
+ * @param socket socket object to send the data to
+ * @return boolean to denote success or failure
+ */
+ bool send_response( icap::Response * response, socketlibrary::TCPSocket * socket ) throw();
+
+ /**
+ * Returns the response status text for the given status
+ *
+ * @param status status to get the text for
+ */
+ const std::string response_status( const ResponseHeader::status_t &status ) throw();
+
+ } /* end of namespace util */
+
+} /* end of namespace icap */
+
+#endif /* !ICAP_UTIL_H */
+
diff --git a/lib/socket/Makefile.am b/lib/socket/Makefile.am
new file mode 100644
index 0000000..93f98a5
--- /dev/null
+++ b/lib/socket/Makefile.am
@@ -0,0 +1,4 @@
+## [socket-library] lib/
+noinst_LTLIBRARIES = libsocket.la
+libsocket_la_SOURCES = socket.h socket.cpp
+
diff --git a/lib/socket/socket.cpp b/lib/socket/socket.cpp
new file mode 100644
index 0000000..a086d95
--- /dev/null
+++ b/lib/socket/socket.cpp
@@ -0,0 +1,472 @@
+/*
+ * C++ sockets on Unix and Windows
+ * Copyright (C) 2002 <unknown>
+ * Copyright (C) 2010 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include <socket.h>
+
+#ifndef WIN32
+ #include <sys/types.h> // For data types
+ #include <sys/socket.h> // For socket(), connect(), send(), and recv()
+ #include <netdb.h> // For gethostbyname()
+ #include <arpa/inet.h> // For inet_addr()
+ #include <unistd.h> // For close()
+#endif
+
+#include <cerrno> // For errno
+#include <cstring> // For strerror
+#include <cstdlib> // For atoi()
+
+using namespace std;
+
+namespace socketlibrary {
+
+#ifdef WIN32
+ static bool initialized = false;
+#endif
+
+// SocketException Code
+
+SocketException::SocketException(const string &message, bool inclSysMsg) throw() : userMessage(message) {
+ if (inclSysMsg) {
+ userMessage.append(": ");
+ userMessage.append(strerror(errno));
+ }
+}
+
+SocketException::~SocketException() throw() {
+}
+
+const char *SocketException::what() const throw() {
+ return userMessage.c_str();
+}
+
+// Function to fill in address structure given an address and port
+void fillAddr(const string &address, unsigned short port, sockaddr_in &addr) {
+
+ memset(&addr, 0, sizeof(addr)); // Zero out address structure
+ addr.sin_family = AF_INET; // Internet address
+
+ hostent *host; // Resolve name
+ if ((host = gethostbyname(address.c_str())) == NULL) {
+ // strerror() will not work for gethostbyname() and hstrerror()
+ // is supposedly obsolete
+ throw SocketException("Failed to resolve name (gethostbyname())");
+ }
+
+ addr.sin_addr.s_addr = *((unsigned long *) host->h_addr_list[0]);
+ addr.sin_port = htons(port); // Assign port in network byte order
+
+}
+
+// Socket Code
+
+Socket::Socket(int type, int protocol) throw(SocketException) {
+#ifdef WIN32
+ if (!initialized) {
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ wVersionRequested = MAKEWORD(2, 0); // Request WinSock v2.0
+ if (WSAStartup(wVersionRequested, &wsaData) != 0) { // Load WinSock DLL
+ throw SocketException("Unable to load WinSock DLL");
+ }
+ initialized = true;
+ }
+#endif
+
+ // Make a new socket
+ if ((sock = socket(PF_INET, type, protocol)) < 0) {
+ throw SocketException("Socket creation failed (socket())", true);
+ }
+}
+
+Socket::Socket(int sock) {
+ this->sock = sock;
+}
+
+Socket::~Socket() {
+
+#ifdef WIN32
+ ::closesocket(sock);
+#else
+ ::close(sock);
+#endif
+ sock = -1;
+}
+
+string Socket::getLocalAddress() throw(SocketException) {
+ sockaddr_in addr;
+ unsigned int addr_len = sizeof(addr);
+
+ if (getsockname(sock, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
+ throw SocketException("Fetch of local address failed (getsockname())", true);
+ }
+ return inet_ntoa(addr.sin_addr);
+}
+
+unsigned short Socket::getLocalPort() throw(SocketException) {
+ sockaddr_in addr;
+ unsigned int addr_len = sizeof(addr);
+
+ if (getsockname(sock, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
+ throw SocketException("Fetch of local port failed (getsockname())", true);
+ }
+ return ntohs(addr.sin_port);
+}
+
+void Socket::setLocalPort(unsigned short localPort) throw(SocketException) {
+ // Bind the socket to its port
+ sockaddr_in localAddr;
+ memset(&localAddr, 0, sizeof(localAddr));
+ localAddr.sin_family = AF_INET;
+ localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ localAddr.sin_port = htons(localPort);
+
+ if (bind(sock, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
+ throw SocketException("Set of local port failed (bind())", true);
+ }
+}
+
+void Socket::setLocalAddressAndPort(const string &localAddress, unsigned short localPort) throw(SocketException) {
+ // Get the address of the requested host
+ sockaddr_in localAddr;
+ fillAddr(localAddress, localPort, localAddr);
+
+ if (bind(sock, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
+ throw SocketException("Set of local address and port failed (bind())", true);
+ }
+}
+
+void Socket::cleanUp() throw(SocketException) {
+#ifdef WIN32
+ if (WSACleanup() != 0) {
+ throw SocketException("WSACleanup() failed");
+ }
+#endif
+}
+
+unsigned short Socket::resolveService(const string &service, const string &protocol) {
+
+ struct servent *serv; /* Structure containing service information */
+
+ if ((serv = getservbyname(service.c_str(), protocol.c_str())) == NULL)
+ return atoi(service.c_str()); /* Service is port number */
+ else
+ return ntohs(serv->s_port); /* Found port (network byte order) by name */
+
+}
+
+// CommunicatingSocket Code
+
+CommunicatingSocket::CommunicatingSocket(int type, int protocol) throw(SocketException) : Socket(type, protocol) {
+}
+
+CommunicatingSocket::CommunicatingSocket(int newSD) : Socket(newSD) {
+}
+
+void CommunicatingSocket::connect(const string &foreignAddress, unsigned short foreignPort) throw(SocketException) {
+ // Get the address of the requested host
+ sockaddr_in destAddr;
+ fillAddr(foreignAddress, foreignPort, destAddr);
+
+ // Try to connect to the given port
+ if (::connect(sock, (sockaddr *) &destAddr, sizeof(destAddr)) < 0) {
+ throw SocketException("Connect failed (connect())", true);
+ }
+}
+
+void CommunicatingSocket::send(const void *buffer, int bufferLen) throw(SocketException) {
+ if (::send(sock, (raw_type *) buffer, bufferLen, 0) < 0) {
+ throw SocketException("Send failed (send())", true);
+ }
+}
+
+int CommunicatingSocket::recv(void *buffer, int bufferLen) throw(SocketException) {
+ int rtn;
+ if ((rtn = ::recv(sock, (raw_type *) buffer, bufferLen, 0)) < 0) {
+ throw SocketException("Received failed (recv()) for socket ", true);
+ }
+ return rtn;
+}
+
+int CommunicatingSocket::peek(void *buffer, int bufferLen) throw(SocketException) {
+ int rtn;
+ if ((rtn = ::recv(sock, (raw_type *) buffer, bufferLen, MSG_PEEK)) < 0) {
+ throw SocketException("Received failed (recv()) for socket ", true);
+ }
+ return rtn;
+}
+
+int CommunicatingSocket::readLine(char *buffer, int bufferLen, const char delimiter) throw(SocketException) {
+
+ int n, rc;
+ char c;
+
+ for (n = 1; n < bufferLen; n++) {
+ if ((rc = recv(&c, 1)) == 1) {
+ *buffer++ = c;
+ if (c == delimiter) {
+ break;
+ }
+ } else if (rc == 0) {
+ if (n == 1) {
+ return 0; // EOF, no data read
+ } else {
+ break; // EOF, read some data
+ }
+ } else {
+ throw SocketException("Failed to read data from socket ", true);
+ }
+ }
+
+ *buffer = '\0';
+ return n;
+
+}
+
+string CommunicatingSocket::getForeignAddress() throw(SocketException) {
+ sockaddr_in addr;
+ unsigned int addr_len = sizeof(addr);
+
+ if (getpeername(sock, (sockaddr *) &addr,(socklen_t *) &addr_len) < 0) {
+ throw SocketException("Fetch of foreign address failed (getpeername())", true);
+ }
+ return inet_ntoa(addr.sin_addr);
+}
+
+unsigned short CommunicatingSocket::getForeignPort() throw(SocketException) {
+ sockaddr_in addr;
+ unsigned int addr_len = sizeof(addr);
+
+ if (getpeername(sock, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
+ throw SocketException("Fetch of foreign port failed (getpeername())", true);
+ }
+ return ntohs(addr.sin_port);
+}
+
+// TCPSocket Code
+
+TCPSocket::TCPSocket() throw(SocketException) : CommunicatingSocket(SOCK_STREAM, IPPROTO_TCP) {
+}
+
+TCPSocket::TCPSocket(const string &foreignAddress, unsigned short foreignPort) throw(SocketException) : CommunicatingSocket(SOCK_STREAM, IPPROTO_TCP) {
+ connect(foreignAddress, foreignPort);
+}
+
+TCPSocket::TCPSocket(int newSD) : CommunicatingSocket(newSD) {
+}
+
+// TCPServerSocket Code
+
+TCPServerSocket::TCPServerSocket(unsigned short localPort, int queueLen) throw(SocketException) : Socket(SOCK_STREAM, IPPROTO_TCP) {
+ setLocalPort(localPort);
+ setListen(queueLen);
+}
+
+TCPServerSocket::TCPServerSocket(const string &localAddress, unsigned short localPort, int queueLen) throw(SocketException) : Socket(SOCK_STREAM, IPPROTO_TCP) {
+ setLocalAddressAndPort(localAddress, localPort);
+ setListen(queueLen);
+}
+
+TCPSocket *TCPServerSocket::accept() throw(SocketException) {
+ int newSD;
+ if ((newSD = ::accept(sock, NULL, 0)) < 0) {
+ throw SocketException("Accept failed (accept())", true);
+ }
+ return new TCPSocket(newSD);
+}
+
+void TCPServerSocket::setListen(int queueLen) throw(SocketException) {
+ if (listen(sock, queueLen) < 0) {
+ throw SocketException("Set listening socket failed (listen())", true);
+ }
+}
+
+// TCPServerSocketM Code
+
+TCPServerSocketM::TCPServerSocketM(unsigned short localPort, int queueLen) throw(SocketException) : TCPServerSocket(localPort, queueLen) {
+
+ FD_ZERO(&fds_master); // clear the master and temp sets
+
+ FD_SET(sock, &fds_master); // Add ourself to the master set
+ fdmax = sock; // keep track of the biggest file descriptor, only ourself for the moment
+
+}
+
+TCPSocket *TCPServerSocketM::accept() throw(SocketException) {
+
+ TCPSocket *newClient = TCPServerSocket::accept();
+ int newSD = newClient->sock;
+
+ FD_SET(newSD, &fds_master); // add to master set
+ if (newSD > fdmax) { // keep track of the max
+ fdmax = newSD;
+ }
+
+ v_clients.push_back(newClient);
+ return newClient;
+
+}
+
+bool TCPServerSocketM::pendingConnections() throw (SocketException) {
+
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+
+ read_fds = fds_master;
+ if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
+ throw SocketException("Failed to select read fds (select())", true);
+ }
+
+ if (FD_ISSET(sock, &read_fds)) {
+ return true;
+ } else {
+ return false;
+ }
+
+}
+
+int TCPServerSocketM::getWaitingClients(vector<TCPSocket *> &clients) throw (SocketException) {
+
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+
+ int cl_count = 0;
+
+ read_fds = fds_master;
+ if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
+ throw SocketException("Failed to select read fds (select())", true);
+ }
+
+ // resize the vector so it doesn't contain any old information
+ clients.resize(0);
+
+ for(unsigned int i=0; i<v_clients.size(); i++) {
+ if (FD_ISSET(v_clients.at(i)->sock, &read_fds)) { // we got one!!
+ clients.push_back(v_clients.at(i));
+ cl_count++;
+ }
+ }
+
+ return cl_count;
+}
+
+void TCPServerSocketM::closeClientConnection(TCPSocket * client) {
+
+ for(unsigned int i=0; i<v_clients.size(); i++) {
+ if (client->sock == v_clients.at(i)->sock) {
+ FD_CLR(client->sock, &fds_master);
+ v_clients.erase(v_clients.begin() + i);
+ delete client;
+ break;
+ }
+ }
+
+}
+
+
+// UDPSocket Code
+
+UDPSocket::UDPSocket() throw(SocketException) : CommunicatingSocket(SOCK_DGRAM, IPPROTO_UDP) {
+ setBroadcast();
+}
+
+UDPSocket::UDPSocket(unsigned short localPort) throw(SocketException) : CommunicatingSocket(SOCK_DGRAM, IPPROTO_UDP) {
+ setLocalPort(localPort);
+ setBroadcast();
+}
+
+UDPSocket::UDPSocket(const string &localAddress, unsigned short localPort) throw(SocketException) : CommunicatingSocket(SOCK_DGRAM, IPPROTO_UDP) {
+ setLocalAddressAndPort(localAddress, localPort);
+ setBroadcast();
+}
+
+void UDPSocket::setBroadcast() {
+ // If this fails, we'll hear about it when we try to send. This will allow
+ // system that cannot broadcast to continue if they don't plan to broadcast
+ int broadcastPermission = 1;
+ setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (raw_type *) &broadcastPermission, sizeof(broadcastPermission));
+}
+
+void UDPSocket::disconnect() throw(SocketException) {
+ sockaddr_in nullAddr;
+ memset(&nullAddr, 0, sizeof(nullAddr));
+ nullAddr.sin_family = AF_UNSPEC;
+
+ // Try to disconnect
+ if (::connect(sock, (sockaddr *) &nullAddr, sizeof(nullAddr)) < 0) {
+#ifdef WIN32
+ if (errno != WSAEAFNOSUPPORT) {
+#else
+ if (errno != EAFNOSUPPORT) {
+#endif
+ throw SocketException("Disconnect failed (connect())", true);
+ }
+ }
+}
+
+void UDPSocket::sendTo(const void *buffer, int bufferLen, const string &foreignAddress, unsigned short foreignPort) throw(SocketException) {
+ sockaddr_in destAddr;
+ fillAddr(foreignAddress, foreignPort, destAddr);
+
+ // Write out the whole buffer as a single message.
+ if (sendto(sock, (raw_type *) buffer, bufferLen, 0, (sockaddr *) &destAddr, sizeof(destAddr)) != bufferLen) {
+ throw SocketException("Send failed (sendto())", true);
+ }
+}
+
+int UDPSocket::recvFrom(void *buffer, int bufferLen, string &sourceAddress, unsigned short &sourcePort) throw(SocketException) {
+ sockaddr_in clntAddr;
+ socklen_t addrLen = sizeof(clntAddr);
+ int rtn;
+ if ((rtn = recvfrom(sock, (raw_type *) buffer, bufferLen, 0, (sockaddr *) &clntAddr, (socklen_t *) &addrLen)) < 0) {
+ throw SocketException("Receive failed (recvfrom())", true);
+ }
+ sourceAddress = inet_ntoa(clntAddr.sin_addr);
+ sourcePort = ntohs(clntAddr.sin_port);
+ return rtn;
+}
+
+void UDPSocket::setMulticastTTL(unsigned char multicastTTL) throw(SocketException) {
+ if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (raw_type *) &multicastTTL, sizeof(multicastTTL)) < 0) {
+ throw SocketException("Multicast TTL set failed (setsockopt())", true);
+ }
+}
+
+void UDPSocket::joinGroup(const string &multicastGroup) throw(SocketException) {
+ struct ip_mreq multicastRequest;
+
+ multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.c_str());
+ multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
+ if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (raw_type *) &multicastRequest, sizeof(multicastRequest)) < 0) {
+ throw SocketException("Multicast group join failed (setsockopt())", true);
+ }
+}
+
+void UDPSocket::leaveGroup(const string &multicastGroup) throw(SocketException) {
+ struct ip_mreq multicastRequest;
+
+ multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.c_str());
+ multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
+ if (setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (raw_type *) &multicastRequest, sizeof(multicastRequest)) < 0) {
+ throw SocketException("Multicast group leave failed (setsockopt())", true);
+ }
+}
+
+} // End of namespace SocketLibrary
diff --git a/lib/socket/socket.h b/lib/socket/socket.h
new file mode 100644
index 0000000..2c4d777
--- /dev/null
+++ b/lib/socket/socket.h
@@ -0,0 +1,427 @@
+/*
+ * C++ sockets on Unix and Windows
+ * Copyright (C) 2002 <unknown>
+ * Copyright (C) 2010 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef SL_SOCKET_H
+#define SL_SOCKET_H
+
+#include <string> // For string
+#include <exception> // For exception class
+#include <vector> // For vectors
+
+#ifdef WIN32
+ #include <winsock.h> // For socket(), connect(), send(), and recv()
+ typedef int socklen_t;
+ typedef char raw_type; // Type used for raw data on this platform
+#else
+ #include <netinet/in.h> // For sockaddr_in
+ typedef void raw_type; // Type used for raw data on this platform
+#endif
+
+using namespace std;
+
+namespace socketlibrary {
+
+/**
+ * Function to fill in address structure given an address and port
+ */
+void fillAddr(const string &address, unsigned short port, sockaddr_in &addr);
+
+/**
+ * Signals a problem with the execution of a socket call.
+ */
+class SocketException : public exception {
+public:
+ /**
+ * Construct a SocketException with a explanatory message.
+ * @param message explanatory message
+ * @param incSysMsg true if system message (from strerror(errno))
+ * should be postfixed to the user provided message
+ */
+ SocketException(const string &message, bool inclSysMsg = false) throw();
+
+ /**
+ * Provided just to guarantee that no exceptions are thrown.
+ */
+ ~SocketException() throw();
+
+ /**
+ * Get the exception message
+ * @return exception message
+ */
+ const char *what() const throw();
+
+private:
+ string userMessage; // Exception message
+};
+
+
+/**
+ * Base class representing basic communication endpoint
+ */
+class Socket {
+public:
+ /**
+ * Close and deallocate this socket
+ */
+ ~Socket();
+
+ /**
+ * Get the local address
+ * @return local address of socket
+ * @exception SocketException thrown if fetch fails
+ */
+ string getLocalAddress() throw(SocketException);
+
+ /**
+ * Get the local port
+ * @return local port of socket
+ * @exception SocketException thrown if fetch fails
+ */
+ unsigned short getLocalPort() throw(SocketException);
+
+ /**
+ * Set the local port to the specified port and the local address
+ * to any interface
+ * @param localPort local port
+ * @exception SocketException thrown if setting local port fails
+ */
+ void setLocalPort(unsigned short localPort) throw(SocketException);
+
+ /**
+ * Set the local port to the specified port and the local address
+ * to the specified address. If you omit the port, a random port
+ * will be selected.
+ * @param localAddress local address
+ * @param localPort local port
+ * @exception SocketException thrown if setting local port or address fails
+ */
+ void setLocalAddressAndPort(const string &localAddress, unsigned short localPort = 0) throw(SocketException);
+
+ /**
+ * If WinSock, unload the WinSock DLLs; otherwise do nothing. We ignore
+ * this in our sample client code but include it in the library for
+ * completeness. If you are running on Windows and you are concerned
+ * about DLL resource consumption, call this after you are done with all
+ * Socket instances. If you execute this on Windows while some instance of
+ * Socket exists, you are toast. For portability of client code, this is
+ * an empty function on non-Windows platforms so you can always include it.
+ * @param buffer buffer to receive the data
+ * @param bufferLen maximum number of bytes to read into buffer
+ * @return number of bytes read, 0 for EOF, and -1 for error
+ * @exception SocketException thrown WinSock clean up fails
+ */
+ static void cleanUp() throw(SocketException);
+
+ /**
+ * Resolve the specified service for the specified protocol to the
+ * corresponding port number in host byte order
+ * @param service service to resolve (e.g., "http")
+ * @param protocol protocol of service to resolve. Default is "tcp".
+ */
+ static unsigned short resolveService(const string &service, const string &protocol = "tcp");
+
+private:
+ // Prevent the user from trying to use value semantics on this object
+ Socket(const Socket &sock);
+ void operator=(const Socket &sock);
+
+protected:
+ int sock; // Socket descriptor
+ Socket(int type, int protocol) throw(SocketException);
+ Socket(int sock);
+};
+
+/**
+ * Socket which is able to connect, send, and receive
+ */
+class CommunicatingSocket : public Socket {
+public:
+ /**
+ * Establish a socket connection with the given foreign
+ * address and port
+ * @param foreignAddress foreign address (IP address or name)
+ * @param foreignPort foreign port
+ * @exception SocketException thrown if unable to establish connection
+ */
+ void connect(const string &foreignAddress, unsigned short foreignPort) throw(SocketException);
+
+ /**
+ * Write the given buffer to this socket. Call connect() before
+ * calling send()
+ * @param buffer buffer to be written
+ * @param bufferLen number of bytes from buffer to be written
+ * @exception SocketException thrown if unable to send data
+ */
+ void send(const void *buffer, int bufferLen) throw(SocketException);
+
+ /**
+ * Read into the given buffer up to bufferLen bytes data from this
+ * socket. Call connect() before calling recv()
+ * @param buffer buffer to receive the data
+ * @param bufferLen maximum number of bytes to read into buffer
+ * @return number of bytes read, 0 for EOF, and -1 for error
+ * @exception SocketException thrown if unable to receive data
+ */
+ int recv(void *buffer, int bufferLen) throw(SocketException);
+
+ /**
+ * Read into the given buffer up to bufferLen bytes data from this
+ * socket but don't remove the read bytes from the socket read buffer.
+ * Call connect() before calling peek()
+ *
+ * @param buffer buffer to receive the data
+ * @param bufferLen maximum number of bytes to read into buffer
+ * @return number of bytes read, 0 for EOF, and -1 for error
+ * @exception SocketException thrown if unable to receive data
+ */
+ int peek(void *buffer, int bufferLen) throw(SocketException);
+
+ /**
+ * Read a line into the given buffer from this socket.
+ * Call connect() before calling recv()
+ *
+ * @param buffer buffer to receive the data
+ * @param bufferLen maximum number of bytes to read into buffer
+ * @param delimiter (optional) end of line delimiter
+ * @return number of bytes read, 0 for EOF, and -1 for error
+ * @exception SocketException thrown if unable to receive data
+ */
+ int readLine(char *buffer, int bufferLen, const char delimiter = '\n') throw(SocketException);
+
+ /**
+ * Get the foreign address. Call connect() before calling recv()
+ * @return foreign address
+ * @exception SocketException thrown if unable to fetch foreign address
+ */
+ string getForeignAddress() throw(SocketException);
+
+ /**
+ * Get the foreign port. Call connect() before calling recv()
+ * @return foreign port
+ * @exception SocketException thrown if unable to fetch foreign port
+ */
+ unsigned short getForeignPort() throw(SocketException);
+
+protected:
+ CommunicatingSocket(int type, int protocol) throw(SocketException);
+ CommunicatingSocket(int newSD);
+};
+
+/**
+ * TCP socket for communication with other TCP sockets
+ */
+class TCPSocket : public CommunicatingSocket {
+public:
+ /**
+ * Construct a TCP socket with no connection
+ * @exception SocketException thrown if unable to create TCP socket
+ */
+ TCPSocket() throw(SocketException);
+
+ /**
+ * Construct a TCP socket with a connection to the given foreign address
+ * and port
+ * @param foreignAddress foreign address (IP address or name)
+ * @param foreignPort foreign port
+ * @exception SocketException thrown if unable to create TCP socket
+ */
+ TCPSocket(const string &foreignAddress, unsigned short foreignPort) throw(SocketException);
+
+private:
+ friend class TCPServerSocket; // Access for TCPServerSocket::accept() connection creation
+ friend class TCPServerSocketM; // Access for TCPServerSocketM::accept() connection creation
+ TCPSocket(int newSD);
+};
+
+/**
+ * TCP socket class for servers
+ */
+class TCPServerSocket : public Socket {
+public:
+ /**
+ * Construct a TCP socket for use with a server, accepting connections
+ * on the specified port on any interface
+ * @param localPort local port of server socket, a value of zero will
+ * give a system-assigned unused port
+ * @param queueLen maximum queue length for outstanding
+ * connection requests (default 5)
+ * @exception SocketException thrown if unable to create TCP server socket
+ */
+ TCPServerSocket(unsigned short localPort, int queueLen = 5) throw(SocketException);
+
+ /**
+ * Construct a TCP socket for use with a server, accepting connections
+ * on the specified port on the interface specified by the given address
+ * @param localAddress local interface (address) of server socket
+ * @param localPort local port of server socket
+ * @param queueLen maximum queue length for outstanding
+ * connection requests (default 5)
+ * @exception SocketException thrown if unable to create TCP server socket
+ */
+ TCPServerSocket(const string &localAddress, unsigned short localPort, int queueLen = 5) throw(SocketException);
+
+ /**
+ * Blocks until a new connection is established on this socket or error
+ * @return new connection socket
+ * @exception SocketException thrown if attempt to accept a new connection fails
+ */
+ TCPSocket *accept() throw(SocketException);
+
+private:
+ void setListen(int queueLen) throw(SocketException);
+};
+
+/**
+ * TCP socket class for multi-client servers
+ */
+class TCPServerSocketM : public TCPServerSocket {
+public:
+
+ /**
+ * Construct a TCP socket for use with a server, accepting connections
+ * on the specified port on any interface
+ * @param localPort local port of server socket, a value of zero will
+ * give a system-assigned unused port
+ * @param queueLen maximum queue length for outstanding
+ * connection requests (default 5)
+ * @exception SocketException thrown if unable to create TCP server socket
+ */
+ TCPServerSocketM(unsigned short localPort, int queueLen = 5) throw(SocketException);
+
+ /**
+ * Blocks until a new connection is established on this socket or error
+ * @return new connection socket
+ * @exception SocketException thrown if attempt to accept a new connection fails
+ */
+ TCPSocket *accept() throw(SocketException);
+
+ /**
+ * Checks for incoming connections or error
+ * @return boolean (true if incoming connections are present)
+ * @exception SocketException thrown if attempt to check for new connections fail
+ */
+ bool pendingConnections() throw(SocketException);
+
+ /**
+ * Checks for read waiting clients
+ * @param clients a vector of TCPSocket pointers to get the waiting clients
+ * @return number of clients waiting
+ * @exception SocketException thrown if attempt to check for waiting clients fail
+ */
+ int getWaitingClients(vector<TCPSocket *> &clients) throw (SocketException);
+
+ /**
+ * Closes the connection to a client
+ * @param client the client TCPSocket to close
+ */
+ void closeClientConnection(TCPSocket *client);
+
+private:
+ fd_set fds_master; // master file descriptor list
+ int fdmax; // maximum file descriptor number
+
+ vector<TCPSocket *> v_clients;
+};
+
+/**
+ * UDP socket class
+ */
+class UDPSocket : public CommunicatingSocket {
+public:
+ /**
+ * Construct a UDP socket
+ * @exception SocketException thrown if unable to create UDP socket
+ */
+ UDPSocket() throw(SocketException);
+
+ /**
+ * Construct a UDP socket with the given local port
+ * @param localPort local port
+ * @exception SocketException thrown if unable to create UDP socket
+ */
+ UDPSocket(unsigned short localPort) throw(SocketException);
+
+ /**
+ * Construct a UDP socket with the given local port and address
+ * @param localAddress local address
+ * @param localPort local port
+ * @exception SocketException thrown if unable to create UDP socket
+ */
+ UDPSocket(const string &localAddress, unsigned short localPort) throw(SocketException);
+
+ /**
+ * Unset foreign address and port
+ * @return true if disassociation is successful
+ * @exception SocketException thrown if unable to disconnect UDP socket
+ */
+ void disconnect() throw(SocketException);
+
+ /**
+ * Send the given buffer as a UDP datagram to the
+ * specified address/port
+ * @param buffer buffer to be written
+ * @param bufferLen number of bytes to write
+ * @param foreignAddress address (IP address or name) to send to
+ * @param foreignPort port number to send to
+ * @return true if send is successful
+ * @exception SocketException thrown if unable to send datagram
+ */
+ void sendTo(const void *buffer, int bufferLen, const string &foreignAddress, unsigned short foreignPort) throw(SocketException);
+
+ /**
+ * Read read up to bufferLen bytes data from this socket. The given buffer
+ * is where the data will be placed
+ * @param buffer buffer to receive data
+ * @param bufferLen maximum number of bytes to receive
+ * @param sourceAddress address of datagram source
+ * @param sourcePort port of data source
+ * @return number of bytes received and -1 for error
+ * @exception SocketException thrown if unable to receive datagram
+ */
+ int recvFrom(void *buffer, int bufferLen, string &sourceAddress, unsigned short &sourcePort) throw(SocketException);
+
+ /**
+ * Set the multicast TTL
+ * @param multicastTTL multicast TTL
+ * @exception SocketException thrown if unable to set TTL
+ */
+ void setMulticastTTL(unsigned char multicastTTL) throw(SocketException);
+
+ /**
+ * Join the specified multicast group
+ * @param multicastGroup multicast group address to join
+ * @exception SocketException thrown if unable to join group
+ */
+ void joinGroup(const string &multicastGroup) throw(SocketException);
+
+ /**
+ * Leave the specified multicast group
+ * @param multicastGroup multicast group address to leave
+ * @exception SocketException thrown if unable to leave group
+ */
+ void leaveGroup(const string &multicastGroup) throw(SocketException);
+
+private:
+ void setBroadcast();
+};
+
+} // End of namespace SocketLibrary
+
+#endif /* !SL_SOCKET_H */
diff --git a/modules/Makefile.am b/modules/Makefile.am
new file mode 100644
index 0000000..c52d720
--- /dev/null
+++ b/modules/Makefile.am
@@ -0,0 +1,3 @@
+## modules/
+SUBDIRS = echo modpy
+
diff --git a/modules/echo/Makefile.am b/modules/echo/Makefile.am
new file mode 100644
index 0000000..3236ad7
--- /dev/null
+++ b/modules/echo/Makefile.am
@@ -0,0 +1,9 @@
+# modules/echo
+AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_srcdir)/src
+
+modlibdir = $(pkglibdir)/modules
+modlib_LTLIBRARIES = mod_echo.la
+mod_echo_la_LDFLAGS = -module -avoid-version
+mod_echo_la_SOURCES = \
+ echo.h echo.cpp
+
diff --git a/modules/echo/echo.cpp b/modules/echo/echo.cpp
new file mode 100644
index 0000000..a8496c5
--- /dev/null
+++ b/modules/echo/echo.cpp
@@ -0,0 +1,55 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "echo.h"
+
+
+namespace bitz {
+
+ Echo::Echo() : Modifier() { }
+ Echo::~Echo() { }
+
+
+ icap::Response * Echo::modify( icap::Request * request ) throw() {
+
+ icap::Response * response;
+ icap::payload_t payload;
+
+ // copy payload from request
+ payload.req_header = request->payload().req_header;
+ payload.req_body = request->payload().req_body;
+ payload.res_header = request->payload().res_header;
+ payload.res_body = request->payload().res_body;
+
+
+ response = new icap::Response( icap::ResponseHeader::OK );
+ response->payload( payload );
+
+ return response;
+
+ }
+
+
+ icap::Response * Echo::preview( icap::Request * request ) throw() {
+ // 100 - continue always
+ return new icap::Response( icap::ResponseHeader::CONTINUE );
+ }
+
+} /* end of namespace bitz */
+
diff --git a/modules/echo/echo.h b/modules/echo/echo.h
new file mode 100644
index 0000000..87df312
--- /dev/null
+++ b/modules/echo/echo.h
@@ -0,0 +1,54 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef BITZ_ECHO_H
+#define BITZ_ECHO_H
+
+#include <bitz/modifier.h>
+
+
+namespace bitz {
+
+ class Echo : public Modifier {
+ public:
+ Echo();
+ virtual ~Echo();
+
+ icap::Response * modify( icap::Request * request ) throw();
+ icap::Response * preview( icap::Request * request ) throw();
+
+ private:
+
+ };
+
+} /* end of namespace bitz */
+
+
+/* class factories */
+
+extern "C" bitz::Modifier * create() {
+ return new bitz::Echo;
+}
+
+extern "C" void destroy( bitz::Modifier * m ) {
+ delete m;
+}
+
+#endif /* !BITZ_ECHO_H */
+
diff --git a/modules/modpy/Makefile.am b/modules/modpy/Makefile.am
new file mode 100644
index 0000000..eccb2a2
--- /dev/null
+++ b/modules/modpy/Makefile.am
@@ -0,0 +1,18 @@
+# modules/modpy
+
+SUBDIRS = modules
+
+if MODPY
+modlibdir = $(pkglibdir)/modules
+modlib_LTLIBRARIES = mod_py.la
+mod_py_la_LDFLAGS = -module -avoid-version
+mod_py_la_SOURCES = \
+ py.h py.cpp \
+ interface.h interface.cpp
+
+AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_srcdir)/src \
+ ${PYTHON_INCLUDES} ${libconfig_CFLAGS} ${log4cpp_CFLAGS}
+
+mod_py_la_LIBADD = ${PYTHON_LIBS}
+endif
+
diff --git a/modules/modpy/interface.cpp b/modules/modpy/interface.cpp
new file mode 100644
index 0000000..948fa5c
--- /dev/null
+++ b/modules/modpy/interface.cpp
@@ -0,0 +1,160 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "interface.h"
+
+#include <bitz/logger.h>
+#include <icap/request.h>
+#include <icap/response.h>
+#include <iostream>
+
+
+PyObject * bitz_get_request( PyObject * self, PyObject * pyrequest ) {
+
+ PyObject * pyreturn;
+ PyObject * pypayload;
+ icap::Request * request;
+
+ // logger
+ bitz::Logger &logger = bitz::Logger::instance();
+ logger.debug( "[modpy.interface] get_request()" );
+
+ // initialise return dictionary
+ pyreturn = PyDict_New();
+
+ // grab the request object pointer from args
+ void * p = PyCapsule_GetPointer( pyrequest, "request" );
+
+ // sanity check
+ if ( p != NULL ) {
+
+ // construct the request
+ request = static_cast<icap::Request *>(p);
+
+ PyDict_SetItemString( pyreturn, "request", PyString_FromString( request->header()->method().c_str() ) );
+ PyDict_SetItemString( pyreturn, "uri", PyString_FromString( request->header()->uri().c_str() ) );
+ PyDict_SetItemString( pyreturn, "protocol", PyString_FromString( request->header()->protocol().c_str() ) );
+
+ // payload dictionary
+ pypayload = PyDict_New();
+ PyDict_SetItemString( pypayload, "req_header", PyString_FromStringAndSize( request->payload().req_header.c_str(), request->payload().req_header.size() ) );
+ PyDict_SetItemString( pypayload, "req_body", PyString_FromStringAndSize( request->payload().req_body.c_str(), request->payload().req_body.size() ) );
+ PyDict_SetItemString( pypayload, "res_header", PyString_FromStringAndSize( request->payload().res_header.c_str(), request->payload().res_header.size() ) );
+ PyDict_SetItemString( pypayload, "res_body", PyString_FromStringAndSize( request->payload().res_body.c_str(), request->payload().res_body.size() ) );
+ PyDict_SetItemString( pypayload, "ieof", PyBool_FromLong( request->payload().ieof ) );
+
+ PyDict_SetItemString( pyreturn, "payload", pypayload );
+
+ // cleanup
+ Py_DECREF( pypayload );
+
+ } else {
+ logger.warn( "[modpy.interface] failed to get request object pointer" );
+ }
+
+ return pyreturn;
+
+}
+
+
+PyObject * bitz_get_response_from_status( PyObject * self, PyObject * args ) {
+
+ PyObject * pyresponse;
+ icap::Response * response;
+
+ unsigned int resp_status;
+
+ // logger
+ bitz::Logger &logger = bitz::Logger::instance();
+ logger.debug( "[modpy.interface] get_response_from_status()" );
+
+ // parse args
+ if ( PyArg_ParseTuple( args, "I", &resp_status ) ) {
+ response = new icap::Response( (icap::ResponseHeader::status_t) resp_status );
+ } else {
+ logger.warn( "[modpy.interface] failed to parse arguments" );
+ response = new icap::Response( icap::ResponseHeader::SERVER_ERROR );
+ }
+
+ // convert the response into a capsule
+ pyresponse = PyCapsule_New( (void *) response, "response", NULL );
+
+ return pyresponse;
+
+}
+
+
+PyObject * bitz_get_response( PyObject * self, PyObject * args ) {
+
+ PyObject * pyresponse;
+ PyObject * pypayload;
+ icap::Response * response = NULL;
+
+ unsigned int resp_status;
+ icap::payload_t payload;
+
+ // vars to ferry across strings from python dictionary to c++
+ char * pybuffer;
+ Py_ssize_t pybuflen;
+
+
+ // logger
+ bitz::Logger &logger = bitz::Logger::instance();
+ logger.debug( "[modpy.interface] get_response()" );
+
+ // parse args
+ if ( PyArg_ParseTuple( args, "IO!", &resp_status, &PyDict_Type, &pypayload ) ) {
+
+ // copy strings from python dictionary
+ PyString_AsStringAndSize( PyDict_GetItemString( pypayload, "req_header" ), &pybuffer, &pybuflen );
+ payload.req_header.assign( pybuffer, pybuflen );
+
+ PyString_AsStringAndSize( PyDict_GetItemString( pypayload, "req_body" ), &pybuffer, &pybuflen );
+ payload.req_body.assign( pybuffer, pybuflen );
+
+ PyString_AsStringAndSize( PyDict_GetItemString( pypayload, "res_header" ), &pybuffer, &pybuflen );
+ payload.res_header.assign( pybuffer, pybuflen );
+
+ PyString_AsStringAndSize( PyDict_GetItemString( pypayload, "res_body" ), &pybuffer, &pybuflen );
+ payload.res_body.assign( pybuffer, pybuflen );
+
+ // copy other data types from python dictionary
+ payload.ieof = PyBool_Check( PyDict_GetItemString( pypayload, "ieof" ) );
+
+ // construct the response object
+ response = new icap::Response( (icap::ResponseHeader::status_t) resp_status );
+ response->payload( payload );
+
+ } else {
+ logger.warn( "[modpy.interface] failed to parse arguments" );
+ }
+
+ // sanity check
+ if ( response == NULL ) {
+ response = new icap::Response( icap::ResponseHeader::SERVER_ERROR );
+ }
+
+ // convert the response into a capsule
+ pyresponse = PyCapsule_New( (void *) response, "response", NULL );
+
+ return pyresponse;
+
+}
+
+
diff --git a/modules/modpy/interface.h b/modules/modpy/interface.h
new file mode 100644
index 0000000..315a2f6
--- /dev/null
+++ b/modules/modpy/interface.h
@@ -0,0 +1,39 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef BITZ_MODPY_INTERFACE_H
+#define BITZ_MODPY_INTERFACE_H
+
+#include <Python.h>
+#include <stddef.h>
+
+
+PyObject * bitz_get_request( PyObject * self, PyObject * pyrequest );
+PyObject * bitz_get_response( PyObject * self, PyObject * args );
+PyObject * bitz_get_response_from_status( PyObject * self, PyObject * args);
+
+static PyMethodDef bitz_methods[] = {
+ { "get_request", bitz_get_request, METH_O, "Convert a capsule request into a python dictionary" },
+ { "get_response", bitz_get_response, METH_VARARGS, "Get a response capsule (takes in status and payload dictionary as args)" },
+ { "get_response_from_status", bitz_get_response_from_status, METH_VARARGS, "Get a response capsule from a response status" },
+ { NULL, NULL, 0, NULL }
+};
+
+#endif /* !BITZ_MODPY_INTERFACE_H */
+
diff --git a/modules/modpy/modules/Makefile.am b/modules/modpy/modules/Makefile.am
new file mode 100644
index 0000000..9292d1d
--- /dev/null
+++ b/modules/modpy/modules/Makefile.am
@@ -0,0 +1,11 @@
+# modules/modpy/modules
+
+# extra dist files
+EXTRA_DIST = \
+ modpy.py
+
+if MODPY
+modpydir = $(pkglibdir)/modules/modpy
+modpy_DATA = modpy.py
+endif
+
diff --git a/modules/modpy/modules/modpy.py b/modules/modpy/modules/modpy.py
new file mode 100644
index 0000000..9a5e578
--- /dev/null
+++ b/modules/modpy/modules/modpy.py
@@ -0,0 +1,42 @@
+#
+# modpy.py
+# Copyright (c) 2013 Uditha Atukorala
+#
+
+import bitz
+
+def init():
+ print "init() called";
+
+def cleanup():
+ print "cleanup() called";
+
+def preview( request ):
+ request = bitz.get_request( request );
+ req_payload = request['payload'];
+ print "preview payload: \r\n", req_payload;
+
+ # response
+ if req_payload['ieof']:
+ response = bitz.get_response_from_status( 204 );
+ else:
+ response = bitz.get_response_from_status( 100 );
+
+ return response;
+
+def modify( request ):
+ request = bitz.get_request( request );
+ req_payload = request['payload'];
+ print "modify payload: \r\n", req_payload;
+
+ # response
+ resp_payload = {};
+ resp_payload['req_header'] = req_payload['req_header'];
+ resp_payload['req_body'] = req_payload['req_body'];
+ resp_payload['res_header'] = req_payload['res_header'];
+ resp_payload['res_body'] = req_payload['res_body'];
+ resp_payload['ieof'] = True;
+
+ response = bitz.get_response( 200, resp_payload );
+ return response;
+
diff --git a/modules/modpy/py.cpp b/modules/modpy/py.cpp
new file mode 100644
index 0000000..51cb38f
--- /dev/null
+++ b/modules/modpy/py.cpp
@@ -0,0 +1,265 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "py.h"
+#include "interface.h"
+
+#include <bitz/config.h>
+#include <bitz/logger.h>
+
+
+namespace bitz {
+
+ Py::Py() : Modifier() {
+
+ // defaults
+ _pymodule = NULL;
+
+ // initialise Py::config_t values
+ _config.module_name = "modpy";
+ _config.module_path = "";
+
+ // load configs
+ load_configs();
+
+ // initialise python
+ init_python();
+
+ }
+
+
+ Py::~Py() {
+
+ // cleanup python
+ cleanup_python();
+
+ }
+
+
+ icap::Response * Py::modify( icap::Request * request ) throw() {
+
+ // get the modify response
+ return python_response( request, "modify" );
+
+ }
+
+
+ icap::Response * Py::preview( icap::Request * request ) throw() {
+
+ // get the preview response
+ return python_response( request, "preview" );
+
+ }
+
+
+ void Py::load_configs() throw() {
+
+ std::string s;
+ Config &server_config = Config::instance();
+
+ // interface module name
+ s = server_config.module_config( "modpy", "module_name" );
+ if ( s != "" ) {
+ _config.module_name = s;
+ }
+
+ // module lookup path
+ _config.module_path = server_config.module_config( "modpy", "module_path" );
+
+ }
+
+
+ void Py::init_python() throw() {
+
+ PyObject * sys_path;
+ PyObject * pymodule_path, * pymodule_name;
+ PyObject * pymethod;
+ PyObject * pyreturn;
+
+ // logger
+ Logger &logger = Logger::instance();
+
+ // python core
+ Py_Initialize();
+
+ // bitz python module
+ if ( Py_InitModule( "bitz", bitz_methods ) == NULL ) {
+ logger.warn( "[modpy] failed to init C interface module: bitz" );
+ }
+
+ // setup python environment
+ if ( _config.module_path != "" ) {
+
+ logger.debug( std::string( "[modpy] appending to sys.path, module_path: " ).append( _config.module_path ) );
+
+ sys_path = PySys_GetObject( (char *) "path" );
+ pymodule_path = PyString_FromString( _config.module_path.c_str() );
+ PyList_Append( sys_path, pymodule_path );
+
+ }
+
+ // load the interface module
+ logger.debug( std::string( "[modpy] interface module: " ).append( _config.module_name ) );
+
+ pymodule_name = PyString_FromString( _config.module_name.c_str() );
+ _pymodule = PyImport_Import( pymodule_name );
+
+ if ( _pymodule != NULL ) {
+
+ logger.debug( "[modpy] interface module loaded successfully" );
+
+ // call init() in the interface module
+ pymethod = PyObject_GetAttrString( _pymodule, "init" );
+
+ if ( pymethod && PyCallable_Check( pymethod ) ) {
+ pyreturn = PyObject_CallObject( pymethod, NULL );
+ Py_DECREF( pyreturn );
+ } else {
+ logger.warn ( "[modpy] failed to call init() in interface module" );
+ }
+
+ Py_DECREF( pymethod );
+
+ } else {
+ logger.warn( "[modpy] failed to load interface module" );
+ }
+
+
+ // cleanup
+ Py_DECREF( pymodule_name );
+ Py_DECREF( pymodule_path );
+ Py_DECREF( sys_path );
+
+ }
+
+
+ void Py::cleanup_python() throw() {
+
+ PyObject * pymethod;
+ PyObject * pyreturn;
+
+ // logger
+ Logger &logger = Logger::instance();
+
+
+ // cleanup
+ if ( _pymodule != NULL ) {
+
+ // call cleanup() in the interface module
+ pymethod = PyObject_GetAttrString( _pymodule, "cleanup" );
+
+ if ( pymethod && PyCallable_Check( pymethod ) ) {
+ pyreturn = PyObject_CallObject( pymethod, NULL );
+ Py_DECREF( pyreturn );
+ } else {
+ logger.warn ( "[modpy] failed to call cleanup() in interface module" );
+ }
+
+ Py_DECREF( pymethod );
+ Py_DECREF( _pymodule );
+
+ }
+
+ // finalise python core
+ Py_Finalize();
+
+ }
+
+
+ icap::Response * Py::python_response( icap::Request * request, const std::string &method ) throw() {
+
+ /*
+ * notes:
+ * + pass icap::Request to python module as a PyCapsule object
+ * so it can be used to grab the data needed using the C/C++ interface.
+ * + process data (within the python module) and use the C/C++ interface
+ * to create a icap::Response and pass it back to this method
+ * using a PyCapsule object
+ */
+
+ icap::Response * response;
+
+ PyObject * pymethod;
+ PyObject * pyargs;
+ PyObject * pyrequest, * pyresponse;
+
+ // logger
+ Logger &logger = Logger::instance();
+
+ // initialise the response object
+ response = NULL;
+
+ // check for the interface module
+ if ( _pymodule != NULL ) {
+
+ /* call the [method]() in the interface module */
+ pymethod = PyObject_GetAttrString( _pymodule, method.c_str() );
+ pyargs = PyTuple_New( 1 );
+ pyrequest = PyCapsule_New( (void *) request, "request", NULL );
+ PyTuple_SetItem( pyargs, 0, pyrequest );
+
+ if ( pymethod && PyCallable_Check( pymethod ) ) {
+
+ // get the response capsule
+ pyresponse = PyObject_CallObject( pymethod, pyargs );
+
+ // sanity check
+ if ( pyresponse != NULL ) {
+
+ void * p = PyCapsule_GetPointer( pyresponse, "response" );
+
+ // sanity check
+ if ( p != NULL ) {
+
+ // construct the response
+ response = static_cast<icap::Response *>(p);
+
+ } else {
+ logger.warn( std::string( "[modpy] invalid capsule response, method: " ).append( method ) );
+ }
+
+ Py_DECREF( pyresponse );
+
+ } else {
+ logger.warn( std::string( "[modpy] response is NULL, method: " ).append( method ) );
+ }
+
+
+ } else {
+ logger.warn ( std::string( "[modpy] failed to call the method in interface module, method: " ).append( method ) );
+ }
+
+ // cleanup
+ // pyrequest is created from the reference passed in
+ Py_DECREF( pyargs );
+ Py_DECREF( pymethod );
+
+ }
+
+ // sanity check
+ if ( response == NULL ) {
+ response = new icap::Response( icap::ResponseHeader::SERVER_ERROR );
+ }
+
+ return response;
+
+ }
+
+} /* end of namespace bitz */
+
diff --git a/modules/modpy/py.h b/modules/modpy/py.h
new file mode 100644
index 0000000..358c36f
--- /dev/null
+++ b/modules/modpy/py.h
@@ -0,0 +1,70 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef BITZ_PY_H
+#define BITZ_PY_H
+
+#include <Python.h>
+
+#include <bitz/modifier.h>
+
+
+namespace bitz {
+
+ class Py : public Modifier {
+ public:
+
+ struct config_t {
+ std::string module_path;
+ std::string module_name;
+ };
+
+ Py();
+ virtual ~Py();
+
+ icap::Response * modify( icap::Request * request ) throw();
+ icap::Response * preview( icap::Request * request ) throw();
+
+ private:
+ config_t _config;
+ PyObject * _pymodule;
+
+ void load_configs() throw();
+ void init_python() throw();
+ void cleanup_python() throw();
+
+ icap::Response * python_response( icap::Request * request, const std::string &method ) throw();
+
+ };
+
+} /* end of namespace bitz */
+
+
+/* class factories */
+
+extern "C" bitz::Modifier * create() {
+ return new bitz::Py;
+}
+
+extern "C" void destroy( bitz::Modifier * m ) {
+ delete m;
+}
+
+#endif /* !BITZ_PY_H */
+
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..201a051
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,32 @@
+## src/
+AUTOMAKE_OPTIONS = subdir-objects
+AM_CPPFLAGS = -I$(top_srcdir)/lib ${libconfig_CFLAGS} ${log4cpp_CFLAGS}
+
+bitzincludedir = $(pkgincludedir)
+sbin_PROGRAMS = bitz-server
+bitz_server_LDFLAGS = -ldl -export-dynamic
+bitz_server_LDADD = $(top_builddir)/lib/socket/libsocket.la \
+ $(top_builddir)/lib/icap/libicap.la \
+ ${libconfig_LIBS} ${log4cpp_LIBS}
+
+bitz_server_SOURCES = main.cpp \
+ bitz-server.h bitz-server.cpp \
+ bitz/exception.h bitz/exception.cpp \
+ bitz/manager_exception.h bitz/manager_exception.cpp \
+ bitz/config.h bitz/config.cpp \
+ bitz/logger.h bitz/logger.cpp \
+ bitz/common.h \
+ bitz/util.h bitz/util.cpp \
+ bitz/manager.h bitz/manager.cpp \
+ bitz/worker.h bitz/worker.cpp \
+ bitz/request_handler.h bitz/request_handler.cpp \
+ bitz/options_request_handler.h bitz/options_request_handler.cpp \
+ bitz/reqmod_request_handler.h bitz/reqmod_request_handler.cpp \
+ bitz/respmod_request_handler.h bitz/respmod_request_handler.cpp \
+ bitz/modifier.cpp
+
+bitzinclude_HEADERS = \
+ bitz/config.h \
+ bitz/logger.h \
+ bitz/modifier.h
+
diff --git a/src/bitz-server.cpp b/src/bitz-server.cpp
new file mode 100644
index 0000000..c444762
--- /dev/null
+++ b/src/bitz-server.cpp
@@ -0,0 +1,472 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include <iostream>
+#include <string>
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <syslog.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <config.h>
+#include "bitz-server.h"
+
+namespace bitz {
+
+ namespace server {
+
+ static server_t globals;
+
+ void init() {
+
+ // initialise defaults
+ globals.pid_handle = -1;
+ globals.manager = NULL;
+ globals.terminating = 0;
+ globals.daemon = false;
+
+ // logger (syslog)
+ setlogmask( LOG_UPTO( LOG_INFO ) );
+ openlog( PACKAGE_NAME, LOG_CONS, LOG_USER );
+
+ // signal handlers
+ init_signal_handlers();
+
+ }
+
+
+ void init_signal_handlers() {
+
+ sigset_t ignore_mask;
+
+ // set signal mask - signals we want to block
+ sigemptyset(&ignore_mask);
+ sigaddset(&ignore_mask, SIGTSTP); // ignore Tty stop signals
+ sigaddset(&ignore_mask, SIGTTOU); // ignore Tty background writes
+ sigaddset(&ignore_mask, SIGTTIN); // ignore Tty background reads
+ sigprocmask(SIG_BLOCK, &ignore_mask, NULL); // block the above specified signals
+
+ init_sigchld_handler();
+ init_sigterm_handler();
+ init_sigquit_handler();
+ init_sigint_handler();
+
+ }
+
+
+ void init_sigchld_handler() {
+
+ struct sigaction sa;
+
+ // block all other signals
+ sigfillset( &sa.sa_mask );
+
+ // signal handler proc
+ sa.sa_sigaction = &sigchld_handler;
+
+ // flags
+ sa.sa_flags = SA_SIGINFO;
+
+ if ( sigaction( SIGCHLD, &sa, NULL ) < 0 ) {
+ exit( EXIT_FAILURE );
+ }
+
+ }
+
+
+ void sigchld_handler( int sig, siginfo_t *siginfo, void *context ) {
+
+ pid_t worker_pid;
+ int status;
+
+ std::cout << "[" << getpid() << "] inside zombie deleter: ";
+ while ( ( worker_pid = waitpid( WAIT_ANY, &status, WNOHANG ) ) > 0 ) {
+ std::cout << "child " << worker_pid << " terminated with status " << status << std::endl;
+
+ if ( globals.manager != NULL ) {
+ globals.manager->reap_worker( worker_pid );
+ }
+ }
+
+ }
+
+
+ void init_sigterm_handler() {
+
+ struct sigaction sa;
+
+ // block all other signals
+ sigfillset( &sa.sa_mask );
+
+ // signal handler proc
+ sa.sa_sigaction = &sigterm_handler;
+
+ // flags
+ sa.sa_flags = SA_SIGINFO;
+
+ if ( sigaction( SIGTERM, &sa, NULL ) < 0 ) {
+ exit( EXIT_FAILURE );
+ }
+
+ }
+
+
+ void sigterm_handler( int sig, siginfo_t *siginfo, void *context ) {
+
+ std::cout << "[" << getpid() << "] inside SIGTERM handler" << std::endl;
+ termination_handler( sig, siginfo, context );
+
+ }
+
+
+ void init_sigquit_handler() {
+
+ struct sigaction sa;
+
+ // block all other signals
+ sigfillset( &sa.sa_mask );
+
+ // signal handler proc
+ sa.sa_sigaction = &sigquit_handler;
+
+ // flags
+ sa.sa_flags = SA_SIGINFO;
+
+ if ( sigaction( SIGQUIT, &sa, NULL ) < 0 ) {
+ exit( EXIT_FAILURE );
+ }
+
+ }
+
+
+ void sigquit_handler( int sig, siginfo_t *siginfo, void *context ) {
+
+ std::cout << "[" << getpid() << "] inside SIGQUIT handler" << std::endl;
+ termination_handler( sig, siginfo, context );
+
+ }
+
+
+ void init_sigint_handler() {
+
+ struct sigaction sa;
+
+ // block all other signals
+ sigfillset( &sa.sa_mask );
+
+ // signal handler proc
+ sa.sa_sigaction = &sigint_handler;
+
+ // flags
+ sa.sa_flags = SA_SIGINFO;
+
+ if ( sigaction( SIGINT, &sa, NULL ) < 0 ) {
+ exit( EXIT_FAILURE );
+ }
+
+ }
+
+
+ void sigint_handler( int sig, siginfo_t *siginfo, void *context ) {
+
+ std::cout << "[" << getpid() << "] inside SIGQINT handler" << std::endl;
+ termination_handler( sig, siginfo, context );
+
+ }
+
+
+ void daemonize( const char *rundir, const char *pidfile ) {
+
+ pid_t pid, sid;
+ long i;
+ char str[10];
+
+ // notify
+ syslog( LOG_NOTICE, "starting daemon (version %s)", PACKAGE_VERSION );
+
+ // check parent process id value
+ if ( getppid() == 1 ) {
+ // we are already a daemon
+ return;
+ }
+
+ /* fork daemon */
+ pid = fork();
+ if ( pid < 0 ) {
+ exit( EXIT_FAILURE );
+ }
+
+ // exit the parent
+ if ( pid > 0 ) {
+ exit( EXIT_SUCCESS );
+ }
+
+
+ /* child (a.k.a daemon) continues */
+
+ // set file permissions (750)
+ umask( 027 );
+
+ // get a new process group
+ sid = setsid();
+ if ( sid < 0 ) {
+ exit(EXIT_FAILURE);
+ }
+
+ // route I/O connections
+ close( STDIN_FILENO );
+ close( STDOUT_FILENO );
+ close( STDERR_FILENO );
+
+ // change running directory
+ chdir( rundir );
+
+
+ /* lock pid file to ensure we have only one copy */
+
+ globals.pid_handle = open( pidfile, O_RDWR | O_CREAT, 0600 );
+ if ( globals.pid_handle == -1 ) {
+ syslog( LOG_ERR, "could not open pid lock file: %s", pidfile );
+ exit( EXIT_FAILURE );
+ }
+
+ if ( lockf( globals.pid_handle, F_TLOCK, 0 ) == -1 ) {
+ syslog( LOG_ERR, "could not lock pid lock file: %s", pidfile);
+ exit( EXIT_FAILURE );
+ }
+
+ // get and format pid
+ sprintf( str, "%d\n", getpid() );
+
+ // write pid to lockfile
+ write( globals.pid_handle, str, strlen( str ) );
+
+ // update status
+ globals.daemon = true;
+
+
+ }
+
+
+ void shutdown() {
+
+ // notify
+ if ( globals.daemon && ( getppid() == 1 ) ) {
+ syslog( LOG_NOTICE, "shutting down daemon (version %s)", PACKAGE_VERSION );
+ }
+
+ // close pid file
+ if ( globals.pid_handle != -1 ) {
+ close( globals.pid_handle );
+ }
+
+ // close logger (syslog)
+ closelog();
+
+ }
+
+
+ void termination_handler( int sig, siginfo_t * sig_info, void * context ) {
+
+ std::cout << "[" << getpid() << "] inside termination handler" << std::endl;
+
+ // exit by re-raising the signal if termination
+ // already in progress
+ if ( globals.terminating ) {
+ std::cout << "[" << getpid() << "] already terminating" << std::endl;
+ raise( sig );
+ }
+
+ // update termination status
+ globals.terminating = 1;
+
+
+ if ( globals.manager != NULL ) {
+
+ // shutdown the manager
+ globals.manager->shutdown();
+
+ // clean-up
+ delete globals.manager;
+
+ }
+
+ // cleanup
+ shutdown();
+
+ // re-raise the signal after reactivating the signal's default action
+ signal( sig, SIG_DFL );
+ raise( sig );
+
+ }
+
+
+ options_t read_options( int argc, char **argv ) {
+
+ int optidx, optchar;
+ options_t options;
+
+ options.config_file = "";
+
+ struct option lopts[] = {
+ { "config", required_argument, 0, 'c' },
+ { "debug", no_argument, &options.debug_flag, 1 },
+ { "help", no_argument, 0, 'h' },
+ { "usage", no_argument, 0, 'h' },
+ { "version", no_argument, 0, 'v' },
+ { 0, 0, 0, 0 }
+ };
+
+ while ( true ) {
+
+ optidx = 0;
+ optchar = getopt_long( argc, argv, "c:hv", lopts, &optidx );
+
+ // sanity check
+ if ( optchar == -1 ) {
+ break;
+ }
+
+ switch ( optchar ) {
+ case 0:
+ // TODO:
+ break;
+
+ case 'c':
+ options.config_file = optarg;
+ break;
+
+ case 'h':
+ print_usage();
+ exit( EXIT_SUCCESS );
+ break;
+
+ case 'v':
+ print_version();
+ exit( EXIT_SUCCESS );
+
+ case '?':
+ print_usage();
+ exit( EXIT_FAILURE );
+ break;
+
+ default:
+ // TODO:
+ break;
+ }
+
+ }
+
+ return options;
+
+ }
+
+
+ void print_version() {
+
+ std::cout << PACKAGE_STRING << std::endl;
+ std::cout << "" << std::endl;
+ std::cout << "Copyright (C) 2012-2013 Uditha Atukorala" << std::endl;
+ std::cout << "" << std::endl;
+ std::cout << "This program is free software; you can redistribute it and/or modify" << std::endl;
+ std::cout << "it under the terms of the GNU General Public License as published by" << std::endl;
+ std::cout << "the Free Software Foundation; either version 3 of the License, or" << std::endl;
+ std::cout << "(at your option) any later version." << std::endl;
+ std::cout << "" << std::endl;
+ std::cout << "This program is distributed in the hope that it will be useful," << std::endl;
+ std::cout << "but WITHOUT ANY WARRANTY; without even the implied warranty of" << std::endl;
+ std::cout << "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the" << std::endl;
+ std::cout << "GNU General Public License (http://gnu.org/licenses/gpl.html)" << std::endl;
+ std::cout << "for more details." << std::endl;
+ std::cout << "" << std::endl;
+
+ }
+
+
+ void print_usage() {
+
+ std::cout << "usage: " << PACKAGE_NAME << " "
+ << "[--version] [--help] [--usage] [--debug] [--config=<config file>]"
+ << std::endl;
+
+ std::cout << "" << std::endl;
+ std::cout << "See the man pages for more information" << std::endl;
+
+ }
+
+
+ void start( int port, unsigned int children, int max_requests ) {
+
+ try {
+ globals.manager = new bitz::Manager( port );
+ globals.manager->spawn( children, max_requests );
+ } catch ( bitz::ManagerException &mex ) {
+ syslog( LOG_ERR, "failed to start, exception: %s", mex.what() );
+ exit( EXIT_FAILURE );
+ }
+
+ }
+
+
+ void run() {
+
+ sigset_t mask, oldmask;
+
+ // sanity check
+ if ( globals.manager == NULL ) {
+ return;
+ }
+
+ // block termination signals until we are ready
+ sigemptyset( &mask );
+ sigaddset( &mask, SIGTERM );
+ sigaddset( &mask, SIGQUIT );
+ sigaddset( &mask, SIGINT );
+ sigprocmask ( SIG_BLOCK, &mask, &oldmask );
+
+ // loop until a termination signal is received
+ while (! globals.terminating ) {
+
+ // capture any signals
+ sigsuspend( &oldmask );
+
+ // unblock termination signals
+ sigprocmask( SIG_UNBLOCK, &mask, NULL );
+
+ // manage workers
+ globals.manager->manager_workers();
+
+ // block termination signals
+ sigprocmask( SIG_BLOCK, &mask, &oldmask );
+
+ }
+
+ }
+
+ } /* end of namespace server */
+
+} /* end of namespace bitz */
+
+
+
diff --git a/src/bitz-server.h b/src/bitz-server.h
new file mode 100644
index 0000000..87129ad
--- /dev/null
+++ b/src/bitz-server.h
@@ -0,0 +1,113 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef BITZ_SERVER_H
+#define BITZ_SERVER_H
+
+#include "bitz/manager.h"
+
+#include <csignal>
+
+
+namespace bitz {
+
+ namespace server {
+
+ /**
+ * Structure to hold server globals initialised
+ * by the init() method.
+ */
+ struct server_t {
+ int pid_handle;
+ volatile sig_atomic_t terminating;
+ bool daemon;
+
+ bitz::Manager * manager;
+ };
+
+ /**
+ * Structure to hold command line options.
+ */
+ struct options_t {
+ int debug_flag;
+ std::string config_file;
+ };
+
+ void init();
+ void init_signal_handlers();
+ void init_sigchld_handler();
+ void init_sigterm_handler();
+ void init_sigquit_handler();
+ void init_sigint_handler();
+ void sigchld_handler( int sig, siginfo_t * sig_info, void * context );
+ void sigterm_handler( int sig, siginfo_t * sig_info, void * context );
+ void sigquit_handler( int sig, siginfo_t * sig_info, void * context );
+ void sigint_handler( int sig, siginfo_t * sig_info, void * context );
+
+ void daemonize( const char * run_dir, const char * pid_file );
+ void shutdown();
+ void termination_handler( int sig, siginfo_t * sig_info, void * context );
+
+ /**
+ * Read command line options and return a options_t structure.
+ * This method will terminate the program with an exit status
+ * of EXIT_FAILURE if any errors are found while reading options.
+ * If --version or --help options are found this will print the
+ * appropriate message to the standard output and terminate with
+ * EXIT_SUCCESS.
+ *
+ * @param argc same as main() argc
+ * @param argv same as main() argv
+ * @return read options
+ */
+ options_t read_options( int argc, char **argv );
+
+ /**
+ * Print version information to the standard output
+ */
+ void print_version();
+
+ /**
+ * Print usage message to the standard output
+ */
+ void print_usage();
+
+ /**
+ * Start the server by creating a bitz::Manager instance and spawn
+ * workers.
+ *
+ * @param port port number to listen to
+ * @param children number of children to spawn
+ * @param max_request maximum number of requests that a child will serve
+ */
+ void start( int port, unsigned int children, int max_requests );
+
+ /**
+ * Run the server managing workers until a termination signal is received.
+ * This process will never return, instead the termination signal will
+ * end the process.
+ */
+ void run();
+
+ } /* end of namespace server */
+
+} /* end of namespace bitz */
+
+#endif /* !BITZ_SERVER_H */
+
diff --git a/src/bitz/common.h b/src/bitz/common.h
new file mode 100644
index 0000000..5b03948
--- /dev/null
+++ b/src/bitz/common.h
@@ -0,0 +1,40 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef BITZ_COMMON_H
+#define BITZ_COMMON_H
+
+#include <string>
+#include <map>
+
+#include "request_handler.h"
+
+
+namespace bitz {
+
+ /* request handlers type */
+ typedef std::map<std::string, RequestHandler *> req_handlers_t;
+
+ /* iterator type */
+ typedef req_handlers_t::iterator req_handlers_index_t;
+
+} /* end of namespace bitz */
+
+#endif /* !BITZ_COMMIN_H */
+
diff --git a/src/bitz/config.cpp b/src/bitz/config.cpp
new file mode 100644
index 0000000..a9ca856
--- /dev/null
+++ b/src/bitz/config.cpp
@@ -0,0 +1,190 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "config.h"
+#include "logger.h"
+
+#include <iostream>
+#include <cstdlib>
+
+
+namespace bitz {
+
+ Config::Config() {
+
+ // initialise config_t values
+ _config.port = 1344;
+ _config.pid_file = "/dev/null";
+ _config.log_file = "/dev/null";
+ _config.log_category = "bitz";
+ _config.req_handlers_count = 0;
+ _config.req_handlers = NULL;
+
+ _config.max_workers = 0;
+ _config.max_worker_requests = 0;
+
+
+ // defaults
+ _lconfig = NULL;
+
+ }
+
+ Config::~Config() {
+
+ // cleanup
+ delete _lconfig;
+
+ for (int i = 0; i < _config.req_handlers_count ; i++ ) {
+ if ( _config.req_handlers[i].modules_count > 0 ) {
+ delete [] _config.req_handlers[i].modules;
+ }
+ }
+
+ if ( _config.req_handlers != NULL ) {
+ delete [] _config.req_handlers;
+ }
+
+ }
+
+
+ const config_t &Config::initialise( const std::string &config_file ) {
+
+ libconfig::Config * config;
+ config = new libconfig::Config;
+
+ try {
+ config->readFile( config_file.c_str() );
+ } catch( const libconfig::FileIOException &ex ) {
+ std::cerr << "[config] failed to read config file: " << config_file
+ << ", exception: " << ex.what() << std::endl;
+ exit( EXIT_FAILURE );
+ } catch( const libconfig::ParseException &pex ) {
+ std::cerr << "[config] parse error at " << pex.getFile()
+ << ":" << pex.getLine() << " - " << pex.getError() << std::endl;
+ exit( EXIT_FAILURE );
+ }
+
+ try {
+
+ // read core configs
+ config->lookupValue( "port", _config.port );
+ config->lookupValue( "pid_file", _config.pid_file );
+ config->lookupValue( "log_file", _config.log_file );
+ config->lookupValue( "log_category", _config.log_category );
+
+ config->lookupValue( "max_workers", _config.max_workers );
+ config->lookupValue( "max_worker_requests", _config.max_worker_requests );
+
+ } catch( const libconfig::SettingNotFoundException &e ) {
+ std::cerr << "[config] failed to load core configs, "
+ << e.getPath() << " : " << e.what() << std::endl;
+ }
+
+ // cache configs
+ _lconfig = config;
+
+ // read other configs
+ read_req_handler_configs();
+
+ return _config;
+
+ }
+
+
+ const config_t &Config::configs() {
+ return _config;
+ }
+
+
+ const std::string Config::module_config( const std::string &module, const std::string &config ) throw() {
+
+ std::string config_value = "";
+
+ if ( _lconfig->exists( "modules" ) ) {
+
+ try {
+ libconfig::Setting &setting = _lconfig->lookup( std::string( "modules." ).append( module ) );
+ setting.lookupValue( config, config_value );
+ } catch( const libconfig::SettingNotFoundException &e ) {
+ // TODO: log errors ??
+ std::cerr << "[config] " << e.getPath() << " : " << e.what() << std::endl;
+ }
+
+ } else {
+ std::cout << "[config] 'modules' configs not found" << std::endl;
+ }
+
+ return config_value;
+
+ }
+
+
+ void Config::read_req_handler_configs() throw() {
+
+ int i, j;
+ std::string s;
+
+ std::cout << "[config] looking for req_handlers... ";
+ if ( _lconfig->exists( "req_handlers" ) ) {
+
+ std::cout << "found ";
+
+ libconfig::Setting &req_handlers = _lconfig->lookup( "req_handlers" );
+ _config.req_handlers_count = req_handlers.getLength();
+ _config.req_handlers = new req_handlers_config_t[_config.req_handlers_count];
+
+ std::cout << "(" << _config.req_handlers_count << ")" << std::endl;
+
+ try {
+
+ // read request handler configs
+ for ( i = 0; i < _config.req_handlers_count ; i++ ) {
+ _config.req_handlers[i].name = (const char *) req_handlers[i]["handler"];
+ _config.req_handlers[i].class_name = (const char *) req_handlers[i]["class"];
+
+ // read request handler modules config
+ std::cout << "[config] looking for " << _config.req_handlers[i].name << " modules... ";
+ if ( req_handlers[i].exists( "modules" ) ) {
+ std::cout << "found ";
+
+ _config.req_handlers[i].modules_count = req_handlers[i]["modules"].getLength();
+ _config.req_handlers[i].modules = new modules_config_t[_config.req_handlers[i].modules_count];
+
+ std::cout << "(" << _config.req_handlers[i].modules_count << ")" << std::endl;
+ for ( j = 0; j < _config.req_handlers[i].modules_count; j++ ) {
+ _config.req_handlers[i].modules[j].name = (const char *) req_handlers[i]["modules"][j]["name"];
+ _config.req_handlers[i].modules[j].module = (const char *) req_handlers[i]["modules"][j]["module"];
+ }
+ } else {
+ std::cout << "not found" << std::endl;
+ }
+ }
+
+ } catch ( const libconfig::SettingNotFoundException &ex ) {
+ std::cerr << "[config] Error: " << ex.getPath() << ex.what() << std::endl;
+ }
+
+ } else {
+ std::cout << "not found" << std::endl;
+ }
+
+ }
+
+} /* end of namespace bitz */
+
diff --git a/src/bitz/config.h b/src/bitz/config.h
new file mode 100644
index 0000000..453d29d
--- /dev/null
+++ b/src/bitz/config.h
@@ -0,0 +1,95 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef BITZ_CONFIG_H
+#define BITZ_CONFIG_H
+
+#include <string>
+#include <libconfig.h++>
+
+
+#ifndef BITZ_SERVER_CONFIG_FILE
+#define BITZ_SERVER_CONFIG_FILE "/etc/bitz/bitz-server.conf"
+#endif
+
+namespace bitz {
+
+ struct modules_config_t {
+ std::string name;
+ std::string module;
+ };
+
+ struct req_handlers_config_t {
+ std::string name;
+ std::string class_name;
+ unsigned int modules_count;
+
+ modules_config_t * modules;
+ };
+
+ struct config_t {
+ int port;
+ int max_workers;
+ int max_worker_requests;
+ std::string pid_file;
+ std::string log_file;
+ std::string log_category;
+ unsigned int req_handlers_count;
+
+ req_handlers_config_t * req_handlers;
+ };
+
+ class Config {
+ public:
+ static Config &instance() {
+ static Config config;
+ return config;
+ }
+
+ const config_t &initialise( const std::string &config_file = BITZ_SERVER_CONFIG_FILE );
+ const config_t &configs();
+
+ /**
+ * Returns module specific config value (or NULL string if not found)
+ * Note: This method should be only used my the pluggable modules and not
+ * by the core code.
+ *
+ * @param module module name
+ * @param config config name
+ * @return module config value
+ */
+ const std::string module_config( const std::string &module, const std::string &config ) throw();
+
+ private:
+ config_t _config;
+ libconfig::Config * _lconfig;
+
+ Config();
+ ~Config();
+ Config( Config const &copy );
+ Config &operator=( const Config &copy );
+
+ void read_req_handler_configs() throw();
+
+ };
+
+} /* end of namespace bitz */
+
+#endif /* !BITZ_CONFIG_H */
+
diff --git a/src/bitz/exception.cpp b/src/bitz/exception.cpp
new file mode 100644
index 0000000..bf8be9e
--- /dev/null
+++ b/src/bitz/exception.cpp
@@ -0,0 +1,40 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "exception.h"
+#include <cerrno> // For errno
+#include <cstring> // For strerror
+
+namespace bitz {
+
+ Exception::Exception( const std::string &message, bool inclSystemMessage ) throw() : _message( message ) {
+ if ( inclSystemMessage ) {
+ _message.append( " : " );
+ _message.append( strerror( errno ) );
+ }
+ }
+
+ Exception::~Exception() throw() { }
+
+ const char * Exception::what() const throw() {
+ return _message.c_str();
+ }
+
+} /* end of namespace bitz */
+
diff --git a/src/bitz/exception.h b/src/bitz/exception.h
new file mode 100644
index 0000000..54abdcd
--- /dev/null
+++ b/src/bitz/exception.h
@@ -0,0 +1,43 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+
+#ifndef BITZ_EXCEPTION_H
+#define BITZ_EXCEPTION_H
+
+#include <exception> // for exception class
+#include <string> // for std::string
+
+namespace bitz {
+
+ class Exception : public std::exception {
+ public:
+ Exception( const std::string &message, bool inclSystemMessage = false ) throw();
+ virtual ~Exception() throw();
+
+ virtual const char * what() const throw();
+
+ private:
+ std::string _message;
+ };
+
+} /* end of namespace bitz */
+
+#endif /* !BITZ_EXCEPTION_H */
+
diff --git a/src/bitz/logger.cpp b/src/bitz/logger.cpp
new file mode 100644
index 0000000..1d7d833
--- /dev/null
+++ b/src/bitz/logger.cpp
@@ -0,0 +1,98 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "logger.h"
+
+#include <log4cpp/FileAppender.hh>
+#include <log4cpp/PatternLayout.hh>
+
+namespace bitz {
+
+ Logger::Logger( std::string log_file, std::string category ) {
+ this->LOGGER = NULL;
+ this->initialise( log_file, category );
+ }
+
+ Logger::~Logger() {
+ this->LOGGER->debug( "closing down logger" );
+ }
+
+ void Logger::initialise( std::string log_file, std::string category ) {
+
+ this->LOGGER = &log4cpp::Category::getInstance( category );
+
+ // setting up appender, layout and category
+ log4cpp::Appender * log_appender = new log4cpp::FileAppender( "FileAppender", log_file );
+ log4cpp::PatternLayout * log_layout = new log4cpp::PatternLayout();
+ log_layout->setConversionPattern( "%d %p %c %x: %m%n" );
+
+ log_appender->setLayout( log_layout );
+ this->LOGGER->setAppender( log_appender );
+ this->LOGGER->setPriority( this->getPriorityValue( "DEBUG" ) );
+
+ this->LOGGER->debug( "logger initialised, log_file: " + log_file );
+
+ }
+
+ int Logger::getPriorityValue( const std::string &priority ) {
+ return ( log4cpp::Priority::getPriorityValue( priority ) );
+ }
+
+ void Logger::log( log4cpp::Priority::Value priority, const std::string &message ) {
+ this->LOGGER->log( priority, message );
+ }
+
+ void Logger::fatal( const std::string& message ) {
+ this->LOGGER->fatal( message );
+ }
+
+ void Logger::emerg( const std::string& message ) {
+ this->LOGGER->emerg( message );
+ }
+
+ void Logger::alert( const std::string& message ) {
+ this->LOGGER->alert( message );
+ }
+
+ void Logger::crit( const std::string& message ) {
+ this->LOGGER->crit( message );
+ }
+
+ void Logger::error( const std::string& message ) {
+ this->LOGGER->error( message );
+ }
+
+ void Logger::warn( const std::string& message ) {
+ this->LOGGER->warn( message );
+ }
+
+ void Logger::notice( const std::string& message ) {
+ this->LOGGER->notice( message );
+ }
+
+ void Logger::info( const std::string& message ) {
+ this->LOGGER->info( message );
+ }
+
+ void Logger::debug( const std::string& message ) {
+ this->LOGGER->debug( message );
+ }
+
+} /* end of namespace bitz */
+
diff --git a/src/bitz/logger.h b/src/bitz/logger.h
new file mode 100644
index 0000000..f1c9c6c
--- /dev/null
+++ b/src/bitz/logger.h
@@ -0,0 +1,62 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef BITZ_LOGGER_H
+#define BITZ_LOGGER_H
+
+#include <string>
+#include <log4cpp/Category.hh>
+
+namespace bitz {
+
+ class Logger {
+ public:
+ static Logger &instance( std::string log_file = "/dev/null" , std::string category = "logger" ) {
+ static Logger logger( log_file, category );
+ return logger;
+ }
+
+ void initialise( std::string log_file, std::string category );
+
+ static int getPriorityValue( const std::string& priority );
+ void log( int priority, const std::string &message );
+
+ void fatal( const std::string& message );
+ void emerg( const std::string& message );
+ void alert( const std::string& message );
+ void crit( const std::string& message );
+ void error( const std::string& message );
+ void warn( const std::string& message );
+ void notice( const std::string& message );
+ void info( const std::string& message );
+ void debug( const std::string& message );
+
+ private:
+ log4cpp::Category * LOGGER;
+
+ Logger( std::string log_file, std::string category );
+ ~Logger();
+ Logger( Logger const &copy );
+ Logger &operator=( const Logger &copy );
+ };
+
+} /* end of namespace bitz */
+
+#endif /* !BITZ_LOGGER_H */
+
diff --git a/src/bitz/manager.cpp b/src/bitz/manager.cpp
new file mode 100644
index 0000000..ffa2dae
--- /dev/null
+++ b/src/bitz/manager.cpp
@@ -0,0 +1,223 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "manager.h"
+#include "logger.h"
+#include "util.h"
+
+#include <cstdlib>
+#include <sstream>
+#include <csignal>
+
+
+namespace bitz {
+
+ Manager::Manager( unsigned short port, const std::string &address, int backlog ) throw( ManagerException ) {
+
+ // initialise manager
+ _manager.worker = false;
+ _manager.max_workers = 0;
+ _manager.workers_count = 0;
+ _manager.worker_id = 0;
+ _manager.socket = NULL;
+ _manager.worker_pool = NULL;
+
+ // initialise listening socket
+ try {
+ if ( address.empty() ) {
+ _manager.socket = new socketlibrary::TCPServerSocket( port, backlog );
+ } else {
+ _manager.socket = new socketlibrary::TCPServerSocket( address, port, backlog );
+ }
+ } catch ( socketlibrary::SocketException &sex ) {
+ throw ManagerException( "failed to initialise socket" );
+ }
+
+ Logger &logger = Logger::instance();
+ logger.debug( "manager initialised" );
+
+ }
+
+
+ Manager::~Manager() {
+
+ Logger &logger = Logger::instance();
+
+ if ( _manager.worker ) {
+ logger.debug( "[worker] cleaning up manager" );
+ } else {
+ logger.debug( "[manager] shutting down manager" );
+ }
+
+ delete [] _manager.worker_pool;
+ delete _manager.socket;
+
+ }
+
+
+ void Manager::spawn( unsigned int max_workers, unsigned int max_worker_requests ) throw( ManagerException ) {
+
+ _manager.max_workers = max_workers;
+ _manager.max_worker_requests = max_worker_requests;
+ _manager.worker_pool = new worker_pool_t[max_workers];
+
+ // pre-fork workers
+ if (! _manager.worker ) {
+ for ( unsigned int i = 0; i < max_workers; i++ ) {
+
+ try {
+ spawn_worker( i );
+ } catch ( ManagerException &mex ) {
+ throw mex;
+ }
+
+ }
+ }
+
+ }
+
+
+ void Manager::spawn_worker( unsigned int worker_id ) throw( ManagerException ) {
+
+ Logger &logger = Logger::instance();
+ pid_t worker_pid;
+
+ // create a worker child
+ worker_pid = fork();
+ if ( worker_pid == -1 ) {
+ throw ManagerException( "failed to create worker", true );
+ }
+
+ if ( worker_pid == 0 ) {
+
+ /* worker */
+
+ _manager.worker = true;
+ _manager.worker_id = worker_id;
+ _manager.worker_pool[worker_id].worker = new Worker();
+ _manager.worker_pool[worker_id].worker_id = worker_id;
+ _manager.worker_pool[worker_id].worker_pid = worker_pid;
+
+ _manager.worker_pool[worker_id].worker->run( _manager.socket, _manager.max_worker_requests );
+ logger.info( std::string( "end of cycle, worker[" ).append( util::itoa( worker_id ) ).append( "]" ) );
+
+ delete _manager.worker_pool[worker_id].worker;
+ _exit( EXIT_SUCCESS );
+
+ } else {
+
+ /* manager */
+ logger.info( std::string( "[manager] worker spawned with pid: " ).append( util::itoa( worker_pid) ) );
+
+ _manager.workers_count++;
+
+ _manager.worker = false;
+ _manager.worker_pool[worker_id].worker = NULL;
+ _manager.worker_pool[worker_id].worker_id = worker_id;
+ _manager.worker_pool[worker_id].worker_pid = worker_pid;
+
+ }
+
+ }
+
+
+ void Manager::shutdown( bool graceful ) throw() {
+
+ // logger
+ Logger &logger = Logger::instance();
+
+ if ( _manager.worker ) {
+
+ logger.info( "[worker] manager shutdown request received" );
+
+ /* worker: cleanup */
+ delete _manager.worker_pool[_manager.worker_id].worker;
+
+ } else {
+
+ /* manager: stop all child processes */
+ logger.info( "[manager] shutdown request received" );
+
+ for (unsigned int i = 0; i < _manager.max_workers; i++ ) {
+ if ( _manager.worker_pool[i].worker_pid != 0 ) {
+ if ( graceful ) {
+ kill( _manager.worker_pool[i].worker_pid, SIGTERM );
+ logger.debug( std::string( "[manager] sending SIGTERM to worker[" ).append( util::itoa( i ) )
+ .append( "], pid: " ).append( util::itoa( _manager.worker_pool[i].worker_pid ) ) );
+ } else {
+ kill( _manager.worker_pool[i].worker_pid, SIGKILL );
+ logger.debug( std::string( "[manager] sending SIGKILL to worker[" ).append( util::itoa( i ) )
+ .append( "], pid: " ).append( util::itoa( _manager.worker_pool[i].worker_pid ) ) );
+ }
+ } else {
+ logger.debug( std::string( "[manager] worker[" ).append( util::itoa( i ) ).append( "] already closed" ) );
+ }
+ }
+ }
+
+ }
+
+
+ void Manager::reap_worker( pid_t worker_pid ) throw() {
+
+ // logger
+ Logger &logger = Logger::instance();
+ logger.debug( std::string( "reaping worker, pid: " ).append( util::itoa( worker_pid ) ) );
+
+ if (! _manager.worker ) {
+ for (unsigned int i = 0; i < _manager.max_workers; i++ ) {
+ if ( _manager.worker_pool[i].worker_pid == worker_pid ) {
+
+ // reap the dead worker
+ _manager.worker_pool[i].worker_pid = 0;
+ _manager.workers_count--;
+
+ // break out the loop
+ break;
+
+ }
+ }
+ }
+
+ }
+
+
+ void Manager::manager_workers() throw() {
+
+ if (! _manager.worker ) {
+
+ // check the worker count
+ while ( _manager.workers_count != _manager.max_workers ) {
+
+ // we are missing workers, find out who
+ for (unsigned int i = 0; i < _manager.max_workers; i++ ) {
+ if ( _manager.worker_pool[i].worker_pid == 0 ) {
+ // spawn a worker for the missing
+ spawn_worker( i );
+ }
+ }
+
+ }
+
+ }
+
+ }
+
+} /* end of namespace bitz */
+
diff --git a/src/bitz/manager.h b/src/bitz/manager.h
new file mode 100644
index 0000000..cc15f9c
--- /dev/null
+++ b/src/bitz/manager.h
@@ -0,0 +1,87 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef BITZ_MANAGER_H
+#define BITZ_MANAGER_H
+
+#include <unistd.h> // pid_t, fork() etc.
+#include <socket/socket.h> // socket-library
+
+#include "manager_exception.h"
+#include "worker.h"
+
+#ifndef BITZ_MAX_WORKERS
+#define BITZ_MAX_WORKERS 2
+#endif
+
+#ifndef BITZ_MAX_WORKER_REQUESTS
+#define BITZ_MAX_WORKER_REQUESTS 100
+#endif
+
+
+namespace bitz {
+
+ class Manager {
+ public:
+
+ struct worker_pool_t {
+ pid_t worker_pid;
+ unsigned int worker_id;
+ Worker * worker;
+ };
+
+ struct manager_t {
+ bool worker;
+ unsigned int max_workers;
+ unsigned int max_worker_requests;
+ unsigned int workers_count;
+ unsigned int worker_id;
+
+ socketlibrary::TCPServerSocket * socket;
+ worker_pool_t * worker_pool;
+ };
+
+
+ /**
+ * Note: backlog = SOMAXCONN (from sys/socket.h)
+ */
+ Manager( unsigned short port, const std::string &address = "", int backlog = 128 ) throw( ManagerException );
+
+ /**
+ * deconstructor
+ */
+ virtual ~Manager();
+
+ virtual void spawn( unsigned int max_workers = BITZ_MAX_WORKERS, unsigned int max_worker_requests = BITZ_MAX_WORKER_REQUESTS ) throw( ManagerException );
+ virtual void shutdown( bool graceful = true ) throw();
+ virtual void reap_worker( pid_t worker_pid ) throw();
+ virtual void manager_workers() throw();
+
+
+ private:
+ manager_t _manager;
+
+ virtual void spawn_worker( unsigned int worker_id ) throw( ManagerException );
+
+ };
+
+} /* end of namespace bitz */
+
+#endif /* !BITZ_MANAGER_H */
+
diff --git a/src/bitz/manager_exception.cpp b/src/bitz/manager_exception.cpp
new file mode 100644
index 0000000..d49f58a
--- /dev/null
+++ b/src/bitz/manager_exception.cpp
@@ -0,0 +1,32 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "manager_exception.h"
+
+namespace bitz {
+
+ ManagerException::ManagerException( const std::string &message, bool inclSystemMessage ) throw() :
+ Exception( message, inclSystemMessage ) {
+ // constructor
+ }
+
+ ManagerException::~ManagerException() throw() { }
+
+} /* end of namespace bitz */
+
diff --git a/src/bitz/manager_exception.h b/src/bitz/manager_exception.h
new file mode 100644
index 0000000..0729ef0
--- /dev/null
+++ b/src/bitz/manager_exception.h
@@ -0,0 +1,36 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef BITZ_MANAGER_EXCEPTION_H
+#define BITZ_MANAGER_EXCEPTION_H
+
+#include "exception.h"
+
+namespace bitz {
+
+ class ManagerException: public Exception {
+ public:
+ ManagerException( const std::string &message, bool inclSystemMessage = false ) throw();
+ virtual ~ManagerException() throw();
+ };
+
+} /* end of namespace bitz */
+
+#endif /* BITZ_MANAGER_EXCEPTION_H */
+
diff --git a/src/bitz/modifier.cpp b/src/bitz/modifier.cpp
new file mode 100644
index 0000000..a0a416f
--- /dev/null
+++ b/src/bitz/modifier.cpp
@@ -0,0 +1,29 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "modifier.h"
+
+
+namespace bitz {
+
+ Modifier::Modifier() { }
+ Modifier::~Modifier() { }
+
+} /* end of namespace bitz */
+
diff --git a/src/bitz/modifier.h b/src/bitz/modifier.h
new file mode 100644
index 0000000..7f189aa
--- /dev/null
+++ b/src/bitz/modifier.h
@@ -0,0 +1,70 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef BITZ_MODIFIER_H
+#define BITZ_MODIFIER_H
+
+#include <icap/request.h>
+#include <icap/response.h>
+
+
+namespace bitz {
+
+ class Modifier {
+ public:
+
+ /* types of the class factories */
+ typedef bitz::Modifier * create_t();
+ typedef void destroy_t( bitz::Modifier * );
+
+ struct symbols_t {
+ void * modifier;
+ create_t * create;
+ destroy_t * destroy;
+ };
+
+ Modifier();
+ virtual ~Modifier();
+
+ /**
+ * Modify the request as needed and return a response object.
+ *
+ * @param request request object
+ * @return response object
+ */
+ virtual icap::Response * modify( icap::Request * request ) throw() =0;
+
+ /**
+ * Preview the request passed in and return a response object. The
+ * response status of 100 (continue) should be handled by the caller
+ * and pass the complete request to modify() method.
+ *
+ * @param request request object
+ * @return response object
+ */
+ virtual icap::Response * preview( icap::Request * request ) throw() =0;
+
+ private:
+
+ };
+
+} /* end of namespace bitz */
+
+#endif /* !BITZ_MODIFIER_H */
+
diff --git a/src/bitz/options_request_handler.cpp b/src/bitz/options_request_handler.cpp
new file mode 100644
index 0000000..6872b5c
--- /dev/null
+++ b/src/bitz/options_request_handler.cpp
@@ -0,0 +1,57 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "options_request_handler.h"
+
+
+namespace bitz {
+
+ OptionsRequestHandler::OptionsRequestHandler() : RequestHandler( "OPTIONS" ) { }
+ OptionsRequestHandler::~OptionsRequestHandler() { }
+
+
+ icap::Response * OptionsRequestHandler::process( icap::RequestHeader * req_header, socketlibrary::TCPSocket * socket ) throw() {
+
+ icap::ResponseHeader * header;
+ icap::Response * response;
+
+ // header
+ header = new icap::ResponseHeader( icap::ResponseHeader::OK );
+
+ // FIXME: Methods are tied to the URIs
+ header->attach( "Methods", _methods.at( 0 ) );
+ header->attach( "Options-TTL", "3600" );
+ header->attach( "Allow", "204" );
+
+ response = new icap::Response( header );
+ return response;
+
+ }
+
+
+ void OptionsRequestHandler::register_handler( RequestHandler * req_handler ) throw() {
+
+ // FIXME: Methods are tied to the URIs
+ _methods.push_back( req_handler->method() );
+ return;
+
+ }
+
+} /* end of namespace bitz */
+
diff --git a/src/bitz/options_request_handler.h b/src/bitz/options_request_handler.h
new file mode 100644
index 0000000..a81377f
--- /dev/null
+++ b/src/bitz/options_request_handler.h
@@ -0,0 +1,51 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef BITZ_OPTIONS_REQUEST_HANDLER_H
+#define BITZ_OPTIONS_REQUEST_HANDLER_H
+
+#include "request_handler.h"
+
+
+namespace bitz {
+
+ class OptionsRequestHandler : public RequestHandler {
+ public:
+ OptionsRequestHandler();
+ virtual ~OptionsRequestHandler();
+
+ icap::Response * process( icap::RequestHeader * req_header, socketlibrary::TCPSocket * socket ) throw();
+
+ /**
+ * Register a request handler so it is known to the OPTIONS
+ * handler
+ *
+ * @param req_handler request handler
+ */
+ void register_handler( RequestHandler * req_handler ) throw();
+
+ private:
+ std::vector<std::string> _methods;
+
+ };
+
+} /* end of namespace bitz */
+
+#endif /* !BITZ_OPTIONS_REQUEST_HANDLER_H */
+
diff --git a/src/bitz/reqmod_request_handler.cpp b/src/bitz/reqmod_request_handler.cpp
new file mode 100644
index 0000000..7b1f0a2
--- /dev/null
+++ b/src/bitz/reqmod_request_handler.cpp
@@ -0,0 +1,30 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "reqmod_request_handler.h"
+
+
+namespace bitz {
+
+ ReqmodRequestHandler::ReqmodRequestHandler() : RequestHandler( "REQMOD" ) { }
+
+ ReqmodRequestHandler::~ReqmodRequestHandler() { }
+
+} /* end of namespace bitz */
+
diff --git a/src/bitz/reqmod_request_handler.h b/src/bitz/reqmod_request_handler.h
new file mode 100644
index 0000000..b267c07
--- /dev/null
+++ b/src/bitz/reqmod_request_handler.h
@@ -0,0 +1,41 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef BITZ_REQMOD_REQUEST_HANDLER_H
+#define BITZ_REQMOD_REQUEST_HANDLER_H
+
+#include "request_handler.h"
+
+
+namespace bitz {
+
+ class ReqmodRequestHandler : public RequestHandler {
+ public:
+
+ ReqmodRequestHandler();
+ virtual ~ReqmodRequestHandler();
+
+ private:
+
+ };
+
+} /* end of namespace bitz */
+
+#endif /* !BITZ_REQMOD_REQUEST_HANDLER_H */
+
diff --git a/src/bitz/request_handler.cpp b/src/bitz/request_handler.cpp
new file mode 100644
index 0000000..3665cba
--- /dev/null
+++ b/src/bitz/request_handler.cpp
@@ -0,0 +1,401 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "request_handler.h"
+#include "config.h"
+#include "logger.h"
+#include "util.h"
+
+#include <dlfcn.h>
+#include <icap/util.h>
+
+
+namespace bitz {
+
+ RequestHandler::RequestHandler( const std::string &method ) {
+
+ // initialise defaults
+ _handlers_count = 0;
+ _handlers = NULL;
+
+ // update variables
+ _req_handler.method = method;
+
+ // load modifier modules
+ load_modules();
+
+ }
+
+
+ RequestHandler::~RequestHandler() {
+
+ // cleanup modifier modules
+ cleanup_modules();
+
+ if ( _handlers != NULL ) {
+ delete [] _handlers;
+ }
+
+ Logger &logger = Logger::instance();
+ logger.debug( std::string( "[req] exiting request handler [" ).append( _req_handler.method ).append( "]" ) );
+
+ }
+
+
+ const std::string &RequestHandler::method() const throw() {
+ return _req_handler.method;
+ }
+
+
+ icap::Response * RequestHandler::process( icap::RequestHeader * req_header, socketlibrary::TCPSocket * socket ) throw() {
+
+
+ icap::Request * request;
+ icap::Response * response = NULL;
+
+ // logger
+ Logger &logger = Logger::instance();
+
+
+ // request
+ request = new icap::Request( req_header );
+
+ // read request data
+ if (! icap::util::read_req_data( request, socket ) ) {
+
+ logger.warn( "[req] failed to read request data" );
+ response = new icap::Response( icap::ResponseHeader::SERVER_ERROR );
+
+ } else {
+
+ logger.debug( std::string( "[req] payload.req-hdr:\r\n").append( request->payload().req_header ) );
+ logger.debug( std::string( "[req] payload.req-body:\r\n").append( request->payload().req_body ) );
+ logger.debug( std::string( "[req] payload.res-hdr:\r\n").append( request->payload().res_header ) );
+ logger.debug( std::string( "[req] payload.res-body:\r\n").append( request->payload().res_body ) );
+
+
+ // check for message preview
+ if ( request->preview_size() >= 0 ) {
+
+ // process preview
+ logger.debug( std::string( "[req] message preview request, preview: " ).append( util::itoa( request->preview_size() ) ) );
+ response = process_preview( request, socket );
+
+ }
+
+ /*
+ * When we get here, if the response is NULL then either this is a
+ * pure REQMOD request without message preview or the preview was
+ * inconclusive (i.e. 100 Continue) and we have requested for the full
+ * request.
+ */
+ if ( response == NULL ) {
+
+ // process modify
+ logger.debug( "[req] modify request" );
+ response = process_modify( request );
+
+ }
+
+ }
+
+ // cleanup
+ delete request;
+
+ // sanity check
+ if ( response == NULL ) {
+ logger.warn( "[req] no valid response from modifiers, creating a server error (500) response" );
+ response = new icap::Response( icap::ResponseHeader::SERVER_ERROR );
+ }
+
+ return response;
+
+ }
+
+
+ bool RequestHandler::load_modifier( const std::string &file, Modifier::symbols_t &symbols ) throw() {
+
+ // logger
+ Logger &logger = Logger::instance();
+
+ // vars
+ const char* dlsym_error;
+
+ // load the modifier module
+ logger.debug( "[req] loading modifier: " + file );
+ symbols.modifier = dlopen( file.c_str(), RTLD_LAZY | RTLD_LOCAL );
+
+ if (! symbols.modifier ) {
+ logger.warn( std::string( "[req] failed to load modifier: " ).append( file ).append( dlerror() ) );
+ return false;
+ }
+
+ // reset errors
+ dlerror();
+
+ // load the symbols
+ symbols.create = ( Modifier::create_t * ) dlsym( symbols.modifier, "create" );
+ dlsym_error = dlerror();
+
+ if ( dlsym_error ) {
+ logger.warn( std::string( "[req] failed to load create symbol: " ).append( dlsym_error ) );
+ return false;
+ }
+
+ symbols.destroy = ( Modifier::destroy_t * ) dlsym( symbols.modifier, "destroy" );
+ dlsym_error = dlerror();
+
+ if ( dlsym_error ) {
+ logger.warn( std::string( "[req] failed to load destroy symbol: " ).append( dlsym_error ) );
+ return false;
+ }
+
+ return true;
+
+ }
+
+
+ void RequestHandler::unload_modifier( void * modifier ) throw() {
+ // unload the modifier module
+ dlclose( modifier );
+ }
+
+
+ void RequestHandler::load_modules() throw() {
+
+ int i = 0;
+ int j = 0;
+ const bitz::config_t &config = Config::instance().configs();
+
+ // search for request handlers
+ for ( i = 0; i < config.req_handlers_count; i++ ) {
+
+ // we are only interested in handlers for the current method (e.g. REQMOD, RESPMOD)
+ if ( config.req_handlers[i].name == method() ) {
+
+ if ( config.req_handlers[i].modules_count > 0 ) {
+
+ _handlers_count = config.req_handlers[i].modules_count;
+ _handlers = new handler_t[_handlers_count];
+
+ // search for request handler modules
+ for (j = 0; j < _handlers_count; j++ ) {
+
+ // load module
+ if ( load_modifier( config.req_handlers[i].modules[j].module, _handlers[j].symbols ) ) {
+ _handlers[j].name = config.req_handlers[i].modules[j].name;
+ } else {
+ _handlers[j].name = "";
+ // FIXME: error handling
+ }
+
+ }
+
+ }
+
+ // not interested in duplicate config entries
+ break;
+ }
+
+ }
+
+
+ }
+
+
+ void RequestHandler::cleanup_modules() throw() {
+
+ int i = 0;
+
+ // logger
+ Logger &logger = Logger::instance();
+
+ for ( i = 0; i < _handlers_count; i++ ) {
+
+ logger.debug( std::string( "[req] unloading module: " ).append( _handlers[i].name ) );
+
+ // unload
+ unload_modifier( _handlers[i].symbols.modifier );
+
+ }
+
+ }
+
+
+ icap::Response * RequestHandler::process_preview( icap::Request * request, socketlibrary::TCPSocket * socket ) throw() {
+
+ icap::Response * response = NULL;
+ Modifier * modifier;
+
+ int i = 0;
+ bool continue_status = false;
+
+ // logger
+ Logger &logger = Logger::instance();
+
+
+ /*
+ * Loop through loaded modifier modules and grab responses
+ *
+ * We will only get a chance to get a response from the first
+ * module. But if the first module returns a '100 Continue' response
+ * then we read the rest of the request here before returning a NULL
+ * response.
+ */
+ for ( i = 0 ; i < _handlers_count; i++ ) {
+
+ // sanity check
+ if ( _handlers[i].name == "" ) {
+ logger.info( "[req] modifier not loaded, not trying to get a response" );
+ continue;
+ }
+
+ // grab the response from modifier
+ logger.debug( std::string( "[req] getting preview response from modifier: " ).append( _handlers[i].name ) );
+ modifier = _handlers[i].symbols.create();
+ response = modifier->preview( request );
+
+ // cleanup
+ logger.debug( std::string( "[req] cleaning up modifier: " ).append( _handlers[i].name ) );
+ _handlers[i].symbols.destroy( modifier );
+
+ // check response status
+ if ( ( response->header()->status() == icap::ResponseHeader::NO_CONTENT )
+ || ( response->header()->status() == icap::ResponseHeader::OK ) ) {
+ // no further action needed, break out of the loop
+ break;
+ }
+
+ if ( response->header()->status() == icap::ResponseHeader::CONTINUE ) {
+
+ // read the full response
+ continue_status = preview_continue( response, request, socket );
+
+ // cleanup
+ delete response;
+
+ // sanity check
+ if ( continue_status ) {
+
+ // success - set the response to NULL
+ response = NULL;
+
+ } else {
+
+ // something went wrong, server error
+ response = new icap::Response( icap::ResponseHeader::SERVER_ERROR );
+
+ }
+
+ // exit the loop
+ break;
+
+ }
+
+ // we shouldn't have got this far
+ logger.info( std::string( "[req] unrecognised preview response from modifier: " ).append( _handlers[i].name ) );
+
+ }
+
+ return response;
+
+ }
+
+
+ icap::Response * RequestHandler::process_modify( icap::Request * request ) throw() {
+
+ icap::Response * response = NULL;
+ Modifier * modifier;
+
+ int i = 0;
+
+ // logger
+ Logger &logger = Logger::instance();
+
+
+ /*
+ * Loop through loaded modifier modules and grab responses
+ *
+ * We will only return the response from the last module
+ * unless a icap::ResponseHeader::OK is received
+ */
+ for ( i = 0 ; i < _handlers_count; i++ ) {
+
+ // sanity check
+ if ( _handlers[i].name == "" ) {
+ logger.info( "[req] modifier not loaded, not trying to get a response" );
+ continue;
+ }
+
+ // grab the response from modifier
+ logger.debug( std::string( "[req] getting modify response from modifier: " ).append( _handlers[i].name ) );
+ modifier = _handlers[i].symbols.create();
+ response = modifier->modify( request );
+
+ // cleanup
+ logger.debug( std::string( "[req] cleaning up modifier: " ).append( _handlers[i].name ) );
+ _handlers[i].symbols.destroy( modifier );
+
+ // status 200 OK means content modified
+ if ( response->header()->status() == icap::ResponseHeader::OK ) {
+ logger.debug( "[req] OK response received, not getting responses from other modifiers" );
+ break;
+ }
+
+ }
+
+ return response;
+
+ }
+
+
+ bool RequestHandler::preview_continue( icap::Response * response, icap::Request * request, socketlibrary::TCPSocket * socket ) throw() {
+
+ bool status = false;
+
+ // logger
+ Logger &logger = Logger::instance();
+
+
+ // sanity check
+ if ( request->payload().ieof ) {
+
+ // we can process a '100 Continue' only if an 'ieof' is not received
+ logger.warn( "[req] illegal '100 Continue' response" );
+
+ } else {
+
+ /* read the full request */
+
+ // send back the response first
+ if ( icap::util::send_response( response, socket ) ) {
+
+ // read the rest of the request
+ status = icap::util::read_req_continue_data( request, socket );
+
+ }
+
+ }
+
+ return status;
+
+ }
+
+} /* end of namespace bitz */
+
diff --git a/src/bitz/request_handler.h b/src/bitz/request_handler.h
new file mode 100644
index 0000000..3fe99f1
--- /dev/null
+++ b/src/bitz/request_handler.h
@@ -0,0 +1,133 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef BITZ_REQUEST_HANDLER_H
+#define BITZ_REQUEST_HANDLER_H
+
+#include "modifier.h"
+
+#include <icap/response.h>
+#include <icap/request.h>
+#include <socket/socket.h>
+
+
+namespace bitz {
+
+ class RequestHandler {
+ public:
+
+ struct req_handler_t {
+ std::string method;
+ };
+
+ struct handler_t {
+ std::string name;
+ Modifier::symbols_t symbols;
+ };
+
+ RequestHandler( const std::string &method );
+ virtual ~RequestHandler();
+
+ /**
+ * Returns the request method handled by this handler
+ * @return method
+ */
+ const std::string &method() const throw();
+
+ /**
+ * Process the request and return a new response object. This will also
+ * read from the passed in socket if more data needs to be read.
+ *
+ * @param req_header request header object
+ * @param socket socket object to read the data from
+ * @return response object
+ */
+ virtual icap::Response * process( icap::RequestHeader * req_header, socketlibrary::TCPSocket * socket ) throw();
+
+
+ protected:
+
+ unsigned int _handlers_count;
+ handler_t * _handlers;
+
+ /**
+ * Load a modifier module
+ *
+ * @param file file name / path of the module
+ * @param symbols structure to return the symbols
+ * @return boolean to denote success or failure
+ */
+ bool load_modifier( const std::string &file, Modifier::symbols_t &symbols ) throw();
+
+ /**
+ * Unload a modifier module
+ *
+ * @param modifier pointer to the modifier to unload
+ */
+ void unload_modifier( void * modifier ) throw();
+
+ /**
+ * Load all the configured modifier modules for this request handler
+ */
+ void load_modules() throw();
+
+ /**
+ * Cleanup all the loaded modifier modules
+ */
+ void cleanup_modules() throw();
+
+ /**
+ * Given a request instance and a socket instance to communicate, this method will use the
+ * loaded handler modules to grab a preview response. This will return a icap::Response
+ * object or NULL after processing a '100 Continue' response.
+ *
+ * @param request request object
+ * @param socket socket object to read data from
+ * @return preview response (response object)
+ */
+ icap::Response * process_preview( icap::Request * request, socketlibrary::TCPSocket * socket ) throw();
+
+ /**
+ * This method will use the loaded handler modules to get a response to the request.
+ *
+ * @param request request object
+ * @return response object
+ */
+ icap::Response * process_modify( icap::Request * request ) throw();
+
+ /**
+ * Helper method to set a '100 Continue' response back to the client and read the full request.
+ *
+ * @param response response object with status 100
+ * @param request request object
+ * @param socket socket object to read / write data
+ * @return
+ */
+ bool preview_continue( icap::Response * response, icap::Request * request, socketlibrary::TCPSocket * socket ) throw();
+
+ private:
+
+ req_handler_t _req_handler;
+
+ };
+
+} /* end of namespace bitz */
+
+#endif /* !BITZ_REQUEST_HANDLER_H */
+
diff --git a/src/bitz/respmod_request_handler.cpp b/src/bitz/respmod_request_handler.cpp
new file mode 100644
index 0000000..8f99695
--- /dev/null
+++ b/src/bitz/respmod_request_handler.cpp
@@ -0,0 +1,30 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "respmod_request_handler.h"
+
+
+namespace bitz {
+
+ RespmodRequestHandler::RespmodRequestHandler() : RequestHandler( "RESPMOD" ) { }
+
+ RespmodRequestHandler::~RespmodRequestHandler() { }
+
+} /* end of namespace bitz */
+
diff --git a/src/bitz/respmod_request_handler.h b/src/bitz/respmod_request_handler.h
new file mode 100644
index 0000000..dc1a18a
--- /dev/null
+++ b/src/bitz/respmod_request_handler.h
@@ -0,0 +1,41 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef BITZ_RESPMOD_REQUEST_HANDLER_H
+#define BITZ_RESPMOD_REQUEST_HANDLER_H
+
+#include "request_handler.h"
+
+
+namespace bitz {
+
+ class RespmodRequestHandler : public RequestHandler {
+ public:
+
+ RespmodRequestHandler();
+ virtual ~RespmodRequestHandler();
+
+ private:
+
+ };
+
+} /* end of namespace bitz */
+
+#endif /* !BITZ_RESPMOD_REQUEST_HANDLER_H */
+
diff --git a/src/bitz/util.cpp b/src/bitz/util.cpp
new file mode 100644
index 0000000..8fedc85
--- /dev/null
+++ b/src/bitz/util.cpp
@@ -0,0 +1,122 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "util.h"
+
+#include <cerrno>
+#include <sys/stat.h>
+
+
+namespace bitz {
+
+ namespace util {
+
+ RequestHandler * find_req_handler( req_handlers_t req_handlers, const std::string &req_method ) throw() {
+
+ RequestHandler * req_handler;
+ req_handlers_index_t rh_i;
+ rh_i = req_handlers.find( req_method );
+
+ if ( rh_i != req_handlers.end() ) {
+ req_handler = rh_i->second;
+ } else {
+ req_handler = NULL;
+ }
+
+ return req_handler;
+
+ }
+
+
+ void delete_req_handlers( req_handlers_t req_handlers ) throw() {
+
+ req_handlers_index_t rh_i;
+
+ for ( rh_i = req_handlers.begin(); rh_i != req_handlers.end(); rh_i++ ) {
+ if ( rh_i->first != "OPTIONS" ) {
+ delete rh_i->second;
+ }
+ }
+
+ return;
+
+ }
+
+
+ std::string dirpath( const std::string &path ) throw() {
+ return path.substr( 0, path.find_last_of( '/' ) );
+ }
+
+
+ std::string filename( const std::string &path ) throw() {
+ return path.substr( path.find_last_of( '/' ) );
+ }
+
+
+ bool mkdirp( const std::string &path ) throw() {
+
+ bool r_success = false;
+
+
+ if ( ::mkdir( path.c_str(), 0755 ) == -1 ) {
+
+ switch( errno ) {
+
+ case ENOENT:
+
+ // parent didn't exist, try to create it
+ if ( mkdirp( path.substr( 0, path.find_last_of( '/' ) ) ) ) {
+
+ // try creating the dir again
+ r_success = ( 0 == ::mkdir( path.c_str(), 0755 ) );
+
+ } else {
+
+ // failed to create parent
+ r_success = false;
+ }
+
+ break;
+
+ case EEXIST:
+
+ // already exists
+ r_success = true;
+ break;
+
+ default:
+ r_success = false;
+ break;
+
+ }
+
+ } else {
+ r_success = true;
+ }
+
+
+ return r_success;
+
+ }
+
+
+ } /* end of namespace util */
+
+} /* end of namespace bitz */
+
diff --git a/src/bitz/util.h b/src/bitz/util.h
new file mode 100644
index 0000000..da1b544
--- /dev/null
+++ b/src/bitz/util.h
@@ -0,0 +1,92 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef BITZ_UTIL_H
+#define BITZ_UTIL_H
+
+#include "common.h"
+
+#include <string>
+#include <sstream>
+
+
+namespace bitz {
+
+ namespace util {
+
+ /**
+ * Convert a number into a string
+ *
+ * @param number number to be converted
+ * @return converted string
+ */
+ template <typename T> std::string itoa( T number ) {
+ std::ostringstream ss;
+ ss << number;
+
+ return ss.str();
+ }
+
+ /**
+ * Find a matching request handler for the given method
+ *
+ * @param req_handlers request handlers
+ * @param req_method request method
+ * @return request handler (or null pointer if not found)
+ */
+ RequestHandler * find_req_handler( req_handlers_t req_handlers, const std::string &req_method ) throw();
+
+ /**
+ * Helper method to delete any loaded request handlers apart
+ * from the OPTIONS handler
+ *
+ * @param req_handlers request handlers
+ */
+ void delete_req_handlers( req_handlers_t req_handlers ) throw();
+
+ /**
+ * Extract directory path from a path
+ *
+ * @param path path to extract the directory from
+ * @return directory path
+ */
+ std::string dirpath( const std::string &path ) throw();
+
+ /**
+ * Extract the file name from a path
+ *
+ * @param path path to extract the file name from
+ * @return file name
+ */
+ std::string filename( const std::string &path ) throw();
+
+ /**
+ * Create a directory tree recursively
+ *
+ * @param path full directory path
+ * @return boolean to denote success or failure
+ */
+ bool mkdirp( const std::string &path ) throw();
+
+ } /* end of namespace util */
+
+} /* end of namespace bitz */
+
+#endif /* !BITZ_UTIL_H */
+
diff --git a/src/bitz/worker.cpp b/src/bitz/worker.cpp
new file mode 100644
index 0000000..efbeef3
--- /dev/null
+++ b/src/bitz/worker.cpp
@@ -0,0 +1,138 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include "worker.h"
+#include "logger.h"
+#include "util.h"
+#include "options_request_handler.h"
+#include "reqmod_request_handler.h"
+#include "respmod_request_handler.h"
+
+#include <icap/util.h>
+#include <icap/request_header.h>
+
+
+namespace bitz {
+
+ Worker::Worker() {
+
+ // load request handlers
+ load_req_handlers();
+
+ }
+
+
+ Worker::~Worker() {
+
+ // logger
+ Logger &logger = Logger::instance();
+ logger.debug( "[worker] exiting" );
+
+ // cleanup request handlers
+ util::delete_req_handlers( _req_handlers );
+ delete _req_handlers["OPTIONS"];
+
+ }
+
+
+ void Worker::run( socketlibrary::TCPServerSocket * server_sock, unsigned int max_requests ) throw() {
+
+ Logger &logger = Logger::instance();
+
+ socketlibrary::TCPSocket * client_sock;
+ icap::RequestHeader * req_header;
+ icap::Response * response;
+ RequestHandler * req_handler;
+
+
+ try {
+
+ while ( max_requests > 0 ) {
+
+ logger.debug( std::string( "[worker] waiting for a connection" ) );
+
+ client_sock = server_sock->accept();
+ logger.debug( std::string( "[worker] new connection accepted on " ).append( client_sock->getForeignAddress() )
+ .append( ":" ).append( util::itoa( client_sock->getForeignPort() ) ) );
+
+ // request header
+ req_header = icap::util::read_req_header( client_sock );
+ logger.debug( std::string( "[worker] request header:\r\n" ).append( req_header->raw_data() ) );
+
+ // try to find a handler for the request
+ req_handler = util::find_req_handler( _req_handlers, req_header->method() );
+
+ if ( req_handler != NULL ) {
+
+ logger.debug( std::string( "[worker] handling request: " ).append( req_header->method() ) );
+
+ // process the request and grab the response
+ response = req_handler->process( req_header, client_sock );
+
+ } else {
+
+ // unsupported request
+ logger.info( std::string( "[worker] unsupported request: " ).append( req_header->method() ) );
+ response = new icap::Response( new icap::ResponseHeader( icap::ResponseHeader::NOT_ALLOWED ) );
+
+ }
+
+ // send the response back to the client
+ icap::util::send_response( response, client_sock );
+
+ // cleanup
+ delete response;
+ delete req_header;
+
+ // destroy / close connection
+ delete client_sock;
+
+ max_requests--;
+
+ }
+
+ } catch( socketlibrary::SocketException &sex ) {
+ logger.error( std::string( "[worker] ERROR: " ).append( sex.what() ) );
+ }
+
+ }
+
+
+ void Worker::load_req_handlers() throw() {
+
+ OptionsRequestHandler * options_handler;
+
+ // OPTIONS handler
+ options_handler = new OptionsRequestHandler();
+ _req_handlers["OPTIONS"] = options_handler;
+
+ /* request handlers */
+
+ // REQMOD
+ _req_handlers["REQMOD"] = new ReqmodRequestHandler();
+ options_handler->register_handler( _req_handlers["REQMOD"] );
+
+ // RESPMOD
+ _req_handlers["RESPMOD"] = new RespmodRequestHandler();
+ options_handler->register_handler( _req_handlers["RESPMOD"] );
+
+ }
+
+} /* end of namespace bitz */
+
diff --git a/src/bitz/worker.h b/src/bitz/worker.h
new file mode 100644
index 0000000..69edbca
--- /dev/null
+++ b/src/bitz/worker.h
@@ -0,0 +1,47 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#ifndef BITZ_WORKER_H
+#define BITZ_WORKER_H
+
+#include <socket/socket.h>
+
+#include "common.h"
+
+
+namespace bitz {
+
+ class Worker {
+ public:
+ Worker();
+ virtual ~Worker();
+
+ virtual void run( socketlibrary::TCPServerSocket * server_sock, unsigned int max_requests ) throw();
+
+ private:
+ req_handlers_t _req_handlers;
+
+ virtual void load_req_handlers() throw();
+
+ };
+
+} /* end of namespace bitz */
+
+#endif /* !BITZ_WORKER_H */
+
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..e00c1c6
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,82 @@
+/*
+ * bitz-server, An ICAP server implementation in C++
+ * Copyright (C) 2012 Uditha Atukorala
+ *
+ * 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 3 of the License, 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
+ */
+
+#include <cstdlib>
+
+#include <config.h>
+#include "bitz-server.h"
+#include "bitz/config.h"
+#include "bitz/logger.h"
+#include "bitz/util.h"
+
+
+int main( int argc, char **argv ) {
+
+ // initialise the server
+ bitz::server::init();
+
+ // read command line options
+ bitz::server::options_t opt = bitz::server::read_options( argc, argv );
+
+ // initialise configurations
+ bitz::Config &server_config = bitz::Config::instance();
+
+ if ( opt.config_file != "" ) {
+ server_config.initialise( opt.config_file );
+ } else {
+ server_config.initialise();
+ }
+
+ // get a copy of the configs
+ const bitz::config_t &config = server_config.configs();
+
+ // create directories
+ if ( ( opt.debug_flag != 1 ) && (! bitz::util::mkdirp( bitz::util::dirpath( config.pid_file ) ) ) ) {
+ std::cerr << "[core] failed to create run dir" << std::endl;
+ exit( EXIT_FAILURE );
+ }
+
+ if (! bitz::util::mkdirp( bitz::util::dirpath( config.log_file ) ) ) {
+ std::cerr << "[core] failed to create log dir" << std::endl;
+ exit( EXIT_FAILURE );
+ }
+
+
+ // daemonize
+ if ( opt.debug_flag != 1 ) {
+ bitz::server::daemonize( bitz::util::dirpath( config.pid_file ).c_str(), config.pid_file.c_str() );
+ }
+
+ // initialise the logger
+ bitz::Logger &logger = bitz::Logger::instance( config.log_file, config.log_category );
+ logger.info( std::string( PACKAGE_STRING ) + " initialised" );
+
+ // start the server
+ bitz::server::start( config.port, config.max_workers, config.max_worker_requests );
+
+ // run the server
+ bitz::server::run();
+
+ // we should never get here
+ bitz::server::shutdown();
+
+ return( EXIT_SUCCESS );
+
+}
+
diff --git a/test/icap-client.py b/test/icap-client.py
new file mode 100644
index 0000000..622d9ca
--- /dev/null
+++ b/test/icap-client.py
@@ -0,0 +1,211 @@
+#!/usr/bin/env python
+#
+# icap-client.py
+# Copyright (c) 2013 Uditha Atukorala
+#
+
+# simple icap client to test a server implementation
+
+import socket
+import sys
+
+HOST = 'localhost'
+SERVICE = 'icap://icap.server.net/sample-service'
+PORT = 1344
+
+# OPTIONS
+print "----- OPTIONS -----"
+try:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+except socket.error, msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(1)
+
+try:
+ sock.connect((HOST, PORT))
+except socket.error, msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(2)
+
+sock.send( "OPTIONS %s ICAP/1.0\r\n" % ( SERVICE ) )
+sock.send( "Host: %s\r\n" % ( HOST ) )
+sock.send( "User-Agent: Python ICAP tester\r\n" )
+sock.send( "\r\n" )
+
+
+data = sock.recv(1024)
+string = ""
+while len(data):
+ string = string + data
+ data = sock.recv(1024)
+sock.close()
+
+print string
+
+
+# REQMOD, GET
+print "----- REQMOD - GET -----"
+try:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+except socket.error, msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(1)
+
+try:
+ sock.connect((HOST, PORT))
+except socket.error, msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(2)
+
+sock.send( "REQMOD %s ICAP/1.0\r\n" % ( SERVICE ) )
+sock.send( "Host: %s\r\n" % ( HOST ) )
+sock.send( "Encapsulated: req-hdr=0, null-body=170\r\n" )
+sock.send( "\r\n" )
+
+sock.send( "GET / HTTP/1.1\r\n" )
+sock.send( "Host: www.origin-server.com\r\n" )
+sock.send( "Accept: text/html, text/plain\r\n" )
+sock.send( "Accept-Encoding: compress\r\n" )
+sock.send( "Cookie: ff39fk3jur@4ii0e02i\r\n" )
+sock.send( "If-None-Match: \"xyzzy\", \"r2d2xxxe\"\r\n" )
+sock.send( "\r\n" )
+
+
+data = sock.recv(1024)
+string = ""
+while len(data):
+ string = string + data
+ data = sock.recv(1024)
+sock.close()
+
+print string
+
+
+# REQMOD, POST
+print "----- REQMOD - POST -----"
+try:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+except socket.error, msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(1)
+
+try:
+ sock.connect((HOST, PORT))
+except socket.error, msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(2)
+
+sock.send( "REQMOD %s ICAP/1.0\r\n" % ( SERVICE ) )
+sock.send( "Host: %s\r\n" % ( HOST ) )
+sock.send( "Encapsulated: req-hdr=0, req-body=147\r\n" )
+sock.send( "\r\n" )
+
+sock.send( "POST /origin-resource/form.pl HTTP/1.1\r\n" )
+sock.send( "Host: www.origin-server.com\r\n" )
+sock.send( "Accept: text/html, text/plain\r\n" )
+sock.send( "Accept-Encoding: compress\r\n" )
+sock.send( "Pragma: no-cache\r\n" )
+sock.send( "\r\n" )
+sock.send( "1e\r\n" )
+sock.send( "I am posting this information.\r\n" )
+sock.send( "0\r\n" )
+sock.send( "\r\n" )
+
+data = sock.recv(1024)
+string = ""
+while len(data):
+ string = string + data
+ data = sock.recv(1024)
+sock.close()
+
+print string
+
+
+# REQMOD - Message preview
+print "----- REQMOD - Message preview -----"
+try:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+except socket.error, msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(1)
+
+try:
+ sock.connect((HOST, PORT))
+except socket.error, msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(2)
+
+sock.send( "REQMOD %s ICAP/1.0\r\n" % ( SERVICE ) )
+sock.send( "Host: %s\r\n" % ( HOST ) )
+sock.send( "Preview: 1024\r\n" )
+sock.send( "Encapsulated: req-hdr=0, req-body=147\r\n" )
+sock.send( "\r\n" )
+
+sock.send( "POST /origin-resource/form.pl HTTP/1.1\r\n" )
+sock.send( "Host: www.origin-server.com\r\n" )
+sock.send( "Accept: text/html, text/plain\r\n" )
+sock.send( "Accept-Encoding: compress\r\n" )
+sock.send( "Pragma: no-cache\r\n" )
+sock.send( "\r\n" )
+sock.send( "1e\r\n" )
+sock.send( "I am posting this information.\r\n" )
+sock.send( "0; ieof\r\n\r\n" )
+
+data = sock.recv(1024)
+string = ""
+while len(data):
+ string = string + data
+ data = sock.recv(1024)
+sock.close()
+
+print string
+
+
+# RESPMOD
+print "----- RESPMOD -----"
+try:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+except socket.error, msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(1)
+
+try:
+ sock.connect((HOST, PORT))
+except socket.error, msg:
+ sys.stderr.write("[ERROR] %s\n" % msg[1])
+ sys.exit(2)
+
+sock.send( "RESPMOD %s ICAP/1.0\r\n" % ( SERVICE ) )
+sock.send( "Host: %s\r\n" % ( HOST ) )
+sock.send( "Encapsulated: req-hdr=0, res-hdr=137, res-body=296\r\n" )
+sock.send( "\r\n" )
+
+sock.send( "GET /origin-resource HTTP/1.1\r\n" )
+sock.send( "Host: www.origin-server.com\r\n" )
+sock.send( "Accept: text/html, text/plain, image/gif\r\n" )
+sock.send( "Accept-Encoding: gzip, compress\r\n" )
+sock.send( "\r\n" )
+sock.send( "HTTP/1.1 200 OK\r\n" )
+sock.send( "Date: Mon, 10 Jan 2000 09:52:22 GMT\r\n" )
+sock.send( "Server: Apache/1.3.6 (Unix)\r\n" )
+sock.send( 'ETag: "63840-1ab7-378d415b"\r\n' )
+sock.send( "Content-Type: text/html\r\n" )
+sock.send( "Content-Length: 51\r\n" )
+sock.send( "\r\n" )
+sock.send( "33\r\n" )
+sock.send( "This is data that was returned by an origin server.\r\n" )
+sock.send( "0\r\n" )
+sock.send( "\r\n" )
+
+data = sock.recv(1024)
+string = ""
+while len(data):
+ string = string + data
+ data = sock.recv(1024)
+sock.close()
+
+print string
+
+
+sys.exit(0)
+
diff --git a/test/sample.txt b/test/sample.txt
new file mode 100644
index 0000000..a149049
--- /dev/null
+++ b/test/sample.txt
@@ -0,0 +1,192 @@
+REQMOD
+======
+
+ICAP Request Modification Example 1 - ICAP Request
+----------------------------------------------------------------
+REQMOD icap://icap-server.net/server?arg=87 ICAP/1.0
+Host: icap-server.net
+Encapsulated: req-hdr=0, null-body=170
+
+GET / HTTP/1.1
+Host: www.origin-server.com
+Accept: text/html, text/plain
+Accept-Encoding: compress
+Cookie: ff39fk3jur@4ii0e02i
+If-None-Match: "xyzzy", "r2d2xxxx"
+
+----------------------------------------------------------------
+ICAP Request Modification Example 1 - ICAP Response
+----------------------------------------------------------------
+ICAP/1.0 200 OK
+Date: Mon, 10 Jan 2000 09:55:21 GMT
+Server: ICAP-Server-Software/1.0
+Connection: close
+ISTag: "W3E4R7U9-L2E4-2"
+Encapsulated: req-hdr=0, null-body=231
+
+GET /modified-path HTTP/1.1
+Host: www.origin-server.com
+Via: 1.0 icap-server.net (ICAP Example ReqMod Service 1.1)
+Accept: text/html, text/plain, image/gif
+Accept-Encoding: gzip, compress
+If-None-Match: "xyzzy", "r2d2xxxx"
+
+----------------------------------------------------------------
+
+
+
+ICAP Request Modification Example 2 - ICAP Request
+----------------------------------------------------------------
+REQMOD icap://icap-server.net/server?arg=87 ICAP/1.0
+Host: icap-server.net
+Encapsulated: req-hdr=0, req-body=147
+
+POST /origin-resource/form.pl HTTP/1.1
+Host: www.origin-server.com
+Accept: text/html, text/plain
+Accept-Encoding: compress
+Pragma: no-cache
+
+1e
+I am posting this information.
+0
+
+----------------------------------------------------------------
+ICAP Request Modification Example 2 - ICAP Response
+----------------------------------------------------------------
+ICAP/1.0 200 OK
+Date: Mon, 10 Jan 2000 09:55:21 GMT
+Server: ICAP-Server-Software/1.0
+Connection: close
+ISTag: "W3E4R7U9-L2E4-2"
+Encapsulated: req-hdr=0, req-body=244
+
+POST /origin-resource/form.pl HTTP/1.1
+Host: www.origin-server.com
+Via: 1.0 icap-server.net (ICAP Example ReqMod Service 1.1)
+Accept: text/html, text/plain, image/gif
+Accept-Encoding: gzip, compress
+Pragma: no-cache
+Content-Length: 45
+
+2d
+I am posting this information. ICAP powered!
+0
+
+----------------------------------------------------------------
+
+
+ICAP Request Modification Example 3 - ICAP Request
+----------------------------------------------------------------
+REQMOD icap://icap-server.net/content-filter ICAP/1.0
+Host: icap-server.net
+Encapsulated: req-hdr=0, null-body=119
+
+GET /naughty-content HTTP/1.1
+Host: www.naughty-site.com
+Accept: text/html, text/plain
+Accept-Encoding: compress
+
+----------------------------------------------------------------
+ICAP Request Modification Example 3 - ICAP Response
+----------------------------------------------------------------
+ICAP/1.0 200 OK
+Date: Mon, 10 Jan 2000 09:55:21 GMT
+Server: ICAP-Server-Software/1.0
+Connection: close
+ISTag: "W3E4R7U9-L2E4-2"
+Encapsulated: res-hdr=0, res-body=213
+
+HTTP/1.1 403 Forbidden
+Date: Wed, 08 Nov 2000 16:02:10 GMT
+Server: Apache/1.3.12 (Unix)
+Last-Modified: Thu, 02 Nov 2000 13:51:37 GMT
+ETag: "63600-1989-3a017169"
+Content-Length: 58
+Content-Type: text/html
+
+3a
+Sorry, you are not allowed to access that naughty content.
+0
+
+----------------------------------------------------------------
+
+
+RESPMOD
+=======
+
+ICAP Response Modification Example 4 - ICAP Request
+----------------------------------------------------------------
+RESPMOD icap://icap.example.org/satisf ICAP/1.0
+Host: icap.example.org
+Encapsulated: req-hdr=0, res-hdr=137, res-body=296
+
+GET /origin-resource HTTP/1.1
+Host: www.origin-server.com
+Accept: text/html, text/plain, image/gif
+Accept-Encoding: gzip, compress
+
+HTTP/1.1 200 OK
+Date: Mon, 10 Jan 2000 09:52:22 GMT
+Server: Apache/1.3.6 (Unix)
+ETag: "63840-1ab7-378d415b"
+Content-Type: text/html
+Content-Length: 51
+
+33
+This is data that was returned by an origin server.
+0
+
+----------------------------------------------------------------
+ICAP Response Modification Example 4 - ICAP Response
+----------------------------------------------------------------
+ICAP/1.0 200 OK
+Date: Mon, 10 Jan 2000 09:55:21 GMT
+Server: ICAP-Server-Software/1.0
+Connection: close
+ISTag: "W3E4R7U9-L2E4-2"
+Encapsulated: res-hdr=0, res-body=222
+
+HTTP/1.1 200 OK
+Date: Mon, 10 Jan 2000 09:55:21 GMT
+Via: 1.0 icap.example.org (ICAP Example RespMod Service 1.1)
+Server: Apache/1.3.6 (Unix)
+ETag: "63840-1ab7-378d415b"
+Content-Type: text/html
+Content-Length: 92
+
+5c
+This is data that was returned by an origin server, but with
+value added by an ICAP server.
+0
+
+----------------------------------------------------------------
+
+
+OPTIONS
+=======
+
+ICAP OPTIONS Example 5 - ICAP OPTIONS Request
+----------------------------------------------------------------
+OPTIONS icap://icap.server.net/sample-service ICAP/1.0
+Host: icap.server.net
+User-Agent: BazookaDotCom-ICAP-Client-Library/2.3
+
+----------------------------------------------------------------
+ICAP OPTIONS Example 5 - ICAP OPTIONS Response
+----------------------------------------------------------------
+ICAP/1.0 200 OK
+Date: Mon, 10 Jan 2000 09:55:21 GMT
+Methods: RESPMOD
+Service: FOO Tech Server 1.0
+ISTag: "W3E4R7U9-L2E4-2"
+Encapsulated: null-body=0
+Max-Connections: 1000
+Options-TTL: 7200
+Allow: 204
+Preview: 2048
+Transfer-Complete: asp, bat, exe, com
+Transfer-Ignore: html
+Transfer-Preview: *
+
+---------------------------------------------------------------- \ No newline at end of file
diff --git a/test/valgrind.supp b/test/valgrind.supp
new file mode 100644
index 0000000..be525db
--- /dev/null
+++ b/test/valgrind.supp
@@ -0,0 +1,29 @@
+#
+# valgrind.supp
+#
+
+# Python
+{
+ Python 2.7 (libpython2.7.so.1.0)
+ Memcheck:Value4
+ obj:/usr/lib/libpython2.7.so.1.0
+}
+
+{
+ Python 2.7 (libpython2.7.so.1.0)
+ Memcheck:Addr4
+ obj:/usr/lib/libpython2.7.so.1.0
+}
+
+{
+ Python 2.7 (libpython2.7.so.1.0)
+ Memcheck:Value8
+ obj:/usr/lib/libpython2.7.so.1.0
+}
+
+{
+ Python 2.7 (libpython2.7.so.1.0)
+ Memcheck:Cond
+ obj:/usr/lib/libpython2.7.so.1.0
+}
+