--- /dev/null
+#
+# Makefile
+#
+# The Makefile is divided into three sections, the "generic section", the
+# "host section" and the "rules section". The generics section defines
+# defaults which you should not change. Changes should solely be made to
+# the rules section.
+#
+# You will need to select several parameters befitting your compiler/system:
+#
+# -DHAS_BOOL - set, if your C++ compiler knows about the 'bool' type.
+# -DHAS_PSIGNAL - set, if your libc supports psignal(int,const char*).
+# -fno-exceptions - may not be recognized by all variants of g++
+# -ffor-scope - the new ANSI C++ scoping of for() variables is used...
+#
+# === [1] ==================================================== generics section
+#
+CXX = g++ -ffor-scope -DHAS_BOOL -DHAS_PSIGNAL
+CC = gcc
+LD = $(CC) # yes, I do mean gcc and not g++
+CXXFLAGS = # -pg -g # -fprofile-arcs -ftest-coverage
+SYSTEM = $(shell uname -s | tr '[a-z]' '[A-Z]' | tr -d '_ -/')
+CPU = $(shell uname -p)
+VERSION = $(shell uname -r)
+HOST = $(shell uname -n)
+MAJOR = $(firstword $(subst ., ,$(VERSION)))
+MINOR = $(strip $(word 2,$(subst ., ,$(VERSION))))
+LOADLIBES =
+SOCKLEN = int # default except for glibc2?
+
+# optimization levels - Do *not* use levels above -O1 with g++,
+# if -fprofile-arcs or -ftest-coverage is selected! Set to different
+# values in the host specific section below.
+#
+# - OPT_NORM for normal level optimization, O2 is a good choice.
+#
+OPT_NORM = -O2
+
+# electric fence library, for test purposes only (helps w/ memory leaks)
+# (developers only)
+EFENCE = -L/usr/local/lib -lefence
+
+#
+# === [2] ======================================================= hosts section
+#
+
+ifeq (SUNOS,${SYSTEM})
+ifeq (5,${MAJOR})
+# use these for the SUN CC compiler (for STL, see below or above)
+# You must define this for Solaris 2.x: CXXFLAGS = -DSOLARIS
+CC = cc
+#CXX = CC -DHAS_BOOL -DHAS_PSIGNAL -DHAS_MUTABLE
+#CXXFLAGS = -DSOLARIS '-library=%none,Cstd,Crun'
+#CXXFLAGS += -dalign -ftrap=%none -fsimple -xlibmil
+#OPT_NORM = -xtarget=ultra2 -xO4
+#EXTRALIB += -lnsl -lsocket
+#LD = CC
+#
+## g++ settings for Solaris on Ultra Sparcs (comment out all of above):
+CXXFLAGS += -DSOLARIS # -ggdb
+OPT_NORM = -O2 # -mcpu=supersparc
+LD = $(CC)
+##
+#EXTRALIB += -lnsl -lsocket -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic
+else
+# old SunOS 4.1.x, not supported!
+CXXFLAGS += -DSUN
+endif
+endif
+
+ifeq (IRIX64,${SYSTEM})
+# The regular 64bit Irix stuff is just too slow, use n32!
+SYSTEM := IRIX
+endif
+
+ifeq (FREEBSD,${SYSTEM})
+SOCKLEN = socklen_t
+endif
+
+ifeq (IRIX,${SYSTEM})
+CXX = CC -n32 -mips3 -r4000 -DEFAULT:abi=n32:isa=mips3:proc=r4k
+CXX += -LANG:ansi-for-init-scope=on -LANG:bool=on
+CXX += -LANG:exceptions=off -LANG:explicit=off -LANG:wchar_t=off
+CXX += -LANG:mutable=on -LANG:namespaces=on -LANG:std
+CC = cc -n32 -mips3 -r4000
+CXXFLAGS = -woff 1174 -LANG:exceptions=off -DHAS_BOOL -DHAS_PSIGNAL
+LD = $(CXX)
+OPT_NORM = -O3 -IPA -LNO:opt=1
+# for g++
+#CXXFLAGS += -mips3 -mcpu=r4000
+endif
+
+ifeq (AIX,${SYSTEM})
+ifeq (,${MINOR})
+MINOR := ${MAJOR}
+MAJOR = 4
+endif
+CXX = xlC -UHAS_BOOL -UHAS_PSIGNAL
+CC = xlc
+CXXFLAGS = -qtune=pwr # -qdbxextra -g
+#CXX = g++ -ffor-scope -DHAS_BOOL -UHAS_PSIGNAL
+SOCKLEN = size_t
+LD = $(CXX)
+endif
+
+ifeq (LINUX,${SYSTEM})
+# determine highest version of all installed libc's.
+LIBCVER = $(shell /bin/ls /lib/libc.so.? | \
+ awk -F'.' '{ if (m<$$3) m=$$3;} END { print m} ')
+ifeq (6,${LIBCVER})
+SOCKLEN = size_t
+endif
+CXXFLAGS += -DHAS_PSIGNAL -DLIBCVERSION=$(LIBCVER) -pipe # -Wall -pedantic
+OPT_NORM = -march=pentium -O2
+# if your g++ balks (e.g. SuSE still uses 2.7.2.3)
+#CXXFLAGS += -DHAS_PSIGNAL -DLIBCVERSION=$(LIBCVER) -m486
+LD = $(CC)
+EXTRALIB = -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic
+endif
+
+#
+# === [3] ======================================================= rules section
+# There is no need to change things below this line.
+CXXFLAGS += -D${SYSTEM} -DMAJOR=${MAJOR} -DMINOR=${MINOR} -DSOCKLEN=${SOCKLEN}
+CFLAGS = $(CXXFLAGS)
+LDFLAGS += $(OPT_NORM)
+
+%.o:%.cc
+ $(CXX) $(CXXFLAGS) $(OPT_NORM) -c $< -o $@
+
+OBJS = convert.o socket.o signal.o squid-tlv.o copyout.o conffile.o
+SRCS = $(OBJS:.o=.cc)
+HDRS = $(OBJS:.o=.hh)
+FILES = $(SRCS) $(HDRS) Makefile purge.cc hexd.c
+DIST = $(addprefix purge/,$(FILES) README)
+
+all: purge
+
+purge: $(OBJS) purge.o
+ $(LD) $(OPT_NORM) $(LDFLAGS) $^ -o $@ $(LOADLIBES) $(EXTRALIB)
+hexd: hexd.o
+ $(CC) $(OPT_NORM) $(LDFLAGS) $^ -o $@ $(LOADLIBES)
+#
+# object file rules, generated with "g++ -MM -E *.cc"
+#
+purge.o: purge.cc $(HDRS)
+ $(CXX) $(CXXFLAGS) $(OPT_NORM) -c $< -o $@
+convert.o: convert.cc convert.hh
+conffile.o: conffile.cc conffile.hh
+signal.o: signal.cc signal.hh
+socket.o: socket.cc socket.hh convert.hh
+squid-tlv.o: squid-tlv.cc squid-tlv.hh
+copyout.o: copyout.cc copyout.hh
+hexd.o: hexd.c
+
+clean:
+ $(RM) *.o
+ if [ "${SYSTEM}" = "IRIX" ]; then rm -rf ii_files; fi
+ if [ "${SYSTEM}" = "SUNOS" ]; then rm -rf Templates.DB; fi
+ if [ "${SYSTEM}" = "SUNOS" ]; then rm -rf SunWS_cache; fi
+
+distclean: clean
+ $(RM) purge hexd
+
+realclean: distclean
+clobber: distclean
+
+co-all: $(FILES)
+ echo all checked out
+co-all-lock:
+ co -l $(FILES)
+ci-all:
+ for i in $(FILES); do \
+ test -w $$i && ci $$i; \
+ rm -f $$i; \
+ done
+
+dist: distclean co-all
+ ( cd .. ; gtar cvzf purge-`date +"%Y%m%d"`-src.tar.gz $(DIST) )
+tar: distclean ci-all
+ ( cd .. ; gtar cvzf purge-`date +"%Y%m%d"`-all.tar.gz purge )
--- /dev/null
+purge
+=====
+
+The purge tool is a kind of magnifying glass into your squid-2 cache. You
+can use purge to have a look at what URLs are stored in which file within
+your cache. The purge tool can also be used to release objects which URLs
+match user specified regular expressions. A more troublesome feature is the
+ability to remove files squid does not seem to know about any longer.
+
+ USE AT YOUR OWN RISK! NO GUARANTEES, WHATSOEVER! DON'T BLAME US!
+ YOU HAVE BEEN WARNED!
+
+
+
+compilation
+===========
+
+Purge has been successfully compiled under the following OSes:
+
+ SYSTEM g++ native
+ ------ --- ------
+ Solaris 2.7 yes CC
+ IRIX 6.5 yes CC -n32
+ Linux 2.0.36 yes (g++ IS native)
+ FreeBSD 4.x yes gmake port must be installed
+ (g++ IS supported)
+
+The recent move of the Linux community towards glibc2 may cause some
+troubles, though. The compilation requires GNU make, no other make will work
+correctly. The source distribution contains all files checked into the
+revision control repository. Therefore, you will need to install GNU RCS
+first (which in turn needs the GNU diffutils).
+
+The repository also contains the prototypical Perl implementation. The user
+interface in the C++ implementation changed a little when compared to the
+Perl one. You will have to state at least one regular expression for purge
+to start working. Also, printing the complete cache URLs, you will need to
+specify the "-e ." regular expression.
+
+In order to compile the purge tool, untar the source distribution and
+change into the purge directory. With RCS and GNU make installed, just say
+"make". GNU make will automagically retrieve all necessary files from the
+repository and create the binary.
+
+Systems not stated above will need to retrieve the makefile (use "co -l
+Makefile" for this) and add their own platform specific definitions to
+section [2] in the makefile.
+
+
+
+squid preparation
+=================
+
+In order to use purge for real PURGEs, you will have to enable this feature
+in squid. By default, PURGE is disabled. You should watch closely for whom
+you enable the PURGE ability, otherwise total stranger just might wipe your
+cache content. The following lines will need to be added to your squid.conf
+(you may want to add further networks to the src_local ACL):
+
+ acl purge method PURGE
+ acl src_local src 127.0.0.0/8
+ http_access allow purge src_local
+ http_access deny purge
+
+Reconfigure or restart (preferred) your squid after changing the
+configuration file.
+
+
+
+modes of operation
+==================
+
+$Id: purge.cc,v 1.15 2000/09/21 09:05:56 cached Exp $
+Usage: purge [-a] [-c cf] [-d l] [-(f|F) fn | -(e|E) re] [-p h[:p]]
+ [-P #] [-s] [-v] [-C dir [-H]] [-n]
+
+ -a display a little rotating thingy to indicate that I am alive (tty only).
+ -c c squid.conf location, default "/usr/local/squid/etc/squid.conf".
+ -C dir base directory for content extraction (copy-out mode).
+ -d l debug level, an OR of different debug options.
+ -e re single regular expression per -e instance (use quotes!).
+ -E re single case sensitive regular expression like -e.
+ -f fn name of textfile containing one regular expression per line.
+ -F fn name of textfile like -f containing case sensitive REs.
+ -H prepend HTTP reply header to destination files in copy-out mode.
+ -n do not fork() when using more than one cache_dir.
+ -p h:p cache runs on host h and optional port p, default is localhost:3128.
+ -P # if 0, just print matches; otherwise OR the following purge modes:
+ 0x01 really send PURGE to the cache.
+ 0x02 remove all caches files reported as 404 (not found).
+ 0x04 remove all weird (inaccessible or too small) cache files.
+ 0 and 1 are recommended - slow rebuild your cache with other modes.
+ -s show all options after option parsing, but before really starting.
+ -v show more information about the file, e.g. MD5, timestamps and flags.
+
+--- &< snip, snip ---
+
+-a is a kind of "i am alive" flag. It can only be activated, if
+ your stdout is a tty. If active, it will display a little
+ rotating line to indicate that there is actually something
+ happening. You should not use this switch, if you capture
+ your stdout in a file, or if your expression list produces
+ many matches. The -a flag is also incompatible with the
+ (default) multi cache_dir mode.
+
+ default: off
+ See also: -n
+
+-c cd CHANGED!
+ this option lets you specify the location of the squid.conf file.
+ Purge now understands about more than one cache_dir, and does so
+ by parsing Squid's configuration file. It knows about both ways
+ of Squid-2 cache_dir specifications, and will automatically try
+ to use the correct one.
+
+ default: /usr/local/squid/etc/squid.conf
+
+-C cd if you want to rescue files from your cache, you need to specify
+ the directory into which the files will be copied. Please note
+ that purge will try to establish the original server's directory
+ structure. This switch also activates copy-out mode. Please do
+ not use copy-out mode with any purge mode (-P) other than 0.
+
+ For instance, if you specified "-C /tmp", Purge will try to
+ recreate /tmp/www.server.1/url/path/file, and so forth.
+
+ default: off
+ See also: -H, -P
+
+-d l lets you specify a debug level. Differents bits are reserved for
+ different output.
+
+ default: 0
+
+-e re the "-e" options let you specify one regular expression at the
+-E re commandline. This is useful, if there is only a handful you
+ want to check. Please remember to escape the shell metachars
+ used in your regular expression. The use of single quotes
+ around your expression is recommended. The capital letter
+ version works case sensitive, the lower caps version does not.
+
+ default: (no default)
+
+-f fn if you have more than a handful of expression, or want to check
+-F fn the same set at regular intervals, the file option might be more
+ useful to you. Each line in the text file will be regarded as
+ one regular expression. Again, the capital letter version works
+ case sensitive, the lower caps version does not.
+
+ default: (no default)
+
+-H if in copy-out mode (see: -C), you can specify to keep the
+ HTTP Header in the recreated file.
+
+ default: off
+ See also: -C
+
+-n by specifying the "-n" switch, you will tell Purge to process
+ one cache_dir after another, instead of doing things in parallel.
+ If you have more than one cache_dir in your configuration,
+ Purge will fork off a worker process for each cache_dir to
+ do the checks for optimum speed - assuming a decently designed
+ cache. Since parallel execution will put quite some load on the
+ system and its controllers, it is sometimes preferred to use
+ less resources, though it will take longer.
+
+ default: parallel mode for more than one cache_dir
+
+-p h[:p] Some cache admins (i.e. me) use a different port than 3128. The
+ purge tool will need to connect to your cache in order to send
+ the PURGE request (see -P). This option lets you specify the
+ host and port to connect to. The port is optional. The port
+ can be a name (check your /etc/services) or number. It is
+ separated from the host name portion by a single colon, no
+ spaces allowed.
+
+ default: localhost:3128
+
+-P # If you want to do more than just print your cache content, you
+ will need to specify this option. Each bit is reserved for a
+ different action. Only the use of the LSB is recommended, the
+ rest should be considered experimental.
+
+ no bit set: just print
+ bit#0 set: send PURGE for matches
+ bit#1 set: unlink object file for 404 not found PURGEs
+ bit#2 set: unlink weird object files
+
+ If you use a value other than 0 or 1, you will need to slow
+ rebuild your cache content. A warning message will remind you
+ of that. If you use bit#1, all unsuccessful PURGEs will result
+ in the object file in your cache directory to be removed, because
+ squid does not seem to know about it any longer. Beware that the
+ asyncio might try to remove it after the purge tool, and thus
+ complains bitterly. Bit#1 only makes sense, if Bit#0 is also
+ set, otherwise it has no effect (since the HTTP status 404 is
+ never returned).
+
+ Bit#2 is reserved for strange files which do not even contain
+ a URL. Beware that these files may indicate a new object squid
+ currently intends to swap onto disk. If the file suddenly went
+ away, or is removed when squid tries to fetch the object, it
+ will complain bitterly. You must slow rebuild your cache, if
+ you use this option.
+
+ It is recommended that if you dare to use bit#1 or bit#2, you
+ should only grant the purge tool access to your squid, e.g.
+ move the HTTP and ICP listening port of squid to a different
+ non-standard location during the purge.
+
+ default: 0 (just print)
+
+-s If you specify this switch, all commandline parameters will be
+ shown after they were parsed.
+
+ default: off
+
+-v be verbose in the things reported about the file. See the output
+ section below.
+
+
+output
+======
+
+In regular mode, the output of purge consists of four columns. If the
+URL contains not encoded whitespaces, it may look as if there are more
+columns, but the last one is the URI.
+
+ # name meaning
+ - ------ -----------------------------------------------------------
+ 1 file name of cache file eximed which matches the re.
+ 2 status return result of purge request, " 0" in print mode.
+ 3 size object size including stored headers, not file size.
+ 4 uri perceived uri
+
+Example for non-verbose output in print-mode:
+
+/cache3/00/00/0000004A 0 5682 http://graphics.userfriendly.org/images/slovenia.gif
+
+In verbose mode, additional columns are inserted before the uri. Time
+stamps are reported using hexadecimal notation, and Squid's standard
+for reporting "no such timestamp" == -1, and "unparsable timestamp" == -2.
+
+ # name meaning
+ - ------ -----------------------------------------------------------
+ 1 file name of cache file eximed which matches the re.
+ 2 status return result of purge request, " 0" in print mode "-P 0".
+ 3 size object size including stored headers, not file size.
+ 4 md5 MD5 of URI from file, or "(no_md5_data_available)" string.
+ 5 ts UTC of Value of Date: header in hex notation
+ 6 lr UTC of last time the object was referenced
+ 7 ex UTC of Expires: header
+ 8 lr UTC of Last-Modified: header
+ 9 flags Value of objects flags field in hex, see: Programmers Guide
+10 refcnt number of times the object was referenced.
+11 uri STORE_META_URL uri or "strange_file"
+
+Example for verbose output in print-mode:
+
+/cache1/00/00/000000B7 0 406 7CFCB1D319F158ADC9CFD991BB8F6DCE 397d449b 39bf677b ffffffff 3820abfc 0460 1 http://www.netscape.com/images/nc_vera_tile.gif
+
+
+hexd
+====
+
+The hexd tool let's you conveniently hex dump a file both, in hex char and
+display char columns. Hexd only assumes that characters 0-31,127-159,255
+are not printable.
+
+
+$ ./hexd /cache1/00/00/000000B7 | less -r
+
+00000000: 03 00 00 00 6D 03 00 00-00 10 7C FC B1 D3 19 F1 ....m.....|ü±Ó.ñ
+00000010: 58 AD C9 CF D9 91 BB 8F-6D CE 05 00 00 00 18 39 XÉÏÙ.».mÎ.....9
+00000020: 7D 44 9B 39 BF 67 7B FF-FF FF FF 38 20 AB FC 00 }D.9¿g{....8 «ü.
+00000030: 00 00 00 00 01 04 60 04-00 00 00 30 68 74 74 70 ......`....0http
+00000040: 3A 2F 2F 77 77 77 2E 6E-65 74 73 63 61 70 65 2E ://www.netscape.
+00000050: 63 6F 6D 2F 69 6D 61 67-65 73 2F 6E 63 5F 76 65 com/images/nc_ve
+00000060: 72 61 5F 74 69 6C 65 2E-67 69 66 00 08 48 54 54 ra_tile.gif..HTT
+00000070: 50 2F 31 2E 30 20 32 30-30 20 4F 4B 0D 0A 53 65 P/1.0 200 OK..Se
+00000080: 72 76 65 72 3A 20 4E 65-74 73 63 61 70 65 2D 45 rver: Netscape-E
+00000090: 6E 74 65 72 70 72 69 73-65 2F 33 2E 36 0D 0A 44 nterprise/3.6..D
+000000A0: 61 74 65 3A 20 54 75 65-2C 20 32 35 20 4A 75 6C ate: Tue, 25 Jul
+000000B0: 20 32 30 30 30 20 30 37-3A 34 31 3A 31 35 20 47 2000 07:41:15 G
+000000C0: 4D 54 0D 0A 43 6F 6E 74-65 6E 74 2D 54 79 70 65 MT..Content-Type
+000000D0: 3A 20 69 6D 61 67 65 2F-67 69 66 0D 0A 4C 61 73 : image/gif..Las
+000000E0: 74 2D 4D 6F 64 69 66 69-65 64 3A 20 57 65 64 2C t-Modified: Wed,
+000000F0: 20 30 33 20 4E 6F 76 20-31 39 39 39 20 32 31 3A 03 Nov 1999 21:
+00000100: 34 31 3A 31 36 20 47 4D-54 0D 0A 43 6F 6E 74 65 41:16 GMT..Conte
+00000110: 6E 74 2D 4C 65 6E 67 74-68 3A 20 36 37 0D 0A 41 nt-Length: 67..A
+00000120: 63 63 65 70 74 2D 52 61-6E 67 65 73 3A 20 62 79 ccept-Ranges: by
+00000130: 74 65 73 0D 0A 41 67 65-3A 20 31 38 32 37 31 33 tes..Age: 182713
+00000140: 0D 0A 58 2D 43 61 63 68-65 3A 20 48 49 54 20 66 ..X-Cache: HIT f
+00000150: 72 6F 6D 20 63 73 2D 68-61 6E 34 2E 77 69 6E 2D rom cs-han4.win-
+00000160: 69 70 2E 64 66 6E 2E 64-65 0D 0A 58 2D 43 61 63 ip.dfn.de..X-Cac
+00000170: 68 65 2D 4C 6F 6F 6B 75-70 3A 20 48 49 54 20 66 he-Lookup: HIT f
+00000180: 72 6F 6D 20 63 73 2D 68-61 6E 34 2E 77 69 6E 2D rom cs-han4.win-
+00000190: 69 70 2E 64 66 6E 2E 64-65 3A 38 30 38 31 0D 0A ip.dfn.de:8081..
+000001A0: 50 72 6F 78 79 2D 43 6F-6E 6E 65 63 74 69 6F 6E Proxy-Connection
+000001B0: 3A 20 6B 65 65 70 2D 61-6C 69 76 65 0D 0A 0D 0A : keep-alive....
+000001C0: 47 49 46 38 39 61 01 00-26 00 A2 00 00 00 00 00 GIF89a..&.¢.....
+000001D0: FF FF FF 00 33 66 33 66-99 FF FF FF 00 00 00 00 ....3f3f........
+000001E0: 00 00 00 00 00 21 F9 04-01 00 00 04 00 2C 00 00 .....!ù......,..
+000001F0: 00 00 01 00 26 00 00 03-08 38 A2 BC DE F0 C9 A8 ....&....8¢¼Þðɨ
+00000200: 12 00 3B ..;
+
+
+
+limitations
+===========
+
+o Purge does not slow rebuild the cache for you.
+
+o It is still relatively slow, especially if your machine is low on memory
+and/or unable to hold all OS directory cache entries in main memory.
+
+o should never be used on "busy" caches with purge modes higher than 1.
+
+
+TODO
+====
+
+1) use the stat() result on weird files to have a look at their ctime and
+ mtime. If they are younger than, lets say 30 seconds, they were just
+ created by squid and should not be removed.
+
+2) Add a query before purging objects or removing files, and add another
+ option to remove nagging for the experienced user.
+
+3) The reported object size may be off by one.
--- /dev/null
+//
+// $Id: conffile.cc,v 1.1 2000/09/21 09:44:53 voeckler Exp $
+//
+// Author: Jens-S. Vöckler <voeckler@rvs.uni-hannover.de>
+//
+// File: conffile.cc
+// Fri Sep 15 2000
+//
+// (c) 2000 Lehrgebiet Rechnernetze und Verteilte Systeme
+// Universität Hannover, Germany
+//
+// Permission to use, copy, modify, distribute, and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that (i) the above copyright notices and this permission
+// notice appear in all copies of the software and related documentation,
+// and (ii) the names of the Lehrgebiet Rechnernetze und Verteilte
+// Systeme and the University of Hannover may not be used in any
+// advertising or publicity relating to the software without the
+// specific, prior written permission of Lehrgebiet Rechnernetze und
+// Verteilte Systeme and the University of Hannover.
+//
+// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// IN NO EVENT SHALL THE LEHRGEBIET RECHNERNETZE UND VERTEILTE SYSTEME OR
+// THE UNIVERSITY OF HANNOVER BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
+// ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
+// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+// SOFTWARE.
+//
+// $Log: conffile.cc,v $
+// Revision 1.1 2000/09/21 09:44:53 voeckler
+// Initial revision
+//
+//
+#if defined(__GNUC__) || defined(__GNUG__)
+#pragma implementation
+#endif
+
+#include "conffile.hh"
+#include <sys/types.h>
+#include <errno.h>
+#include <memory.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <regex.h>
+
+int
+readConfigFile( CacheDirVector& cachedir, const char* fn, FILE* debug )
+ // purpose: read squid.conf file and extract cache_dir entries
+ // paramtr: cachedir (OUT): vector with an entry for each cache_dir found
+ // fn (IN): file name of squid.conf to use
+ // returns: number of entries, or negative to warn of errors
+{
+ static const char* expression =
+ "^[ \t]*cache_dir([ \t]+([[:alpha:]]+))?[ \t]+([[:graph:]]+)[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)";
+
+ // try to open file
+ if ( debug ) fprintf( debug, "# trying to open %s\n", fn ? fn : "(null)" );
+ FILE* in = fopen( fn, "r" );
+ if ( in == NULL ) {
+ fprintf( stderr, "fopen %s: %s\n", fn, strerror(errno) );
+ return -1;
+ }
+
+ // prepare regular expression for matching
+ if ( debug ) fprintf( debug, "# trying to compile \"%s\"\n", expression );
+ regex_t rexp;
+ int result = regcomp( &rexp, expression, REG_EXTENDED );
+ if ( result != 0 ) {
+ char buffer[256];
+ regerror( result, &rexp, buffer, sizeof(buffer) );
+ fprintf( stderr, "regular expression \"%s\": %s\n", expression, buffer );
+ return -1;
+ }
+
+ // read line by line
+ if ( debug ) fputs( "# trying to read lines\n", debug );
+
+ regmatch_t subs[8];
+ char *s, line[1024];
+ CacheDir cd;
+ while ( fgets( line, sizeof(line), in ) ) {
+ // FIXME: overly long lines
+
+ // terminate line at start of comment
+ if ( (s = (char*) memchr( line, '#', sizeof(line) )) ) *s = '\0';
+
+ // quick skip
+ if ( *line == '\0' || *line == '\n' ) continue;
+
+ // test line
+ if ( (result=regexec( &rexp, line, 7, subs, 0 )) != 0 ) {
+ // error or no match
+ if ( result != REG_NOMATCH ) {
+ char buffer[256];
+ regerror( result, &rexp, buffer, sizeof(buffer) );
+ fprintf( stderr, "while matching \"%s\" against %s%s\n",
+ expression, line, buffer );
+ regfree(&rexp);
+ fclose(in);
+ return -1;
+ }
+ } else {
+ // match, please record
+ memset( &cd, 0, sizeof(cd) );
+ if ( debug ) fprintf( debug, "# match from %d-%d on line %s",
+ subs[0].rm_so, subs[0].rm_eo, line );
+
+ // terminate line after matched expression
+ line[ subs[0].rm_eo ] = '\0';
+
+ // extract information. If 6th parenthesis is filled, this is
+ // a new squid with disk types, otherwise it is an older version
+ int offset = 2;
+ if ( subs[6].rm_so == -1 ) {
+ // old version, disk type at position 2 is always UFS
+ cd.type = CacheDir::CDT_UFS;
+ } else {
+ // new version, disk type at position 2
+ line[ subs[offset].rm_eo ] = '\0';
+ if ( debug ) fprintf( debug, "# match from %d-%d on \"%s\"\n",
+ subs[offset].rm_so, subs[offset].rm_eo,
+ line+subs[offset].rm_so );
+ if ( strcmp( line + subs[offset].rm_so, "ufs" ) == 0 )
+ cd.type = CacheDir::CDT_UFS;
+ else if ( strcmp( line + subs[offset].rm_so, "asyncufs" ) == 0 )
+ cd.type = CacheDir::CDT_AUFS;
+ else if ( strcmp( line + subs[offset].rm_so, "diskd" ) == 0 )
+ cd.type = CacheDir::CDT_DISKD;
+ else
+ cd.type = CacheDir::CDT_OTHER;
+ offset++;
+ }
+
+ // extract base directory
+ line[ subs[offset].rm_eo ] = '\0';
+ if ( debug ) fprintf( debug, "# match from %d-%d on \"%s\"\n",
+ subs[offset].rm_so, subs[offset].rm_eo,
+ line+subs[offset].rm_so );
+ cd.base = strdup( line+subs[offset].rm_so );
+ offset++;
+
+ // extract size information
+ line[ subs[offset].rm_eo ] = '\0';
+ if ( debug ) fprintf( debug, "# match from %d-%d on \"%s\"\n",
+ subs[offset].rm_so, subs[offset].rm_eo,
+ line+subs[offset].rm_so );
+ cd.size = strtoul( line+subs[offset].rm_so, 0, 10 );
+ offset++;
+
+ // extract 1st level directories
+ line[ subs[offset].rm_eo ] = '\0';
+ if ( debug ) fprintf( debug, "# match from %d-%d on \"%s\"\n",
+ subs[offset].rm_so, subs[offset].rm_eo,
+ line+subs[offset].rm_so );
+ cd.level[0] = strtoul( line+subs[offset].rm_so, 0, 10 );
+ offset++;
+
+ // extract 2nd level directories
+ line[ subs[offset].rm_eo ] = '\0';
+ if ( debug ) fprintf( debug, "# match from %d-%d on \"%s\"\n",
+ subs[offset].rm_so, subs[offset].rm_eo,
+ line+subs[offset].rm_so );
+ cd.level[1] = strtoul( line+subs[offset].rm_so, 0, 10 );
+ offset++;
+
+ cachedir.push_back( cd );
+ }
+ }
+
+ fclose(in);
+ regfree(&rexp);
+ return cachedir.size();
+}
--- /dev/null
+//
+// $Id: conffile.hh,v 1.2 2000/09/21 10:17:17 cached Exp $
+//
+// Author: Jens-S. Vöckler <voeckler@rvs.uni-hannover.de>
+//
+// File: conffile.hh
+// Fri Sep 15 2000
+//
+// (c) 2000 Lehrgebiet Rechnernetze und Verteilte Systeme
+// Universität Hannover, Germany
+//
+// Permission to use, copy, modify, distribute, and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that (i) the above copyright notices and this permission
+// notice appear in all copies of the software and related documentation,
+// and (ii) the names of the Lehrgebiet Rechnernetze und Verteilte
+// Systeme and the University of Hannover may not be used in any
+// advertising or publicity relating to the software without the
+// specific, prior written permission of Lehrgebiet Rechnernetze und
+// Verteilte Systeme and the University of Hannover.
+//
+// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// IN NO EVENT SHALL THE LEHRGEBIET RECHNERNETZE UND VERTEILTE SYSTEME OR
+// THE UNIVERSITY OF HANNOVER BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
+// ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
+// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+// SOFTWARE.
+//
+// $Log: conffile.hh,v $
+// Revision 1.2 2000/09/21 10:17:17 cached
+// namespace std:: needed for Sun WS compiler.
+//
+// Revision 1.1 2000/09/21 09:45:14 voeckler
+// Initial revision
+//
+//
+#ifndef _CONFFILE_HH
+#define _CONFFILE_HH
+
+#if defined(__GNUC__) || defined(__GNUG__)
+#pragma interface
+#else
+#ifndef HAS_BOOL
+#define HAS_BOOL
+typedef int bool;
+#define false 0
+#define true 1
+#endif
+#endif
+
+
+#ifndef DEFAULT_SQUID_CONF
+#define DEFAULT_SQUID_CONF "/usr/local/squid/etc/squid.conf"
+#endif // DEFAULT_SQUID_CONF
+
+#include <stdio.h> // FILE*
+#include <vector> // minimum STL container
+
+struct CacheDir {
+ enum CacheDirType { CDT_NONE, CDT_UFS, CDT_AUFS, CDT_DISKD, CDT_OTHER };
+
+ const char* base;
+ CacheDirType type;
+ size_t size;
+ unsigned level[2];
+};
+
+typedef std::vector<CacheDir> CacheDirVector;
+
+int
+readConfigFile( CacheDirVector& cachedir,
+ const char* fn = DEFAULT_SQUID_CONF,
+ FILE* debug = 0 );
+ // purpose: read squid.conf file and extract cache_dir entries
+ // paramtr: cachedir (OUT): vector with an entry for each cache_dir found
+ // fn (IN): file name of squid.conf to use
+ // debug (IO): if not null, place debug information there
+ // returns: number of entries, or negative to warn of errors
+
+#endif // _CONFFILE_HH
--- /dev/null
+//
+// $Id: convert.cc,v 1.3 2000/06/20 09:43:01 voeckler Exp $
+//
+// Author: Jens-S. Vöckler <voeckler@rvs.uni-hannover.de>
+//
+// File: convert.cc
+// Thu Oct 30 1997
+//
+// (c) 1997 Lehrgebiet Rechnernetze und Verteilte Systeme
+// Universität Hannover, Germany
+//
+// Permission to use, copy, modify, distribute, and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that (i) the above copyright notices and this permission
+// notice appear in all copies of the software and related documentation,
+// and (ii) the names of the Lehrgebiet Rechnernetze und Verteilte
+// Systeme and the University of Hannover may not be used in any
+// advertising or publicity relating to the software without the
+// specific, prior written permission of Lehrgebiet Rechnernetze und
+// Verteilte Systeme and the University of Hannover.
+//
+// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// IN NO EVENT SHALL THE LEHRGEBIET RECHNERNETZE UND VERTEILTE SYSTEME OR
+// THE UNIVERSITY OF HANNOVER BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
+// ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
+// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+// SOFTWARE.
+//
+// $Log: convert.cc,v $
+// Revision 1.3 2000/06/20 09:43:01 voeckler
+// added FreeBSD related fixes and support.
+//
+// Revision 1.2 1999/01/19 11:00:50 voeckler
+// Linux glibc2 fixes for sockets.
+//
+// Revision 1.1 1998/08/13 21:38:04 voeckler
+// Initial revision
+//
+//
+#if defined(__GNUC__) || defined(__GNUG__)
+#pragma implementation
+#endif
+
+#include "convert.hh"
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifndef SA
+#define SA struct sockaddr
+#endif
+
+static const char* RCS_ID =
+"$Id: convert.cc,v 1.3 2000/06/20 09:43:01 voeckler Exp $";
+
+const char*
+my_inet_ntoa( const struct in_addr& a, HostAddress output )
+ // purpose: thread-safely convert IPv4 address -> ASCII representation
+ // paramtr: a (IN): networked representation of IPv4 address
+ // buffer (OUT): storage area to store representation into.
+ // returns: pointer to buffer
+ // goodies: INADDR_ANY will be converted to "*"
+{
+ if ( a.s_addr == ntohl(INADDR_ANY) ) {
+ // 'default' or '*' or ...
+ output[0] = '*';
+ output[1] = '\0';
+ } else {
+ // ANSI C++ forbids casting to an array type, nag, nag, nag...
+ unsigned char s[sizeof(a.s_addr)];
+ memcpy( s, &a.s_addr, sizeof(a.s_addr) );
+
+ sprintf( output, "%d.%d.%d.%d", s[0], s[1], s[2], s[3] );
+ }
+ return output;
+}
+
+const char*
+my_sock_ntoa( const struct sockaddr_in& a, SockAddress buffer )
+ // purpose: thread-safely convert IPv4 socket pair into ASCII rep.
+ // paramtr: a (IN): sockaddr_in address
+ // buffer (OUT): storage area to store representation into.
+ // returns: pointer to buffer
+{
+ HostAddress host;
+ sprintf( buffer, "%s:%u",
+ my_inet_ntoa(a.sin_addr,host), ntohs(a.sin_port) );
+ return buffer;
+}
+
+const char*
+my_sock_fd2a( int fd, SockAddress buffer, bool peer )
+ // purpose: thread-safely convert IPv4 socket FD associated address
+ // to ASCII representation
+ // paramtr: fd (IN): open socket FD
+ // buffer (OUT): storage area
+ // peer (IN): true, use peer (remote) socket pair
+ // false, use own (local) socket pair
+ // returns: NULL in case of error, or pointer to buffer otherwise
+ // Refer to errno in case of error (usually unconnected fd...)
+{
+ struct sockaddr_in socket;
+ SOCKLEN len = sizeof(socket);
+
+ if ( (peer ? getpeername( fd, (SA*) &socket, &len ) :
+ getsockname( fd, (SA*) &socket, &len )) == -1 )
+ return NULL;
+ else
+ return my_sock_ntoa( socket, buffer );
+}
+
+int
+convertHostname( const char* host, in_addr& dst )
+ // purpose: convert a numeric or symbolic hostname
+ // paramtr: host (IN): host description to convert
+ // dst (OUT): the internet address in network byteorder.
+ // returns: -1 in case of error, see h_errno; 0 otherwise.
+{
+ if ( host == 0 ) return -1;
+ unsigned long int h = inet_addr(host);
+ if ( h == 0xFFFFFFFF && strncmp(host,"255.255.255.255",15) != 0 ) {
+ // symbolic host
+ struct hostent* dns = gethostbyname(host);
+ if ( dns == NULL ) return -1;
+ else memcpy( &dst.s_addr, dns->h_addr, dns->h_length );
+ } else {
+ // numeric host
+ dst.s_addr = h;
+ }
+ return 0;
+}
+
+int
+convertPortname( const char* port, unsigned short& dst )
+ // purpose: convert a numeric or symbolic port number
+ // paramtr: port (IN): port description to convert
+ // dst (OUT): port number in network byteorder.
+ // returns: -1 in case of error, see errno; 0 otherwise.
+{
+ int p = strtoul(port,0,0);
+
+ if ( p == 0 ) {
+ // symbolic port
+ struct servent* proto = getservbyname( port, "tcp" );
+ if ( proto == NULL ) return -1;
+ else dst = proto->s_port;
+ } else {
+ // numeric port
+ dst = htons(p);
+ }
+ return 0;
+}
--- /dev/null
+//
+// $Id: convert.hh,v 1.2 1999/01/19 11:00:50 voeckler Exp $
+//
+// Author: Jens-S. Vöckler <voeckler@rvs.uni-hannover.de>
+//
+// File: convert.hh
+// Thu Oct 30 1997
+//
+// (c) 1997 Lehrgebiet Rechnernetze und Verteilte Systeme
+// Universität Hannover, Germany
+//
+// Permission to use, copy, modify, distribute, and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that (i) the above copyright notices and this permission
+// notice appear in all copies of the software and related documentation,
+// and (ii) the names of the Lehrgebiet Rechnernetze und Verteilte
+// Systeme and the University of Hannover may not be used in any
+// advertising or publicity relating to the software without the
+// specific, prior written permission of Lehrgebiet Rechnernetze und
+// Verteilte Systeme and the University of Hannover.
+//
+// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// IN NO EVENT SHALL THE LEHRGEBIET RECHNERNETZE UND VERTEILTE SYSTEME OR
+// THE UNIVERSITY OF HANNOVER BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
+// ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
+// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+// SOFTWARE.
+//
+// $Log: convert.hh,v $
+// Revision 1.2 1999/01/19 11:00:50 voeckler
+// added bool type workaround.
+//
+// Revision 1.1 1998/08/13 21:38:04 voeckler
+// Initial revision
+//
+//
+#ifndef _CONVERT_HH
+#define _CONVERT_HH
+
+#if defined(__GNUC__) || defined(__GNUG__)
+#pragma interface
+#else
+#ifndef HAS_BOOL
+#define HAS_BOOL
+typedef int bool;
+#define false 0
+#define true 1
+#endif
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+typedef char HostAddress[16]; // strlen("xxx.xxx.xxx.xxx\0") <= 16
+typedef char SockAddress[24]; // strlen("xxx.xxx.xxx.xxx:xxxxx\0" ) < 24
+
+const char*
+my_inet_ntoa( const struct in_addr& a, HostAddress buffer );
+ // purpose: thread-safely convert IPv4 address -> ASCII representation
+ // paramtr: a (IN): networked representation of IPv4 address
+ // buffer (OUT): storage area to store representation into.
+ // returns: pointer to buffer
+ // goodies: INADDR_ANY will be converted to "*"
+
+const char*
+my_sock_ntoa( const struct sockaddr_in& a, SockAddress buffer );
+ // purpose: thread-safely convert IPv4 socket pair into ASCII rep.
+ // paramtr: a (IN): socket_in address
+ // buffer (OUT): storage area to store representation into.
+ // returns: pointer to buffer
+
+const char*
+my_sock_fd2a( int fd, SockAddress buffer, bool peer = true );
+ // purpose: thread-safely convert IPv4 socket FD associated address
+ // to ASCII representation
+ // paramtr: fd (IN): open socket FD
+ // buffer (OUT): storage area
+ // peer (IN): true, use peer (remote) socket pair
+ // false, use own (local) socket pair
+ // returns: NULL in case of error, or pointer to buffer otherwise
+ // Refer to errno in case of error (usually unconnected fd...)
+
+int
+convertHostname( const char* host, struct in_addr& dst );
+ // purpose: convert a numeric or symbolic hostname
+ // paramtr: host (IN): host description to convert
+ // dst (OUT): the internet address in network byteorder.
+ // returns: -1 in case of error, see h_errno; 0 otherwise.
+
+int
+convertPortname( const char* port, unsigned short& dst );
+ // purpose: convert a numeric or symbolic port number
+ // paramtr: port (IN): port description to convert
+ // dst (OUT): port number in network byteorder.
+ // returns: -1 in case of error, see errno; 0 otherwise.
+
+#endif // _CONVERT_HH
--- /dev/null
+//
+// $Id: copyout.cc,v 1.2 1999/06/16 13:05:26 voeckler Exp $
+//
+// Author: Jens-S. Vöckler <voeckler@rvs.uni-hannover.de>
+//
+// File: copyout.cc
+// Tue Jun 15 1999
+//
+// (c) 1999 Lehrgebiet Rechnernetze und Verteilte Systeme
+// Universität Hannover, Germany
+//
+// Permission to use, copy, modify, distribute, and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that (i) the above copyright notices and this permission
+// notice appear in all copies of the software and related documentation,
+// and (ii) the names of the Lehrgebiet Rechnernetze und Verteilte
+// Systeme and the University of Hannover may not be used in any
+// advertising or publicity relating to the software without the
+// specific, prior written permission of Lehrgebiet Rechnernetze und
+// Verteilte Systeme and the University of Hannover.
+//
+// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// IN NO EVENT SHALL THE LEHRGEBIET RECHNERNETZE UND VERTEILTE SYSTEME OR
+// THE UNIVERSITY OF HANNOVER BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
+// ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
+// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+// SOFTWARE.
+//
+// $Log: copyout.cc,v $
+// Revision 1.2 1999/06/16 13:05:26 voeckler
+// mmap file copying on Solaris.
+//
+// Revision 1.1 1999/06/15 21:10:47 voeckler
+// Initial revision
+//
+//
+#if defined(__GNUC__) || defined(__GNUG__)
+#pragma implementation
+#endif
+
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif // MAP_FILE
+
+#include "copyout.hh"
+
+static const char* RCS_ID =
+"$Id: copyout.cc,v 1.2 1999/06/16 13:05:26 voeckler Exp $";
+
+int
+assert_copydir( const char* copydir )
+ // purpose: check, if copydir is a directory and that we can write into it.
+ // paramtr: copydir (IN): name of directory for copying bodies.
+ // returns: 0 if ok, -1 otherwise.
+ // further: errors are handled within. If the directory does not exist,
+ // the assertion function will try to create it.
+{
+ struct stat st;
+ int status = stat( copydir, &st );
+
+ // check, if either "copydir" points to a valid directory,
+ // or if copydir can be created.
+ if ( status == 0 && ! S_ISDIR(st.st_mode) ) {
+ // stat() returned true, but did not point to a directory
+ fprintf( stderr, "copy dir \"%s\" is a file!\n", copydir );
+ return -1;
+ } else if ( S_ISDIR(st.st_mode) &&
+ !( (st.st_uid == geteuid() && ( (st.st_mode & S_IWUSR) > 0 )) ||
+ (st.st_gid == getegid() && ( (st.st_mode & S_IWGRP) > 0 )) ||
+ ((st.st_mode & S_IWOTH) > 0) ) ) {
+ fprintf( stderr, "copy dir \"%s\" is not accessible to me\n", copydir );
+ return -1;
+ } if ( status == -1 ) {
+ // stat() returned with an error. 'File not found' is a legal error.
+ if ( errno != ENOENT ) {
+ // not a 'file not found' error, so this is hard error.
+ fprintf( stderr, "accessing copy-out dir \"%s\": %s\n",
+ copydir, strerror(errno) );
+ return -1;
+ } else {
+ // directory does not exist. Try to create it.
+ if ( mkdir( copydir, 0750 ) == -1 ) {
+ fprintf( stderr, "mkdir(%s): %s\n", copydir, strerror(errno) );
+ return -1;
+ }
+ }
+ }
+
+ // postcondition: copydir exists and is a directory.
+ return 0;
+}
+
+inline
+unsigned
+xlate( char ch )
+{
+ if ( ch == '\r' ) return 0u;
+ else if ( ch == '\n' ) return 1u;
+ else return 2u;
+}
+
+// shortcut for monotoneous typings...
+#define BAUTZ(x) delete[] filename; close(input); close(out); return (x)
+
+bool
+copy_out( size_t filesize, size_t metasize, unsigned debug,
+ const char* fn, const char* url, const char* copydir,
+ bool copyHdr )
+ // purpose: copy content from squid disk file into separate file
+ // paramtr: metasize (IN): size of metadata to skip
+ // fn (IN): current filename of squid disk file
+ // url (IN): currently looked at URL to generate separate file
+ // copydir (IN): base directory where to generate the file
+ // copyHdr (IN): copy HTTP header, too, if set to true.
+ // returns: true, if successful, false otherwise.
+{
+ static const char* index = "index.html";
+
+ // find hostname part after the scheme (okok, not counting port, etc.)
+ char* ptr = strstr( url, "://" );
+ if ( ptr == 0 || strlen(ptr) < 4 ) return false;
+
+ // create filename to store contents into
+ char *filename = new char[ strlen(url) + strlen(copydir) + strlen(index) ];
+ assert( filename != 0 );
+ strcpy( filename, copydir );
+ strcat( filename, "/" );
+ char* here = filename + strlen(filename);
+ strcat( filename, ptr+3 );
+
+ // handle server root (e.g. "http://www.focus.de" )
+ if ( strchr( ptr+3, '/' ) == 0 ) strcat( filename, "/" );
+
+ // handle directories (e.g. "http://www.focus.de/A/" )
+ if ( filename[strlen(filename)-1] == '/' ) strcat( filename, index );
+
+ // create subdirectory structure
+ for ( char* t = strchr(here,'/'); t; t = strchr(t,'/') ) {
+ *t = 0;
+ if ( mkdir( filename, 0775 ) == -1 && errno != EEXIST ) {
+ fprintf( stderr, "mkdir(%s): %s\n", filename, strerror(errno) );
+ delete[] filename;
+ return false;
+ } else if ( debug & 0x02 ) {
+ fprintf( stderr, "# creating %s\n", filename );
+ }
+ *t++ = '/';
+ }
+
+ // create file
+ int out = open( filename, O_CREAT | O_RDWR | O_TRUNC, 0664 );
+ if ( out == -1 ) {
+ fprintf( stderr, "open(%s,RDWR): %s\n", filename, strerror(errno) );
+ delete[] filename;
+ return false;
+ } else if ( debug & 0x02 ) {
+ fprintf( stderr, "# creating %s\n", filename );
+ }
+
+ // (re)open cache file
+ int input = open( fn, O_RDONLY );
+ if ( input == -1 ) {
+ fprintf( stderr, "open(%s,RDONLY): %s\n", fn, strerror(errno) );
+ delete[] filename;
+ close(out);
+ return false;
+ }
+
+ // find double CRLF sequence (actually, look at the FSM below)
+ // FIXME: this only looks at the already known buffer read previously,
+ // which is globally passed (yuck)! As a limitation, the content data
+ // *must* begin within the buffer size (that is: 16k)!
+ if ( ! copyHdr ) {
+ extern char* linebuffer; // import from purge.cc
+ extern size_t buffersize; // import from purge.cc
+
+ unsigned state = 0;
+ char* s = linebuffer + metasize;
+ while ( s < linebuffer + buffersize && state < 4 ) {
+ // state transition machine
+ static unsigned table[4][3] = { {3,2,0}, {0,4,0}, {1,4,0}, {4,2,0} };
+ // old || \r | \n |else|
+ // =====++====+====+====+
+ // 0 || 3 | 2 | 0 |
+ // 1 || 0 | 4 | 0 |
+ // 2 || 1 | 4 | 0 |
+ // 3 || 4 | 2 | 0 |
+ state = table[ state ][ xlate(*s++) ];
+ }
+
+ if ( state < 4 )
+ // complain bitterly, if the HTTP header was too large ( > 16k ).
+ fprintf( stderr, "WARNING: %s will contain partial HTTP header data!\n",
+ filename );
+
+ // adjust to different seek size
+ metasize = s - linebuffer;
+ }
+
+ // no need to copy zero content files
+ if ( filesize - metasize <= 0 ) {
+ BAUTZ( filesize-metasize == 0 );
+ }
+
+#ifdef USE_REGULAR_COPY
+ // position input at start of server answer (contains HTTP headers)
+ if ( lseek( input, metasize, SEEK_SET ) == -1 ) {
+ fprintf( stderr, "lseek(%s,%lu): %s\n", fn, metasize, strerror(errno) );
+ BAUTZ(false);
+ }
+
+ // file copy input into output via buffer (regular io)
+ char buffer[32768];
+ int rsize, wsize;
+ while ( (rsize=read(input,buffer,sizeof(buffer))) > 0 ) {
+ if ( (wsize=write(out,buffer,rsize)) <= 0 ) break;
+ }
+ if ( rsize < 0 || wsize < 0 ) perror( "while copying" );
+#else // use mmap copy (compare: Stevens APUE 12.9)
+ // precondition: filesize-metasize > 0
+ // seek end of output file ...
+ off_t position = lseek( out, filesize-metasize-1, SEEK_SET );
+ if ( position == -1 ) {
+ fprintf( stderr, "lseek(%s,%lu): %s\n", filename, filesize-metasize,
+ strerror(errno) );
+ BAUTZ(false);
+ } else if ( debug & 0x02 ) {
+ fprintf( stderr, "# filesize=%lu, metasize=%lu, filepos=%ld\n",
+ filesize, metasize, position );
+ }
+
+ // ...and write 1 byte there (create a file that length)
+ if ( write( out, "", 1 ) != 1 ) {
+ perror( "write to output" );
+ BAUTZ(false);
+ }
+
+ // create source mmap to copy from (mmap complete file)
+ caddr_t src = (caddr_t) mmap( 0, filesize, PROT_READ,
+ MAP_FILE | MAP_SHARED, input, 0 );
+ if ( src == (caddr_t) -1 ) {
+ perror( "mmap input" );
+ BAUTZ(false);
+ }
+
+ // create destination mmap to copy into (mmap data portion)
+ caddr_t dst = (caddr_t) mmap( 0, filesize-metasize, PROT_READ | PROT_WRITE,
+ MAP_FILE | MAP_SHARED, out, 0 );
+ if ( dst == (caddr_t) -1 ) {
+ perror( "mmap output" );
+ munmap( src, filesize );
+ BAUTZ(false);
+ }
+
+ // copy file (beware of offset into wanted data, skip meta data)
+ memcpy( dst, src+metasize, filesize-metasize );
+
+ // clean up
+ munmap( dst, filesize-metasize );
+ munmap( src, filesize );
+#endif // USE_REGULAR_COPY
+
+ BAUTZ(true);
+}
--- /dev/null
+//
+// $Id: copyout.hh,v 1.1 1999/06/15 21:10:47 voeckler Exp $
+//
+// Author: Jens-S. Vöckler <voeckler@rvs.uni-hannover.de>
+//
+// File: copyout.hh
+// Tue Jun 15 1999
+//
+// (c) 1999 Lehrgebiet Rechnernetze und Verteilte Systeme
+// Universität Hannover, Germany
+//
+// Permission to use, copy, modify, distribute, and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that (i) the above copyright notices and this permission
+// notice appear in all copies of the software and related documentation,
+// and (ii) the names of the Lehrgebiet Rechnernetze und Verteilte
+// Systeme and the University of Hannover may not be used in any
+// advertising or publicity relating to the software without the
+// specific, prior written permission of Lehrgebiet Rechnernetze und
+// Verteilte Systeme and the University of Hannover.
+//
+// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// IN NO EVENT SHALL THE LEHRGEBIET RECHNERNETZE UND VERTEILTE SYSTEME OR
+// THE UNIVERSITY OF HANNOVER BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
+// ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
+// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+// SOFTWARE.
+//
+// $Log: copyout.hh,v $
+// Revision 1.1 1999/06/15 21:10:47 voeckler
+// Initial revision
+//
+#ifndef _COPYOUT_HH
+#define _COPYOUT_HH
+
+#if defined(__GNUC__) || defined(__GNUG__)
+#pragma interface
+#else
+#ifndef HAS_BOOL
+#define HAS_BOOL
+typedef int bool;
+#define false 0
+#define true 1
+#endif
+#endif
+
+int
+assert_copydir( const char* copydir );
+ // purpose: check, if copydir is a directory and that we can write into it.
+ // paramtr: copydir (IN): name of directory for copying bodies.
+ // returns: 0 if ok, -1 otherwise.
+ // further: errors are handled within. If the directory does not exist,
+ // the assertion function will try to create it.
+
+bool
+copy_out( size_t filesize, size_t metasize, unsigned debug,
+ const char* fn, const char* url, const char* copydir,
+ bool copyHdr = true );
+ // purpose: copy content from squid disk file into separate file
+ // paramtr: filesize (IN): complete size of input file
+ // metasize (IN): size of metadata to skip
+ // fn (IN): current filename of squid disk file
+ // url (IN): currently looked at URL to generate separate file
+ // copydir (IN): base directory where to generate the file
+ // copyHdr (IN): copy HTTP header, too, if set to true.
+ // returns: true, if successful, false otherwise.
+
+#endif // _COPYOUT_HH
--- /dev/null
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+unsigned char
+xlate( unsigned char ch )
+{
+ return (isprint(ch & 0x7f) ? ch : '.');
+}
+
+typedef struct {
+ int fd, rsize, cursor;
+ size_t bufsize;
+ unsigned char* buffer;
+} InputByByte;
+
+int
+in_open( InputByByte* this, const char* fn, size_t size )
+{
+ if ( (this->fd = open( fn, O_RDONLY )) == -1 ) return -1;
+ if ( (this->buffer=(unsigned char*) malloc(size)) == 0 ) {
+ close(this->fd);
+ return -1;
+ }
+ this->bufsize = size;
+ this->rsize = this->cursor = 0;
+ return 0;
+}
+
+int
+in_get( InputByByte* this )
+ /*
+ * purpose: read next character
+ * returns: 0..255 as valid character, -1 for error, -2 for EOF
+ */
+{
+ if ( this->cursor >= this->rsize ) {
+ do {
+ this->rsize = read( this->fd, this->buffer, this->bufsize );
+ } while ( this->rsize == -1 && errno == EINTR );
+ if ( this->rsize > 0 ) this->cursor = 0;
+ else return ((-2) - this->rsize);
+ }
+
+ return this->buffer[this->cursor++];
+}
+
+int
+in_close( InputByByte* this )
+{
+ free((void*) this->buffer);
+ return close(this->fd);
+}
+
+int
+main( int argc, char* argv[] )
+{
+ int ch, i;
+ unsigned line = 0;
+ InputByByte in;
+ char b2[20];
+
+ if ( argc != 2 ) {
+ fprintf( stderr, "Usage: %s filename\n", argv[0] );
+ return 1;
+ }
+
+ if ( in_open(&in,argv[1],32768) == -1 ) {
+ perror( "open" );
+ return 1;
+ }
+
+ for ( ch = in_get(&in); ch >= 0; ) {
+ printf( "%08X: ", line );
+ memset( b2, 0, sizeof(b2) );
+ for ( i=0; i < 16 && ch >= 0; i++ ) {
+ printf( "%02X%c", ch, ((i==7) ? '-' : ' ' ) );
+ b2[i] = xlate(ch);
+ ch = in_get(&in);
+ }
+ line += i;
+ for ( ; i<16; i++ ) fputs(" ",stdout);
+ printf( " %s\n", b2 );
+ }
+
+ return in_close(&in);
+}
+
+
--- /dev/null
+//
+// $Id: purge.cc,v 1.17 2000/09/21 10:59:53 cached Exp $
+//
+// Author: Jens-S. Vöckler <voeckler@rvs.uni-hannover.de>
+//
+// File: purge.cc
+// Wed Jan 13 1999
+//
+// (c) 1999 Lehrgebiet Rechnernetze und Verteilte Systeme
+// Universität Hannover, Germany
+//
+// Permission to use, copy, modify, distribute, and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that (i) the above copyright notices and this permission
+// notice appear in all copies of the software and related documentation,
+// and (ii) the names of the Lehrgebiet Rechnernetze und Verteilte
+// Systeme and the University of Hannover may not be used in any
+// advertising or publicity relating to the software without the
+// specific, prior written permission of Lehrgebiet Rechnernetze und
+// Verteilte Systeme and the University of Hannover.
+//
+// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// IN NO EVENT SHALL THE LEHRGEBIET RECHNERNETZE UND VERTEILTE SYSTEME OR
+// THE UNIVERSITY OF HANNOVER BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
+// ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
+// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+// SOFTWARE.
+//
+// $Log: purge.cc,v $
+// Revision 1.17 2000/09/21 10:59:53 cached
+// *** empty log message ***
+//
+// Revision 1.16 2000/09/21 09:45:18 cached
+// Fixed some small bugs.
+//
+// Revision 1.15 2000/09/21 09:05:56 cached
+// added multi cache_dir support, thus changing -c cmdline option.
+// modified file reading to support /dev/fd/0 reading for non-disclosed items.
+//
+// Revision 1.14 2000/06/20 09:43:01 voeckler
+// added FreeBSD related fixes and support.
+//
+// Revision 1.13 2000/03/29 08:12:21 voeckler
+// fixed wrong header file.
+//
+// Revision 1.12 2000/03/29 07:54:41 voeckler
+// added mechanism to give a port specification precedence over a host
+// specificiation with the -p option and not colon.
+//
+// Revision 1.11 1999/06/18 13:18:28 voeckler
+// added refcount, fixed missing LF in -s output.
+//
+// Revision 1.10 1999/06/16 13:06:05 voeckler
+// reversed meaning of -M flag.
+//
+// Revision 1.9 1999/06/15 21:11:53 voeckler
+// added extended logging feature which extract the squid meta data available
+// within the disk files. moved the content extraction and squid meta data
+// handling parts into separate files. added options for copy-out and verbose.
+//
+// Revision 1.8 1999/06/14 20:14:46 voeckler
+// intermediate version when adding understanding about the way
+// Squid does log the metadata into the file.
+//
+// Revision 1.7 1999/01/23 21:01:10 root
+// stumbled over libc5 header/lib inconsistency bug....
+//
+// Revision 1.6 1999/01/23 20:47:54 root
+// added Linux specifics for psignal...
+// Hope this helps.
+//
+// Revision 1.5 1999/01/20 09:48:12 voeckler
+// added warning as first line of output.
+//
+// Revision 1.4 1999/01/19 11:53:49 voeckler
+// added psignal() from <siginfo.h> handling.
+//
+// Revision 1.3 1999/01/19 11:00:50 voeckler
+// added keyboard interrupt handling, exit handling, removed C++ strings and
+// regular expression syntax in favour of less source code, added comments,
+// added a reminder to remove swap.state in case of unlinks, added IAA flag,
+// added a few assertions, changed policy to enforce the definition of at
+// least one regular expression, and catch a few signals.
+//
+// Revision 1.2 1999/01/15 23:06:28 voeckler
+// downgraded to simple C strings...
+//
+// Revision 1.1 1999/01/14 12:05:32 voeckler
+// Initial revision
+//
+//
+#if defined(__GNUC__) || defined(__GNUG__)
+#pragma implementation
+#else
+#ifndef HAS_BOOL
+#define HAS_BOOL
+typedef int bool;
+#define false 0
+#define true 1
+#endif
+#endif
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <signal.h>
+#include <errno.h>
+
+#if defined(HAS_PSIGNAL) && !defined(LINUX) && !defined(FREEBSD)
+#include <siginfo.h>
+#endif // HAS_PSIGNAL
+
+#include <netinet/in.h>
+#include <netinet/tcp.h> // TCP_NODELAY
+#include <arpa/inet.h>
+#include <netdb.h> // gethostbyname()
+#include <regex.h>
+
+#include "convert.hh"
+#include "socket.hh"
+#include "signal.hh"
+#include "squid-tlv.hh"
+#include "copyout.hh"
+#include "conffile.hh"
+
+#ifndef DEFAULTHOST
+#define DEFAULTHOST "localhost"
+#endif // DEFAULTHOST
+
+#ifndef DEFAULTPORT
+#define DEFAULTPORT 3128
+#endif // DEFAULTPORT
+
+volatile sig_atomic_t term_flag = 0; // 'terminate' is a gcc 2.8.x internal...
+ char* linebuffer = 0;
+ size_t buffersize = 16834;
+static char* copydir = 0;
+static unsigned debug = 0;
+static unsigned purgeMode = 0;
+static bool iamalive = false;
+static bool reminder = false;
+static bool verbose = false;
+static bool envelope = false;
+static bool no_fork = false;
+static const char* programname = 0;
+static const char* RCS_ID =
+"$Id: purge.cc,v 1.17 2000/09/21 10:59:53 cached Exp $";
+
+// ----------------------------------------------------------------------
+
+struct REList {
+ REList( const char* what, bool doCase );
+ ~REList();
+ bool match( const char* check ) const;
+
+ REList* next;
+ const char* data;
+ regex_t rexp;
+};
+
+REList::REList( const char* what, bool doCase )
+ :next(0),data(strdup(what))
+{
+ int result = regcomp( &rexp, what,
+ REG_EXTENDED | REG_NOSUB | (doCase ? 0 : REG_ICASE) );
+ if ( result != 0 ) {
+ char buffer[256];
+ regerror( result, &rexp, buffer, 256 );
+ fprintf( stderr, "unable to compile re \"%s\": %s\n", what, buffer );
+ exit(1);
+ }
+}
+
+REList::~REList()
+{
+ if ( next ) delete next;
+ if ( data ) free((void*) data);
+ regfree(&rexp);
+}
+
+bool
+REList::match( const char* check ) const
+{
+ int result = regexec( &rexp, check, 0, 0, 0 );
+ if ( result != 0 && result != REG_NOMATCH ) {
+ char buffer[256];
+ regerror( result, &rexp, buffer, 256 );
+ fprintf( stderr, "unable to execute re \"%s\"\n+ on line \"%s\": %s\n",
+ data, check, buffer );
+ exit(1);
+ }
+ return ( result == 0 );
+}
+
+// ----------------------------------------------------------------------
+
+char*
+concat( const char* start, ... )
+ // purpose: concatinate an arbitrary number of C strings.
+ // paramtr: start (IN): first C string
+ // ... (IN): further C strings, terminated with a NULL pointer
+ // returns: memory allocated via new(), containing the concatinated string.
+{
+ va_list ap;
+ const char* s;
+
+ // first run: determine size
+ unsigned size = strlen(start)+1;
+ va_start( ap, start );
+ while ( (s=va_arg(ap,const char*)) != NULL ) size += strlen(s ? s : "");
+ va_end(ap);
+
+ // allocate
+ char* result = new char[size];
+ if ( result == 0 ) {
+ perror( "string memory allocation" );
+ exit(1);
+ }
+
+ // second run: copy content
+ strcpy( result, start );
+ va_start( ap, start );
+ while ( (s=va_arg(ap,const char*)) != NULL ) strcat( result, s );
+ va_end(ap);
+
+ return result;
+}
+
+bool
+isxstring( const char* s, size_t testlen )
+ // purpose: test a string for conforming to xdigit
+ // paramtr: s (IN): string to test
+ // testlen (IN): length the string must have
+ // returns: true, iff strlen(s)==testlen && all_x_chars(s), false otherwise
+{
+ if ( strlen(s) != testlen ) return false;
+
+ size_t i=0;
+ while ( i<testlen && isxdigit(s[i]) ) i++;
+ return (i==testlen);
+}
+
+inline
+int
+log_output( const char* fn, int code, long size, const char* url )
+{
+ return printf( "%s %3d %8ld %s\n", fn, code, size, url );
+}
+
+static
+int
+log_extended( const char* fn, int code, long size, const SquidMetaList* meta )
+{
+ static const char hexdigit[] = "0123456789ABCDEF";
+ char md5[34];
+ const SquidTLV* findings = 0;
+
+ if ( meta && (findings = meta->search( STORE_META_KEY_MD5 )) ) {
+ unsigned char* s = (unsigned char*) findings->data;
+ for ( int j=0; j<16; j++, s++ ) {
+ md5[j*2+0] = hexdigit[ *s >> 4 ];
+ md5[j*2+1] = hexdigit[ *s & 15 ];
+ }
+ md5[32] = '\0'; // terminate string
+ } else {
+ sprintf( md5, "%-32s", "(no_md5_data_available)" );
+ }
+
+ char timeb[64];
+ if ( meta && (findings = meta->search( STORE_META_STD )) ) {
+ StoreMetaStd temp;
+ // make data aligned, avoid SIGBUS on RISC machines (ARGH!)
+ memcpy( &temp, findings->data, sizeof(StoreMetaStd) );
+ sprintf( timeb, "%08x %08x %08x %08x %04x %5hu ",
+ temp.timestamp, temp.lastref,
+ temp.expires, temp.lastmod, temp.flags, temp.refcount );
+ } else {
+ sprintf( timeb, "%08x %08x %08x %08x %04x %5hu ", -1, -1, -1, -1, 0, 0 );
+ }
+
+ // make sure that there is just one printf()
+ if ( meta && (findings = meta->search( STORE_META_URL )) ) {
+ return printf( "%s %3d %8ld %s %s %s\n",
+ fn, code, size, md5, timeb, findings->data );
+ } else {
+ return printf( "%s %3d %8ld %s %s strange_file\n",
+ fn, code, size, md5, timeb );
+ }
+}
+
+// o.k., this is pure lazyness...
+static struct in_addr serverHost;
+static unsigned short serverPort;
+
+bool
+action( int fd, size_t metasize,
+ const char* fn, const char* url, const SquidMetaList& meta )
+ // purpose: if cmdline-requested, send the purge request to the cache
+ // paramtr: fd (IN): open FD for the object file
+ // metasize (IN): offset into data portion of file (meta data size)
+ // fn (IN): name of the object file
+ // url (IN): URL string stored in the object file
+ // meta (IN): list containing further meta data
+ // returns: true for a successful action, false otherwise. The action
+ // may just print the file, send the purge request or even
+ // remove unwanted files.
+ // globals: ::purgeMode (IN): bit#0 set -> send purge request.
+ // bit#1 set -> remove 404 object files.
+ // ::serverHost (IN): cache host address
+ // ::serverPort (IN): cache port number
+{
+ static const char* schablone = "PURGE %s HTTP/1.0\r\nAccept: */*\r\n\r\n";
+ struct stat st;
+ long size = ( fstat(fd,&st) == -1 ? -1 : long(st.st_size - metasize) );
+ int status = 0;
+
+ // if we want to copy out the file, do that first of all.
+ if ( ::copydir && *copydir && size > 0 )
+ copy_out( st.st_size, metasize, ::debug,
+ fn, url, ::copydir, ::envelope );
+
+ // do we need to PURGE the file, yes, if purgemode bit#0 was set.
+ if ( ::purgeMode & 0x01 ) {
+ unsigned long bufsize = strlen(url) + strlen(schablone) + 4;
+ char* buffer = new char[bufsize];
+
+ sprintf( buffer, schablone, url );
+ int sockfd = connectTo( serverHost, serverPort, true );
+ if ( sockfd == -1 ) {
+ fprintf( stderr, "unable to connect to server: %s\n", strerror(errno) );
+ delete[] buffer;
+ return false;
+ }
+
+ int size = strlen(buffer);
+ if ( write( sockfd, buffer, size ) != size ) {
+ // error while talking to squid
+ fprintf( stderr, "unable to talk to server: %s\n", strerror(errno) );
+ close(sockfd);
+ delete[] buffer;
+ return false;
+ }
+ memset( buffer+8, 0, 4 );
+ if ( read( sockfd, buffer, bufsize ) < 1 ) {
+ // error while reading squid's answer
+ fprintf( stderr, "unable to read answer: %s\n", strerror(errno) );
+ close(sockfd);
+ delete[] buffer;
+ return false;
+ }
+ close(sockfd);
+ status = strtol(buffer+8,0,10);
+ delete[] buffer;
+ }
+
+ // log the output of our operation
+ bool flag = true;
+ if ( ::verbose ) flag = ( log_extended( fn, status, size, &meta ) >= 0 );
+ else flag = ( log_output( fn, status, size, url ) >= 0 );
+
+ // remove the file, if purgemode bit#1, and HTTP result status 404).
+ if ( (::purgeMode & 0x02) && status == 404 ) {
+ reminder = true;
+ if ( unlink(fn) == -1 )
+ // error while unlinking file, this may happen due to the cache
+ // unlinking a file while it is still in the readdir() cache of purge.
+ fprintf( stderr, "WARNING: unable to unlink %s: %s\n",
+ fn, strerror(errno) );
+ }
+
+ return flag;
+}
+
+bool
+match( const char* fn, const REList* list )
+ // purpose: do something with the given cache content filename
+ // paramtr: fn (IN): filename of cache file
+ // returns: true for successful action, false otherwise.
+ // warning: only return false, if you want the loop to terminate!
+{
+ static const size_t addon = sizeof(unsigned char) + sizeof(unsigned int);
+ bool flag = true;
+
+ if ( debug & 0x01 ) fprintf( stderr, "# [3] %s\n", fn );
+ int fd = open( fn, O_RDONLY );
+ if ( fd != -1 ) {
+ if ( read(fd,::linebuffer,::buffersize-1) > 60 ) {
+ ::linebuffer[ ::buffersize-1 ] = '\0'; // force-terminate string
+
+ // check the offset into the start of object data. The offset is
+ // stored in a host endianess after the first byte.
+ unsigned int datastart;
+ memcpy( &datastart, ::linebuffer + 1, sizeof(unsigned int) );
+ if ( datastart > ::buffersize - addon - 1 ) {
+ // check offset into server reply header (start of cache data).
+ fputs( "WARNING: Using a truncated URL string.\n", stderr );
+ datastart = ::buffersize - addon - 1;
+ }
+
+ // NEW: Parse squid meta data, which is a kind of linked list
+ // flattened out into a file byte stream. Somewhere within is
+ // the URL as part of the list. First, gobble all meta data.
+ unsigned int offset = addon;
+ SquidMetaList meta;
+ while ( offset < datastart && *(offset+linebuffer) != STORE_META_END ) {
+ unsigned int size = 0;
+ memcpy( &size, linebuffer+offset+sizeof(char), sizeof(unsigned int) );
+ meta.append( SquidMetaType(*(linebuffer+offset)),
+ size, linebuffer+offset+addon );
+ offset += ( addon + size );
+ }
+
+ // Now extract the key URL from the meta data.
+ const SquidTLV* urlmeta = meta.search( STORE_META_URL );
+ if ( urlmeta ) {
+ // found URL in meta data. Try to process the URL
+ if ( list == 0 )
+ flag = action( fd, datastart, fn, (char*) urlmeta->data, meta );
+ else {
+ REList* head = (REList*) list; // YUCK!
+ while ( head != 0 ) {
+ if ( head->match( (char*) urlmeta->data ) ) break;
+ head = head->next;
+ }
+ if ( head != 0 )
+ flag = action( fd, datastart, fn, (char*) urlmeta->data, meta );
+ else flag = true;
+ }
+ }
+
+ // "meta" will be deleted when exiting from this block
+ } else {
+ // weird file, FIXME: stat() it!
+ struct stat st;
+ long size = ( fstat(fd,&st) == -1 ? -1 : st.st_size );
+ if ( ::verbose ) flag = ( log_extended( fn, -1, size, 0 ) >= 0 );
+ else flag = ( log_output( fn, -1, size, "strange file" ) >= 0 );
+
+ if ( (::purgeMode & 0x04) ) {
+ reminder = true;
+ if ( unlink(fn) == -1 )
+ // error while unlinking file, this may happen due to the cache
+ // unlinking a file while it is in the readdir() cache of purge.
+ fprintf( stderr, "WARNING: unable to unlink %s: %s\n",
+ fn, strerror(errno) );
+ }
+ }
+ close(fd);
+ } else {
+ // error while opening file, this may happen due to the cache
+ // unlinking a file while it is still in the readdir() cache of purge.
+ fprintf( stderr, "WARNING: open \"%s\": %s\n", fn, strerror(errno) );
+ }
+
+ return flag;
+}
+
+bool
+filelevel( const char* directory, const REList* list )
+ // purpose: from given starting point, look for squid xxxxxxxx files.
+ // example: "/var/spool/cache/08/7F" as input, do action over files
+ // paramtr: directory (IN): starting point
+ // list (IN): list of rexps to match URLs against
+ // returns: true, if every subdir && action was successful.
+{
+ struct dirent* entry;
+ if ( debug & 0x01 )
+ fprintf( stderr, "# [2] %s\n", directory );
+
+ DIR* dir = opendir( directory );
+ if ( dir == NULL ) {
+ fprintf( stderr, "unable to open directory \"%s\": %s\n",
+ directory, strerror(errno) );
+ return false;
+ }
+
+ // display a rotating character as "i am alive" signal (slows purge).
+ if ( ::iamalive ) {
+ static char alivelist[4][3] = { "\\\b", "|\b", "/\b", "-\b" };
+ static unsigned short alivecount = 0;
+ assert( write( STDOUT_FILENO, alivelist[alivecount++ & 3], 2 ) == 2 );
+ }
+
+ bool flag = true;
+ while ( (entry=readdir(dir)) && flag ) {
+ if ( isxstring(entry->d_name,8) ) {
+ char* name = concat( directory, "/", entry->d_name, 0 );
+ flag = match( name, list );
+ delete[] name;
+ }
+ }
+
+ closedir(dir);
+ return flag;
+}
+
+bool
+dirlevel( const char* dirname, const REList* list, bool level=false )
+ // purpose: from given starting point, look for squid 00..FF directories.
+ // paramtr: dirname (IN): starting point
+ // list (IN): list of rexps to match URLs against
+ // level (IN): false==toplevel, true==1st level
+ // example: "/var/spool/cache", false as input, traverse subdirs w/ action.
+ // example: "/var/spool/cache/08", true as input, traverse subdirs w/ action.
+ // returns: true, if every subdir && action was successful.
+ // warning: this function is once-recursive, no deeper.
+{
+ struct dirent* entry;
+ if ( debug & 0x01 )
+ fprintf( stderr, "# [%d] %s\n", (level ? 1 : 0), dirname );
+
+ DIR* dir = opendir( dirname );
+ if ( dir == NULL ) {
+ fprintf( stderr, "unable to open directory \"%s\": %s\n",
+ dirname, strerror(errno) );
+ return false;
+ }
+
+ bool flag = true;
+ while ( (entry=readdir(dir)) && flag ) {
+ if ( strlen(entry->d_name) == 2 &&
+ isxdigit(entry->d_name[0]) &&
+ isxdigit(entry->d_name[1]) ) {
+ char* name = concat( dirname, "/", entry->d_name, 0 );
+ flag = level ? filelevel( name, list ) : dirlevel( name, list, true );
+ delete[] name;
+ }
+ }
+
+ closedir(dir);
+ return flag;
+}
+
+int
+checkForPortOnly( const char* optarg )
+ // purpose: see if somebody just put in a port instead of a hostname
+ // paramtr: optarg (IN): argument from commandline
+ // returns: 0..65535 is the valid port number in network byte order,
+ // -1 if not a port
+{
+ // if there is a period in there, it must be a valid hostname
+ if ( strchr( optarg, '.' ) != 0 ) return -1;
+
+ // if it is just a number between 0 and 65535, it must be a port
+ char* errstr = 0;
+ unsigned long result = strtoul( optarg, &errstr, 0 );
+ if ( result < 65536 && errstr != optarg ) return htons(result);
+
+#if 0
+ // one last try, test for a symbolical service name
+ struct servent* service = getservbyname( optarg, "tcp" );
+ return service ? service->s_port : -1;
+#else
+ return -1;
+#endif
+}
+
+void
+helpMe( void )
+ // purpuse: write help message and exit
+{
+ printf( "\n%s\nUsage:\t%s\t[-a] [-c cf] [-d l] [-(f|F) fn | -(e|E) re] "
+ "[-p h[:p]]\n\t\t[-P #] [-s] [-v] [-C dir [-H]] [-n]\n\n",
+ ::RCS_ID, ::programname );
+ printf(
+" -a\tdisplay a little rotating thingy to indicate that I am alive (tty only).\n"
+" -c c\tsquid.conf location, default \"%s\".\n"
+" -C dir\tbase directory for content extraction (copy-out mode).\n"
+" -d l\tdebug level, an OR of different debug options.\n"
+" -e re\tsingle regular expression per -e instance (use quotes!).\n"
+" -E re\tsingle case sensitive regular expression like -e.\n"
+" -f fn\tname of textfile containing one regular expression per line.\n"
+" -F fn\tname of textfile like -f containing case sensitive REs.\n"
+" -H\tprepend HTTP reply header to destination files in copy-out mode.\n"
+" -n\tdo not fork() when using more than one cache_dir.\n"
+" -p h:p\tcache runs on host h and optional port p, default is %s:%u.\n"
+" -P #\tif 0, just print matches; otherwise OR the following purge modes:\n"
+"\t 0x01 really send PURGE to the cache.\n"
+"\t 0x02 remove all caches files reported as 404 (not found).\n"
+"\t 0x04 remove all weird (inaccessible or too small) cache files.\n"
+"\t0 and 1 are recommended - slow rebuild your cache with other modes.\n"
+" -s\tshow all options after option parsing, but before really starting.\n"
+" -v\tshow more information about the file, e.g. MD5, timestamps and flags.\n"
+"\n", DEFAULT_SQUID_CONF, DEFAULTHOST, DEFAULTPORT );
+
+}
+
+void
+parseCommandline( int argc, char* argv[], REList*& head,
+ char*& conffile, char*& copydir,
+ struct in_addr& serverHost, unsigned short& serverPort )
+ // paramtr: argc: see ::main().
+ // argv: see ::main().
+ // returns: Does terminate the program on errors!
+ // purpose: suck in any commandline options, and set the global vars.
+{ int option, port, showme = 0;
+ char* ptr, *colon;
+ FILE* rfile;
+
+ // program basename
+ if ( (ptr = strrchr(argv[0],'/')) == NULL ) ptr=argv[0];
+ else ptr++;
+ ::programname = ptr;
+
+ // extract commandline parameters
+ REList* tail = head = 0;
+ opterr = 0;
+ while ( (option = getopt( argc, argv, "ac:C:d:E:e:F:f:Hnp:P:sv" )) != -1 ) {
+ switch ( option ) {
+ case 'a':
+ ::iamalive = ! ::iamalive;
+ break;
+ case 'C':
+ if ( optarg && *optarg ) {
+ if ( copydir ) free( (void*) copydir );
+ assert( (copydir = strdup(optarg)) );
+ }
+ break;
+ case 'c':
+ if ( optarg && *optarg ) {
+ if ( *conffile ) free((void*) conffile );
+ assert( (conffile = strdup(optarg)) );
+ }
+ break;
+
+ case 'd':
+ ::debug = strtoul( optarg, 0, 0 );
+ break;
+
+ case 'E':
+ case 'e':
+ if ( head == 0 ) tail = head = new REList( optarg, option=='E' );
+ else {
+ tail->next = new REList( optarg, option=='E' );
+ tail = tail->next;
+ }
+ break;
+
+ case 'f':
+ if ( (rfile = fopen( optarg, "r" )) != NULL ) {
+ unsigned long lineno = 0;
+#define LINESIZE 512
+ char line[LINESIZE];
+ while ( fgets( line, LINESIZE, rfile ) != NULL ) {
+ lineno++;
+ int len = strlen(line)-1;
+ if ( len+2 >= LINESIZE ) {
+ fprintf( stderr, "%s:%lu: line too long, sorry.\n",
+ optarg, lineno );
+ exit(1);
+ }
+
+ // remove trailing line breaks
+ while ( len > 0 && ( line[len] == '\n' || line[len] == '\r' ) )
+ line[len--] = '\0';
+
+ // insert into list of expressions
+ if ( head == 0 ) tail = head = new REList(line,option=='F');
+ else {
+ tail->next = new REList(line,option=='F');
+ tail = tail->next;
+ }
+ }
+ fclose(rfile);
+ } else
+ fprintf( stderr, "unable to open %s: %s\n", optarg, strerror(errno));
+ break;
+
+ case 'H':
+ ::envelope = ! ::envelope;
+ break;
+ case 'n':
+ ::no_fork = ! ::no_fork;
+ break;
+ case 'p':
+ colon = strchr( optarg, ':' );
+ if ( colon == 0 ) {
+ // no colon, only look at host
+
+ // fix: see if somebody just put in there a port (no periods)
+ // give port number precedence over host names
+ port = checkForPortOnly( optarg );
+ if ( port == -1 ) {
+ // assume that main() did set the default port
+ if ( convertHostname(optarg,serverHost) == -1 ) {
+ fprintf( stderr, "unable to resolve host %s!\n", optarg );
+ exit(1);
+ }
+ } else {
+ // assume that main() did set the default host
+ serverPort = port;
+ }
+ } else {
+ // colon used, port is extra
+ *colon++ = 0;
+ if ( convertHostname(optarg,serverHost) == -1 ) {
+ fprintf( stderr, "unable to resolve host %s!\n", optarg );
+ exit(1);
+ }
+ if ( convertPortname(colon,serverPort) == -1 ) {
+ fprintf( stderr, "unable to resolve port %s!\n", colon );
+ exit(1);
+ }
+ }
+ break;
+ case 'P':
+ ::purgeMode = ( strtol( optarg, 0, 0 ) & 0x07 );
+ break;
+ case 's':
+ showme=1;
+ break;
+ case 'v':
+ ::verbose = ! ::verbose;
+ break;
+ case '?':
+ default:
+ helpMe();
+ exit(1);
+ }
+ }
+
+ // adjust
+ if ( ! isatty(fileno(stdout)) || (::debug & 0x01) ) ::iamalive = false;
+ if ( head == 0 ) {
+ fputs( "There was no regular expression defined. If you intend\n", stderr );
+ fputs( "to match all possible URLs, use \"-e .\" instead.\n", stderr );
+ exit(1);
+ }
+
+ // postcondition: head != 0
+ assert( head != 0 );
+
+ // make sure that the copy out directory is there and accessible
+ if ( copydir && *copydir )
+ if ( assert_copydir( copydir ) != 0 ) exit(1);
+
+ // show results
+ if ( showme ) {
+ printf( "#\n# Currently active values for %s:\n# %s\n",
+ ::programname, ::RCS_ID );
+ printf( "# Debug level : " );
+ if ( ::debug ) printf( "%#6.4hx", ::debug );
+ else printf( "production level" ); // printf omits 0x prefix for 0!
+ printf( " + %s mode", ::no_fork ? "linear" : "parallel" );
+ puts( ::verbose ? " + extra verbosity" : "" );
+
+ printf( "# Copy-out directory: %s ",
+ copydir ? copydir : "copy-out mode disabled" );
+ if ( copydir )
+ printf( "(%s HTTP header)\n", ::envelope ? "prepend" : "no" );
+ else
+ puts("");
+
+ printf( "# Squid config file : %s\n", conffile );
+ printf( "# Cacheserveraddress: %s:%u\n",
+ inet_ntoa( serverHost ), ntohs( serverPort ) );
+ printf( "# purge mode : 0x%02x\n", ::purgeMode );
+ printf( "# Regular expression: " );
+
+ unsigned count(0);
+ for ( tail = head; tail != NULL; tail = tail->next ) {
+ if ( count++ ) printf( "#%22u", count );
+#if defined(LINUX) && putc==_IO_putc
+ // I HATE BROKEN LINUX HEADERS!
+ // purge.o(.text+0x1040): undefined reference to `_IO_putc'
+ // If your compilation breaks here, remove the undefinition
+#undef putc
+#endif
+ else putchar('1');
+ printf( " \"%s\"\n", tail->data );
+ }
+ puts( "#" );
+ }
+ fflush( stdout );
+}
+
+extern "C" {
+
+static
+void
+exiter( void )
+{
+ if ( ::term_flag ) psignal( ::term_flag, "received signal" );
+ delete[] ::linebuffer;
+ if ( ::reminder ) {
+ fputs(
+"WARNING! Caches files were removed. Please shut down your cache, remove\n"
+"your swap.state files and restart your cache again, i.e. effictively do\n"
+"a slow rebuild your cache! Otherwise your squid *will* choke!\n", stderr );
+ }
+}
+
+static
+void
+handler( int signo )
+{
+ ::term_flag = signo;
+ if ( getpid() == getpgrp() ) kill( -getpgrp(), signo );
+ exit(1);
+}
+
+} // extern "C"
+
+static
+int
+makelinebuffered( FILE* fp, const char* fn = 0 )
+ // purpose: make the given FILE line buffered
+ // paramtr: fp (IO): file pointer which to put into line buffer mode
+ // fn (IN): name of file to print in case of error
+ // returns: 0 is ok, -1 to indicate an error
+ // warning: error messages will already be printed
+{
+ if ( setvbuf( fp, 0, _IOLBF, 0 ) == 0 ) {
+ // ok
+ return 0;
+ } else {
+ // error
+ fprintf( stderr, "unable to make \"%s\" line buffered: %s\n",
+ fn ? fn : "", strerror(errno) );
+ return -1;
+ }
+}
+
+int
+main( int argc, char* argv[] )
+{
+ // setup variables
+ REList* list = 0;
+ char* conffile = strdup( DEFAULT_SQUID_CONF );
+ serverPort = htons(DEFAULTPORT);
+ if ( convertHostname(DEFAULTHOST,serverHost) == -1 ) {
+ fprintf( stderr, "unable to resolve host %s!\n", DEFAULTHOST );
+ return 1;
+ }
+
+ // setup line buffer
+ ::linebuffer = new char[ ::buffersize ];
+ assert( ::linebuffer != 0 );
+
+ // parse commandline
+ puts( "### Use at your own risk! No guarantees whatsoever. You were warned. ###");
+ parseCommandline( argc, argv, list, conffile, ::copydir,
+ serverHost, serverPort );
+
+ // prepare execution
+ if ( atexit( exiter ) != 0 ||
+ Signal( SIGTERM, handler, true ) == SIG_ERR ||
+ Signal( SIGINT, handler, true ) == SIG_ERR ||
+ Signal( SIGHUP, handler, true ) == SIG_ERR ) {
+ perror( "unable to install signal/exit function" );
+ return 1;
+ }
+
+ // try to read squid.conf file to determine all cache_dir locations
+ CacheDirVector cdv(0);
+ if ( readConfigFile( cdv, conffile, debug ? stderr : 0 ) > 0 ) {
+ // there are some valid cache_dir entries.
+ // unless forking was forbidden by cmdline option,
+ // for a process for each cache_dir entry to remove files.
+
+ if ( ::no_fork || cdv.size() == 1 ) {
+ // linear mode, one cache_dir after the next
+ for ( CacheDirVector::iterator i = cdv.begin(); i != cdv.end(); ++i ) {
+ // execute OR complain
+ if ( ! dirlevel(i->base,list) )
+ fprintf( stderr, "program terminated due to error: %s",
+ strerror(errno) );
+ free((void*) i->base);
+ }
+ } else {
+ // parallel mode, all cache_dir in parallel
+ pid_t* child = new pid_t[ cdv.size() ];
+
+ // make stdout/stderr line bufferd
+ makelinebuffered( stdout, "stdout" );
+ makelinebuffered( stderr, "stderr" );
+
+ // make parent process group leader for easier killings
+ if ( setpgid(getpid(), getpid()) != 0 ) {
+ perror( "unable to set process group leader" );
+ return 1;
+ }
+
+ // -a is mutually exclusive with fork mode
+ if ( ::iamalive ) {
+ puts( "# i-am-alive flag incompatible with fork mode, resetting" );
+ ::iamalive = false;
+ }
+
+ for ( int i=0; i < cdv.size(); ++i ) {
+ if ( getpid() == getpgrp() ) {
+ // only parent == group leader may fork off new processes
+ if ( (child[i]=fork()) < 0 ) {
+ // fork error, this is bad!
+ perror( "unable to fork" );
+ kill( -getpgrp(), SIGTERM );
+ return 1;
+ } else if ( child[i] == 0 ) {
+ // child mode
+ // execute OR complain
+ if ( ! dirlevel(cdv[i].base,list) )
+ fprintf( stderr, "program terminated due to error: %s\n",
+ strerror(errno) );
+ free((void*) cdv[i].base);
+ return 0;
+ } else {
+ // parent mode
+ if ( ::debug ) printf( "forked child %d\n", (int) child[i] );
+ }
+ }
+ }
+
+ // collect the garbase
+ pid_t temp;
+ int status;
+ for ( int i=0; i < cdv.size(); ++i ) {
+ while ( (temp=waitpid( (pid_t)-1, &status, 0 )) == -1 )
+ if ( errno == EINTR ) continue;
+ if ( ::debug ) printf( "collected child %d\n", (int) temp );
+ }
+ delete[] child;
+ }
+ } else {
+ fprintf( stderr, "no cache_dir or error accessing \"%s\"\n", conffile );
+ }
+
+ // clean up
+ if ( copydir ) free( (void*) copydir );
+ free((void*) conffile);
+ delete list;
+ return 0;
+}
--- /dev/null
+//
+// $Id: signal.cc,v 1.3 1999/01/19 13:11:52 cached Exp $
+//
+// Author: Jens-S. Vöckler <voeckler@rvs.uni-hannover.de>
+// File: signal.cc
+// Date: Sat Feb 28 1998
+// Compiler: gcc 2.7.2.x series
+//
+// Books: W. Richard Steven, "Advanced Programming in the UNIX Environment",
+// Addison-Wesley, 1992.
+//
+// (c) 1998 Lehrgebiet Rechnernetze und Verteilte Systeme
+// Universität Hannover, Germany
+//
+// Permission to use, copy, modify, distribute, and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that (i) the above copyright notices and this permission
+// notice appear in all copies of the software and related documentation,
+// and (ii) the names of the Lehrgebiet Rechnernetze und Verteilte
+// Systeme and the University of Hannover may not be used in any
+// advertising or publicity relating to the software without the
+// specific, prior written permission of Lehrgebiet Rechnernetze und
+// Verteilte Systeme and the University of Hannover.
+//
+// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// IN NO EVENT SHALL THE LEHRGEBIET RECHNERNETZE UND VERTEILTE SYSTEME OR
+// THE UNIVERSITY OF HANNOVER BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
+// ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
+// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+// SOFTWARE.
+//
+// $Log: signal.cc,v $
+// Revision 1.3 1999/01/19 13:11:52 cached
+// adaptations necessary for AIX.
+//
+// Revision 1.2 1999/01/19 11:00:50 voeckler
+// added psignal(int,const char*) compatibility function.
+//
+// Revision 1.1 1998/08/13 21:51:58 voeckler
+// Initial revision
+//
+//
+
+#if defined(__GNUC__) || defined(__GNUG__)
+#pragma implementation
+#endif
+
+#include <sys/types.h>
+#include <errno.h>
+#include <string.h>
+#include <memory.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#include "signal.hh"
+
+static const char* RCS_ID =
+"$Id: signal.cc,v 1.3 1999/01/19 13:11:52 cached Exp $";
+
+#ifndef HAS_PSIGNAL
+#ifdef AIX
+extern const char* const sys_siglist[];
+#define _sys_nsig 64
+#define _sys_siglist sys_siglist
+#endif // AIX
+
+void
+psignal( int sig, const char* msg )
+ // purpose: print message, colon, space, signal name and LF.
+ // paramtr: sig (IN): signal number
+ // msg (IN): message to prepend
+{
+ if ( msg && *msg ) fprintf( stderr, "%s: ", msg );
+ if ( sig > 0 && sig < _sys_nsig )
+ fprintf( stderr, "%s\n", _sys_siglist[sig] );
+ else
+ fputs( "(unknown)\n", stderr );
+}
+#endif // !HAS_PSIGNAL
+
+SigFunc*
+Signal( int signo, SigFunc* newhandler, bool doInterrupt )
+ // purpose: install reliable signals
+ // paramtr: signo (IN): signal for which a handler is to be installed
+ // newhandler (IN): function pointer to the signal handler
+ // doInterrupt (IN): interrupted system calls wanted!
+ // returns: the old signal handler, or SIG_ERR in case of error.
+{
+ struct sigaction action, old;
+
+ memset( &old, 0, sizeof(old) );
+ memset( &action, 0, sizeof(action) );
+
+ // action.sa_handler = newhandler; I HATE TYPE-OVERCORRECTNESS !
+ memmove( &action.sa_handler, &newhandler, sizeof(SigFunc*) );
+ sigemptyset( &action.sa_mask );
+
+ if ( signo == SIGCHLD ) {
+ action.sa_flags |= SA_NOCLDSTOP;
+
+#ifdef SA_NODEFER
+ action.sa_flags |= SA_NODEFER; // SYSV: don't block current signal
+#endif
+ }
+
+ if ( signo == SIGALRM || doInterrupt ) {
+#ifdef SA_INTERRUPT
+ action.sa_flags |= SA_INTERRUPT; // SunOS, obsoleted by POSIX
+#endif
+ } else {
+#ifdef SA_RESTART
+ action.sa_flags |= SA_RESTART; // BSD, SVR4
+#endif
+ }
+
+ return ( sigaction( signo, &action, &old ) < 0 ) ?
+ (SigFunc*) SIG_ERR :
+ (SigFunc*) old.sa_handler;
+}
+
+SIGRETTYPE
+sigChild( int signo )
+ // purpose: supply ad hoc child handler with output on stderr
+ // paramtr: signo (IN): == SIGCHLD
+ // returns: only if OS uses a return type for signal handler
+ // seealso: Stevens, UNP, figure 5.11 *and* Stevens, APUE, figure 8.3
+{
+ pid_t pid;
+ int status = signo; // to stop GNU from complaining...
+ char line[128];
+
+ int saveerr = errno;
+ while ( (pid = waitpid( -1, &status, WNOHANG )) > 0 ) {
+ if ( WIFEXITED(status) ) {
+ sprintf( line, "child (pid=%ld) reaped, status %d\n%c",
+ (long) pid, WEXITSTATUS(status), 0 );
+ } else if ( WIFSIGNALED(status) ) {
+ sprintf( line, "child (pid=%ld) died on signal %d%s\n%c",
+ (long) pid, WTERMSIG(status),
+#ifdef WCOREDUMP
+ WCOREDUMP(status) ? " (core generated)" : "",
+#else
+ "",
+#endif
+ 0 );
+ } else {
+ sprintf( line, "detected dead child (pid=%ld), status %d\n%c",
+ (long) pid, status, 0 );
+ }
+ write( STDERR_FILENO, line, strlen(line) );
+ }
+ errno = saveerr;
+
+#if SIGRETTYPE != void
+ return 0;
+#endif
+}
--- /dev/null
+//
+// $Id: signal.hh,v 1.4 2000/09/21 10:59:27 cached Exp $
+//
+// Author: Jens-S. Vöckler <voeckler@rvs.uni-hannover.de>
+// File: signal.hh
+// Date: Sat Feb 28 1998
+// Compiler: gcc 2.7.2.x series
+//
+// Books: W. Richard Steven, "Advanced Programming in the UNIX Environment",
+// Addison-Wesley, 1992.
+//
+// (c) 1998 Lehrgebiet Rechnernetze und Verteilte Systeme
+// Universität Hannover, Germany
+//
+// Permission to use, copy, modify, distribute, and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that (i) the above copyright notices and this permission
+// notice appear in all copies of the software and related documentation,
+// and (ii) the names of the Lehrgebiet Rechnernetze und Verteilte
+// Systeme and the University of Hannover may not be used in any
+// advertising or publicity relating to the software without the
+// specific, prior written permission of Lehrgebiet Rechnernetze und
+// Verteilte Systeme and the University of Hannover.
+//
+// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// IN NO EVENT SHALL THE LEHRGEBIET RECHNERNETZE UND VERTEILTE SYSTEME OR
+// THE UNIVERSITY OF HANNOVER BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
+// ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
+// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+// SOFTWARE.
+//
+// $Log: signal.hh,v $
+// Revision 1.4 2000/09/21 10:59:27 cached
+// introduced extern "C" to function pointer type.
+//
+// Revision 1.3 1999/01/19 11:53:49 voeckler
+// added bool compatibility definitions.
+//
+// Revision 1.2 1999/01/19 11:00:50 voeckler
+// added psignal(int,const char*) compatibility function declaration.
+//
+// Revision 1.1 1998/08/13 21:51:58 voeckler
+// Initial revision
+//
+//
+#ifndef _SIGNAL_HH
+#define _SIGNAL_HH
+
+#if defined(__GNUC__) || defined(__GNUG__)
+#pragma interface
+#else
+#ifndef HAS_BOOL
+#define HAS_BOOL
+typedef int bool;
+#define false 0
+#define true 1
+#endif
+#endif
+
+#if 1 // so far, all systems I know use void
+# define SIGRETTYPE void
+#else
+# define SIGRETTYPE int
+#endif
+
+#if defined(SUNOS) && defined(SUN)
+# define SIGPARAM void
+#else // SOLARIS, LINUX, IRIX, AIX, SINIXY
+# define SIGPARAM int
+#endif
+
+extern "C" {
+ typedef SIGRETTYPE SigFunc( SIGPARAM );
+}
+
+#ifndef HAS_PSIGNAL
+void
+psignal( int sig, const char* msg );
+ // purpose: print message, colon, space, signal name and LF.
+ // paramtr: sig (IN): signal number
+ // msg (IN): message to prepend
+#endif // ! HAS_PSIGNAL
+
+SigFunc*
+Signal( int signo, SigFunc* newhandler, bool doInterrupt );
+ // purpose: install reliable signals
+ // paramtr: signo (IN): signal for which a handler is to be installed
+ // newhandler (IN): function pointer to the signal handler
+ // doInterrupt (IN): interrupted system calls wanted!
+ // returns: the old signal handler, or SIG_ERR in case of error.
+
+SIGRETTYPE
+sigChild( int signo );
+ // purpose: supply ad hoc child handler with output on stderr
+ // paramtr: signo (IN): == SIGCHLD
+ // returns: only if OS uses a return type for signal handler
+
+#endif // _SIGNAL_HH
--- /dev/null
+//
+// $Id: socket.cc,v 1.3 1999/01/19 11:00:50 voeckler Exp $
+//
+// Author: Jens-S. Vöckler <voeckler@rvs.uni-hannover.de>
+//
+// File: socket.hh
+// Sun May 3 1998
+//
+// (c) 1998 Lehrgebiet Rechnernetze und Verteilte Systeme
+// Universität Hannover, Germany
+//
+// Books: W. Richard Steven, "Advanced Programming in the UNIX Environment",
+// Addison-Wesley, 1992.
+//
+// Permission to use, copy, modify, distribute, and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that (i) the above copyright notices and this permission
+// notice appear in all copies of the software and related documentation,
+// and (ii) the names of the Lehrgebiet Rechnernetze und Verteilte
+// Systeme and the University of Hannover may not be used in any
+// advertising or publicity relating to the software without the
+// specific, prior written permission of Lehrgebiet Rechnernetze und
+// Verteilte Systeme and the University of Hannover.
+//
+// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// IN NO EVENT SHALL THE LEHRGEBIET RECHNERNETZE UND VERTEILTE SYSTEME OR
+// THE UNIVERSITY OF HANNOVER BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
+// ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
+// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+// SOFTWARE.
+//
+// $Log: socket.cc,v $
+// Revision 1.3 1999/01/19 11:00:50 voeckler
+// Linux glibc2 fixes for socket size parameters.
+//
+// Revision 1.2 1998/08/27 15:23:39 voeckler
+// added TCP_NODELAY options at several places.
+//
+// Revision 1.1 1998/08/13 21:52:55 voeckler
+// Initial revision
+//
+//
+#if defined(__GNUC__) || defined(__GNUG__)
+#pragma implementation
+#endif
+
+#include "socket.hh"
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "convert.hh"
+
+static const char* RCS_ID =
+"$Id: socket.cc,v 1.3 1999/01/19 11:00:50 voeckler Exp $";
+
+int
+setSocketBuffers( int sockfd, int size )
+ // purpose: set socket buffers for both directions to the specified size
+ // paramtr: sockfd (IN): socket file descriptor
+ // size (IN): new socket buffer size
+ // returns: -1 on setsockopt() errors, 0 otherwise
+ // warning: prints error message on stderr, errno will be changed
+{
+ if ( setsockopt( sockfd, SOL_SOCKET, SO_RCVBUF,
+ (char*) &size, sizeof(size) ) == -1 ) {
+ perror( "setsockopt( SO_RCVBUF )" );
+ return -1;
+ }
+
+ if ( setsockopt( sockfd, SOL_SOCKET, SO_SNDBUF,
+ (char*) &size, sizeof(size) ) == -1 ) {
+ perror( "setsockopt( SO_SNDBUF )" );
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+getSocketNoDelay( int sockfd )
+ // purpose: get state of the TCP_NODELAY of the socket
+ // paramtr: sockfd (IN): socket descriptor
+ // returns: 1, if TCP_NODELAY is set,
+ // 0, if TCP_NODELAY is not set,
+ // -1, if an error occurred (e.g. datagram socket)
+{
+ int delay = 0;
+ SOCKLEN len = sizeof(delay);
+ if ( getsockopt( sockfd, IPPROTO_TCP, TCP_NODELAY,
+ (char*) &delay, &len ) == -1 ) {
+ perror( "# getsockopt( TCP_NODELAY ) failed" );
+ return -1;
+ } else
+ return ( delay ? 1 : 0 );
+}
+
+int
+setSocketNoDelay( int sockfd, bool nodelay )
+ // purpose: get state of the TCP_NODELAY of the socket
+ // paramtr: sockfd (IN): socket descriptor
+ // nodelay (IN): true, if TCP_NODELAY is to be set, false otherwise.
+ // returns: 0, if everything worked out o.k.
+ // -1, if an error occurred (e.g. datagram socket)
+{
+ const int delay = 1;
+ if ( setsockopt( sockfd, IPPROTO_TCP, TCP_NODELAY,
+ (const char*) &delay, sizeof(delay) ) == -1 ) {
+ perror( "setsockopt( TCP_NODELAY ) failed" );
+ return -1;
+ } else
+ return 0;
+}
+
+
+int
+commonCode( int& sockfd, bool nodelay, int sendBufferSize, int recvBufferSize )
+ // purpose: common code in server sockets and client sockets
+ // paramtr: sockfd (IO): socket filedescriptor
+ // nodelay (IN): true=set TCP_NODELAY option.
+ // sendBufferSize (IN): don't set (use sys defaults) if < 0
+ // recvBufferSize (IN): don't set (use sys defaults) if < 0
+ // returns: 0 == if everthing went ok, -1 otherwise
+ // warning: sockfd will be closed, if -1 is returned!
+{
+ // set TCP_NODELAY option, if that is wanted.
+ // The socket API default is unset.
+ if ( nodelay ) {
+ const int delay = 1;
+ if ( setsockopt( sockfd, IPPROTO_TCP, TCP_NODELAY,
+ (const char*) &delay, sizeof(delay) ) == -1 ) {
+ perror( "setsockopt( TCP_NODELAY ) failed" );
+ close(sockfd);
+ return -1;
+ }
+ }
+
+ // set the socket send buffer size explicitly, or use the system default
+ if ( sendBufferSize >= 0 ) {
+ if ( setsockopt( sockfd, SOL_SOCKET, SO_SNDBUF, (char*) &sendBufferSize,
+ sizeof(sendBufferSize) ) == -1 ) {
+ perror( "setsockopt( SO_SNDBUF )" );
+ close(sockfd);
+ return -1;
+ }
+ }
+
+ // set the socket recv buffer size explicitly, or use the system default
+ if ( recvBufferSize >= 0 ) {
+ if ( setsockopt( sockfd, SOL_SOCKET, SO_RCVBUF, (char*) &recvBufferSize,
+ sizeof(recvBufferSize) ) == -1 ) {
+ perror( "setsockopt( SO_RCVBUF )" );
+ close(sockfd);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int
+connectTo( struct in_addr host, unsigned short port, bool nodelay,
+ int sendBufferSize, int recvBufferSize )
+ // purpose: connect to a server as a client
+ // paramtr: host (IN): address describing the server
+ // port (IN): port to connect at the server
+ // nodelay (IN): true=set TCP_NODELAY option.
+ // sendBufferSize (IN): don't set (use sys defaults) if < 0
+ // recvBufferSize (IN): don't set (use sys defaults) if < 0
+ // returns: >=0 is the descriptor of the opened, connected socket,
+ // -1 is an indication of an error (errno may have been reset).
+{
+ int sockfd = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );
+ if ( sockfd == -1 ) {
+ perror( "socket() failed" );
+ return -1;
+ }
+
+ if ( commonCode( sockfd, nodelay, sendBufferSize, recvBufferSize ) == -1 )
+ return -1;
+
+ struct sockaddr_in server;
+ memset( &server, 0, sizeof(server) );
+ server.sin_family = AF_INET;
+ server.sin_addr = host;
+ server.sin_port = port;
+ if ( connect( sockfd, (struct sockaddr*) &server, sizeof(server) ) == -1 ) {
+ perror( "connect() failure" );
+ close(sockfd);
+ return -1;
+ }
+
+ return sockfd;
+}
+
+int
+serverSocket( struct in_addr host, unsigned short port,
+ int backlog, bool reuse, bool nodelay,
+ int sendBufferSize, int recvBufferSize )
+ // purpose: open a server socket for listening
+ // paramtr: host (IN): host to bind locally to, use INADDRY_ANY for *
+ // port (IN): port to bind to, use 0 for system assigned
+ // backlog (IN): listen backlog queue length
+ // reuse (IN): set SO_REUSEADDR option - default usefully
+ // nodelay (IN): true=set TCP_NODELAY option.
+ // SETTING TCP_NODELAY ON A SERVER SOCKET DOES NOT MAKE SENSE!
+ // sendBufferSize (IN): don't set (use sys defaults) if < 0
+ // recvBufferSize (IN): don't set (use sys defaults) if < 0
+ // returns: opened listening fd, or -1 on error.
+ // warning: error message will be printed on stderr and errno reset.
+{
+ int sockfd = socket( AF_INET, SOCK_STREAM, 0 );
+ if ( sockfd == -1 ) {
+ perror( "socket" );
+ return -1;
+ }
+
+ if ( reuse ) {
+ int reuse = 1;
+ if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR,
+ (char*) &reuse, sizeof(int) ) == -1) {
+ perror( "setsockopt( SO_REUSEADDR )" );
+ close( sockfd );
+ return -1;
+ }
+ }
+
+ if ( commonCode( sockfd, nodelay, sendBufferSize, recvBufferSize ) == -1 )
+ return -1;
+
+ struct sockaddr_in server;
+ memset( &server, 0, sizeof(server) );
+ server.sin_family = AF_INET;
+ server.sin_port = port;
+ server.sin_addr = host;
+ if ( bind( sockfd, (SA*) &server, sizeof(server) ) == -1 ) {
+ SockAddress socket;
+ fprintf( stderr, "bind(%s): %s\n",
+ my_sock_ntoa(server,socket), strerror(errno) );
+ close(sockfd);
+ return -1;
+ }
+
+ if ( listen( sockfd, backlog ) == -1 ) {
+ perror( "listen" );
+ close(sockfd);
+ return -1;
+ }
+
+ return sockfd;
+}
--- /dev/null
+//
+// $Id: socket.hh,v 1.3 1999/01/19 11:00:50 voeckler Exp $
+//
+// Author: Jens-S. Vöckler <voeckler@rvs.uni-hannover.de>
+//
+// File: socket.hh
+// Sun May 3 1998
+//
+// (c) 1998 Lehrgebiet Rechnernetze und Verteilte Systeme
+// Universität Hannover, Germany
+//
+// Books: W. Richard Steven, "Advanced Programming in the UNIX Environment",
+// Addison-Wesley, 1992.
+//
+// Permission to use, copy, modify, distribute, and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that (i) the above copyright notices and this permission
+// notice appear in all copies of the software and related documentation,
+// and (ii) the names of the Lehrgebiet Rechnernetze und Verteilte
+// Systeme and the University of Hannover may not be used in any
+// advertising or publicity relating to the software without the
+// specific, prior written permission of Lehrgebiet Rechnernetze und
+// Verteilte Systeme and the University of Hannover.
+//
+// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// IN NO EVENT SHALL THE LEHRGEBIET RECHNERNETZE UND VERTEILTE SYSTEME OR
+// THE UNIVERSITY OF HANNOVER BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
+// ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
+// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+// SOFTWARE.
+//
+// $Log: socket.hh,v $
+// Revision 1.3 1999/01/19 11:00:50 voeckler
+// added bool type workaround.
+//
+// Revision 1.2 1998/08/27 15:23:24 voeckler
+// added TCP_NODELAY options at several places.
+//
+// Revision 1.1 1998/08/13 21:52:55 voeckler
+// Initial revision
+//
+//
+#ifndef _SOCKET_HH
+#define _SOCKET_HH
+
+#if defined(__GNUC__) || defined(__GNUG__)
+#pragma interface
+#else
+#ifndef HAS_BOOL
+#define HAS_BOOL
+typedef int bool;
+#define false 0
+#define true 1
+#endif
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h> // SOMAXCONN
+#include <netinet/in.h>
+
+#if SOMAXCONN <= 5
+#undef SOMAXCONN
+#endif
+
+#ifndef SOMAXCONN
+#if defined(SOLARIS)
+#if MAJOR < 5
+#define SOMAXCONN 32
+#else
+#define SOMAXCONN 128
+#endif
+#elif defined(LINUX)
+#define SOMAXCONN 128
+#else
+#define SOMAXCONN 5 // BSD
+#endif // OS selection
+#endif // !SOMAXCONN
+
+#ifndef SA
+#define SA struct sockaddr
+#endif
+
+int
+setSocketBuffers( int fd, int size );
+ // purpose: set socket buffers for both directions to the specified size
+ // paramtr: size (IN): new socket buffer size
+ // returns: -1 on setsockopt() errors, 0 otherwise
+ // warning: prints error message on stderr, errno will be changed
+
+int
+getSocketNoDelay( int sockfd );
+ // purpose: get state of the TCP_NODELAY of the socket
+ // paramtr: sockfd (IN): socket descriptor
+ // returns: 1, if TCP_NODELAY is set,
+ // 0, if TCP_NODELAY is not set,
+ // -1, if an error occurred (e.g. datagram socket)
+
+
+int
+setSocketNoDelay( int sockfd, bool nodelay = true );
+ // purpose: get state of the TCP_NODELAY of the socket
+ // paramtr: sockfd (IN): socket descriptor
+ // nodelay (IN): true, if TCP_NODELAY is to be set, false otherwise.
+ // returns: 0, if everything worked out o.k.
+ // -1, if an error occurred (e.g. datagram socket)
+
+int
+connectTo( struct in_addr host, unsigned short port, bool nodelay = false,
+ int sendBufferSize = -1, int recvBufferSize = -1 );
+ // purpose: connect to a server as a client
+ // paramtr: host (IN): address describing the server
+ // port (IN): port to connect at the server
+ // nodelay (IN): true=set TCP_NODELAY option.
+ // sendBufferSize (IN): don't set (use sys defaults) if < 0
+ // recvBufferSize (IN): don't set (use sys defaults) if < 0
+ // returns: >=0 is the descriptor of the opened, connected socket,
+ // -1 is an indication of an error (errno may have been reset).
+
+int
+serverSocket( struct in_addr host, unsigned short port,
+ int backlog = SOMAXCONN, bool reuse = true, bool nodelay = false,
+ int sendBufferSize = -1, int recvBufferSize = -1 );
+ // purpose: open a server socket for listening
+ // paramtr: host (IN): host to bind locally to, use INADDRY_ANY for *
+ // port (IN): port to bind to, use 0 for system assigned
+ // backlog (IN): listen backlog queue length
+ // reuse (IN): set SO_REUSEADDR option - default usefully
+ // nodelay (IN): true=set TCP_NODELAY option.
+ // SETTING TCP_NODELAY ON A SERVER SOCKET DOES NOT MAKE SENSE!
+ // sendBufferSize (IN): don't set (use sys defaults) if < 0
+ // recvBufferSize (IN): don't set (use sys defaults) if < 0
+ // returns: opened listening fd, or -1 on error.
+ // warning: error message will be printed on stderr and errno reset.
+
+#endif // _SOCKET_HH
--- /dev/null
+//
+// $Id: squid-tlv.cc,v 1.1 1999/06/15 21:10:16 voeckler Exp $
+//
+// Author: Jens-S. Vöckler <voeckler@rvs.uni-hannover.de>
+//
+// File: squid-tlv.cc
+// Tue Jun 15 1999
+//
+// (c) 1999 Lehrgebiet Rechnernetze und Verteilte Systeme
+// Universität Hannover, Germany
+//
+// Permission to use, copy, modify, distribute, and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that (i) the above copyright notices and this permission
+// notice appear in all copies of the software and related documentation,
+// and (ii) the names of the Lehrgebiet Rechnernetze und Verteilte
+// Systeme and the University of Hannover may not be used in any
+// advertising or publicity relating to the software without the
+// specific, prior written permission of Lehrgebiet Rechnernetze und
+// Verteilte Systeme and the University of Hannover.
+//
+// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// IN NO EVENT SHALL THE LEHRGEBIET RECHNERNETZE UND VERTEILTE SYSTEME OR
+// THE UNIVERSITY OF HANNOVER BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
+// ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
+// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+// SOFTWARE.
+//
+// $Log: squid-tlv.cc,v $
+// Revision 1.1 1999/06/15 21:10:16 voeckler
+// Initial revision
+//
+//
+#if defined(__GNUC__) || defined(__GNUG__)
+#pragma implementation
+#endif
+
+#include <assert.h>
+#include "squid-tlv.hh"
+
+static const char* RCS_ID =
+"$Id: squid-tlv.cc,v 1.1 1999/06/15 21:10:16 voeckler Exp $";
+
+SquidTLV::SquidTLV( SquidMetaType _type, size_t _size, void* _data )
+ :next(0),size(_size)
+{
+ if ( size ) {
+ type = _type;
+ data = (char*) _data;
+ } else {
+ type = STORE_META_END;
+ data = 0;
+ }
+}
+
+SquidMetaList::SquidMetaList()
+{
+ head = tail = 0;
+}
+
+SquidMetaList::~SquidMetaList()
+{
+ for ( SquidTLV* temp = head; temp; temp = head ) {
+ head = temp->next;
+ delete temp;
+ }
+}
+
+void
+SquidMetaList::append( SquidMetaType type, size_t size, void* data )
+{
+ SquidTLV* temp = new SquidTLV( type, size, data );
+ if ( head == 0 ) head = tail = temp;
+ else {
+ tail->next = temp;
+ tail = temp;
+ }
+}
+
+const SquidTLV*
+SquidMetaList::search( SquidMetaType type ) const
+{
+ const SquidTLV* temp = head;
+ while ( temp && temp->type != type ) temp = temp->next;
+ return temp;
+}
--- /dev/null
+//
+// $Id: squid-tlv.hh,v 1.1 1999/06/15 21:10:16 voeckler Exp $
+//
+// Author: Jens-S. Vöckler <voeckler@rvs.uni-hannover.de>
+//
+// File: squid-tlv.hh
+// Tue Jun 15 1999
+//
+// (c) 1999 Lehrgebiet Rechnernetze und Verteilte Systeme
+// Universität Hannover, Germany
+//
+// Permission to use, copy, modify, distribute, and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that (i) the above copyright notices and this permission
+// notice appear in all copies of the software and related documentation,
+// and (ii) the names of the Lehrgebiet Rechnernetze und Verteilte
+// Systeme and the University of Hannover may not be used in any
+// advertising or publicity relating to the software without the
+// specific, prior written permission of Lehrgebiet Rechnernetze und
+// Verteilte Systeme and the University of Hannover.
+//
+// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// IN NO EVENT SHALL THE LEHRGEBIET RECHNERNETZE UND VERTEILTE SYSTEME OR
+// THE UNIVERSITY OF HANNOVER BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
+// ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
+// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+// SOFTWARE.
+//
+// $Log: squid-tlv.hh,v $
+// Revision 1.1 1999/06/15 21:10:16 voeckler
+// Initial revision
+//
+#ifndef _SQUID_TLV_HH
+#define _SQUID_TLV_HH
+
+#if defined(__GNUC__) || defined(__GNUG__)
+#pragma interface
+#else
+#ifndef HAS_BOOL
+#define HAS_BOOL
+typedef int bool;
+#define false 0
+#define true 1
+#endif
+#endif
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <time.h>
+
+// taken from Squid-2.x
+// NOTE! We must preserve the order of this list!
+enum SquidMetaType {
+ STORE_META_VOID, // should not come up
+ STORE_META_KEY_URL, // key w/ keytype
+ STORE_META_KEY_SHA,
+ STORE_META_KEY_MD5,
+ STORE_META_URL, // the url , if not in the header
+ STORE_META_STD, // standard metadata
+ STORE_META_HITMETERING, // reserved for hit metering
+ STORE_META_VALID,
+ STORE_META_END
+};
+
+// taken from Squid-2.x
+struct StoreMetaStd {
+ time_t timestamp;
+ time_t lastref;
+ time_t expires;
+ time_t lastmod;
+ size_t swap_file_sz;
+ u_short refcount;
+ u_short flags;
+};
+
+struct SquidTLV {
+ // create a shallow reference pointing into the "buffer" variable
+ // do not copy --> saves times, saves memory.
+ SquidTLV( SquidMetaType _type, size_t _size = 0, void* _data = 0 );
+ ~SquidTLV() {}
+
+ SquidTLV* next;
+ size_t size;
+ SquidMetaType type;
+ char* data;
+};
+
+class SquidMetaList {
+public:
+ SquidMetaList();
+ ~SquidMetaList();
+
+ void append( SquidMetaType type, size_t size, void* data );
+ const SquidTLV* search( SquidMetaType type ) const;
+
+private:
+ SquidTLV* head;
+ SquidTLV* tail;
+};
+
+#endif // _SQUID_TLV_HH