├── .dir-locals.el ├── src ├── test │ ├── varnish-4.1.0-doc.log │ ├── raw.conf │ ├── backend_client.conf │ ├── regress.sh │ ├── Makefile.am │ ├── varnishevent.conf │ ├── vslarg.sh │ ├── test_writer.c │ ├── ncsa.sh │ ├── minunit.h │ ├── test_strfTIM.c │ ├── test_data.c │ └── test_hdrtrie.c ├── base64.h ├── data.h ├── flopen.h ├── writer.h ├── Makefile.am ├── vpf.h ├── vtim.h ├── strfTIM.h ├── signals.h ├── base64.c ├── vmb.c ├── hdrtrie.h ├── spscq.c ├── vmb.h ├── format.h ├── log.c ├── strfTIM.c ├── flopen.c ├── monitor.c ├── handler.c ├── vpf.c ├── hdrtrie.c ├── vtim.c ├── varnishevent.h ├── config.c ├── writer.c └── data.c ├── Makefile.am ├── .gitignore ├── LICENSE ├── autogen.sh ├── configure.ac └── m4 └── ax_pthread.m4 /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((c-mode (indent-tabs-mode . nil) 2 | (c-basic-offset . 4) 3 | (c-file-style . "BSD"))) 4 | 5 | -------------------------------------------------------------------------------- /src/test/varnish-4.1.0-doc.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/varnishevent/master/src/test/varnish-4.1.0-doc.log -------------------------------------------------------------------------------- /src/test/raw.conf: -------------------------------------------------------------------------------- 1 | # varnishevent test configuration for raw transactions 2 | 3 | monitor.interval = 0 4 | 5 | cformat= 6 | rformat=%t %{%F-%T.%i}t %{tag:Begin}x %{VSL:Begin}x %{vxid}x 7 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # 2 | 3 | ACLOCAL_AMFLAGS = -I m4 -I ${VARNISH_DATAROOTDIR}/aclocal 4 | 5 | SUBDIRS = src 6 | 7 | dist_man_MANS = varnishevent.1 8 | 9 | varnishevent.1: README.rst 10 | if HAVE_RST2MAN 11 | ${RST2MAN} $? $@ 12 | else 13 | @echo "========================================" 14 | @echo "You need rst2man installed to make dist" 15 | @echo "========================================" 16 | @false 17 | endif 18 | 19 | EXTRA_DIST = LICENSE autogen.sh README.rst 20 | 21 | DISTCHECK_CONFIGURE_FLAGS = \ 22 | --enable-developer-warnings \ 23 | --enable-debugging-symbols \ 24 | --enable-dependency-tracking \ 25 | --enable-extra-developer-warnings \ 26 | --enable-werror 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Matches ALL Makefile and Makefile.in occurrences 2 | Makefile 3 | Makefile.in 4 | aclocal.m4 5 | autom4te.cache/ 6 | config.guess 7 | config.h 8 | config.h.in 9 | config.log 10 | config.status 11 | config.sub 12 | configure 13 | depcomp 14 | install-sh 15 | libtool 16 | ltmain.sh 17 | m4/libtool.m4 18 | m4/ltoptions.m4 19 | m4/ltsugar.m4 20 | m4/ltversion.m4 21 | m4/lt~obsolete.m4 22 | missing 23 | src/.deps/ 24 | *.o 25 | *.Po 26 | src/test/.deps/ 27 | *~ 28 | src/test/test_data 29 | src/test/test_strfTIM 30 | src/test/test_format 31 | src/test/test_writer 32 | src/test/test_hdrtrie 33 | src/test/output.log 34 | src/test/test.log 35 | src/varnishevent 36 | src/vcs_version.h 37 | *.1 38 | stamp-h1 39 | src/test/*.log 40 | src/test/*.trs 41 | compile 42 | test-driver 43 | -------------------------------------------------------------------------------- /src/test/backend_client.conf: -------------------------------------------------------------------------------- 1 | # varnishevent test configuration for backend and client logging 2 | # test for equivalence with varnishncsa 3 | 4 | bformat=%b %H %h %I %{Host}i %{User-Agent}i %{X-Forwarded-For}i %{Accept-Ranges}o %{Connection}o %{Content-Encoding}o %{Content-Length}o %{Content-Type}o %{Date}o %{Last-Modified}o %{ETag}o %{Server}o %l %m %O %q %r %s %t %{%F-%T}t %U %u %{Varnish:time_firstbyte}x %{VSL:Begin}x %{VSL:End}x %{VSL:Link}x %{VSL:Timestamp}x %{Varnish:vxid}x %{Varnish:side}x 5 | cformat=%b %H %h %I %{Host}i %{User-Agent}i %{X-Forwarded-For}i %{Accept-Ranges}o %{Connection}o %{Content-Encoding}o %{Content-Length}o %{Content-Type}o %{Date}o %{Last-Modified}o %{ETag}o %{Server}o %l %m %O %q %r %s %t %{%F-%T}t %U %u %{Varnish:time_firstbyte}x %{VSL:Begin}x %{VSL:End}x %{VSL:Link}x %{VSL:Timestamp}x %{Varnish:vxid}x %{Varnish:side}x 6 | 7 | monitor.interval = 0 8 | log.file = /dev/null 9 | -------------------------------------------------------------------------------- /src/test/regress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo 4 | echo "TEST: $0" 5 | echo '... testing output and log against known checksums' 6 | 7 | # Ensure that the local time date formatters produce the same output 8 | # wherever the test is run. 9 | export TZ=UTC 10 | 11 | LOG=test.log 12 | OUT=output.log 13 | 14 | rm -f $LOG $OUT 15 | 16 | ../varnishevent -f varnishevent.conf -r varnish-4.1.0-doc.log -w $OUT -v 17 | 18 | CKSUM=$( cksum $OUT ) 19 | if [ "$CKSUM" != "54743924 442153 $OUT" ]; then 20 | echo "ERROR: Regression test log output incorrect cksum: $CKSUM" 21 | exit 1 22 | fi 23 | 24 | # sed removes the version/revision from the "initializing" line. 25 | # grep removes logs about table allocations and by the threads about 26 | # free lists, which are not relevant to the regression, and are not 27 | # predictable from one run to the next. 28 | CKSUM=$( sed -e 's/\(initializing\) \(.*\)/\1/' $LOG | egrep -v 'Writer: returned|Reader: took|^DEBUG: Allocating' | cksum ) 29 | 30 | if [ "$CKSUM" != '1109151867 836995' ]; then 31 | echo "ERROR: Regression test varnishevent log incorrect cksum: $CKSUM" 32 | exit 1 33 | fi 34 | 35 | exit 0 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2016 UPLEX Nils Goroll Systemoptimierung 2 | Copyright (c) 2015-2016 Otto Gmbh & Co KG 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | 4 | warn() { 5 | echo "WARNING: $@" 1>&2 6 | } 7 | 8 | case `uname -s` in 9 | Darwin) 10 | LIBTOOLIZE=glibtoolize 11 | ;; 12 | FreeBSD) 13 | LIBTOOLIZE=libtoolize 14 | ;; 15 | OpenBSD) 16 | LIBTOOLIZE=libtoolize 17 | ;; 18 | Linux) 19 | LIBTOOLIZE=libtoolize 20 | ;; 21 | SunOS) 22 | LIBTOOLIZE=libtoolize 23 | ;; 24 | *) 25 | warn "unrecognized platform:" `uname -s` 26 | LIBTOOLIZE=libtoolize 27 | esac 28 | 29 | automake_version=`automake --version | tr ' ' '\n' | egrep '^[0-9]\.[0-9a-z.-]+'` 30 | if [ -z "$automake_version" ] ; then 31 | warn "unable to determine automake version" 32 | else 33 | case $automake_version in 34 | 0.*|1.[0-8]|1.[0-8][.-]*) 35 | warn "automake ($automake_version) detected; 1.9 or newer recommended" 36 | ;; 37 | *) 38 | ;; 39 | esac 40 | fi 41 | 42 | # check for varnishapi m4 scripts in custom paths 43 | dataroot=$(pkg-config --variable=datarootdir varnishapi 2>/dev/null) 44 | if [ -z "$dataroot" ] ; then 45 | cat >&2 <<'EOF' 46 | Package varnishapi was not found in the pkg-config search path. 47 | Perhaps you should add the directory containing `varnishapi.pc' 48 | to the PKG_CONFIG_PATH environment variable 49 | EOF 50 | exit 1 51 | fi 52 | 53 | set -ex 54 | 55 | aclocal -I m4 -I ${dataroot}/aclocal 56 | $LIBTOOLIZE --copy --force 57 | autoheader 58 | automake --add-missing --copy --foreign 59 | autoconf 60 | -------------------------------------------------------------------------------- /src/base64.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2006 Verdens Gang AS 3 | * Copyright (c) 2006-2011 Varnish Software AS 4 | * All rights reserved. 5 | * 6 | * Author: Poul-Henning Kamp 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | */ 30 | 31 | void VB64_init(void); 32 | int VB64_decode(char *d, unsigned dlen, const char *s, const char *e); 33 | -------------------------------------------------------------------------------- /src/data.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2015 Otto Gmbh & Co KG 4 | * All rights reserved. 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include "varnishevent.h" 33 | 34 | extern const void * const magic_end_rec; 35 | -------------------------------------------------------------------------------- /src/flopen.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2007 Dag-Erling Coïdan Smørgrav 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer 10 | * in this position and unchanged. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 | * SUCH DAMAGE. 26 | * 27 | * Derived from: 28 | * $FreeBSD: src/lib/libutil/libutil.h,v 1.44 2007/05/10 15:01:42 des Exp $ 29 | */ 30 | 31 | #ifndef FLOPEN_H_INCLUDED 32 | #define FLOPEN_H_INCLUDED 33 | 34 | int flopen(const char *, int, ...); 35 | int fltest(int fd, pid_t *pid); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/writer.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2015 Otto Gmbh & Co KG 4 | * All rights reserved. 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include "varnishevent.h" 33 | 34 | /* local freelist - return space in chunks */ 35 | struct txhead_s wrt_freetx; 36 | 37 | void wrt_write(tx_t *tx); 38 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | # 2 | 3 | AM_CPPFLAGS = -I${VARNISH_SHARE_INCLUDE} -I${VARNISH_PKG_INCLUDE} 4 | 5 | SUBDIRS = test 6 | 7 | bin_PROGRAMS = varnishevent 8 | 9 | varnishevent_SOURCES = \ 10 | varnishevent.c \ 11 | varnishevent.h \ 12 | signals.h \ 13 | base64.c \ 14 | base64.h \ 15 | data.c \ 16 | spscq.c \ 17 | writer.h \ 18 | writer.c \ 19 | config.c \ 20 | log.c \ 21 | monitor.c \ 22 | strfTIM.h \ 23 | strfTIM.c \ 24 | format.c \ 25 | handler.c \ 26 | vtim.h \ 27 | vtim.c \ 28 | vpf.h \ 29 | vpf.c \ 30 | flopen.h \ 31 | flopen.c \ 32 | vcs_version.h \ 33 | vmb.h \ 34 | vmb.c \ 35 | hdrtrie.h \ 36 | hdrtrie.c 37 | 38 | varnishevent_LDADD = \ 39 | ${PTHREAD_LIBS} ${RT_LIBS} ${LIBM} @VARNISH_LIBS@ 40 | 41 | # from Varnish include/Makefile.am 42 | BUILT_SOURCES = vcs_version.h 43 | MAINTAINERCLEANFILES = vcs_version.h 44 | vcs_version.h: FORCE 45 | @if [ -d "$(top_srcdir)/.git" ]; then \ 46 | V="$$(git show -s --pretty=format:%h)" \ 47 | B="$$(git rev-parse --abbrev-ref HEAD)" \ 48 | H="$$(head -n 1 vcs_version.h 2>/dev/null || true)"; \ 49 | if [ "/* $$V */" != "$$H" ]; then \ 50 | ( \ 51 | echo "/* $$V */" ;\ 52 | echo '/*' ;\ 53 | echo ' * NB: This file is machine generated, DO NOT EDIT!' ;\ 54 | echo ' *' ;\ 55 | echo ' * Run make to regenerate' ;\ 56 | echo ' *' ;\ 57 | echo ' */' ;\ 58 | echo "/* $$V */" ;\ 59 | echo '' ;\ 60 | echo "#define VCS_Version \"$$V\"" ; \ 61 | echo "#define VCS_Branch \"$$B\"" \ 62 | ) > vcs_version.h ; \ 63 | fi \ 64 | else \ 65 | if [ ! -f vcs_version.h ]; then \ 66 | ( \ 67 | echo "/* NOGIT */" ; \ 68 | echo '/* No git commit ID available, see include/Makefile.am for explanation */' ; \ 69 | echo '#define VCS_Version "NOGIT"' ; \ 70 | echo '#define VCS_Branch "NOGIT"' \ 71 | ) > vcs_version.h ; \ 72 | fi \ 73 | fi 74 | FORCE: 75 | -------------------------------------------------------------------------------- /src/vpf.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2005 Pawel Jakub Dawidek 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * Derived from: 27 | * $FreeBSD: src/lib/libutil/libutil.h,v 1.41 2005/08/24 17:21:38 pjd Exp $ 28 | */ 29 | 30 | #ifndef VPF_H_INCLUDED 31 | #define VPF_H_INCLUDED 32 | 33 | struct vpf_fh; 34 | 35 | struct vpf_fh *VPF_Open(const char *path, mode_t mode, pid_t *pidptr); 36 | int VPF_Write(struct vpf_fh *pfh); 37 | int VPF_Close(struct vpf_fh *pfh); 38 | int VPF_Remove(struct vpf_fh *pfh); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/vtim.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2006 Verdens Gang AS 3 | * Copyright (c) 2006-2011 Varnish Software AS 4 | * All rights reserved. 5 | * 6 | * Author: Poul-Henning Kamp 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | */ 30 | 31 | /* from libvarnish/vtim.c */ 32 | #define VTIM_FORMAT_SIZE 30 33 | void VTIM_format(double t, char *p); 34 | double VTIM_parse(const char *p); 35 | double VTIM_mono(void); 36 | double VTIM_real(void); 37 | void VTIM_sleep(double t); 38 | struct timespec VTIM_timespec(double t); 39 | struct timeval VTIM_timeval(double t); 40 | -------------------------------------------------------------------------------- /src/strfTIM.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2013 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2013 Otto Gmbh & Co KG 4 | * All rights reserved 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include 33 | #include 34 | 35 | size_t strfTIM(char *s, size_t max, const char *fmt, struct tm *tm, 36 | unsigned usec); 37 | size_t strfTIMlocal(char *s, size_t max, const char *fmt, double t); 38 | size_t strfTIMgm(char *s, size_t max, const char *fmt, double t); 39 | -------------------------------------------------------------------------------- /src/test/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = @VARNISH_CFLAGS@ -I ${VARNISH_PKG_INCLUDE} 2 | 3 | AM_TESTS_ENVIRONMENT = \ 4 | PATH=@LIBVARNISHAPI_BINDIR@:$$PATH; export PATH; 5 | 6 | TESTS = test_data test_strfTIM test_hdrtrie test_format test_writer \ 7 | ncsa.sh vslarg.sh regress.sh 8 | 9 | # artifacts of the regression test 10 | CLEANFILES = test.log output.log 11 | 12 | check_PROGRAMS = test_data test_strfTIM test_format test_writer test_hdrtrie 13 | 14 | test_data_SOURCES = \ 15 | minunit.h \ 16 | test_data.c 17 | 18 | test_data_LDADD = \ 19 | ../base64.$(OBJEXT) \ 20 | ../config.$(OBJEXT) \ 21 | ../log.$(OBJEXT) \ 22 | ../data.$(OBJEXT) \ 23 | ../format.$(OBJEXT) \ 24 | ../strfTIM.$(OBJEXT) \ 25 | ../hdrtrie.$(OBJEXT) \ 26 | @VARNISH_LIBS@ @VARNISH_LIBVARNISH_LIB@ ${LIBM} 27 | 28 | test_format_SOURCES = \ 29 | minunit.h \ 30 | test_format.c 31 | 32 | test_format_LDADD = \ 33 | ../config.$(OBJEXT) \ 34 | ../strfTIM.$(OBJEXT) \ 35 | ../base64.$(OBJEXT) \ 36 | ../data.$(OBJEXT) \ 37 | ../hdrtrie.$(OBJEXT) \ 38 | ../format.$(OBJEXT) \ 39 | @VARNISH_LIBS@ @VARNISH_LIBVARNISH_LIB@ ${LIBM} 40 | 41 | test_writer_SOURCES = \ 42 | minunit.h \ 43 | test_writer.c 44 | 45 | test_writer_LDADD = \ 46 | ../config.$(OBJEXT) \ 47 | ../format.$(OBJEXT) \ 48 | ../log.$(OBJEXT) \ 49 | ../data.$(OBJEXT) \ 50 | ../monitor.$(OBJEXT) \ 51 | ../base64.$(OBJEXT) \ 52 | ../spscq.$(OBJEXT) \ 53 | ../strfTIM.$(OBJEXT) \ 54 | ../hdrtrie.$(OBJEXT) \ 55 | ../writer.$(OBJEXT) \ 56 | @VARNISH_LIBS@ @VARNISH_LIBVARNISH_LIB@ ${LIBM} 57 | 58 | test_strfTIM_SOURCES = \ 59 | minunit.h \ 60 | ../strfTIM.h \ 61 | test_strfTIM.c 62 | 63 | test_strfTIM_LDADD = \ 64 | ../strfTIM.$(OBJEXT) \ 65 | @VARNISH_LIBS@ @VARNISH_LIBVARNISH_LIB@ ${LIBM} 66 | 67 | test_hdrtrie_SOURCES = \ 68 | minunit.h \ 69 | ../hdrtrie.h \ 70 | test_hdrtrie.c 71 | 72 | test_hdrtrie_LDADD = \ 73 | ../hdrtrie.$(OBJEXT) \ 74 | @VARNISH_LIBS@ @VARNISH_LIBVARNISH_LIB@ ${LIBM} 75 | -------------------------------------------------------------------------------- /src/signals.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2012-2015 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2012-2015 Otto Gmbh & Co KG 4 | * All rights reserved 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | SIGDISP(SIGTERM, terminate_action); 33 | SIGDISP(SIGINT, terminate_action); 34 | SIGDISP(SIGUSR1, flush_action); 35 | SIGDISP(SIGUSR2, dump_action); 36 | SIGDISP(SIGABRT, stacktrace_action); 37 | SIGDISP(SIGSEGV, stacktrace_action); 38 | SIGDISP(SIGBUS, stacktrace_action); 39 | SIGDISP(SIGPIPE, reopen_action); 40 | SIGDISP(SIGHUP, reopen_action); 41 | -------------------------------------------------------------------------------- /src/base64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Written by Poul-Henning Kamp 3 | * 4 | * This file is in the public domain. 5 | */ 6 | 7 | #include "config.h" 8 | 9 | #include 10 | #include 11 | 12 | #include "base64.h" 13 | 14 | static const char b64[] = 15 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 16 | 17 | static char i64[256]; 18 | 19 | void 20 | VB64_init(void) 21 | { 22 | int i; 23 | const char *p; 24 | 25 | for (i = 0; i < 256; i++) 26 | i64[i] = -1; 27 | for (p = b64, i = 0; *p; p++, i++) 28 | i64[(int)*p] = (char)i; 29 | i64['='] = 0; 30 | } 31 | 32 | int 33 | VB64_decode(char *d, unsigned dlen, const char *s, const char *e) 34 | { 35 | unsigned u, v, l; 36 | int i; 37 | 38 | if (e == NULL) 39 | e = s + strlen(s); 40 | u = 0; 41 | l = 0; 42 | while (s < e) { 43 | for (v = 0; s < e && v < 4; v++) { 44 | i = i64[(int)*s++]; 45 | if (i < 0) 46 | return (-1); 47 | u <<= 6; 48 | u |= i; 49 | } 50 | for (v = 0; v < 3; v++) { 51 | if (l >= dlen - 1) 52 | return (-1); 53 | *d = (u >> 16) & 0xff; 54 | u <<= 8; 55 | l++; 56 | d++; 57 | } 58 | } 59 | *d = '\0'; 60 | return (0); 61 | } 62 | 63 | #ifdef TEST_DRIVER 64 | 65 | #include // for test-prog 66 | 67 | const char *test1 = 68 | "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz" 69 | "IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg" 70 | "dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu" 71 | "dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo" 72 | "ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="; 73 | 74 | int 75 | main(int argc, char **argv) 76 | { 77 | int i; 78 | char buf[BUFSIZ]; 79 | unsigned l; 80 | 81 | (void)argc; 82 | (void)argv; 83 | 84 | VB64_init(); 85 | l = sizeof buf; 86 | VB64_decode(buf, l, test1, NULL); 87 | printf("%s\n", buf); 88 | return (0); 89 | } 90 | #endif 91 | -------------------------------------------------------------------------------- /src/vmb.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2010 Varnish Software AS 3 | * All rights reserved. 4 | * 5 | * Author: Poul-Henning Kamp 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | * SUCH DAMAGE. 27 | */ 28 | 29 | #include "config.h" 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #include "vas.h" 36 | #include "vmb.h" 37 | 38 | #ifdef VMB_NEEDS_PTHREAD_WORKAROUND_THIS_IS_BAD_FOR_PERFORMANCE 39 | 40 | static pthread_mutex_t mb_mtx; 41 | static pthread_once_t mb_mtx_once = PTHREAD_ONCE_INIT; 42 | 43 | static void 44 | vmb_init(void) 45 | { 46 | 47 | AZ(pthread_mutex_init(&mb_mtx, NULL)); 48 | } 49 | 50 | 51 | void 52 | vmb_pthread(void) 53 | { 54 | 55 | AZ(pthread_once(&mb_mtx_once, vmb_init)); 56 | 57 | AZ(pthread_mutex_lock(&mb_mtx)); 58 | AZ(pthread_mutex_unlock(&mb_mtx)); 59 | } 60 | 61 | #endif /* VMB_NEEDS_PTHREAD_WORKAROUND_THIS_IS_BAD_FOR_PERFORMANCE */ 62 | -------------------------------------------------------------------------------- /src/test/varnishevent.conf: -------------------------------------------------------------------------------- 1 | # varnishevent test configuration 2 | 3 | monitor.interval = 0 4 | 5 | cformat=%b %d %D %H %h %I %{Host}i %{Connection}i %{User-Agent}i %{X-Forwarded-For}i %{Accept-Ranges}o %{Age}o %{Connection}o %{Content-Encoding}o %{Content-Length}o %{Content-Type}o %{Date}o %{Last-Modified}o %{Server}o %{Transfer-Encoding}o %{Via}o %{X-Varnish}o %l %m %O %q %r %s %t %{%F-%T}t %U %u %{Varnish:time_firstbyte}x %{Varnish:hitmiss}x %{Varnish:handling}x %{tag:Begin}x %{tag:Debug}x %{tag:End}x %{tag:Gzip}x %{tag:Hit}x %{tag:Length}x %{tag:Link}x %{tag:ReqAcct}x %{tag:ReqStart}x %{tag:RespProtocol}x %{tag:ReqMethod}x %{tag:ReqURL}x %{tag:ReqProtocol}x %{tag:RespReason}x %{tag:RespStatus}x %{tag:Timestamp:Req}x %{tag:ReqAcct[5]}x %{tag:Timestamp:Req[2]}x %{VSL:Begin}x %{VSL:Debug}x %{VSL:End}x %{VSL:Gzip}x %{VSL:Hit}x %{VSL:Length}x %{VSL:Link}x %{VSL:ReqAcct}x %{VSL:ReqStart}x %{VSL:RespProtocol}x %{VSL:ReqMethod}x %{VSL:ReqURL}x %{VSL:ReqProtocol}x %{VSL:RespReason}x %{VSL:RespStatus}x %{VSL:Timestamp:Req}x %{VSL:ReqAcct[5]}x %{VSL:Timestamp:Req[2]}x %{VSL:Timestamp}x %{vxid}x %{Varnish:vxid}x %{pvxid}x %{Varnish:side}x 6 | 7 | bformat=%b %d %D %H %h %I %{Accept-Encoding}i %{Host}i %{User-Agent}i %{X-Forwarded-For}i %{X-Varnish}i %{Accept-Ranges}o %{Connection}o %{Content-Encoding}o %{Content-Length}o %{Content-Type}o %{Date}o %{ETag}o %{Last-Modified}o %{Server}o %{Transfer-Encoding}o %{Vary}o %l %m %O %q %r %s %t %{%F-%T}t %U %u %{Varnish:time_firstbyte}x %{tag:Backend}x %{tag:BackendOpen}x %{tag:BackendClose}x %{tag:BackendReuse}x %{tag:Begin}x %{tag:BereqAcct}x %{tag:Length}x %{tag:BerespProtocol}x %{tag:BerespReason}x %{tag:BerespStatus}x %{tag:BereqProtocol}x %{tag:BereqMethod}x %{tag:BereqURL}x %{tag:Debug}x %{tag:End}x %{tag:Timestamp:Bereq}x %{tag:BereqAcct[5]}x %{tag:Timestamp:Bereq[2]}x %{VSL:Backend}x %{VSL:BackendOpen}x %{VSL:BackendClose}x %{VSL:BackendReuse}x %{VSL:Begin}x %{VSL:BereqAcct}x %{VSL:Length}x %{VSL:BerespProtocol}x %{VSL:BerespReason}x %{VSL:BerespStatus}x %{VSL:BereqProtocol}x %{VSL:BereqMethod}x %{VSL:BereqURL}x %{VSL:Debug}x %{VSL:End}x %{VSL:Timestamp:Bereq}x %{VSL:BereqAcct[5]}x %{VSL:Timestamp:Bereq[2]}x %{VSL:Timestamp}x %{vxid}x %{Varnish:vxid}x %{pvxid}x %{Varnish:side}x 8 | 9 | log.file = test.log 10 | -------------------------------------------------------------------------------- /src/hdrtrie.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2015 Otto Gmbh & Co KG 4 | * All rights reserved. 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #ifndef HDRTRIE_H_INCLUDED 33 | #define HDRTRIE_H_INCLUDED 34 | 35 | #include "vdef.h" 36 | #include "vsb.h" 37 | 38 | struct hdrt_node { 39 | unsigned magic; 40 | #define HDRT_NODE_MAGIC 0x970ec029 41 | char *str; 42 | struct hdrt_node **next; 43 | int idx; 44 | }; 45 | 46 | int HDR_FindIdx(struct hdrt_node *hdrt, const char *hdr); 47 | struct hdrt_node *HDR_InsertIdx(struct hdrt_node *hdrt, const char *hdr, 48 | int idx); 49 | int HDR_N(struct hdrt_node *hdrt); 50 | void HDR_List(struct hdrt_node *hdrt, struct vsb *sb); 51 | void HDR_Fini(struct hdrt_node *hdrt); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/test/vslarg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo 4 | echo "TEST: $0" 5 | echo "... testing standard VSL args" 6 | 7 | IN=varnish-4.1.0-doc.log 8 | CONF=varnishevent.conf 9 | LOG=/dev/null 10 | 11 | # Ensure that the local time date formatters produce the same output 12 | # wherever the test is run. 13 | export TZ=UTC 14 | 15 | echo "... no VSL args" 16 | CKSUM=$( ../varnishevent -r ${IN} -f ${CONF} -l ${LOG} | cksum) 17 | 18 | if [ "$CKSUM" != '2542287168 442191' ]; then 19 | echo "ERROR: no VSL args unexpected cksum: $CKSUM" 20 | exit 1 21 | fi 22 | 23 | echo "... -g vxid" 24 | CKSUM=$( ../varnishevent -g vxid -r ${IN} -f ${CONF} -l ${LOG} | cksum) 25 | 26 | # Same as default (no -g arg) 27 | if [ "$CKSUM" != '2542287168 442191' ]; then 28 | echo "ERROR: -g vxid unexpected cksum: $CKSUM" 29 | exit 1 30 | fi 31 | 32 | echo "... -g request" 33 | CKSUM=$( ../varnishevent -g request -r ${IN} -f ${CONF} -l ${LOG} | cksum) 34 | 35 | if [ "$CKSUM" != '3970366484 443186' ]; then 36 | echo "ERROR: -g request unexpected cksum: $CKSUM" 37 | exit 1 38 | fi 39 | 40 | echo "... -g raw" 41 | # Timestamps for raw grouping are always the time at which the tx was read, 42 | # even for binary file reads. So we check against the last four columns. 43 | # The query restricts output to Begin records; the previous invocation 44 | # rendered every record with just the VXIDs. 45 | CKSUM=$( ../varnishevent -g raw -r ${IN} -f raw.conf -l ${LOG} -q 'Begin' | cut -d' ' -f4- | cksum) 46 | 47 | if [ "$CKSUM" != '3267477005 21053' ]; then 48 | echo "ERROR: -g raw with query unexpected cksum: $CKSUM" 49 | exit 1 50 | fi 51 | 52 | # Cannot mix raw grouping with client and/or backend formats 53 | ../varnishevent -g raw -f ${CONF} -l ${LOG} 54 | 55 | if [ "$?" != "1" ]; then 56 | echo "ERROR: -g raw with client/backend formats did not exit with failure as expected" 57 | exit 1 58 | fi 59 | 60 | echo '... -g session' 61 | ../varnishevent -g session -l ${LOG} 62 | 63 | if [ "$?" != "1" ]; then 64 | echo "ERROR: -g session did not exit with failure as expected" 65 | exit 1 66 | fi 67 | 68 | echo "... -q query" 69 | CKSUM=$( ../varnishevent -q 'ReqURL ~ "_static"' -r ${IN} -l ${LOG} | cksum) 70 | 71 | if [ "$CKSUM" != '805680033 830' ]; then 72 | echo "ERROR: -q query unexpected cksum: $CKSUM" 73 | exit 1 74 | fi 75 | 76 | ../varnishevent -q 'ReqURL ~' -l ${LOG} 77 | 78 | if [ "$?" != "1" ]; then 79 | echo "ERROR: -q query with illegal VSL query did not exit with failure as expected" 80 | exit 1 81 | fi 82 | 83 | echo "... -C" 84 | CKSUM=$( ../varnishevent -C -q 'ReqURL ~ "_STATIC"' -r ${IN} -l ${LOG} | cksum) 85 | 86 | if [ "$CKSUM" != '805680033 830' ]; then 87 | echo "ERROR: -q query unexpected cksum: $CKSUM" 88 | exit 1 89 | fi 90 | 91 | exit 0 92 | -------------------------------------------------------------------------------- /src/spscq.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2013 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2013 Otto Gmbh & Co KG 4 | * All rights reserved 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include "varnishevent.h" 37 | #include "vqueue.h" 38 | #include "vas.h" 39 | 40 | static volatile unsigned long enqs = 0, deqs = 0, occ_hi = 0; 41 | VSTAILQ_HEAD(spscq_s, tx_t); 42 | struct spscq_s spscq_head = VSTAILQ_HEAD_INITIALIZER(spscq_head); 43 | struct spscq_s deq_head = VSTAILQ_HEAD_INITIALIZER(deq_head); 44 | 45 | static pthread_mutex_t spscq_lock = PTHREAD_MUTEX_INITIALIZER; 46 | 47 | void 48 | SPSCQ_Enq(tx_t *ptr) 49 | { 50 | AZ(pthread_mutex_lock(&spscq_lock)); 51 | assert(enqs - deqs < config.max_data); 52 | enqs++; 53 | if (enqs - deqs > occ_hi) 54 | occ_hi = enqs - deqs; 55 | VSTAILQ_INSERT_TAIL(&spscq_head, ptr, spscq); 56 | AZ(pthread_mutex_unlock(&spscq_lock)); 57 | } 58 | 59 | tx_t 60 | *SPSCQ_Deq(void) 61 | { 62 | void *ptr; 63 | 64 | if (VSTAILQ_EMPTY(&deq_head)) { 65 | AZ(pthread_mutex_lock(&spscq_lock)); 66 | VSTAILQ_CONCAT(&deq_head, &spscq_head); 67 | AZ(pthread_mutex_unlock(&spscq_lock)); 68 | } 69 | if (VSTAILQ_EMPTY(&deq_head)) 70 | return NULL; 71 | ptr = VSTAILQ_FIRST(&deq_head); 72 | VSTAILQ_REMOVE_HEAD(&deq_head, spscq); 73 | deqs++; 74 | return ptr; 75 | } 76 | 77 | void 78 | SPSCQ_Stats(void) 79 | { 80 | unsigned len = enqs - deqs; 81 | 82 | LOG_Log(LOG_INFO, "Queue: max=%u len=%u load=%.2f occ_hi=%u", 83 | config.max_data, len, 100.0 * len / config.max_data, occ_hi); 84 | } 85 | 86 | void 87 | SPSCQ_Shutdown(void) 88 | { 89 | AZ(pthread_mutex_destroy(&spscq_lock)); 90 | } 91 | -------------------------------------------------------------------------------- /src/vmb.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2010 Varnish Software AS 3 | * All rights reserved. 4 | * 5 | * Author: Poul-Henning Kamp 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | * SUCH DAMAGE. 27 | * 28 | * Memory barriers 29 | * 30 | * XXX: It is utterly braindamaged, that no standard facility for this 31 | * XXX: is available. The "just use pthreads locking" excuse does not 32 | * XXX: make sense, and does not apply to two unthreaded programs sharing 33 | * XXX: a memory segment. 34 | */ 35 | 36 | #ifndef VMB_H_INCLUDED 37 | #define VMB_H_INCLUDED 38 | 39 | #if defined(__FreeBSD__) 40 | #include 41 | #endif 42 | 43 | #if defined(__FreeBSD__) && __FreeBSD_version >= 800058 44 | 45 | #include 46 | #include 47 | #define VMB() mb() 48 | #define VWMB() wmb() 49 | #define VRMB() rmb() 50 | 51 | #elif defined(__amd64__) && defined(__GNUC__) 52 | 53 | #define VMB() __asm __volatile("mfence;" : : : "memory") 54 | #define VWMB() __asm __volatile("sfence;" : : : "memory") 55 | #define VRMB() __asm __volatile("lfence;" : : : "memory") 56 | 57 | #elif defined(__arm__) 58 | 59 | #define VMB() 60 | #define VWMB() 61 | #define VRMB() 62 | 63 | #elif defined(__i386__) && defined(__GNUC__) 64 | 65 | #define VMB() __asm __volatile("lock; addl $0,(%%esp)" : : : "memory") 66 | #define VWMB() __asm __volatile("lock; addl $0,(%%esp)" : : : "memory") 67 | #define VRMB() __asm __volatile("lock; addl $0,(%%esp)" : : : "memory") 68 | 69 | #elif defined(__sparc64__) && defined(__GNUC__) 70 | 71 | #define VMB() __asm__ __volatile__ ("membar #MemIssue": : :"memory") 72 | #define VWMB() VMB() 73 | #define VRMB() VMB() 74 | 75 | #else 76 | 77 | #define VMB_NEEDS_PTHREAD_WORKAROUND_THIS_IS_BAD_FOR_PERFORMANCE 1 78 | 79 | void vmb_pthread(void); 80 | 81 | #define VMB() vmb_pthread() 82 | #define VWMB() vmb_pthread() 83 | #define VRMB() vmb_pthread() 84 | 85 | #endif 86 | 87 | #endif /* VMB_H_INCLUDED */ 88 | -------------------------------------------------------------------------------- /src/test/test_writer.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2015 Otto Gmbh & Co KG 4 | * All rights reserved 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include "../varnishevent.h" 33 | #include "../writer.h" 34 | #include "../vtim.h" 35 | #include "minunit.h" 36 | 37 | int tests_run = 0; 38 | static char errmsg[BUFSIZ]; 39 | 40 | #define N 1000 41 | #define THRESHOLD 1e-3 42 | 43 | void 44 | RDR_Stats(void) 45 | {} 46 | 47 | int 48 | RDR_Depleted(void) 49 | { 50 | return 0; 51 | } 52 | 53 | int 54 | RDR_Waiting(void) 55 | { 56 | return 0; 57 | } 58 | 59 | static char 60 | *test_timeout(void) 61 | { 62 | tx_t tx; 63 | rec_node_t node, *nptr[1]; 64 | 65 | printf("... testing write timeouts\n"); 66 | 67 | CONF_Init(); 68 | VSB_clear(config.cformat); 69 | MAZ(FMT_Init(&errmsg[0])); 70 | 71 | strcpy(config.log_file, "/dev/null"); 72 | MAZ(LOG_Open("test_writer")); 73 | 74 | config.output_timeout = 1.; 75 | 76 | MAZ(WRT_Init()); 77 | 78 | VSTAILQ_INIT(&wrt_freetx); 79 | MASSERT(VSTAILQ_EMPTY(&wrt_freetx)); 80 | 81 | tx.magic = TX_MAGIC; 82 | tx.recs = nptr; 83 | nptr[0] = &node; 84 | node.magic = REC_NODE_MAGIC; 85 | node.rec = NULL; 86 | node.hdrs = NULL; 87 | 88 | for (int i = 0; i < N; i++) { 89 | double t = VTIM_mono(); 90 | tx.state = TX_SUBMITTED; 91 | tx.type = VSL_t_req; 92 | 93 | t = VTIM_mono(); 94 | wrt_write(&tx); 95 | MASSERT(VTIM_mono() - t < THRESHOLD); 96 | } 97 | return NULL; 98 | } 99 | 100 | static const char 101 | *all_tests(void) 102 | { 103 | mu_run_test(test_timeout); 104 | return NULL; 105 | } 106 | 107 | TEST_RUNNER 108 | -------------------------------------------------------------------------------- /src/format.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2015 Otto Gmbh & Co KG 4 | * All rights reserved. 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include "varnishevent.h" 33 | 34 | typedef struct arg_t { 35 | char *name; 36 | enum VSL_tag_e tag; 37 | int fld; 38 | int hdr_idx; 39 | } arg_t; 40 | 41 | typedef void formatter_f(const tx_t *tx, const arg_t *args, char **s, 42 | size_t *len); 43 | 44 | int hidx[MAX_VSL_TAG]; 45 | 46 | char *get_payload(const rec_t *rec); 47 | rec_t *get_tag(const tx_t *tx, enum VSL_tag_e tag); 48 | char *get_hdr(const tx_t *tx, enum VSL_tag_e tag, int hdr_idx); 49 | char *get_fld(char *str, int n, size_t *len); 50 | char *get_rec_fld(const rec_t *rec, int n, size_t *len); 51 | 52 | formatter_f format_b_client; 53 | formatter_f format_b_backend; 54 | 55 | formatter_f format_D_client; 56 | formatter_f format_D_backend; 57 | 58 | formatter_f format_H_client; 59 | formatter_f format_H_backend; 60 | 61 | formatter_f format_h_client; 62 | formatter_f format_h_backend; 63 | 64 | formatter_f format_I_client; 65 | formatter_f format_I_backend; 66 | 67 | formatter_f format_m_client; 68 | formatter_f format_m_backend; 69 | 70 | formatter_f format_O_client; 71 | formatter_f format_O_backend; 72 | 73 | formatter_f format_q_client; 74 | formatter_f format_q_backend; 75 | 76 | formatter_f format_r_client; 77 | formatter_f format_r_backend; 78 | 79 | formatter_f format_s_client; 80 | formatter_f format_s_backend; 81 | 82 | formatter_f format_t; 83 | 84 | formatter_f format_T_client; 85 | formatter_f format_T_backend; 86 | 87 | formatter_f format_U_client; 88 | formatter_f format_U_backend; 89 | 90 | formatter_f format_u_client; 91 | formatter_f format_u_backend; 92 | 93 | formatter_f format_Xi_client; 94 | formatter_f format_Xi_backend; 95 | formatter_f format_Xo_client; 96 | formatter_f format_Xo_backend; 97 | 98 | formatter_f format_Xt; 99 | 100 | formatter_f format_Xttfb_client; 101 | formatter_f format_Xttfb_backend; 102 | 103 | formatter_f format_VCL_disp; 104 | 105 | formatter_f format_VCL_Log; 106 | 107 | formatter_f format_SLT; 108 | 109 | formatter_f format_vxid; 110 | formatter_f format_pvxid; 111 | -------------------------------------------------------------------------------- /src/log.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2013 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2013 Otto Gmbh & Co KG 4 | * All rights reserved 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "varnishevent.h" 41 | 42 | static const char *level2name[LOG_DEBUG+1]; 43 | 44 | static void 45 | syslog_setlevel(int level) 46 | { 47 | setlogmask(LOG_UPTO(level)); 48 | } 49 | 50 | static void 51 | stdio_initnames(void) 52 | { 53 | level2name[LOG_EMERG] = "EMERG"; 54 | level2name[LOG_ALERT] = "ALERT"; 55 | level2name[LOG_CRIT] = "CRIT"; 56 | level2name[LOG_ERR] = "ERR"; 57 | level2name[LOG_WARNING] = "WARNING"; 58 | level2name[LOG_NOTICE] = "NOTICE"; 59 | level2name[LOG_INFO] = "INFO"; 60 | level2name[LOG_DEBUG] = "DEBUG"; 61 | } 62 | 63 | static void 64 | stdio_log(int level, const char *msg, ...) 65 | { 66 | va_list ap; 67 | 68 | if (level > logconf.level) 69 | return; 70 | flockfile(logconf.out); 71 | fprintf(logconf.out, "%s: ", level2name[level]); 72 | va_start(ap, msg); 73 | (void) vfprintf(logconf.out, msg, ap); 74 | va_end(ap); 75 | fprintf(logconf.out, "\n"); 76 | funlockfile(logconf.out); 77 | fflush(logconf.out); 78 | } 79 | 80 | static void 81 | stdio_setlevel(int level) 82 | { 83 | logconf.level = level; 84 | } 85 | 86 | static void 87 | stdio_close(void) 88 | { 89 | fclose(logconf.out); 90 | } 91 | 92 | int LOG_Open(const char *progname) 93 | { 94 | if (EMPTY(config.log_file)) { 95 | /* syslog */ 96 | logconf.log = syslog; 97 | logconf.setlevel = syslog_setlevel; 98 | logconf.close = closelog; 99 | openlog(progname, LOG_PID | LOG_CONS | LOG_NDELAY | LOG_NOWAIT, 100 | config.syslog_facility); 101 | setlogmask(LOG_UPTO(LOG_INFO)); 102 | atexit(closelog); 103 | return(0); 104 | } 105 | 106 | if (strcmp(config.log_file, "-") == 0) 107 | logconf.out = stdout; 108 | else { 109 | logconf.out = fopen(config.log_file, "a"); 110 | if (logconf.out == NULL) { 111 | perror(config.log_file); 112 | return(-1); 113 | } 114 | } 115 | logconf.level = LOG_INFO; 116 | logconf.log = stdio_log; 117 | logconf.setlevel = stdio_setlevel; 118 | logconf.close = stdio_close; 119 | stdio_initnames(); 120 | 121 | return(0); 122 | } 123 | -------------------------------------------------------------------------------- /src/strfTIM.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2013-2015 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2013-2015 Otto Gmbh & Co KG 4 | * All rights reserved 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "strfTIM.h" 39 | 40 | #include "vas.h" 41 | 42 | /* 43 | * cf. vtim.c/VTIM:timespec in libvarnish 44 | */ 45 | static struct timeval 46 | double2timeval(double t) 47 | { 48 | struct timeval tv; 49 | 50 | tv.tv_sec = (time_t)trunc(t); 51 | tv.tv_usec = (int)(1e6 * (t - tv.tv_sec)); 52 | return (tv); 53 | } 54 | 55 | size_t 56 | strfTIM(char *s, size_t max, const char *fmt, struct tm *tm, unsigned usec) 57 | { 58 | const char *p; 59 | char newfmt[max], *f = newfmt; 60 | size_t n, len = 0; 61 | 62 | assert(usec < 1000000); 63 | for (p = fmt; *p; p++) { 64 | if (*p != '%') { 65 | len++; 66 | if (len > max) 67 | return 0; 68 | *f++ = *p; 69 | continue; 70 | } 71 | p++; 72 | if (*p != 'i') { 73 | len += 2; 74 | if (len > max) 75 | return 0; 76 | *f++ = '%'; 77 | *f++ = *p; 78 | continue; 79 | } 80 | len += 6; 81 | if (len > max) 82 | return 0; 83 | sprintf(f, "%06u", usec); 84 | f += 6; 85 | } 86 | if (len + 1 > max) 87 | return 0; 88 | *f = '\0'; 89 | 90 | n = strftime(s, max, newfmt, tm); 91 | return n; 92 | } 93 | 94 | #define strfTIM_tz(tz) \ 95 | size_t \ 96 | strfTIM##tz(char *s, size_t max, const char *fmt, double t) \ 97 | { \ 98 | struct timeval tim = double2timeval(t); \ 99 | struct tm tm; \ 100 | \ 101 | AN(tz##time_r((time_t *) &tim.tv_sec, &tm)); \ 102 | return(strfTIM(s, max, fmt, &tm, tim.tv_usec)); \ 103 | } 104 | 105 | strfTIM_tz(local) 106 | strfTIM_tz(gm) 107 | -------------------------------------------------------------------------------- /src/flopen.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2007 Dag-Erling Coïdan Smørgrav 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer 10 | * in this position and unchanged. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 | * SUCH DAMAGE. 26 | * Derived from: 27 | * $FreeBSD: head/lib/libutil/flopen.c 184094 2008-10-20 18:11:30Z des $ 28 | */ 29 | 30 | #include "config.h" 31 | 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "flopen.h" 41 | 42 | int 43 | flopen(const char *path, int flags, ...) 44 | { 45 | int fd, operation, serrno, trunc; 46 | struct flock lock; 47 | struct stat sb, fsb; 48 | mode_t mode; 49 | 50 | #ifdef O_EXLOCK 51 | flags &= ~O_EXLOCK; 52 | #endif 53 | 54 | mode = 0; 55 | if (flags & O_CREAT) { 56 | va_list ap; 57 | 58 | va_start(ap, flags); 59 | mode = (mode_t)va_arg(ap, int); /* mode_t promoted to int */ 60 | va_end(ap); 61 | } 62 | 63 | memset(&lock, 0, sizeof lock); 64 | lock.l_type = ((flags & O_ACCMODE) == O_RDONLY) ? F_RDLCK : F_WRLCK; 65 | lock.l_whence = SEEK_SET; 66 | operation = (flags & O_NONBLOCK) ? F_SETLK : F_SETLKW; 67 | 68 | trunc = (flags & O_TRUNC); 69 | flags &= ~O_TRUNC; 70 | 71 | for (;;) { 72 | if ((fd = open(path, flags, mode)) == -1) 73 | /* non-existent or no access */ 74 | return (-1); 75 | if (fcntl(fd, operation, &lock) == -1) { 76 | /* unsupported or interrupted */ 77 | serrno = errno; 78 | (void)close(fd); 79 | errno = serrno; 80 | return (-1); 81 | } 82 | if (stat(path, &sb) == -1) { 83 | /* disappeared from under our feet */ 84 | (void)close(fd); 85 | continue; 86 | } 87 | if (fstat(fd, &fsb) == -1) { 88 | /* can't happen [tm] */ 89 | serrno = errno; 90 | (void)close(fd); 91 | errno = serrno; 92 | return (-1); 93 | } 94 | if (sb.st_dev != fsb.st_dev || 95 | sb.st_ino != fsb.st_ino) { 96 | /* changed under our feet */ 97 | (void)close(fd); 98 | continue; 99 | } 100 | if (trunc && ftruncate(fd, 0) != 0) { 101 | /* can't happen [tm] */ 102 | serrno = errno; 103 | (void)close(fd); 104 | errno = serrno; 105 | return (-1); 106 | } 107 | return (fd); 108 | } 109 | } 110 | 111 | /* Tests if the given fd is locked through flopen 112 | * If pid is non-NULL, stores the pid of the process holding the lock there 113 | * Returns 1 if the file is locked 114 | * Returns 0 if the file is unlocked 115 | * Returns -1 on error (and errno) 116 | */ 117 | int 118 | fltest(int fd, pid_t *pid) 119 | { 120 | struct flock lock; 121 | 122 | memset(&lock, 0, sizeof lock); 123 | lock.l_type = F_WRLCK; 124 | lock.l_whence = SEEK_SET; 125 | 126 | if (fcntl(fd, F_GETLK, &lock) == -1) 127 | return (-1); 128 | if (lock.l_type == F_UNLCK) 129 | return (0); 130 | if (pid != NULL) 131 | *pid = lock.l_pid; 132 | return (1); 133 | } 134 | -------------------------------------------------------------------------------- /src/monitor.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2013-2015 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2013-2015 Otto Gmbh & Co KG 4 | * All rights reserved 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include "config.h" 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #include "varnishevent.h" 39 | #include "vtim.h" 40 | 41 | #include "vas.h" 42 | 43 | static int run = 0; 44 | 45 | static pthread_t monitor; 46 | static pthread_mutex_t stats_lock = PTHREAD_MUTEX_INITIALIZER; 47 | 48 | static void 49 | log_output(void) 50 | { 51 | LOG_Log(LOG_INFO, "Data tables: len_tx=%u len_rec=%u len_chunk=%u " 52 | "tx_occ=%u rec_occ=%u chunk_occ=%u tx_occ_hi=%u rec_occ_hi=%u " 53 | "chunk_occ_hi=%u global_free_tx=%u global_free_rec=%u " 54 | "global_free_chunk=%u", 55 | config.max_data, nrecords, nchunks, tx_occ, rec_occ, chunk_occ, 56 | tx_occ_hi, rec_occ_hi, chunk_occ_hi, global_nfree_tx, 57 | global_nfree_rec, global_nfree_chunk); 58 | 59 | RDR_Stats(); 60 | 61 | WRT_Stats(); 62 | 63 | SPSCQ_Stats(); 64 | } 65 | 66 | static void 67 | monitor_cleanup(void *arg) 68 | { 69 | (void) arg; 70 | 71 | log_output(); 72 | LOG_Log0(LOG_NOTICE, "Monitoring thread exiting"); 73 | } 74 | 75 | static void * 76 | monitor_main(void *arg) 77 | { 78 | thread_setname(pthread_self(), "vevent_monitor"); 79 | LOG_Log(LOG_NOTICE, "Monitor thread running every %u secs", 80 | config.monitor_interval); 81 | run = 1; 82 | 83 | pthread_cleanup_push(monitor_cleanup, arg); 84 | 85 | while (run) { 86 | VTIM_sleep(config.monitor_interval); 87 | log_output(); 88 | } 89 | 90 | pthread_cleanup_pop(0); 91 | LOG_Log0(LOG_NOTICE, "Monitoring thread exiting"); 92 | pthread_exit((void *) NULL); 93 | } 94 | 95 | void 96 | MON_Output(void) 97 | { 98 | log_output(); 99 | } 100 | 101 | void 102 | MON_Shutdown(void) 103 | { 104 | if (run) { 105 | run = 0; 106 | AZ(pthread_cancel(monitor)); 107 | AZ(pthread_join(monitor, NULL)); 108 | } 109 | AZ(pthread_mutex_destroy(&stats_lock)); 110 | } 111 | 112 | void 113 | MON_Start(void) 114 | { 115 | AZ(pthread_create(&monitor, NULL, monitor_main, NULL)); 116 | } 117 | 118 | void 119 | MON_StatsUpdate(stats_update_t update, unsigned nrec, unsigned nchunk) 120 | { 121 | AZ(pthread_mutex_lock(&stats_lock)); 122 | switch(update) { 123 | 124 | case STATS_WRITTEN: 125 | tx_occ--; 126 | rec_occ -= nrec; 127 | chunk_occ -= nchunk; 128 | break; 129 | 130 | case STATS_DONE: 131 | tx_occ++; 132 | rec_occ += nrec; 133 | chunk_occ += nchunk; 134 | break; 135 | 136 | default: 137 | /* Unreachable */ 138 | AN(NULL); 139 | } 140 | AZ(pthread_mutex_unlock(&stats_lock)); 141 | } 142 | -------------------------------------------------------------------------------- /src/test/ncsa.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Outputs of varnishevent and varnishncsa for client formats are 4 | # identical, except that varnishevent emits empty strings for data 5 | # from headers that are empty, and varnishnca emits a '-'. 6 | 7 | echo 8 | echo "TEST: $0" 9 | echo "... testing equivalence of output with varnishncsa" 10 | 11 | # automake skip 12 | SKIP=77 13 | 14 | TMP=${TMPDIR:-/tmp} 15 | EVENT="../varnishevent" 16 | NCSA=$( which varnishncsa ) 17 | 18 | if [ -x "$NSCA" ]; then 19 | echo "varnishncsa not found or not executable ($NCSA), skipping" 20 | exit $SKIP 21 | fi 22 | 23 | EVENT_LOG=$TMP/event.log 24 | NCSA_LOG=$TMP/ncsa.log 25 | INPUT=varnish-4.1.0-doc.log 26 | 27 | DIFF_CMD="diff $EVENT_LOG $NCSA_LOG" 28 | 29 | echo "... default format" 30 | $EVENT -r $INPUT | sed 's/-//g' > $EVENT_LOG 31 | $NCSA -r $INPUT | sed 's/-//g' > $NCSA_LOG 32 | 33 | $DIFF_CMD 34 | RC=$? 35 | rm $EVENT_LOG 36 | rm $NCSA_LOG 37 | 38 | if [ "$RC" -ne "0" ]; then 39 | echo "ERROR: outputs of no-arg varnishevent and varnishncsa differ" 40 | exit 1 41 | fi 42 | 43 | # Cannot test the %D formatter, because varnishevent gets it more accurately 44 | # (varnishncsa has floating point errors). 45 | FORMAT='%b %H %h %I %{Host}i %{Connection}i %{User-Agent}i %{X-Forwarded-For}i %{Accept-Ranges}o %{Age}o %{Connection}o %{Content-Encoding}o %{Content-Length}o %{Content-Type}o %{Date}o %{Last-Modified}o %{Server}o %{Transfer-Encoding}o %{Via}o %{X-Varnish}o %l %m %O %q %r %s %t %{%F-%T}t %U %u %{Varnish:time_firstbyte}x %{Varnish:hitmiss}x %{Varnish:handling}x %{VSL:Begin}x %{VSL:Debug}x %{VSL:End}x %{VSL:Gzip}x %{VSL:Hit}x %{VSL:Length}x %{VSL:Link}x %{VSL:ReqAcct}x %{VSL:ReqStart}x %{VSL:RespProtocol}x %{VSL:ReqMethod}x %{VSL:ReqURL}x %{VSL:ReqProtocol}x %{VSL:RespReason}x %{VSL:RespStatus}x %{VSL:Timestamp}x %{Varnish:vxid}x %{Varnish:side}x' 46 | 47 | echo "... custom -F format" 48 | $EVENT -r $INPUT -F "$FORMAT" | sed 's/-//g' > $EVENT_LOG 49 | $NCSA -r $INPUT -F "$FORMAT" | sed 's/-//g' > $NCSA_LOG 50 | 51 | $DIFF_CMD 52 | RC=$? 53 | rm $EVENT_LOG 54 | rm $NCSA_LOG 55 | 56 | if [ "$RC" -ne "0" ]; then 57 | echo "ERROR: outputs of varnishevent/varnishncsa -F differ" 58 | exit 1 59 | fi 60 | 61 | FORMAT='%b %H %h %I %{Host}i %{User-Agent}i %{X-Forwarded-For}i %{Accept-Ranges}o %{Connection}o %{Content-Encoding}o %{Content-Length}o %{Content-Type}o %{Date}o %{Last-Modified}o %{ETag}o %{Server}o %l %m %O %q %r %s %t %{%F-%T}t %U %u %{Varnish:time_firstbyte}x %{VSL:Begin}x %{VSL:End}x %{VSL:Link}x %{VSL:Timestamp}x %{Varnish:vxid}x %{Varnish:side}x' 62 | 63 | # Skip the first line of varnishevent output ("Reading config file ...") 64 | # Remove \" escaping from varnishncsa output (done for ETag) 65 | echo "... client and backend logging" 66 | $EVENT -r $INPUT -f backend_client.conf | tail -n +2 | sed 's/-//g' > $EVENT_LOG 67 | $NCSA -r $INPUT -F "$FORMAT" -b -c | sed 's/-//g; s/\\"/"/g' > $NCSA_LOG 68 | 69 | $DIFF_CMD 70 | RC=$? 71 | rm $EVENT_LOG 72 | rm $NCSA_LOG 73 | 74 | if [ "$RC" -ne "0" ]; then 75 | echo "ERROR: varnishevent/varnishncsa backend and client logs differ" 76 | exit 1 77 | fi 78 | 79 | FORMAT_EVENT='%{VSL:Timestamp[1]}x' 80 | FORMAT_NCSA='%{VSL:Timestamp[2]}x' 81 | 82 | echo "... VSL formatter" 83 | $EVENT -r $INPUT -F "$FORMAT_EVENT" > $EVENT_LOG 84 | $NCSA -r $INPUT -F "$FORMAT_NCSA" > $NCSA_LOG 85 | 86 | $DIFF_CMD 87 | RC=$? 88 | rm $EVENT_LOG 89 | rm $NCSA_LOG 90 | 91 | if [ "$RC" -ne "0" ]; then 92 | echo "ERROR: outputs of varnishevent/varnishncsa VSL formatter differ" 93 | exit 1 94 | fi 95 | 96 | FORMAT_EVENT='%{tag:Timestamp[1]}x' 97 | FORMAT_NCSA='%{VSL:Timestamp[2]}x' 98 | 99 | echo "... compatibility of tag and VSL formatter" 100 | $EVENT -r $INPUT -F "$FORMAT_EVENT" > $EVENT_LOG 101 | $NCSA -r $INPUT -F "$FORMAT_NCSA" > $NCSA_LOG 102 | 103 | $DIFF_CMD 104 | RC=$? 105 | rm $EVENT_LOG 106 | rm $NCSA_LOG 107 | 108 | if [ "$RC" -ne "0" ]; then 109 | echo "ERROR: tag and VSL formatters for varnishevent and varnishncsa differ" 110 | exit 1 111 | fi 112 | 113 | FORMAT_EVENT='%{vxid}x' 114 | FORMAT_NCSA='%{Varnish:vxid}x' 115 | 116 | echo "... compatibility of the vxid and Varnish:vxid formatters" 117 | $EVENT -r $INPUT -F "$FORMAT_EVENT" > $EVENT_LOG 118 | $NCSA -r $INPUT -F "$FORMAT_NCSA" > $NCSA_LOG 119 | 120 | $DIFF_CMD 121 | RC=$? 122 | rm $EVENT_LOG 123 | rm $NCSA_LOG 124 | 125 | if [ "$RC" -ne "0" ]; then 126 | echo "ERROR: vxid and Varnish:vxid formatters for varnishevent and varnishncsa differ" 127 | exit 1 128 | fi 129 | 130 | exit 0 131 | -------------------------------------------------------------------------------- /src/test/minunit.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2012 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2012 Otto Gmbh & Co KG 4 | * All rights reserved 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #ifndef _MINUNIT_INCLUDED 33 | #define _MINUNIT_INCLUDED 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | /*- 41 | * Adapted from http://www.jera.com/techinfo/jtns/jtn002.html 42 | * "MinUnit" - a minimal unit testing framework for C 43 | * 44 | * "You may use the code in this tech note for any purpose, with the 45 | * understanding that it comes with NO WARRANTY." 46 | */ 47 | 48 | #define mu_assert(msg, test) do { if (!(test)) return msg; } while (0) 49 | #define mu_run_test(test) do { const char *msg = test(); tests_run++; \ 50 | if (msg) return msg; } while (0) 51 | 52 | char _mu_errmsg[BUFSIZ]; 53 | 54 | #define _massert(test, msg, ...) \ 55 | do { \ 56 | if (!(test)) { \ 57 | sprintf(_mu_errmsg, (msg), __VA_ARGS__); \ 58 | return (_mu_errmsg); \ 59 | } \ 60 | } while(0) 61 | 62 | #define _massert0(test, msg) \ 63 | do { \ 64 | if (!(test)) { \ 65 | sprintf(_mu_errmsg, (msg)); \ 66 | return (_mu_errmsg); \ 67 | } \ 68 | } while(0) 69 | 70 | #define VMASSERT(test, msg, ...) _massert((test),(msg),__VA_ARGS__) 71 | #define MASSERT0(test, msg) _massert0((test),(msg)) 72 | 73 | #define MASSERT(c) \ 74 | VMASSERT((c), "%s failed in %s at %s:%d (errno %d: %s)", \ 75 | #c, __func__, __FILE__, __LINE__, errno, strerror(errno)) 76 | 77 | /* short for MU Assert Zero / Non-Zero */ 78 | #define MAZ(c) MASSERT((c) == 0) 79 | #define MAN(c) MASSERT((c) != 0) 80 | 81 | #define MCHECK_OBJ(ptr, type_magic) MASSERT((ptr)->magic == type_magic) 82 | #define MCHECK_OBJ_NOTNULL(ptr, type_magic) \ 83 | do { \ 84 | MAN(ptr); \ 85 | MCHECK_OBJ(ptr, type_magic); \ 86 | } while(0) 87 | 88 | extern int tests_run; 89 | 90 | #define TEST_RUNNER \ 91 | int \ 92 | main(int argc, char **argv) \ 93 | { \ 94 | (void) argc; \ 95 | \ 96 | printf("\nTEST: %s\n", argv[0]); \ 97 | const char *result = all_tests(); \ 98 | printf("%s: %d tests run\n", argv[0], tests_run); \ 99 | if (result != NULL) { \ 100 | printf("%s\n", result); \ 101 | exit(EXIT_FAILURE); \ 102 | } \ 103 | exit(EXIT_SUCCESS); \ 104 | } 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /src/test/test_strfTIM.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2012 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2012 Otto Gmbh & Co KG 4 | * All rights reserved 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "minunit.h" 38 | 39 | #include "../strfTIM.h" 40 | 41 | int tests_run = 0; 42 | 43 | static char 44 | *test_strfTIM_strftime(void) 45 | { 46 | time_t now; 47 | struct tm *tm; 48 | char strftime_s[BUFSIZ], strfTIM_s[BUFSIZ]; 49 | const char *fmt = 50 | "%a %A %b %B %c %C %d %D %e %F %g %G %h %H %I %J %m %M %n %p %r %R %S "\ 51 | "%t %T %u %U %V %w %W %x %X %y %Y %z %Z %% %Ec %EC %Ex %EX %Ey %Ey "\ 52 | "%Od %Oe %OH %OI %Om %OM %OS %Ou %OU %OV %Ow %OW %Oy"; 53 | size_t strftime_n, strfTIM_n; 54 | 55 | printf("... testing strfTIM equivalence to strftime\n"); 56 | 57 | time(&now); 58 | tm = localtime(&now); 59 | assert(tm != NULL); 60 | 61 | strftime_n = strftime(strftime_s, BUFSIZ, fmt, tm); 62 | strfTIM_n = strfTIM(strfTIM_s, BUFSIZ, fmt, tm, 0); 63 | 64 | VMASSERT(strfTIM_n == strftime_n, "strfTIM return value %zu (expected %zu)", 65 | strfTIM_n, strftime_n); 66 | 67 | VMASSERT(strcmp(strfTIM_s, strftime_s) == 0, 68 | "strfTIM result '%s' (expected '%s')", strfTIM_s, strftime_s); 69 | 70 | return NULL; 71 | } 72 | 73 | static char 74 | *test_strfTIM_N(void) 75 | { 76 | size_t n; 77 | time_t t = 1382804827; 78 | long usec = 112625; 79 | const char *exp = "2013-10-26-16:27:07.112625"; 80 | char s[BUFSIZ]; 81 | struct tm *tm; 82 | 83 | printf("... testing strfTIM %%i conversion specifier\n"); 84 | 85 | tm = gmtime(&t); 86 | MAN(tm); 87 | 88 | n = strfTIM(s, BUFSIZ, "%F-%T.%i", tm, usec); 89 | VMASSERT(n == strlen(exp), "strfTIM return value %zu (expected %zu)", n, 90 | strlen(exp)); 91 | 92 | VMASSERT(strcmp(s, exp) == 0, "strfTIM result '%s' (expected '%s')", s, 93 | exp); 94 | 95 | n = strfTIM(s, BUFSIZ, "%%i", tm, usec); 96 | VMASSERT(n == strlen("%i"), "strfTIM return value %zu (expected %zu)", n, 97 | strlen("%i")); 98 | 99 | VMASSERT(strcmp(s, "%i") == 0, "strfTIM result '%s' (expected '%s')", s, 100 | "%i"); 101 | 102 | n = strfTIM(s, BUFSIZ, "%%%i", tm, usec); 103 | VMASSERT(n == strlen("%112625"), "strfTIM return value %zu (expected %zu)", 104 | n, strlen("%112625")); 105 | 106 | VMASSERT(strcmp(s, "%112625") == 0, "strfTIM result '%s' (expected '%s')", 107 | s, "%112625"); 108 | 109 | return NULL; 110 | } 111 | 112 | static char 113 | *test_strfTIMlocal(void) 114 | { 115 | size_t n; 116 | time_t t = 1382804820; 117 | struct tm *tm; 118 | char s[BUFSIZ], exp[BUFSIZ]; 119 | 120 | printf("... testing strfTIMlocal\n"); 121 | 122 | n = strfTIMlocal(s, BUFSIZ, "%F-%T.%i", 1382804820.112625); 123 | tm = localtime(&t); 124 | MAN(tm); 125 | strftime(exp, BUFSIZ, "%F-%T.112625", tm); 126 | VMASSERT(n == strlen(exp), "strfTIMlocal return value %zu (expected %zu)", 127 | n, strlen(exp)); 128 | 129 | /* Not accurate at the last decimal place, due to floating point 130 | * precision */ 131 | s[n - 1] = exp[n - 1] = '\0'; 132 | VMASSERT(strcmp(s, exp) == 0, "strfTIMlocal result '%s' (expected '%s')", 133 | s, exp); 134 | 135 | return NULL; 136 | } 137 | 138 | static char 139 | *test_strfTIMgm(void) 140 | { 141 | size_t n; 142 | char s[BUFSIZ], exp[BUFSIZ]; 143 | 144 | printf("... testing strfTIMgm\n"); 145 | 146 | n = strfTIMgm(s, BUFSIZ, "%F-%T.%i", 1382804820.112625); 147 | sprintf(exp, "2013-10-26-16:27:0%.6f", 0.112625); 148 | VMASSERT(n == strlen(exp), "strfTIMgm return value %zu (expected %zu)", 149 | n, strlen(exp)); 150 | 151 | /* As above */ 152 | s[n - 1] = exp[n - 1] = '\0'; 153 | VMASSERT(strcmp(s, exp) == 0, "strfTIMgm result '%s' (expected '%s')", 154 | s, exp); 155 | 156 | return NULL; 157 | } 158 | 159 | static const char 160 | *all_tests(void) 161 | { 162 | mu_run_test(test_strfTIM_strftime); 163 | mu_run_test(test_strfTIM_N); 164 | mu_run_test(test_strfTIMlocal); 165 | mu_run_test(test_strfTIMgm); 166 | return NULL; 167 | } 168 | 169 | TEST_RUNNER 170 | -------------------------------------------------------------------------------- /src/handler.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2012 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2012 Otto Gmbh & Co KG 4 | * All rights reserved 5 | * Use only with permission 6 | * 7 | * Authors: Geoffrey Simmons 8 | * Nils Goroll 9 | * 10 | * Portions adopted from varnishlog.c from the Varnish project 11 | * Author: Poul-Henning Kamp 12 | * Copyright (c) 2006 Verdens Gang AS 13 | * Copyright (c) 2006-2011 Varnish Software AS 14 | * 15 | * Redistribution and use in source and binary forms, with or without 16 | * modification, are permitted provided that the following conditions 17 | * are met: 18 | * 1. Redistributions of source code must retain the above copyright 19 | * notice, this list of conditions and the following disclaimer. 20 | * 2. Redistributions in binary form must reproduce the above copyright 21 | * notice, this list of conditions and the following disclaimer in the 22 | * documentation and/or other materials provided with the distribution. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 | * SUCH DAMAGE. 35 | * 36 | */ 37 | 38 | #include "config.h" 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #ifdef HAVE_EXECINFO_H 48 | #include 49 | #endif 50 | 51 | #include "vas.h" 52 | #include "vdef.h" 53 | #include "vsb.h" 54 | 55 | #include "varnishevent.h" 56 | 57 | /* XXX: configurable? */ 58 | #define MAX_STACK_DEPTH 100 59 | 60 | /*--------------------------------------------------------------------*/ 61 | 62 | /* 63 | * This hack is almost verbatim from varnishd.c -- attempt to run nm(1) on 64 | * ourselves at startup to get a mapping from lib pointers to symbolic 65 | * function names for stack traces. 66 | * 67 | * +1 to phk's rant in varnishd.c about the lack of a standard for this. 68 | */ 69 | 70 | #ifdef HAVE_EXECINFO_H 71 | 72 | struct symbols { 73 | uintptr_t a; 74 | char *n; 75 | VTAILQ_ENTRY(symbols) list; 76 | }; 77 | 78 | static VTAILQ_HEAD(,symbols) symbols = VTAILQ_HEAD_INITIALIZER(symbols); 79 | 80 | static int 81 | symbol_lookup(struct vsb *vsb, void *ptr) 82 | { 83 | struct symbols *s, *s0; 84 | uintptr_t pp; 85 | 86 | pp = (uintptr_t)ptr; 87 | s0 = NULL; 88 | VTAILQ_FOREACH(s, &symbols, list) { 89 | if (s->a > pp) 90 | continue; 91 | if (s0 == NULL || s->a > s0->a) 92 | s0 = s; 93 | } 94 | if (s0 == NULL) 95 | return (-1); 96 | VSB_printf(vsb, "%p: %s+%jx", ptr, s0->n, (uintmax_t)pp - s0->a); 97 | return (0); 98 | } 99 | 100 | static void 101 | symbol_hack(const char *a0) 102 | { 103 | char buf[BUFSIZ], *p, *e; 104 | FILE *fi; 105 | uintptr_t a; 106 | struct symbols *s; 107 | 108 | bprintf(buf, "nm -an %s 2>/dev/null", a0); 109 | fi = popen(buf, "r"); 110 | if (fi == NULL) 111 | return; 112 | while (fgets(buf, sizeof buf, fi)) { 113 | if (buf[0] == ' ') 114 | continue; 115 | p = NULL; 116 | a = strtoul(buf, &p, 16); 117 | if (p == NULL) 118 | continue; 119 | if (a == 0) 120 | continue; 121 | if (*p++ != ' ') 122 | continue; 123 | p++; 124 | if (*p++ != ' ') 125 | continue; 126 | if (*p <= ' ') 127 | continue; 128 | e = strchr(p, '\0'); 129 | AN(e); 130 | while (e > p && isspace(e[-1])) 131 | e--; 132 | *e = '\0'; 133 | s = malloc(sizeof *s + strlen(p) + 1); 134 | AN(s); 135 | s->a = a; 136 | s->n = (void*)(s + 1); 137 | strcpy(s->n, p); 138 | VTAILQ_INSERT_TAIL(&symbols, s, list); 139 | } 140 | (void)pclose(fi); 141 | } 142 | 143 | static void 144 | stacktrace(void) 145 | { 146 | void *buf[MAX_STACK_DEPTH]; 147 | int depth, i; 148 | struct vsb *sb = VSB_new_auto(); 149 | 150 | depth = backtrace (buf, MAX_STACK_DEPTH); 151 | if (depth == 0) { 152 | LOG_Log0(LOG_ERR, "Stacktrace empty"); 153 | return; 154 | } 155 | for (i = 0; i < depth; i++) { 156 | VSB_clear(sb); 157 | if (symbol_lookup(sb, buf[i]) < 0) { 158 | char **strings; 159 | strings = backtrace_symbols(&buf[i], 1); 160 | if (strings != NULL && strings[0] != NULL) 161 | VSB_printf(sb, "%p: %s", buf[i], strings[0]); 162 | else 163 | VSB_printf(sb, "%p: (?)", buf[i]); 164 | } 165 | VSB_finish(sb); 166 | LOG_Log(LOG_ERR, "%s", VSB_data(sb)); 167 | } 168 | } 169 | 170 | #endif 171 | 172 | void 173 | HNDL_Init(const char *a0) 174 | { 175 | #ifdef HAVE_EXECINFO_H 176 | symbol_hack(a0); 177 | #else 178 | (void) a0; 179 | #endif 180 | } 181 | 182 | void 183 | HNDL_Abort(int sig) 184 | { 185 | AZ(sigaction(SIGABRT, &default_action, NULL)); 186 | LOG_Log(LOG_ALERT, "Received signal %d (%s)", sig, strsignal(sig)); 187 | #ifdef HAVE_EXECINFO_H 188 | LOG_Log0(LOG_NOTICE, "Stacktrace follows"); 189 | stacktrace(); 190 | #endif 191 | CONF_Dump(); 192 | DATA_Dump(); 193 | MON_Output(); 194 | LOG_Log0(LOG_ALERT, "Aborting"); 195 | abort(); 196 | } 197 | -------------------------------------------------------------------------------- /src/vpf.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2005 Pawel Jakub Dawidek 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * Derived from: 26 | * $FreeBSD: head/lib/libutil/pidfile.c 184091 2008-10-20 17:41:08Z des $ 27 | */ 28 | 29 | #include "config.h" 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "flopen.h" 44 | #include "vas.h" 45 | #include "vpf.h" 46 | 47 | struct vpf_fh { 48 | int pf_fd; 49 | char pf_path[MAXPATHLEN + 1]; 50 | dev_t pf_dev; 51 | ino_t pf_ino; 52 | }; 53 | 54 | static int _VPF_Remove(struct vpf_fh *pfh, int freeit); 55 | 56 | static int 57 | vpf_verify(const struct vpf_fh *pfh) 58 | { 59 | struct stat sb; 60 | 61 | if (pfh == NULL || pfh->pf_fd == -1) 62 | return (EINVAL); 63 | /* 64 | * Check remembered descriptor. 65 | */ 66 | if (fstat(pfh->pf_fd, &sb) == -1) 67 | return (errno); 68 | if (sb.st_dev != pfh->pf_dev || sb.st_ino != pfh->pf_ino) 69 | return (EINVAL); 70 | return (0); 71 | } 72 | 73 | static int 74 | vpf_read(const char *path, pid_t *pidptr) 75 | { 76 | char buf[16], *endptr; 77 | int error, fd, i; 78 | 79 | fd = open(path, O_RDONLY); 80 | if (fd == -1) 81 | return (errno); 82 | 83 | i = read(fd, buf, sizeof(buf) - 1); 84 | error = errno; /* Remember errno in case close() wants to change it. */ 85 | (void)close(fd); 86 | if (i == -1) 87 | return (error); 88 | buf[i] = '\0'; 89 | 90 | *pidptr = strtol(buf, &endptr, 10); 91 | if (endptr != &buf[i]) 92 | return (EINVAL); 93 | 94 | return (0); 95 | } 96 | 97 | struct vpf_fh * 98 | VPF_Open(const char *path, mode_t mode, pid_t *pidptr) 99 | { 100 | struct vpf_fh *pfh; 101 | struct stat sb; 102 | int error, fd, len; 103 | 104 | pfh = malloc(sizeof(*pfh)); 105 | if (pfh == NULL) 106 | return (NULL); 107 | 108 | #if 0 109 | if (path == NULL) 110 | len = snprintf(pfh->pf_path, sizeof(pfh->pf_path), 111 | "/var/run/%s.pid", getprogname()); 112 | else 113 | #endif 114 | { 115 | assert(path != NULL); 116 | len = snprintf(pfh->pf_path, sizeof(pfh->pf_path), 117 | "%s", path); 118 | } 119 | if (len >= (int)sizeof(pfh->pf_path)) { 120 | free(pfh); 121 | errno = ENAMETOOLONG; 122 | return (NULL); 123 | } 124 | 125 | /* 126 | * Open the PID file and obtain exclusive lock. 127 | * We truncate PID file here only to remove old PID immediatelly, 128 | * PID file will be truncated again in VPF_Write(), so 129 | * VPF_Write() can be called multiple times. 130 | */ 131 | fd = flopen(pfh->pf_path, 132 | O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, mode); 133 | if (fd == -1) { 134 | if (errno == EWOULDBLOCK && pidptr != NULL) { 135 | errno = vpf_read(pfh->pf_path, pidptr); 136 | if (errno == 0) 137 | errno = EEXIST; 138 | } 139 | free(pfh); 140 | return (NULL); 141 | } 142 | /* 143 | * Remember file information, so in VPF_Write() we are sure we write 144 | * to the proper descriptor. 145 | */ 146 | if (fstat(fd, &sb) == -1) { 147 | error = errno; 148 | (void)unlink(pfh->pf_path); 149 | (void)close(fd); 150 | free(pfh); 151 | errno = error; 152 | return (NULL); 153 | } 154 | 155 | pfh->pf_fd = fd; 156 | pfh->pf_dev = sb.st_dev; 157 | pfh->pf_ino = sb.st_ino; 158 | 159 | return (pfh); 160 | } 161 | 162 | int 163 | VPF_Write(struct vpf_fh *pfh) 164 | { 165 | char pidstr[16]; 166 | int error, fd; 167 | 168 | /* 169 | * Check remembered descriptor, so we don't overwrite some other 170 | * file if pidfile was closed and descriptor reused. 171 | */ 172 | errno = vpf_verify(pfh); 173 | if (errno != 0) { 174 | /* 175 | * Don't close descriptor, because we are not sure if it's ours. 176 | */ 177 | return (-1); 178 | } 179 | fd = pfh->pf_fd; 180 | 181 | /* 182 | * Truncate PID file, so multiple calls of VPF_Write() are allowed. 183 | */ 184 | if (ftruncate(fd, 0) == -1) { 185 | error = errno; 186 | (void)_VPF_Remove(pfh, 0); 187 | errno = error; 188 | return (-1); 189 | } 190 | 191 | error = snprintf(pidstr, sizeof(pidstr), "%ju", (uintmax_t)getpid()); 192 | assert(error < sizeof pidstr); 193 | if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) { 194 | error = errno; 195 | (void)_VPF_Remove(pfh, 0); 196 | errno = error; 197 | return (-1); 198 | } 199 | 200 | return (0); 201 | } 202 | 203 | int 204 | VPF_Close(struct vpf_fh *pfh) 205 | { 206 | int error; 207 | 208 | error = vpf_verify(pfh); 209 | if (error != 0) { 210 | errno = error; 211 | return (-1); 212 | } 213 | 214 | if (close(pfh->pf_fd) == -1) 215 | error = errno; 216 | free(pfh); 217 | if (error != 0) { 218 | errno = error; 219 | return (-1); 220 | } 221 | return (0); 222 | } 223 | 224 | static int 225 | _VPF_Remove(struct vpf_fh *pfh, int freeit) 226 | { 227 | int error; 228 | 229 | error = vpf_verify(pfh); 230 | if (error != 0) { 231 | errno = error; 232 | return (-1); 233 | } 234 | 235 | if (unlink(pfh->pf_path) == -1) 236 | error = errno; 237 | if (close(pfh->pf_fd) == -1) { 238 | if (error == 0) 239 | error = errno; 240 | } 241 | if (freeit) 242 | free(pfh); 243 | else 244 | pfh->pf_fd = -1; 245 | if (error != 0) { 246 | errno = error; 247 | return (-1); 248 | } 249 | return (0); 250 | } 251 | 252 | int 253 | VPF_Remove(struct vpf_fh *pfh) 254 | { 255 | 256 | return (_VPF_Remove(pfh, 1)); 257 | } 258 | -------------------------------------------------------------------------------- /src/hdrtrie.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2016 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2016 Otto Gmbh & Co KG 4 | * All rights reserved. 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "hdrtrie.h" 38 | 39 | #include "vas.h" 40 | #include "miniobj.h" 41 | 42 | static inline int 43 | hdr_next(const char c) 44 | { 45 | if (c == '~') 46 | return ':' - 32; 47 | return toupper(c) - 32; 48 | } 49 | 50 | int 51 | HDR_FindIdx(struct hdrt_node *hdrt, const char *hdr) 52 | { 53 | const char *h = hdr; 54 | 55 | if (hdrt == NULL) 56 | return -1; 57 | while (*h && isspace(*h)) 58 | h++; 59 | if (*h == '\0') 60 | return -1; 61 | while (1) { 62 | char *s; 63 | int n; 64 | 65 | CHECK_OBJ(hdrt, HDRT_NODE_MAGIC); 66 | s = hdrt->str; 67 | while (*h && *s && (toupper(*h) == *s)) { 68 | h++; 69 | s++; 70 | } 71 | if (*s != '\0') 72 | return -1; 73 | n = hdr_next(*h); 74 | if (n < 0 || n >= 64) 75 | return -1; 76 | if (hdrt->next[n] == NULL) 77 | break; 78 | hdrt = hdrt->next[n]; 79 | h++; 80 | } 81 | while (*h && isspace(*h)) 82 | h++; 83 | if (*h != ':' || *h == '\0') 84 | return -1; 85 | return hdrt->idx; 86 | } 87 | 88 | struct hdrt_node * 89 | HDR_InsertIdx(struct hdrt_node *hdrt, const char *hdr, int idx) 90 | { 91 | const char *h = hdr; 92 | char *s; 93 | int n; 94 | 95 | if (hdrt == NULL) { 96 | ALLOC_OBJ(hdrt, HDRT_NODE_MAGIC); 97 | AN(hdrt); 98 | hdrt->str = strdup(hdr); 99 | AN(hdrt->str); 100 | for (s = hdrt->str; *s; s++) 101 | *s = toupper(*s); 102 | hdrt->next = calloc(64, sizeof(struct hdrt_node *)); 103 | AN(hdrt->next); 104 | hdrt->idx = idx; 105 | return hdrt; 106 | } 107 | 108 | CHECK_OBJ(hdrt, HDRT_NODE_MAGIC); 109 | s = hdrt->str; 110 | while (*h && *s && (toupper(*h) == *s)) { 111 | h++; 112 | s++; 113 | } 114 | if (*s == '\0' && *h == '\0') 115 | assert(hdrt->idx == idx); 116 | else if (*s == '\0') { 117 | n = hdr_next(*h); 118 | assert(n >= 0 && n < 64); 119 | hdrt->next[n] = HDR_InsertIdx(hdrt->next[n], ++h, idx); 120 | CHECK_OBJ_NOTNULL(hdrt->next[n], HDRT_NODE_MAGIC); 121 | } 122 | else if (*h == '\0') { 123 | n = hdr_next(*s); 124 | assert(n >= 0 && n < 64); 125 | *s = '\0'; 126 | hdrt->next[n] = HDR_InsertIdx(hdrt->next[n], ++s, hdrt->idx); 127 | CHECK_OBJ_NOTNULL(hdrt->next[n], HDRT_NODE_MAGIC); 128 | hdrt->idx = idx; 129 | } 130 | else { 131 | struct hdrt_node **s_next; 132 | 133 | n = hdr_next(*s); 134 | assert(n >= 0 && n < 64); 135 | *s = '\0'; 136 | s_next = hdrt->next; 137 | hdrt->next = calloc(64, sizeof(struct hdrt_next *)); 138 | AN(hdrt->next); 139 | hdrt->next[n] = HDR_InsertIdx(hdrt->next[n], ++s, hdrt->idx); 140 | CHECK_OBJ_NOTNULL(hdrt->next[n], HDRT_NODE_MAGIC); 141 | hdrt->next[n]->next = s_next; 142 | n = hdr_next(*h); 143 | assert(n >= 0 && n < 64); 144 | AZ(hdrt->next[n]); 145 | hdrt->next[n] = HDR_InsertIdx(hdrt->next[n], ++h, idx); 146 | CHECK_OBJ_NOTNULL(hdrt->next[n], HDRT_NODE_MAGIC); 147 | hdrt->idx = -1; 148 | } 149 | 150 | return hdrt; 151 | } 152 | 153 | int 154 | HDR_N(struct hdrt_node *hdrt) 155 | { 156 | int n = 0; 157 | 158 | if (hdrt == NULL) 159 | return 0; 160 | CHECK_OBJ(hdrt, HDRT_NODE_MAGIC); 161 | if (hdrt->idx >= 0) 162 | n++; 163 | for (int i = 0; i < 64; i++) 164 | if (hdrt->next[i] != NULL) 165 | n += HDR_N(hdrt->next[i]); 166 | return n; 167 | } 168 | 169 | static struct vsb * 170 | vsb_dup(struct vsb *vsb) 171 | { 172 | struct vsb *dup = VSB_new_auto(); 173 | char *str; 174 | 175 | VSB_finish(vsb); 176 | str = strdup(VSB_data(vsb)); 177 | VSB_cat(dup, str); 178 | VSB_clear(vsb); 179 | VSB_cat(vsb, str); 180 | free(str); 181 | return dup; 182 | } 183 | 184 | static void 185 | hdr_traverse(struct hdrt_node *hdrt, struct vsb *sb, struct vsb *prefix) 186 | { 187 | struct vsb *current; 188 | 189 | if (hdrt == NULL) 190 | return; 191 | CHECK_OBJ(hdrt, HDRT_NODE_MAGIC); 192 | AN(hdrt->str); 193 | current = vsb_dup(prefix); 194 | VSB_cat(current, hdrt->str); 195 | if (hdrt->idx >= 0) { 196 | struct vsb *word = vsb_dup(current); 197 | VSB_finish(word); 198 | VSB_cat(sb, VSB_data(word)); 199 | VSB_cat(sb, ","); 200 | VSB_destroy(&word); 201 | } 202 | for (int i = 0; i < 64; i++) 203 | if (hdrt->next[i] != NULL) { 204 | struct vsb *next = vsb_dup(current); 205 | char c = i + 32; 206 | if (i + 32 == ':') 207 | c = '~'; 208 | VSB_putc(next, toupper(c)); 209 | hdr_traverse(hdrt->next[i], sb, next); 210 | } 211 | VSB_destroy(¤t); 212 | } 213 | 214 | void 215 | HDR_List(struct hdrt_node *hdrt, struct vsb *sb) 216 | { 217 | struct vsb *p = VSB_new_auto(); 218 | hdr_traverse(hdrt, sb, p); 219 | } 220 | 221 | void 222 | HDR_Fini(struct hdrt_node *hdrt) 223 | { 224 | if (hdrt == NULL) 225 | return; 226 | 227 | free(hdrt->str); 228 | for (int i = 0; i < 64; i++) 229 | HDR_Fini(hdrt->next[i]); 230 | free(hdrt->next); 231 | FREE_OBJ(hdrt); 232 | } 233 | -------------------------------------------------------------------------------- /src/vtim.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2006 Verdens Gang AS 3 | * Copyright (c) 2006-2011 Varnish Software AS 4 | * All rights reserved. 5 | * 6 | * Author: Poul-Henning Kamp 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | * Semi-trivial functions to handle HTTP header timestamps according to 30 | * RFC 2616 section 3.3. 31 | * 32 | * In the highly unlikely event of performance trouble, handbuilt versions 33 | * would likely be faster than relying on the OS time functions. 34 | * 35 | * We must parse three different formats: 36 | * 000000000011111111112222222222 37 | * 012345678901234567890123456789 38 | * ------------------------------ 39 | * "Sun, 06 Nov 1994 08:49:37 GMT" RFC822 & RFC1123 40 | * "Sunday, 06-Nov-94 08:49:37 GMT" RFC850 41 | * "Sun Nov 6 08:49:37 1994" ANSI-C asctime() 42 | * 43 | * And always output the RFC1123 format. 44 | * 45 | */ 46 | 47 | #include "config.h" 48 | 49 | #include 50 | 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | 59 | #include "vas.h" 60 | #include "vtim.h" 61 | 62 | /* 63 | * Note on Solaris: for some reason, clock_gettime(CLOCK_MONOTONIC, &ts) is not 64 | * implemented in assembly, but falls into a syscall, while gethrtime() doesn't, 65 | * so we save a syscall by using gethrtime() if it is defined. 66 | */ 67 | 68 | double 69 | VTIM_mono(void) 70 | { 71 | #ifdef HAVE_GETHRTIME 72 | return (gethrtime() * 1e-9); 73 | #elif HAVE_CLOCK_GETTIME 74 | struct timespec ts; 75 | 76 | AZ(clock_gettime(CLOCK_MONOTONIC, &ts)); 77 | return (ts.tv_sec + 1e-9 * ts.tv_nsec); 78 | #else 79 | struct timeval tv; 80 | 81 | AZ(gettimeofday(&tv, NULL)); 82 | return (tv.tv_sec + 1e-6 * tv.tv_usec); 83 | #endif 84 | } 85 | 86 | double 87 | VTIM_real(void) 88 | { 89 | #ifdef HAVE_CLOCK_GETTIME 90 | struct timespec ts; 91 | 92 | AZ(clock_gettime(CLOCK_REALTIME, &ts)); 93 | return (ts.tv_sec + 1e-9 * ts.tv_nsec); 94 | #else 95 | struct timeval tv; 96 | 97 | AZ(gettimeofday(&tv, NULL)); 98 | return (tv.tv_sec + 1e-6 * tv.tv_usec); 99 | #endif 100 | } 101 | 102 | void 103 | VTIM_format(double t, char *p) 104 | { 105 | struct tm tm; 106 | time_t tt; 107 | 108 | tt = (time_t) t; 109 | (void)gmtime_r(&tt, &tm); 110 | AN(strftime(p, VTIM_FORMAT_SIZE, "%a, %d %b %Y %T GMT", &tm)); 111 | } 112 | 113 | /* XXX: add statistics ? */ 114 | static const char *fmts[] = { 115 | "%a, %d %b %Y %T GMT", /* RFC 822 & RFC 1123 */ 116 | "%A, %d-%b-%y %T GMT", /* RFC 850 */ 117 | "%a %b %d %T %Y", /* ANSI-C asctime() */ 118 | "%F %T", /* ISO 8601 (incorrect, only in 4.0) */ 119 | "%FT%T", /* ISO 8601 */ 120 | NULL 121 | }; 122 | 123 | double 124 | VTIM_parse(const char *p) 125 | { 126 | double t; 127 | struct tm tm; 128 | const char **r; 129 | 130 | for (r = fmts; *r != NULL; r++) { 131 | memset(&tm, 0, sizeof tm); 132 | if (strptime(p, *r, &tm) != NULL) { 133 | /* 134 | * Make sure this is initialized on the off-chance 135 | * that some raving loonie would apply DST to UTC. 136 | */ 137 | tm.tm_isdst = -1; 138 | #if defined(HAVE_TIMEGM) 139 | t = timegm(&tm); 140 | #else 141 | /* 142 | * Ahh, another POSIX_STUPIDITY, how unexpected. 143 | * Instead of, as would have been logical, to have 144 | * tm_timezone element, mktime() is standardized as 145 | * always working in localtime. This brilliant idea 146 | * came from the same people who said "leap-seconds ? 147 | * Naah, screw it!". 148 | * 149 | * On broken systems without a working timegm(), 150 | * it is the responsibility of the calling program 151 | * to set the timezone to UTC. We check that. 152 | */ 153 | t = mktime(&tm); 154 | AZ(strcmp(tzname[0], "UTC")); 155 | #endif 156 | return (t); 157 | } 158 | } 159 | return (0); 160 | } 161 | 162 | void 163 | VTIM_sleep(double t) 164 | { 165 | #ifdef HAVE_NANOSLEEP 166 | struct timespec ts; 167 | 168 | ts = VTIM_timespec(t); 169 | 170 | (void)nanosleep(&ts, NULL); 171 | #else 172 | if (t >= 1.) { 173 | (void)sleep(floor(t)); 174 | t -= floor(t); 175 | } 176 | /* XXX: usleep() is not mandated to be thread safe */ 177 | t *= 1e6; 178 | if (t > 0) 179 | (void)usleep(floor(t)); 180 | #endif 181 | } 182 | 183 | struct timeval 184 | VTIM_timeval(double t) 185 | { 186 | struct timeval tv; 187 | 188 | tv.tv_sec = (time_t)trunc(t); 189 | tv.tv_usec = (int)(1e6 * (t - tv.tv_sec)); 190 | return (tv); 191 | } 192 | 193 | struct timespec 194 | VTIM_timespec(double t) 195 | { 196 | struct timespec tv; 197 | 198 | tv.tv_sec = (time_t)trunc(t); 199 | tv.tv_nsec = (int)(1e9 * (t - tv.tv_sec)); 200 | return (tv); 201 | } 202 | 203 | 204 | #ifdef TEST_DRIVER 205 | 206 | /* 207 | * Compile with: 208 | * cc -o foo -DTEST_DRIVER -I../.. -I../../include time.c assert.c 209 | * (Solaris) 210 | * cc -o foo -DTEST_DRIVER -I../.. -I../../include -lm time.c assert.c 211 | * Test with: 212 | * env TZ=UTC ./foo 213 | * env TZ=CET ./foo 214 | */ 215 | 216 | static void 217 | tst(const char *s, time_t good) 218 | { 219 | time_t t; 220 | char buf[BUFSIZ]; 221 | 222 | t = VTIM_parse(s); 223 | VTIM_format(t, buf); 224 | printf("%-30s -> %12jd -> %s\n", s, (intmax_t)t, buf); 225 | if (t != good) { 226 | printf("Parse error! Got: %jd should have %jd diff %jd\n", 227 | (intmax_t)t, (intmax_t)good, (intmax_t)(t - good)); 228 | exit(4); 229 | } 230 | } 231 | 232 | static int 233 | tst_delta_check(const char *name, double begin, double end, double ref) 234 | { 235 | const double tol_max = 1.1; 236 | const double tol_min = 1; 237 | 238 | printf("%s delta for %fs sleep: %f\n", name, ref, (end - begin)); 239 | 240 | if ((end - begin) > tol_max * ref) { 241 | printf("%s delta above tolerance: ((%f - %f) = %f) > %f\n", 242 | name, end, begin, (end - begin), tol_max); 243 | return (1); 244 | } else if ((end - begin) < tol_min * ref) { 245 | printf("%s delta below tolerance: ((%f - %f) = %f) < %f\n", 246 | name, end, begin, (end - begin), tol_min); 247 | return (1); 248 | } 249 | return (0); 250 | } 251 | 252 | static void 253 | tst_delta() 254 | { 255 | double m_begin, m_end; 256 | double r_begin, r_end; 257 | const double ref = 1; 258 | int err = 0; 259 | 260 | r_begin = VTIM_real(); 261 | m_begin = VTIM_mono(); 262 | VTIM_sleep(ref); 263 | r_end = VTIM_real(); 264 | m_end = VTIM_mono(); 265 | 266 | err += tst_delta_check("VTIM_mono", m_begin, m_end, ref); 267 | err += tst_delta_check("VTIM_real", r_begin, r_end, ref); 268 | 269 | if (err) { 270 | printf("%d time delta test errrors\n", err); 271 | exit(4); 272 | } 273 | } 274 | 275 | int 276 | main(int argc, char **argv) 277 | { 278 | time_t t; 279 | char buf[BUFSIZ]; 280 | 281 | time(&t); 282 | memset(buf, 0x55, sizeof buf); 283 | VTIM_format(t, buf); 284 | printf("scan = %d <%s>\n", VTIM_parse(buf), buf); 285 | 286 | /* Examples from RFC2616 section 3.3.1 */ 287 | tst("Sun, 06 Nov 1994 08:49:37 GMT", 784111777); 288 | tst("Sunday, 06-Nov-94 08:49:37 GMT", 784111777); 289 | tst("Sun Nov 6 08:49:37 1994", 784111777); 290 | 291 | tst_delta(); 292 | 293 | return (0); 294 | } 295 | #endif 296 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ(2.59) 2 | AC_COPYRIGHT([Copyright (c) 2015 UPLEX Nils Goroll Systemoptimierung 3 | Copyright (c) 2015 Otto Gmbh & Co KG]) 4 | AC_INIT([varnishevent], [trunk]) 5 | AC_CONFIG_MACRO_DIR([m4]) 6 | AC_CONFIG_SRCDIR(src/varnishevent.h) 7 | AM_CONFIG_HEADER(config.h) 8 | 9 | AC_CANONICAL_SYSTEM 10 | AC_LANG(C) 11 | 12 | AM_INIT_AUTOMAKE([foreign]) 13 | 14 | # Checks for programs. 15 | AC_GNU_SOURCE 16 | AC_PROG_CC 17 | AC_PROG_CC_STDC 18 | if test "x$ac_cv_prog_cc_c99" = xno; then 19 | AC_MSG_ERROR([Could not find a C99 compatible compiler]) 20 | fi 21 | AC_PROG_CPP 22 | 23 | AX_PTHREAD(,[AC_MSG_ERROR([Could not configure pthreads support])]) 24 | 25 | LIBS="$PTHREAD_LIBS $LIBS" 26 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 27 | CC="$PTHREAD_CC" 28 | 29 | AC_PROG_INSTALL 30 | AC_PROG_LIBTOOL 31 | AC_PROG_MAKE_SET 32 | AC_ARG_WITH([rst2man], 33 | AS_HELP_STRING([--with-rst2man=PATH], 34 | [Location of rst2man (auto)]), 35 | [RST2MAN="$withval"], 36 | [AC_CHECK_PROGS(RST2MAN, [rst2man rst2man.py], "no") 37 | if test "x$RST2MAN" = "xno"; then 38 | AC_MSG_WARN([rst2man not found – not building man pages]) 39 | fi]) 40 | AM_CONDITIONAL(HAVE_RST2MAN,[test "x$RST2MAN" != "xno"]) 41 | 42 | AC_ARG_WITH([rst2html], 43 | AS_HELP_STRING([--with-rst2html=PATH], 44 | [Location of rst2html (auto)]), 45 | [RST2HTML="$withval"], 46 | [AC_CHECK_PROGS(RST2HTML, [rst2html rst2html.py], "no") 47 | if test "x$RST2HTML" = "xno"; then 48 | AC_MSG_WARN([rst2html not found – not building changelog]) 49 | fi]) 50 | AM_CONDITIONAL(HAVE_RST2HTML,[test "x$RST2HTML" != "xno"]) 51 | 52 | # Check for pkg-config 53 | m4_ifndef([PKG_PROG_PKG_CONFIG], [m4_fatal([pkg.m4 missing, please install pkg-config])]) 54 | PKG_PROG_PKG_CONFIG 55 | 56 | PKG_CHECK_MODULES([VARNISH], [varnishapi = trunk], [], 57 | [AC_MSG_ERROR([Varnish trunk is required])]) 58 | AC_SUBST(VARNISH_CFLAGS) 59 | AC_SUBST(VARNISH_LIBS) 60 | PKG_CHECK_VAR([VARNISH_PKG_INCLUDE], [varnishapi], [pkgincludedir]) 61 | AC_SUBST(VARNISH_SHARE_INCLUDE, "${VARNISH_PKG_INCLUDE}/include") 62 | PKG_CHECK_VAR(VARNISH_PKG_LIB, [varnishapi], [libdir]) 63 | AC_SUBST(VARNISH_LIBVARNISH_LIB, "-L${VARNISH_PKG_LIB}/varnish") 64 | PKG_CHECK_VAR(VARNISH_DATAROOTDIR, [varnishapi], [datarootdir]) 65 | PKG_CHECK_VAR([LIBVARNISHAPI_BINDIR], [varnishapi], [bindir]) 66 | AC_SUBST([LIBVARNISHAPI_BINDIR]) 67 | 68 | # Checks for header files. 69 | AC_HEADER_STDC 70 | AC_CHECK_HEADERS([sys/stdlib.h]) 71 | 72 | # Checks for libraries. 73 | save_LIBS="${LIBS}" 74 | LIBS="" 75 | AC_CHECK_LIB(rt, clock_gettime) 76 | RT_LIBS="${LIBS}" 77 | LIBS="${save_LIBS}" 78 | AC_SUBST(RT_LIBS) 79 | 80 | save_LIBS="${LIBS}" 81 | LIBS="" 82 | AC_SEARCH_LIBS(pthread_create, [thr pthread c_r]) 83 | PTHREAD_LIBS="${LIBS}" 84 | LIBS="${save_LIBS}" 85 | AC_SUBST(PTHREAD_LIBS) 86 | 87 | AC_CHECK_LIBM 88 | AC_SUBST(LIBM) 89 | 90 | # Checks for header files. 91 | AC_HEADER_STDC 92 | AC_HEADER_TIME 93 | AC_CHECK_HEADERS([sys/param.h]) 94 | AC_CHECK_HEADERS([sys/types.h]) 95 | AC_CHECK_HEADERS([execinfo.h]) 96 | AC_CHECK_HEADERS([pthread_np.h]) 97 | AC_CHECK_HEADERS([stddef.h]) 98 | AC_CHECK_HEADERS([stdlib.h]) 99 | AC_CHECK_HEADERS([unistd.h]) 100 | AC_CHECK_HEADERS([fcntl.h]) 101 | AC_CHECK_HEADERS([limits.h]) 102 | AC_CHECK_HEADERS([sys/file.h]) 103 | AC_CHECK_HEADERS([sys/time.h]) 104 | AC_CHECK_HEADERS([syslog.h]) 105 | 106 | # Checks for typedefs, structures, and compiler characteristics. 107 | AC_C_CONST 108 | AC_C_INLINE 109 | AC_C_RESTRICT 110 | 111 | # Checks for library functions. 112 | AC_TYPE_SIGNAL 113 | AC_TYPE_SIZE_T 114 | AC_TYPE_INT32_T 115 | AC_TYPE_MODE_T 116 | AC_TYPE_PID_T 117 | AC_TYPE_SSIZE_T 118 | AC_FUNC_VPRINTF 119 | AC_CHECK_FUNCS([strerror]) 120 | AC_FUNC_STRERROR_R 121 | AC_FUNC_ERROR_AT_LINE 122 | AC_FUNC_MALLOC 123 | AC_FUNC_MKTIME 124 | AC_FUNC_REALLOC 125 | AC_FUNC_STRTOD 126 | AC_CHECK_FUNCS([strptime]) 127 | AC_CHECK_FUNCS([timegm]) 128 | AC_CHECK_FUNCS([nanosleep]) 129 | AC_CHECK_FUNCS([getline]) 130 | AC_CHECK_FUNCS([pthread_setname_np]) 131 | AC_CHECK_FUNCS([atexit]) 132 | AC_CHECK_FUNCS([floor]) 133 | AC_CHECK_FUNCS([ftruncate]) 134 | AC_CHECK_FUNCS([gettimeofday]) 135 | AC_CHECK_FUNCS([isascii]) 136 | AC_CHECK_FUNCS([localtime_r]) 137 | AC_CHECK_FUNCS([memchr]) 138 | AC_CHECK_FUNCS([memset]) 139 | AC_CHECK_FUNCS([strcasecmp]) 140 | AC_CHECK_FUNCS([strchr]) 141 | AC_CHECK_FUNCS([strdup]) 142 | AC_CHECK_FUNCS([strncasecmp]) 143 | AC_CHECK_FUNCS([strndup]) 144 | AC_CHECK_FUNCS([strstr]) 145 | AC_CHECK_FUNCS([strtol]) 146 | AC_CHECK_FUNCS([strtoul]) 147 | 148 | save_LIBS="${LIBS}" 149 | LIBS="${PTHREAD_LIBS}" 150 | AC_CHECK_FUNCS([pthread_set_name_np]) 151 | LIBS="${save_LIBS}" 152 | 153 | # Use jemalloc on Linux 154 | JEMALLOC_SUBDIR= 155 | JEMALLOC_LDADD= 156 | AC_ARG_WITH([jemalloc], 157 | [AS_HELP_STRING([--with-jemalloc], 158 | [use jemalloc memory allocator. Default is yes on Linux, no elsewhere])], 159 | [], 160 | [with_jemalloc=check]) 161 | 162 | case $target in 163 | *-*-linux*) 164 | if test "x$with_jemalloc" != xno; then 165 | AC_CHECK_LIB([jemalloc], [malloc_conf], 166 | [JEMALLOC_LDADD="-ljemalloc"], 167 | [AC_MSG_NOTICE([No system jemalloc found, using bundled version]) 168 | JEMALLOC_SUBDIR=libjemalloc 169 | JEMALLOC_LDADD='$(top_builddir)/lib/libjemalloc/libjemalloc_mt.la']) 170 | fi 171 | ;; 172 | esac 173 | AC_SUBST(JEMALLOC_SUBDIR) 174 | AC_SUBST(JEMALLOC_LDADD) 175 | 176 | AC_CHECK_FUNCS([backtrace]) 177 | # white lie - we don't actually test it 178 | AC_MSG_CHECKING([whether daemon() works]) 179 | case $target in 180 | *-*-darwin*) 181 | # present but not functional 182 | AC_MSG_RESULT([no]) 183 | ac_cv_func_daemon=no 184 | ;; 185 | *) 186 | AC_CHECK_FUNCS([daemon]) 187 | ;; 188 | esac 189 | 190 | AC_SYS_LARGEFILE 191 | 192 | save_LIBS="${LIBS}" 193 | LIBS="${LIBS} ${RT_LIBS}" 194 | AC_CHECK_FUNCS([clock_gettime]) 195 | AC_CHECK_FUNCS([gethrtime]) 196 | LIBS="${save_LIBS}" 197 | 198 | AC_CHECK_PROGS(PYTHON, [python3 python3.1 python3.2 python2.7 python2.6 python2.5 python2 python], "no") 199 | if test "x$PYTHON" = "xno"; then 200 | AC_MSG_ERROR([Python is needed to build Varnish, please install python.]) 201 | fi 202 | 203 | # Now that we're done using the compiler to look for functions and 204 | # libraries, set CFLAGS to what we want them to be for our own code 205 | 206 | # This corresponds to FreeBSD's WARNS level 6 207 | DEVELOPER_CFLAGS="-Wall -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch -Wshadow -Wcast-align -Wunused-parameter -Wchar-subscripts -Wnested-externs -Wredundant-decls -Wformat" 208 | 209 | # Additional flags for GCC 4 210 | EXTRA_DEVELOPER_CFLAGS="-Wextra -Wno-missing-field-initializers -Wno-sign-compare" 211 | 212 | # --enable-developer-warnings 213 | AC_ARG_ENABLE(developer-warnings, 214 | AS_HELP_STRING([--enable-developer-warnings],[enable strict warnings (default is NO)]), 215 | CFLAGS="${CFLAGS} ${DEVELOPER_CFLAGS}") 216 | 217 | # --enable-debugging-symbols 218 | AC_ARG_ENABLE(debugging-symbols, 219 | AS_HELP_STRING([--enable-debugging-symbols],[enable debugging symbols (default is NO)]), 220 | CFLAGS="${CFLAGS} -g") 221 | 222 | # --enable-debugging 223 | AC_ARG_ENABLE(debugging, 224 | AS_HELP_STRING([--enable-debugging],[enable debugging (default is NO)]), 225 | [], 226 | [enable_debugging=no]) 227 | 228 | # AC_PROG_CC sets CFLAGS to '-g -O2' unless it is already set, so 229 | # there's no need to add -g. Disable or change by explicitly setting 230 | # CFLAGS. If this option is enabled, then -Og or -O0 becomes the last 231 | # optimization option, and hence takes precedence. 232 | if test "x$enable_debugging" != "xno"; then 233 | CFLAGS="${CFLAGS} -fno-inline" 234 | CFLAGS=`echo ${CFLAGS} | sed -e 's/-Winline//'` 235 | AX_CHECK_COMPILE_FLAG([-Og], 236 | [CFLAGS="${CFLAGS} -Og"], 237 | [CFLAGS="${CFLAGS} -O0"], 238 | []) 239 | fi 240 | 241 | # --enable-extra-developer-warnings 242 | AC_ARG_ENABLE(extra-developer-warnings, 243 | AS_HELP_STRING([--enable-extra-developer-warnings],[enable even stricter warnings (default is NO)]), 244 | CFLAGS="${CFLAGS} ${EXTRA_DEVELOPER_CFLAGS}") 245 | 246 | # --enable-stack-protector 247 | AC_ARG_ENABLE(stack-protector, 248 | AS_HELP_STRING([--enable-stack-protector],[enable stack protector (default is NO)]), 249 | [], 250 | [enable_stack_protector=no]) 251 | 252 | if test "x$enable_stack_protector" != "xno"; then 253 | save_CFLAGS="$CFLAGS" 254 | CFLAGS="${CFLAGS} -fstack-protector-all" 255 | AC_COMPILE_IFELSE( 256 | [AC_LANG_PROGRAM([],[],[])], 257 | [], 258 | [AC_MSG_WARN([-fstack-protector not supported, disabling]) 259 | CFLAGS="$save_CFLAGS"]) 260 | fi 261 | 262 | # --enable-werror 263 | AC_ARG_ENABLE(werror, 264 | AS_HELP_STRING([--enable-werror],[use -Werror (default is NO)]), 265 | CFLAGS="${CFLAGS} -Werror") 266 | 267 | # Generate output 268 | AC_CONFIG_FILES([ 269 | Makefile 270 | src/Makefile 271 | src/test/Makefile 272 | ]) 273 | AC_OUTPUT 274 | -------------------------------------------------------------------------------- /src/varnishevent.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2013-2015 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2013-2015 Otto Gmbh & Co KG 4 | * All rights reserved. 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #ifndef VARNISHEVENT_H_INCLUDED 33 | #define VARNISHEVENT_H_INCLUDED 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #include "hdrtrie.h" 46 | 47 | #include "vapi/vsl.h" 48 | #include "vqueue.h" 49 | #include "vsb.h" 50 | #include "vas.h" 51 | #include "vbm.h" 52 | 53 | #define C(txtype) ((txtype) == VSL_t_req) 54 | #define B(txtype) ((txtype) == VSL_t_bereq) 55 | #define R(txtype) ((txtype) == VSL_t_raw) 56 | 57 | #define EMPTY(s) (s[0] == '\0') 58 | #define VSB_EMPTY(vsb) (VSB_len((vsb)) == 0) 59 | 60 | #define DEFAULT_MAX_RECLEN 255 /* default vsl_reclen in Varnish 4.0.3 */ 61 | 62 | #define DEFAULT_CHUNK_SIZE 64 63 | #define DEFAULT_MAX_DATA 4096 64 | 65 | #define MAX_VSL_TAG SLT__MAX 66 | 67 | #define DEFAULT_CFORMAT \ 68 | "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\"" 69 | 70 | #ifdef HAVE_PTHREAD_SETNAME_NP 71 | #define thread_setname(thr,name) pthread_setname_np((thr),(name)) 72 | #elif defined(HAVE_PTHREAD_SET_NAME_NP) 73 | #define thread_setname(thr,name) pthread_set_name_np((thr),(name)) 74 | #else 75 | #define thread_setname(thr,name) do { (void)(thr); (void)(name); } while(0) 76 | #endif 77 | 78 | struct sigaction default_action; 79 | 80 | int tag2idx[MAX_VSL_TAG]; 81 | int max_idx; 82 | 83 | typedef struct chunk_t { 84 | unsigned magic; 85 | #define CHUNK_MAGIC 0x676e0d19 86 | unsigned occupied; 87 | char *data; 88 | VSTAILQ_ENTRY(chunk_t) freelist; 89 | VSTAILQ_ENTRY(chunk_t) chunklist; 90 | } chunk_t; 91 | 92 | typedef VSTAILQ_HEAD(chunkhead_s, chunk_t) chunkhead_t; 93 | 94 | chunk_t *chunks; 95 | unsigned nchunks; 96 | 97 | typedef struct rec_t { 98 | unsigned magic; 99 | #define RECORD_MAGIC 0xf427a374 100 | unsigned len; 101 | unsigned occupied; 102 | enum VSL_tag_e tag; 103 | chunkhead_t chunks; 104 | VSTAILQ_ENTRY(rec_t) freelist; 105 | } rec_t; 106 | 107 | rec_t *records; 108 | unsigned nrecords; 109 | 110 | typedef VSTAILQ_HEAD(rechead_s, rec_t) rechead_t; 111 | 112 | typedef struct rec_node_t { 113 | unsigned magic; 114 | #define REC_NODE_MAGIC 0x92d4933d 115 | rec_t *rec; 116 | rec_t **hdrs; 117 | } rec_node_t; 118 | 119 | rec_node_t *rec_nodes; 120 | 121 | enum tx_state_e { 122 | TX_FREE, 123 | TX_OPEN, 124 | TX_DONE, 125 | TX_SUBMITTED, 126 | TX_FORMATTING, 127 | TX_WRITTEN 128 | }; 129 | 130 | enum tx_disp_e { 131 | DISP_NONE = 0, 132 | DISP_HIT, 133 | DISP_MISS, 134 | DISP_PASS, 135 | DISP_PIPE, 136 | DISP_ERROR 137 | }; 138 | 139 | typedef struct tx_t { 140 | unsigned magic; 141 | #define TX_MAGIC 0xff463e42 142 | int32_t vxid; 143 | int32_t pvxid; 144 | enum VSL_transaction_e type; 145 | enum tx_state_e state; 146 | enum tx_disp_e disp; 147 | double t; 148 | rec_node_t **recs; 149 | VSTAILQ_ENTRY(tx_t) freelist; 150 | VSTAILQ_ENTRY(tx_t) spscq; 151 | } tx_t; 152 | 153 | tx_t *txn; 154 | 155 | typedef VSTAILQ_HEAD(txhead_s, tx_t) txhead_t; 156 | 157 | #define OCCUPIED(p) ((p)->occupied == 1) 158 | 159 | unsigned tx_occ, rec_occ, chunk_occ, tx_occ_hi, rec_occ_hi, chunk_occ_hi, 160 | global_nfree_tx, global_nfree_rec, global_nfree_chunk; 161 | 162 | struct hdrt_node *hdr_trie[MAX_VSL_TAG]; 163 | 164 | /* non-zero if vxid or pvxid outputs are requested for a transaction type */ 165 | int nonrecs_wanted[VSL_t__MAX]; 166 | 167 | struct vbitmap *tag_no_hdr[VSL_t__MAX]; 168 | 169 | /* Writer (consumer) waits for this condition when the SPSC queue is empty. 170 | Reader (producer) signals the condition after enqueue. */ 171 | pthread_cond_t spscq_ready_cond; 172 | pthread_mutex_t spscq_ready_lock; 173 | 174 | /* Reader waits for this condition if any of the freelists are exhausted. 175 | Writer signals the condition when it returns freelists. */ 176 | pthread_cond_t data_ready_cond; 177 | pthread_mutex_t data_ready_lock; 178 | 179 | struct config { 180 | char log_file[PATH_MAX + 1]; 181 | 182 | char output_file[PATH_MAX + 1]; 183 | unsigned append; 184 | double output_timeout; 185 | double reader_timeout; 186 | 187 | /* VSL 'r' argument */ 188 | char varnish_bindump[PATH_MAX + 1]; 189 | 190 | /* rformat is for raw transactions */ 191 | struct vsb *cformat; 192 | struct vsb *bformat; 193 | struct vsb *rformat; 194 | 195 | int syslog_facility; 196 | char syslog_facility_name[sizeof("LOCAL0")]; 197 | struct vsb *syslog_ident; 198 | unsigned monitor_interval; 199 | 200 | /* varnishd param vsl_reclen */ 201 | unsigned max_reclen; 202 | 203 | unsigned chunk_size; 204 | unsigned max_data; 205 | 206 | size_t output_bufsiz; 207 | } config; 208 | 209 | /* varnishevent.c */ 210 | void RDR_Stats(void); 211 | int RDR_Depleted(void); 212 | int RDR_Waiting(void); 213 | 214 | /* config.c */ 215 | void CONF_Init(void); 216 | int CONF_Add(const char *lval, const char *rval); 217 | int CONF_ReadFile(const char *file); 218 | void CONF_Dump(void); 219 | 220 | /* log.c */ 221 | 222 | typedef void log_log_t(int level, const char *msg, ...); 223 | typedef void log_setlevel_t(int level); 224 | typedef void log_close_t(void); 225 | 226 | struct logconf { 227 | log_log_t *log; 228 | log_setlevel_t *setlevel; 229 | log_close_t *close; 230 | FILE *out; 231 | int level; 232 | } logconf; 233 | 234 | int LOG_Open(const char *progname); 235 | /* XXX: __VA_ARGS__ can't be empty ... */ 236 | #define LOG_Log0(level, msg) logconf.log(level, msg) 237 | #define LOG_Log(level, msg, ...) logconf.log(level, msg, __VA_ARGS__) 238 | #define LOG_SetLevel(level) logconf.setlevel(level) 239 | #define LOG_Close() logconf.close() 240 | 241 | /* data.c */ 242 | int DATA_Init(void); 243 | void DATA_Clear_Tx(tx_t * const tx, txhead_t * const freetx, 244 | rechead_t * const freerec, chunkhead_t * const freechunk, 245 | unsigned * restrict const nfree_tx, 246 | unsigned * restrict const nfree_rec, 247 | unsigned * restrict const nfree_chunk); 248 | unsigned DATA_Take_Freetx(struct txhead_s *dst); 249 | unsigned DATA_Take_Freerec(struct rechead_s *dst); 250 | unsigned DATA_Take_Freechunk(struct chunkhead_s *dst); 251 | void DATA_Return_Freetx(struct txhead_s *returned, unsigned nreturned); 252 | void DATA_Return_Freerec(struct rechead_s *returned, unsigned nreturned); 253 | void DATA_Return_Freechunk(struct chunkhead_s *returned, unsigned nreturned); 254 | void DATA_Dump(void); 255 | 256 | /* writer.c */ 257 | int WRT_Init(void); 258 | void WRT_Start(void); 259 | void WRT_Stats(void); 260 | int WRT_Running(void); 261 | int WRT_Waiting(void); 262 | void WRT_Reopen(void); 263 | void WRT_Halt(void); 264 | void WRT_Fini(void); 265 | 266 | /* spscq.c */ 267 | void SPSCQ_Enq(tx_t *ptr); 268 | tx_t *SPSCQ_Deq(void); 269 | unsigned SPSCQ_Len(void); 270 | void SPSCQ_Stats(void); 271 | void SPSCQ_Shutdown(void); 272 | 273 | /* monitor.c */ 274 | typedef enum { 275 | /* Transaction read */ 276 | STATS_DONE, 277 | /* Transaction written */ 278 | STATS_WRITTEN, 279 | } stats_update_t; 280 | 281 | void MON_Start(void); 282 | void MON_Shutdown(void); 283 | void MON_StatsUpdate(stats_update_t update, unsigned nrec, unsigned nchunk); 284 | void MON_Output(void); 285 | 286 | /* format.c */ 287 | int FMT_Init(char *err); 288 | int FMT_GetMaxIdx(void); 289 | int FMT_Estimate_RecsPerTx(void); 290 | char *FMT_Format(tx_t *tx, size_t *len); 291 | void FMT_Fini(void); 292 | 293 | /* handler.c */ 294 | void HNDL_Init(const char *a0); 295 | void HNDL_Abort(int sig); 296 | 297 | #endif 298 | -------------------------------------------------------------------------------- /src/config.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2013 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2013 Otto Gmbh & Co KG 4 | * All rights reserved 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "config.h" 44 | 45 | #include "varnishevent.h" 46 | 47 | #include "vas.h" 48 | #include "vdef.h" 49 | 50 | static const int facilitynum[8] = 51 | { LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5, 52 | LOG_LOCAL6, LOG_LOCAL7 }; 53 | 54 | static int 55 | conf_getFacility(const char *facility) { 56 | int localnum; 57 | 58 | if (strcasecmp(facility, "USER") == 0) 59 | return LOG_USER; 60 | if (strlen(facility) != 6 61 | || strncasecmp(facility, "LOCAL", 5) != 0 62 | || !isdigit(facility[5])) 63 | return(-1); 64 | localnum = atoi(&facility[5]); 65 | if (localnum > 7) 66 | return(-1); 67 | return(facilitynum[localnum]); 68 | } 69 | 70 | static int 71 | conf_getUnsignedInt(const char *rval, unsigned *i) 72 | { 73 | long n; 74 | char *p; 75 | 76 | errno = 0; 77 | n = strtoul(rval, &p, 10); 78 | if (errno) 79 | return(errno); 80 | if (strlen(p) != 0) 81 | return(EINVAL); 82 | if (n < 0 || n > UINT_MAX) 83 | return(ERANGE); 84 | *i = (unsigned int) n; 85 | return(0); 86 | } 87 | 88 | static int 89 | conf_getDouble(const char *rval, double *d) 90 | { 91 | char *p; 92 | errno = 0; 93 | double x = strtod(rval, &p); 94 | if (errno == ERANGE) 95 | return errno; 96 | if (p[0] != '\0' || x < 0 || isnan(x) || !finite(x)) 97 | return EINVAL; 98 | *d = x; 99 | return 0; 100 | } 101 | 102 | /* For char fields with fixed-size buffers */ 103 | #define confString(name,fld) \ 104 | if (strcmp(lval, (name)) == 0) { \ 105 | if (strlen(rval) > sizeof(config.fld)) \ 106 | return EINVAL; \ 107 | bprintf((config.fld), "%s", rval); \ 108 | return(0); \ 109 | } 110 | 111 | #define confVSB(name,fld) \ 112 | if (strcmp(lval, (name)) == 0) { \ 113 | VSB_clear(config.fld); \ 114 | VSB_cat(config.fld, rval); \ 115 | VSB_finish(config.fld); \ 116 | return(0); \ 117 | } 118 | 119 | /* XXX: need confNonNegative? */ 120 | 121 | #define confUnsigned(name,fld) \ 122 | if (strcmp(lval, name) == 0) { \ 123 | unsigned int i; \ 124 | int err = conf_getUnsignedInt(rval, &i); \ 125 | if (err != 0) \ 126 | return err; \ 127 | config.fld = i; \ 128 | return(0); \ 129 | } 130 | 131 | #define confDouble(name,fld) \ 132 | if (strcmp(lval, name) == 0) { \ 133 | double d; \ 134 | int err = conf_getDouble(rval, &d); \ 135 | if (err != 0) \ 136 | return err; \ 137 | config.fld = d; \ 138 | return(0); \ 139 | } 140 | 141 | int 142 | CONF_Add(const char *lval, const char *rval) 143 | { 144 | int ret; 145 | 146 | confString("log.file", log_file); 147 | confString("output.file", output_file); 148 | confString("varnish.bindump", varnish_bindump); 149 | 150 | confVSB("cformat", cformat); 151 | confVSB("bformat", bformat); 152 | confVSB("rformat", rformat); 153 | confVSB("syslog.ident", syslog_ident); 154 | 155 | confUnsigned("max.reclen", max_reclen); 156 | confUnsigned("chunk_size", chunk_size); 157 | confUnsigned("max.data", max_data); 158 | confUnsigned("monitor.interval", monitor_interval); 159 | confUnsigned("output.bufsiz", output_bufsiz); 160 | confUnsigned("append", append); 161 | 162 | confDouble("output.timeout", output_timeout); 163 | confDouble("reader.timeout", reader_timeout); 164 | 165 | if (strcmp(lval, "syslog.facility") == 0) { 166 | if ((ret = conf_getFacility(rval)) < 0) 167 | return EINVAL; 168 | config.syslog_facility = ret; 169 | bprintf(config.syslog_facility_name, "%s", rval); 170 | char *p = &config.syslog_facility_name[0]; 171 | do { *p = toupper(*p); } while (*++p); 172 | return(0); 173 | } 174 | 175 | return EINVAL; 176 | } 177 | 178 | static int 179 | conf_ParseLine(char *ptr, char **lval, char **rval) 180 | { 181 | char *endlval; 182 | 183 | *lval = ptr; 184 | while(*++ptr && !isspace(*ptr) && *ptr != '=') 185 | ; 186 | if (*ptr == '\0') 187 | return(1); 188 | endlval = ptr; 189 | while(isspace(*ptr) && *++ptr) 190 | ; 191 | if (ptr == '\0' || *ptr != '=') 192 | return(1); 193 | while(*++ptr && isspace(*ptr)) 194 | ; 195 | if (ptr == '\0') 196 | return(1); 197 | *endlval = '\0'; 198 | *rval = ptr; 199 | return(0); 200 | } 201 | 202 | void 203 | CONF_Init(void) 204 | { 205 | config.log_file[0] = '\0'; 206 | /* Default is stdout */ 207 | config.output_file[0] = '\0'; 208 | config.varnish_bindump[0] = '\0'; 209 | bprintf(config.syslog_facility_name, "%s", "LOCAL0"); 210 | 211 | config.cformat = VSB_new_auto(); 212 | VSB_cat(config.cformat, DEFAULT_CFORMAT); 213 | VSB_finish(config.cformat); 214 | config.bformat = VSB_new_auto(); 215 | VSB_finish(config.bformat); 216 | config.rformat = VSB_new_auto(); 217 | VSB_finish(config.rformat); 218 | config.syslog_ident = VSB_new_auto(); 219 | VSB_cat(config.syslog_ident, "varnishevent"); 220 | VSB_finish(config.syslog_ident); 221 | 222 | config.syslog_facility = LOG_LOCAL0; 223 | 224 | config.monitor_interval = 30; 225 | config.output_bufsiz = BUFSIZ; 226 | 227 | config.max_reclen = DEFAULT_MAX_RECLEN; 228 | config.max_data = DEFAULT_MAX_DATA; 229 | config.chunk_size = DEFAULT_CHUNK_SIZE; 230 | 231 | config.append = 0; 232 | config.output_timeout = 0.; 233 | config.reader_timeout = 0.; 234 | } 235 | 236 | static int 237 | conf_get_line(char *line, FILE *in) 238 | { 239 | #ifdef HAVE_GETLINE 240 | size_t n = BUFSIZ; 241 | errno = 0; 242 | return (getline(&line, &n, in)); 243 | #else 244 | if (fgets(line, BUFSIZ, in) == NULL) 245 | return -1; 246 | return 0; 247 | #endif 248 | } 249 | 250 | int 251 | CONF_ReadFile(const char *file) { 252 | FILE *in; 253 | char *line; 254 | int linenum = 0; 255 | struct vsb *orig; 256 | 257 | in = fopen(file, "r"); 258 | if (in == NULL) { 259 | perror(file); 260 | return(-1); 261 | } 262 | 263 | line = (char *) malloc(BUFSIZ); 264 | AN(line); 265 | orig = VSB_new_auto(); 266 | while (conf_get_line(line, in) != -1) { 267 | linenum++; 268 | char *comment = strchr(line, '#'); 269 | if (comment != NULL) 270 | *comment = '\0'; 271 | if (strlen(line) == 0) 272 | continue; 273 | 274 | char *ptr = line + strlen(line) - 1; 275 | while (ptr != line && isspace(*ptr)) 276 | --ptr; 277 | ptr[isspace(*ptr) ? 0 : 1] = '\0'; 278 | if (strlen(line) == 0) 279 | continue; 280 | 281 | ptr = line; 282 | while (isspace(*ptr) && *++ptr) 283 | ; 284 | 285 | VSB_clear(orig); 286 | VSB_cat(orig, ptr); 287 | VSB_finish(orig); 288 | 289 | char *lval, *rval; 290 | if (conf_ParseLine(ptr, &lval, &rval) != 0) { 291 | fprintf(stderr, "Cannot parse %s line %d: '%s'\n", file, linenum, 292 | VSB_data(orig)); 293 | return(-1); 294 | } 295 | 296 | int ret; 297 | if ((ret = CONF_Add((const char *) lval, (const char *) rval)) != 0) { 298 | fprintf(stderr, "Error in %s line %d (%s): '%s'\n", file, linenum, 299 | strerror(ret), VSB_data(orig)); 300 | return(-1); 301 | } 302 | } 303 | int ret = 0; 304 | if (ferror(in)) { 305 | fprintf(stderr, "Error reading file %s (errno %d: %s)\n", file, errno, 306 | strerror(errno)); 307 | ret = -1; 308 | } 309 | errno = 0; 310 | if (fclose(in) != 0) { 311 | fprintf(stderr, "Error closing file %s: %s)\n", file, strerror(errno)); 312 | ret = -1; 313 | } 314 | free(line); 315 | return(ret); 316 | } 317 | 318 | #define confdump(str,val) \ 319 | LOG_Log(LOG_INFO, "config: " str, (val)) 320 | 321 | void 322 | CONF_Dump(void) 323 | { 324 | confdump("log.file = %s", 325 | strcmp(config.log_file,"-") == 0 ? "stdout" : config.log_file); 326 | confdump("varnish.bindump = %s", config.varnish_bindump); 327 | confdump("output.file = %s", 328 | EMPTY(config.output_file) ? "stdout" : config.output_file); 329 | confdump("append = %u", config.append); 330 | confdump("output.timeout = %f", config.output_timeout); 331 | confdump("reader.timeout = %f", config.reader_timeout); 332 | confdump("cformat = %s", VSB_data(config.cformat)); 333 | confdump("bformat = %s", VSB_data(config.bformat)); 334 | confdump("rformat = %s", VSB_data(config.rformat)); 335 | confdump("syslog.facility = %s", config.syslog_facility_name); 336 | confdump("syslog.ident = %s", VSB_data(config.syslog_ident)); 337 | confdump("monitor.interval = %u", config.monitor_interval); 338 | confdump("max.reclen = %u", config.max_reclen); 339 | confdump("max.data = %u", config.max_data); 340 | confdump("chunk.size = %u", config.chunk_size); 341 | confdump("output.bufsiz = %u", config.output_bufsiz); 342 | } 343 | -------------------------------------------------------------------------------- /m4/ax_pthread.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_pthread.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # This macro figures out how to build C programs using POSIX threads. It 12 | # sets the PTHREAD_LIBS output variable to the threads library and linker 13 | # flags, and the PTHREAD_CFLAGS output variable to any special C compiler 14 | # flags that are needed. (The user can also force certain compiler 15 | # flags/libs to be tested by setting these environment variables.) 16 | # 17 | # Also sets PTHREAD_CC to any special C compiler that is needed for 18 | # multi-threaded programs (defaults to the value of CC otherwise). (This 19 | # is necessary on AIX to use the special cc_r compiler alias.) 20 | # 21 | # NOTE: You are assumed to not only compile your program with these flags, 22 | # but also link it with them as well. e.g. you should link with 23 | # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS 24 | # 25 | # If you are only building threads programs, you may wish to use these 26 | # variables in your default LIBS, CFLAGS, and CC: 27 | # 28 | # LIBS="$PTHREAD_LIBS $LIBS" 29 | # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 30 | # CC="$PTHREAD_CC" 31 | # 32 | # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant 33 | # has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name 34 | # (e.g. PTHREAD_CREATE_UNDETACHED on AIX). 35 | # 36 | # ACTION-IF-FOUND is a list of shell commands to run if a threads library 37 | # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it 38 | # is not found. If ACTION-IF-FOUND is not specified, the default action 39 | # will define HAVE_PTHREAD. 40 | # 41 | # Please let the authors know if this macro fails on any platform, or if 42 | # you have any other suggestions or comments. This macro was based on work 43 | # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help 44 | # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by 45 | # Alejandro Forero Cuervo to the autoconf macro repository. We are also 46 | # grateful for the helpful feedback of numerous users. 47 | # 48 | # LICENSE 49 | # 50 | # Copyright (c) 2008 Steven G. Johnson 51 | # 52 | # This program is free software: you can redistribute it and/or modify it 53 | # under the terms of the GNU General Public License as published by the 54 | # Free Software Foundation, either version 3 of the License, or (at your 55 | # option) any later version. 56 | # 57 | # This program is distributed in the hope that it will be useful, but 58 | # WITHOUT ANY WARRANTY; without even the implied warranty of 59 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 60 | # Public License for more details. 61 | # 62 | # You should have received a copy of the GNU General Public License along 63 | # with this program. If not, see . 64 | # 65 | # As a special exception, the respective Autoconf Macro's copyright owner 66 | # gives unlimited permission to copy, distribute and modify the configure 67 | # scripts that are the output of Autoconf when processing the Macro. You 68 | # need not follow the terms of the GNU General Public License when using 69 | # or distributing such scripts, even though portions of the text of the 70 | # Macro appear in them. The GNU General Public License (GPL) does govern 71 | # all other use of the material that constitutes the Autoconf Macro. 72 | # 73 | # This special exception to the GPL applies to versions of the Autoconf 74 | # Macro released by the Autoconf Archive. When you make and distribute a 75 | # modified version of the Autoconf Macro, you may extend this special 76 | # exception to the GPL to apply to your modified version as well. 77 | 78 | #serial 7 79 | 80 | AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) 81 | AC_DEFUN([AX_PTHREAD], [ 82 | AC_REQUIRE([AC_CANONICAL_HOST]) 83 | AC_LANG_SAVE 84 | AC_LANG_C 85 | ax_pthread_ok=no 86 | 87 | # We used to check for pthread.h first, but this fails if pthread.h 88 | # requires special compiler flags (e.g. on True64 or Sequent). 89 | # It gets checked for in the link test anyway. 90 | 91 | # First of all, check if the user has set any of the PTHREAD_LIBS, 92 | # etcetera environment variables, and if threads linking works using 93 | # them: 94 | if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then 95 | save_CFLAGS="$CFLAGS" 96 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 97 | save_LIBS="$LIBS" 98 | LIBS="$PTHREAD_LIBS $LIBS" 99 | AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) 100 | AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes) 101 | AC_MSG_RESULT($ax_pthread_ok) 102 | if test x"$ax_pthread_ok" = xno; then 103 | PTHREAD_LIBS="" 104 | PTHREAD_CFLAGS="" 105 | fi 106 | LIBS="$save_LIBS" 107 | CFLAGS="$save_CFLAGS" 108 | fi 109 | 110 | # We must check for the threads library under a number of different 111 | # names; the ordering is very important because some systems 112 | # (e.g. DEC) have both -lpthread and -lpthreads, where one of the 113 | # libraries is broken (non-POSIX). 114 | 115 | # Create a list of thread flags to try. Items starting with a "-" are 116 | # C compiler flags, and other items are library names, except for "none" 117 | # which indicates that we try without any flags at all, and "pthread-config" 118 | # which is a program returning the flags for the Pth emulation library. 119 | 120 | ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" 121 | 122 | # The ordering *is* (sometimes) important. Some notes on the 123 | # individual items follow: 124 | 125 | # pthreads: AIX (must check this before -lpthread) 126 | # none: in case threads are in libc; should be tried before -Kthread and 127 | # other compiler flags to prevent continual compiler warnings 128 | # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) 129 | # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) 130 | # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) 131 | # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) 132 | # -pthreads: Solaris/gcc 133 | # -mthreads: Mingw32/gcc, Lynx/gcc 134 | # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it 135 | # doesn't hurt to check since this sometimes defines pthreads too; 136 | # also defines -D_REENTRANT) 137 | # ... -mt is also the pthreads flag for HP/aCC 138 | # pthread: Linux, etcetera 139 | # --thread-safe: KAI C++ 140 | # pthread-config: use pthread-config program (for GNU Pth library) 141 | 142 | case "${host_cpu}-${host_os}" in 143 | *solaris*) 144 | 145 | # On Solaris (at least, for some versions), libc contains stubbed 146 | # (non-functional) versions of the pthreads routines, so link-based 147 | # tests will erroneously succeed. (We need to link with -pthreads/-mt/ 148 | # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather 149 | # a function called by this macro, so we could check for that, but 150 | # who knows whether they'll stub that too in a future libc.) So, 151 | # we'll just look for -pthreads and -lpthread first: 152 | 153 | ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" 154 | ;; 155 | 156 | *-darwin*) 157 | acx_pthread_flags="-pthread $acx_pthread_flags" 158 | ;; 159 | esac 160 | 161 | if test x"$ax_pthread_ok" = xno; then 162 | for flag in $ax_pthread_flags; do 163 | 164 | case $flag in 165 | none) 166 | AC_MSG_CHECKING([whether pthreads work without any flags]) 167 | ;; 168 | 169 | -*) 170 | AC_MSG_CHECKING([whether pthreads work with $flag]) 171 | PTHREAD_CFLAGS="$flag" 172 | ;; 173 | 174 | pthread-config) 175 | AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no) 176 | if test x"$ax_pthread_config" = xno; then continue; fi 177 | PTHREAD_CFLAGS="`pthread-config --cflags`" 178 | PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" 179 | ;; 180 | 181 | *) 182 | AC_MSG_CHECKING([for the pthreads library -l$flag]) 183 | PTHREAD_LIBS="-l$flag" 184 | ;; 185 | esac 186 | 187 | save_LIBS="$LIBS" 188 | save_CFLAGS="$CFLAGS" 189 | LIBS="$PTHREAD_LIBS $LIBS" 190 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 191 | 192 | # Check for various functions. We must include pthread.h, 193 | # since some functions may be macros. (On the Sequent, we 194 | # need a special flag -Kthread to make this header compile.) 195 | # We check for pthread_join because it is in -lpthread on IRIX 196 | # while pthread_create is in libc. We check for pthread_attr_init 197 | # due to DEC craziness with -lpthreads. We check for 198 | # pthread_cleanup_push because it is one of the few pthread 199 | # functions on Solaris that doesn't have a non-functional libc stub. 200 | # We try pthread_create on general principles. 201 | AC_TRY_LINK([#include 202 | static void routine(void* a) {a=0;} 203 | static void* start_routine(void* a) {return a;}], 204 | [pthread_t th; pthread_attr_t attr; 205 | pthread_join(th, 0); 206 | pthread_attr_init(&attr); 207 | pthread_cleanup_push(routine, 0); 208 | pthread_create(&th,0,start_routine,0); 209 | pthread_cleanup_pop(0); ], 210 | [ax_pthread_ok=yes]) 211 | 212 | LIBS="$save_LIBS" 213 | CFLAGS="$save_CFLAGS" 214 | 215 | AC_MSG_RESULT($ax_pthread_ok) 216 | if test "x$ax_pthread_ok" = xyes; then 217 | break; 218 | fi 219 | 220 | PTHREAD_LIBS="" 221 | PTHREAD_CFLAGS="" 222 | done 223 | fi 224 | 225 | # Various other checks: 226 | if test "x$ax_pthread_ok" = xyes; then 227 | save_LIBS="$LIBS" 228 | LIBS="$PTHREAD_LIBS $LIBS" 229 | save_CFLAGS="$CFLAGS" 230 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 231 | 232 | # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. 233 | AC_MSG_CHECKING([for joinable pthread attribute]) 234 | attr_name=unknown 235 | for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do 236 | AC_TRY_LINK([#include ], [int attr=$attr; return attr;], 237 | [attr_name=$attr; break]) 238 | done 239 | AC_MSG_RESULT($attr_name) 240 | if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then 241 | AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, 242 | [Define to necessary symbol if this constant 243 | uses a non-standard name on your system.]) 244 | fi 245 | 246 | AC_MSG_CHECKING([if more special flags are required for pthreads]) 247 | flag=no 248 | case "${host_cpu}-${host_os}" in 249 | *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; 250 | *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; 251 | esac 252 | AC_MSG_RESULT(${flag}) 253 | if test "x$flag" != xno; then 254 | PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" 255 | fi 256 | 257 | LIBS="$save_LIBS" 258 | CFLAGS="$save_CFLAGS" 259 | 260 | # More AIX lossage: must compile with xlc_r or cc_r 261 | if test x"$GCC" != xyes; then 262 | AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) 263 | else 264 | PTHREAD_CC=$CC 265 | fi 266 | else 267 | PTHREAD_CC="$CC" 268 | fi 269 | 270 | AC_SUBST(PTHREAD_LIBS) 271 | AC_SUBST(PTHREAD_CFLAGS) 272 | AC_SUBST(PTHREAD_CC) 273 | 274 | # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: 275 | if test x"$ax_pthread_ok" = xyes; then 276 | ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) 277 | : 278 | else 279 | ax_pthread_ok=no 280 | $2 281 | fi 282 | AC_LANG_RESTORE 283 | ])dnl AX_PTHREAD 284 | -------------------------------------------------------------------------------- /src/writer.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2013-2015 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2013-2015 Otto Gmbh & Co KG 4 | * All rights reserved 5 | * Use only with permission 6 | * 7 | * Authors: Geoffrey Simmons 8 | * Nils Goroll 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | * SUCH DAMAGE. 30 | * 31 | */ 32 | 33 | #include "config.h" 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "varnishevent.h" 44 | #include "writer.h" 45 | 46 | #include "vas.h" 47 | #include "miniobj.h" 48 | #include "vsb.h" 49 | #include "vmb.h" 50 | #include "vtim.h" 51 | 52 | typedef enum { 53 | WRT_NOTSTARTED = 0, 54 | WRT_INITIALIZING, 55 | WRT_RUNNING, 56 | WRT_WAITING, 57 | WRT_SHUTTINGDOWN, 58 | WRT_EXITED, 59 | WRT_STATE_E_LIMIT 60 | } wrt_state_e; 61 | 62 | static const char* statename[WRT_STATE_E_LIMIT] = { 63 | [WRT_NOTSTARTED] = "not started", 64 | [WRT_INITIALIZING] = "initializing", 65 | [WRT_RUNNING] = "running", 66 | [WRT_WAITING] = "waiting", 67 | [WRT_SHUTTINGDOWN] = "shutting down", 68 | [WRT_EXITED] = "exited" 69 | }; 70 | 71 | /* Single writer thread, consumer for the SPSC queue. */ 72 | static pthread_t writer; 73 | 74 | rechead_t wrt_freerecs; 75 | chunkhead_t wrt_freechunks; 76 | 77 | static unsigned wrt_nfree_tx, wrt_nfree_recs, wrt_nfree_chunks; 78 | 79 | static FILE *fo; 80 | static struct pollfd fds[1]; 81 | static int blocking = 0, timeout = -1; 82 | static char *obuf = NULL; 83 | static pthread_mutex_t reopen_lock = PTHREAD_MUTEX_INITIALIZER; 84 | 85 | /* stats */ 86 | static unsigned long deqs = 0; 87 | static unsigned long bytes = 0; 88 | static unsigned long waits = 0; 89 | static unsigned long writes = 0; 90 | static unsigned long errors = 0; 91 | static unsigned long timeouts = 0; 92 | static double pollt = 0., writet = 0.; 93 | 94 | typedef struct writer_data_s { 95 | unsigned magic; 96 | #define WRITER_DATA_MAGIC 0xd8eef137 97 | unsigned status; /* exit status */ 98 | wrt_state_e state; 99 | } writer_data_t; 100 | 101 | static writer_data_t wrt_data; 102 | 103 | static unsigned run, reopen = 0, tx_thresh, rec_thresh, chunk_thresh; 104 | 105 | static int 106 | open_log(void) 107 | { 108 | struct stat st; 109 | 110 | if (EMPTY(config.output_file) || strcmp(config.output_file, "-") == 0) 111 | fo = stdout; 112 | else { 113 | if ((fo = fopen(config.output_file, config.append ? "a" : "w")) 114 | == NULL) 115 | return errno; 116 | if (stat(config.output_file, &st) < 0) 117 | return errno; 118 | if (S_ISDIR(st.st_mode)) 119 | return EISDIR; 120 | blocking = !S_ISREG(st.st_mode); 121 | if (blocking) { 122 | fds[0].fd = fileno(fo); 123 | fds[0].events = POLLOUT; 124 | } 125 | } 126 | 127 | if (obuf != NULL) 128 | free(obuf); 129 | obuf = (char *) malloc(config.output_bufsiz); 130 | if (obuf == NULL) 131 | return errno; 132 | 133 | if (setvbuf(fo, obuf, _IOFBF, config.output_bufsiz) != 0) 134 | return errno; 135 | 136 | return 0; 137 | } 138 | 139 | static void 140 | wrt_signal_data_ready(void) 141 | { 142 | if (RDR_Waiting()) { 143 | AZ(pthread_mutex_lock(&data_ready_lock)); 144 | if (RDR_Waiting()) 145 | AZ(pthread_cond_signal(&data_ready_cond)); 146 | AZ(pthread_mutex_unlock(&data_ready_lock)); 147 | } 148 | } 149 | 150 | static inline void 151 | wrt_return_freelist(void) 152 | { 153 | if (wrt_nfree_chunks > 0) { 154 | DATA_Return_Freechunk(&wrt_freechunks, wrt_nfree_chunks); 155 | wrt_signal_data_ready(); 156 | LOG_Log(LOG_DEBUG, "Writer: returned %u chunks to free list", 157 | wrt_nfree_chunks); 158 | wrt_nfree_chunks = 0; 159 | assert(VSTAILQ_EMPTY(&wrt_freechunks)); 160 | } 161 | if (wrt_nfree_recs > 0) { 162 | DATA_Return_Freerec(&wrt_freerecs, wrt_nfree_recs); 163 | wrt_signal_data_ready(); 164 | LOG_Log(LOG_DEBUG, "Writer: returned %u records to free list", 165 | wrt_nfree_recs); 166 | wrt_nfree_recs = 0; 167 | assert(VSTAILQ_EMPTY(&wrt_freerecs)); 168 | } 169 | if (wrt_nfree_tx > 0) { 170 | DATA_Return_Freetx(&wrt_freetx, wrt_nfree_tx); 171 | wrt_signal_data_ready(); 172 | LOG_Log(LOG_DEBUG, "Writer: returned %u tx to free list", wrt_nfree_tx); 173 | wrt_nfree_tx = 0; 174 | assert(VSTAILQ_EMPTY(&wrt_freetx)); 175 | } 176 | } 177 | 178 | void 179 | wrt_write(tx_t *tx) 180 | { 181 | char *os; 182 | int ready = 1; 183 | size_t len; 184 | 185 | CHECK_OBJ_NOTNULL(tx, TX_MAGIC); 186 | assert(tx->state == TX_SUBMITTED); 187 | 188 | AZ(pthread_mutex_lock(&reopen_lock)); 189 | if (reopen && fo != stdout) { 190 | int errnum; 191 | 192 | wrt_return_freelist(); 193 | if (fflush(fo) != 0) 194 | LOG_Log(LOG_ERR, "Cannot flush to %s, DATA DISCARDED: %s", 195 | config.output_file, strerror(errno)); 196 | if (fclose(fo) != 0) { 197 | LOG_Log(LOG_ALERT, "Cannot close %s, exiting: %s", 198 | config.output_file, strerror(errno)); 199 | exit(EXIT_FAILURE); 200 | } 201 | if ((errnum = open_log()) != 0) { 202 | LOG_Log(LOG_ALERT, "Cannot reopen %s, exiting: %s", 203 | config.output_file, strerror(errnum)); 204 | exit(EXIT_FAILURE); 205 | } 206 | reopen = 0; 207 | } 208 | AZ(pthread_mutex_unlock(&reopen_lock)); 209 | 210 | VRMB(); 211 | os = FMT_Format(tx, &len); 212 | assert(tx->state == TX_WRITTEN); 213 | 214 | if (blocking) { 215 | int nfds; 216 | 217 | ready = 0; 218 | do { 219 | double start = VTIM_mono(); 220 | nfds = poll(fds, 1, timeout); 221 | pollt += VTIM_mono() - start; 222 | if (nfds < 0) 223 | assert(errno == EAGAIN || errno == EINTR); 224 | } while (nfds < 0); 225 | AZ(fds[0].revents & POLLNVAL); 226 | if (fds[0].revents & POLLERR) { 227 | LOG_Log(LOG_ERR, 228 | "Error waiting for ready output %d (%s), " 229 | "DATA DISCARDED: %s", errno, strerror(errno), os); 230 | errors++; 231 | } 232 | else if (nfds == 0) { 233 | wrt_return_freelist(); 234 | LOG_Log(LOG_ERR, 235 | "Timeout waiting for ready output, DATA DISCARDED: %s", os); 236 | timeouts++; 237 | } 238 | else if (nfds != 1) 239 | WRONG("More than one ready file descriptor for output"); 240 | else { 241 | AN(fds[0].revents & POLLOUT); 242 | ready = 1; 243 | } 244 | } 245 | if (ready) { 246 | errno = 0; 247 | double start = VTIM_mono(); 248 | int items = fwrite(os, 1, len, fo); 249 | writet += VTIM_mono() - start; 250 | if (ferror(fo) || items < len) { 251 | LOG_Log(LOG_ERR, "Output error %d (%s), DATA DISCARDED: %s", 252 | errno, strerror(errno), os); 253 | errors++; 254 | clearerr(fo); 255 | } 256 | else { 257 | writes++; 258 | bytes += len; 259 | } 260 | } 261 | 262 | /* clean up */ 263 | DATA_Clear_Tx(tx, &wrt_freetx, &wrt_freerecs, &wrt_freechunks, 264 | &wrt_nfree_tx, &wrt_nfree_recs, &wrt_nfree_chunks); 265 | 266 | assert(tx->state == TX_FREE); 267 | 268 | if (RDR_Waiting() || RDR_Depleted() || wrt_nfree_tx > tx_thresh 269 | || wrt_nfree_recs > rec_thresh || wrt_nfree_chunks > chunk_thresh) 270 | wrt_return_freelist(); 271 | } 272 | 273 | static void 274 | *wrt_main(void *arg) 275 | { 276 | writer_data_t *wrt = (writer_data_t *) arg; 277 | tx_t *tx; 278 | 279 | LOG_Log0(LOG_NOTICE, "Writer thread starting"); 280 | CHECK_OBJ_NOTNULL(wrt, WRITER_DATA_MAGIC); 281 | thread_setname(pthread_self(), "vevent_writer"); 282 | wrt->state = WRT_INITIALIZING; 283 | 284 | VSTAILQ_INIT(&wrt_freetx); 285 | wrt_nfree_tx = 0; 286 | 287 | wrt->state = WRT_RUNNING; 288 | 289 | VMB(); 290 | while (run) { 291 | tx = SPSCQ_Deq(); 292 | if (tx != NULL) { 293 | deqs++; 294 | CHECK_OBJ(tx, TX_MAGIC); 295 | wrt_write(tx); 296 | continue; 297 | } 298 | 299 | /* 300 | * wait until data are available, or quit is signaled. 301 | * flush ouput and return space before sleeping 302 | */ 303 | if (fflush(fo) != 0) { 304 | LOG_Log(LOG_ERR, "Output flush failed, error %d (%s)", 305 | errno, strerror(errno)); 306 | errors++; 307 | } 308 | wrt_return_freelist(); 309 | 310 | wrt->state = WRT_WAITING; 311 | AZ(pthread_mutex_lock(&spscq_ready_lock)); 312 | /* 313 | * run is guaranteed to be fresh after the lock 314 | */ 315 | if (run && !RDR_Waiting()) { 316 | waits++; 317 | AZ(pthread_cond_wait(&spscq_ready_cond, &spscq_ready_lock)); 318 | } 319 | wrt->state = WRT_RUNNING; 320 | AZ(pthread_mutex_unlock(&spscq_ready_lock)); 321 | } 322 | 323 | wrt->state = WRT_SHUTTINGDOWN; 324 | 325 | /* Prepare to exit, drain the queue */ 326 | while ((tx = SPSCQ_Deq()) != NULL) { 327 | deqs++; 328 | CHECK_OBJ(tx, TX_MAGIC); 329 | wrt_write(tx); 330 | } 331 | if (fflush(fo) != 0) { 332 | LOG_Log(LOG_ERR, "Output flush failed, error %d (%s)", 333 | errno, strerror(errno)); 334 | errors++; 335 | } 336 | 337 | wrt->status = EXIT_SUCCESS; 338 | LOG_Log0(LOG_NOTICE, "Writer thread exiting"); 339 | wrt->state = WRT_EXITED; 340 | pthread_exit((void *) wrt); 341 | } 342 | 343 | int 344 | WRT_Init(void) 345 | { 346 | int err; 347 | 348 | if ((err = open_log()) != 0) 349 | return err; 350 | 351 | wrt_data.magic = WRITER_DATA_MAGIC; 352 | wrt_data.state = WRT_NOTSTARTED; 353 | 354 | if (config.output_timeout != 0.) 355 | timeout = config.output_timeout * 1e3; 356 | 357 | tx_thresh = config.max_data >> 2; 358 | rec_thresh = nrecords >> 2; 359 | chunk_thresh = nchunks >> 2; 360 | 361 | run = 1; 362 | return 0; 363 | } 364 | 365 | void 366 | WRT_Start(void) 367 | { 368 | AZ(pthread_create(&writer, NULL, wrt_main, &wrt_data)); 369 | } 370 | 371 | void 372 | WRT_Stats(void) 373 | { 374 | LOG_Log(LOG_INFO, 375 | "Writer (%s): seen=%lu writes=%lu bytes=%lu errors=%lu timeouts=%lu" 376 | " waits=%lu free_tx=%u free_rec=%u free_chunk=%u pollt=%.6f" 377 | " writet=%.6f", 378 | statename[wrt_data.state], deqs, writes, bytes, errors, timeouts, 379 | waits, wrt_nfree_tx, wrt_nfree_recs, wrt_nfree_chunks, pollt, 380 | writet); 381 | } 382 | 383 | int 384 | WRT_Running(void) 385 | { 386 | return wrt_data.state > WRT_INITIALIZING 387 | && wrt_data.state < WRT_EXITED; 388 | } 389 | 390 | int 391 | WRT_Waiting(void) 392 | { 393 | return wrt_data.state == WRT_WAITING; 394 | } 395 | 396 | void 397 | WRT_Reopen(void) 398 | { 399 | AZ(pthread_mutex_lock(&reopen_lock)); 400 | reopen = 1; 401 | AZ(pthread_mutex_unlock(&reopen_lock)); 402 | } 403 | 404 | void 405 | WRT_Halt(void) 406 | { 407 | writer_data_t *wrt; 408 | 409 | AZ(pthread_mutex_lock(&spscq_ready_lock)); 410 | run = 0; 411 | AZ(pthread_cond_signal(&spscq_ready_cond)); 412 | AZ(pthread_mutex_unlock(&spscq_ready_lock)); 413 | 414 | AZ(pthread_join(writer, (void **) &wrt)); 415 | CHECK_OBJ_NOTNULL(wrt, WRITER_DATA_MAGIC); 416 | if (wrt->status != EXIT_SUCCESS) 417 | LOG_Log0(LOG_ERR, "Writer thread returned failure status"); 418 | } 419 | 420 | void 421 | WRT_Fini(void) 422 | { 423 | /* WRT_Halt() must always be called first */ 424 | AZ(run); 425 | fclose(fo); 426 | free(obuf); 427 | AZ(pthread_mutex_destroy(&reopen_lock)); 428 | } 429 | -------------------------------------------------------------------------------- /src/test/test_data.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2015 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2015 Otto Gmbh & Co KG 4 | * All rights reserved 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include 33 | #include 34 | 35 | #include "common/common.h" 36 | 37 | #include "minunit.h" 38 | 39 | #include "../varnishevent.h" 40 | #include "../data.h" 41 | 42 | int tests_run = 0; 43 | 44 | static txhead_t local_freetx = VSTAILQ_HEAD_INITIALIZER(local_freetx); 45 | static rechead_t local_freerec = VSTAILQ_HEAD_INITIALIZER(local_freerec); 46 | static chunkhead_t local_freechunk = VSTAILQ_HEAD_INITIALIZER(local_freechunk); 47 | 48 | /* So that we don't have to link monitor.o, and hence varnishevent.o */ 49 | void 50 | MON_StatsUpdate(stats_update_t update, unsigned nrec, unsigned nchunk) 51 | { 52 | (void) update; 53 | (void) nrec; 54 | (void) nchunk; 55 | } 56 | 57 | /* N.B.: Always run the tests in this order */ 58 | static char 59 | *test_data_init(void) 60 | { 61 | int err; 62 | char fmterr[BUFSIZ]; 63 | unsigned tx_free = 0, rec_free = 0, chunk_free = 0; 64 | 65 | printf("... testing data table initialization\n"); 66 | 67 | MAZ(LOG_Open("test_data")); 68 | CONF_Init(); 69 | MAZ(FMT_Init(fmterr)); 70 | 71 | VMASSERT((err = DATA_Init()) == 0, "DATA_Init: %s", strerror(err)); 72 | MAN(txn); 73 | 74 | for (int i = 0; i < config.max_data; i++) { 75 | MCHECK_OBJ(&txn[i], TX_MAGIC); 76 | MASSERT(txn[i].state == TX_FREE); 77 | MASSERT(txn[i].vxid == -1); 78 | MASSERT(txn[i].pvxid == -1); 79 | MASSERT(txn[i].type == VSL_t_unknown); 80 | MASSERT(txn[i].disp == DISP_NONE); 81 | MAZ(txn[i].t); 82 | for (int j = 0; j < max_idx; j++) { 83 | MCHECK_OBJ_NOTNULL(txn[i].recs[j], REC_NODE_MAGIC); 84 | MAZ(txn[i].recs[j]->rec); 85 | if (txn[i].recs[j]->hdrs != NULL) 86 | for (int k = 0; txn[i].recs[j]->hdrs[k] != magic_end_rec; k++) 87 | MAZ(txn[i].recs[j]->hdrs[k]); 88 | } 89 | if (VSTAILQ_NEXT(&txn[i], freelist) != NULL) 90 | tx_free++; 91 | } 92 | MASSERT(global_nfree_tx == config.max_data); 93 | 94 | for (int i = 0; i < config.max_data * (max_idx + 1); i++) { 95 | MCHECK_OBJ(&rec_nodes[i], REC_NODE_MAGIC); 96 | MAZ(rec_nodes[i].rec); 97 | if (rec_nodes[i].hdrs != NULL) 98 | for (int j = 0; rec_nodes[i].hdrs[j] != magic_end_rec; j++) 99 | MAZ(rec_nodes[i].hdrs[j]); 100 | } 101 | 102 | for (int i = 0; i < nrecords; i++) { 103 | MCHECK_OBJ(&records[i], RECORD_MAGIC); 104 | MASSERT(!OCCUPIED(&records[i])); 105 | MASSERT(records[i].tag == SLT__Bogus); 106 | MASSERT(records[i].len == 0); 107 | MASSERT(VSTAILQ_EMPTY(&records[i].chunks)); 108 | if (VSTAILQ_NEXT(&records[i], freelist) != NULL) 109 | rec_free++; 110 | } 111 | MASSERT(global_nfree_rec == nrecords); 112 | 113 | for (int i = 0; i < nchunks; i++) { 114 | MCHECK_OBJ(&chunks[i], CHUNK_MAGIC); 115 | MASSERT(!OCCUPIED(&chunks[i])); 116 | MASSERT(chunks[i].data == (chunks[0].data + (i * config.chunk_size))); 117 | if (VSTAILQ_NEXT(&chunks[i], freelist) != NULL) 118 | chunk_free++; 119 | } 120 | MASSERT(global_nfree_chunk == nchunks); 121 | 122 | MASSERT(tx_free == config.max_data - 1); 123 | MASSERT(rec_free == nrecords - 1); 124 | MASSERT(chunk_free == nchunks - 1); 125 | 126 | return NULL; 127 | } 128 | 129 | static const char 130 | *test_data_take_tx(void) 131 | { 132 | unsigned nfree, cfree = 0; 133 | tx_t *tx; 134 | 135 | printf("... testing tx freelist take\n"); 136 | 137 | nfree = DATA_Take_Freetx(&local_freetx); 138 | 139 | MASSERT(nfree == config.max_data); 140 | MASSERT(!VSTAILQ_EMPTY(&local_freetx)); 141 | VSTAILQ_FOREACH(tx, &local_freetx, freelist) { 142 | MCHECK_OBJ_NOTNULL(tx, TX_MAGIC); 143 | cfree++; 144 | } 145 | MAZ(global_nfree_tx); 146 | MASSERT(nfree == cfree); 147 | 148 | return NULL; 149 | } 150 | 151 | static const char 152 | *test_data_take_rec(void) 153 | { 154 | unsigned nfree, cfree = 0; 155 | rec_t *rec; 156 | 157 | printf("... testing record freelist take\n"); 158 | 159 | nfree = DATA_Take_Freerec(&local_freerec); 160 | 161 | MAZ(global_nfree_rec); 162 | MASSERT(nfree == nrecords); 163 | MASSERT(!VSTAILQ_EMPTY(&local_freerec)); 164 | VSTAILQ_FOREACH(rec, &local_freerec, freelist) { 165 | MCHECK_OBJ_NOTNULL(rec, RECORD_MAGIC); 166 | cfree++; 167 | } 168 | MASSERT(nfree == cfree); 169 | 170 | return NULL; 171 | } 172 | 173 | static const char 174 | *test_data_take_chunks(void) 175 | { 176 | unsigned nfree, cfree = 0; 177 | chunk_t *chunk; 178 | 179 | printf("... testing chunk freelist take\n"); 180 | 181 | nfree = DATA_Take_Freechunk(&local_freechunk); 182 | 183 | MAZ(global_nfree_chunk); 184 | MASSERT(nfree == nchunks); 185 | MASSERT(!VSTAILQ_EMPTY(&local_freechunk)); 186 | VSTAILQ_FOREACH(chunk, &local_freechunk, freelist) { 187 | MCHECK_OBJ_NOTNULL(chunk, CHUNK_MAGIC); 188 | cfree++; 189 | } 190 | MASSERT(nfree == cfree); 191 | 192 | return NULL; 193 | } 194 | 195 | static const char 196 | *test_data_return_tx(void) 197 | { 198 | printf("... testing tx freelist return\n"); 199 | 200 | DATA_Return_Freetx(&local_freetx, config.max_data); 201 | 202 | MASSERT(VSTAILQ_EMPTY(&local_freetx)); 203 | MASSERT(global_nfree_tx == config.max_data); 204 | 205 | return NULL; 206 | } 207 | 208 | static const char 209 | *test_data_return_rec(void) 210 | { 211 | printf("... testing record freelist return\n"); 212 | 213 | DATA_Return_Freerec(&local_freerec, nrecords); 214 | 215 | MASSERT(VSTAILQ_EMPTY(&local_freerec)); 216 | MASSERT(global_nfree_rec == nrecords); 217 | 218 | return NULL; 219 | } 220 | 221 | static const char 222 | *test_data_return_chunk(void) 223 | { 224 | printf("... testing chunk freelist return\n"); 225 | 226 | DATA_Return_Freechunk(&local_freechunk, nchunks); 227 | 228 | MASSERT(VSTAILQ_EMPTY(&local_freechunk)); 229 | MASSERT(global_nfree_chunk == nchunks); 230 | 231 | return NULL; 232 | } 233 | 234 | static const char 235 | *test_data_prepend(void) 236 | { 237 | tx_t *tx; 238 | int n = 0; 239 | 240 | printf("... testing freelist prepend\n"); 241 | 242 | MASSERT(VSTAILQ_EMPTY(&local_freetx)); 243 | /* Return an empty list */ 244 | DATA_Return_Freetx(&local_freetx, 0); 245 | MASSERT(VSTAILQ_EMPTY(&local_freetx)); 246 | MASSERT(global_nfree_tx == config.max_data); 247 | 248 | DATA_Take_Freetx(&local_freetx); 249 | VSTAILQ_INIT(&local_freetx); 250 | /* insert the first 10 txn to the local list */ 251 | for (int i = 0; i < 10; i++) 252 | VSTAILQ_INSERT_TAIL(&local_freetx, &txn[i], freelist); 253 | /* Prepend them to the global free list */ 254 | DATA_Return_Freetx(&local_freetx, 10); 255 | /* insert the next 10 txn */ 256 | VSTAILQ_INIT(&local_freetx); 257 | for (int i = 10; i < 20; i++) 258 | VSTAILQ_INSERT_TAIL(&local_freetx, &txn[i], freelist); 259 | /* Prepend them to the global list */ 260 | DATA_Return_Freetx(&local_freetx, 10); 261 | /* 262 | * Take the global list, and verify that txn 10-19 are at the front, 263 | * followed by txn 0-9. 264 | */ 265 | DATA_Take_Freetx(&local_freetx); 266 | VSTAILQ_FOREACH(tx, &local_freetx, freelist) { 267 | if (n < 10) 268 | MASSERT(tx == &txn[n + 10]); 269 | else 270 | MASSERT(tx == &txn[n - 10]); 271 | n++; 272 | } 273 | MASSERT(n == 20); 274 | 275 | return NULL; 276 | } 277 | 278 | static int chunks_filled = 0; 279 | 280 | static void 281 | fill_rec(rec_t *rec, chunk_t *c, int nc) 282 | { 283 | chunk_t *chunk; 284 | 285 | rec->magic = RECORD_MAGIC; 286 | rec->len = 42; 287 | rec->tag = MAX_VSL_TAG/2; 288 | rec->occupied = 1; 289 | VSTAILQ_INIT(&rec->chunks); 290 | for (int i = 0; i < nc; i++) { 291 | chunk = &c[i]; 292 | VSTAILQ_INSERT_TAIL(&rec->chunks, chunk, chunklist); 293 | chunk->magic = CHUNK_MAGIC; 294 | chunk->data = (char *) calloc(1, config.chunk_size); 295 | chunk->occupied = 1; 296 | chunks_filled++; 297 | } 298 | } 299 | 300 | #define REC_NODE_CLEARED(n) \ 301 | do { \ 302 | MCHECK_OBJ(n, REC_NODE_MAGIC); \ 303 | MAZ((n)->rec); \ 304 | if ((n)->hdrs != NULL) { \ 305 | for (int x = 0; (n)->hdrs[x] != magic_end_rec; x++) \ 306 | MAZ((n)->hdrs[x]); \ 307 | MASSERT((n)->hdrs[HDRS_PER_NODE] == magic_end_rec); \ 308 | } \ 309 | } while(0) 310 | 311 | #define REC_CLEARED(rec) \ 312 | do { \ 313 | MCHECK_OBJ_NOTNULL((rec), RECORD_MAGIC); \ 314 | MASSERT(!OCCUPIED(rec)); \ 315 | MASSERT((rec)->tag == SLT__Bogus); \ 316 | MAZ((rec)->len); \ 317 | MASSERT(VSTAILQ_EMPTY(&(rec)->chunks)); \ 318 | } while(0) 319 | 320 | #define CHUNK_CLEARED(chunk) \ 321 | do { \ 322 | MCHECK_OBJ_NOTNULL((chunk), CHUNK_MAGIC); \ 323 | MASSERT(!OCCUPIED(chunk)); \ 324 | MAZ((chunk)->data[0]); \ 325 | } while(0) 326 | 327 | static const char 328 | *test_data_clear_tx(void) 329 | { 330 | #define N_NODES (max_idx + 1) 331 | #define HDRS_PER_NODE 5 332 | #define CHUNKS_PER_REC 3 333 | #define NRECS ((max_idx)/2 + (((max_idx) - (max_idx)/2) * HDRS_PER_NODE)) 334 | #define NCHUNKS ((NRECS) * (CHUNKS_PER_REC)) 335 | tx_t tx; 336 | rec_t *rec; 337 | chunk_t *chunk; 338 | int n = 0; 339 | unsigned nfree_tx = 4711, nfree_recs = 815, nfree_chunks = 1147; 340 | 341 | printf("... testing transaction clear\n"); 342 | 343 | VSTAILQ_INIT(&local_freetx); 344 | VSTAILQ_INIT(&local_freerec); 345 | VSTAILQ_INIT(&local_freechunk); 346 | 347 | tx.magic = TX_MAGIC; 348 | tx.t = 123456789.0; 349 | tx.vxid = 314159265; 350 | tx.pvxid = 2718281828; 351 | tx.type = VSL_t_req; 352 | tx.state = TX_WRITTEN; 353 | tx.disp = DISP_HIT; 354 | tx.recs = (rec_node_t **) calloc(max_idx, sizeof(rec_node_t *)); 355 | MAN(tx.recs); 356 | for (int i = 0; i < max_idx/2; i++) { 357 | tx.recs[i] = &rec_nodes[i]; 358 | rec_nodes[i].magic = REC_NODE_MAGIC; 359 | rec_nodes[i].rec = &records[i]; 360 | fill_rec(&records[i], &chunks[i * CHUNKS_PER_REC], CHUNKS_PER_REC); 361 | rec_nodes[i].hdrs = NULL; 362 | } 363 | for (int i = max_idx/2; i < max_idx; i++) { 364 | tx.recs[i] = &rec_nodes[i]; 365 | rec_nodes[i].magic = REC_NODE_MAGIC; 366 | rec_nodes[i].rec = NULL; 367 | rec_nodes[i].hdrs = (rec_t **) calloc(HDRS_PER_NODE + 1, 368 | sizeof(rec_t *)); 369 | MAN(rec_nodes[i].hdrs); 370 | for (int j = 0; j < HDRS_PER_NODE; j++) { 371 | int idx = max_idx/2 + (i - max_idx/2) * HDRS_PER_NODE + j; 372 | rec_nodes[i].hdrs[j] = &records[idx]; 373 | fill_rec(&records[idx], &chunks[idx * CHUNKS_PER_REC], 374 | CHUNKS_PER_REC); 375 | } 376 | rec_nodes[i].hdrs[HDRS_PER_NODE] = TRUST_ME(magic_end_rec); 377 | } 378 | 379 | DATA_Clear_Tx(&tx, &local_freetx, &local_freerec, &local_freechunk, 380 | &nfree_tx, &nfree_recs, &nfree_chunks); 381 | 382 | MASSERT(nfree_tx == 4712); 383 | MASSERT(nfree_recs == 815 + NRECS); 384 | MASSERT(nfree_chunks == 1147 + NCHUNKS); 385 | 386 | MCHECK_OBJ(&tx, TX_MAGIC); 387 | MASSERT(tx.state == TX_FREE); 388 | MASSERT(tx.vxid == -1); 389 | MASSERT(tx.pvxid == -1); 390 | MASSERT(tx.type == VSL_t_unknown); 391 | MASSERT(tx.disp == DISP_NONE); 392 | MAZ(tx.t); 393 | for (int i = 0; i < max_idx; i++) { 394 | REC_NODE_CLEARED(tx.recs[i]); 395 | REC_NODE_CLEARED(&rec_nodes[i]); 396 | } 397 | 398 | MASSERT(!VSTAILQ_EMPTY(&local_freetx)); 399 | MASSERT(VSTAILQ_FIRST(&local_freetx) == &tx); 400 | MAZ(VSTAILQ_NEXT(&tx, freelist)); 401 | 402 | MASSERT(!VSTAILQ_EMPTY(&local_freerec)); 403 | VSTAILQ_FOREACH(rec, &local_freerec, freelist) { 404 | REC_CLEARED(rec); 405 | n++; 406 | } 407 | MASSERT(n == NRECS); 408 | 409 | MASSERT(!VSTAILQ_EMPTY(&local_freechunk)); 410 | n = 0; 411 | VSTAILQ_FOREACH(chunk, &local_freechunk, freelist) { 412 | CHUNK_CLEARED(chunk); 413 | n++; 414 | } 415 | MASSERT(n == NCHUNKS); 416 | 417 | for (int i = 0; i < NRECS; i++) 418 | REC_CLEARED(&records[i]); 419 | 420 | for (int i = 0; i < NCHUNKS; i++) 421 | CHUNK_CLEARED(&chunks[i]); 422 | 423 | return NULL; 424 | } 425 | 426 | static const char 427 | *all_tests(void) 428 | { 429 | mu_run_test(test_data_init); 430 | mu_run_test(test_data_take_tx); 431 | mu_run_test(test_data_take_rec); 432 | mu_run_test(test_data_take_chunks); 433 | mu_run_test(test_data_return_tx); 434 | mu_run_test(test_data_return_rec); 435 | mu_run_test(test_data_return_chunk); 436 | mu_run_test(test_data_prepend); 437 | mu_run_test(test_data_clear_tx); 438 | return NULL; 439 | } 440 | 441 | TEST_RUNNER 442 | -------------------------------------------------------------------------------- /src/data.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2013-2015 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2013-2015 Otto Gmbh & Co KG 4 | * All rights reserved 5 | * Use only with permission 6 | * 7 | * Authors: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "varnishevent.h" 41 | #include "data.h" 42 | #include "hdrtrie.h" 43 | 44 | #include "vas.h" 45 | #include "miniobj.h" 46 | #include "vqueue.h" 47 | #include "vdef.h" 48 | #include "vsb.h" 49 | #include "vmb.h" 50 | #include "common/common.h" 51 | 52 | #define __offsetof(st, m) offsetof(st,m) 53 | 54 | /* Preprend head2 before head1, result in head1, head2 empty afterward */ 55 | #define VSTAILQ_PREPEND(head1, head2) do { \ 56 | if (VSTAILQ_EMPTY((head2))) \ 57 | break; \ 58 | if (VSTAILQ_EMPTY((head1))) \ 59 | (head1)->vstqh_last = (head2)->vstqh_last; \ 60 | else \ 61 | *(head2)->vstqh_last = VSTAILQ_FIRST((head1)); \ 62 | VSTAILQ_FIRST((head1)) = VSTAILQ_FIRST((head2)); \ 63 | VSTAILQ_INIT((head2)); \ 64 | } while (0) 65 | 66 | static const char *statename[] = { 67 | "FREE", "OPEN", "DONE", "SUBMITTED", "FORMATTING", "WRITTEN" 68 | }; 69 | 70 | static pthread_mutex_t freetx_lock = PTHREAD_MUTEX_INITIALIZER; 71 | static pthread_mutex_t freerec_lock = PTHREAD_MUTEX_INITIALIZER; 72 | static pthread_mutex_t freechunk_lock = PTHREAD_MUTEX_INITIALIZER; 73 | static char *bufptr; 74 | static txhead_t freetxhead; 75 | static rechead_t freerechead; 76 | static chunkhead_t freechunkhead; 77 | 78 | static const char bogus_rec; 79 | const void * const magic_end_rec = &bogus_rec; 80 | 81 | static void 82 | data_Cleanup(void) 83 | { 84 | free(txn); 85 | free(rec_nodes); 86 | free(records); 87 | free(chunks); 88 | free(bufptr); 89 | AZ(pthread_mutex_destroy(&freetx_lock)); 90 | AZ(pthread_mutex_destroy(&freerec_lock)); 91 | AZ(pthread_mutex_destroy(&freechunk_lock)); 92 | } 93 | 94 | static unsigned 95 | data_clear_rec(rec_t *rec, rechead_t * const freerec, 96 | chunkhead_t * const freechunk) 97 | { 98 | chunk_t *chunk; 99 | unsigned nchunk = 0; 100 | 101 | CHECK_OBJ_NOTNULL(rec, RECORD_MAGIC); 102 | assert(OCCUPIED(rec)); 103 | while ((chunk = VSTAILQ_FIRST(&rec->chunks)) != NULL) { 104 | CHECK_OBJ(chunk, CHUNK_MAGIC); 105 | assert(OCCUPIED(chunk)); 106 | chunk->occupied = 0; 107 | *chunk->data = '\0'; 108 | VSTAILQ_REMOVE_HEAD(&rec->chunks, chunklist); 109 | VSTAILQ_INSERT_HEAD(freechunk, chunk, freelist); 110 | nchunk++; 111 | } 112 | assert(VSTAILQ_EMPTY(&rec->chunks)); 113 | rec->tag = SLT__Bogus; 114 | rec->len = 0; 115 | rec->occupied = 0; 116 | VSTAILQ_INSERT_HEAD(freerec, rec, freelist); 117 | return nchunk; 118 | } 119 | 120 | void 121 | DATA_Clear_Tx(tx_t * const tx, txhead_t * const freetx, 122 | rechead_t * const freerec, chunkhead_t * const freechunk, 123 | unsigned * restrict const nfree_tx, 124 | unsigned * restrict const nfree_rec, 125 | unsigned * restrict const nfree_chunk) 126 | { 127 | unsigned nchunk = 0, nrec = 0; 128 | 129 | CHECK_OBJ_NOTNULL(tx, TX_MAGIC); 130 | assert(tx->state == TX_WRITTEN); 131 | 132 | tx->vxid = -1; 133 | tx->pvxid = -1; 134 | tx->type = VSL_t_unknown; 135 | tx->t = 0.; 136 | tx->disp = DISP_NONE; 137 | 138 | for (int i = 0; i < max_idx; i++) { 139 | rec_node_t *rec_node = tx->recs[i]; 140 | CHECK_OBJ_NOTNULL(rec_node, REC_NODE_MAGIC); 141 | if (rec_node->rec != NULL) { 142 | CHECK_OBJ(rec_node->rec, RECORD_MAGIC); 143 | nchunk += data_clear_rec(rec_node->rec, freerec, freechunk); 144 | nrec++; 145 | rec_node->rec = NULL; 146 | continue; 147 | } 148 | if (rec_node->hdrs == NULL) 149 | continue; 150 | for (int j = 0; rec_node->hdrs[j] != magic_end_rec; j++) { 151 | rec_t *rec; 152 | if ((rec = rec_node->hdrs[j]) != NULL) { 153 | CHECK_OBJ(rec, RECORD_MAGIC); 154 | nchunk += data_clear_rec(rec, freerec, freechunk); 155 | nrec++; 156 | rec_node->hdrs[j] = NULL; 157 | } 158 | } 159 | } 160 | tx->state = TX_FREE; 161 | VSTAILQ_INSERT_HEAD(freetx, tx, freelist); 162 | *nfree_tx += 1; 163 | *nfree_rec += nrec; 164 | *nfree_chunk += nchunk; 165 | MON_StatsUpdate(STATS_WRITTEN, nrec, nchunk); 166 | } 167 | 168 | int 169 | DATA_Init(void) 170 | { 171 | int bufidx = 0, chunks_per_rec, recs_per_tx = FMT_Estimate_RecsPerTx(), 172 | nrecnodes = config.max_data * (max_idx + 1); 173 | 174 | LOG_Log(LOG_DEBUG, "Estimated %d records per transaction", recs_per_tx); 175 | nrecords = config.max_data * recs_per_tx; 176 | AN(config.chunk_size); 177 | chunks_per_rec 178 | = (config.max_reclen + config.chunk_size - 1) / config.chunk_size; 179 | nchunks = nrecords * chunks_per_rec; 180 | 181 | LOG_Log(LOG_DEBUG, "Allocating space for %d chunks (%d bytes)", 182 | nchunks, nchunks * config.chunk_size); 183 | bufptr = (char *) calloc(nchunks, config.chunk_size); 184 | if (bufptr == NULL) 185 | return errno; 186 | 187 | LOG_Log(LOG_DEBUG, "Allocating table for %d chunks (%d bytes)", nchunks, 188 | nchunks * sizeof(chunk_t)); 189 | chunks = (chunk_t *) calloc(nchunks, sizeof(chunk_t)); 190 | if (chunks == NULL) { 191 | free(bufptr); 192 | return errno; 193 | } 194 | VSTAILQ_INIT(&freechunkhead); 195 | for (int i = 0; i < nchunks; i++) { 196 | chunks[i].magic = CHUNK_MAGIC; 197 | chunks[i].occupied = 0; 198 | chunks[i].data = &bufptr[bufidx++ * config.chunk_size]; 199 | VSTAILQ_INSERT_TAIL(&freechunkhead, &chunks[i], freelist); 200 | } 201 | assert(bufidx == nchunks); 202 | 203 | LOG_Log(LOG_DEBUG, "Allocating table for %d records (%d bytes)", nrecords, 204 | nrecords * sizeof(rec_t)); 205 | records = (rec_t *) calloc(nrecords, sizeof(rec_t)); 206 | if (records == NULL) { 207 | free(bufptr); 208 | free(chunks); 209 | return errno; 210 | } 211 | VSTAILQ_INIT(&freerechead); 212 | for (int i = 0; i < nrecords; i++) { 213 | records[i].magic = RECORD_MAGIC; 214 | records[i].occupied = 0; 215 | records[i].tag = SLT__Bogus; 216 | records[i].len = 0; 217 | VSTAILQ_INIT(&records[i].chunks); 218 | VSTAILQ_INSERT_TAIL(&freerechead, &records[i], freelist); 219 | } 220 | 221 | LOG_Log(LOG_DEBUG, "Allocating table for %d recnodes (%d bytes)", 222 | nrecnodes, nrecnodes * sizeof(rec_node_t)); 223 | rec_nodes = (rec_node_t *) calloc(nrecnodes, sizeof(rec_node_t)); 224 | if (rec_nodes == NULL) { 225 | free(bufptr); 226 | free(chunks); 227 | free(records); 228 | return errno; 229 | } 230 | for (int i = 0; i < nrecnodes; i++) 231 | rec_nodes[i].magic = REC_NODE_MAGIC; 232 | 233 | LOG_Log(LOG_DEBUG, "Allocating table for %d transactions (%d bytes)", 234 | config.max_data, config.max_data * sizeof(tx_t)); 235 | txn = (tx_t *) calloc(config.max_data, sizeof(tx_t)); 236 | if (txn == NULL) { 237 | free(bufptr); 238 | free(chunks); 239 | free(records); 240 | free(rec_nodes); 241 | return errno; 242 | } 243 | VSTAILQ_INIT(&freetxhead); 244 | for (int i = 0; i < config.max_data; i++) { 245 | txn[i].magic = TX_MAGIC; 246 | txn[i].state = TX_FREE; 247 | txn[i].vxid = -1; 248 | txn[i].pvxid = -1; 249 | txn[i].type = VSL_t_unknown; 250 | txn[i].t = 0.; 251 | txn[i].disp = DISP_NONE; 252 | txn[i].recs = (rec_node_t **) malloc(max_idx * sizeof(rec_node_t *)); 253 | AN(txn[i].recs); 254 | for (int j = 0; j < max_idx; j++) { 255 | assert((i * max_idx) + j < nrecnodes); 256 | txn[i].recs[j] = &rec_nodes[(i * max_idx) + j]; 257 | CHECK_OBJ(txn[i].recs[j], REC_NODE_MAGIC); 258 | } 259 | for (int j = 0; j < MAX_VSL_TAG; j++) { 260 | int idx, nhdrs; 261 | 262 | idx = tag2idx[j]; 263 | if (idx == -1) 264 | continue; 265 | assert(idx < max_idx); 266 | nhdrs = HDR_N(hdr_trie[j]); 267 | if (nhdrs == 0) { 268 | txn[i].recs[idx]->hdrs = NULL; 269 | continue; 270 | } 271 | txn[i].recs[idx]->hdrs = (rec_t **) calloc(nhdrs + 1, 272 | sizeof(rec_t *)); 273 | txn[i].recs[idx]->hdrs[nhdrs] = TRUST_ME(magic_end_rec); 274 | } 275 | VSTAILQ_INSERT_TAIL(&freetxhead, &txn[i], freelist); 276 | } 277 | 278 | tx_occ = rec_occ = chunk_occ = tx_occ_hi = rec_occ_hi = chunk_occ_hi = 0; 279 | global_nfree_tx = config.max_data; 280 | global_nfree_rec = nrecords; 281 | global_nfree_chunk = nchunks; 282 | 283 | atexit(data_Cleanup); 284 | 285 | return(0); 286 | } 287 | 288 | /* 289 | * take all free entries from the datatable for lockless allocation 290 | */ 291 | #define DATA_Take_Free(type) \ 292 | unsigned \ 293 | DATA_Take_Free##type(struct type##head_s *dst) \ 294 | { \ 295 | unsigned nfree; \ 296 | \ 297 | AZ(pthread_mutex_lock(&free##type##_lock)); \ 298 | VSTAILQ_PREPEND(dst, &free##type##head); \ 299 | nfree = global_nfree_##type; \ 300 | global_nfree_##type = 0; \ 301 | AZ(pthread_mutex_unlock(&free##type##_lock)); \ 302 | return nfree; \ 303 | } 304 | 305 | DATA_Take_Free(tx) 306 | DATA_Take_Free(rec) 307 | DATA_Take_Free(chunk) 308 | 309 | /* 310 | * return to global freelist 311 | * returned must be locked by caller, if required 312 | */ 313 | #define DATA_Return_Free(type) \ 314 | void \ 315 | DATA_Return_Free##type(struct type##head_s *returned, unsigned nreturned) \ 316 | { \ 317 | AZ(pthread_mutex_lock(&free##type##_lock)); \ 318 | VSTAILQ_PREPEND(&free##type##head, returned); \ 319 | global_nfree_##type += nreturned; \ 320 | AZ(pthread_mutex_unlock(&free##type##_lock)); \ 321 | } 322 | 323 | DATA_Return_Free(tx) 324 | DATA_Return_Free(rec) 325 | DATA_Return_Free(chunk) 326 | 327 | static void 328 | data_dump_rec(int txidx, int nodeidx, int hdridx, rec_t *rec, struct vsb *data) 329 | { 330 | AN(rec); 331 | AN(data); 332 | 333 | if (rec->magic != RECORD_MAGIC) { 334 | LOG_Log(LOG_ERR, 335 | "Invalid record at tx %d node %d hdr %d, magic = 0x%08x, " 336 | "expected 0x%08x", txidx, nodeidx, hdridx, rec->magic, 337 | RECORD_MAGIC); 338 | return; 339 | } 340 | VSB_printf(data, "%s ", VSL_tags[rec->tag]); 341 | if (rec->len) { 342 | int n = rec->len; 343 | chunk_t *chunk = VSTAILQ_FIRST(&rec->chunks); 344 | while (n > 0 && chunk != NULL) { 345 | if (chunk->magic != CHUNK_MAGIC) { 346 | LOG_Log(LOG_ERR, 347 | "Invalid chunk at tx %d node %d hdr %d, " 348 | "magic = 0x%08x, expected 0x%08x", 349 | txidx, nodeidx, hdridx, chunk->magic, CHUNK_MAGIC); 350 | continue; 351 | } 352 | int cp = n; 353 | if (cp > config.chunk_size) 354 | cp = config.chunk_size; 355 | VSB_bcat(data, chunk->data, cp); 356 | n -= cp; 357 | chunk = VSTAILQ_NEXT(chunk, chunklist); 358 | } 359 | } 360 | } 361 | 362 | void 363 | DATA_Dump(void) 364 | { 365 | struct vsb *data; 366 | 367 | if (txn == NULL) 368 | return; 369 | 370 | data = VSB_new_auto(); 371 | 372 | for (int i = 0; i < config.max_data; i++) { 373 | tx_t *tx; 374 | rec_node_t *rec_node; 375 | 376 | if (txn[i].magic != TX_MAGIC) { 377 | LOG_Log(LOG_ERR, 378 | "Invalid tx at index %d, magic = 0x%08x, expected 0x%08x", 379 | i, txn[i].magic, TX_MAGIC); 380 | continue; 381 | } 382 | 383 | if (txn[i].state == TX_FREE) 384 | continue; 385 | 386 | tx = &txn[i]; 387 | VSB_clear(data); 388 | 389 | VSB_printf(data, 390 | "Tx entry %d: vxid=%u pvxid=%d state=%s dir=%c records={", 391 | i, tx->vxid, tx->pvxid, statename[tx->state], 392 | C(tx->type) ? 'c' : B(tx->type) ? 'b' : '-'); 393 | 394 | for (int j = 0; j < max_idx; j++) { 395 | rec_t *rec; 396 | 397 | rec_node = tx->recs[j]; 398 | AN(rec_node); 399 | if (rec_node->magic != REC_NODE_MAGIC) { 400 | LOG_Log(LOG_ERR, "Invalid rec node at tx %d node %d, " 401 | "magic = 0x%08x, expected 0x%08x", i, j, 402 | rec_node->magic, REC_NODE_MAGIC); 403 | continue; 404 | } 405 | if (rec_node->rec != NULL) { 406 | data_dump_rec(i, j, -1, rec_node->rec, data); 407 | continue; 408 | } 409 | if (rec_node->hdrs == NULL) 410 | continue; 411 | for (int k = 0; rec_node->hdrs[k] != magic_end_rec; k++) { 412 | rec = rec_node->hdrs[k]; 413 | if (rec == NULL) 414 | continue; 415 | data_dump_rec(i, j, k, rec, data); 416 | } 417 | } 418 | 419 | VSB_putc(data, '}'); 420 | VSB_finish(data); 421 | 422 | LOG_Log(LOG_INFO, "%s", VSB_data(data)); 423 | } 424 | } 425 | -------------------------------------------------------------------------------- /src/test/test_hdrtrie.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2012 UPLEX Nils Goroll Systemoptimierung 3 | * Copyright (c) 2012 Otto Gmbh & Co KG 4 | * All rights reserved 5 | * Use only with permission 6 | * 7 | * Author: Geoffrey Simmons 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include 33 | #include 34 | 35 | #include "minunit.h" 36 | 37 | #include "../hdrtrie.h" 38 | 39 | int tests_run = 0; 40 | 41 | static int 42 | next_idx(char c) 43 | { 44 | int n = toupper(c) - 32; 45 | if (c == '~') 46 | n = ':' - 32; 47 | return n; 48 | } 49 | 50 | static char 51 | *test_HDR_FindIdx(void) 52 | { 53 | #define NODES 10 54 | struct hdrt_node hdrt[NODES]; 55 | 56 | printf("... testing HDR_FindIdx()\n"); 57 | 58 | for (int i = 0; i < NODES; i++) { 59 | hdrt[i].magic = HDRT_NODE_MAGIC; 60 | hdrt[i].next = calloc(64, sizeof(struct hdrt_node *)); 61 | } 62 | 63 | hdrt[0].str = strdup("FOO"); 64 | hdrt[0].idx = 4711; 65 | 66 | MASSERT(HDR_FindIdx(&hdrt[0], "Foo:") == 4711); 67 | MASSERT(HDR_FindIdx(&hdrt[0], "Foo: bar") == 4711); 68 | MASSERT(HDR_FindIdx(&hdrt[0], "Foo:bar") == 4711); 69 | MASSERT(HDR_FindIdx(&hdrt[0], "Foo: bar baz") == 4711); 70 | MASSERT(HDR_FindIdx(&hdrt[0], " Foo : ") == 4711); 71 | MASSERT(HDR_FindIdx(&hdrt[0], " fOO : ") == 4711); 72 | 73 | MASSERT(HDR_FindIdx(&hdrt[0], "Bar:") == -1); 74 | MASSERT(HDR_FindIdx(&hdrt[0], " Bar:") == -1); 75 | MASSERT(HDR_FindIdx(&hdrt[0], "Fo:") == -1); 76 | MASSERT(HDR_FindIdx(&hdrt[0], "Food:") == -1); 77 | MASSERT(HDR_FindIdx(&hdrt[0], "Foo bar baz") == -1); 78 | MASSERT(HDR_FindIdx(&hdrt[0], "Foo") == -1); 79 | MASSERT(HDR_FindIdx(&hdrt[0], " Foo ") == -1); 80 | MASSERT(HDR_FindIdx(&hdrt[0], " ") == -1); 81 | MASSERT(HDR_FindIdx(&hdrt[0], "") == -1); 82 | 83 | hdrt[0].str = strdup("ACCEPT"); 84 | hdrt[0].next[next_idx('-')] = &hdrt[1]; 85 | 86 | hdrt[1].str = strdup(""); 87 | hdrt[1].next[next_idx('C')] = &hdrt[2]; 88 | hdrt[1].next[next_idx('E')] = &hdrt[3]; 89 | hdrt[1].next[next_idx('L')] = &hdrt[4]; 90 | hdrt[1].next[next_idx('D')] = &hdrt[5]; 91 | hdrt[1].idx = -1; 92 | 93 | hdrt[2].str = strdup("HARSET"); 94 | hdrt[2].idx = 1; 95 | 96 | hdrt[3].str = strdup("NCODING"); 97 | hdrt[3].idx = 2; 98 | 99 | hdrt[4].str = strdup("ANGUAGE"); 100 | hdrt[4].idx = 3; 101 | 102 | hdrt[5].str = strdup("ATETIME"); 103 | hdrt[5].idx = 4; 104 | 105 | MASSERT(HDR_FindIdx(&hdrt[0], "Accept:") == 4711); 106 | MASSERT(HDR_FindIdx(&hdrt[0], "Accept-Charset:") == 1); 107 | MASSERT(HDR_FindIdx(&hdrt[0], "Accept-Encoding:") == 2); 108 | MASSERT(HDR_FindIdx(&hdrt[0], "Accept-Language:") == 3); 109 | MASSERT(HDR_FindIdx(&hdrt[0], "Accept-Datetime:") == 4); 110 | 111 | MASSERT(HDR_FindIdx(&hdrt[0], "accept:") == 4711); 112 | MASSERT(HDR_FindIdx(&hdrt[0], "accept-charset:") == 1); 113 | MASSERT(HDR_FindIdx(&hdrt[0], "accept-encoding:") == 2); 114 | MASSERT(HDR_FindIdx(&hdrt[0], "accept-language:") == 3); 115 | MASSERT(HDR_FindIdx(&hdrt[0], "accept-datetime:") == 4); 116 | 117 | MASSERT(HDR_FindIdx(&hdrt[0], "Accept-:") == -1); 118 | MASSERT(HDR_FindIdx(&hdrt[0], "Foo:") == -1); 119 | MASSERT(HDR_FindIdx(&hdrt[0], "Accept-Foo:") == -1); 120 | MASSERT(HDR_FindIdx(&hdrt[0], "Accept-CharsetFoo:") == -1); 121 | MASSERT(HDR_FindIdx(&hdrt[0], "Accept-Charse:") == -1); 122 | 123 | hdrt[0].str = strdup("CONTENT-"); 124 | memset(hdrt[0].next, 0, 64 * sizeof(struct hdrt_node *)); 125 | hdrt[0].next[next_idx('D')] = &hdrt[1]; 126 | hdrt[0].next[next_idx('E')] = &hdrt[2]; 127 | hdrt[0].next[next_idx('L')] = &hdrt[3]; 128 | hdrt[0].next[next_idx('M')] = &hdrt[4]; 129 | hdrt[0].next[next_idx('R')] = &hdrt[5]; 130 | hdrt[0].next[next_idx('T')] = &hdrt[6]; 131 | hdrt[0].idx = -1; 132 | 133 | hdrt[1].str = strdup("ISPOSITION"); 134 | memset(hdrt[1].next, 0, 64 * sizeof(struct hdrt_node *)); 135 | hdrt[1].idx = 1; 136 | 137 | hdrt[2].str = strdup("NCODING"); 138 | memset(hdrt[2].next, 0, 64 * sizeof(struct hdrt_node *)); 139 | hdrt[2].idx = 2; 140 | 141 | hdrt[3].str = strdup(""); 142 | memset(hdrt[3].next, 0, 64 * sizeof(struct hdrt_node *)); 143 | hdrt[3].next[next_idx('A')] = &hdrt[7]; 144 | hdrt[3].next[next_idx('E')] = &hdrt[8]; 145 | hdrt[3].next[next_idx('O')] = &hdrt[9]; 146 | hdrt[3].idx = -1; 147 | 148 | hdrt[4].str = strdup("D5"); 149 | memset(hdrt[4].next, 0, 64 * sizeof(struct hdrt_node *)); 150 | hdrt[4].idx = 3; 151 | 152 | hdrt[5].str = strdup("ANGE"); 153 | memset(hdrt[5].next, 0, 64 * sizeof(struct hdrt_node *)); 154 | hdrt[5].idx = 4; 155 | 156 | hdrt[6].str = strdup("YPE"); 157 | hdrt[6].idx = 5; 158 | 159 | hdrt[7].str = strdup("NGUAGE"); 160 | hdrt[7].idx = 6; 161 | 162 | hdrt[8].str = strdup("NGTH"); 163 | hdrt[8].idx = 7; 164 | 165 | hdrt[9].str = strdup("CATION"); 166 | hdrt[9].idx = 8; 167 | 168 | MASSERT(HDR_FindIdx(&hdrt[0], "Content-Disposition:") == 1); 169 | MASSERT(HDR_FindIdx(&hdrt[0], "Content-Encoding:") == 2); 170 | MASSERT(HDR_FindIdx(&hdrt[0], "Content-Language:") == 6); 171 | MASSERT(HDR_FindIdx(&hdrt[0], "Content-Length:") == 7); 172 | MASSERT(HDR_FindIdx(&hdrt[0], "Content-Location:") == 8); 173 | MASSERT(HDR_FindIdx(&hdrt[0], "Content-MD5:") == 3); 174 | MASSERT(HDR_FindIdx(&hdrt[0], "Content-Range:") == 4); 175 | MASSERT(HDR_FindIdx(&hdrt[0], "Content-Type:") == 5); 176 | 177 | MASSERT(HDR_FindIdx(&hdrt[0], "Content-:") == -1); 178 | MASSERT(HDR_FindIdx(&hdrt[0], "Content-L:") == -1); 179 | MASSERT(HDR_FindIdx(&hdrt[0], "Content-La:") == -1); 180 | MASSERT(HDR_FindIdx(&hdrt[0], "Content-Le:") == -1); 181 | MASSERT(HDR_FindIdx(&hdrt[0], "Content-Lo:") == -1); 182 | MASSERT(HDR_FindIdx(&hdrt[0], "Content:") == -1); 183 | MASSERT(HDR_FindIdx(&hdrt[0], "Content-Foo:") == -1); 184 | 185 | hdrt[0].str = strdup("X-"); 186 | memset(hdrt[0].next, 0, 64 * sizeof(struct hdrt_node *)); 187 | hdrt[0].next[next_idx('C')] = &hdrt[1]; 188 | hdrt[0].next[next_idx('F')] = &hdrt[2]; 189 | hdrt[0].idx = -1; 190 | 191 | hdrt[1].str = strdup("SRF-TOKEN"); 192 | memset(hdrt[1].next, 0, 64 * sizeof(struct hdrt_node *)); 193 | hdrt[1].idx = 1; 194 | 195 | hdrt[2].str = strdup("ORWARDED-"); 196 | memset(hdrt[2].next, 0, 64 * sizeof(struct hdrt_node *)); 197 | hdrt[2].next[next_idx('F')] = &hdrt[3]; 198 | hdrt[2].next[next_idx('H')] = &hdrt[4]; 199 | hdrt[2].next[next_idx('P')] = &hdrt[5]; 200 | hdrt[2].idx = -1; 201 | 202 | hdrt[3].str = strdup("OR"); 203 | memset(hdrt[3].next, 0, 64 * sizeof(struct hdrt_node *)); 204 | hdrt[3].idx = 2; 205 | 206 | hdrt[4].str = strdup("OST"); 207 | memset(hdrt[4].next, 0, 64 * sizeof(struct hdrt_node *)); 208 | hdrt[4].idx = 3; 209 | 210 | hdrt[5].str = strdup("ROTO"); 211 | memset(hdrt[5].next, 0, 64 * sizeof(struct hdrt_node *)); 212 | hdrt[5].idx = 4; 213 | 214 | MASSERT(HDR_FindIdx(&hdrt[0], "X-Csrf-Token:") == 1); 215 | MASSERT(HDR_FindIdx(&hdrt[0], "X-Forwarded-For:") == 2); 216 | MASSERT(HDR_FindIdx(&hdrt[0], "X-Forwarded-Host:") == 3); 217 | MASSERT(HDR_FindIdx(&hdrt[0], "X-Forwarded-Proto:") == 4); 218 | 219 | MASSERT(HDR_FindIdx(&hdrt[0], "X-:") == -1); 220 | MASSERT(HDR_FindIdx(&hdrt[0], "X-Forwarded-:") == -1); 221 | MASSERT(HDR_FindIdx(&hdrt[0], "X-Forwarded-F:") == -1); 222 | MASSERT(HDR_FindIdx(&hdrt[0], "X-Forwarded-H:") == -1); 223 | MASSERT(HDR_FindIdx(&hdrt[0], "X-Forwarded-P:") == -1); 224 | 225 | return NULL; 226 | } 227 | 228 | static char 229 | *test_HDR_InsertIdx(void) 230 | { 231 | #define NODES 10 232 | #define SIZEOF_NEXTTBL (64 * sizeof(struct hdrt_node *)) 233 | struct hdrt_node *hdrt, *hdrt2, *next; 234 | 235 | printf("... testing HDR_InsertIdx()\n"); 236 | 237 | next = calloc(64, sizeof(next)); 238 | MAN(next); 239 | 240 | hdrt = HDR_InsertIdx(NULL, "Foo", 4711); 241 | MCHECK_OBJ_NOTNULL(hdrt, HDRT_NODE_MAGIC); 242 | MASSERT(strcmp(hdrt->str, "FOO") == 0); 243 | MASSERT(hdrt->idx == 4711); 244 | MASSERT(memcmp(hdrt->next, next, SIZEOF_NEXTTBL) == 0); 245 | MASSERT(HDR_FindIdx(hdrt, "Foo:") == 4711); 246 | MASSERT(HDR_FindIdx(hdrt, "Foo: bar") == 4711); 247 | MASSERT(HDR_FindIdx(hdrt, "Foo:bar") == 4711); 248 | MASSERT(HDR_FindIdx(hdrt, "Foo: bar baz") == 4711); 249 | MASSERT(HDR_FindIdx(hdrt, " Foo : ") == 4711); 250 | MASSERT(HDR_FindIdx(hdrt, " fOO : ") == 4711); 251 | 252 | MASSERT(HDR_FindIdx(hdrt, "Bar:") == -1); 253 | MASSERT(HDR_FindIdx(hdrt, " Bar:") == -1); 254 | MASSERT(HDR_FindIdx(hdrt, "Fo:") == -1); 255 | MASSERT(HDR_FindIdx(hdrt, "Food:") == -1); 256 | MASSERT(HDR_FindIdx(hdrt, "Foo bar baz") == -1); 257 | MASSERT(HDR_FindIdx(hdrt, "Foo") == -1); 258 | MASSERT(HDR_FindIdx(hdrt, " Foo ") == -1); 259 | MASSERT(HDR_FindIdx(hdrt, " ") == -1); 260 | MASSERT(HDR_FindIdx(hdrt, "") == -1); 261 | 262 | hdrt = HDR_InsertIdx(hdrt, "Foo", 4711); 263 | MCHECK_OBJ_NOTNULL(hdrt, HDRT_NODE_MAGIC); 264 | MASSERT(HDR_FindIdx(hdrt, "Foo:") == 4711); 265 | 266 | hdrt = HDR_InsertIdx(hdrt, "Bar", 1147); 267 | MCHECK_OBJ_NOTNULL(hdrt, HDRT_NODE_MAGIC); 268 | MASSERT(*hdrt->str == '\0'); 269 | MASSERT(hdrt->idx == -1); 270 | for (int i = 0; i < 64; i ++) 271 | if (i != next_idx('B') && i != next_idx('F')) 272 | MAZ(hdrt->next[i]); 273 | hdrt2 = hdrt->next[next_idx('B')]; 274 | MCHECK_OBJ_NOTNULL(hdrt2, HDRT_NODE_MAGIC); 275 | MASSERT(strcmp(hdrt2->str, "AR") == 0); 276 | MASSERT(hdrt2->idx == 1147); 277 | MASSERT(memcmp(hdrt2->next, next, SIZEOF_NEXTTBL) == 0); 278 | hdrt2 = hdrt->next[next_idx('F')]; 279 | MCHECK_OBJ_NOTNULL(hdrt2, HDRT_NODE_MAGIC); 280 | MASSERT(strcmp(hdrt2->str, "OO") == 0); 281 | MASSERT(hdrt2->idx == 4711); 282 | MASSERT(memcmp(hdrt2->next, next, SIZEOF_NEXTTBL) == 0); 283 | MASSERT(HDR_FindIdx(hdrt, "Foo:") == 4711); 284 | MASSERT(HDR_FindIdx(hdrt, "Bar:") == 1147); 285 | 286 | hdrt = HDR_InsertIdx(NULL, "Accept", 1); 287 | MCHECK_OBJ_NOTNULL(hdrt, HDRT_NODE_MAGIC); 288 | hdrt = HDR_InsertIdx(hdrt, "Accept-Encoding", 2); 289 | MCHECK_OBJ_NOTNULL(hdrt, HDRT_NODE_MAGIC); 290 | MASSERT(strcmp(hdrt->str, "ACCEPT") == 0); 291 | MASSERT(hdrt->idx == 1); 292 | for (int i = 0; i < 64; i ++) 293 | if (i != next_idx('-')) 294 | MAZ(hdrt->next[i]); 295 | hdrt2 = hdrt->next[next_idx('-')]; 296 | MCHECK_OBJ_NOTNULL(hdrt2, HDRT_NODE_MAGIC); 297 | MASSERT(strcmp(hdrt2->str, "ENCODING") == 0); 298 | MASSERT(hdrt2->idx == 2); 299 | MASSERT(memcmp(hdrt2->next, next, SIZEOF_NEXTTBL) == 0); 300 | MASSERT(HDR_FindIdx(hdrt, "Accept:") == 1); 301 | MASSERT(HDR_FindIdx(hdrt, "Accept-Encoding:") == 2); 302 | 303 | hdrt = HDR_InsertIdx(hdrt, "Accept-Charset", 3); 304 | MCHECK_OBJ_NOTNULL(hdrt, HDRT_NODE_MAGIC); 305 | hdrt = HDR_InsertIdx(hdrt, "Accept-Language", 4); 306 | MCHECK_OBJ_NOTNULL(hdrt, HDRT_NODE_MAGIC); 307 | hdrt = HDR_InsertIdx(hdrt, "Accept-Datetime", 5); 308 | MCHECK_OBJ_NOTNULL(hdrt, HDRT_NODE_MAGIC); 309 | MASSERT(strcmp(hdrt->str, "ACCEPT") == 0); 310 | MASSERT(hdrt->idx == 1); 311 | for (int i = 0; i < 64; i ++) 312 | if (i != next_idx('-')) 313 | MAZ(hdrt->next[i]); 314 | hdrt2 = hdrt->next[next_idx('-')]; 315 | MCHECK_OBJ_NOTNULL(hdrt2, HDRT_NODE_MAGIC); 316 | MASSERT(*hdrt2->str == '\0'); 317 | MASSERT(hdrt2->idx == -1); 318 | for (int i = 0; i < 64; i ++) 319 | if (i != next_idx('C') && i != next_idx('D') && i != next_idx('E') 320 | && i != next_idx('L')) 321 | MAZ(hdrt2->next[i]); 322 | MCHECK_OBJ_NOTNULL(hdrt2->next[next_idx('C')], HDRT_NODE_MAGIC); 323 | MCHECK_OBJ_NOTNULL(hdrt2->next[next_idx('D')], HDRT_NODE_MAGIC); 324 | MCHECK_OBJ_NOTNULL(hdrt2->next[next_idx('E')], HDRT_NODE_MAGIC); 325 | MCHECK_OBJ_NOTNULL(hdrt2->next[next_idx('L')], HDRT_NODE_MAGIC); 326 | MASSERT(strcmp(hdrt2->next[next_idx('C')]->str, "HARSET") == 0); 327 | MASSERT(hdrt2->next[next_idx('C')]->idx == 3); 328 | MASSERT(strcmp(hdrt2->next[next_idx('D')]->str, "ATETIME") == 0); 329 | MASSERT(hdrt2->next[next_idx('D')]->idx == 5); 330 | MASSERT(strcmp(hdrt2->next[next_idx('E')]->str, "NCODING") == 0); 331 | MASSERT(hdrt2->next[next_idx('E')]->idx == 2); 332 | MASSERT(strcmp(hdrt2->next[next_idx('L')]->str, "ANGUAGE") == 0); 333 | MASSERT(hdrt2->next[next_idx('L')]->idx == 4); 334 | MASSERT(HDR_FindIdx(hdrt, "Accept:") == 1); 335 | MASSERT(HDR_FindIdx(hdrt, "Accept-Charset:") == 3); 336 | MASSERT(HDR_FindIdx(hdrt, "Accept-Encoding:") == 2); 337 | MASSERT(HDR_FindIdx(hdrt, "Accept-Language:") == 4); 338 | MASSERT(HDR_FindIdx(hdrt, "Accept-Datetime:") == 5); 339 | 340 | hdrt = HDR_InsertIdx(NULL, "Accept-Encoding", 4711); 341 | hdrt = HDR_InsertIdx(hdrt, "Accept", 1147); 342 | MASSERT(HDR_FindIdx(hdrt, "Accept:") == 1147); 343 | MASSERT(HDR_FindIdx(hdrt, "Accept-Charset:") == -1); 344 | MASSERT(HDR_FindIdx(hdrt, "Accept-Encoding:") == 4711); 345 | 346 | hdrt = HDR_InsertIdx(NULL, "Content-Disposition", 1); 347 | hdrt = HDR_InsertIdx(hdrt, "Content-Encoding", 2); 348 | hdrt = HDR_InsertIdx(hdrt, "Content-Language", 3); 349 | hdrt = HDR_InsertIdx(hdrt, "Content-Length", 4); 350 | hdrt = HDR_InsertIdx(hdrt, "Content-Location", 5); 351 | hdrt = HDR_InsertIdx(hdrt, "Content-MD5", 6); 352 | hdrt = HDR_InsertIdx(hdrt, "Content-Range", 7); 353 | hdrt = HDR_InsertIdx(hdrt, "Content-Type", 8); 354 | MASSERT(HDR_FindIdx(hdrt, "Content-Disposition:") == 1); 355 | MASSERT(HDR_FindIdx(hdrt, "Content-Encoding:") == 2); 356 | MASSERT(HDR_FindIdx(hdrt, "Content-Language:") == 3); 357 | MASSERT(HDR_FindIdx(hdrt, "Content-Length:") == 4); 358 | MASSERT(HDR_FindIdx(hdrt, "Content-Location:") == 5); 359 | MASSERT(HDR_FindIdx(hdrt, "Content-MD5:") == 6); 360 | MASSERT(HDR_FindIdx(hdrt, "Content-Range:") == 7); 361 | MASSERT(HDR_FindIdx(hdrt, "Content-Type:") == 8); 362 | 363 | MASSERT(HDR_FindIdx(hdrt, "Content-:") == -1); 364 | MASSERT(HDR_FindIdx(hdrt, "Content-L:") == -1); 365 | MASSERT(HDR_FindIdx(hdrt, "Content-La:") == -1); 366 | MASSERT(HDR_FindIdx(hdrt, "Content-Le:") == -1); 367 | MASSERT(HDR_FindIdx(hdrt, "Content-Lo:") == -1); 368 | MASSERT(HDR_FindIdx(hdrt, "Content:") == -1); 369 | MASSERT(HDR_FindIdx(hdrt, "Content-Foo:") == -1); 370 | 371 | hdrt = HDR_InsertIdx(NULL, "X-Csrf-Token", 11); 372 | hdrt = HDR_InsertIdx(hdrt, "X-Forwarded-For", 12); 373 | hdrt = HDR_InsertIdx(hdrt, "X-Forwarded-Host", 13); 374 | hdrt = HDR_InsertIdx(hdrt, "X-Forwarded-Proto", 14); 375 | 376 | MASSERT(HDR_FindIdx(hdrt, "X-Csrf-Token:") == 11); 377 | MASSERT(HDR_FindIdx(hdrt, "X-Forwarded-For:") == 12); 378 | MASSERT(HDR_FindIdx(hdrt, "X-Forwarded-Host:") == 13); 379 | MASSERT(HDR_FindIdx(hdrt, "X-Forwarded-Proto:") == 14); 380 | 381 | MASSERT(HDR_FindIdx(hdrt, "X-:") == -1); 382 | MASSERT(HDR_FindIdx(hdrt, "X-Forwarded-:") == -1); 383 | MASSERT(HDR_FindIdx(hdrt, "X-Forwarded-F:") == -1); 384 | MASSERT(HDR_FindIdx(hdrt, "X-Forwarded-H:") == -1); 385 | MASSERT(HDR_FindIdx(hdrt, "X-Forwarded-P:") == -1); 386 | 387 | hdrt = HDR_InsertIdx(NULL, "Beresp", 0); 388 | hdrt = HDR_InsertIdx(hdrt, "BerespBody", 1); 389 | hdrt = HDR_InsertIdx(hdrt, "Bereq", 2); 390 | MASSERT(HDR_FindIdx(hdrt, "Beresp:") == 0); 391 | MASSERT(HDR_FindIdx(hdrt, "BerespBody:") == 1); 392 | MASSERT(HDR_FindIdx(hdrt, "Bereq:") == 2); 393 | 394 | return NULL; 395 | } 396 | 397 | static char 398 | *test_HDR_N(void) 399 | { 400 | struct hdrt_node *hdrt; 401 | 402 | printf("... testing HDR_N()\n"); 403 | 404 | MAZ(HDR_N(NULL)); 405 | 406 | hdrt = HDR_InsertIdx(NULL, "Foo", 4711); 407 | MASSERT(HDR_N(hdrt) == 1); 408 | 409 | hdrt = HDR_InsertIdx(NULL, "Accept-Encoding", 1); 410 | hdrt = HDR_InsertIdx(hdrt, "Accept", 2); 411 | hdrt = HDR_InsertIdx(hdrt, "Accept-Charset", 3); 412 | hdrt = HDR_InsertIdx(hdrt, "Accept-Language", 4); 413 | hdrt = HDR_InsertIdx(hdrt, "Accept-Datetime", 5); 414 | MASSERT(HDR_N(hdrt) == 5); 415 | 416 | hdrt = HDR_InsertIdx(NULL, "Content-Disposition", 1); 417 | hdrt = HDR_InsertIdx(hdrt, "Content-Encoding", 2); 418 | hdrt = HDR_InsertIdx(hdrt, "Content-Language", 3); 419 | hdrt = HDR_InsertIdx(hdrt, "Content-Length", 4); 420 | hdrt = HDR_InsertIdx(hdrt, "Content-Location", 5); 421 | hdrt = HDR_InsertIdx(hdrt, "Content-MD5", 6); 422 | hdrt = HDR_InsertIdx(hdrt, "Content-Range", 7); 423 | hdrt = HDR_InsertIdx(hdrt, "Content-Type", 8); 424 | MASSERT(HDR_N(hdrt) == 8); 425 | 426 | hdrt = HDR_InsertIdx(NULL, "X-Csrf-Token", 1); 427 | hdrt = HDR_InsertIdx(hdrt, "X-Forwarded-For", 2); 428 | hdrt = HDR_InsertIdx(hdrt, "X-Forwarded-Host", 3); 429 | hdrt = HDR_InsertIdx(hdrt, "X-Forwarded-Proto", 4); 430 | MASSERT(HDR_N(hdrt) == 4); 431 | 432 | hdrt = HDR_InsertIdx(NULL, "Beresp", 0); 433 | hdrt = HDR_InsertIdx(hdrt, "BerespBody", 1); 434 | hdrt = HDR_InsertIdx(hdrt, "Bereq", 2); 435 | MASSERT(HDR_N(hdrt) == 3); 436 | 437 | return NULL; 438 | } 439 | 440 | static char 441 | *test_HDR_List(void) 442 | { 443 | struct hdrt_node *hdrt; 444 | struct vsb *sb = VSB_new_auto(); 445 | 446 | printf("... testing HDR_List()\n"); 447 | 448 | HDR_List(NULL, sb); 449 | VSB_finish(sb); 450 | MASSERT(VSB_error(sb) == 0); 451 | MASSERT(VSB_len(sb) == 0); 452 | 453 | VSB_clear(sb); 454 | hdrt = HDR_InsertIdx(NULL, "Foo", 4711); 455 | HDR_List(hdrt, sb); 456 | VSB_finish(sb); 457 | MASSERT(VSB_error(sb) == 0); 458 | MASSERT(strcasecmp(VSB_data(sb), "Foo,") == 0); 459 | 460 | #define EXP "Accept,Accept-Charset,Accept-Datetime,Accept-Encoding," \ 461 | "Accept-Language," 462 | VSB_clear(sb); 463 | hdrt = HDR_InsertIdx(NULL, "Accept-Encoding", 1); 464 | hdrt = HDR_InsertIdx(hdrt, "Accept", 2); 465 | hdrt = HDR_InsertIdx(hdrt, "Accept-Charset", 3); 466 | hdrt = HDR_InsertIdx(hdrt, "Accept-Language", 4); 467 | hdrt = HDR_InsertIdx(hdrt, "Accept-Datetime", 5); 468 | HDR_List(hdrt, sb); 469 | VSB_finish(sb); 470 | MASSERT(VSB_error(sb) == 0); 471 | MASSERT(strcasecmp(VSB_data(sb), EXP) == 0); 472 | #undef EXP 473 | 474 | #define EXP "Content-Disposition,Content-Encoding,Content-Language," \ 475 | "Content-Length,Content-Location,Content-MD5,Content-Range," \ 476 | "Content-Type," 477 | VSB_clear(sb); 478 | hdrt = HDR_InsertIdx(NULL, "Content-Disposition", 1); 479 | hdrt = HDR_InsertIdx(hdrt, "Content-Encoding", 2); 480 | hdrt = HDR_InsertIdx(hdrt, "Content-Language", 3); 481 | hdrt = HDR_InsertIdx(hdrt, "Content-Length", 4); 482 | hdrt = HDR_InsertIdx(hdrt, "Content-Location", 5); 483 | hdrt = HDR_InsertIdx(hdrt, "Content-MD5", 6); 484 | hdrt = HDR_InsertIdx(hdrt, "Content-Range", 7); 485 | hdrt = HDR_InsertIdx(hdrt, "Content-Type", 8); 486 | HDR_List(hdrt, sb); 487 | VSB_finish(sb); 488 | MASSERT(VSB_error(sb) == 0); 489 | MASSERT(strcasecmp(VSB_data(sb), EXP) == 0); 490 | #undef EXP 491 | 492 | #define EXP "X-Csrf-Token,X-Forwarded-For,X-Forwarded-Host,X-Forwarded-Proto," 493 | VSB_clear(sb); 494 | hdrt = HDR_InsertIdx(NULL, "X-Csrf-Token", 1); 495 | hdrt = HDR_InsertIdx(hdrt, "X-Forwarded-For", 2); 496 | hdrt = HDR_InsertIdx(hdrt, "X-Forwarded-Host", 3); 497 | hdrt = HDR_InsertIdx(hdrt, "X-Forwarded-Proto", 4); 498 | HDR_List(hdrt, sb); 499 | VSB_finish(sb); 500 | MASSERT(VSB_error(sb) == 0); 501 | MASSERT(strcasecmp(VSB_data(sb), EXP) == 0); 502 | #undef EXP 503 | 504 | #define EXP "Bereq,Beresp,BerespBody," 505 | VSB_clear(sb); 506 | hdrt = HDR_InsertIdx(NULL, "Beresp", 0); 507 | hdrt = HDR_InsertIdx(hdrt, "BerespBody", 1); 508 | hdrt = HDR_InsertIdx(hdrt, "Bereq", 2); 509 | HDR_List(hdrt, sb); 510 | VSB_finish(sb); 511 | MASSERT(VSB_error(sb) == 0); 512 | MASSERT(strcasecmp(VSB_data(sb), EXP) == 0); 513 | #undef EXP 514 | 515 | VSB_destroy(&sb); 516 | 517 | return NULL; 518 | } 519 | 520 | static char 521 | *test_HDR_Fini(void) 522 | { 523 | struct hdrt_node *hdrt; 524 | 525 | printf("... testing HDR_Fini()\n"); 526 | 527 | hdrt = HDR_InsertIdx(NULL, "Content-Disposition", 1); 528 | hdrt = HDR_InsertIdx(hdrt, "Content-Encoding", 2); 529 | hdrt = HDR_InsertIdx(hdrt, "Content-Language", 3); 530 | hdrt = HDR_InsertIdx(hdrt, "Content-Length", 4); 531 | hdrt = HDR_InsertIdx(hdrt, "Content-Location", 5); 532 | hdrt = HDR_InsertIdx(hdrt, "Content-MD5", 6); 533 | hdrt = HDR_InsertIdx(hdrt, "Content-Range", 7); 534 | hdrt = HDR_InsertIdx(hdrt, "Content-Type", 8); 535 | MCHECK_OBJ_NOTNULL(hdrt, HDRT_NODE_MAGIC); 536 | 537 | HDR_Fini(hdrt); 538 | MASSERT(hdrt == NULL || hdrt->magic != HDRT_NODE_MAGIC); 539 | 540 | return NULL; 541 | } 542 | 543 | static const char 544 | *all_tests(void) 545 | { 546 | mu_run_test(test_HDR_FindIdx); 547 | mu_run_test(test_HDR_InsertIdx); 548 | mu_run_test(test_HDR_N); 549 | mu_run_test(test_HDR_List); 550 | mu_run_test(test_HDR_Fini); 551 | return NULL; 552 | } 553 | 554 | TEST_RUNNER 555 | --------------------------------------------------------------------------------