aboutsummaryrefslogtreecommitdiff
path: root/libevent-2.0.20-stable/test
diff options
context:
space:
mode:
authorBjørn Mork <bjorn@mork.no>2015-05-15 10:22:43 +0200
committerBjørn Mork <bjorn@mork.no>2015-05-15 10:22:43 +0200
commit9b3dbb454e8f8a463d5fe4541ee2001585527bc6 (patch)
tree565eb0531cd8d3427f4e04445972ff340afb2a41 /libevent-2.0.20-stable/test
parent73b16af8feec390afbabd9356d6e5e83c0390838 (diff)
libevent: imported from https://github.com/downloads/libevent/libevent/libevent-2.0.20-stable.tar.gzlibevent-2.0.20
Signed-off-by: Bjørn Mork <bjorn@mork.no>
Diffstat (limited to 'libevent-2.0.20-stable/test')
-rw-r--r--libevent-2.0.20-stable/test/Makefile.am98
-rw-r--r--libevent-2.0.20-stable/test/Makefile.in1047
-rw-r--r--libevent-2.0.20-stable/test/Makefile.nmake61
-rw-r--r--libevent-2.0.20-stable/test/bench.c196
-rw-r--r--libevent-2.0.20-stable/test/bench_cascade.c177
-rw-r--r--libevent-2.0.20-stable/test/bench_http.c191
-rw-r--r--libevent-2.0.20-stable/test/bench_httpclient.c223
-rw-r--r--libevent-2.0.20-stable/test/regress.c2489
-rw-r--r--libevent-2.0.20-stable/test/regress.gen.c1225
-rw-r--r--libevent-2.0.20-stable/test/regress.gen.h207
-rw-r--r--libevent-2.0.20-stable/test/regress.h129
-rw-r--r--libevent-2.0.20-stable/test/regress.rpc25
-rw-r--r--libevent-2.0.20-stable/test/regress_buffer.c1677
-rw-r--r--libevent-2.0.20-stable/test/regress_bufferevent.c841
-rw-r--r--libevent-2.0.20-stable/test/regress_dns.c1855
-rw-r--r--libevent-2.0.20-stable/test/regress_et.c207
-rw-r--r--libevent-2.0.20-stable/test/regress_http.c3621
-rw-r--r--libevent-2.0.20-stable/test/regress_iocp.c352
-rw-r--r--libevent-2.0.20-stable/test/regress_listener.c214
-rw-r--r--libevent-2.0.20-stable/test/regress_main.c421
-rw-r--r--libevent-2.0.20-stable/test/regress_minheap.c98
-rw-r--r--libevent-2.0.20-stable/test/regress_rpc.c898
-rw-r--r--libevent-2.0.20-stable/test/regress_ssl.c450
-rw-r--r--libevent-2.0.20-stable/test/regress_testutils.c220
-rw-r--r--libevent-2.0.20-stable/test/regress_testutils.h66
-rw-r--r--libevent-2.0.20-stable/test/regress_thread.c511
-rw-r--r--libevent-2.0.20-stable/test/regress_util.c1094
-rw-r--r--libevent-2.0.20-stable/test/regress_zlib.c344
-rwxr-xr-xlibevent-2.0.20-stable/test/rpcgen_wrapper.sh41
-rw-r--r--libevent-2.0.20-stable/test/test-changelist.c224
-rw-r--r--libevent-2.0.20-stable/test/test-eof.c125
-rw-r--r--libevent-2.0.20-stable/test/test-init.c66
-rw-r--r--libevent-2.0.20-stable/test/test-ratelim.c479
-rw-r--r--libevent-2.0.20-stable/test/test-time.c114
-rw-r--r--libevent-2.0.20-stable/test/test-weof.c118
-rwxr-xr-xlibevent-2.0.20-stable/test/test.sh163
-rw-r--r--libevent-2.0.20-stable/test/tinytest.c400
-rw-r--r--libevent-2.0.20-stable/test/tinytest.h87
-rw-r--r--libevent-2.0.20-stable/test/tinytest_local.h12
-rw-r--r--libevent-2.0.20-stable/test/tinytest_macros.h184
40 files changed, 20950 insertions, 0 deletions
diff --git a/libevent-2.0.20-stable/test/Makefile.am b/libevent-2.0.20-stable/test/Makefile.am
new file mode 100644
index 0000000..b10c41a
--- /dev/null
+++ b/libevent-2.0.20-stable/test/Makefile.am
@@ -0,0 +1,98 @@
+# test/Makefile.am for libevent
+# Copyright 2000-2007 Niels Provos
+# Copyright 2007-2012 Niels Provos and Nick Mathewson
+#
+# See LICENSE for copying information.
+
+AUTOMAKE_OPTIONS = foreign
+
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat -I$(top_srcdir)/include -I../include -DTINYTEST_LOCAL
+
+EXTRA_DIST = regress.rpc regress.gen.h regress.gen.c rpcgen_wrapper.sh test.sh
+
+noinst_PROGRAMS = test-init test-eof test-weof test-time \
+ bench bench_cascade bench_http bench_httpclient test-ratelim \
+ test-changelist
+if BUILD_REGRESS
+noinst_PROGRAMS += regress
+endif
+EXTRA_PROGRAMS = regress
+noinst_HEADERS = tinytest.h tinytest_macros.h regress.h tinytest_local.h
+
+TESTS = $(top_srcdir)/test/test.sh
+
+BUILT_SOURCES =
+if BUILD_REGRESS
+BUILT_SOURCES += regress.gen.c regress.gen.h
+endif
+
+test_init_SOURCES = test-init.c
+test_init_LDADD = ../libevent_core.la
+test_eof_SOURCES = test-eof.c
+test_eof_LDADD = ../libevent_core.la
+test_changelist_SOURCES = test-changelist.c
+test_changelist_LDADD = ../libevent_core.la
+test_weof_SOURCES = test-weof.c
+test_weof_LDADD = ../libevent_core.la
+test_time_SOURCES = test-time.c
+test_time_LDADD = ../libevent_core.la
+test_ratelim_SOURCES = test-ratelim.c
+test_ratelim_LDADD = ../libevent_core.la -lm
+
+regress_SOURCES = regress.c regress_buffer.c regress_http.c regress_dns.c \
+ regress_testutils.c regress_testutils.h \
+ regress_rpc.c regress.gen.c regress.gen.h regress_et.c \
+ regress_bufferevent.c regress_listener.c \
+ regress_util.c tinytest.c regress_main.c regress_minheap.c \
+ $(regress_thread_SOURCES) $(regress_zlib_SOURCES)
+if PTHREADS
+regress_thread_SOURCES = regress_thread.c
+PTHREAD_LIBS += ../libevent_pthreads.la
+endif
+if BUILD_WIN32
+regress_thread_SOURCES = regress_thread.c
+endif
+if ZLIB_REGRESS
+regress_zlib_SOURCES = regress_zlib.c
+endif
+if BUILD_WIN32
+regress_SOURCES += regress_iocp.c
+endif
+
+regress_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la $(PTHREAD_LIBS) $(ZLIB_LIBS)
+regress_CPPFLAGS = $(AM_CPPFLAGS) $(PTHREAD_CFLAGS) $(ZLIB_CFLAGS)
+regress_LDFLAGS = $(PTHREAD_CFLAGS)
+
+if OPENSSL
+regress_SOURCES += regress_ssl.c
+regress_LDADD += ../libevent_openssl.la -lssl -lcrypto ${OPENSSL_LIBADD}
+endif
+
+bench_SOURCES = bench.c
+bench_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la
+bench_cascade_SOURCES = bench_cascade.c
+bench_cascade_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la
+bench_http_SOURCES = bench_http.c
+bench_http_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la
+bench_httpclient_SOURCES = bench_httpclient.c
+bench_httpclient_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent_core.la
+
+regress.gen.c regress.gen.h: rpcgen-attempted
+
+rpcgen-attempted: $(srcdir)/regress.rpc $(srcdir)/../event_rpcgen.py $(srcdir)/rpcgen_wrapper.sh
+ date -u > $@
+ if $(srcdir)/rpcgen_wrapper.sh $(srcdir); then \
+ echo "rpcgen okay"; \
+ else \
+ echo "No Python installed; stubbing out RPC test." >&2; \
+ echo " "> regress.gen.c; \
+ echo "#define NO_PYTHON_EXISTS" > regress.gen.h; \
+ fi
+
+CLEANFILES = rpcgen-attempted
+
+DISTCLEANFILES = *~
+
+verify: check
+
+bench test-init test-eof test-weof test-time test-changelist: ../libevent.la
diff --git a/libevent-2.0.20-stable/test/Makefile.in b/libevent-2.0.20-stable/test/Makefile.in
new file mode 100644
index 0000000..a8c3838
--- /dev/null
+++ b/libevent-2.0.20-stable/test/Makefile.in
@@ -0,0 +1,1047 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# test/Makefile.am for libevent
+# Copyright 2000-2007 Niels Provos
+# Copyright 2007-2012 Niels Provos and Nick Mathewson
+#
+# See LICENSE for copying information.
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+noinst_PROGRAMS = test-init$(EXEEXT) test-eof$(EXEEXT) \
+ test-weof$(EXEEXT) test-time$(EXEEXT) bench$(EXEEXT) \
+ bench_cascade$(EXEEXT) bench_http$(EXEEXT) \
+ bench_httpclient$(EXEEXT) test-ratelim$(EXEEXT) \
+ test-changelist$(EXEEXT) $(am__EXEEXT_1)
+@BUILD_REGRESS_TRUE@am__append_1 = regress
+EXTRA_PROGRAMS = regress$(EXEEXT)
+@BUILD_REGRESS_TRUE@am__append_2 = regress.gen.c regress.gen.h
+@PTHREADS_TRUE@am__append_3 = ../libevent_pthreads.la
+@BUILD_WIN32_TRUE@am__append_4 = regress_iocp.c
+@OPENSSL_TRUE@am__append_5 = regress_ssl.c
+@OPENSSL_TRUE@am__append_6 = ../libevent_openssl.la -lssl -lcrypto ${OPENSSL_LIBADD}
+subdir = test
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+@BUILD_REGRESS_TRUE@am__EXEEXT_1 = regress$(EXEEXT)
+PROGRAMS = $(noinst_PROGRAMS)
+am_bench_OBJECTS = bench.$(OBJEXT)
+bench_OBJECTS = $(am_bench_OBJECTS)
+am__DEPENDENCIES_1 =
+bench_DEPENDENCIES = $(am__DEPENDENCIES_1) ../libevent.la
+am_bench_cascade_OBJECTS = bench_cascade.$(OBJEXT)
+bench_cascade_OBJECTS = $(am_bench_cascade_OBJECTS)
+bench_cascade_DEPENDENCIES = $(am__DEPENDENCIES_1) ../libevent.la
+am_bench_http_OBJECTS = bench_http.$(OBJEXT)
+bench_http_OBJECTS = $(am_bench_http_OBJECTS)
+bench_http_DEPENDENCIES = $(am__DEPENDENCIES_1) ../libevent.la
+am_bench_httpclient_OBJECTS = bench_httpclient.$(OBJEXT)
+bench_httpclient_OBJECTS = $(am_bench_httpclient_OBJECTS)
+bench_httpclient_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ ../libevent_core.la
+am__regress_SOURCES_DIST = regress.c regress_buffer.c regress_http.c \
+ regress_dns.c regress_testutils.c regress_testutils.h \
+ regress_rpc.c regress.gen.c regress.gen.h regress_et.c \
+ regress_bufferevent.c regress_listener.c regress_util.c \
+ tinytest.c regress_main.c regress_minheap.c regress_thread.c \
+ regress_zlib.c regress_iocp.c regress_ssl.c
+@BUILD_WIN32_FALSE@@PTHREADS_TRUE@am__objects_1 = regress-regress_thread.$(OBJEXT)
+@BUILD_WIN32_TRUE@am__objects_1 = regress-regress_thread.$(OBJEXT)
+@ZLIB_REGRESS_TRUE@am__objects_2 = regress-regress_zlib.$(OBJEXT)
+@BUILD_WIN32_TRUE@am__objects_3 = regress-regress_iocp.$(OBJEXT)
+@OPENSSL_TRUE@am__objects_4 = regress-regress_ssl.$(OBJEXT)
+am_regress_OBJECTS = regress-regress.$(OBJEXT) \
+ regress-regress_buffer.$(OBJEXT) \
+ regress-regress_http.$(OBJEXT) regress-regress_dns.$(OBJEXT) \
+ regress-regress_testutils.$(OBJEXT) \
+ regress-regress_rpc.$(OBJEXT) regress-regress.gen.$(OBJEXT) \
+ regress-regress_et.$(OBJEXT) \
+ regress-regress_bufferevent.$(OBJEXT) \
+ regress-regress_listener.$(OBJEXT) \
+ regress-regress_util.$(OBJEXT) regress-tinytest.$(OBJEXT) \
+ regress-regress_main.$(OBJEXT) \
+ regress-regress_minheap.$(OBJEXT) $(am__objects_1) \
+ $(am__objects_2) $(am__objects_3) $(am__objects_4)
+regress_OBJECTS = $(am_regress_OBJECTS)
+am__DEPENDENCIES_2 = $(am__append_3)
+@OPENSSL_TRUE@am__DEPENDENCIES_3 = ../libevent_openssl.la \
+@OPENSSL_TRUE@ $(am__DEPENDENCIES_1)
+regress_DEPENDENCIES = $(am__DEPENDENCIES_1) ../libevent.la \
+ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_3)
+regress_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(regress_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am_test_changelist_OBJECTS = test-changelist.$(OBJEXT)
+test_changelist_OBJECTS = $(am_test_changelist_OBJECTS)
+test_changelist_DEPENDENCIES = ../libevent_core.la
+am_test_eof_OBJECTS = test-eof.$(OBJEXT)
+test_eof_OBJECTS = $(am_test_eof_OBJECTS)
+test_eof_DEPENDENCIES = ../libevent_core.la
+am_test_init_OBJECTS = test-init.$(OBJEXT)
+test_init_OBJECTS = $(am_test_init_OBJECTS)
+test_init_DEPENDENCIES = ../libevent_core.la
+am_test_ratelim_OBJECTS = test-ratelim.$(OBJEXT)
+test_ratelim_OBJECTS = $(am_test_ratelim_OBJECTS)
+test_ratelim_DEPENDENCIES = ../libevent_core.la
+am_test_time_OBJECTS = test-time.$(OBJEXT)
+test_time_OBJECTS = $(am_test_time_OBJECTS)
+test_time_DEPENDENCIES = ../libevent_core.la
+am_test_weof_OBJECTS = test-weof.$(OBJEXT)
+test_weof_OBJECTS = $(am_test_weof_OBJECTS)
+test_weof_DEPENDENCIES = ../libevent_core.la
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(bench_SOURCES) $(bench_cascade_SOURCES) \
+ $(bench_http_SOURCES) $(bench_httpclient_SOURCES) \
+ $(regress_SOURCES) $(test_changelist_SOURCES) \
+ $(test_eof_SOURCES) $(test_init_SOURCES) \
+ $(test_ratelim_SOURCES) $(test_time_SOURCES) \
+ $(test_weof_SOURCES)
+DIST_SOURCES = $(bench_SOURCES) $(bench_cascade_SOURCES) \
+ $(bench_http_SOURCES) $(bench_httpclient_SOURCES) \
+ $(am__regress_SOURCES_DIST) $(test_changelist_SOURCES) \
+ $(test_eof_SOURCES) $(test_init_SOURCES) \
+ $(test_ratelim_SOURCES) $(test_time_SOURCES) \
+ $(test_weof_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors = \
+red=; grn=; lgn=; blu=; std=
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EV_LIB_GDI = @EV_LIB_GDI@
+EV_LIB_WS32 = @EV_LIB_WS32@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBEVENT_GC_SECTIONS = @LIBEVENT_GC_SECTIONS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_LIBADD = @OPENSSL_LIBADD@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@ $(am__append_3)
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = foreign
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat -I$(top_srcdir)/include -I../include -DTINYTEST_LOCAL
+EXTRA_DIST = regress.rpc regress.gen.h regress.gen.c rpcgen_wrapper.sh test.sh
+noinst_HEADERS = tinytest.h tinytest_macros.h regress.h tinytest_local.h
+TESTS = $(top_srcdir)/test/test.sh
+BUILT_SOURCES = $(am__append_2)
+test_init_SOURCES = test-init.c
+test_init_LDADD = ../libevent_core.la
+test_eof_SOURCES = test-eof.c
+test_eof_LDADD = ../libevent_core.la
+test_changelist_SOURCES = test-changelist.c
+test_changelist_LDADD = ../libevent_core.la
+test_weof_SOURCES = test-weof.c
+test_weof_LDADD = ../libevent_core.la
+test_time_SOURCES = test-time.c
+test_time_LDADD = ../libevent_core.la
+test_ratelim_SOURCES = test-ratelim.c
+test_ratelim_LDADD = ../libevent_core.la -lm
+regress_SOURCES = regress.c regress_buffer.c regress_http.c \
+ regress_dns.c regress_testutils.c regress_testutils.h \
+ regress_rpc.c regress.gen.c regress.gen.h regress_et.c \
+ regress_bufferevent.c regress_listener.c regress_util.c \
+ tinytest.c regress_main.c regress_minheap.c \
+ $(regress_thread_SOURCES) $(regress_zlib_SOURCES) \
+ $(am__append_4) $(am__append_5)
+@BUILD_WIN32_TRUE@regress_thread_SOURCES = regress_thread.c
+@PTHREADS_TRUE@regress_thread_SOURCES = regress_thread.c
+@ZLIB_REGRESS_TRUE@regress_zlib_SOURCES = regress_zlib.c
+regress_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la $(PTHREAD_LIBS) \
+ $(ZLIB_LIBS) $(am__append_6)
+regress_CPPFLAGS = $(AM_CPPFLAGS) $(PTHREAD_CFLAGS) $(ZLIB_CFLAGS)
+regress_LDFLAGS = $(PTHREAD_CFLAGS)
+bench_SOURCES = bench.c
+bench_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la
+bench_cascade_SOURCES = bench_cascade.c
+bench_cascade_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la
+bench_http_SOURCES = bench_http.c
+bench_http_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la
+bench_httpclient_SOURCES = bench_httpclient.c
+bench_httpclient_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent_core.la
+CLEANFILES = rpcgen-attempted
+DISTCLEANFILES = *~
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign test/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+bench$(EXEEXT): $(bench_OBJECTS) $(bench_DEPENDENCIES) $(EXTRA_bench_DEPENDENCIES)
+ @rm -f bench$(EXEEXT)
+ $(LINK) $(bench_OBJECTS) $(bench_LDADD) $(LIBS)
+bench_cascade$(EXEEXT): $(bench_cascade_OBJECTS) $(bench_cascade_DEPENDENCIES) $(EXTRA_bench_cascade_DEPENDENCIES)
+ @rm -f bench_cascade$(EXEEXT)
+ $(LINK) $(bench_cascade_OBJECTS) $(bench_cascade_LDADD) $(LIBS)
+bench_http$(EXEEXT): $(bench_http_OBJECTS) $(bench_http_DEPENDENCIES) $(EXTRA_bench_http_DEPENDENCIES)
+ @rm -f bench_http$(EXEEXT)
+ $(LINK) $(bench_http_OBJECTS) $(bench_http_LDADD) $(LIBS)
+bench_httpclient$(EXEEXT): $(bench_httpclient_OBJECTS) $(bench_httpclient_DEPENDENCIES) $(EXTRA_bench_httpclient_DEPENDENCIES)
+ @rm -f bench_httpclient$(EXEEXT)
+ $(LINK) $(bench_httpclient_OBJECTS) $(bench_httpclient_LDADD) $(LIBS)
+regress$(EXEEXT): $(regress_OBJECTS) $(regress_DEPENDENCIES) $(EXTRA_regress_DEPENDENCIES)
+ @rm -f regress$(EXEEXT)
+ $(regress_LINK) $(regress_OBJECTS) $(regress_LDADD) $(LIBS)
+test-changelist$(EXEEXT): $(test_changelist_OBJECTS) $(test_changelist_DEPENDENCIES) $(EXTRA_test_changelist_DEPENDENCIES)
+ @rm -f test-changelist$(EXEEXT)
+ $(LINK) $(test_changelist_OBJECTS) $(test_changelist_LDADD) $(LIBS)
+test-eof$(EXEEXT): $(test_eof_OBJECTS) $(test_eof_DEPENDENCIES) $(EXTRA_test_eof_DEPENDENCIES)
+ @rm -f test-eof$(EXEEXT)
+ $(LINK) $(test_eof_OBJECTS) $(test_eof_LDADD) $(LIBS)
+test-init$(EXEEXT): $(test_init_OBJECTS) $(test_init_DEPENDENCIES) $(EXTRA_test_init_DEPENDENCIES)
+ @rm -f test-init$(EXEEXT)
+ $(LINK) $(test_init_OBJECTS) $(test_init_LDADD) $(LIBS)
+test-ratelim$(EXEEXT): $(test_ratelim_OBJECTS) $(test_ratelim_DEPENDENCIES) $(EXTRA_test_ratelim_DEPENDENCIES)
+ @rm -f test-ratelim$(EXEEXT)
+ $(LINK) $(test_ratelim_OBJECTS) $(test_ratelim_LDADD) $(LIBS)
+test-time$(EXEEXT): $(test_time_OBJECTS) $(test_time_DEPENDENCIES) $(EXTRA_test_time_DEPENDENCIES)
+ @rm -f test-time$(EXEEXT)
+ $(LINK) $(test_time_OBJECTS) $(test_time_LDADD) $(LIBS)
+test-weof$(EXEEXT): $(test_weof_OBJECTS) $(test_weof_DEPENDENCIES) $(EXTRA_test_weof_DEPENDENCIES)
+ @rm -f test-weof$(EXEEXT)
+ $(LINK) $(test_weof_OBJECTS) $(test_weof_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bench.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bench_cascade.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bench_http.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bench_httpclient.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress.gen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_buffer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_bufferevent.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_dns.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_et.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_http.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_iocp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_listener.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_minheap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_rpc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_ssl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_testutils.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_thread.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_util.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_zlib.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-tinytest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-changelist.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-eof.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-init.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-ratelim.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-time.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-weof.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+regress-regress.o: regress.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress.o -MD -MP -MF $(DEPDIR)/regress-regress.Tpo -c -o regress-regress.o `test -f 'regress.c' || echo '$(srcdir)/'`regress.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress.Tpo $(DEPDIR)/regress-regress.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress.c' object='regress-regress.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress.o `test -f 'regress.c' || echo '$(srcdir)/'`regress.c
+
+regress-regress.obj: regress.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress.obj -MD -MP -MF $(DEPDIR)/regress-regress.Tpo -c -o regress-regress.obj `if test -f 'regress.c'; then $(CYGPATH_W) 'regress.c'; else $(CYGPATH_W) '$(srcdir)/regress.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress.Tpo $(DEPDIR)/regress-regress.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress.c' object='regress-regress.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress.obj `if test -f 'regress.c'; then $(CYGPATH_W) 'regress.c'; else $(CYGPATH_W) '$(srcdir)/regress.c'; fi`
+
+regress-regress_buffer.o: regress_buffer.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_buffer.o -MD -MP -MF $(DEPDIR)/regress-regress_buffer.Tpo -c -o regress-regress_buffer.o `test -f 'regress_buffer.c' || echo '$(srcdir)/'`regress_buffer.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_buffer.Tpo $(DEPDIR)/regress-regress_buffer.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_buffer.c' object='regress-regress_buffer.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_buffer.o `test -f 'regress_buffer.c' || echo '$(srcdir)/'`regress_buffer.c
+
+regress-regress_buffer.obj: regress_buffer.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_buffer.obj -MD -MP -MF $(DEPDIR)/regress-regress_buffer.Tpo -c -o regress-regress_buffer.obj `if test -f 'regress_buffer.c'; then $(CYGPATH_W) 'regress_buffer.c'; else $(CYGPATH_W) '$(srcdir)/regress_buffer.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_buffer.Tpo $(DEPDIR)/regress-regress_buffer.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_buffer.c' object='regress-regress_buffer.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_buffer.obj `if test -f 'regress_buffer.c'; then $(CYGPATH_W) 'regress_buffer.c'; else $(CYGPATH_W) '$(srcdir)/regress_buffer.c'; fi`
+
+regress-regress_http.o: regress_http.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_http.o -MD -MP -MF $(DEPDIR)/regress-regress_http.Tpo -c -o regress-regress_http.o `test -f 'regress_http.c' || echo '$(srcdir)/'`regress_http.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_http.Tpo $(DEPDIR)/regress-regress_http.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_http.c' object='regress-regress_http.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_http.o `test -f 'regress_http.c' || echo '$(srcdir)/'`regress_http.c
+
+regress-regress_http.obj: regress_http.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_http.obj -MD -MP -MF $(DEPDIR)/regress-regress_http.Tpo -c -o regress-regress_http.obj `if test -f 'regress_http.c'; then $(CYGPATH_W) 'regress_http.c'; else $(CYGPATH_W) '$(srcdir)/regress_http.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_http.Tpo $(DEPDIR)/regress-regress_http.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_http.c' object='regress-regress_http.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_http.obj `if test -f 'regress_http.c'; then $(CYGPATH_W) 'regress_http.c'; else $(CYGPATH_W) '$(srcdir)/regress_http.c'; fi`
+
+regress-regress_dns.o: regress_dns.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_dns.o -MD -MP -MF $(DEPDIR)/regress-regress_dns.Tpo -c -o regress-regress_dns.o `test -f 'regress_dns.c' || echo '$(srcdir)/'`regress_dns.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_dns.Tpo $(DEPDIR)/regress-regress_dns.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_dns.c' object='regress-regress_dns.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_dns.o `test -f 'regress_dns.c' || echo '$(srcdir)/'`regress_dns.c
+
+regress-regress_dns.obj: regress_dns.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_dns.obj -MD -MP -MF $(DEPDIR)/regress-regress_dns.Tpo -c -o regress-regress_dns.obj `if test -f 'regress_dns.c'; then $(CYGPATH_W) 'regress_dns.c'; else $(CYGPATH_W) '$(srcdir)/regress_dns.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_dns.Tpo $(DEPDIR)/regress-regress_dns.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_dns.c' object='regress-regress_dns.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_dns.obj `if test -f 'regress_dns.c'; then $(CYGPATH_W) 'regress_dns.c'; else $(CYGPATH_W) '$(srcdir)/regress_dns.c'; fi`
+
+regress-regress_testutils.o: regress_testutils.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_testutils.o -MD -MP -MF $(DEPDIR)/regress-regress_testutils.Tpo -c -o regress-regress_testutils.o `test -f 'regress_testutils.c' || echo '$(srcdir)/'`regress_testutils.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_testutils.Tpo $(DEPDIR)/regress-regress_testutils.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_testutils.c' object='regress-regress_testutils.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_testutils.o `test -f 'regress_testutils.c' || echo '$(srcdir)/'`regress_testutils.c
+
+regress-regress_testutils.obj: regress_testutils.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_testutils.obj -MD -MP -MF $(DEPDIR)/regress-regress_testutils.Tpo -c -o regress-regress_testutils.obj `if test -f 'regress_testutils.c'; then $(CYGPATH_W) 'regress_testutils.c'; else $(CYGPATH_W) '$(srcdir)/regress_testutils.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_testutils.Tpo $(DEPDIR)/regress-regress_testutils.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_testutils.c' object='regress-regress_testutils.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_testutils.obj `if test -f 'regress_testutils.c'; then $(CYGPATH_W) 'regress_testutils.c'; else $(CYGPATH_W) '$(srcdir)/regress_testutils.c'; fi`
+
+regress-regress_rpc.o: regress_rpc.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_rpc.o -MD -MP -MF $(DEPDIR)/regress-regress_rpc.Tpo -c -o regress-regress_rpc.o `test -f 'regress_rpc.c' || echo '$(srcdir)/'`regress_rpc.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_rpc.Tpo $(DEPDIR)/regress-regress_rpc.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_rpc.c' object='regress-regress_rpc.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_rpc.o `test -f 'regress_rpc.c' || echo '$(srcdir)/'`regress_rpc.c
+
+regress-regress_rpc.obj: regress_rpc.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_rpc.obj -MD -MP -MF $(DEPDIR)/regress-regress_rpc.Tpo -c -o regress-regress_rpc.obj `if test -f 'regress_rpc.c'; then $(CYGPATH_W) 'regress_rpc.c'; else $(CYGPATH_W) '$(srcdir)/regress_rpc.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_rpc.Tpo $(DEPDIR)/regress-regress_rpc.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_rpc.c' object='regress-regress_rpc.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_rpc.obj `if test -f 'regress_rpc.c'; then $(CYGPATH_W) 'regress_rpc.c'; else $(CYGPATH_W) '$(srcdir)/regress_rpc.c'; fi`
+
+regress-regress.gen.o: regress.gen.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress.gen.o -MD -MP -MF $(DEPDIR)/regress-regress.gen.Tpo -c -o regress-regress.gen.o `test -f 'regress.gen.c' || echo '$(srcdir)/'`regress.gen.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress.gen.Tpo $(DEPDIR)/regress-regress.gen.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress.gen.c' object='regress-regress.gen.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress.gen.o `test -f 'regress.gen.c' || echo '$(srcdir)/'`regress.gen.c
+
+regress-regress.gen.obj: regress.gen.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress.gen.obj -MD -MP -MF $(DEPDIR)/regress-regress.gen.Tpo -c -o regress-regress.gen.obj `if test -f 'regress.gen.c'; then $(CYGPATH_W) 'regress.gen.c'; else $(CYGPATH_W) '$(srcdir)/regress.gen.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress.gen.Tpo $(DEPDIR)/regress-regress.gen.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress.gen.c' object='regress-regress.gen.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress.gen.obj `if test -f 'regress.gen.c'; then $(CYGPATH_W) 'regress.gen.c'; else $(CYGPATH_W) '$(srcdir)/regress.gen.c'; fi`
+
+regress-regress_et.o: regress_et.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_et.o -MD -MP -MF $(DEPDIR)/regress-regress_et.Tpo -c -o regress-regress_et.o `test -f 'regress_et.c' || echo '$(srcdir)/'`regress_et.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_et.Tpo $(DEPDIR)/regress-regress_et.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_et.c' object='regress-regress_et.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_et.o `test -f 'regress_et.c' || echo '$(srcdir)/'`regress_et.c
+
+regress-regress_et.obj: regress_et.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_et.obj -MD -MP -MF $(DEPDIR)/regress-regress_et.Tpo -c -o regress-regress_et.obj `if test -f 'regress_et.c'; then $(CYGPATH_W) 'regress_et.c'; else $(CYGPATH_W) '$(srcdir)/regress_et.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_et.Tpo $(DEPDIR)/regress-regress_et.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_et.c' object='regress-regress_et.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_et.obj `if test -f 'regress_et.c'; then $(CYGPATH_W) 'regress_et.c'; else $(CYGPATH_W) '$(srcdir)/regress_et.c'; fi`
+
+regress-regress_bufferevent.o: regress_bufferevent.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_bufferevent.o -MD -MP -MF $(DEPDIR)/regress-regress_bufferevent.Tpo -c -o regress-regress_bufferevent.o `test -f 'regress_bufferevent.c' || echo '$(srcdir)/'`regress_bufferevent.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_bufferevent.Tpo $(DEPDIR)/regress-regress_bufferevent.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_bufferevent.c' object='regress-regress_bufferevent.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_bufferevent.o `test -f 'regress_bufferevent.c' || echo '$(srcdir)/'`regress_bufferevent.c
+
+regress-regress_bufferevent.obj: regress_bufferevent.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_bufferevent.obj -MD -MP -MF $(DEPDIR)/regress-regress_bufferevent.Tpo -c -o regress-regress_bufferevent.obj `if test -f 'regress_bufferevent.c'; then $(CYGPATH_W) 'regress_bufferevent.c'; else $(CYGPATH_W) '$(srcdir)/regress_bufferevent.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_bufferevent.Tpo $(DEPDIR)/regress-regress_bufferevent.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_bufferevent.c' object='regress-regress_bufferevent.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_bufferevent.obj `if test -f 'regress_bufferevent.c'; then $(CYGPATH_W) 'regress_bufferevent.c'; else $(CYGPATH_W) '$(srcdir)/regress_bufferevent.c'; fi`
+
+regress-regress_listener.o: regress_listener.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_listener.o -MD -MP -MF $(DEPDIR)/regress-regress_listener.Tpo -c -o regress-regress_listener.o `test -f 'regress_listener.c' || echo '$(srcdir)/'`regress_listener.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_listener.Tpo $(DEPDIR)/regress-regress_listener.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_listener.c' object='regress-regress_listener.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_listener.o `test -f 'regress_listener.c' || echo '$(srcdir)/'`regress_listener.c
+
+regress-regress_listener.obj: regress_listener.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_listener.obj -MD -MP -MF $(DEPDIR)/regress-regress_listener.Tpo -c -o regress-regress_listener.obj `if test -f 'regress_listener.c'; then $(CYGPATH_W) 'regress_listener.c'; else $(CYGPATH_W) '$(srcdir)/regress_listener.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_listener.Tpo $(DEPDIR)/regress-regress_listener.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_listener.c' object='regress-regress_listener.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_listener.obj `if test -f 'regress_listener.c'; then $(CYGPATH_W) 'regress_listener.c'; else $(CYGPATH_W) '$(srcdir)/regress_listener.c'; fi`
+
+regress-regress_util.o: regress_util.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_util.o -MD -MP -MF $(DEPDIR)/regress-regress_util.Tpo -c -o regress-regress_util.o `test -f 'regress_util.c' || echo '$(srcdir)/'`regress_util.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_util.Tpo $(DEPDIR)/regress-regress_util.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_util.c' object='regress-regress_util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_util.o `test -f 'regress_util.c' || echo '$(srcdir)/'`regress_util.c
+
+regress-regress_util.obj: regress_util.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_util.obj -MD -MP -MF $(DEPDIR)/regress-regress_util.Tpo -c -o regress-regress_util.obj `if test -f 'regress_util.c'; then $(CYGPATH_W) 'regress_util.c'; else $(CYGPATH_W) '$(srcdir)/regress_util.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_util.Tpo $(DEPDIR)/regress-regress_util.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_util.c' object='regress-regress_util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_util.obj `if test -f 'regress_util.c'; then $(CYGPATH_W) 'regress_util.c'; else $(CYGPATH_W) '$(srcdir)/regress_util.c'; fi`
+
+regress-tinytest.o: tinytest.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-tinytest.o -MD -MP -MF $(DEPDIR)/regress-tinytest.Tpo -c -o regress-tinytest.o `test -f 'tinytest.c' || echo '$(srcdir)/'`tinytest.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-tinytest.Tpo $(DEPDIR)/regress-tinytest.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tinytest.c' object='regress-tinytest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-tinytest.o `test -f 'tinytest.c' || echo '$(srcdir)/'`tinytest.c
+
+regress-tinytest.obj: tinytest.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-tinytest.obj -MD -MP -MF $(DEPDIR)/regress-tinytest.Tpo -c -o regress-tinytest.obj `if test -f 'tinytest.c'; then $(CYGPATH_W) 'tinytest.c'; else $(CYGPATH_W) '$(srcdir)/tinytest.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-tinytest.Tpo $(DEPDIR)/regress-tinytest.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tinytest.c' object='regress-tinytest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-tinytest.obj `if test -f 'tinytest.c'; then $(CYGPATH_W) 'tinytest.c'; else $(CYGPATH_W) '$(srcdir)/tinytest.c'; fi`
+
+regress-regress_main.o: regress_main.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_main.o -MD -MP -MF $(DEPDIR)/regress-regress_main.Tpo -c -o regress-regress_main.o `test -f 'regress_main.c' || echo '$(srcdir)/'`regress_main.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_main.Tpo $(DEPDIR)/regress-regress_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_main.c' object='regress-regress_main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_main.o `test -f 'regress_main.c' || echo '$(srcdir)/'`regress_main.c
+
+regress-regress_main.obj: regress_main.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_main.obj -MD -MP -MF $(DEPDIR)/regress-regress_main.Tpo -c -o regress-regress_main.obj `if test -f 'regress_main.c'; then $(CYGPATH_W) 'regress_main.c'; else $(CYGPATH_W) '$(srcdir)/regress_main.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_main.Tpo $(DEPDIR)/regress-regress_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_main.c' object='regress-regress_main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_main.obj `if test -f 'regress_main.c'; then $(CYGPATH_W) 'regress_main.c'; else $(CYGPATH_W) '$(srcdir)/regress_main.c'; fi`
+
+regress-regress_minheap.o: regress_minheap.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_minheap.o -MD -MP -MF $(DEPDIR)/regress-regress_minheap.Tpo -c -o regress-regress_minheap.o `test -f 'regress_minheap.c' || echo '$(srcdir)/'`regress_minheap.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_minheap.Tpo $(DEPDIR)/regress-regress_minheap.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_minheap.c' object='regress-regress_minheap.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_minheap.o `test -f 'regress_minheap.c' || echo '$(srcdir)/'`regress_minheap.c
+
+regress-regress_minheap.obj: regress_minheap.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_minheap.obj -MD -MP -MF $(DEPDIR)/regress-regress_minheap.Tpo -c -o regress-regress_minheap.obj `if test -f 'regress_minheap.c'; then $(CYGPATH_W) 'regress_minheap.c'; else $(CYGPATH_W) '$(srcdir)/regress_minheap.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_minheap.Tpo $(DEPDIR)/regress-regress_minheap.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_minheap.c' object='regress-regress_minheap.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_minheap.obj `if test -f 'regress_minheap.c'; then $(CYGPATH_W) 'regress_minheap.c'; else $(CYGPATH_W) '$(srcdir)/regress_minheap.c'; fi`
+
+regress-regress_thread.o: regress_thread.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_thread.o -MD -MP -MF $(DEPDIR)/regress-regress_thread.Tpo -c -o regress-regress_thread.o `test -f 'regress_thread.c' || echo '$(srcdir)/'`regress_thread.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_thread.Tpo $(DEPDIR)/regress-regress_thread.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_thread.c' object='regress-regress_thread.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_thread.o `test -f 'regress_thread.c' || echo '$(srcdir)/'`regress_thread.c
+
+regress-regress_thread.obj: regress_thread.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_thread.obj -MD -MP -MF $(DEPDIR)/regress-regress_thread.Tpo -c -o regress-regress_thread.obj `if test -f 'regress_thread.c'; then $(CYGPATH_W) 'regress_thread.c'; else $(CYGPATH_W) '$(srcdir)/regress_thread.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_thread.Tpo $(DEPDIR)/regress-regress_thread.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_thread.c' object='regress-regress_thread.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_thread.obj `if test -f 'regress_thread.c'; then $(CYGPATH_W) 'regress_thread.c'; else $(CYGPATH_W) '$(srcdir)/regress_thread.c'; fi`
+
+regress-regress_zlib.o: regress_zlib.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_zlib.o -MD -MP -MF $(DEPDIR)/regress-regress_zlib.Tpo -c -o regress-regress_zlib.o `test -f 'regress_zlib.c' || echo '$(srcdir)/'`regress_zlib.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_zlib.Tpo $(DEPDIR)/regress-regress_zlib.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_zlib.c' object='regress-regress_zlib.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_zlib.o `test -f 'regress_zlib.c' || echo '$(srcdir)/'`regress_zlib.c
+
+regress-regress_zlib.obj: regress_zlib.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_zlib.obj -MD -MP -MF $(DEPDIR)/regress-regress_zlib.Tpo -c -o regress-regress_zlib.obj `if test -f 'regress_zlib.c'; then $(CYGPATH_W) 'regress_zlib.c'; else $(CYGPATH_W) '$(srcdir)/regress_zlib.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_zlib.Tpo $(DEPDIR)/regress-regress_zlib.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_zlib.c' object='regress-regress_zlib.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_zlib.obj `if test -f 'regress_zlib.c'; then $(CYGPATH_W) 'regress_zlib.c'; else $(CYGPATH_W) '$(srcdir)/regress_zlib.c'; fi`
+
+regress-regress_iocp.o: regress_iocp.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_iocp.o -MD -MP -MF $(DEPDIR)/regress-regress_iocp.Tpo -c -o regress-regress_iocp.o `test -f 'regress_iocp.c' || echo '$(srcdir)/'`regress_iocp.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_iocp.Tpo $(DEPDIR)/regress-regress_iocp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_iocp.c' object='regress-regress_iocp.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_iocp.o `test -f 'regress_iocp.c' || echo '$(srcdir)/'`regress_iocp.c
+
+regress-regress_iocp.obj: regress_iocp.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_iocp.obj -MD -MP -MF $(DEPDIR)/regress-regress_iocp.Tpo -c -o regress-regress_iocp.obj `if test -f 'regress_iocp.c'; then $(CYGPATH_W) 'regress_iocp.c'; else $(CYGPATH_W) '$(srcdir)/regress_iocp.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_iocp.Tpo $(DEPDIR)/regress-regress_iocp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_iocp.c' object='regress-regress_iocp.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_iocp.obj `if test -f 'regress_iocp.c'; then $(CYGPATH_W) 'regress_iocp.c'; else $(CYGPATH_W) '$(srcdir)/regress_iocp.c'; fi`
+
+regress-regress_ssl.o: regress_ssl.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_ssl.o -MD -MP -MF $(DEPDIR)/regress-regress_ssl.Tpo -c -o regress-regress_ssl.o `test -f 'regress_ssl.c' || echo '$(srcdir)/'`regress_ssl.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_ssl.Tpo $(DEPDIR)/regress-regress_ssl.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_ssl.c' object='regress-regress_ssl.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_ssl.o `test -f 'regress_ssl.c' || echo '$(srcdir)/'`regress_ssl.c
+
+regress-regress_ssl.obj: regress_ssl.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_ssl.obj -MD -MP -MF $(DEPDIR)/regress-regress_ssl.Tpo -c -o regress-regress_ssl.obj `if test -f 'regress_ssl.c'; then $(CYGPATH_W) 'regress_ssl.c'; else $(CYGPATH_W) '$(srcdir)/regress_ssl.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/regress-regress_ssl.Tpo $(DEPDIR)/regress-regress_ssl.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='regress_ssl.c' object='regress-regress_ssl.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_ssl.obj `if test -f 'regress_ssl.c'; then $(CYGPATH_W) 'regress_ssl.c'; else $(CYGPATH_W) '$(srcdir)/regress_ssl.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=XPASS; \
+ ;; \
+ *) \
+ col=$$grn; res=PASS; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xfail=`expr $$xfail + 1`; \
+ col=$$lgn; res=XFAIL; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=FAIL; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ col=$$blu; res=SKIP; \
+ fi; \
+ echo "$${col}$$res$${std}: $$tst"; \
+ done; \
+ if test "$$all" -eq 1; then \
+ tests="test"; \
+ All=""; \
+ else \
+ tests="tests"; \
+ All="All "; \
+ fi; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="$$All$$all $$tests passed"; \
+ else \
+ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all $$tests failed"; \
+ else \
+ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ skipped="($$skip test was not run)"; \
+ else \
+ skipped="($$skip tests were not run)"; \
+ fi; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ if test "$$failed" -eq 0; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ fi; \
+ echo "$${col}$$dashes$${std}"; \
+ echo "$${col}$$banner$${std}"; \
+ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+ test -z "$$report" || echo "$${col}$$report$${std}"; \
+ echo "$${col}$$dashes$${std}"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(PROGRAMS) $(HEADERS)
+installdirs:
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: all check check-am install install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+ clean-generic clean-libtool clean-noinstPROGRAMS ctags \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am
+
+
+regress.gen.c regress.gen.h: rpcgen-attempted
+
+rpcgen-attempted: $(srcdir)/regress.rpc $(srcdir)/../event_rpcgen.py $(srcdir)/rpcgen_wrapper.sh
+ date -u > $@
+ if $(srcdir)/rpcgen_wrapper.sh $(srcdir); then \
+ echo "rpcgen okay"; \
+ else \
+ echo "No Python installed; stubbing out RPC test." >&2; \
+ echo " "> regress.gen.c; \
+ echo "#define NO_PYTHON_EXISTS" > regress.gen.h; \
+ fi
+
+verify: check
+
+bench test-init test-eof test-weof test-time test-changelist: ../libevent.la
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libevent-2.0.20-stable/test/Makefile.nmake b/libevent-2.0.20-stable/test/Makefile.nmake
new file mode 100644
index 0000000..a899941
--- /dev/null
+++ b/libevent-2.0.20-stable/test/Makefile.nmake
@@ -0,0 +1,61 @@
+
+CFLAGS=/I.. /I../WIN32-Code /I../include /I../compat /DWIN32 /DHAVE_CONFIG_H /DTINYTEST_LOCAL
+
+CFLAGS=$(CFLAGS) /Ox /W3 /wd4996 /nologo
+
+REGRESS_OBJS=regress.obj regress_buffer.obj regress_http.obj regress_dns.obj \
+ regress_testutils.obj \
+ regress_rpc.obj regress.gen.obj \
+ regress_et.obj regress_bufferevent.obj \
+ regress_listener.obj regress_util.obj tinytest.obj \
+ regress_main.obj regress_minheap.obj regress_iocp.obj \
+ regress_thread.obj
+
+OTHER_OBJS=test-init.obj test-eof.obj test-weof.obj test-time.obj \
+ bench.obj bench_cascade.obj bench_http.obj bench_httpclient.obj \
+ test-changelist.obj
+
+PROGRAMS=regress.exe \
+ test-init.exe test-eof.exe test-weof.exe test-time.exe \
+ test-changelist.exe
+
+# Disabled for now:
+# bench.exe bench_cascade.exe bench_http.exe bench_httpclient.exe
+
+
+LIBS=..\libevent.lib ws2_32.lib shell32.lib advapi32.lib
+
+all: $(PROGRAMS)
+
+regress.exe: $(REGRESS_OBJS)
+ $(CC) $(CFLAGS) $(LIBS) $(REGRESS_OBJS)
+
+test-init.exe: test-init.obj
+ $(CC) $(CFLAGS) $(LIBS) test-init.obj
+test-eof.exe: test-eof.obj
+ $(CC) $(CFLAGS) $(LIBS) test-eof.obj
+test-changelist.exe: test-changelist.obj
+ $(CC) $(CFLAGS) $(LIBS) test-changelist.obj
+test-weof.exe: test-weof.obj
+ $(CC) $(CFLAGS) $(LIBS) test-weof.obj
+test-time.exe: test-time.obj
+ $(CC) $(CFLAGS) $(LIBS) test-time.obj
+
+bench.exe: bench.obj
+ $(CC) $(CFLAGS) $(LIBS) bench.obj
+bench_cascade.exe: bench_cascade.obj
+ $(CC) $(CFLAGS) $(LIBS) bench_cascade.obj
+bench_http.exe: bench_http.obj
+ $(CC) $(CFLAGS) $(LIBS) bench_http.obj
+bench_httpclient.exe: bench_httpclient.obj
+ $(CC) $(CFLAGS) $(LIBS) bench_httpclient.obj
+
+regress.gen.c regress.gen.h: regress.rpc ../event_rpcgen.py
+ echo // > regress.gen.c
+ echo #define NO_PYTHON_EXISTS > regress.gen.h
+ -python ..\event_rpcgen.py regress.rpc
+
+clean:
+ -del $(REGRESS_OBJS)
+ -del $(OTHER_OBJS)
+ -del regress.exe
diff --git a/libevent-2.0.20-stable/test/bench.c b/libevent-2.0.20-stable/test/bench.c
new file mode 100644
index 0000000..66b7d71
--- /dev/null
+++ b/libevent-2.0.20-stable/test/bench.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * Mon 03/10/2003 - Modified by Davide Libenzi <davidel@xmailserver.org>
+ *
+ * Added chain event propagation to improve the sensitivity of
+ * the measure respect to the event loop efficency.
+ *
+ *
+ */
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#else
+#include <sys/socket.h>
+#include <signal.h>
+#include <sys/resource.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef _EVENT_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <event.h>
+#include <evutil.h>
+
+static int count, writes, fired;
+static int *pipes;
+static int num_pipes, num_active, num_writes;
+static struct event *events;
+
+
+static void
+read_cb(evutil_socket_t fd, short which, void *arg)
+{
+ long idx = (long) arg, widx = idx + 1;
+ u_char ch;
+
+ count += recv(fd, (char*)&ch, sizeof(ch), 0);
+ if (writes) {
+ if (widx >= num_pipes)
+ widx -= num_pipes;
+ send(pipes[2 * widx + 1], "e", 1, 0);
+ writes--;
+ fired++;
+ }
+}
+
+static struct timeval *
+run_once(void)
+{
+ int *cp, space;
+ long i;
+ static struct timeval ts, te;
+
+ for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
+ if (event_initialized(&events[i]))
+ event_del(&events[i]);
+ event_set(&events[i], cp[0], EV_READ | EV_PERSIST, read_cb, (void *) i);
+ event_add(&events[i], NULL);
+ }
+
+ event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK);
+
+ fired = 0;
+ space = num_pipes / num_active;
+ space = space * 2;
+ for (i = 0; i < num_active; i++, fired++)
+ send(pipes[i * space + 1], "e", 1, 0);
+
+ count = 0;
+ writes = num_writes;
+ { int xcount = 0;
+ evutil_gettimeofday(&ts, NULL);
+ do {
+ event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK);
+ xcount++;
+ } while (count != fired);
+ evutil_gettimeofday(&te, NULL);
+
+ if (xcount != count) fprintf(stderr, "Xcount: %d, Rcount: %d\n", xcount, count);
+ }
+
+ evutil_timersub(&te, &ts, &te);
+
+ return (&te);
+}
+
+int
+main(int argc, char **argv)
+{
+#ifndef WIN32
+ struct rlimit rl;
+#endif
+ int i, c;
+ struct timeval *tv;
+ int *cp;
+
+#ifdef WIN32
+ WSADATA WSAData;
+ WSAStartup(0x101, &WSAData);
+#endif
+ num_pipes = 100;
+ num_active = 1;
+ num_writes = num_pipes;
+ while ((c = getopt(argc, argv, "n:a:w:")) != -1) {
+ switch (c) {
+ case 'n':
+ num_pipes = atoi(optarg);
+ break;
+ case 'a':
+ num_active = atoi(optarg);
+ break;
+ case 'w':
+ num_writes = atoi(optarg);
+ break;
+ default:
+ fprintf(stderr, "Illegal argument \"%c\"\n", c);
+ exit(1);
+ }
+ }
+
+#ifndef WIN32
+ rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50;
+ if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
+ perror("setrlimit");
+ exit(1);
+ }
+#endif
+
+ events = calloc(num_pipes, sizeof(struct event));
+ pipes = calloc(num_pipes * 2, sizeof(int));
+ if (events == NULL || pipes == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+ event_init();
+
+ for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
+#ifdef USE_PIPES
+ if (pipe(cp) == -1) {
+#else
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) {
+#endif
+ perror("pipe");
+ exit(1);
+ }
+ }
+
+ for (i = 0; i < 25; i++) {
+ tv = run_once();
+ if (tv == NULL)
+ exit(1);
+ fprintf(stdout, "%ld\n",
+ tv->tv_sec * 1000000L + tv->tv_usec);
+ }
+
+ exit(0);
+}
diff --git a/libevent-2.0.20-stable/test/bench_cascade.c b/libevent-2.0.20-stable/test/bench_cascade.c
new file mode 100644
index 0000000..a614156
--- /dev/null
+++ b/libevent-2.0.20-stable/test/bench_cascade.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#else
+#include <sys/socket.h>
+#include <sys/resource.h>
+#endif
+#include <signal.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef _EVENT_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <event.h>
+#include <evutil.h>
+
+/*
+ * This benchmark tests how quickly we can propagate a write down a chain
+ * of socket pairs. We start by writing to the first socket pair and all
+ * events will fire subsequently until the last socket pair has been reached
+ * and the benchmark terminates.
+ */
+
+static int fired;
+static int *pipes;
+static struct event *events;
+
+static void
+read_cb(evutil_socket_t fd, short which, void *arg)
+{
+ char ch;
+ long idx = (long) arg;
+
+ recv(fd, &ch, sizeof(ch), 0);
+ if (idx >= 0) {
+ if (send(idx, "e", 1, 0) < 0)
+ perror("send");
+ }
+ fired++;
+}
+
+static struct timeval *
+run_once(int num_pipes)
+{
+ int *cp, i;
+ static struct timeval ts, te, tv_timeout;
+
+ events = calloc(num_pipes, sizeof(struct event));
+ pipes = calloc(num_pipes * 2, sizeof(int));
+
+ if (events == NULL || pipes == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+ for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) {
+ perror("socketpair");
+ exit(1);
+ }
+ }
+
+ /* measurements includes event setup */
+ evutil_gettimeofday(&ts, NULL);
+
+ /* provide a default timeout for events */
+ evutil_timerclear(&tv_timeout);
+ tv_timeout.tv_sec = 60;
+
+ for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
+ long fd = i < num_pipes - 1 ? cp[3] : -1;
+ event_set(&events[i], cp[0], EV_READ, read_cb, (void *) fd);
+ event_add(&events[i], &tv_timeout);
+ }
+
+ fired = 0;
+
+ /* kick everything off with a single write */
+ if (send(pipes[1], "e", 1, 0) < 0)
+ perror("send");
+
+ event_dispatch();
+
+ evutil_gettimeofday(&te, NULL);
+ evutil_timersub(&te, &ts, &te);
+
+ for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
+ event_del(&events[i]);
+ close(cp[0]);
+ close(cp[1]);
+ }
+
+ free(pipes);
+ free(events);
+
+ return (&te);
+}
+
+int
+main(int argc, char **argv)
+{
+#ifndef WIN32
+ struct rlimit rl;
+#endif
+ int i, c;
+ struct timeval *tv;
+
+ int num_pipes = 100;
+ while ((c = getopt(argc, argv, "n:")) != -1) {
+ switch (c) {
+ case 'n':
+ num_pipes = atoi(optarg);
+ break;
+ default:
+ fprintf(stderr, "Illegal argument \"%c\"\n", c);
+ exit(1);
+ }
+ }
+
+#ifndef WIN32
+ rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50;
+ if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
+ perror("setrlimit");
+ exit(1);
+ }
+#endif
+
+ event_init();
+
+ for (i = 0; i < 25; i++) {
+ tv = run_once(num_pipes);
+ if (tv == NULL)
+ exit(1);
+ fprintf(stdout, "%ld\n",
+ tv->tv_sec * 1000000L + tv->tv_usec);
+ }
+
+ exit(0);
+}
diff --git a/libevent-2.0.20-stable/test/bench_http.c b/libevent-2.0.20-stable/test/bench_http.c
new file mode 100644
index 0000000..f6fd81b
--- /dev/null
+++ b/libevent-2.0.20-stable/test/bench_http.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2008-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event2/event.h"
+#include "event2/buffer.h"
+#include "event2/util.h"
+#include "event2/http.h"
+#include "event2/thread.h"
+
+static void http_basic_cb(struct evhttp_request *req, void *arg);
+
+static char *content;
+static size_t content_len = 0;
+
+static void
+http_basic_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *evb = evbuffer_new();
+
+ evbuffer_add(evb, content, content_len);
+
+ /* allow sending of an empty reply */
+ evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
+
+ evbuffer_free(evb);
+}
+
+#if LIBEVENT_VERSION_NUMBER >= 0x02000200
+static void
+http_ref_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *evb = evbuffer_new();
+
+ evbuffer_add_reference(evb, content, content_len, NULL, NULL);
+
+ /* allow sending of an empty reply */
+ evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
+
+ evbuffer_free(evb);
+}
+#endif
+
+int
+main(int argc, char **argv)
+{
+ struct event_config *cfg = event_config_new();
+ struct event_base *base;
+ struct evhttp *http;
+ int i;
+ int c;
+ int use_iocp = 0;
+ unsigned short port = 8080;
+ char *endptr = NULL;
+
+#ifdef WIN32
+ WSADATA WSAData;
+ WSAStartup(0x101, &WSAData);
+#else
+ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+ return (1);
+#endif
+
+ for (i = 1; i < argc; ++i) {
+ if (*argv[i] != '-')
+ continue;
+
+ c = argv[i][1];
+
+ if ((c == 'p' || c == 'l') && i + 1 >= argc) {
+ fprintf(stderr, "-%c requires argument.\n", c);
+ exit(1);
+ }
+
+ switch (c) {
+ case 'p':
+ if (i+1 >= argc || !argv[i+1]) {
+ fprintf(stderr, "Missing port\n");
+ exit(1);
+ }
+ port = (int)strtol(argv[i+1], &endptr, 10);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Bad port\n");
+ exit(1);
+ }
+ break;
+ case 'l':
+ if (i+1 >= argc || !argv[i+1]) {
+ fprintf(stderr, "Missing content length\n");
+ exit(1);
+ }
+ content_len = (size_t)strtol(argv[i+1], &endptr, 10);
+ if (*endptr != '\0' || content_len == 0) {
+ fprintf(stderr, "Bad content length\n");
+ exit(1);
+ }
+ break;
+#ifdef WIN32
+ case 'i':
+ use_iocp = 1;
+ evthread_use_windows_threads();
+ event_config_set_flag(cfg,EVENT_BASE_FLAG_STARTUP_IOCP);
+ break;
+#endif
+ default:
+ fprintf(stderr, "Illegal argument \"%c\"\n", c);
+ exit(1);
+ }
+ }
+
+ base = event_base_new_with_config(cfg);
+ if (!base) {
+ fprintf(stderr, "creating event_base failed. Exiting.\n");
+ return 1;
+ }
+
+ http = evhttp_new(base);
+
+ content = malloc(content_len);
+ if (content == NULL) {
+ fprintf(stderr, "Cannot allocate content\n");
+ exit(1);
+ } else {
+ int i = 0;
+ for (i = 0; i < (int)content_len; ++i)
+ content[i] = (i & 255);
+ }
+
+ evhttp_set_cb(http, "/ind", http_basic_cb, NULL);
+ fprintf(stderr, "/ind - basic content (memory copy)\n");
+
+#ifdef _EVENT2_EVENT_H_
+ evhttp_set_cb(http, "/ref", http_ref_cb, NULL);
+ fprintf(stderr, "/ref - basic content (reference)\n");
+#endif
+
+ fprintf(stderr, "Serving %d bytes on port %d using %s\n",
+ (int)content_len, port,
+ use_iocp? "IOCP" : event_base_get_method(base));
+
+ evhttp_bind_socket(http, "0.0.0.0", port);
+
+ if (use_iocp) {
+ struct timeval tv={99999999,0};
+ event_base_loopexit(base, &tv);
+ }
+ event_base_dispatch(base);
+
+ /* NOTREACHED */
+ return (0);
+}
diff --git a/libevent-2.0.20-stable/test/bench_httpclient.c b/libevent-2.0.20-stable/test/bench_httpclient.c
new file mode 100644
index 0000000..581b23d
--- /dev/null
+++ b/libevent-2.0.20-stable/test/bench_httpclient.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/types.h>
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+# ifdef _XOPEN_SOURCE_EXTENDED
+# include <arpa/inet.h>
+# endif
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event2/event.h"
+#include "event2/bufferevent.h"
+#include "event2/buffer.h"
+#include "event2/util.h"
+
+/* for EVUTIL_ERR_CONNECT_RETRIABLE macro */
+#include "util-internal.h"
+
+const char *resource = NULL;
+struct event_base *base = NULL;
+
+int total_n_handled = 0;
+int total_n_errors = 0;
+int total_n_launched = 0;
+size_t total_n_bytes = 0;
+struct timeval total_time = {0,0};
+int n_errors = 0;
+
+const int PARALLELISM = 200;
+const int N_REQUESTS = 20000;
+
+struct request_info {
+ size_t n_read;
+ struct timeval started;
+};
+
+static int launch_request(void);
+static void readcb(struct bufferevent *b, void *arg);
+static void errorcb(struct bufferevent *b, short what, void *arg);
+
+static void
+readcb(struct bufferevent *b, void *arg)
+{
+ struct request_info *ri = arg;
+ struct evbuffer *input = bufferevent_get_input(b);
+ size_t n = evbuffer_get_length(input);
+
+ ri->n_read += n;
+ evbuffer_drain(input, n);
+}
+
+static void
+errorcb(struct bufferevent *b, short what, void *arg)
+{
+ struct request_info *ri = arg;
+ struct timeval now, diff;
+ if (what & BEV_EVENT_EOF) {
+ ++total_n_handled;
+ total_n_bytes += ri->n_read;
+ evutil_gettimeofday(&now, NULL);
+ evutil_timersub(&now, &ri->started, &diff);
+ evutil_timeradd(&diff, &total_time, &total_time);
+
+ if (total_n_handled && (total_n_handled%1000)==0)
+ printf("%d requests done\n",total_n_handled);
+
+ if (total_n_launched < N_REQUESTS) {
+ if (launch_request() < 0)
+ perror("Can't launch");
+ }
+ } else {
+ ++total_n_errors;
+ perror("Unexpected error");
+ }
+
+ bufferevent_setcb(b, NULL, NULL, NULL, NULL);
+ free(ri);
+ bufferevent_disable(b, EV_READ|EV_WRITE);
+ bufferevent_free(b);
+}
+
+static void
+frob_socket(evutil_socket_t sock)
+{
+ struct linger l;
+ int one = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&one, sizeof(one))<0)
+ perror("setsockopt(SO_REUSEADDR)");
+ l.l_onoff = 1;
+ l.l_linger = 0;
+ if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&l, sizeof(l))<0)
+ perror("setsockopt(SO_LINGER)");
+}
+
+static int
+launch_request(void)
+{
+ evutil_socket_t sock;
+ struct sockaddr_in sin;
+ struct bufferevent *b;
+
+ struct request_info *ri;
+
+ memset(&sin, 0, sizeof(sin));
+
+ ++total_n_launched;
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(0x7f000001);
+ sin.sin_port = htons(8080);
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ return -1;
+ if (evutil_make_socket_nonblocking(sock) < 0)
+ return -1;
+ frob_socket(sock);
+ if (connect(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
+ int e = errno;
+ if (! EVUTIL_ERR_CONNECT_RETRIABLE(e)) {
+ return -1;
+ }
+ }
+
+ ri = malloc(sizeof(*ri));
+ ri->n_read = 0;
+ evutil_gettimeofday(&ri->started, NULL);
+
+ b = bufferevent_socket_new(base, sock, BEV_OPT_CLOSE_ON_FREE);
+
+ bufferevent_setcb(b, readcb, NULL, errorcb, ri);
+ bufferevent_enable(b, EV_READ|EV_WRITE);
+
+ evbuffer_add_printf(bufferevent_get_output(b),
+ "GET %s HTTP/1.0\r\n\r\n", resource);
+
+ return 0;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ int i;
+ struct timeval start, end, total;
+ long long usec;
+ double throughput;
+ resource = "/ref";
+
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ base = event_base_new();
+
+ for (i=0; i < PARALLELISM; ++i) {
+ if (launch_request() < 0)
+ perror("launch");
+ }
+
+ evutil_gettimeofday(&start, NULL);
+
+ event_base_dispatch(base);
+
+ evutil_gettimeofday(&end, NULL);
+ evutil_timersub(&end, &start, &total);
+ usec = total_time.tv_sec * 1000000 + total_time.tv_usec;
+
+ if (!total_n_handled) {
+ puts("Nothing worked. You probably did something dumb.");
+ return 0;
+ }
+
+
+ throughput = total_n_handled /
+ (total.tv_sec+ ((double)total.tv_usec)/1000000.0);
+
+#ifdef WIN32
+#define I64_FMT "%I64d"
+#define I64_TYP __int64
+#else
+#define I64_FMT "%lld"
+#define I64_TYP long long int
+#endif
+
+ printf("\n%d requests in %d.%06d sec. (%.2f throughput)\n"
+ "Each took about %.02f msec latency\n"
+ I64_FMT "bytes read. %d errors.\n",
+ total_n_handled,
+ (int)total.tv_sec, (int)total.tv_usec,
+ throughput,
+ (double)(usec/1000) / total_n_handled,
+ (I64_TYP)total_n_bytes, n_errors);
+
+ return 0;
+}
diff --git a/libevent-2.0.20-stable/test/regress.c b/libevent-2.0.20-stable/test/regress.c
new file mode 100644
index 0000000..5935f9b
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress.c
@@ -0,0 +1,2489 @@
+/*
+ * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+#endif
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include "event2/event.h"
+#include "event2/event_struct.h"
+#include "event2/event_compat.h"
+#include "event2/tag.h"
+#include "event2/buffer.h"
+#include "event2/buffer_compat.h"
+#include "event2/util.h"
+#include "event-internal.h"
+#include "evthread-internal.h"
+#include "util-internal.h"
+#include "log-internal.h"
+
+#include "regress.h"
+
+#ifndef WIN32
+#include "regress.gen.h"
+#endif
+
+evutil_socket_t pair[2];
+int test_ok;
+int called;
+struct event_base *global_base;
+
+static char wbuf[4096];
+static char rbuf[4096];
+static int woff;
+static int roff;
+static int usepersist;
+static struct timeval tset;
+static struct timeval tcalled;
+
+
+#define TEST1 "this is a test"
+#define SECONDS 1
+
+#ifndef SHUT_WR
+#define SHUT_WR 1
+#endif
+
+#ifdef WIN32
+#define write(fd,buf,len) send((fd),(buf),(int)(len),0)
+#define read(fd,buf,len) recv((fd),(buf),(int)(len),0)
+#endif
+
+struct basic_cb_args
+{
+ struct event_base *eb;
+ struct event *ev;
+ unsigned int callcount;
+};
+
+static void
+simple_read_cb(evutil_socket_t fd, short event, void *arg)
+{
+ char buf[256];
+ int len;
+
+ len = read(fd, buf, sizeof(buf));
+
+ if (len) {
+ if (!called) {
+ if (event_add(arg, NULL) == -1)
+ exit(1);
+ }
+ } else if (called == 1)
+ test_ok = 1;
+
+ called++;
+}
+
+static void
+basic_read_cb(evutil_socket_t fd, short event, void *data)
+{
+ char buf[256];
+ int len;
+ struct basic_cb_args *arg = data;
+
+ len = read(fd, buf, sizeof(buf));
+
+ if (len < 0) {
+ tt_fail_perror("read (callback)");
+ } else {
+ switch (arg->callcount++) {
+ case 0: /* first call: expect to read data; cycle */
+ if (len > 0)
+ return;
+
+ tt_fail_msg("EOF before data read");
+ break;
+
+ case 1: /* second call: expect EOF; stop */
+ if (len > 0)
+ tt_fail_msg("not all data read on first cycle");
+ break;
+
+ default: /* third call: should not happen */
+ tt_fail_msg("too many cycles");
+ }
+ }
+
+ event_del(arg->ev);
+ event_base_loopexit(arg->eb, NULL);
+}
+
+static void
+dummy_read_cb(evutil_socket_t fd, short event, void *arg)
+{
+}
+
+static void
+simple_write_cb(evutil_socket_t fd, short event, void *arg)
+{
+ int len;
+
+ len = write(fd, TEST1, strlen(TEST1) + 1);
+ if (len == -1)
+ test_ok = 0;
+ else
+ test_ok = 1;
+}
+
+static void
+multiple_write_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct event *ev = arg;
+ int len;
+
+ len = 128;
+ if (woff + len >= (int)sizeof(wbuf))
+ len = sizeof(wbuf) - woff;
+
+ len = write(fd, wbuf + woff, len);
+ if (len == -1) {
+ fprintf(stderr, "%s: write\n", __func__);
+ if (usepersist)
+ event_del(ev);
+ return;
+ }
+
+ woff += len;
+
+ if (woff >= (int)sizeof(wbuf)) {
+ shutdown(fd, SHUT_WR);
+ if (usepersist)
+ event_del(ev);
+ return;
+ }
+
+ if (!usepersist) {
+ if (event_add(ev, NULL) == -1)
+ exit(1);
+ }
+}
+
+static void
+multiple_read_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct event *ev = arg;
+ int len;
+
+ len = read(fd, rbuf + roff, sizeof(rbuf) - roff);
+ if (len == -1)
+ fprintf(stderr, "%s: read\n", __func__);
+ if (len <= 0) {
+ if (usepersist)
+ event_del(ev);
+ return;
+ }
+
+ roff += len;
+ if (!usepersist) {
+ if (event_add(ev, NULL) == -1)
+ exit(1);
+ }
+}
+
+static void
+timeout_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct timeval tv;
+ int diff;
+
+ evutil_gettimeofday(&tcalled, NULL);
+ if (evutil_timercmp(&tcalled, &tset, >))
+ evutil_timersub(&tcalled, &tset, &tv);
+ else
+ evutil_timersub(&tset, &tcalled, &tv);
+
+ diff = tv.tv_sec*1000 + tv.tv_usec/1000 - SECONDS * 1000;
+ if (diff < 0)
+ diff = -diff;
+
+ if (diff < 100)
+ test_ok = 1;
+}
+
+struct both {
+ struct event ev;
+ int nread;
+};
+
+static void
+combined_read_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct both *both = arg;
+ char buf[128];
+ int len;
+
+ len = read(fd, buf, sizeof(buf));
+ if (len == -1)
+ fprintf(stderr, "%s: read\n", __func__);
+ if (len <= 0)
+ return;
+
+ both->nread += len;
+ if (event_add(&both->ev, NULL) == -1)
+ exit(1);
+}
+
+static void
+combined_write_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct both *both = arg;
+ char buf[128];
+ int len;
+
+ len = sizeof(buf);
+ if (len > both->nread)
+ len = both->nread;
+
+ memset(buf, 'q', len);
+
+ len = write(fd, buf, len);
+ if (len == -1)
+ fprintf(stderr, "%s: write\n", __func__);
+ if (len <= 0) {
+ shutdown(fd, SHUT_WR);
+ return;
+ }
+
+ both->nread -= len;
+ if (event_add(&both->ev, NULL) == -1)
+ exit(1);
+}
+
+/* These macros used to replicate the work of the legacy test wrapper code */
+#define setup_test(x) do { \
+ if (!in_legacy_test_wrapper) { \
+ TT_FAIL(("Legacy test %s not wrapped properly", x)); \
+ return; \
+ } \
+ } while (0)
+#define cleanup_test() setup_test("cleanup")
+
+static void
+test_simpleread(void)
+{
+ struct event ev;
+
+ /* Very simple read test */
+ setup_test("Simple read: ");
+
+ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
+ tt_fail_perror("write");
+ }
+
+ shutdown(pair[0], SHUT_WR);
+
+ event_set(&ev, pair[1], EV_READ, simple_read_cb, &ev);
+ if (event_add(&ev, NULL) == -1)
+ exit(1);
+ event_dispatch();
+
+ cleanup_test();
+}
+
+static void
+test_simplewrite(void)
+{
+ struct event ev;
+
+ /* Very simple write test */
+ setup_test("Simple write: ");
+
+ event_set(&ev, pair[0], EV_WRITE, simple_write_cb, &ev);
+ if (event_add(&ev, NULL) == -1)
+ exit(1);
+ event_dispatch();
+
+ cleanup_test();
+}
+
+static void
+simpleread_multiple_cb(evutil_socket_t fd, short event, void *arg)
+{
+ if (++called == 2)
+ test_ok = 1;
+}
+
+static void
+test_simpleread_multiple(void)
+{
+ struct event one, two;
+
+ /* Very simple read test */
+ setup_test("Simple read to multiple evens: ");
+
+ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
+ tt_fail_perror("write");
+ }
+
+ shutdown(pair[0], SHUT_WR);
+
+ event_set(&one, pair[1], EV_READ, simpleread_multiple_cb, NULL);
+ if (event_add(&one, NULL) == -1)
+ exit(1);
+ event_set(&two, pair[1], EV_READ, simpleread_multiple_cb, NULL);
+ if (event_add(&two, NULL) == -1)
+ exit(1);
+ event_dispatch();
+
+ cleanup_test();
+}
+
+static int have_closed = 0;
+static int premature_event = 0;
+static void
+simpleclose_close_fd_cb(evutil_socket_t s, short what, void *ptr)
+{
+ evutil_socket_t **fds = ptr;
+ TT_BLATHER(("Closing"));
+ evutil_closesocket(*fds[0]);
+ evutil_closesocket(*fds[1]);
+ *fds[0] = -1;
+ *fds[1] = -1;
+ have_closed = 1;
+}
+
+static void
+record_event_cb(evutil_socket_t s, short what, void *ptr)
+{
+ short *whatp = ptr;
+ if (!have_closed)
+ premature_event = 1;
+ *whatp = what;
+ TT_BLATHER(("Recorded %d on socket %d", (int)what, (int)s));
+}
+
+static void
+test_simpleclose(void *ptr)
+{
+ /* Test that a close of FD is detected as a read and as a write. */
+ struct event_base *base = event_base_new();
+ evutil_socket_t pair1[2]={-1,-1}, pair2[2] = {-1, -1};
+ evutil_socket_t *to_close[2];
+ struct event *rev=NULL, *wev=NULL, *closeev=NULL;
+ struct timeval tv;
+ short got_read_on_close = 0, got_write_on_close = 0;
+ char buf[1024];
+ memset(buf, 99, sizeof(buf));
+#ifdef WIN32
+#define LOCAL_SOCKETPAIR_AF AF_INET
+#else
+#define LOCAL_SOCKETPAIR_AF AF_UNIX
+#endif
+ if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair1)<0)
+ TT_DIE(("socketpair: %s", strerror(errno)));
+ if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair2)<0)
+ TT_DIE(("socketpair: %s", strerror(errno)));
+ if (evutil_make_socket_nonblocking(pair1[1]) < 0)
+ TT_DIE(("make_socket_nonblocking"));
+ if (evutil_make_socket_nonblocking(pair2[1]) < 0)
+ TT_DIE(("make_socket_nonblocking"));
+
+ /** Stuff pair2[1] full of data, until write fails */
+ while (1) {
+ int r = write(pair2[1], buf, sizeof(buf));
+ if (r<0) {
+ int err = evutil_socket_geterror(pair2[1]);
+ if (! EVUTIL_ERR_RW_RETRIABLE(err))
+ TT_DIE(("write failed strangely: %s",
+ evutil_socket_error_to_string(err)));
+ break;
+ }
+ }
+ to_close[0] = &pair1[0];
+ to_close[1] = &pair2[0];
+
+ closeev = event_new(base, -1, EV_TIMEOUT, simpleclose_close_fd_cb,
+ to_close);
+ rev = event_new(base, pair1[1], EV_READ, record_event_cb,
+ &got_read_on_close);
+ TT_BLATHER(("Waiting for read on %d", (int)pair1[1]));
+ wev = event_new(base, pair2[1], EV_WRITE, record_event_cb,
+ &got_write_on_close);
+ TT_BLATHER(("Waiting for write on %d", (int)pair2[1]));
+ tv.tv_sec = 0;
+ tv.tv_usec = 100*1000; /* Close pair1[0] after a little while, and make
+ * sure we get a read event. */
+ event_add(closeev, &tv);
+ event_add(rev, NULL);
+ event_add(wev, NULL);
+ /* Don't let the test go on too long. */
+ tv.tv_sec = 0;
+ tv.tv_usec = 200*1000;
+ event_base_loopexit(base, &tv);
+ event_base_loop(base, 0);
+
+ tt_int_op(got_read_on_close, ==, EV_READ);
+ tt_int_op(got_write_on_close, ==, EV_WRITE);
+ tt_int_op(premature_event, ==, 0);
+
+end:
+ if (pair1[0] >= 0)
+ evutil_closesocket(pair1[0]);
+ if (pair1[1] >= 0)
+ evutil_closesocket(pair1[1]);
+ if (pair2[0] >= 0)
+ evutil_closesocket(pair2[0]);
+ if (pair2[1] >= 0)
+ evutil_closesocket(pair2[1]);
+ if (rev)
+ event_free(rev);
+ if (wev)
+ event_free(wev);
+ if (closeev)
+ event_free(closeev);
+ if (base)
+ event_base_free(base);
+}
+
+
+static void
+test_multiple(void)
+{
+ struct event ev, ev2;
+ int i;
+
+ /* Multiple read and write test */
+ setup_test("Multiple read/write: ");
+ memset(rbuf, 0, sizeof(rbuf));
+ for (i = 0; i < (int)sizeof(wbuf); i++)
+ wbuf[i] = i;
+
+ roff = woff = 0;
+ usepersist = 0;
+
+ event_set(&ev, pair[0], EV_WRITE, multiple_write_cb, &ev);
+ if (event_add(&ev, NULL) == -1)
+ exit(1);
+ event_set(&ev2, pair[1], EV_READ, multiple_read_cb, &ev2);
+ if (event_add(&ev2, NULL) == -1)
+ exit(1);
+ event_dispatch();
+
+ if (roff == woff)
+ test_ok = memcmp(rbuf, wbuf, sizeof(wbuf)) == 0;
+
+ cleanup_test();
+}
+
+static void
+test_persistent(void)
+{
+ struct event ev, ev2;
+ int i;
+
+ /* Multiple read and write test with persist */
+ setup_test("Persist read/write: ");
+ memset(rbuf, 0, sizeof(rbuf));
+ for (i = 0; i < (int)sizeof(wbuf); i++)
+ wbuf[i] = i;
+
+ roff = woff = 0;
+ usepersist = 1;
+
+ event_set(&ev, pair[0], EV_WRITE|EV_PERSIST, multiple_write_cb, &ev);
+ if (event_add(&ev, NULL) == -1)
+ exit(1);
+ event_set(&ev2, pair[1], EV_READ|EV_PERSIST, multiple_read_cb, &ev2);
+ if (event_add(&ev2, NULL) == -1)
+ exit(1);
+ event_dispatch();
+
+ if (roff == woff)
+ test_ok = memcmp(rbuf, wbuf, sizeof(wbuf)) == 0;
+
+ cleanup_test();
+}
+
+static void
+test_combined(void)
+{
+ struct both r1, r2, w1, w2;
+
+ setup_test("Combined read/write: ");
+ memset(&r1, 0, sizeof(r1));
+ memset(&r2, 0, sizeof(r2));
+ memset(&w1, 0, sizeof(w1));
+ memset(&w2, 0, sizeof(w2));
+
+ w1.nread = 4096;
+ w2.nread = 8192;
+
+ event_set(&r1.ev, pair[0], EV_READ, combined_read_cb, &r1);
+ event_set(&w1.ev, pair[0], EV_WRITE, combined_write_cb, &w1);
+ event_set(&r2.ev, pair[1], EV_READ, combined_read_cb, &r2);
+ event_set(&w2.ev, pair[1], EV_WRITE, combined_write_cb, &w2);
+ tt_assert(event_add(&r1.ev, NULL) != -1);
+ tt_assert(!event_add(&w1.ev, NULL));
+ tt_assert(!event_add(&r2.ev, NULL));
+ tt_assert(!event_add(&w2.ev, NULL));
+ event_dispatch();
+
+ if (r1.nread == 8192 && r2.nread == 4096)
+ test_ok = 1;
+
+end:
+ cleanup_test();
+}
+
+static void
+test_simpletimeout(void)
+{
+ struct timeval tv;
+ struct event ev;
+
+ setup_test("Simple timeout: ");
+
+ tv.tv_usec = 0;
+ tv.tv_sec = SECONDS;
+ evtimer_set(&ev, timeout_cb, NULL);
+ evtimer_add(&ev, &tv);
+
+ evutil_gettimeofday(&tset, NULL);
+ event_dispatch();
+
+ cleanup_test();
+}
+
+static void
+periodic_timeout_cb(evutil_socket_t fd, short event, void *arg)
+{
+ int *count = arg;
+
+ (*count)++;
+ if (*count == 6) {
+ /* call loopexit only once - on slow machines(?), it is
+ * apparently possible for this to get called twice. */
+ test_ok = 1;
+ event_base_loopexit(global_base, NULL);
+ }
+}
+
+static void
+test_persistent_timeout(void)
+{
+ struct timeval tv;
+ struct event ev;
+ int count = 0;
+
+ evutil_timerclear(&tv);
+ tv.tv_usec = 10000;
+
+ event_assign(&ev, global_base, -1, EV_TIMEOUT|EV_PERSIST,
+ periodic_timeout_cb, &count);
+ event_add(&ev, &tv);
+
+ event_dispatch();
+
+ event_del(&ev);
+}
+
+static void
+test_persistent_timeout_jump(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event ev;
+ int count = 0;
+ struct timeval msec100 = { 0, 100 * 1000 };
+ struct timeval msec50 = { 0, 50 * 1000 };
+
+ event_assign(&ev, data->base, -1, EV_PERSIST, periodic_timeout_cb, &count);
+ event_add(&ev, &msec100);
+ /* Wait for a bit */
+#ifdef _WIN32
+ Sleep(1000);
+#else
+ sleep(1);
+#endif
+ event_base_loopexit(data->base, &msec50);
+ event_base_dispatch(data->base);
+ tt_int_op(count, ==, 1);
+
+end:
+ event_del(&ev);
+}
+
+struct persist_active_timeout_called {
+ int n;
+ short events[16];
+ struct timeval tvs[16];
+};
+
+static void
+activate_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct event *ev = arg;
+ event_active(ev, EV_READ, 1);
+}
+
+static void
+persist_active_timeout_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct persist_active_timeout_called *c = arg;
+ if (c->n < 15) {
+ c->events[c->n] = event;
+ evutil_gettimeofday(&c->tvs[c->n], NULL);
+ ++c->n;
+ }
+}
+
+static void
+test_persistent_active_timeout(void *ptr)
+{
+ struct timeval tv, tv2, tv_exit, start;
+ struct event ev;
+ struct persist_active_timeout_called res;
+
+ struct basic_test_data *data = ptr;
+ struct event_base *base = data->base;
+
+ memset(&res, 0, sizeof(res));
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 200 * 1000;
+ event_assign(&ev, base, -1, EV_TIMEOUT|EV_PERSIST,
+ persist_active_timeout_cb, &res);
+ event_add(&ev, &tv);
+
+ tv2.tv_sec = 0;
+ tv2.tv_usec = 100 * 1000;
+ event_base_once(base, -1, EV_TIMEOUT, activate_cb, &ev, &tv2);
+
+ tv_exit.tv_sec = 0;
+ tv_exit.tv_usec = 600 * 1000;
+ event_base_loopexit(base, &tv_exit);
+
+ event_base_assert_ok(base);
+ evutil_gettimeofday(&start, NULL);
+
+ event_base_dispatch(base);
+ event_base_assert_ok(base);
+
+ tt_int_op(res.n, ==, 3);
+ tt_int_op(res.events[0], ==, EV_READ);
+ tt_int_op(res.events[1], ==, EV_TIMEOUT);
+ tt_int_op(res.events[2], ==, EV_TIMEOUT);
+ test_timeval_diff_eq(&start, &res.tvs[0], 100);
+ test_timeval_diff_eq(&start, &res.tvs[1], 300);
+ test_timeval_diff_eq(&start, &res.tvs[2], 500);
+end:
+ event_del(&ev);
+}
+
+struct common_timeout_info {
+ struct event ev;
+ struct timeval called_at;
+ int which;
+ int count;
+};
+
+static void
+common_timeout_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct common_timeout_info *ti = arg;
+ ++ti->count;
+ evutil_gettimeofday(&ti->called_at, NULL);
+ if (ti->count >= 6)
+ event_del(&ti->ev);
+}
+
+static void
+test_common_timeout(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+
+ struct event_base *base = data->base;
+ int i;
+ struct common_timeout_info info[100];
+
+ struct timeval now;
+ struct timeval tmp_100_ms = { 0, 100*1000 };
+ struct timeval tmp_200_ms = { 0, 200*1000 };
+
+ const struct timeval *ms_100, *ms_200;
+
+ ms_100 = event_base_init_common_timeout(base, &tmp_100_ms);
+ ms_200 = event_base_init_common_timeout(base, &tmp_200_ms);
+ tt_assert(ms_100);
+ tt_assert(ms_200);
+ tt_ptr_op(event_base_init_common_timeout(base, &tmp_200_ms),
+ ==, ms_200);
+ tt_int_op(ms_100->tv_sec, ==, 0);
+ tt_int_op(ms_200->tv_sec, ==, 0);
+ tt_int_op(ms_100->tv_usec, ==, 100000|0x50000000);
+ tt_int_op(ms_200->tv_usec, ==, 200000|0x50100000);
+
+ memset(info, 0, sizeof(info));
+
+ for (i=0; i<100; ++i) {
+ info[i].which = i;
+ event_assign(&info[i].ev, base, -1, EV_TIMEOUT|EV_PERSIST,
+ common_timeout_cb, &info[i]);
+ if (i % 2) {
+ event_add(&info[i].ev, ms_100);
+ } else {
+ event_add(&info[i].ev, ms_200);
+ }
+ }
+
+ event_base_assert_ok(base);
+ event_base_dispatch(base);
+
+ evutil_gettimeofday(&now, NULL);
+ event_base_assert_ok(base);
+
+ for (i=0; i<10; ++i) {
+ struct timeval tmp;
+ int ms_diff;
+ tt_int_op(info[i].count, ==, 6);
+ evutil_timersub(&now, &info[i].called_at, &tmp);
+ ms_diff = tmp.tv_usec/1000 + tmp.tv_sec*1000;
+ if (i % 2) {
+ tt_int_op(ms_diff, >, 500);
+ tt_int_op(ms_diff, <, 700);
+ } else {
+ tt_int_op(ms_diff, >, -100);
+ tt_int_op(ms_diff, <, 100);
+ }
+ }
+
+ /* Make sure we can free the base with some events in. */
+ for (i=0; i<100; ++i) {
+ if (i % 2) {
+ event_add(&info[i].ev, ms_100);
+ } else {
+ event_add(&info[i].ev, ms_200);
+ }
+ }
+
+end:
+ event_base_free(data->base); /* need to do this here before info is
+ * out-of-scope */
+ data->base = NULL;
+}
+
+#ifndef WIN32
+static void signal_cb(evutil_socket_t fd, short event, void *arg);
+
+#define current_base event_global_current_base_
+extern struct event_base *current_base;
+
+static void
+child_signal_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct timeval tv;
+ int *pint = arg;
+
+ *pint = 1;
+
+ tv.tv_usec = 500000;
+ tv.tv_sec = 0;
+ event_loopexit(&tv);
+}
+
+static void
+test_fork(void)
+{
+ int status, got_sigchld = 0;
+ struct event ev, sig_ev;
+ pid_t pid;
+
+ setup_test("After fork: ");
+
+ tt_assert(current_base);
+ evthread_make_base_notifiable(current_base);
+
+ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
+ tt_fail_perror("write");
+ }
+
+ event_set(&ev, pair[1], EV_READ, simple_read_cb, &ev);
+ if (event_add(&ev, NULL) == -1)
+ exit(1);
+
+ evsignal_set(&sig_ev, SIGCHLD, child_signal_cb, &got_sigchld);
+ evsignal_add(&sig_ev, NULL);
+
+ event_base_assert_ok(current_base);
+ TT_BLATHER(("Before fork"));
+ if ((pid = regress_fork()) == 0) {
+ /* in the child */
+ TT_BLATHER(("In child, before reinit"));
+ event_base_assert_ok(current_base);
+ if (event_reinit(current_base) == -1) {
+ fprintf(stdout, "FAILED (reinit)\n");
+ exit(1);
+ }
+ TT_BLATHER(("After reinit"));
+ event_base_assert_ok(current_base);
+ TT_BLATHER(("After assert-ok"));
+
+ evsignal_del(&sig_ev);
+
+ called = 0;
+
+ event_dispatch();
+
+ event_base_free(current_base);
+
+ /* we do not send an EOF; simple_read_cb requires an EOF
+ * to set test_ok. we just verify that the callback was
+ * called. */
+ exit(test_ok != 0 || called != 2 ? -2 : 76);
+ }
+
+ /* wait for the child to read the data */
+ sleep(1);
+
+ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
+ tt_fail_perror("write");
+ }
+
+ TT_BLATHER(("Before waitpid"));
+ if (waitpid(pid, &status, 0) == -1) {
+ fprintf(stdout, "FAILED (fork)\n");
+ exit(1);
+ }
+ TT_BLATHER(("After waitpid"));
+
+ if (WEXITSTATUS(status) != 76) {
+ fprintf(stdout, "FAILED (exit): %d\n", WEXITSTATUS(status));
+ exit(1);
+ }
+
+ /* test that the current event loop still works */
+ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
+ fprintf(stderr, "%s: write\n", __func__);
+ }
+
+ shutdown(pair[0], SHUT_WR);
+
+ event_dispatch();
+
+ if (!got_sigchld) {
+ fprintf(stdout, "FAILED (sigchld)\n");
+ exit(1);
+ }
+
+ evsignal_del(&sig_ev);
+
+ end:
+ cleanup_test();
+}
+
+static void
+signal_cb_sa(int sig)
+{
+ test_ok = 2;
+}
+
+static void
+signal_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct event *ev = arg;
+
+ evsignal_del(ev);
+ test_ok = 1;
+}
+
+static void
+test_simplesignal(void)
+{
+ struct event ev;
+ struct itimerval itv;
+
+ setup_test("Simple signal: ");
+ evsignal_set(&ev, SIGALRM, signal_cb, &ev);
+ evsignal_add(&ev, NULL);
+ /* find bugs in which operations are re-ordered */
+ evsignal_del(&ev);
+ evsignal_add(&ev, NULL);
+
+ memset(&itv, 0, sizeof(itv));
+ itv.it_value.tv_sec = 1;
+ if (setitimer(ITIMER_REAL, &itv, NULL) == -1)
+ goto skip_simplesignal;
+
+ event_dispatch();
+ skip_simplesignal:
+ if (evsignal_del(&ev) == -1)
+ test_ok = 0;
+
+ cleanup_test();
+}
+
+static void
+test_multiplesignal(void)
+{
+ struct event ev_one, ev_two;
+ struct itimerval itv;
+
+ setup_test("Multiple signal: ");
+
+ evsignal_set(&ev_one, SIGALRM, signal_cb, &ev_one);
+ evsignal_add(&ev_one, NULL);
+
+ evsignal_set(&ev_two, SIGALRM, signal_cb, &ev_two);
+ evsignal_add(&ev_two, NULL);
+
+ memset(&itv, 0, sizeof(itv));
+ itv.it_value.tv_sec = 1;
+ if (setitimer(ITIMER_REAL, &itv, NULL) == -1)
+ goto skip_simplesignal;
+
+ event_dispatch();
+
+ skip_simplesignal:
+ if (evsignal_del(&ev_one) == -1)
+ test_ok = 0;
+ if (evsignal_del(&ev_two) == -1)
+ test_ok = 0;
+
+ cleanup_test();
+}
+
+static void
+test_immediatesignal(void)
+{
+ struct event ev;
+
+ test_ok = 0;
+ evsignal_set(&ev, SIGUSR1, signal_cb, &ev);
+ evsignal_add(&ev, NULL);
+ raise(SIGUSR1);
+ event_loop(EVLOOP_NONBLOCK);
+ evsignal_del(&ev);
+ cleanup_test();
+}
+
+static void
+test_signal_dealloc(void)
+{
+ /* make sure that evsignal_event is event_del'ed and pipe closed */
+ struct event ev;
+ struct event_base *base = event_init();
+ evsignal_set(&ev, SIGUSR1, signal_cb, &ev);
+ evsignal_add(&ev, NULL);
+ evsignal_del(&ev);
+ event_base_free(base);
+ /* If we got here without asserting, we're fine. */
+ test_ok = 1;
+ cleanup_test();
+}
+
+static void
+test_signal_pipeloss(void)
+{
+ /* make sure that the base1 pipe is closed correctly. */
+ struct event_base *base1, *base2;
+ int pipe1;
+ test_ok = 0;
+ base1 = event_init();
+ pipe1 = base1->sig.ev_signal_pair[0];
+ base2 = event_init();
+ event_base_free(base2);
+ event_base_free(base1);
+ if (close(pipe1) != -1 || errno!=EBADF) {
+ /* fd must be closed, so second close gives -1, EBADF */
+ printf("signal pipe not closed. ");
+ test_ok = 0;
+ } else {
+ test_ok = 1;
+ }
+ cleanup_test();
+}
+
+/*
+ * make two bases to catch signals, use both of them. this only works
+ * for event mechanisms that use our signal pipe trick. kqueue handles
+ * signals internally, and all interested kqueues get all the signals.
+ */
+static void
+test_signal_switchbase(void)
+{
+ struct event ev1, ev2;
+ struct event_base *base1, *base2;
+ int is_kqueue;
+ test_ok = 0;
+ base1 = event_init();
+ base2 = event_init();
+ is_kqueue = !strcmp(event_get_method(),"kqueue");
+ evsignal_set(&ev1, SIGUSR1, signal_cb, &ev1);
+ evsignal_set(&ev2, SIGUSR1, signal_cb, &ev2);
+ if (event_base_set(base1, &ev1) ||
+ event_base_set(base2, &ev2) ||
+ event_add(&ev1, NULL) ||
+ event_add(&ev2, NULL)) {
+ fprintf(stderr, "%s: cannot set base, add\n", __func__);
+ exit(1);
+ }
+
+ tt_ptr_op(event_get_base(&ev1), ==, base1);
+ tt_ptr_op(event_get_base(&ev2), ==, base2);
+
+ test_ok = 0;
+ /* can handle signal before loop is called */
+ raise(SIGUSR1);
+ event_base_loop(base2, EVLOOP_NONBLOCK);
+ if (is_kqueue) {
+ if (!test_ok)
+ goto end;
+ test_ok = 0;
+ }
+ event_base_loop(base1, EVLOOP_NONBLOCK);
+ if (test_ok && !is_kqueue) {
+ test_ok = 0;
+
+ /* set base1 to handle signals */
+ event_base_loop(base1, EVLOOP_NONBLOCK);
+ raise(SIGUSR1);
+ event_base_loop(base1, EVLOOP_NONBLOCK);
+ event_base_loop(base2, EVLOOP_NONBLOCK);
+ }
+end:
+ event_base_free(base1);
+ event_base_free(base2);
+ cleanup_test();
+}
+
+/*
+ * assert that a signal event removed from the event queue really is
+ * removed - with no possibility of it's parent handler being fired.
+ */
+static void
+test_signal_assert(void)
+{
+ struct event ev;
+ struct event_base *base = event_init();
+ test_ok = 0;
+ /* use SIGCONT so we don't kill ourselves when we signal to nowhere */
+ evsignal_set(&ev, SIGCONT, signal_cb, &ev);
+ evsignal_add(&ev, NULL);
+ /*
+ * if evsignal_del() fails to reset the handler, it's current handler
+ * will still point to evsig_handler().
+ */
+ evsignal_del(&ev);
+
+ raise(SIGCONT);
+#if 0
+ /* only way to verify we were in evsig_handler() */
+ /* XXXX Now there's no longer a good way. */
+ if (base->sig.evsig_caught)
+ test_ok = 0;
+ else
+ test_ok = 1;
+#else
+ test_ok = 1;
+#endif
+
+ event_base_free(base);
+ cleanup_test();
+ return;
+}
+
+/*
+ * assert that we restore our previous signal handler properly.
+ */
+static void
+test_signal_restore(void)
+{
+ struct event ev;
+ struct event_base *base = event_init();
+#ifdef _EVENT_HAVE_SIGACTION
+ struct sigaction sa;
+#endif
+
+ test_ok = 0;
+#ifdef _EVENT_HAVE_SIGACTION
+ sa.sa_handler = signal_cb_sa;
+ sa.sa_flags = 0x0;
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(SIGUSR1, &sa, NULL) == -1)
+ goto out;
+#else
+ if (signal(SIGUSR1, signal_cb_sa) == SIG_ERR)
+ goto out;
+#endif
+ evsignal_set(&ev, SIGUSR1, signal_cb, &ev);
+ evsignal_add(&ev, NULL);
+ evsignal_del(&ev);
+
+ raise(SIGUSR1);
+ /* 1 == signal_cb, 2 == signal_cb_sa, we want our previous handler */
+ if (test_ok != 2)
+ test_ok = 0;
+out:
+ event_base_free(base);
+ cleanup_test();
+ return;
+}
+
+static void
+signal_cb_swp(int sig, short event, void *arg)
+{
+ called++;
+ if (called < 5)
+ raise(sig);
+ else
+ event_loopexit(NULL);
+}
+static void
+timeout_cb_swp(evutil_socket_t fd, short event, void *arg)
+{
+ if (called == -1) {
+ struct timeval tv = {5, 0};
+
+ called = 0;
+ evtimer_add((struct event *)arg, &tv);
+ raise(SIGUSR1);
+ return;
+ }
+ test_ok = 0;
+ event_loopexit(NULL);
+}
+
+static void
+test_signal_while_processing(void)
+{
+ struct event_base *base = event_init();
+ struct event ev, ev_timer;
+ struct timeval tv = {0, 0};
+
+ setup_test("Receiving a signal while processing other signal: ");
+
+ called = -1;
+ test_ok = 1;
+ signal_set(&ev, SIGUSR1, signal_cb_swp, NULL);
+ signal_add(&ev, NULL);
+ evtimer_set(&ev_timer, timeout_cb_swp, &ev_timer);
+ evtimer_add(&ev_timer, &tv);
+ event_dispatch();
+
+ event_base_free(base);
+ cleanup_test();
+ return;
+}
+#endif
+
+static void
+test_free_active_base(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event_base *base1;
+ struct event ev1;
+
+ base1 = event_init();
+ if (base1) {
+ event_assign(&ev1, base1, data->pair[1], EV_READ,
+ dummy_read_cb, NULL);
+ event_add(&ev1, NULL);
+ event_base_free(base1); /* should not crash */
+ } else {
+ tt_fail_msg("failed to create event_base for test");
+ }
+
+ base1 = event_init();
+ tt_assert(base1);
+ event_assign(&ev1, base1, 0, 0, dummy_read_cb, NULL);
+ event_active(&ev1, EV_READ, 1);
+ event_base_free(base1);
+end:
+ ;
+}
+
+static void
+test_manipulate_active_events(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event_base *base = data->base;
+ struct event ev1;
+
+ event_assign(&ev1, base, -1, EV_TIMEOUT, dummy_read_cb, NULL);
+
+ /* Make sure an active event is pending. */
+ event_active(&ev1, EV_READ, 1);
+ tt_int_op(event_pending(&ev1, EV_READ|EV_TIMEOUT|EV_WRITE, NULL),
+ ==, EV_READ);
+
+ /* Make sure that activating an event twice works. */
+ event_active(&ev1, EV_WRITE, 1);
+ tt_int_op(event_pending(&ev1, EV_READ|EV_TIMEOUT|EV_WRITE, NULL),
+ ==, EV_READ|EV_WRITE);
+
+end:
+ event_del(&ev1);
+}
+
+static void
+test_bad_assign(void *ptr)
+{
+ struct event ev;
+ int r;
+ /* READ|SIGNAL is not allowed */
+ r = event_assign(&ev, NULL, -1, EV_SIGNAL|EV_READ, dummy_read_cb, NULL);
+ tt_int_op(r,==,-1);
+
+end:
+ ;
+}
+
+static int reentrant_cb_run = 0;
+
+static void
+bad_reentrant_run_loop_cb(evutil_socket_t fd, short what, void *ptr)
+{
+ struct event_base *base = ptr;
+ int r;
+ reentrant_cb_run = 1;
+ /* This reentrant call to event_base_loop should be detected and
+ * should fail */
+ r = event_base_loop(base, 0);
+ tt_int_op(r, ==, -1);
+end:
+ ;
+}
+
+static void
+test_bad_reentrant(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event_base *base = data->base;
+ struct event ev;
+ int r;
+ event_assign(&ev, base, -1,
+ 0, bad_reentrant_run_loop_cb, base);
+
+ event_active(&ev, EV_WRITE, 1);
+ r = event_base_loop(base, 0);
+ tt_int_op(r, ==, 1);
+ tt_int_op(reentrant_cb_run, ==, 1);
+end:
+ ;
+}
+
+static void
+test_event_base_new(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event_base *base = 0;
+ struct event ev1;
+ struct basic_cb_args args;
+
+ int towrite = (int)strlen(TEST1)+1;
+ int len = write(data->pair[0], TEST1, towrite);
+
+ if (len < 0)
+ tt_abort_perror("initial write");
+ else if (len != towrite)
+ tt_abort_printf(("initial write fell short (%d of %d bytes)",
+ len, towrite));
+
+ if (shutdown(data->pair[0], SHUT_WR))
+ tt_abort_perror("initial write shutdown");
+
+ base = event_base_new();
+ if (!base)
+ tt_abort_msg("failed to create event base");
+
+ args.eb = base;
+ args.ev = &ev1;
+ args.callcount = 0;
+ event_assign(&ev1, base, data->pair[1],
+ EV_READ|EV_PERSIST, basic_read_cb, &args);
+
+ if (event_add(&ev1, NULL))
+ tt_abort_perror("initial event_add");
+
+ if (event_base_loop(base, 0))
+ tt_abort_msg("unsuccessful exit from event loop");
+
+end:
+ if (base)
+ event_base_free(base);
+}
+
+static void
+test_loopexit(void)
+{
+ struct timeval tv, tv_start, tv_end;
+ struct event ev;
+
+ setup_test("Loop exit: ");
+
+ tv.tv_usec = 0;
+ tv.tv_sec = 60*60*24;
+ evtimer_set(&ev, timeout_cb, NULL);
+ evtimer_add(&ev, &tv);
+
+ tv.tv_usec = 0;
+ tv.tv_sec = 1;
+ event_loopexit(&tv);
+
+ evutil_gettimeofday(&tv_start, NULL);
+ event_dispatch();
+ evutil_gettimeofday(&tv_end, NULL);
+ evutil_timersub(&tv_end, &tv_start, &tv_end);
+
+ evtimer_del(&ev);
+
+ tt_assert(event_base_got_exit(global_base));
+ tt_assert(!event_base_got_break(global_base));
+
+ if (tv.tv_sec < 2)
+ test_ok = 1;
+
+end:
+ cleanup_test();
+}
+
+static void
+test_loopexit_multiple(void)
+{
+ struct timeval tv;
+ struct event_base *base;
+
+ setup_test("Loop Multiple exit: ");
+
+ base = event_base_new();
+
+ tv.tv_usec = 0;
+ tv.tv_sec = 1;
+ event_base_loopexit(base, &tv);
+
+ tv.tv_usec = 0;
+ tv.tv_sec = 2;
+ event_base_loopexit(base, &tv);
+
+ event_base_dispatch(base);
+
+ tt_assert(event_base_got_exit(base));
+ tt_assert(!event_base_got_break(base));
+
+ event_base_free(base);
+
+ test_ok = 1;
+
+end:
+ cleanup_test();
+}
+
+static void
+break_cb(evutil_socket_t fd, short events, void *arg)
+{
+ test_ok = 1;
+ event_loopbreak();
+}
+
+static void
+fail_cb(evutil_socket_t fd, short events, void *arg)
+{
+ test_ok = 0;
+}
+
+static void
+test_loopbreak(void)
+{
+ struct event ev1, ev2;
+ struct timeval tv;
+
+ setup_test("Loop break: ");
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ evtimer_set(&ev1, break_cb, NULL);
+ evtimer_add(&ev1, &tv);
+ evtimer_set(&ev2, fail_cb, NULL);
+ evtimer_add(&ev2, &tv);
+
+ event_dispatch();
+
+ tt_assert(!event_base_got_exit(global_base));
+ tt_assert(event_base_got_break(global_base));
+
+ evtimer_del(&ev1);
+ evtimer_del(&ev2);
+
+end:
+ cleanup_test();
+}
+
+static struct event *readd_test_event_last_added = NULL;
+static void
+re_add_read_cb(evutil_socket_t fd, short event, void *arg)
+{
+ char buf[256];
+ struct event *ev_other = arg;
+ readd_test_event_last_added = ev_other;
+
+ if (read(fd, buf, sizeof(buf)) < 0) {
+ tt_fail_perror("read");
+ }
+
+ event_add(ev_other, NULL);
+ ++test_ok;
+}
+
+static void
+test_nonpersist_readd(void)
+{
+ struct event ev1, ev2;
+
+ setup_test("Re-add nonpersistent events: ");
+ event_set(&ev1, pair[0], EV_READ, re_add_read_cb, &ev2);
+ event_set(&ev2, pair[1], EV_READ, re_add_read_cb, &ev1);
+
+ if (write(pair[0], "Hello", 5) < 0) {
+ tt_fail_perror("write(pair[0])");
+ }
+
+ if (write(pair[1], "Hello", 5) < 0) {
+ tt_fail_perror("write(pair[1])\n");
+ }
+
+ if (event_add(&ev1, NULL) == -1 ||
+ event_add(&ev2, NULL) == -1) {
+ test_ok = 0;
+ }
+ if (test_ok != 0)
+ exit(1);
+ event_loop(EVLOOP_ONCE);
+ if (test_ok != 2)
+ exit(1);
+ /* At this point, we executed both callbacks. Whichever one got
+ * called first added the second, but the second then immediately got
+ * deleted before its callback was called. At this point, though, it
+ * re-added the first.
+ */
+ if (!readd_test_event_last_added) {
+ test_ok = 0;
+ } else if (readd_test_event_last_added == &ev1) {
+ if (!event_pending(&ev1, EV_READ, NULL) ||
+ event_pending(&ev2, EV_READ, NULL))
+ test_ok = 0;
+ } else {
+ if (event_pending(&ev1, EV_READ, NULL) ||
+ !event_pending(&ev2, EV_READ, NULL))
+ test_ok = 0;
+ }
+
+ event_del(&ev1);
+ event_del(&ev2);
+
+ cleanup_test();
+}
+
+struct test_pri_event {
+ struct event ev;
+ int count;
+};
+
+static void
+test_priorities_cb(evutil_socket_t fd, short what, void *arg)
+{
+ struct test_pri_event *pri = arg;
+ struct timeval tv;
+
+ if (pri->count == 3) {
+ event_loopexit(NULL);
+ return;
+ }
+
+ pri->count++;
+
+ evutil_timerclear(&tv);
+ event_add(&pri->ev, &tv);
+}
+
+static void
+test_priorities_impl(int npriorities)
+{
+ struct test_pri_event one, two;
+ struct timeval tv;
+
+ TT_BLATHER(("Testing Priorities %d: ", npriorities));
+
+ event_base_priority_init(global_base, npriorities);
+
+ memset(&one, 0, sizeof(one));
+ memset(&two, 0, sizeof(two));
+
+ timeout_set(&one.ev, test_priorities_cb, &one);
+ if (event_priority_set(&one.ev, 0) == -1) {
+ fprintf(stderr, "%s: failed to set priority", __func__);
+ exit(1);
+ }
+
+ timeout_set(&two.ev, test_priorities_cb, &two);
+ if (event_priority_set(&two.ev, npriorities - 1) == -1) {
+ fprintf(stderr, "%s: failed to set priority", __func__);
+ exit(1);
+ }
+
+ evutil_timerclear(&tv);
+
+ if (event_add(&one.ev, &tv) == -1)
+ exit(1);
+ if (event_add(&two.ev, &tv) == -1)
+ exit(1);
+
+ event_dispatch();
+
+ event_del(&one.ev);
+ event_del(&two.ev);
+
+ if (npriorities == 1) {
+ if (one.count == 3 && two.count == 3)
+ test_ok = 1;
+ } else if (npriorities == 2) {
+ /* Two is called once because event_loopexit is priority 1 */
+ if (one.count == 3 && two.count == 1)
+ test_ok = 1;
+ } else {
+ if (one.count == 3 && two.count == 0)
+ test_ok = 1;
+ }
+}
+
+static void
+test_priorities(void)
+{
+ test_priorities_impl(1);
+ if (test_ok)
+ test_priorities_impl(2);
+ if (test_ok)
+ test_priorities_impl(3);
+}
+
+/* priority-active-inversion: activate a higher-priority event, and make sure
+ * it keeps us from running a lower-priority event first. */
+static int n_pai_calls = 0;
+static struct event pai_events[3];
+
+static void
+prio_active_inversion_cb(evutil_socket_t fd, short what, void *arg)
+{
+ int *call_order = arg;
+ *call_order = n_pai_calls++;
+ if (n_pai_calls == 1) {
+ /* This should activate later, even though it shares a
+ priority with us. */
+ event_active(&pai_events[1], EV_READ, 1);
+ /* This should activate next, since its priority is higher,
+ even though we activated it second. */
+ event_active(&pai_events[2], EV_TIMEOUT, 1);
+ }
+}
+
+static void
+test_priority_active_inversion(void *data_)
+{
+ struct basic_test_data *data = data_;
+ struct event_base *base = data->base;
+ int call_order[3];
+ int i;
+ tt_int_op(event_base_priority_init(base, 8), ==, 0);
+
+ n_pai_calls = 0;
+ memset(call_order, 0, sizeof(call_order));
+
+ for (i=0;i<3;++i) {
+ event_assign(&pai_events[i], data->base, -1, 0,
+ prio_active_inversion_cb, &call_order[i]);
+ }
+
+ event_priority_set(&pai_events[0], 4);
+ event_priority_set(&pai_events[1], 4);
+ event_priority_set(&pai_events[2], 0);
+
+ event_active(&pai_events[0], EV_WRITE, 1);
+
+ event_base_dispatch(base);
+ tt_int_op(n_pai_calls, ==, 3);
+ tt_int_op(call_order[0], ==, 0);
+ tt_int_op(call_order[1], ==, 2);
+ tt_int_op(call_order[2], ==, 1);
+end:
+ ;
+}
+
+
+static void
+test_multiple_cb(evutil_socket_t fd, short event, void *arg)
+{
+ if (event & EV_READ)
+ test_ok |= 1;
+ else if (event & EV_WRITE)
+ test_ok |= 2;
+}
+
+static void
+test_multiple_events_for_same_fd(void)
+{
+ struct event e1, e2;
+
+ setup_test("Multiple events for same fd: ");
+
+ event_set(&e1, pair[0], EV_READ, test_multiple_cb, NULL);
+ event_add(&e1, NULL);
+ event_set(&e2, pair[0], EV_WRITE, test_multiple_cb, NULL);
+ event_add(&e2, NULL);
+ event_loop(EVLOOP_ONCE);
+ event_del(&e2);
+
+ if (write(pair[1], TEST1, strlen(TEST1)+1) < 0) {
+ tt_fail_perror("write");
+ }
+
+ event_loop(EVLOOP_ONCE);
+ event_del(&e1);
+
+ if (test_ok != 3)
+ test_ok = 0;
+
+ cleanup_test();
+}
+
+int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf);
+int evtag_decode_int64(ev_uint64_t *pnumber, struct evbuffer *evbuf);
+int evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t number);
+int evtag_decode_tag(ev_uint32_t *pnumber, struct evbuffer *evbuf);
+
+static void
+read_once_cb(evutil_socket_t fd, short event, void *arg)
+{
+ char buf[256];
+ int len;
+
+ len = read(fd, buf, sizeof(buf));
+
+ if (called) {
+ test_ok = 0;
+ } else if (len) {
+ /* Assumes global pair[0] can be used for writing */
+ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
+ tt_fail_perror("write");
+ test_ok = 0;
+ } else {
+ test_ok = 1;
+ }
+ }
+
+ called++;
+}
+
+static void
+test_want_only_once(void)
+{
+ struct event ev;
+ struct timeval tv;
+
+ /* Very simple read test */
+ setup_test("Want read only once: ");
+
+ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
+ tt_fail_perror("write");
+ }
+
+ /* Setup the loop termination */
+ evutil_timerclear(&tv);
+ tv.tv_sec = 1;
+ event_loopexit(&tv);
+
+ event_set(&ev, pair[1], EV_READ, read_once_cb, &ev);
+ if (event_add(&ev, NULL) == -1)
+ exit(1);
+ event_dispatch();
+
+ cleanup_test();
+}
+
+#define TEST_MAX_INT 6
+
+static void
+evtag_int_test(void *ptr)
+{
+ struct evbuffer *tmp = evbuffer_new();
+ ev_uint32_t integers[TEST_MAX_INT] = {
+ 0xaf0, 0x1000, 0x1, 0xdeadbeef, 0x00, 0xbef000
+ };
+ ev_uint32_t integer;
+ ev_uint64_t big_int;
+ int i;
+
+ evtag_init();
+
+ for (i = 0; i < TEST_MAX_INT; i++) {
+ int oldlen, newlen;
+ oldlen = (int)EVBUFFER_LENGTH(tmp);
+ evtag_encode_int(tmp, integers[i]);
+ newlen = (int)EVBUFFER_LENGTH(tmp);
+ TT_BLATHER(("encoded 0x%08x with %d bytes",
+ (unsigned)integers[i], newlen - oldlen));
+ big_int = integers[i];
+ big_int *= 1000000000; /* 1 billion */
+ evtag_encode_int64(tmp, big_int);
+ }
+
+ for (i = 0; i < TEST_MAX_INT; i++) {
+ tt_int_op(evtag_decode_int(&integer, tmp), !=, -1);
+ tt_uint_op(integer, ==, integers[i]);
+ tt_int_op(evtag_decode_int64(&big_int, tmp), !=, -1);
+ tt_assert((big_int / 1000000000) == integers[i]);
+ }
+
+ tt_uint_op(EVBUFFER_LENGTH(tmp), ==, 0);
+end:
+ evbuffer_free(tmp);
+}
+
+static void
+evtag_fuzz(void *ptr)
+{
+ u_char buffer[4096];
+ struct evbuffer *tmp = evbuffer_new();
+ struct timeval tv;
+ int i, j;
+
+ int not_failed = 0;
+
+ evtag_init();
+
+ for (j = 0; j < 100; j++) {
+ for (i = 0; i < (int)sizeof(buffer); i++)
+ buffer[i] = rand();
+ evbuffer_drain(tmp, -1);
+ evbuffer_add(tmp, buffer, sizeof(buffer));
+
+ if (evtag_unmarshal_timeval(tmp, 0, &tv) != -1)
+ not_failed++;
+ }
+
+ /* The majority of decodes should fail */
+ tt_int_op(not_failed, <, 10);
+
+ /* Now insert some corruption into the tag length field */
+ evbuffer_drain(tmp, -1);
+ evutil_timerclear(&tv);
+ tv.tv_sec = 1;
+ evtag_marshal_timeval(tmp, 0, &tv);
+ evbuffer_add(tmp, buffer, sizeof(buffer));
+
+ ((char *)EVBUFFER_DATA(tmp))[1] = '\xff';
+ if (evtag_unmarshal_timeval(tmp, 0, &tv) != -1) {
+ tt_abort_msg("evtag_unmarshal_timeval should have failed");
+ }
+
+end:
+ evbuffer_free(tmp);
+}
+
+static void
+evtag_tag_encoding(void *ptr)
+{
+ struct evbuffer *tmp = evbuffer_new();
+ ev_uint32_t integers[TEST_MAX_INT] = {
+ 0xaf0, 0x1000, 0x1, 0xdeadbeef, 0x00, 0xbef000
+ };
+ ev_uint32_t integer;
+ int i;
+
+ evtag_init();
+
+ for (i = 0; i < TEST_MAX_INT; i++) {
+ int oldlen, newlen;
+ oldlen = (int)EVBUFFER_LENGTH(tmp);
+ evtag_encode_tag(tmp, integers[i]);
+ newlen = (int)EVBUFFER_LENGTH(tmp);
+ TT_BLATHER(("encoded 0x%08x with %d bytes",
+ (unsigned)integers[i], newlen - oldlen));
+ }
+
+ for (i = 0; i < TEST_MAX_INT; i++) {
+ tt_int_op(evtag_decode_tag(&integer, tmp), !=, -1);
+ tt_uint_op(integer, ==, integers[i]);
+ }
+
+ tt_uint_op(EVBUFFER_LENGTH(tmp), ==, 0);
+
+end:
+ evbuffer_free(tmp);
+}
+
+static void
+evtag_test_peek(void *ptr)
+{
+ struct evbuffer *tmp = evbuffer_new();
+ ev_uint32_t u32;
+
+ evtag_marshal_int(tmp, 30, 0);
+ evtag_marshal_string(tmp, 40, "Hello world");
+
+ tt_int_op(evtag_peek(tmp, &u32), ==, 1);
+ tt_int_op(u32, ==, 30);
+ tt_int_op(evtag_peek_length(tmp, &u32), ==, 0);
+ tt_int_op(u32, ==, 1+1+1);
+ tt_int_op(evtag_consume(tmp), ==, 0);
+
+ tt_int_op(evtag_peek(tmp, &u32), ==, 1);
+ tt_int_op(u32, ==, 40);
+ tt_int_op(evtag_peek_length(tmp, &u32), ==, 0);
+ tt_int_op(u32, ==, 1+1+11);
+ tt_int_op(evtag_payload_length(tmp, &u32), ==, 0);
+ tt_int_op(u32, ==, 11);
+
+end:
+ evbuffer_free(tmp);
+}
+
+
+static void
+test_methods(void *ptr)
+{
+ const char **methods = event_get_supported_methods();
+ struct event_config *cfg = NULL;
+ struct event_base *base = NULL;
+ const char *backend;
+ int n_methods = 0;
+
+ tt_assert(methods);
+
+ backend = methods[0];
+ while (*methods != NULL) {
+ TT_BLATHER(("Support method: %s", *methods));
+ ++methods;
+ ++n_methods;
+ }
+
+ cfg = event_config_new();
+ assert(cfg != NULL);
+
+ tt_int_op(event_config_avoid_method(cfg, backend), ==, 0);
+ event_config_set_flag(cfg, EVENT_BASE_FLAG_IGNORE_ENV);
+
+ base = event_base_new_with_config(cfg);
+ if (n_methods > 1) {
+ tt_assert(base);
+ tt_str_op(backend, !=, event_base_get_method(base));
+ } else {
+ tt_assert(base == NULL);
+ }
+
+end:
+ if (base)
+ event_base_free(base);
+ if (cfg)
+ event_config_free(cfg);
+}
+
+static void
+test_version(void *arg)
+{
+ const char *vstr;
+ ev_uint32_t vint;
+ int major, minor, patch, n;
+
+ vstr = event_get_version();
+ vint = event_get_version_number();
+
+ tt_assert(vstr);
+ tt_assert(vint);
+
+ tt_str_op(vstr, ==, LIBEVENT_VERSION);
+ tt_int_op(vint, ==, LIBEVENT_VERSION_NUMBER);
+
+ n = sscanf(vstr, "%d.%d.%d", &major, &minor, &patch);
+ tt_assert(3 == n);
+ tt_int_op((vint&0xffffff00), ==, ((major<<24)|(minor<<16)|(patch<<8)));
+end:
+ ;
+}
+
+static void
+test_base_features(void *arg)
+{
+ struct event_base *base = NULL;
+ struct event_config *cfg = NULL;
+
+ cfg = event_config_new();
+
+ tt_assert(0 == event_config_require_features(cfg, EV_FEATURE_ET));
+
+ base = event_base_new_with_config(cfg);
+ if (base) {
+ tt_int_op(EV_FEATURE_ET, ==,
+ event_base_get_features(base) & EV_FEATURE_ET);
+ } else {
+ base = event_base_new();
+ tt_int_op(0, ==, event_base_get_features(base) & EV_FEATURE_ET);
+ }
+
+end:
+ if (base)
+ event_base_free(base);
+ if (cfg)
+ event_config_free(cfg);
+}
+
+#ifdef _EVENT_HAVE_SETENV
+#define SETENV_OK
+#elif !defined(_EVENT_HAVE_SETENV) && defined(_EVENT_HAVE_PUTENV)
+static void setenv(const char *k, const char *v, int _o)
+{
+ char b[256];
+ evutil_snprintf(b, sizeof(b), "%s=%s",k,v);
+ putenv(b);
+}
+#define SETENV_OK
+#endif
+
+#ifdef _EVENT_HAVE_UNSETENV
+#define UNSETENV_OK
+#elif !defined(_EVENT_HAVE_UNSETENV) && defined(_EVENT_HAVE_PUTENV)
+static void unsetenv(const char *k)
+{
+ char b[256];
+ evutil_snprintf(b, sizeof(b), "%s=",k);
+ putenv(b);
+}
+#define UNSETENV_OK
+#endif
+
+#if defined(SETENV_OK) && defined(UNSETENV_OK)
+static void
+methodname_to_envvar(const char *mname, char *buf, size_t buflen)
+{
+ char *cp;
+ evutil_snprintf(buf, buflen, "EVENT_NO%s", mname);
+ for (cp = buf; *cp; ++cp) {
+ *cp = EVUTIL_TOUPPER(*cp);
+ }
+}
+#endif
+
+static void
+test_base_environ(void *arg)
+{
+ struct event_base *base = NULL;
+ struct event_config *cfg = NULL;
+
+#if defined(SETENV_OK) && defined(UNSETENV_OK)
+ const char **basenames;
+ int i, n_methods=0;
+ char varbuf[128];
+ const char *defaultname, *ignoreenvname;
+
+ /* See if unsetenv works before we rely on it. */
+ setenv("EVENT_NOWAFFLES", "1", 1);
+ unsetenv("EVENT_NOWAFFLES");
+ if (getenv("EVENT_NOWAFFLES") != NULL) {
+#ifndef _EVENT_HAVE_UNSETENV
+ TT_DECLARE("NOTE", ("Can't fake unsetenv; skipping test"));
+#else
+ TT_DECLARE("NOTE", ("unsetenv doesn't work; skipping test"));
+#endif
+ tt_skip();
+ }
+
+ basenames = event_get_supported_methods();
+ for (i = 0; basenames[i]; ++i) {
+ methodname_to_envvar(basenames[i], varbuf, sizeof(varbuf));
+ unsetenv(varbuf);
+ ++n_methods;
+ }
+
+ base = event_base_new();
+ tt_assert(base);
+
+ defaultname = event_base_get_method(base);
+ TT_BLATHER(("default is <%s>", defaultname));
+ event_base_free(base);
+ base = NULL;
+
+ /* Can we disable the method with EVENT_NOfoo ? */
+ if (!strcmp(defaultname, "epoll (with changelist)")) {
+ setenv("EVENT_NOEPOLL", "1", 1);
+ ignoreenvname = "epoll";
+ } else {
+ methodname_to_envvar(defaultname, varbuf, sizeof(varbuf));
+ setenv(varbuf, "1", 1);
+ ignoreenvname = defaultname;
+ }
+
+ /* Use an empty cfg rather than NULL so a failure doesn't exit() */
+ cfg = event_config_new();
+ base = event_base_new_with_config(cfg);
+ event_config_free(cfg);
+ cfg = NULL;
+ if (n_methods == 1) {
+ tt_assert(!base);
+ } else {
+ tt_assert(base);
+ tt_str_op(defaultname, !=, event_base_get_method(base));
+ event_base_free(base);
+ base = NULL;
+ }
+
+ /* Can we disable looking at the environment with IGNORE_ENV ? */
+ cfg = event_config_new();
+ event_config_set_flag(cfg, EVENT_BASE_FLAG_IGNORE_ENV);
+ base = event_base_new_with_config(cfg);
+ tt_assert(base);
+ tt_str_op(ignoreenvname, ==, event_base_get_method(base));
+#else
+ tt_skip();
+#endif
+
+end:
+ if (base)
+ event_base_free(base);
+ if (cfg)
+ event_config_free(cfg);
+}
+
+static void
+read_called_once_cb(evutil_socket_t fd, short event, void *arg)
+{
+ tt_int_op(event, ==, EV_READ);
+ called += 1;
+end:
+ ;
+}
+
+static void
+timeout_called_once_cb(evutil_socket_t fd, short event, void *arg)
+{
+ tt_int_op(event, ==, EV_TIMEOUT);
+ called += 100;
+end:
+ ;
+}
+
+static void
+test_event_once(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct timeval tv;
+ int r;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 50*1000;
+ called = 0;
+ r = event_base_once(data->base, data->pair[0], EV_READ,
+ read_called_once_cb, NULL, NULL);
+ tt_int_op(r, ==, 0);
+ r = event_base_once(data->base, -1, EV_TIMEOUT,
+ timeout_called_once_cb, NULL, &tv);
+ tt_int_op(r, ==, 0);
+ r = event_base_once(data->base, -1, 0, NULL, NULL, NULL);
+ tt_int_op(r, <, 0);
+
+ if (write(data->pair[1], TEST1, strlen(TEST1)+1) < 0) {
+ tt_fail_perror("write");
+ }
+
+ shutdown(data->pair[1], SHUT_WR);
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(called, ==, 101);
+end:
+ ;
+}
+
+static void
+test_event_pending(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event *r=NULL, *w=NULL, *t=NULL;
+ struct timeval tv, now, tv2, diff;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 500 * 1000;
+ r = event_new(data->base, data->pair[0], EV_READ, simple_read_cb,
+ NULL);
+ w = event_new(data->base, data->pair[1], EV_WRITE, simple_write_cb,
+ NULL);
+ t = evtimer_new(data->base, timeout_cb, NULL);
+
+ tt_assert(r);
+ tt_assert(w);
+ tt_assert(t);
+
+ evutil_gettimeofday(&now, NULL);
+ event_add(r, NULL);
+ event_add(t, &tv);
+
+ tt_assert( event_pending(r, EV_READ, NULL));
+ tt_assert(!event_pending(w, EV_WRITE, NULL));
+ tt_assert(!event_pending(r, EV_WRITE, NULL));
+ tt_assert( event_pending(r, EV_READ|EV_WRITE, NULL));
+ tt_assert(!event_pending(r, EV_TIMEOUT, NULL));
+ tt_assert( event_pending(t, EV_TIMEOUT, NULL));
+ tt_assert( event_pending(t, EV_TIMEOUT, &tv2));
+
+ tt_assert(evutil_timercmp(&tv2, &now, >));
+ evutil_timeradd(&now, &tv, &tv);
+ evutil_timersub(&tv2, &tv, &diff);
+ tt_int_op(diff.tv_sec, ==, 0);
+ tt_int_op(labs(diff.tv_usec), <, 1000);
+
+end:
+ if (r) {
+ event_del(r);
+ event_free(r);
+ }
+ if (w) {
+ event_del(w);
+ event_free(w);
+ }
+ if (t) {
+ event_del(t);
+ event_free(t);
+ }
+}
+
+#ifndef WIN32
+/* You can't do this test on windows, since dup2 doesn't work on sockets */
+
+static void
+dfd_cb(evutil_socket_t fd, short e, void *data)
+{
+ *(int*)data = (int)e;
+}
+
+/* Regression test for our workaround for a fun epoll/linux related bug
+ * where fd2 = dup(fd1); add(fd2); close(fd2); dup2(fd1,fd2); add(fd2)
+ * will get you an EEXIST */
+static void
+test_dup_fd(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct event *ev1=NULL, *ev2=NULL;
+ int fd, dfd=-1;
+ int ev1_got, ev2_got;
+
+ tt_int_op(write(data->pair[0], "Hello world",
+ strlen("Hello world")), >, 0);
+ fd = data->pair[1];
+
+ dfd = dup(fd);
+ tt_int_op(dfd, >=, 0);
+
+ ev1 = event_new(base, fd, EV_READ|EV_PERSIST, dfd_cb, &ev1_got);
+ ev2 = event_new(base, dfd, EV_READ|EV_PERSIST, dfd_cb, &ev2_got);
+ ev1_got = ev2_got = 0;
+ event_add(ev1, NULL);
+ event_add(ev2, NULL);
+ event_base_loop(base, EVLOOP_ONCE);
+ tt_int_op(ev1_got, ==, EV_READ);
+ tt_int_op(ev2_got, ==, EV_READ);
+
+ /* Now close and delete dfd then dispatch. We need to do the
+ * dispatch here so that when we add it later, we think there
+ * was an intermediate delete. */
+ close(dfd);
+ event_del(ev2);
+ ev1_got = ev2_got = 0;
+ event_base_loop(base, EVLOOP_ONCE);
+ tt_want_int_op(ev1_got, ==, EV_READ);
+ tt_int_op(ev2_got, ==, 0);
+
+ /* Re-duplicate the fd. We need to get the same duplicated
+ * value that we closed to provoke the epoll quirk. Also, we
+ * need to change the events to write, or else the old lingering
+ * read event will make the test pass whether the change was
+ * successful or not. */
+ tt_int_op(dup2(fd, dfd), ==, dfd);
+ event_free(ev2);
+ ev2 = event_new(base, dfd, EV_WRITE|EV_PERSIST, dfd_cb, &ev2_got);
+ event_add(ev2, NULL);
+ ev1_got = ev2_got = 0;
+ event_base_loop(base, EVLOOP_ONCE);
+ tt_want_int_op(ev1_got, ==, EV_READ);
+ tt_int_op(ev2_got, ==, EV_WRITE);
+
+end:
+ if (ev1)
+ event_free(ev1);
+ if (ev2)
+ event_free(ev2);
+ if (dfd >= 0)
+ close(dfd);
+}
+#endif
+
+#ifdef _EVENT_DISABLE_MM_REPLACEMENT
+static void
+test_mm_functions(void *arg)
+{
+ _tinytest_set_test_skipped();
+}
+#else
+static int
+check_dummy_mem_ok(void *_mem)
+{
+ char *mem = _mem;
+ mem -= 16;
+ return !memcmp(mem, "{[<guardedram>]}", 16);
+}
+
+static void *
+dummy_malloc(size_t len)
+{
+ char *mem = malloc(len+16);
+ memcpy(mem, "{[<guardedram>]}", 16);
+ return mem+16;
+}
+
+static void *
+dummy_realloc(void *_mem, size_t len)
+{
+ char *mem = _mem;
+ if (!mem)
+ return dummy_malloc(len);
+ tt_want(check_dummy_mem_ok(_mem));
+ mem -= 16;
+ mem = realloc(mem, len+16);
+ return mem+16;
+}
+
+static void
+dummy_free(void *_mem)
+{
+ char *mem = _mem;
+ tt_want(check_dummy_mem_ok(_mem));
+ mem -= 16;
+ free(mem);
+}
+
+static void
+test_mm_functions(void *arg)
+{
+ struct event_base *b = NULL;
+ struct event_config *cfg = NULL;
+ event_set_mem_functions(dummy_malloc, dummy_realloc, dummy_free);
+ cfg = event_config_new();
+ event_config_avoid_method(cfg, "Nonesuch");
+ b = event_base_new_with_config(cfg);
+ tt_assert(b);
+ tt_assert(check_dummy_mem_ok(b));
+end:
+ if (cfg)
+ event_config_free(cfg);
+ if (b)
+ event_base_free(b);
+}
+#endif
+
+static void
+many_event_cb(evutil_socket_t fd, short event, void *arg)
+{
+ int *calledp = arg;
+ *calledp += 1;
+}
+
+static void
+test_many_events(void *arg)
+{
+ /* Try 70 events that should all be ready at once. This will
+ * exercise the "resize" code on most of the backends, and will make
+ * sure that we can get past the 64-handle limit of some windows
+ * functions. */
+#define MANY 70
+
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ int one_at_a_time = data->setup_data != NULL;
+ evutil_socket_t sock[MANY];
+ struct event *ev[MANY];
+ int called[MANY];
+ int i;
+ int loopflags = EVLOOP_NONBLOCK, evflags=0;
+ const int is_evport = !strcmp(event_base_get_method(base),"evport");
+ if (one_at_a_time) {
+ loopflags |= EVLOOP_ONCE;
+ evflags = EV_PERSIST;
+ }
+
+ memset(sock, 0xff, sizeof(sock));
+ memset(ev, 0, sizeof(ev));
+ memset(called, 0, sizeof(called));
+ if (is_evport && one_at_a_time) {
+ TT_DECLARE("NOTE", ("evport can't pass this in 2.0; skipping\n"));
+ tt_skip();
+ }
+
+ for (i = 0; i < MANY; ++i) {
+ /* We need an event that will hit the backend, and that will
+ * be ready immediately. "Send a datagram" is an easy
+ * instance of that. */
+ sock[i] = socket(AF_INET, SOCK_DGRAM, 0);
+ tt_assert(sock[i] >= 0);
+ called[i] = 0;
+ ev[i] = event_new(base, sock[i], EV_WRITE|evflags,
+ many_event_cb, &called[i]);
+ event_add(ev[i], NULL);
+ if (one_at_a_time)
+ event_base_loop(base, EVLOOP_NONBLOCK|EVLOOP_ONCE);
+ }
+
+ event_base_loop(base, loopflags);
+
+ for (i = 0; i < MANY; ++i) {
+ if (one_at_a_time)
+ tt_int_op(called[i], ==, MANY - i + 1);
+ else
+ tt_int_op(called[i], ==, 1);
+ }
+
+end:
+ for (i = 0; i < MANY; ++i) {
+ if (ev[i])
+ event_free(ev[i]);
+ if (sock[i] >= 0)
+ evutil_closesocket(sock[i]);
+ }
+#undef MANY
+}
+
+static void
+test_struct_event_size(void *arg)
+{
+ tt_int_op(event_get_struct_event_size(), <=, sizeof(struct event));
+end:
+ ;
+}
+
+struct testcase_t main_testcases[] = {
+ /* Some converted-over tests */
+ { "methods", test_methods, TT_FORK, NULL, NULL },
+ { "version", test_version, 0, NULL, NULL },
+ BASIC(base_features, TT_FORK|TT_NO_LOGS),
+ { "base_environ", test_base_environ, TT_FORK, NULL, NULL },
+
+ BASIC(event_base_new, TT_FORK|TT_NEED_SOCKETPAIR),
+ BASIC(free_active_base, TT_FORK|TT_NEED_SOCKETPAIR),
+
+ BASIC(manipulate_active_events, TT_FORK|TT_NEED_BASE),
+
+ BASIC(bad_assign, TT_FORK|TT_NEED_BASE|TT_NO_LOGS),
+ BASIC(bad_reentrant, TT_FORK|TT_NEED_BASE|TT_NO_LOGS),
+
+ LEGACY(persistent_timeout, TT_FORK|TT_NEED_BASE),
+ { "persistent_timeout_jump", test_persistent_timeout_jump, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "persistent_active_timeout", test_persistent_active_timeout,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ LEGACY(priorities, TT_FORK|TT_NEED_BASE),
+ BASIC(priority_active_inversion, TT_FORK|TT_NEED_BASE),
+ { "common_timeout", test_common_timeout, TT_FORK|TT_NEED_BASE,
+ &basic_setup, NULL },
+
+ /* These legacy tests may not all need all of these flags. */
+ LEGACY(simpleread, TT_ISOLATED),
+ LEGACY(simpleread_multiple, TT_ISOLATED),
+ LEGACY(simplewrite, TT_ISOLATED),
+ { "simpleclose", test_simpleclose, TT_FORK, &basic_setup,
+ NULL },
+ LEGACY(multiple, TT_ISOLATED),
+ LEGACY(persistent, TT_ISOLATED),
+ LEGACY(combined, TT_ISOLATED),
+ LEGACY(simpletimeout, TT_ISOLATED),
+ LEGACY(loopbreak, TT_ISOLATED),
+ LEGACY(loopexit, TT_ISOLATED),
+ LEGACY(loopexit_multiple, TT_ISOLATED),
+ LEGACY(nonpersist_readd, TT_ISOLATED),
+ LEGACY(multiple_events_for_same_fd, TT_ISOLATED),
+ LEGACY(want_only_once, TT_ISOLATED),
+ { "event_once", test_event_once, TT_ISOLATED, &basic_setup, NULL },
+ { "event_pending", test_event_pending, TT_ISOLATED, &basic_setup,
+ NULL },
+#ifndef WIN32
+ { "dup_fd", test_dup_fd, TT_ISOLATED, &basic_setup, NULL },
+#endif
+ { "mm_functions", test_mm_functions, TT_FORK, NULL, NULL },
+ { "many_events", test_many_events, TT_ISOLATED, &basic_setup, NULL },
+ { "many_events_slow_add", test_many_events, TT_ISOLATED, &basic_setup, (void*)1 },
+
+ { "struct_event_size", test_struct_event_size, 0, NULL, NULL },
+
+#ifndef WIN32
+ LEGACY(fork, TT_ISOLATED),
+#endif
+ END_OF_TESTCASES
+};
+
+struct testcase_t evtag_testcases[] = {
+ { "int", evtag_int_test, TT_FORK, NULL, NULL },
+ { "fuzz", evtag_fuzz, TT_FORK, NULL, NULL },
+ { "encoding", evtag_tag_encoding, TT_FORK, NULL, NULL },
+ { "peek", evtag_test_peek, 0, NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
+struct testcase_t signal_testcases[] = {
+#ifndef WIN32
+ LEGACY(simplesignal, TT_ISOLATED),
+ LEGACY(multiplesignal, TT_ISOLATED),
+ LEGACY(immediatesignal, TT_ISOLATED),
+ LEGACY(signal_dealloc, TT_ISOLATED),
+ LEGACY(signal_pipeloss, TT_ISOLATED),
+ LEGACY(signal_switchbase, TT_ISOLATED|TT_NO_LOGS),
+ LEGACY(signal_restore, TT_ISOLATED),
+ LEGACY(signal_assert, TT_ISOLATED),
+ LEGACY(signal_while_processing, TT_ISOLATED),
+#endif
+ END_OF_TESTCASES
+};
+
diff --git a/libevent-2.0.20-stable/test/regress.gen.c b/libevent-2.0.20-stable/test/regress.gen.c
new file mode 100644
index 0000000..141f4f4
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress.gen.c
@@ -0,0 +1,1225 @@
+/*
+ * Automatically generated from ./regress.rpc
+ * by event_rpcgen.py/0.1. DO NOT EDIT THIS FILE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <event2/event-config.h>
+#include <event2/event.h>
+#include <event2/buffer.h>
+#include <event2/tag.h>
+
+#ifdef _EVENT___func__
+#define __func__ _EVENT___func__
+#endif
+
+
+#include "regress.gen.h"
+
+void event_warn(const char *fmt, ...);
+void event_warnx(const char *fmt, ...);
+
+
+/*
+ * Implementation of msg
+ */
+
+static struct msg_access_ __msg_base = {
+ msg_from_name_assign,
+ msg_from_name_get,
+ msg_to_name_assign,
+ msg_to_name_get,
+ msg_attack_assign,
+ msg_attack_get,
+ msg_run_assign,
+ msg_run_get,
+ msg_run_add,
+};
+
+struct msg *
+msg_new(void)
+{
+ return msg_new_with_arg(NULL);
+}
+
+struct msg *
+msg_new_with_arg(void *unused)
+{
+ struct msg *tmp;
+ if ((tmp = malloc(sizeof(struct msg))) == NULL) {
+ event_warn("%s: malloc", __func__);
+ return (NULL);
+ }
+ tmp->base = &__msg_base;
+
+ tmp->from_name_data = NULL;
+ tmp->from_name_set = 0;
+
+ tmp->to_name_data = NULL;
+ tmp->to_name_set = 0;
+
+ tmp->attack_data = NULL;
+ tmp->attack_set = 0;
+
+ tmp->run_data = NULL;
+ tmp->run_length = 0;
+ tmp->run_num_allocated = 0;
+ tmp->run_set = 0;
+
+ return (tmp);
+}
+
+
+
+
+static int
+msg_run_expand_to_hold_more(struct msg *msg)
+{
+ int tobe_allocated = msg->run_num_allocated;
+ struct run** new_data = NULL;
+ tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;
+ new_data = (struct run**) realloc(msg->run_data,
+ tobe_allocated * sizeof(struct run*));
+ if (new_data == NULL)
+ return -1;
+ msg->run_data = new_data;
+ msg->run_num_allocated = tobe_allocated;
+ return 0;}
+
+struct run*
+msg_run_add(struct msg *msg)
+{
+ if (++msg->run_length >= msg->run_num_allocated) {
+ if (msg_run_expand_to_hold_more(msg)<0)
+ goto error;
+ }
+ msg->run_data[msg->run_length - 1] = run_new();
+ if (msg->run_data[msg->run_length - 1] == NULL)
+ goto error;
+ msg->run_set = 1;
+ return (msg->run_data[msg->run_length - 1]);
+error:
+ --msg->run_length;
+ return (NULL);
+}
+
+int
+msg_from_name_assign(struct msg *msg,
+ const char * value)
+{
+ if (msg->from_name_data != NULL)
+ free(msg->from_name_data);
+ if ((msg->from_name_data = strdup(value)) == NULL)
+ return (-1);
+ msg->from_name_set = 1;
+ return (0);
+}
+
+int
+msg_to_name_assign(struct msg *msg,
+ const char * value)
+{
+ if (msg->to_name_data != NULL)
+ free(msg->to_name_data);
+ if ((msg->to_name_data = strdup(value)) == NULL)
+ return (-1);
+ msg->to_name_set = 1;
+ return (0);
+}
+
+int
+msg_attack_assign(struct msg *msg,
+ const struct kill* value)
+{
+ struct evbuffer *tmp = NULL;
+ if (msg->attack_set) {
+ kill_clear(msg->attack_data);
+ msg->attack_set = 0;
+ } else {
+ msg->attack_data = kill_new();
+ if (msg->attack_data == NULL) {
+ event_warn("%s: kill_new()", __func__);
+ goto error;
+ }
+ }
+ if ((tmp = evbuffer_new()) == NULL) {
+ event_warn("%s: evbuffer_new()", __func__);
+ goto error;
+ }
+ kill_marshal(tmp, value);
+ if (kill_unmarshal(msg->attack_data, tmp) == -1) {
+ event_warnx("%s: kill_unmarshal", __func__);
+ goto error;
+ }
+ msg->attack_set = 1;
+ evbuffer_free(tmp);
+ return (0);
+ error:
+ if (tmp != NULL)
+ evbuffer_free(tmp);
+ if (msg->attack_data != NULL) {
+ kill_free(msg->attack_data);
+ msg->attack_data = NULL;
+ }
+ return (-1);
+}
+
+int
+msg_run_assign(struct msg *msg, int off,
+ const struct run* value)
+{
+ if (!msg->run_set || off < 0 || off >= msg->run_length)
+ return (-1);
+
+ {
+ int had_error = 0;
+ struct evbuffer *tmp = NULL;
+ run_clear(msg->run_data[off]);
+ if ((tmp = evbuffer_new()) == NULL) {
+ event_warn("%s: evbuffer_new()", __func__);
+ had_error = 1;
+ goto done;
+ }
+ run_marshal(tmp, value);
+ if (run_unmarshal(msg->run_data[off], tmp) == -1) {
+ event_warnx("%s: run_unmarshal", __func__);
+ had_error = 1;
+ goto done;
+ }
+ done:if (tmp != NULL)
+ evbuffer_free(tmp);
+ if (had_error) {
+ run_clear(msg->run_data[off]);
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+int
+msg_from_name_get(struct msg *msg, char * *value)
+{
+ if (msg->from_name_set != 1)
+ return (-1);
+ *value = msg->from_name_data;
+ return (0);
+}
+
+int
+msg_to_name_get(struct msg *msg, char * *value)
+{
+ if (msg->to_name_set != 1)
+ return (-1);
+ *value = msg->to_name_data;
+ return (0);
+}
+
+int
+msg_attack_get(struct msg *msg, struct kill* *value)
+{
+ if (msg->attack_set != 1) {
+ msg->attack_data = kill_new();
+ if (msg->attack_data == NULL)
+ return (-1);
+ msg->attack_set = 1;
+ }
+ *value = msg->attack_data;
+ return (0);
+}
+
+int
+msg_run_get(struct msg *msg, int offset,
+ struct run* *value)
+{
+ if (!msg->run_set || offset < 0 || offset >= msg->run_length)
+ return (-1);
+ *value = msg->run_data[offset];
+ return (0);
+}
+
+void
+msg_clear(struct msg *tmp)
+{
+ if (tmp->from_name_set == 1) {
+ free(tmp->from_name_data);
+ tmp->from_name_data = NULL;
+ tmp->from_name_set = 0;
+ }
+ if (tmp->to_name_set == 1) {
+ free(tmp->to_name_data);
+ tmp->to_name_data = NULL;
+ tmp->to_name_set = 0;
+ }
+ if (tmp->attack_set == 1) {
+ kill_free(tmp->attack_data);
+ tmp->attack_data = NULL;
+ tmp->attack_set = 0;
+ }
+ if (tmp->run_set == 1) {
+ int i;
+ for (i = 0; i < tmp->run_length; ++i) {
+ run_free(tmp->run_data[i]);
+ }
+ free(tmp->run_data);
+ tmp->run_data = NULL;
+ tmp->run_set = 0;
+ tmp->run_length = 0;
+ tmp->run_num_allocated = 0;
+ }
+}
+
+void
+msg_free(struct msg *tmp)
+{
+ if (tmp->from_name_data != NULL)
+ free (tmp->from_name_data);
+ if (tmp->to_name_data != NULL)
+ free (tmp->to_name_data);
+ if (tmp->attack_data != NULL)
+ kill_free(tmp->attack_data);
+ if (tmp->run_set == 1) {
+ int i;
+ for (i = 0; i < tmp->run_length; ++i) {
+ run_free(tmp->run_data[i]);
+ }
+ free(tmp->run_data);
+ tmp->run_data = NULL;
+ tmp->run_set = 0;
+ tmp->run_length = 0;
+ tmp->run_num_allocated = 0;
+ }
+ free(tmp->run_data);
+ free(tmp);
+}
+
+void
+msg_marshal(struct evbuffer *evbuf, const struct msg *tmp){
+ evtag_marshal_string(evbuf, MSG_FROM_NAME, tmp->from_name_data);
+ evtag_marshal_string(evbuf, MSG_TO_NAME, tmp->to_name_data);
+ if (tmp->attack_set) {
+ evtag_marshal_kill(evbuf, MSG_ATTACK, tmp->attack_data);
+ }
+ if (tmp->run_set) {
+ {
+ int i;
+ for (i = 0; i < tmp->run_length; ++i) {
+ evtag_marshal_run(evbuf, MSG_RUN, tmp->run_data[i]);
+ }
+ }
+ }
+}
+
+int
+msg_unmarshal(struct msg *tmp, struct evbuffer *evbuf)
+{
+ ev_uint32_t tag;
+ while (evbuffer_get_length(evbuf) > 0) {
+ if (evtag_peek(evbuf, &tag) == -1)
+ return (-1);
+ switch (tag) {
+
+ case MSG_FROM_NAME:
+
+ if (tmp->from_name_set)
+ return (-1);
+ if (evtag_unmarshal_string(evbuf, MSG_FROM_NAME, &tmp->from_name_data) == -1) {
+ event_warnx("%s: failed to unmarshal from_name", __func__);
+ return (-1);
+ }
+ tmp->from_name_set = 1;
+ break;
+
+ case MSG_TO_NAME:
+
+ if (tmp->to_name_set)
+ return (-1);
+ if (evtag_unmarshal_string(evbuf, MSG_TO_NAME, &tmp->to_name_data) == -1) {
+ event_warnx("%s: failed to unmarshal to_name", __func__);
+ return (-1);
+ }
+ tmp->to_name_set = 1;
+ break;
+
+ case MSG_ATTACK:
+
+ if (tmp->attack_set)
+ return (-1);
+ tmp->attack_data = kill_new();
+ if (tmp->attack_data == NULL)
+ return (-1);
+ if (evtag_unmarshal_kill(evbuf, MSG_ATTACK, tmp->attack_data) == -1) {
+ event_warnx("%s: failed to unmarshal attack", __func__);
+ return (-1);
+ }
+ tmp->attack_set = 1;
+ break;
+
+ case MSG_RUN:
+
+ if (tmp->run_length >= tmp->run_num_allocated &&
+ msg_run_expand_to_hold_more(tmp) < 0) {
+ puts("HEY NOW");
+ return (-1);
+ }
+ tmp->run_data[tmp->run_length] = run_new();
+ if (tmp->run_data[tmp->run_length] == NULL)
+ return (-1);
+ if (evtag_unmarshal_run(evbuf, MSG_RUN, tmp->run_data[tmp->run_length]) == -1) {
+ event_warnx("%s: failed to unmarshal run", __func__);
+ return (-1);
+ }
+ ++tmp->run_length;
+ tmp->run_set = 1;
+ break;
+
+ default:
+ return -1;
+ }
+ }
+
+ if (msg_complete(tmp) == -1)
+ return (-1);
+ return (0);
+}
+
+int
+msg_complete(struct msg *msg)
+{
+ if (!msg->from_name_set)
+ return (-1);
+ if (!msg->to_name_set)
+ return (-1);
+ if (msg->attack_set && kill_complete(msg->attack_data) == -1)
+ return (-1);
+ {
+ int i;
+ for (i = 0; i < msg->run_length; ++i) {
+ if (msg->run_set && run_complete(msg->run_data[i]) == -1)
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+int
+evtag_unmarshal_msg(struct evbuffer *evbuf, ev_uint32_t need_tag, struct msg *msg)
+{
+ ev_uint32_t tag;
+ int res = -1;
+
+ struct evbuffer *tmp = evbuffer_new();
+
+ if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag)
+ goto error;
+
+ if (msg_unmarshal(msg, tmp) == -1)
+ goto error;
+
+ res = 0;
+
+ error:
+ evbuffer_free(tmp);
+ return (res);
+}
+
+void
+evtag_marshal_msg(struct evbuffer *evbuf, ev_uint32_t tag, const struct msg *msg)
+{
+ struct evbuffer *_buf = evbuffer_new();
+ assert(_buf != NULL);
+ msg_marshal(_buf, msg);
+ evtag_marshal_buffer(evbuf, tag, _buf);
+ evbuffer_free(_buf);
+}
+
+/*
+ * Implementation of kill
+ */
+
+static struct kill_access_ __kill_base = {
+ kill_weapon_assign,
+ kill_weapon_get,
+ kill_action_assign,
+ kill_action_get,
+ kill_how_often_assign,
+ kill_how_often_get,
+ kill_how_often_add,
+};
+
+struct kill *
+kill_new(void)
+{
+ return kill_new_with_arg(NULL);
+}
+
+struct kill *
+kill_new_with_arg(void *unused)
+{
+ struct kill *tmp;
+ if ((tmp = malloc(sizeof(struct kill))) == NULL) {
+ event_warn("%s: malloc", __func__);
+ return (NULL);
+ }
+ tmp->base = &__kill_base;
+
+ tmp->weapon_data = NULL;
+ tmp->weapon_set = 0;
+
+ tmp->action_data = NULL;
+ tmp->action_set = 0;
+
+ tmp->how_often_data = NULL;
+ tmp->how_often_length = 0;
+ tmp->how_often_num_allocated = 0;
+ tmp->how_often_set = 0;
+
+ return (tmp);
+}
+
+
+
+static int
+kill_how_often_expand_to_hold_more(struct kill *msg)
+{
+ int tobe_allocated = msg->how_often_num_allocated;
+ ev_uint32_t* new_data = NULL;
+ tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;
+ new_data = (ev_uint32_t*) realloc(msg->how_often_data,
+ tobe_allocated * sizeof(ev_uint32_t));
+ if (new_data == NULL)
+ return -1;
+ msg->how_often_data = new_data;
+ msg->how_often_num_allocated = tobe_allocated;
+ return 0;}
+
+ev_uint32_t *
+kill_how_often_add(struct kill *msg, const ev_uint32_t value)
+{
+ if (++msg->how_often_length >= msg->how_often_num_allocated) {
+ if (kill_how_often_expand_to_hold_more(msg)<0)
+ goto error;
+ }
+ msg->how_often_data[msg->how_often_length - 1] = value;
+ msg->how_often_set = 1;
+ return &(msg->how_often_data[msg->how_often_length - 1]);
+error:
+ --msg->how_often_length;
+ return (NULL);
+}
+
+int
+kill_weapon_assign(struct kill *msg,
+ const char * value)
+{
+ if (msg->weapon_data != NULL)
+ free(msg->weapon_data);
+ if ((msg->weapon_data = strdup(value)) == NULL)
+ return (-1);
+ msg->weapon_set = 1;
+ return (0);
+}
+
+int
+kill_action_assign(struct kill *msg,
+ const char * value)
+{
+ if (msg->action_data != NULL)
+ free(msg->action_data);
+ if ((msg->action_data = strdup(value)) == NULL)
+ return (-1);
+ msg->action_set = 1;
+ return (0);
+}
+
+int
+kill_how_often_assign(struct kill *msg, int off,
+ const ev_uint32_t value)
+{
+ if (!msg->how_often_set || off < 0 || off >= msg->how_often_length)
+ return (-1);
+
+ {
+ msg->how_often_data[off] = value;
+ }
+ return (0);
+}
+
+int
+kill_weapon_get(struct kill *msg, char * *value)
+{
+ if (msg->weapon_set != 1)
+ return (-1);
+ *value = msg->weapon_data;
+ return (0);
+}
+
+int
+kill_action_get(struct kill *msg, char * *value)
+{
+ if (msg->action_set != 1)
+ return (-1);
+ *value = msg->action_data;
+ return (0);
+}
+
+int
+kill_how_often_get(struct kill *msg, int offset,
+ ev_uint32_t *value)
+{
+ if (!msg->how_often_set || offset < 0 || offset >= msg->how_often_length)
+ return (-1);
+ *value = msg->how_often_data[offset];
+ return (0);
+}
+
+void
+kill_clear(struct kill *tmp)
+{
+ if (tmp->weapon_set == 1) {
+ free(tmp->weapon_data);
+ tmp->weapon_data = NULL;
+ tmp->weapon_set = 0;
+ }
+ if (tmp->action_set == 1) {
+ free(tmp->action_data);
+ tmp->action_data = NULL;
+ tmp->action_set = 0;
+ }
+ if (tmp->how_often_set == 1) {
+ free(tmp->how_often_data);
+ tmp->how_often_data = NULL;
+ tmp->how_often_set = 0;
+ tmp->how_often_length = 0;
+ tmp->how_often_num_allocated = 0;
+ }
+}
+
+void
+kill_free(struct kill *tmp)
+{
+ if (tmp->weapon_data != NULL)
+ free (tmp->weapon_data);
+ if (tmp->action_data != NULL)
+ free (tmp->action_data);
+ if (tmp->how_often_set == 1) {
+ free(tmp->how_often_data);
+ tmp->how_often_data = NULL;
+ tmp->how_often_set = 0;
+ tmp->how_often_length = 0;
+ tmp->how_often_num_allocated = 0;
+ }
+ free(tmp->how_often_data);
+ free(tmp);
+}
+
+void
+kill_marshal(struct evbuffer *evbuf, const struct kill *tmp){
+ evtag_marshal_string(evbuf, KILL_WEAPON, tmp->weapon_data);
+ evtag_marshal_string(evbuf, KILL_ACTION, tmp->action_data);
+ if (tmp->how_often_set) {
+ {
+ int i;
+ for (i = 0; i < tmp->how_often_length; ++i) {
+ evtag_marshal_int(evbuf, KILL_HOW_OFTEN, tmp->how_often_data[i]);
+ }
+ }
+ }
+}
+
+int
+kill_unmarshal(struct kill *tmp, struct evbuffer *evbuf)
+{
+ ev_uint32_t tag;
+ while (evbuffer_get_length(evbuf) > 0) {
+ if (evtag_peek(evbuf, &tag) == -1)
+ return (-1);
+ switch (tag) {
+
+ case KILL_WEAPON:
+
+ if (tmp->weapon_set)
+ return (-1);
+ if (evtag_unmarshal_string(evbuf, KILL_WEAPON, &tmp->weapon_data) == -1) {
+ event_warnx("%s: failed to unmarshal weapon", __func__);
+ return (-1);
+ }
+ tmp->weapon_set = 1;
+ break;
+
+ case KILL_ACTION:
+
+ if (tmp->action_set)
+ return (-1);
+ if (evtag_unmarshal_string(evbuf, KILL_ACTION, &tmp->action_data) == -1) {
+ event_warnx("%s: failed to unmarshal action", __func__);
+ return (-1);
+ }
+ tmp->action_set = 1;
+ break;
+
+ case KILL_HOW_OFTEN:
+
+ if (tmp->how_often_length >= tmp->how_often_num_allocated &&
+ kill_how_often_expand_to_hold_more(tmp) < 0) {
+ puts("HEY NOW");
+ return (-1);
+ }
+ if (evtag_unmarshal_int(evbuf, KILL_HOW_OFTEN, &tmp->how_often_data[tmp->how_often_length]) == -1) {
+ event_warnx("%s: failed to unmarshal how_often", __func__);
+ return (-1);
+ }
+ ++tmp->how_often_length;
+ tmp->how_often_set = 1;
+ break;
+
+ default:
+ return -1;
+ }
+ }
+
+ if (kill_complete(tmp) == -1)
+ return (-1);
+ return (0);
+}
+
+int
+kill_complete(struct kill *msg)
+{
+ if (!msg->weapon_set)
+ return (-1);
+ if (!msg->action_set)
+ return (-1);
+ return (0);
+}
+
+int
+evtag_unmarshal_kill(struct evbuffer *evbuf, ev_uint32_t need_tag, struct kill *msg)
+{
+ ev_uint32_t tag;
+ int res = -1;
+
+ struct evbuffer *tmp = evbuffer_new();
+
+ if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag)
+ goto error;
+
+ if (kill_unmarshal(msg, tmp) == -1)
+ goto error;
+
+ res = 0;
+
+ error:
+ evbuffer_free(tmp);
+ return (res);
+}
+
+void
+evtag_marshal_kill(struct evbuffer *evbuf, ev_uint32_t tag, const struct kill *msg)
+{
+ struct evbuffer *_buf = evbuffer_new();
+ assert(_buf != NULL);
+ kill_marshal(_buf, msg);
+ evtag_marshal_buffer(evbuf, tag, _buf);
+ evbuffer_free(_buf);
+}
+
+/*
+ * Implementation of run
+ */
+
+static struct run_access_ __run_base = {
+ run_how_assign,
+ run_how_get,
+ run_some_bytes_assign,
+ run_some_bytes_get,
+ run_fixed_bytes_assign,
+ run_fixed_bytes_get,
+ run_notes_assign,
+ run_notes_get,
+ run_notes_add,
+ run_large_number_assign,
+ run_large_number_get,
+ run_other_numbers_assign,
+ run_other_numbers_get,
+ run_other_numbers_add,
+};
+
+struct run *
+run_new(void)
+{
+ return run_new_with_arg(NULL);
+}
+
+struct run *
+run_new_with_arg(void *unused)
+{
+ struct run *tmp;
+ if ((tmp = malloc(sizeof(struct run))) == NULL) {
+ event_warn("%s: malloc", __func__);
+ return (NULL);
+ }
+ tmp->base = &__run_base;
+
+ tmp->how_data = NULL;
+ tmp->how_set = 0;
+
+ tmp->some_bytes_data = NULL;
+ tmp->some_bytes_length = 0;
+ tmp->some_bytes_set = 0;
+
+ memset(tmp->fixed_bytes_data, 0, sizeof(tmp->fixed_bytes_data));
+ tmp->fixed_bytes_set = 0;
+
+ tmp->notes_data = NULL;
+ tmp->notes_length = 0;
+ tmp->notes_num_allocated = 0;
+ tmp->notes_set = 0;
+
+ tmp->large_number_data = 0;
+ tmp->large_number_set = 0;
+
+ tmp->other_numbers_data = NULL;
+ tmp->other_numbers_length = 0;
+ tmp->other_numbers_num_allocated = 0;
+ tmp->other_numbers_set = 0;
+
+ return (tmp);
+}
+
+
+
+
+static int
+run_notes_expand_to_hold_more(struct run *msg)
+{
+ int tobe_allocated = msg->notes_num_allocated;
+ char ** new_data = NULL;
+ tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;
+ new_data = (char **) realloc(msg->notes_data,
+ tobe_allocated * sizeof(char *));
+ if (new_data == NULL)
+ return -1;
+ msg->notes_data = new_data;
+ msg->notes_num_allocated = tobe_allocated;
+ return 0;}
+
+char * *
+run_notes_add(struct run *msg, const char * value)
+{
+ if (++msg->notes_length >= msg->notes_num_allocated) {
+ if (run_notes_expand_to_hold_more(msg)<0)
+ goto error;
+ }
+ if (value != NULL) {
+ msg->notes_data[msg->notes_length - 1] = strdup(value);
+ if (msg->notes_data[msg->notes_length - 1] == NULL) {
+ goto error;
+ }
+ } else {
+ msg->notes_data[msg->notes_length - 1] = NULL;
+ }
+ msg->notes_set = 1;
+ return &(msg->notes_data[msg->notes_length - 1]);
+error:
+ --msg->notes_length;
+ return (NULL);
+}
+
+
+static int
+run_other_numbers_expand_to_hold_more(struct run *msg)
+{
+ int tobe_allocated = msg->other_numbers_num_allocated;
+ ev_uint32_t* new_data = NULL;
+ tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;
+ new_data = (ev_uint32_t*) realloc(msg->other_numbers_data,
+ tobe_allocated * sizeof(ev_uint32_t));
+ if (new_data == NULL)
+ return -1;
+ msg->other_numbers_data = new_data;
+ msg->other_numbers_num_allocated = tobe_allocated;
+ return 0;}
+
+ev_uint32_t *
+run_other_numbers_add(struct run *msg, const ev_uint32_t value)
+{
+ if (++msg->other_numbers_length >= msg->other_numbers_num_allocated) {
+ if (run_other_numbers_expand_to_hold_more(msg)<0)
+ goto error;
+ }
+ msg->other_numbers_data[msg->other_numbers_length - 1] = value;
+ msg->other_numbers_set = 1;
+ return &(msg->other_numbers_data[msg->other_numbers_length - 1]);
+error:
+ --msg->other_numbers_length;
+ return (NULL);
+}
+
+int
+run_how_assign(struct run *msg,
+ const char * value)
+{
+ if (msg->how_data != NULL)
+ free(msg->how_data);
+ if ((msg->how_data = strdup(value)) == NULL)
+ return (-1);
+ msg->how_set = 1;
+ return (0);
+}
+
+int
+run_some_bytes_assign(struct run *msg, const ev_uint8_t * value, ev_uint32_t len)
+{
+ if (msg->some_bytes_data != NULL)
+ free (msg->some_bytes_data);
+ msg->some_bytes_data = malloc(len);
+ if (msg->some_bytes_data == NULL)
+ return (-1);
+ msg->some_bytes_set = 1;
+ msg->some_bytes_length = len;
+ memcpy(msg->some_bytes_data, value, len);
+ return (0);
+}
+
+int
+run_fixed_bytes_assign(struct run *msg, const ev_uint8_t *value)
+{
+ msg->fixed_bytes_set = 1;
+ memcpy(msg->fixed_bytes_data, value, 24);
+ return (0);
+}
+
+int
+run_notes_assign(struct run *msg, int off,
+ const char * value)
+{
+ if (!msg->notes_set || off < 0 || off >= msg->notes_length)
+ return (-1);
+
+ {
+ if (msg->notes_data[off] != NULL)
+ free(msg->notes_data[off]);
+ msg->notes_data[off] = strdup(value);
+ if (msg->notes_data[off] == NULL) {
+ event_warnx("%s: strdup", __func__);
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+int
+run_large_number_assign(struct run *msg, const ev_uint64_t value)
+{
+ msg->large_number_set = 1;
+ msg->large_number_data = value;
+ return (0);
+}
+
+int
+run_other_numbers_assign(struct run *msg, int off,
+ const ev_uint32_t value)
+{
+ if (!msg->other_numbers_set || off < 0 || off >= msg->other_numbers_length)
+ return (-1);
+
+ {
+ msg->other_numbers_data[off] = value;
+ }
+ return (0);
+}
+
+int
+run_how_get(struct run *msg, char * *value)
+{
+ if (msg->how_set != 1)
+ return (-1);
+ *value = msg->how_data;
+ return (0);
+}
+
+int
+run_some_bytes_get(struct run *msg, ev_uint8_t * *value, ev_uint32_t *plen)
+{
+ if (msg->some_bytes_set != 1)
+ return (-1);
+ *value = msg->some_bytes_data;
+ *plen = msg->some_bytes_length;
+ return (0);
+}
+
+int
+run_fixed_bytes_get(struct run *msg, ev_uint8_t **value)
+{
+ if (msg->fixed_bytes_set != 1)
+ return (-1);
+ *value = msg->fixed_bytes_data;
+ return (0);
+}
+
+int
+run_notes_get(struct run *msg, int offset,
+ char * *value)
+{
+ if (!msg->notes_set || offset < 0 || offset >= msg->notes_length)
+ return (-1);
+ *value = msg->notes_data[offset];
+ return (0);
+}
+
+int
+run_large_number_get(struct run *msg, ev_uint64_t *value)
+{
+ if (msg->large_number_set != 1)
+ return (-1);
+ *value = msg->large_number_data;
+ return (0);
+}
+
+int
+run_other_numbers_get(struct run *msg, int offset,
+ ev_uint32_t *value)
+{
+ if (!msg->other_numbers_set || offset < 0 || offset >= msg->other_numbers_length)
+ return (-1);
+ *value = msg->other_numbers_data[offset];
+ return (0);
+}
+
+void
+run_clear(struct run *tmp)
+{
+ if (tmp->how_set == 1) {
+ free(tmp->how_data);
+ tmp->how_data = NULL;
+ tmp->how_set = 0;
+ }
+ if (tmp->some_bytes_set == 1) {
+ free (tmp->some_bytes_data);
+ tmp->some_bytes_data = NULL;
+ tmp->some_bytes_length = 0;
+ tmp->some_bytes_set = 0;
+ }
+ tmp->fixed_bytes_set = 0;
+ memset(tmp->fixed_bytes_data, 0, sizeof(tmp->fixed_bytes_data));
+ if (tmp->notes_set == 1) {
+ int i;
+ for (i = 0; i < tmp->notes_length; ++i) {
+ if (tmp->notes_data[i] != NULL) free(tmp->notes_data[i]);
+ }
+ free(tmp->notes_data);
+ tmp->notes_data = NULL;
+ tmp->notes_set = 0;
+ tmp->notes_length = 0;
+ tmp->notes_num_allocated = 0;
+ }
+ tmp->large_number_set = 0;
+ if (tmp->other_numbers_set == 1) {
+ free(tmp->other_numbers_data);
+ tmp->other_numbers_data = NULL;
+ tmp->other_numbers_set = 0;
+ tmp->other_numbers_length = 0;
+ tmp->other_numbers_num_allocated = 0;
+ }
+}
+
+void
+run_free(struct run *tmp)
+{
+ if (tmp->how_data != NULL)
+ free (tmp->how_data);
+ if (tmp->some_bytes_data != NULL)
+ free(tmp->some_bytes_data);
+ if (tmp->notes_set == 1) {
+ int i;
+ for (i = 0; i < tmp->notes_length; ++i) {
+ if (tmp->notes_data[i] != NULL) free(tmp->notes_data[i]);
+ }
+ free(tmp->notes_data);
+ tmp->notes_data = NULL;
+ tmp->notes_set = 0;
+ tmp->notes_length = 0;
+ tmp->notes_num_allocated = 0;
+ }
+ free(tmp->notes_data);
+ if (tmp->other_numbers_set == 1) {
+ free(tmp->other_numbers_data);
+ tmp->other_numbers_data = NULL;
+ tmp->other_numbers_set = 0;
+ tmp->other_numbers_length = 0;
+ tmp->other_numbers_num_allocated = 0;
+ }
+ free(tmp->other_numbers_data);
+ free(tmp);
+}
+
+void
+run_marshal(struct evbuffer *evbuf, const struct run *tmp){
+ evtag_marshal_string(evbuf, RUN_HOW, tmp->how_data);
+ if (tmp->some_bytes_set) {
+ evtag_marshal(evbuf, RUN_SOME_BYTES, tmp->some_bytes_data, tmp->some_bytes_length);
+ }
+ evtag_marshal(evbuf, RUN_FIXED_BYTES, tmp->fixed_bytes_data, (24));
+ if (tmp->notes_set) {
+ {
+ int i;
+ for (i = 0; i < tmp->notes_length; ++i) {
+ evtag_marshal_string(evbuf, RUN_NOTES, tmp->notes_data[i]);
+ }
+ }
+ }
+ if (tmp->large_number_set) {
+ evtag_marshal_int64(evbuf, RUN_LARGE_NUMBER, tmp->large_number_data);
+ }
+ if (tmp->other_numbers_set) {
+ {
+ int i;
+ for (i = 0; i < tmp->other_numbers_length; ++i) {
+ evtag_marshal_int(evbuf, RUN_OTHER_NUMBERS, tmp->other_numbers_data[i]);
+ }
+ }
+ }
+}
+
+int
+run_unmarshal(struct run *tmp, struct evbuffer *evbuf)
+{
+ ev_uint32_t tag;
+ while (evbuffer_get_length(evbuf) > 0) {
+ if (evtag_peek(evbuf, &tag) == -1)
+ return (-1);
+ switch (tag) {
+
+ case RUN_HOW:
+
+ if (tmp->how_set)
+ return (-1);
+ if (evtag_unmarshal_string(evbuf, RUN_HOW, &tmp->how_data) == -1) {
+ event_warnx("%s: failed to unmarshal how", __func__);
+ return (-1);
+ }
+ tmp->how_set = 1;
+ break;
+
+ case RUN_SOME_BYTES:
+
+ if (tmp->some_bytes_set)
+ return (-1);
+ if (evtag_payload_length(evbuf, &tmp->some_bytes_length) == -1)
+ return (-1);
+ if (tmp->some_bytes_length > evbuffer_get_length(evbuf))
+ return (-1);
+ if ((tmp->some_bytes_data = malloc(tmp->some_bytes_length)) == NULL)
+ return (-1);
+ if (evtag_unmarshal_fixed(evbuf, RUN_SOME_BYTES, tmp->some_bytes_data, tmp->some_bytes_length) == -1) {
+ event_warnx("%s: failed to unmarshal some_bytes", __func__);
+ return (-1);
+ }
+ tmp->some_bytes_set = 1;
+ break;
+
+ case RUN_FIXED_BYTES:
+
+ if (tmp->fixed_bytes_set)
+ return (-1);
+ if (evtag_unmarshal_fixed(evbuf, RUN_FIXED_BYTES, tmp->fixed_bytes_data, (24)) == -1) {
+ event_warnx("%s: failed to unmarshal fixed_bytes", __func__);
+ return (-1);
+ }
+ tmp->fixed_bytes_set = 1;
+ break;
+
+ case RUN_NOTES:
+
+ if (tmp->notes_length >= tmp->notes_num_allocated &&
+ run_notes_expand_to_hold_more(tmp) < 0) {
+ puts("HEY NOW");
+ return (-1);
+ }
+ if (evtag_unmarshal_string(evbuf, RUN_NOTES, &tmp->notes_data[tmp->notes_length]) == -1) {
+ event_warnx("%s: failed to unmarshal notes", __func__);
+ return (-1);
+ }
+ ++tmp->notes_length;
+ tmp->notes_set = 1;
+ break;
+
+ case RUN_LARGE_NUMBER:
+
+ if (tmp->large_number_set)
+ return (-1);
+ if (evtag_unmarshal_int64(evbuf, RUN_LARGE_NUMBER, &tmp->large_number_data) == -1) {
+ event_warnx("%s: failed to unmarshal large_number", __func__);
+ return (-1);
+ }
+ tmp->large_number_set = 1;
+ break;
+
+ case RUN_OTHER_NUMBERS:
+
+ if (tmp->other_numbers_length >= tmp->other_numbers_num_allocated &&
+ run_other_numbers_expand_to_hold_more(tmp) < 0) {
+ puts("HEY NOW");
+ return (-1);
+ }
+ if (evtag_unmarshal_int(evbuf, RUN_OTHER_NUMBERS, &tmp->other_numbers_data[tmp->other_numbers_length]) == -1) {
+ event_warnx("%s: failed to unmarshal other_numbers", __func__);
+ return (-1);
+ }
+ ++tmp->other_numbers_length;
+ tmp->other_numbers_set = 1;
+ break;
+
+ default:
+ return -1;
+ }
+ }
+
+ if (run_complete(tmp) == -1)
+ return (-1);
+ return (0);
+}
+
+int
+run_complete(struct run *msg)
+{
+ if (!msg->how_set)
+ return (-1);
+ if (!msg->fixed_bytes_set)
+ return (-1);
+ return (0);
+}
+
+int
+evtag_unmarshal_run(struct evbuffer *evbuf, ev_uint32_t need_tag, struct run *msg)
+{
+ ev_uint32_t tag;
+ int res = -1;
+
+ struct evbuffer *tmp = evbuffer_new();
+
+ if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag)
+ goto error;
+
+ if (run_unmarshal(msg, tmp) == -1)
+ goto error;
+
+ res = 0;
+
+ error:
+ evbuffer_free(tmp);
+ return (res);
+}
+
+void
+evtag_marshal_run(struct evbuffer *evbuf, ev_uint32_t tag, const struct run *msg)
+{
+ struct evbuffer *_buf = evbuffer_new();
+ assert(_buf != NULL);
+ run_marshal(_buf, msg);
+ evtag_marshal_buffer(evbuf, tag, _buf);
+ evbuffer_free(_buf);
+}
+
diff --git a/libevent-2.0.20-stable/test/regress.gen.h b/libevent-2.0.20-stable/test/regress.gen.h
new file mode 100644
index 0000000..1281b94
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress.gen.h
@@ -0,0 +1,207 @@
+/*
+ * Automatically generated from ./regress.rpc
+ */
+
+#ifndef ___REGRESS_RPC_
+#define ___REGRESS_RPC_
+
+#include <event2/util.h> /* for ev_uint*_t */
+#include <event2/rpc.h>
+
+struct msg;
+struct kill;
+struct run;
+
+/* Tag definition for msg */
+enum msg_ {
+ MSG_FROM_NAME=1,
+ MSG_TO_NAME=2,
+ MSG_ATTACK=3,
+ MSG_RUN=4,
+ MSG_MAX_TAGS
+};
+
+/* Structure declaration for msg */
+struct msg_access_ {
+ int (*from_name_assign)(struct msg *, const char *);
+ int (*from_name_get)(struct msg *, char * *);
+ int (*to_name_assign)(struct msg *, const char *);
+ int (*to_name_get)(struct msg *, char * *);
+ int (*attack_assign)(struct msg *, const struct kill*);
+ int (*attack_get)(struct msg *, struct kill* *);
+ int (*run_assign)(struct msg *, int, const struct run*);
+ int (*run_get)(struct msg *, int, struct run* *);
+ struct run* (*run_add)(struct msg *msg);
+};
+
+struct msg {
+ struct msg_access_ *base;
+
+ char *from_name_data;
+ char *to_name_data;
+ struct kill* attack_data;
+ struct run* *run_data;
+ int run_length;
+ int run_num_allocated;
+
+ ev_uint8_t from_name_set;
+ ev_uint8_t to_name_set;
+ ev_uint8_t attack_set;
+ ev_uint8_t run_set;
+};
+
+struct msg *msg_new(void);
+struct msg *msg_new_with_arg(void *);
+void msg_free(struct msg *);
+void msg_clear(struct msg *);
+void msg_marshal(struct evbuffer *, const struct msg *);
+int msg_unmarshal(struct msg *, struct evbuffer *);
+int msg_complete(struct msg *);
+void evtag_marshal_msg(struct evbuffer *, ev_uint32_t,
+ const struct msg *);
+int evtag_unmarshal_msg(struct evbuffer *, ev_uint32_t,
+ struct msg *);
+int msg_from_name_assign(struct msg *, const char *);
+int msg_from_name_get(struct msg *, char * *);
+int msg_to_name_assign(struct msg *, const char *);
+int msg_to_name_get(struct msg *, char * *);
+int msg_attack_assign(struct msg *, const struct kill*);
+int msg_attack_get(struct msg *, struct kill* *);
+int msg_run_assign(struct msg *, int, const struct run*);
+int msg_run_get(struct msg *, int, struct run* *);
+struct run* msg_run_add(struct msg *msg);
+/* --- msg done --- */
+
+/* Tag definition for kill */
+enum kill_ {
+ KILL_WEAPON=65825,
+ KILL_ACTION=2,
+ KILL_HOW_OFTEN=3,
+ KILL_MAX_TAGS
+};
+
+/* Structure declaration for kill */
+struct kill_access_ {
+ int (*weapon_assign)(struct kill *, const char *);
+ int (*weapon_get)(struct kill *, char * *);
+ int (*action_assign)(struct kill *, const char *);
+ int (*action_get)(struct kill *, char * *);
+ int (*how_often_assign)(struct kill *, int, const ev_uint32_t);
+ int (*how_often_get)(struct kill *, int, ev_uint32_t *);
+ ev_uint32_t * (*how_often_add)(struct kill *msg, const ev_uint32_t value);
+};
+
+struct kill {
+ struct kill_access_ *base;
+
+ char *weapon_data;
+ char *action_data;
+ ev_uint32_t *how_often_data;
+ int how_often_length;
+ int how_often_num_allocated;
+
+ ev_uint8_t weapon_set;
+ ev_uint8_t action_set;
+ ev_uint8_t how_often_set;
+};
+
+struct kill *kill_new(void);
+struct kill *kill_new_with_arg(void *);
+void kill_free(struct kill *);
+void kill_clear(struct kill *);
+void kill_marshal(struct evbuffer *, const struct kill *);
+int kill_unmarshal(struct kill *, struct evbuffer *);
+int kill_complete(struct kill *);
+void evtag_marshal_kill(struct evbuffer *, ev_uint32_t,
+ const struct kill *);
+int evtag_unmarshal_kill(struct evbuffer *, ev_uint32_t,
+ struct kill *);
+int kill_weapon_assign(struct kill *, const char *);
+int kill_weapon_get(struct kill *, char * *);
+int kill_action_assign(struct kill *, const char *);
+int kill_action_get(struct kill *, char * *);
+int kill_how_often_assign(struct kill *, int, const ev_uint32_t);
+int kill_how_often_get(struct kill *, int, ev_uint32_t *);
+ev_uint32_t * kill_how_often_add(struct kill *msg, const ev_uint32_t value);
+/* --- kill done --- */
+
+/* Tag definition for run */
+enum run_ {
+ RUN_HOW=1,
+ RUN_SOME_BYTES=2,
+ RUN_FIXED_BYTES=3,
+ RUN_NOTES=4,
+ RUN_LARGE_NUMBER=5,
+ RUN_OTHER_NUMBERS=6,
+ RUN_MAX_TAGS
+};
+
+/* Structure declaration for run */
+struct run_access_ {
+ int (*how_assign)(struct run *, const char *);
+ int (*how_get)(struct run *, char * *);
+ int (*some_bytes_assign)(struct run *, const ev_uint8_t *, ev_uint32_t);
+ int (*some_bytes_get)(struct run *, ev_uint8_t * *, ev_uint32_t *);
+ int (*fixed_bytes_assign)(struct run *, const ev_uint8_t *);
+ int (*fixed_bytes_get)(struct run *, ev_uint8_t **);
+ int (*notes_assign)(struct run *, int, const char *);
+ int (*notes_get)(struct run *, int, char * *);
+ char * * (*notes_add)(struct run *msg, const char * value);
+ int (*large_number_assign)(struct run *, const ev_uint64_t);
+ int (*large_number_get)(struct run *, ev_uint64_t *);
+ int (*other_numbers_assign)(struct run *, int, const ev_uint32_t);
+ int (*other_numbers_get)(struct run *, int, ev_uint32_t *);
+ ev_uint32_t * (*other_numbers_add)(struct run *msg, const ev_uint32_t value);
+};
+
+struct run {
+ struct run_access_ *base;
+
+ char *how_data;
+ ev_uint8_t *some_bytes_data;
+ ev_uint32_t some_bytes_length;
+ ev_uint8_t fixed_bytes_data[24];
+ char * *notes_data;
+ int notes_length;
+ int notes_num_allocated;
+ ev_uint64_t large_number_data;
+ ev_uint32_t *other_numbers_data;
+ int other_numbers_length;
+ int other_numbers_num_allocated;
+
+ ev_uint8_t how_set;
+ ev_uint8_t some_bytes_set;
+ ev_uint8_t fixed_bytes_set;
+ ev_uint8_t notes_set;
+ ev_uint8_t large_number_set;
+ ev_uint8_t other_numbers_set;
+};
+
+struct run *run_new(void);
+struct run *run_new_with_arg(void *);
+void run_free(struct run *);
+void run_clear(struct run *);
+void run_marshal(struct evbuffer *, const struct run *);
+int run_unmarshal(struct run *, struct evbuffer *);
+int run_complete(struct run *);
+void evtag_marshal_run(struct evbuffer *, ev_uint32_t,
+ const struct run *);
+int evtag_unmarshal_run(struct evbuffer *, ev_uint32_t,
+ struct run *);
+int run_how_assign(struct run *, const char *);
+int run_how_get(struct run *, char * *);
+int run_some_bytes_assign(struct run *, const ev_uint8_t *, ev_uint32_t);
+int run_some_bytes_get(struct run *, ev_uint8_t * *, ev_uint32_t *);
+int run_fixed_bytes_assign(struct run *, const ev_uint8_t *);
+int run_fixed_bytes_get(struct run *, ev_uint8_t **);
+int run_notes_assign(struct run *, int, const char *);
+int run_notes_get(struct run *, int, char * *);
+char * * run_notes_add(struct run *msg, const char * value);
+int run_large_number_assign(struct run *, const ev_uint64_t);
+int run_large_number_get(struct run *, ev_uint64_t *);
+int run_other_numbers_assign(struct run *, int, const ev_uint32_t);
+int run_other_numbers_get(struct run *, int, ev_uint32_t *);
+ev_uint32_t * run_other_numbers_add(struct run *msg, const ev_uint32_t value);
+/* --- run done --- */
+
+#endif /* ___REGRESS_RPC_ */
diff --git a/libevent-2.0.20-stable/test/regress.h b/libevent-2.0.20-stable/test/regress.h
new file mode 100644
index 0000000..78dc3d0
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _REGRESS_H_
+#define _REGRESS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "tinytest.h"
+#include "tinytest_macros.h"
+
+extern struct testcase_t main_testcases[];
+extern struct testcase_t evtag_testcases[];
+extern struct testcase_t evbuffer_testcases[];
+extern struct testcase_t bufferevent_testcases[];
+extern struct testcase_t bufferevent_iocp_testcases[];
+extern struct testcase_t util_testcases[];
+extern struct testcase_t signal_testcases[];
+extern struct testcase_t http_testcases[];
+extern struct testcase_t dns_testcases[];
+extern struct testcase_t rpc_testcases[];
+extern struct testcase_t edgetriggered_testcases[];
+extern struct testcase_t minheap_testcases[];
+extern struct testcase_t iocp_testcases[];
+extern struct testcase_t ssl_testcases[];
+extern struct testcase_t listener_testcases[];
+extern struct testcase_t listener_iocp_testcases[];
+extern struct testcase_t thread_testcases[];
+
+void regress_threads(void *);
+void test_bufferevent_zlib(void *);
+
+/* Helpers to wrap old testcases */
+extern evutil_socket_t pair[2];
+extern int test_ok;
+extern int called;
+extern struct event_base *global_base;
+extern int in_legacy_test_wrapper;
+
+int regress_make_tmpfile(const void *data, size_t datalen);
+
+struct basic_test_data {
+ struct event_base *base;
+ evutil_socket_t pair[2];
+
+ void (*legacy_test_fn)(void);
+
+ void *setup_data;
+};
+extern const struct testcase_setup_t basic_setup;
+
+
+extern const struct testcase_setup_t legacy_setup;
+void run_legacy_test_fn(void *ptr);
+
+/* A couple of flags that basic/legacy_setup can support. */
+#define TT_NEED_SOCKETPAIR TT_FIRST_USER_FLAG
+#define TT_NEED_BASE (TT_FIRST_USER_FLAG<<1)
+#define TT_NEED_DNS (TT_FIRST_USER_FLAG<<2)
+#define TT_LEGACY (TT_FIRST_USER_FLAG<<3)
+#define TT_NEED_THREADS (TT_FIRST_USER_FLAG<<4)
+#define TT_NO_LOGS (TT_FIRST_USER_FLAG<<5)
+#define TT_ENABLE_IOCP_FLAG (TT_FIRST_USER_FLAG<<6)
+#define TT_ENABLE_IOCP (TT_ENABLE_IOCP_FLAG|TT_NEED_THREADS)
+
+/* All the flags that a legacy test needs. */
+#define TT_ISOLATED TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE
+
+
+#define BASIC(name,flags) \
+ { #name, test_## name, flags, &basic_setup, NULL }
+
+#define LEGACY(name,flags) \
+ { #name, run_legacy_test_fn, flags|TT_LEGACY, &legacy_setup, \
+ test_## name }
+
+struct evutil_addrinfo;
+struct evutil_addrinfo *ai_find_by_family(struct evutil_addrinfo *ai, int f);
+struct evutil_addrinfo *ai_find_by_protocol(struct evutil_addrinfo *ai, int p);
+int _test_ai_eq(const struct evutil_addrinfo *ai, const char *sockaddr_port,
+ int socktype, int protocol, int line);
+
+#define test_ai_eq(ai, str, s, p) do { \
+ if (_test_ai_eq((ai), (str), (s), (p), __LINE__)<0) \
+ goto end; \
+ } while (0)
+
+#define test_timeval_diff_leq(tv1, tv2, diff, tolerance) \
+ tt_int_op(abs(timeval_msec_diff((tv1), (tv2)) - diff), <=, tolerance)
+
+#define test_timeval_diff_eq(tv1, tv2, diff) \
+ test_timeval_diff_leq((tv1), (tv2), (diff), 50)
+
+long timeval_msec_diff(const struct timeval *start, const struct timeval *end);
+
+#ifndef _WIN32
+pid_t regress_fork(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _REGRESS_H_ */
diff --git a/libevent-2.0.20-stable/test/regress.rpc b/libevent-2.0.20-stable/test/regress.rpc
new file mode 100644
index 0000000..0ee904e
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress.rpc
@@ -0,0 +1,25 @@
+/* tests data packing and unpacking */
+
+struct msg {
+ string /* sender */ from_name = 1; /* be verbose */
+ string to_name = 2;
+ optional struct[kill] attack = 3;
+ array struct[run] run = 4;
+}
+
+struct kill {
+ string weapon = 0x10121;
+ string action = 2;
+ array int how_often = 3;
+}
+
+struct run {
+ string how = 1;
+ optional bytes some_bytes = 2;
+
+ bytes fixed_bytes[24] = 3;
+ array string notes = 4;
+
+ optional int64 large_number = 5;
+ array int other_numbers = 6;
+}
diff --git a/libevent-2.0.20-stable/test/regress_buffer.c b/libevent-2.0.20-stable/test/regress_buffer.c
new file mode 100644
index 0000000..99a8c0e
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress_buffer.c
@@ -0,0 +1,1677 @@
+/*
+ * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "event2/event.h"
+#include "event2/buffer.h"
+#include "event2/buffer_compat.h"
+#include "event2/util.h"
+
+#include "evbuffer-internal.h"
+#include "log-internal.h"
+
+#include "regress.h"
+
+/* Validates that an evbuffer is good. Returns false if it isn't, true if it
+ * is*/
+static int
+_evbuffer_validate(struct evbuffer *buf)
+{
+ struct evbuffer_chain *chain;
+ size_t sum = 0;
+ int found_last_with_datap = 0;
+
+ if (buf->first == NULL) {
+ tt_assert(buf->last == NULL);
+ tt_assert(buf->total_len == 0);
+ }
+
+ chain = buf->first;
+
+ tt_assert(buf->last_with_datap);
+ if (buf->last_with_datap == &buf->first)
+ found_last_with_datap = 1;
+
+ while (chain != NULL) {
+ if (&chain->next == buf->last_with_datap)
+ found_last_with_datap = 1;
+ sum += chain->off;
+ if (chain->next == NULL) {
+ tt_assert(buf->last == chain);
+ }
+ tt_assert(chain->buffer_len >= chain->misalign + chain->off);
+ chain = chain->next;
+ }
+
+ if (buf->first)
+ tt_assert(*buf->last_with_datap);
+
+ if (*buf->last_with_datap) {
+ chain = *buf->last_with_datap;
+ if (chain->off == 0 || buf->total_len == 0) {
+ tt_assert(chain->off == 0)
+ tt_assert(chain == buf->first);
+ tt_assert(buf->total_len == 0);
+ }
+ chain = chain->next;
+ while (chain != NULL) {
+ tt_assert(chain->off == 0);
+ chain = chain->next;
+ }
+ } else {
+ tt_assert(buf->last_with_datap == &buf->first);
+ }
+ tt_assert(found_last_with_datap);
+
+ tt_assert(sum == buf->total_len);
+ return 1;
+ end:
+ return 0;
+}
+
+static void
+evbuffer_get_waste(struct evbuffer *buf, size_t *allocatedp, size_t *wastedp, size_t *usedp)
+{
+ struct evbuffer_chain *chain;
+ size_t a, w, u;
+ int n = 0;
+ u = a = w = 0;
+
+ chain = buf->first;
+ /* skip empty at start */
+ while (chain && chain->off==0) {
+ ++n;
+ a += chain->buffer_len;
+ chain = chain->next;
+ }
+ /* first nonempty chain: stuff at the end only is wasted. */
+ if (chain) {
+ ++n;
+ a += chain->buffer_len;
+ u += chain->off;
+ if (chain->next && chain->next->off)
+ w += (size_t)(chain->buffer_len - (chain->misalign + chain->off));
+ chain = chain->next;
+ }
+ /* subsequent nonempty chains */
+ while (chain && chain->off) {
+ ++n;
+ a += chain->buffer_len;
+ w += (size_t)chain->misalign;
+ u += chain->off;
+ if (chain->next && chain->next->off)
+ w += (size_t) (chain->buffer_len - (chain->misalign + chain->off));
+ chain = chain->next;
+ }
+ /* subsequent empty chains */
+ while (chain) {
+ ++n;
+ a += chain->buffer_len;
+ }
+ *allocatedp = a;
+ *wastedp = w;
+ *usedp = u;
+}
+
+#define evbuffer_validate(buf) \
+ TT_STMT_BEGIN if (!_evbuffer_validate(buf)) TT_DIE(("Buffer format invalid")); TT_STMT_END
+
+static void
+test_evbuffer(void *ptr)
+{
+ static char buffer[512], *tmp;
+ struct evbuffer *evb = evbuffer_new();
+ struct evbuffer *evb_two = evbuffer_new();
+ size_t sz_tmp;
+ int i;
+
+ evbuffer_validate(evb);
+ evbuffer_add_printf(evb, "%s/%d", "hello", 1);
+ evbuffer_validate(evb);
+
+ tt_assert(evbuffer_get_length(evb) == 7);
+ tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "hello/1", 1));
+
+ evbuffer_add_buffer(evb, evb_two);
+ evbuffer_validate(evb);
+
+ evbuffer_drain(evb, strlen("hello/"));
+ evbuffer_validate(evb);
+ tt_assert(evbuffer_get_length(evb) == 1);
+ tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1", 1));
+
+ evbuffer_add_printf(evb_two, "%s", "/hello");
+ evbuffer_validate(evb);
+ evbuffer_add_buffer(evb, evb_two);
+ evbuffer_validate(evb);
+
+ tt_assert(evbuffer_get_length(evb_two) == 0);
+ tt_assert(evbuffer_get_length(evb) == 7);
+ tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1/hello", 7) != 0);
+
+ memset(buffer, 0, sizeof(buffer));
+ evbuffer_add(evb, buffer, sizeof(buffer));
+ evbuffer_validate(evb);
+ tt_assert(evbuffer_get_length(evb) == 7 + 512);
+
+ tmp = (char *)evbuffer_pullup(evb, 7 + 512);
+ tt_assert(tmp);
+ tt_assert(!strncmp(tmp, "1/hello", 7));
+ tt_assert(!memcmp(tmp + 7, buffer, sizeof(buffer)));
+ evbuffer_validate(evb);
+
+ evbuffer_prepend(evb, "something", 9);
+ evbuffer_validate(evb);
+ evbuffer_prepend(evb, "else", 4);
+ evbuffer_validate(evb);
+
+ tmp = (char *)evbuffer_pullup(evb, 4 + 9 + 7);
+ tt_assert(!strncmp(tmp, "elsesomething1/hello", 4 + 9 + 7));
+ evbuffer_validate(evb);
+
+ evbuffer_drain(evb, -1);
+ evbuffer_validate(evb);
+ evbuffer_drain(evb_two, -1);
+ evbuffer_validate(evb);
+
+ for (i = 0; i < 3; ++i) {
+ evbuffer_add(evb_two, buffer, sizeof(buffer));
+ evbuffer_validate(evb_two);
+ evbuffer_add_buffer(evb, evb_two);
+ evbuffer_validate(evb);
+ evbuffer_validate(evb_two);
+ }
+
+ tt_assert(evbuffer_get_length(evb_two) == 0);
+ tt_assert(evbuffer_get_length(evb) == i * sizeof(buffer));
+
+ /* test remove buffer */
+ sz_tmp = (size_t)(sizeof(buffer)*2.5);
+ evbuffer_remove_buffer(evb, evb_two, sz_tmp);
+ tt_assert(evbuffer_get_length(evb_two) == sz_tmp);
+ tt_assert(evbuffer_get_length(evb) == sizeof(buffer) / 2);
+ evbuffer_validate(evb);
+
+ if (memcmp(evbuffer_pullup(
+ evb, -1), buffer, sizeof(buffer) / 2) != 0 ||
+ memcmp(evbuffer_pullup(
+ evb_two, -1), buffer, sizeof(buffer) != 0))
+ tt_abort_msg("Pullup did not preserve content");
+
+ evbuffer_validate(evb);
+
+
+ /* testing one-vector reserve and commit */
+ {
+ struct evbuffer_iovec v[1];
+ char *buf;
+ int i, j, r;
+
+ for (i = 0; i < 3; ++i) {
+ r = evbuffer_reserve_space(evb, 10000, v, 1);
+ tt_int_op(r, ==, 1);
+ tt_assert(v[0].iov_len >= 10000);
+ tt_assert(v[0].iov_base != NULL);
+
+ evbuffer_validate(evb);
+ buf = v[0].iov_base;
+ for (j = 0; j < 10000; ++j) {
+ buf[j] = j;
+ }
+ evbuffer_validate(evb);
+
+ tt_int_op(evbuffer_commit_space(evb, v, 1), ==, 0);
+ evbuffer_validate(evb);
+
+ tt_assert(evbuffer_get_length(evb) >= 10000);
+
+ evbuffer_drain(evb, j * 5000);
+ evbuffer_validate(evb);
+ }
+ }
+
+ end:
+ evbuffer_free(evb);
+ evbuffer_free(evb_two);
+}
+
+static void
+no_cleanup(const void *data, size_t datalen, void *extra)
+{
+}
+
+static void
+test_evbuffer_remove_buffer_with_empty(void *ptr)
+{
+ struct evbuffer *src = evbuffer_new();
+ struct evbuffer *dst = evbuffer_new();
+ char buf[2];
+
+ evbuffer_validate(src);
+ evbuffer_validate(dst);
+
+ /* setup the buffers */
+ /* we need more data in src than we will move later */
+ evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL);
+ evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL);
+ /* we need one buffer in dst and one empty buffer at the end */
+ evbuffer_add(dst, buf, sizeof(buf));
+ evbuffer_add_reference(dst, buf, 0, no_cleanup, NULL);
+
+ evbuffer_validate(src);
+ evbuffer_validate(dst);
+
+ /* move three bytes over */
+ evbuffer_remove_buffer(src, dst, 3);
+
+ evbuffer_validate(src);
+ evbuffer_validate(dst);
+
+end:
+ evbuffer_free(src);
+ evbuffer_free(dst);
+}
+
+static void
+test_evbuffer_reserve2(void *ptr)
+{
+ /* Test the two-vector cases of reserve/commit. */
+ struct evbuffer *buf = evbuffer_new();
+ int n, i;
+ struct evbuffer_iovec v[2];
+ size_t remaining;
+ char *cp, *cp2;
+
+ /* First chunk will necessarily be one chunk. Use 512 bytes of it.*/
+ n = evbuffer_reserve_space(buf, 1024, v, 2);
+ tt_int_op(n, ==, 1);
+ tt_int_op(evbuffer_get_length(buf), ==, 0);
+ tt_assert(v[0].iov_base != NULL);
+ tt_int_op(v[0].iov_len, >=, 1024);
+ memset(v[0].iov_base, 'X', 512);
+ cp = v[0].iov_base;
+ remaining = v[0].iov_len - 512;
+ v[0].iov_len = 512;
+ evbuffer_validate(buf);
+ tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1));
+ tt_int_op(evbuffer_get_length(buf), ==, 512);
+ evbuffer_validate(buf);
+
+ /* Ask for another same-chunk request, in an existing chunk. Use 8
+ * bytes of it. */
+ n = evbuffer_reserve_space(buf, 32, v, 2);
+ tt_int_op(n, ==, 1);
+ tt_assert(cp + 512 == v[0].iov_base);
+ tt_int_op(remaining, ==, v[0].iov_len);
+ memset(v[0].iov_base, 'Y', 8);
+ v[0].iov_len = 8;
+ tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1));
+ tt_int_op(evbuffer_get_length(buf), ==, 520);
+ remaining -= 8;
+ evbuffer_validate(buf);
+
+ /* Now ask for a request that will be split. Use only one byte of it,
+ though. */
+ n = evbuffer_reserve_space(buf, remaining+64, v, 2);
+ tt_int_op(n, ==, 2);
+ tt_assert(cp + 520 == v[0].iov_base);
+ tt_int_op(remaining, ==, v[0].iov_len);
+ tt_assert(v[1].iov_base);
+ tt_assert(v[1].iov_len >= 64);
+ cp2 = v[1].iov_base;
+ memset(v[0].iov_base, 'Z', 1);
+ v[0].iov_len = 1;
+ tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1));
+ tt_int_op(evbuffer_get_length(buf), ==, 521);
+ remaining -= 1;
+ evbuffer_validate(buf);
+
+ /* Now ask for a request that will be split. Use some of the first
+ * part and some of the second. */
+ n = evbuffer_reserve_space(buf, remaining+64, v, 2);
+ evbuffer_validate(buf);
+ tt_int_op(n, ==, 2);
+ tt_assert(cp + 521 == v[0].iov_base);
+ tt_int_op(remaining, ==, v[0].iov_len);
+ tt_assert(v[1].iov_base == cp2);
+ tt_assert(v[1].iov_len >= 64);
+ memset(v[0].iov_base, 'W', 400);
+ v[0].iov_len = 400;
+ memset(v[1].iov_base, 'x', 60);
+ v[1].iov_len = 60;
+ tt_int_op(0, ==, evbuffer_commit_space(buf, v, 2));
+ tt_int_op(evbuffer_get_length(buf), ==, 981);
+ evbuffer_validate(buf);
+
+ /* Now peek to make sure stuff got made how we like. */
+ memset(v,0,sizeof(v));
+ n = evbuffer_peek(buf, -1, NULL, v, 2);
+ tt_int_op(n, ==, 2);
+ tt_int_op(v[0].iov_len, ==, 921);
+ tt_int_op(v[1].iov_len, ==, 60);
+
+ cp = v[0].iov_base;
+ for (i=0; i<512; ++i)
+ tt_int_op(cp[i], ==, 'X');
+ for (i=512; i<520; ++i)
+ tt_int_op(cp[i], ==, 'Y');
+ for (i=520; i<521; ++i)
+ tt_int_op(cp[i], ==, 'Z');
+ for (i=521; i<921; ++i)
+ tt_int_op(cp[i], ==, 'W');
+
+ cp = v[1].iov_base;
+ for (i=0; i<60; ++i)
+ tt_int_op(cp[i], ==, 'x');
+
+end:
+ evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_reserve_many(void *ptr)
+{
+ /* This is a glass-box test to handle expanding a buffer with more
+ * chunks and reallocating chunks as needed */
+ struct evbuffer *buf = evbuffer_new();
+ struct evbuffer_iovec v[8];
+ int n;
+ size_t sz;
+ int add_data = ptr && !strcmp(ptr, "add");
+ int fill_first = ptr && !strcmp(ptr, "fill");
+ char *cp1, *cp2;
+
+ /* When reserving the the first chunk, we just allocate it */
+ n = evbuffer_reserve_space(buf, 128, v, 2);
+ evbuffer_validate(buf);
+ tt_int_op(n, ==, 1);
+ tt_assert(v[0].iov_len >= 128);
+ sz = v[0].iov_len;
+ cp1 = v[0].iov_base;
+ if (add_data) {
+ *(char*)v[0].iov_base = 'X';
+ v[0].iov_len = 1;
+ n = evbuffer_commit_space(buf, v, 1);
+ tt_int_op(n, ==, 0);
+ } else if (fill_first) {
+ memset(v[0].iov_base, 'X', v[0].iov_len);
+ n = evbuffer_commit_space(buf, v, 1);
+ tt_int_op(n, ==, 0);
+ n = evbuffer_reserve_space(buf, 128, v, 2);
+ tt_int_op(n, ==, 1);
+ sz = v[0].iov_len;
+ tt_assert(v[0].iov_base != cp1);
+ cp1 = v[0].iov_base;
+ }
+
+ /* Make another chunk get added. */
+ n = evbuffer_reserve_space(buf, sz+128, v, 2);
+ evbuffer_validate(buf);
+ tt_int_op(n, ==, 2);
+ sz = v[0].iov_len + v[1].iov_len;
+ tt_int_op(sz, >=, v[0].iov_len+128);
+ if (add_data) {
+ tt_assert(v[0].iov_base == cp1 + 1);
+ } else {
+ tt_assert(v[0].iov_base == cp1);
+ }
+ cp1 = v[0].iov_base;
+ cp2 = v[1].iov_base;
+
+ /* And a third chunk. */
+ n = evbuffer_reserve_space(buf, sz+128, v, 3);
+ evbuffer_validate(buf);
+ tt_int_op(n, ==, 3);
+ tt_assert(cp1 == v[0].iov_base);
+ tt_assert(cp2 == v[1].iov_base);
+ sz = v[0].iov_len + v[1].iov_len + v[2].iov_len;
+
+ /* Now force a reallocation by asking for more space in only 2
+ * buffers. */
+ n = evbuffer_reserve_space(buf, sz+128, v, 2);
+ evbuffer_validate(buf);
+ if (add_data) {
+ tt_int_op(n, ==, 2);
+ tt_assert(cp1 == v[0].iov_base);
+ } else {
+ tt_int_op(n, ==, 1);
+ }
+
+end:
+ evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_expand(void *ptr)
+{
+ char data[4096];
+ struct evbuffer *buf;
+ size_t a,w,u;
+ void *buffer;
+
+ memset(data, 'X', sizeof(data));
+
+ /* Make sure that expand() works on an empty buffer */
+ buf = evbuffer_new();
+ tt_int_op(evbuffer_expand(buf, 20000), ==, 0);
+ evbuffer_validate(buf);
+ a=w=u=0;
+ evbuffer_get_waste(buf, &a,&w,&u);
+ tt_assert(w == 0);
+ tt_assert(u == 0);
+ tt_assert(a >= 20000);
+ tt_assert(buf->first);
+ tt_assert(buf->first == buf->last);
+ tt_assert(buf->first->off == 0);
+ tt_assert(buf->first->buffer_len >= 20000);
+
+ /* Make sure that expand() works as a no-op when there's enough
+ * contiguous space already. */
+ buffer = buf->first->buffer;
+ evbuffer_add(buf, data, 1024);
+ tt_int_op(evbuffer_expand(buf, 1024), ==, 0);
+ tt_assert(buf->first->buffer == buffer);
+ evbuffer_validate(buf);
+ evbuffer_free(buf);
+
+ /* Make sure that expand() can work by moving misaligned data
+ * when it makes sense to do so. */
+ buf = evbuffer_new();
+ evbuffer_add(buf, data, 400);
+ {
+ int n = (int)(buf->first->buffer_len - buf->first->off - 1);
+ tt_assert(n < (int)sizeof(data));
+ evbuffer_add(buf, data, n);
+ }
+ tt_assert(buf->first == buf->last);
+ tt_assert(buf->first->off == buf->first->buffer_len - 1);
+ evbuffer_drain(buf, buf->first->off - 1);
+ tt_assert(1 == evbuffer_get_length(buf));
+ tt_assert(buf->first->misalign > 0);
+ tt_assert(buf->first->off == 1);
+ buffer = buf->first->buffer;
+ tt_assert(evbuffer_expand(buf, 40) == 0);
+ tt_assert(buf->first == buf->last);
+ tt_assert(buf->first->off == 1);
+ tt_assert(buf->first->buffer == buffer);
+ tt_assert(buf->first->misalign == 0);
+ evbuffer_validate(buf);
+ evbuffer_free(buf);
+
+ /* add, expand, pull-up: This used to crash libevent. */
+ buf = evbuffer_new();
+
+ evbuffer_add(buf, data, sizeof(data));
+ evbuffer_add(buf, data, sizeof(data));
+ evbuffer_add(buf, data, sizeof(data));
+
+ evbuffer_validate(buf);
+ evbuffer_expand(buf, 1024);
+ evbuffer_validate(buf);
+ evbuffer_pullup(buf, -1);
+ evbuffer_validate(buf);
+
+end:
+ evbuffer_free(buf);
+}
+
+
+static int reference_cb_called;
+static void
+reference_cb(const void *data, size_t len, void *extra)
+{
+ tt_str_op(data, ==, "this is what we add as read-only memory.");
+ tt_int_op(len, ==, strlen(data));
+ tt_want(extra == (void *)0xdeadaffe);
+ ++reference_cb_called;
+end:
+ ;
+}
+
+static void
+test_evbuffer_reference(void *ptr)
+{
+ struct evbuffer *src = evbuffer_new();
+ struct evbuffer *dst = evbuffer_new();
+ struct evbuffer_iovec v[1];
+ const char *data = "this is what we add as read-only memory.";
+ reference_cb_called = 0;
+
+ tt_assert(evbuffer_add_reference(src, data, strlen(data),
+ reference_cb, (void *)0xdeadaffe) != -1);
+
+ evbuffer_reserve_space(dst, strlen(data), v, 1);
+ tt_assert(evbuffer_remove(src, v[0].iov_base, 10) != -1);
+
+ evbuffer_validate(src);
+ evbuffer_validate(dst);
+
+ /* make sure that we don't write data at the beginning */
+ evbuffer_prepend(src, "aaaaa", 5);
+ evbuffer_validate(src);
+ evbuffer_drain(src, 5);
+
+ tt_assert(evbuffer_remove(src, ((char*)(v[0].iov_base)) + 10,
+ strlen(data) - 10) != -1);
+
+ v[0].iov_len = strlen(data);
+
+ evbuffer_commit_space(dst, v, 1);
+ evbuffer_validate(src);
+ evbuffer_validate(dst);
+
+ tt_int_op(reference_cb_called, ==, 1);
+
+ tt_assert(!memcmp(evbuffer_pullup(dst, strlen(data)),
+ data, strlen(data)));
+ evbuffer_validate(dst);
+
+ end:
+ evbuffer_free(dst);
+ evbuffer_free(src);
+}
+
+int _evbuffer_testing_use_sendfile(void);
+int _evbuffer_testing_use_mmap(void);
+int _evbuffer_testing_use_linear_file_access(void);
+
+static void
+test_evbuffer_add_file(void *ptr)
+{
+ const char *impl = ptr;
+ struct evbuffer *src = evbuffer_new();
+ const char *data = "this is what we add as file system data.";
+ size_t datalen;
+ const char *compare;
+ int fd = -1;
+ evutil_socket_t pair[2] = {-1, -1};
+ int r=0, n_written=0;
+
+ /* Add a test for a big file. XXXX */
+
+ tt_assert(impl);
+ if (!strcmp(impl, "sendfile")) {
+ if (!_evbuffer_testing_use_sendfile())
+ tt_skip();
+ TT_BLATHER(("Using sendfile-based implementaion"));
+ } else if (!strcmp(impl, "mmap")) {
+ if (!_evbuffer_testing_use_mmap())
+ tt_skip();
+ TT_BLATHER(("Using mmap-based implementaion"));
+ } else if (!strcmp(impl, "linear")) {
+ if (!_evbuffer_testing_use_linear_file_access())
+ tt_skip();
+ TT_BLATHER(("Using read-based implementaion"));
+ } else {
+ TT_DIE(("Didn't recognize the implementation"));
+ }
+
+ /* Say that it drains to a fd so that we can use sendfile. */
+ evbuffer_set_flags(src, EVBUFFER_FLAG_DRAINS_TO_FD);
+
+#if defined(_EVENT_HAVE_SENDFILE) && defined(__sun__) && defined(__svr4__)
+ /* We need to use a pair of AF_INET sockets, since Solaris
+ doesn't support sendfile() over AF_UNIX. */
+ if (evutil_ersatz_socketpair(AF_INET, SOCK_STREAM, 0, pair) == -1)
+ tt_abort_msg("ersatz_socketpair failed");
+#else
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
+ tt_abort_msg("socketpair failed");
+#endif
+
+ datalen = strlen(data);
+ fd = regress_make_tmpfile(data, datalen);
+
+ tt_assert(fd != -1);
+
+ tt_assert(evbuffer_add_file(src, fd, 0, datalen) != -1);
+
+ evbuffer_validate(src);
+
+ while (evbuffer_get_length(src) &&
+ (r = evbuffer_write(src, pair[0])) > 0) {
+ evbuffer_validate(src);
+ n_written += r;
+ }
+ tt_int_op(r, !=, -1);
+ tt_int_op(n_written, ==, datalen);
+
+ evbuffer_validate(src);
+ tt_int_op(evbuffer_read(src, pair[1], (int)strlen(data)), ==, datalen);
+ evbuffer_validate(src);
+ compare = (char *)evbuffer_pullup(src, datalen);
+ tt_assert(compare != NULL);
+ if (memcmp(compare, data, datalen))
+ tt_abort_msg("Data from add_file differs.");
+
+ evbuffer_validate(src);
+ end:
+ if (pair[0] >= 0)
+ evutil_closesocket(pair[0]);
+ if (pair[1] >= 0)
+ evutil_closesocket(pair[1]);
+ evbuffer_free(src);
+}
+
+#ifndef _EVENT_DISABLE_MM_REPLACEMENT
+static void *
+failing_malloc(size_t how_much)
+{
+ errno = ENOMEM;
+ return NULL;
+}
+#endif
+
+static void
+test_evbuffer_readln(void *ptr)
+{
+ struct evbuffer *evb = evbuffer_new();
+ struct evbuffer *evb_tmp = evbuffer_new();
+ const char *s;
+ char *cp = NULL;
+ size_t sz;
+
+#define tt_line_eq(content) \
+ TT_STMT_BEGIN \
+ if (!cp || sz != strlen(content) || strcmp(cp, content)) { \
+ TT_DIE(("Wanted %s; got %s [%d]", content, cp, (int)sz)); \
+ } \
+ TT_STMT_END
+
+ /* Test EOL_ANY. */
+ s = "complex silly newline\r\n\n\r\n\n\rmore\0\n";
+ evbuffer_add(evb, s, strlen(s)+2);
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
+ tt_line_eq("complex silly newline");
+ free(cp);
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
+ if (!cp || sz != 5 || memcmp(cp, "more\0\0", 6))
+ tt_abort_msg("Not as expected");
+ tt_uint_op(evbuffer_get_length(evb), ==, 0);
+ evbuffer_validate(evb);
+ s = "\nno newline";
+ evbuffer_add(evb, s, strlen(s));
+ free(cp);
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
+ tt_line_eq("");
+ free(cp);
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
+ tt_assert(!cp);
+ evbuffer_validate(evb);
+ evbuffer_drain(evb, evbuffer_get_length(evb));
+ tt_assert(evbuffer_get_length(evb) == 0);
+ evbuffer_validate(evb);
+
+ /* Test EOL_CRLF */
+ s = "Line with\rin the middle\nLine with good crlf\r\n\nfinal\n";
+ evbuffer_add(evb, s, strlen(s));
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
+ tt_line_eq("Line with\rin the middle");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
+ tt_line_eq("Line with good crlf");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
+ tt_line_eq("");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
+ tt_line_eq("final");
+ s = "x";
+ evbuffer_validate(evb);
+ evbuffer_add(evb, s, 1);
+ evbuffer_validate(evb);
+ free(cp);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
+ tt_assert(!cp);
+ evbuffer_validate(evb);
+
+ /* Test CRLF_STRICT */
+ s = " and a bad crlf\nand a good one\r\n\r\nMore\r";
+ evbuffer_add(evb, s, strlen(s));
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_line_eq("x and a bad crlf\nand a good one");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_line_eq("");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_assert(!cp);
+ evbuffer_validate(evb);
+ evbuffer_add(evb, "\n", 1);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_line_eq("More");
+ free(cp);
+ tt_assert(evbuffer_get_length(evb) == 0);
+ evbuffer_validate(evb);
+
+ s = "An internal CR\r is not an eol\r\nNor is a lack of one";
+ evbuffer_add(evb, s, strlen(s));
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_line_eq("An internal CR\r is not an eol");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_assert(!cp);
+ evbuffer_validate(evb);
+
+ evbuffer_add(evb, "\r\n", 2);
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_line_eq("Nor is a lack of one");
+ free(cp);
+ tt_assert(evbuffer_get_length(evb) == 0);
+ evbuffer_validate(evb);
+
+ /* Test LF */
+ s = "An\rand a nl\n\nText";
+ evbuffer_add(evb, s, strlen(s));
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+ tt_line_eq("An\rand a nl");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+ tt_line_eq("");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+ tt_assert(!cp);
+ free(cp);
+ evbuffer_add(evb, "\n", 1);
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+ tt_line_eq("Text");
+ free(cp);
+ evbuffer_validate(evb);
+
+ /* Test CRLF_STRICT - across boundaries*/
+ s = " and a bad crlf\nand a good one\r";
+ evbuffer_add(evb_tmp, s, strlen(s));
+ evbuffer_validate(evb);
+ evbuffer_add_buffer(evb, evb_tmp);
+ evbuffer_validate(evb);
+ s = "\n\r";
+ evbuffer_add(evb_tmp, s, strlen(s));
+ evbuffer_validate(evb);
+ evbuffer_add_buffer(evb, evb_tmp);
+ evbuffer_validate(evb);
+ s = "\nMore\r";
+ evbuffer_add(evb_tmp, s, strlen(s));
+ evbuffer_validate(evb);
+ evbuffer_add_buffer(evb, evb_tmp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_line_eq(" and a bad crlf\nand a good one");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_line_eq("");
+ free(cp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_assert(!cp);
+ free(cp);
+ evbuffer_validate(evb);
+ evbuffer_add(evb, "\n", 1);
+ evbuffer_validate(evb);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+ tt_line_eq("More");
+ free(cp); cp = NULL;
+ evbuffer_validate(evb);
+ tt_assert(evbuffer_get_length(evb) == 0);
+
+ /* Test memory problem*/
+ s = "one line\ntwo line\nblue line";
+ evbuffer_add(evb_tmp, s, strlen(s));
+ evbuffer_validate(evb);
+ evbuffer_add_buffer(evb, evb_tmp);
+ evbuffer_validate(evb);
+
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+ tt_line_eq("one line");
+ free(cp); cp = NULL;
+ evbuffer_validate(evb);
+
+ /* the next call to readline should fail */
+#ifndef _EVENT_DISABLE_MM_REPLACEMENT
+ event_set_mem_functions(failing_malloc, realloc, free);
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+ tt_assert(cp == NULL);
+ evbuffer_validate(evb);
+
+ /* now we should get the next line back */
+ event_set_mem_functions(malloc, realloc, free);
+#endif
+ cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+ tt_line_eq("two line");
+ free(cp); cp = NULL;
+ evbuffer_validate(evb);
+
+ end:
+ evbuffer_free(evb);
+ evbuffer_free(evb_tmp);
+ if (cp) free(cp);
+}
+
+static void
+test_evbuffer_search_eol(void *ptr)
+{
+ struct evbuffer *buf = evbuffer_new();
+ struct evbuffer_ptr ptr1, ptr2;
+ const char *s;
+ size_t eol_len;
+
+ s = "string! \r\n\r\nx\n";
+ evbuffer_add(buf, s, strlen(s));
+ eol_len = -1;
+ ptr1 = evbuffer_search_eol(buf, NULL, &eol_len, EVBUFFER_EOL_CRLF);
+ tt_int_op(ptr1.pos, ==, 8);
+ tt_int_op(eol_len, ==, 2);
+
+ eol_len = -1;
+ ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF);
+ tt_int_op(ptr2.pos, ==, 8);
+ tt_int_op(eol_len, ==, 2);
+
+ evbuffer_ptr_set(buf, &ptr1, 1, EVBUFFER_PTR_ADD);
+ eol_len = -1;
+ ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF);
+ tt_int_op(ptr2.pos, ==, 9);
+ tt_int_op(eol_len, ==, 1);
+
+ eol_len = -1;
+ ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF_STRICT);
+ tt_int_op(ptr2.pos, ==, 10);
+ tt_int_op(eol_len, ==, 2);
+
+ eol_len = -1;
+ ptr1 = evbuffer_search_eol(buf, NULL, &eol_len, EVBUFFER_EOL_LF);
+ tt_int_op(ptr1.pos, ==, 9);
+ tt_int_op(eol_len, ==, 1);
+
+ eol_len = -1;
+ ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF);
+ tt_int_op(ptr2.pos, ==, 9);
+ tt_int_op(eol_len, ==, 1);
+
+ evbuffer_ptr_set(buf, &ptr1, 1, EVBUFFER_PTR_ADD);
+ eol_len = -1;
+ ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF);
+ tt_int_op(ptr2.pos, ==, 11);
+ tt_int_op(eol_len, ==, 1);
+
+end:
+ evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_iterative(void *ptr)
+{
+ struct evbuffer *buf = evbuffer_new();
+ const char *abc = "abcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyz";
+ unsigned i, j, sum, n;
+
+ sum = 0;
+ n = 0;
+ for (i = 0; i < 1000; ++i) {
+ for (j = 1; j < strlen(abc); ++j) {
+ char format[32];
+ evutil_snprintf(format, sizeof(format), "%%%u.%us", j, j);
+ evbuffer_add_printf(buf, format, abc);
+
+ /* Only check for rep violations every so often.
+ Walking over the whole list of chains can get
+ pretty expensive as it gets long.
+ */
+ if ((n % 337) == 0)
+ evbuffer_validate(buf);
+
+ sum += j;
+ n++;
+ }
+ }
+ evbuffer_validate(buf);
+
+ tt_uint_op(sum, ==, evbuffer_get_length(buf));
+
+ {
+ size_t a,w,u;
+ a=w=u=0;
+ evbuffer_get_waste(buf, &a, &w, &u);
+ if (0)
+ printf("Allocated: %u.\nWasted: %u.\nUsed: %u.",
+ (unsigned)a, (unsigned)w, (unsigned)u);
+ tt_assert( ((double)w)/a < .125);
+ }
+ end:
+ evbuffer_free(buf);
+
+}
+
+static void
+test_evbuffer_find(void *ptr)
+{
+ u_char* p;
+ const char* test1 = "1234567890\r\n";
+ const char* test2 = "1234567890\r";
+#define EVBUFFER_INITIAL_LENGTH 256
+ char test3[EVBUFFER_INITIAL_LENGTH];
+ unsigned int i;
+ struct evbuffer * buf = evbuffer_new();
+
+ tt_assert(buf);
+
+ /* make sure evbuffer_find doesn't match past the end of the buffer */
+ evbuffer_add(buf, (u_char*)test1, strlen(test1));
+ evbuffer_validate(buf);
+ evbuffer_drain(buf, strlen(test1));
+ evbuffer_validate(buf);
+ evbuffer_add(buf, (u_char*)test2, strlen(test2));
+ evbuffer_validate(buf);
+ p = evbuffer_find(buf, (u_char*)"\r\n", 2);
+ tt_want(p == NULL);
+
+ /*
+ * drain the buffer and do another find; in r309 this would
+ * read past the allocated buffer causing a valgrind error.
+ */
+ evbuffer_drain(buf, strlen(test2));
+ evbuffer_validate(buf);
+ for (i = 0; i < EVBUFFER_INITIAL_LENGTH; ++i)
+ test3[i] = 'a';
+ test3[EVBUFFER_INITIAL_LENGTH - 1] = 'x';
+ evbuffer_add(buf, (u_char *)test3, EVBUFFER_INITIAL_LENGTH);
+ evbuffer_validate(buf);
+ p = evbuffer_find(buf, (u_char *)"xy", 2);
+ tt_want(p == NULL);
+
+ /* simple test for match at end of allocated buffer */
+ p = evbuffer_find(buf, (u_char *)"ax", 2);
+ tt_assert(p != NULL);
+ tt_want(strncmp((char*)p, "ax", 2) == 0);
+
+end:
+ if (buf)
+ evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_ptr_set(void *ptr)
+{
+ struct evbuffer *buf = evbuffer_new();
+ struct evbuffer_ptr pos;
+ struct evbuffer_iovec v[1];
+
+ tt_assert(buf);
+
+ /* create some chains */
+ evbuffer_reserve_space(buf, 5000, v, 1);
+ v[0].iov_len = 5000;
+ memset(v[0].iov_base, 1, v[0].iov_len);
+ evbuffer_commit_space(buf, v, 1);
+ evbuffer_validate(buf);
+
+ evbuffer_reserve_space(buf, 4000, v, 1);
+ v[0].iov_len = 4000;
+ memset(v[0].iov_base, 2, v[0].iov_len);
+ evbuffer_commit_space(buf, v, 1);
+
+ evbuffer_reserve_space(buf, 3000, v, 1);
+ v[0].iov_len = 3000;
+ memset(v[0].iov_base, 3, v[0].iov_len);
+ evbuffer_commit_space(buf, v, 1);
+ evbuffer_validate(buf);
+
+ tt_int_op(evbuffer_get_length(buf), ==, 12000);
+
+ tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_SET) == -1);
+ tt_assert(pos.pos == -1);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
+ tt_assert(pos.pos == 0);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_ADD) == -1);
+
+ tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
+ tt_assert(pos.pos == 0);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 10000, EVBUFFER_PTR_ADD) == 0);
+ tt_assert(pos.pos == 10000);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == 0);
+ tt_assert(pos.pos == 11000);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == -1);
+ tt_assert(pos.pos == -1);
+
+end:
+ if (buf)
+ evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_search(void *ptr)
+{
+ struct evbuffer *buf = evbuffer_new();
+ struct evbuffer *tmp = evbuffer_new();
+ struct evbuffer_ptr pos, end;
+
+ tt_assert(buf);
+ tt_assert(tmp);
+
+ /* set up our chains */
+ evbuffer_add_printf(tmp, "hello"); /* 5 chars */
+ evbuffer_add_buffer(buf, tmp);
+ evbuffer_add_printf(tmp, "foo"); /* 3 chars */
+ evbuffer_add_buffer(buf, tmp);
+ evbuffer_add_printf(tmp, "cat"); /* 3 chars */
+ evbuffer_add_buffer(buf, tmp);
+ evbuffer_add_printf(tmp, "attack");
+ evbuffer_add_buffer(buf, tmp);
+
+ pos = evbuffer_search(buf, "attack", 6, NULL);
+ tt_int_op(pos.pos, ==, 11);
+ pos = evbuffer_search(buf, "attacker", 8, NULL);
+ tt_int_op(pos.pos, ==, -1);
+
+ /* test continuing search */
+ pos = evbuffer_search(buf, "oc", 2, NULL);
+ tt_int_op(pos.pos, ==, 7);
+ pos = evbuffer_search(buf, "cat", 3, &pos);
+ tt_int_op(pos.pos, ==, 8);
+ pos = evbuffer_search(buf, "tacking", 7, &pos);
+ tt_int_op(pos.pos, ==, -1);
+
+ evbuffer_ptr_set(buf, &pos, 5, EVBUFFER_PTR_SET);
+ pos = evbuffer_search(buf, "foo", 3, &pos);
+ tt_int_op(pos.pos, ==, 5);
+
+ evbuffer_ptr_set(buf, &pos, 2, EVBUFFER_PTR_ADD);
+ pos = evbuffer_search(buf, "tat", 3, &pos);
+ tt_int_op(pos.pos, ==, 10);
+
+ /* test bounded search. */
+ /* Set "end" to the first t in "attack". */
+ evbuffer_ptr_set(buf, &end, 12, EVBUFFER_PTR_SET);
+ pos = evbuffer_search_range(buf, "foo", 3, NULL, &end);
+ tt_int_op(pos.pos, ==, 5);
+ pos = evbuffer_search_range(buf, "foocata", 7, NULL, &end);
+ tt_int_op(pos.pos, ==, 5);
+ pos = evbuffer_search_range(buf, "foocatat", 8, NULL, &end);
+ tt_int_op(pos.pos, ==, -1);
+ pos = evbuffer_search_range(buf, "ack", 3, NULL, &end);
+ tt_int_op(pos.pos, ==, -1);
+
+
+end:
+ if (buf)
+ evbuffer_free(buf);
+ if (tmp)
+ evbuffer_free(tmp);
+}
+
+static void
+log_change_callback(struct evbuffer *buffer,
+ const struct evbuffer_cb_info *cbinfo,
+ void *arg)
+{
+
+ size_t old_len = cbinfo->orig_size;
+ size_t new_len = old_len + cbinfo->n_added - cbinfo->n_deleted;
+ struct evbuffer *out = arg;
+ evbuffer_add_printf(out, "%lu->%lu; ", (unsigned long)old_len,
+ (unsigned long)new_len);
+}
+static void
+self_draining_callback(struct evbuffer *evbuffer, size_t old_len,
+ size_t new_len, void *arg)
+{
+ if (new_len > old_len)
+ evbuffer_drain(evbuffer, new_len);
+}
+
+static void
+test_evbuffer_callbacks(void *ptr)
+{
+ struct evbuffer *buf = evbuffer_new();
+ struct evbuffer *buf_out1 = evbuffer_new();
+ struct evbuffer *buf_out2 = evbuffer_new();
+ struct evbuffer_cb_entry *cb1, *cb2;
+
+ tt_assert(buf);
+ tt_assert(buf_out1);
+ tt_assert(buf_out2);
+
+ cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
+ cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
+
+ /* Let's run through adding and deleting some stuff from the buffer
+ * and turning the callbacks on and off and removing them. The callback
+ * adds a summary of length changes to buf_out1/buf_out2 when called. */
+ /* size: 0-> 36. */
+ evbuffer_add_printf(buf, "The %d magic words are spotty pudding", 2);
+ evbuffer_validate(buf);
+ evbuffer_cb_clear_flags(buf, cb2, EVBUFFER_CB_ENABLED);
+ evbuffer_drain(buf, 10); /*36->26*/
+ evbuffer_validate(buf);
+ evbuffer_prepend(buf, "Hello", 5);/*26->31*/
+ evbuffer_cb_set_flags(buf, cb2, EVBUFFER_CB_ENABLED);
+ evbuffer_add_reference(buf, "Goodbye", 7, NULL, NULL); /*31->38*/
+ evbuffer_remove_cb_entry(buf, cb1);
+ evbuffer_validate(buf);
+ evbuffer_drain(buf, evbuffer_get_length(buf)); /*38->0*/;
+ tt_assert(-1 == evbuffer_remove_cb(buf, log_change_callback, NULL));
+ evbuffer_add(buf, "X", 1); /* 0->1 */
+ tt_assert(!evbuffer_remove_cb(buf, log_change_callback, buf_out2));
+ evbuffer_validate(buf);
+
+ tt_str_op(evbuffer_pullup(buf_out1, -1), ==,
+ "0->36; 36->26; 26->31; 31->38; ");
+ tt_str_op(evbuffer_pullup(buf_out2, -1), ==,
+ "0->36; 31->38; 38->0; 0->1; ");
+ evbuffer_drain(buf_out1, evbuffer_get_length(buf_out1));
+ evbuffer_drain(buf_out2, evbuffer_get_length(buf_out2));
+ /* Let's test the obsolete buffer_setcb function too. */
+ cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
+ tt_assert(cb1 != NULL);
+ cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
+ tt_assert(cb2 != NULL);
+ evbuffer_setcb(buf, self_draining_callback, NULL);
+ evbuffer_add_printf(buf, "This should get drained right away.");
+ tt_uint_op(evbuffer_get_length(buf), ==, 0);
+ tt_uint_op(evbuffer_get_length(buf_out1), ==, 0);
+ tt_uint_op(evbuffer_get_length(buf_out2), ==, 0);
+ evbuffer_setcb(buf, NULL, NULL);
+ evbuffer_add_printf(buf, "This will not.");
+ tt_str_op(evbuffer_pullup(buf, -1), ==, "This will not.");
+ evbuffer_validate(buf);
+ evbuffer_drain(buf, evbuffer_get_length(buf));
+ evbuffer_validate(buf);
+#if 0
+ /* Now let's try a suspended callback. */
+ cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
+ cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
+ evbuffer_cb_suspend(buf,cb2);
+ evbuffer_prepend(buf,"Hello world",11); /*0->11*/
+ evbuffer_validate(buf);
+ evbuffer_cb_suspend(buf,cb1);
+ evbuffer_add(buf,"more",4); /* 11->15 */
+ evbuffer_cb_unsuspend(buf,cb2);
+ evbuffer_drain(buf, 4); /* 15->11 */
+ evbuffer_cb_unsuspend(buf,cb1);
+ evbuffer_drain(buf, evbuffer_get_length(buf)); /* 11->0 */
+
+ tt_str_op(evbuffer_pullup(buf_out1, -1), ==,
+ "0->11; 11->11; 11->0; ");
+ tt_str_op(evbuffer_pullup(buf_out2, -1), ==,
+ "0->15; 15->11; 11->0; ");
+#endif
+
+ end:
+ if (buf)
+ evbuffer_free(buf);
+ if (buf_out1)
+ evbuffer_free(buf_out1);
+ if (buf_out2)
+ evbuffer_free(buf_out2);
+}
+
+static int ref_done_cb_called_count = 0;
+static void *ref_done_cb_called_with = NULL;
+static const void *ref_done_cb_called_with_data = NULL;
+static size_t ref_done_cb_called_with_len = 0;
+static void ref_done_cb(const void *data, size_t len, void *info)
+{
+ ++ref_done_cb_called_count;
+ ref_done_cb_called_with = info;
+ ref_done_cb_called_with_data = data;
+ ref_done_cb_called_with_len = len;
+}
+
+static void
+test_evbuffer_add_reference(void *ptr)
+{
+ const char chunk1[] = "If you have found the answer to such a problem";
+ const char chunk2[] = "you ought to write it up for publication";
+ /* -- Knuth's "Notes on the Exercises" from TAOCP */
+ char tmp[16];
+ size_t len1 = strlen(chunk1), len2=strlen(chunk2);
+
+ struct evbuffer *buf1 = NULL, *buf2 = NULL;
+
+ buf1 = evbuffer_new();
+ tt_assert(buf1);
+
+ evbuffer_add_reference(buf1, chunk1, len1, ref_done_cb, (void*)111);
+ evbuffer_add(buf1, ", ", 2);
+ evbuffer_add_reference(buf1, chunk2, len2, ref_done_cb, (void*)222);
+ tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2);
+
+ /* Make sure we can drain a little from a reference. */
+ tt_int_op(evbuffer_remove(buf1, tmp, 6), ==, 6);
+ tt_int_op(memcmp(tmp, "If you", 6), ==, 0);
+ tt_int_op(evbuffer_remove(buf1, tmp, 5), ==, 5);
+ tt_int_op(memcmp(tmp, " have", 5), ==, 0);
+
+ /* Make sure that prepending does not meddle with immutable data */
+ tt_int_op(evbuffer_prepend(buf1, "I have ", 7), ==, 0);
+ tt_int_op(memcmp(chunk1, "If you", 6), ==, 0);
+ evbuffer_validate(buf1);
+
+ /* Make sure that when the chunk is over, the callback is invoked. */
+ evbuffer_drain(buf1, 7); /* Remove prepended stuff. */
+ evbuffer_drain(buf1, len1-11-1); /* remove all but one byte of chunk1 */
+ tt_int_op(ref_done_cb_called_count, ==, 0);
+ evbuffer_remove(buf1, tmp, 1);
+ tt_int_op(tmp[0], ==, 'm');
+ tt_assert(ref_done_cb_called_with == (void*)111);
+ tt_assert(ref_done_cb_called_with_data == chunk1);
+ tt_assert(ref_done_cb_called_with_len == len1);
+ tt_int_op(ref_done_cb_called_count, ==, 1);
+ evbuffer_validate(buf1);
+
+ /* Drain some of the remaining chunk, then add it to another buffer */
+ evbuffer_drain(buf1, 6); /* Remove the ", you ". */
+ buf2 = evbuffer_new();
+ tt_assert(buf2);
+ tt_int_op(ref_done_cb_called_count, ==, 1);
+ evbuffer_add(buf2, "I ", 2);
+
+ evbuffer_add_buffer(buf2, buf1);
+ tt_int_op(ref_done_cb_called_count, ==, 1);
+ evbuffer_remove(buf2, tmp, 16);
+ tt_int_op(memcmp("I ought to write", tmp, 16), ==, 0);
+ evbuffer_drain(buf2, evbuffer_get_length(buf2));
+ tt_int_op(ref_done_cb_called_count, ==, 2);
+ tt_assert(ref_done_cb_called_with == (void*)222);
+ evbuffer_validate(buf2);
+
+ /* Now add more stuff to buf1 and make sure that it gets removed on
+ * free. */
+ evbuffer_add(buf1, "You shake and shake the ", 24);
+ evbuffer_add_reference(buf1, "ketchup bottle", 14, ref_done_cb,
+ (void*)3333);
+ evbuffer_add(buf1, ". Nothing comes and then a lot'll.", 42);
+ evbuffer_free(buf1);
+ buf1 = NULL;
+ tt_int_op(ref_done_cb_called_count, ==, 3);
+ tt_assert(ref_done_cb_called_with == (void*)3333);
+
+end:
+ if (buf1)
+ evbuffer_free(buf1);
+ if (buf2)
+ evbuffer_free(buf2);
+}
+
+/* Some cases that we didn't get in test_evbuffer() above, for more coverage. */
+static void
+test_evbuffer_prepend(void *ptr)
+{
+ struct evbuffer *buf1 = NULL, *buf2 = NULL;
+ char tmp[128];
+ int n;
+
+ buf1 = evbuffer_new();
+ tt_assert(buf1);
+
+ /* Case 0: The evbuffer is entirely empty. */
+ evbuffer_prepend(buf1, "This string has 29 characters", 29);
+ evbuffer_validate(buf1);
+
+ /* Case 1: Prepend goes entirely in new chunk. */
+ evbuffer_prepend(buf1, "Short.", 6);
+ evbuffer_validate(buf1);
+
+ /* Case 2: prepend goes entirely in first chunk. */
+ evbuffer_drain(buf1, 6+11);
+ evbuffer_prepend(buf1, "it", 2);
+ evbuffer_validate(buf1);
+ tt_assert(!memcmp(buf1->first->buffer+buf1->first->misalign,
+ "it has", 6));
+
+ /* Case 3: prepend is split over multiple chunks. */
+ evbuffer_prepend(buf1, "It is no longer true to say ", 28);
+ evbuffer_validate(buf1);
+ n = evbuffer_remove(buf1, tmp, sizeof(tmp)-1);
+ tmp[n]='\0';
+ tt_str_op(tmp,==,"It is no longer true to say it has 29 characters");
+
+ buf2 = evbuffer_new();
+ tt_assert(buf2);
+
+ /* Case 4: prepend a buffer to an empty buffer. */
+ n = 999;
+ evbuffer_add_printf(buf1, "Here is string %d. ", n++);
+ evbuffer_prepend_buffer(buf2, buf1);
+ evbuffer_validate(buf2);
+
+ /* Case 5: prepend a buffer to a nonempty buffer. */
+ evbuffer_add_printf(buf1, "Here is string %d. ", n++);
+ evbuffer_prepend_buffer(buf2, buf1);
+ evbuffer_validate(buf2);
+ evbuffer_validate(buf1);
+ n = evbuffer_remove(buf2, tmp, sizeof(tmp)-1);
+ tmp[n]='\0';
+ tt_str_op(tmp,==,"Here is string 1000. Here is string 999. ");
+
+end:
+ if (buf1)
+ evbuffer_free(buf1);
+ if (buf2)
+ evbuffer_free(buf2);
+
+}
+
+static void
+test_evbuffer_peek(void *info)
+{
+ struct evbuffer *buf = NULL, *tmp_buf = NULL;
+ int i;
+ struct evbuffer_iovec v[20];
+ struct evbuffer_ptr ptr;
+
+#define tt_iov_eq(v, s) \
+ tt_int_op((v)->iov_len, ==, strlen(s)); \
+ tt_assert(!memcmp((v)->iov_base, (s), strlen(s)))
+
+ /* Let's make a very fragmented buffer. */
+ buf = evbuffer_new();
+ tmp_buf = evbuffer_new();
+ for (i = 0; i < 16; ++i) {
+ evbuffer_add_printf(tmp_buf, "Contents of chunk [%d]\n", i);
+ evbuffer_add_buffer(buf, tmp_buf);
+ }
+
+ /* How many chunks do we need for everything? */
+ i = evbuffer_peek(buf, -1, NULL, NULL, 0);
+ tt_int_op(i, ==, 16);
+
+ /* Simple peek: get everything. */
+ i = evbuffer_peek(buf, -1, NULL, v, 20);
+ tt_int_op(i, ==, 16); /* we used only 16 chunks. */
+ tt_iov_eq(&v[0], "Contents of chunk [0]\n");
+ tt_iov_eq(&v[3], "Contents of chunk [3]\n");
+ tt_iov_eq(&v[12], "Contents of chunk [12]\n");
+ tt_iov_eq(&v[15], "Contents of chunk [15]\n");
+
+ /* Just get one chunk worth. */
+ memset(v, 0, sizeof(v));
+ i = evbuffer_peek(buf, -1, NULL, v, 1);
+ tt_int_op(i, ==, 1);
+ tt_iov_eq(&v[0], "Contents of chunk [0]\n");
+ tt_assert(v[1].iov_base == NULL);
+
+ /* Suppose we want at least the first 40 bytes. */
+ memset(v, 0, sizeof(v));
+ i = evbuffer_peek(buf, 40, NULL, v, 16);
+ tt_int_op(i, ==, 2);
+ tt_iov_eq(&v[0], "Contents of chunk [0]\n");
+ tt_iov_eq(&v[1], "Contents of chunk [1]\n");
+ tt_assert(v[2].iov_base == NULL);
+
+ /* How many chunks do we need for 100 bytes? */
+ memset(v, 0, sizeof(v));
+ i = evbuffer_peek(buf, 100, NULL, NULL, 0);
+ tt_int_op(i, ==, 5);
+ tt_assert(v[0].iov_base == NULL);
+
+ /* Now we ask for more bytes than we provide chunks for */
+ memset(v, 0, sizeof(v));
+ i = evbuffer_peek(buf, 60, NULL, v, 1);
+ tt_int_op(i, ==, 3);
+ tt_iov_eq(&v[0], "Contents of chunk [0]\n");
+ tt_assert(v[1].iov_base == NULL);
+
+ /* Now we ask for more bytes than the buffer has. */
+ memset(v, 0, sizeof(v));
+ i = evbuffer_peek(buf, 65536, NULL, v, 20);
+ tt_int_op(i, ==, 16); /* we used only 16 chunks. */
+ tt_iov_eq(&v[0], "Contents of chunk [0]\n");
+ tt_iov_eq(&v[3], "Contents of chunk [3]\n");
+ tt_iov_eq(&v[12], "Contents of chunk [12]\n");
+ tt_iov_eq(&v[15], "Contents of chunk [15]\n");
+ tt_assert(v[16].iov_base == NULL);
+
+ /* What happens if we try an empty buffer? */
+ memset(v, 0, sizeof(v));
+ i = evbuffer_peek(tmp_buf, -1, NULL, v, 20);
+ tt_int_op(i, ==, 0);
+ tt_assert(v[0].iov_base == NULL);
+ memset(v, 0, sizeof(v));
+ i = evbuffer_peek(tmp_buf, 50, NULL, v, 20);
+ tt_int_op(i, ==, 0);
+ tt_assert(v[0].iov_base == NULL);
+
+ /* Okay, now time to have fun with pointers. */
+ memset(v, 0, sizeof(v));
+ evbuffer_ptr_set(buf, &ptr, 30, EVBUFFER_PTR_SET);
+ i = evbuffer_peek(buf, 50, &ptr, v, 20);
+ tt_int_op(i, ==, 3);
+ tt_iov_eq(&v[0], " of chunk [1]\n");
+ tt_iov_eq(&v[1], "Contents of chunk [2]\n");
+ tt_iov_eq(&v[2], "Contents of chunk [3]\n"); /*more than we asked for*/
+
+ /* advance to the start of another chain. */
+ memset(v, 0, sizeof(v));
+ evbuffer_ptr_set(buf, &ptr, 14, EVBUFFER_PTR_ADD);
+ i = evbuffer_peek(buf, 44, &ptr, v, 20);
+ tt_int_op(i, ==, 2);
+ tt_iov_eq(&v[0], "Contents of chunk [2]\n");
+ tt_iov_eq(&v[1], "Contents of chunk [3]\n"); /*more than we asked for*/
+
+end:
+ if (buf)
+ evbuffer_free(buf);
+ if (tmp_buf)
+ evbuffer_free(tmp_buf);
+}
+
+/* Check whether evbuffer freezing works right. This is called twice,
+ once with the argument "start" and once with the argument "end".
+ When we test "start", we freeze the start of an evbuffer and make sure
+ that modifying the start of the buffer doesn't work. When we test
+ "end", we freeze the end of an evbuffer and make sure that modifying
+ the end of the buffer doesn't work.
+ */
+static void
+test_evbuffer_freeze(void *ptr)
+{
+ struct evbuffer *buf = NULL, *tmp_buf=NULL;
+ const char string[] = /* Year's End, Richard Wilbur */
+ "I've known the wind by water banks to shake\n"
+ "The late leaves down, which frozen where they fell\n"
+ "And held in ice as dancers in a spell\n"
+ "Fluttered all winter long into a lake...";
+ const int start = !strcmp(ptr, "start");
+ char *cp;
+ char charbuf[128];
+ int r;
+ size_t orig_length;
+ struct evbuffer_iovec v[1];
+
+ if (!start)
+ tt_str_op(ptr, ==, "end");
+
+ buf = evbuffer_new();
+ tmp_buf = evbuffer_new();
+ tt_assert(tmp_buf);
+
+ evbuffer_add(buf, string, strlen(string));
+ evbuffer_freeze(buf, start); /* Freeze the start or the end.*/
+
+#define FREEZE_EQ(a, startcase, endcase) \
+ do { \
+ if (start) { \
+ tt_int_op((a), ==, (startcase)); \
+ } else { \
+ tt_int_op((a), ==, (endcase)); \
+ } \
+ } while (0)
+
+
+ orig_length = evbuffer_get_length(buf);
+
+ /* These functions all manipulate the end of buf. */
+ r = evbuffer_add(buf, "abc", 0);
+ FREEZE_EQ(r, 0, -1);
+ r = evbuffer_reserve_space(buf, 10, v, 1);
+ FREEZE_EQ(r, 1, -1);
+ if (r == 0) {
+ memset(v[0].iov_base, 'X', 10);
+ v[0].iov_len = 10;
+ }
+ r = evbuffer_commit_space(buf, v, 1);
+ FREEZE_EQ(r, 0, -1);
+ r = evbuffer_add_reference(buf, string, 5, NULL, NULL);
+ FREEZE_EQ(r, 0, -1);
+ r = evbuffer_add_printf(buf, "Hello %s", "world");
+ FREEZE_EQ(r, 11, -1);
+ /* TODO: test add_buffer, add_file, read */
+
+ if (!start)
+ tt_int_op(orig_length, ==, evbuffer_get_length(buf));
+
+ orig_length = evbuffer_get_length(buf);
+
+ /* These functions all manipulate the start of buf. */
+ r = evbuffer_remove(buf, charbuf, 1);
+ FREEZE_EQ(r, -1, 1);
+ r = evbuffer_drain(buf, 3);
+ FREEZE_EQ(r, -1, 0);
+ r = evbuffer_prepend(buf, "dummy", 5);
+ FREEZE_EQ(r, -1, 0);
+ cp = evbuffer_readln(buf, NULL, EVBUFFER_EOL_LF);
+ FREEZE_EQ(cp==NULL, 1, 0);
+ if (cp)
+ free(cp);
+ /* TODO: Test remove_buffer, add_buffer, write, prepend_buffer */
+
+ if (start)
+ tt_int_op(orig_length, ==, evbuffer_get_length(buf));
+
+end:
+ if (buf)
+ evbuffer_free(buf);
+
+ if (tmp_buf)
+ evbuffer_free(tmp_buf);
+}
+
+static void *
+setup_passthrough(const struct testcase_t *testcase)
+{
+ return testcase->setup_data;
+}
+static int
+cleanup_passthrough(const struct testcase_t *testcase, void *ptr)
+{
+ (void) ptr;
+ return 1;
+}
+
+static const struct testcase_setup_t nil_setup = {
+ setup_passthrough,
+ cleanup_passthrough
+};
+
+struct testcase_t evbuffer_testcases[] = {
+ { "evbuffer", test_evbuffer, 0, NULL, NULL },
+ { "remove_buffer_with_empty", test_evbuffer_remove_buffer_with_empty, 0, NULL, NULL },
+ { "reserve2", test_evbuffer_reserve2, 0, NULL, NULL },
+ { "reserve_many", test_evbuffer_reserve_many, 0, NULL, NULL },
+ { "reserve_many2", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"add" },
+ { "reserve_many3", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"fill" },
+ { "expand", test_evbuffer_expand, 0, NULL, NULL },
+ { "reference", test_evbuffer_reference, 0, NULL, NULL },
+ { "iterative", test_evbuffer_iterative, 0, NULL, NULL },
+ { "readln", test_evbuffer_readln, TT_NO_LOGS, &basic_setup, NULL },
+ { "search_eol", test_evbuffer_search_eol, 0, NULL, NULL },
+ { "find", test_evbuffer_find, 0, NULL, NULL },
+ { "ptr_set", test_evbuffer_ptr_set, 0, NULL, NULL },
+ { "search", test_evbuffer_search, 0, NULL, NULL },
+ { "callbacks", test_evbuffer_callbacks, 0, NULL, NULL },
+ { "add_reference", test_evbuffer_add_reference, 0, NULL, NULL },
+ { "prepend", test_evbuffer_prepend, TT_FORK, NULL, NULL },
+ { "peek", test_evbuffer_peek, 0, NULL, NULL },
+ { "freeze_start", test_evbuffer_freeze, 0, &nil_setup, (void*)"start" },
+ { "freeze_end", test_evbuffer_freeze, 0, &nil_setup, (void*)"end" },
+ /* TODO: need a temp file implementation for Windows */
+ { "add_file_sendfile", test_evbuffer_add_file, TT_FORK, &nil_setup,
+ (void*)"sendfile" },
+ { "add_file_mmap", test_evbuffer_add_file, TT_FORK, &nil_setup,
+ (void*)"mmap" },
+ { "add_file_linear", test_evbuffer_add_file, TT_FORK, &nil_setup,
+ (void*)"linear" },
+
+ END_OF_TESTCASES
+};
diff --git a/libevent-2.0.20-stable/test/regress_bufferevent.c b/libevent-2.0.20-stable/test/regress_bufferevent.c
new file mode 100644
index 0000000..cdfed0c
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress_bufferevent.c
@@ -0,0 +1,841 @@
+/*
+ * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* The old tests here need assertions to work. */
+#undef NDEBUG
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#endif
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#ifdef _EVENT_HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include "event2/event-config.h"
+#include "event2/event.h"
+#include "event2/event_struct.h"
+#include "event2/event_compat.h"
+#include "event2/tag.h"
+#include "event2/buffer.h"
+#include "event2/bufferevent.h"
+#include "event2/bufferevent_compat.h"
+#include "event2/bufferevent_struct.h"
+#include "event2/listener.h"
+#include "event2/util.h"
+
+#include "bufferevent-internal.h"
+#ifdef WIN32
+#include "iocp-internal.h"
+#endif
+
+#include "regress.h"
+#include "regress_testutils.h"
+
+/*
+ * simple bufferevent test
+ */
+
+static void
+readcb(struct bufferevent *bev, void *arg)
+{
+ if (evbuffer_get_length(bev->input) == 8333) {
+ struct evbuffer *evbuf = evbuffer_new();
+ assert(evbuf != NULL);
+
+ /* gratuitous test of bufferevent_read_buffer */
+ bufferevent_read_buffer(bev, evbuf);
+
+ bufferevent_disable(bev, EV_READ);
+
+ if (evbuffer_get_length(evbuf) == 8333) {
+ test_ok++;
+ }
+
+ evbuffer_free(evbuf);
+ }
+}
+
+static void
+writecb(struct bufferevent *bev, void *arg)
+{
+ if (evbuffer_get_length(bev->output) == 0) {
+ test_ok++;
+ }
+}
+
+static void
+errorcb(struct bufferevent *bev, short what, void *arg)
+{
+ test_ok = -2;
+}
+
+static void
+test_bufferevent_impl(int use_pair)
+{
+ struct bufferevent *bev1 = NULL, *bev2 = NULL;
+ char buffer[8333];
+ int i;
+
+ if (use_pair) {
+ struct bufferevent *pair[2];
+ tt_assert(0 == bufferevent_pair_new(NULL, 0, pair));
+ bev1 = pair[0];
+ bev2 = pair[1];
+ bufferevent_setcb(bev1, readcb, writecb, errorcb, NULL);
+ bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL);
+ tt_int_op(bufferevent_getfd(bev1), ==, -1);
+ tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL);
+ tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, bev2);
+ tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, bev1);
+ } else {
+ bev1 = bufferevent_new(pair[0], readcb, writecb, errorcb, NULL);
+ bev2 = bufferevent_new(pair[1], readcb, writecb, errorcb, NULL);
+ tt_int_op(bufferevent_getfd(bev1), ==, pair[0]);
+ tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL);
+ tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL);
+ tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, NULL);
+ }
+
+ bufferevent_disable(bev1, EV_READ);
+ bufferevent_enable(bev2, EV_READ);
+
+ tt_int_op(bufferevent_get_enabled(bev1), ==, EV_WRITE);
+ tt_int_op(bufferevent_get_enabled(bev2), ==, EV_WRITE|EV_READ);
+
+ for (i = 0; i < (int)sizeof(buffer); i++)
+ buffer[i] = i;
+
+ bufferevent_write(bev1, buffer, sizeof(buffer));
+
+ event_dispatch();
+
+ bufferevent_free(bev1);
+ tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, NULL);
+ bufferevent_free(bev2);
+
+ if (test_ok != 2)
+ test_ok = 0;
+end:
+ ;
+}
+
+static void
+test_bufferevent(void)
+{
+ test_bufferevent_impl(0);
+}
+
+static void
+test_bufferevent_pair(void)
+{
+ test_bufferevent_impl(1);
+}
+
+/*
+ * test watermarks and bufferevent
+ */
+
+static void
+wm_readcb(struct bufferevent *bev, void *arg)
+{
+ struct evbuffer *evbuf = evbuffer_new();
+ int len = (int)evbuffer_get_length(bev->input);
+ static int nread;
+
+ assert(len >= 10 && len <= 20);
+
+ assert(evbuf != NULL);
+
+ /* gratuitous test of bufferevent_read_buffer */
+ bufferevent_read_buffer(bev, evbuf);
+
+ nread += len;
+ if (nread == 65000) {
+ bufferevent_disable(bev, EV_READ);
+ test_ok++;
+ }
+
+ evbuffer_free(evbuf);
+}
+
+static void
+wm_writecb(struct bufferevent *bev, void *arg)
+{
+ assert(evbuffer_get_length(bev->output) <= 100);
+ if (evbuffer_get_length(bev->output) == 0) {
+ evbuffer_drain(bev->output, evbuffer_get_length(bev->output));
+ test_ok++;
+ }
+}
+
+static void
+wm_errorcb(struct bufferevent *bev, short what, void *arg)
+{
+ test_ok = -2;
+}
+
+static void
+test_bufferevent_watermarks_impl(int use_pair)
+{
+ struct bufferevent *bev1 = NULL, *bev2 = NULL;
+ char buffer[65000];
+ int i;
+ test_ok = 0;
+
+ if (use_pair) {
+ struct bufferevent *pair[2];
+ tt_assert(0 == bufferevent_pair_new(NULL, 0, pair));
+ bev1 = pair[0];
+ bev2 = pair[1];
+ bufferevent_setcb(bev1, NULL, wm_writecb, errorcb, NULL);
+ bufferevent_setcb(bev2, wm_readcb, NULL, errorcb, NULL);
+ } else {
+ bev1 = bufferevent_new(pair[0], NULL, wm_writecb, wm_errorcb, NULL);
+ bev2 = bufferevent_new(pair[1], wm_readcb, NULL, wm_errorcb, NULL);
+ }
+ tt_assert(bev1);
+ tt_assert(bev2);
+ bufferevent_disable(bev1, EV_READ);
+ bufferevent_enable(bev2, EV_READ);
+
+ for (i = 0; i < (int)sizeof(buffer); i++)
+ buffer[i] = (char)i;
+
+ /* limit the reading on the receiving bufferevent */
+ bufferevent_setwatermark(bev2, EV_READ, 10, 20);
+
+ /* Tell the sending bufferevent not to notify us till it's down to
+ 100 bytes. */
+ bufferevent_setwatermark(bev1, EV_WRITE, 100, 2000);
+
+ bufferevent_write(bev1, buffer, sizeof(buffer));
+
+ event_dispatch();
+
+ tt_int_op(test_ok, ==, 2);
+
+ /* The write callback drained all the data from outbuf, so we
+ * should have removed the write event... */
+ tt_assert(!event_pending(&bev2->ev_write, EV_WRITE, NULL));
+
+end:
+ if (bev1)
+ bufferevent_free(bev1);
+ if (bev2)
+ bufferevent_free(bev2);
+}
+
+static void
+test_bufferevent_watermarks(void)
+{
+ test_bufferevent_watermarks_impl(0);
+}
+
+static void
+test_bufferevent_pair_watermarks(void)
+{
+ test_bufferevent_watermarks_impl(1);
+}
+
+/*
+ * Test bufferevent filters
+ */
+
+/* strip an 'x' from each byte */
+
+static enum bufferevent_filter_result
+bufferevent_input_filter(struct evbuffer *src, struct evbuffer *dst,
+ ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
+{
+ const unsigned char *buffer;
+ unsigned i;
+
+ buffer = evbuffer_pullup(src, evbuffer_get_length(src));
+ for (i = 0; i < evbuffer_get_length(src); i += 2) {
+ assert(buffer[i] == 'x');
+ evbuffer_add(dst, buffer + i + 1, 1);
+
+ if (i + 2 > evbuffer_get_length(src))
+ break;
+ }
+
+ evbuffer_drain(src, i);
+ return (BEV_OK);
+}
+
+/* add an 'x' before each byte */
+
+static enum bufferevent_filter_result
+bufferevent_output_filter(struct evbuffer *src, struct evbuffer *dst,
+ ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
+{
+ const unsigned char *buffer;
+ unsigned i;
+
+ buffer = evbuffer_pullup(src, evbuffer_get_length(src));
+ for (i = 0; i < evbuffer_get_length(src); ++i) {
+ evbuffer_add(dst, "x", 1);
+ evbuffer_add(dst, buffer + i, 1);
+ }
+
+ evbuffer_drain(src, evbuffer_get_length(src));
+ return (BEV_OK);
+}
+
+static void
+test_bufferevent_filters_impl(int use_pair)
+{
+ struct bufferevent *bev1 = NULL, *bev2 = NULL;
+ struct bufferevent *bev1_base = NULL, *bev2_base = NULL;
+ char buffer[8333];
+ int i;
+
+ test_ok = 0;
+
+ if (use_pair) {
+ struct bufferevent *pair[2];
+ tt_assert(0 == bufferevent_pair_new(NULL, 0, pair));
+ bev1 = pair[0];
+ bev2 = pair[1];
+ } else {
+ bev1 = bufferevent_socket_new(NULL, pair[0], 0);
+ bev2 = bufferevent_socket_new(NULL, pair[1], 0);
+ }
+ bev1_base = bev1;
+ bev2_base = bev2;
+
+ for (i = 0; i < (int)sizeof(buffer); i++)
+ buffer[i] = i;
+
+ bev1 = bufferevent_filter_new(bev1, NULL, bufferevent_output_filter,
+ BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
+
+ bev2 = bufferevent_filter_new(bev2, bufferevent_input_filter,
+ NULL, BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
+ bufferevent_setcb(bev1, NULL, writecb, errorcb, NULL);
+ bufferevent_setcb(bev2, readcb, NULL, errorcb, NULL);
+
+ tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev1_base);
+ tt_ptr_op(bufferevent_get_underlying(bev2), ==, bev2_base);
+ tt_int_op(bufferevent_getfd(bev1), ==, -1);
+ tt_int_op(bufferevent_getfd(bev2), ==, -1);
+
+ bufferevent_disable(bev1, EV_READ);
+ bufferevent_enable(bev2, EV_READ);
+ /* insert some filters */
+ bufferevent_write(bev1, buffer, sizeof(buffer));
+
+ event_dispatch();
+
+ if (test_ok != 2)
+ test_ok = 0;
+
+end:
+ if (bev1)
+ bufferevent_free(bev1);
+ if (bev2)
+ bufferevent_free(bev2);
+
+}
+
+static void
+test_bufferevent_filters(void)
+{
+ test_bufferevent_filters_impl(0);
+}
+
+static void
+test_bufferevent_pair_filters(void)
+{
+ test_bufferevent_filters_impl(1);
+}
+
+
+static void
+sender_writecb(struct bufferevent *bev, void *ctx)
+{
+ if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
+ bufferevent_disable(bev,EV_READ|EV_WRITE);
+ bufferevent_free(bev);
+ }
+}
+
+static void
+sender_errorcb(struct bufferevent *bev, short what, void *ctx)
+{
+ TT_FAIL(("Got sender error %d",(int)what));
+}
+
+static int bufferevent_connect_test_flags = 0;
+static int n_strings_read = 0;
+static int n_reads_invoked = 0;
+
+#define TEST_STR "Now is the time for all good events to signal for " \
+ "the good of their protocol"
+static void
+listen_cb(struct evconnlistener *listener, evutil_socket_t fd,
+ struct sockaddr *sa, int socklen, void *arg)
+{
+ struct event_base *base = arg;
+ struct bufferevent *bev;
+ const char s[] = TEST_STR;
+ TT_BLATHER(("Got a request on socket %d", (int)fd ));
+ bev = bufferevent_socket_new(base, fd, bufferevent_connect_test_flags);
+ tt_assert(bev);
+ bufferevent_setcb(bev, NULL, sender_writecb, sender_errorcb, NULL);
+ bufferevent_write(bev, s, sizeof(s));
+end:
+ ;
+}
+
+static void
+reader_eventcb(struct bufferevent *bev, short what, void *ctx)
+{
+ struct event_base *base = ctx;
+ if (what & BEV_EVENT_ERROR) {
+ perror("foobar");
+ TT_FAIL(("got connector error %d", (int)what));
+ return;
+ }
+ if (what & BEV_EVENT_CONNECTED) {
+ bufferevent_enable(bev, EV_READ);
+ }
+ if (what & BEV_EVENT_EOF) {
+ char buf[512];
+ size_t n;
+ n = bufferevent_read(bev, buf, sizeof(buf)-1);
+ buf[n] = '\0';
+ tt_str_op(buf, ==, TEST_STR);
+ if (++n_strings_read == 2)
+ event_base_loopexit(base, NULL);
+ }
+end:
+ ;
+}
+
+static void
+reader_readcb(struct bufferevent *bev, void *ctx)
+{
+ n_reads_invoked++;
+}
+
+static void
+test_bufferevent_connect(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct evconnlistener *lev=NULL;
+ struct bufferevent *bev1=NULL, *bev2=NULL;
+ struct sockaddr_in localhost;
+ struct sockaddr_storage ss;
+ struct sockaddr *sa;
+ ev_socklen_t slen;
+
+ int be_flags=BEV_OPT_CLOSE_ON_FREE;
+
+ if (strstr((char*)data->setup_data, "defer")) {
+ be_flags |= BEV_OPT_DEFER_CALLBACKS;
+ }
+ if (strstr((char*)data->setup_data, "unlocked")) {
+ be_flags |= BEV_OPT_UNLOCK_CALLBACKS;
+ }
+ if (strstr((char*)data->setup_data, "lock")) {
+ be_flags |= BEV_OPT_THREADSAFE;
+ }
+ bufferevent_connect_test_flags = be_flags;
+#ifdef WIN32
+ if (!strcmp((char*)data->setup_data, "unset_connectex")) {
+ struct win32_extension_fns *ext =
+ (struct win32_extension_fns *)
+ event_get_win32_extension_fns();
+ ext->ConnectEx = NULL;
+ }
+#endif
+
+ memset(&localhost, 0, sizeof(localhost));
+
+ localhost.sin_port = 0; /* pick-a-port */
+ localhost.sin_addr.s_addr = htonl(0x7f000001L);
+ localhost.sin_family = AF_INET;
+ sa = (struct sockaddr *)&localhost;
+ lev = evconnlistener_new_bind(data->base, listen_cb, data->base,
+ LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
+ 16, sa, sizeof(localhost));
+ tt_assert(lev);
+
+ sa = (struct sockaddr *)&ss;
+ slen = sizeof(ss);
+ if (regress_get_listener_addr(lev, sa, &slen) < 0) {
+ tt_abort_perror("getsockname");
+ }
+
+ tt_assert(!evconnlistener_enable(lev));
+ bev1 = bufferevent_socket_new(data->base, -1, be_flags);
+ bev2 = bufferevent_socket_new(data->base, -1, be_flags);
+ tt_assert(bev1);
+ tt_assert(bev2);
+ bufferevent_setcb(bev1, reader_readcb,NULL, reader_eventcb, data->base);
+ bufferevent_setcb(bev2, reader_readcb,NULL, reader_eventcb, data->base);
+
+ bufferevent_enable(bev1, EV_READ);
+ bufferevent_enable(bev2, EV_READ);
+
+ tt_want(!bufferevent_socket_connect(bev1, sa, sizeof(localhost)));
+ tt_want(!bufferevent_socket_connect(bev2, sa, sizeof(localhost)));
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(n_strings_read, ==, 2);
+ tt_int_op(n_reads_invoked, >=, 2);
+end:
+ if (lev)
+ evconnlistener_free(lev);
+
+ if (bev1)
+ bufferevent_free(bev1);
+
+ if (bev2)
+ bufferevent_free(bev2);
+}
+
+static void
+want_fail_eventcb(struct bufferevent *bev, short what, void *ctx)
+{
+ struct event_base *base = ctx;
+ const char *err;
+ evutil_socket_t s;
+
+ if (what & BEV_EVENT_ERROR) {
+ s = bufferevent_getfd(bev);
+ err = evutil_socket_error_to_string(evutil_socket_geterror(s));
+ TT_BLATHER(("connection failure on %d: %s", s, err));
+ test_ok = 1;
+ } else {
+ TT_FAIL(("didn't fail? what %hd", what));
+ }
+
+ event_base_loopexit(base, NULL);
+}
+
+static void
+close_socket_cb(evutil_socket_t fd, short what, void *arg)
+{
+ evutil_socket_t *fdp = arg;
+ if (*fdp >= 0) {
+ evutil_closesocket(*fdp);
+ *fdp = -1;
+ }
+}
+
+static void
+test_bufferevent_connect_fail(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev=NULL;
+ struct sockaddr_in localhost;
+ struct sockaddr *sa = (struct sockaddr*)&localhost;
+ evutil_socket_t fake_listener = -1;
+ ev_socklen_t slen = sizeof(localhost);
+ struct event close_listener_event;
+ int close_listener_event_added = 0;
+ struct timeval one_second = { 1, 0 };
+ int r;
+
+ test_ok = 0;
+
+ memset(&localhost, 0, sizeof(localhost));
+ localhost.sin_port = 0; /* have the kernel pick a port */
+ localhost.sin_addr.s_addr = htonl(0x7f000001L);
+ localhost.sin_family = AF_INET;
+
+ /* bind, but don't listen or accept. should trigger
+ "Connection refused" reliably on most platforms. */
+ fake_listener = socket(localhost.sin_family, SOCK_STREAM, 0);
+ tt_assert(fake_listener >= 0);
+ tt_assert(bind(fake_listener, sa, slen) == 0);
+ tt_assert(getsockname(fake_listener, sa, &slen) == 0);
+ bev = bufferevent_socket_new(data->base, -1,
+ BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
+ tt_assert(bev);
+ bufferevent_setcb(bev, NULL, NULL, want_fail_eventcb, data->base);
+
+ r = bufferevent_socket_connect(bev, sa, slen);
+ /* XXXX we'd like to test the '0' case everywhere, but FreeBSD tells
+ * detects the error immediately, which is not really wrong of it. */
+ tt_want(r == 0 || r == -1);
+
+ /* Close the listener socket after a second. This should trigger
+ "connection refused" on some other platforms, including OSX. */
+ evtimer_assign(&close_listener_event, data->base, close_socket_cb,
+ &fake_listener);
+ event_add(&close_listener_event, &one_second);
+ close_listener_event_added = 1;
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(test_ok, ==, 1);
+
+end:
+ if (fake_listener >= 0)
+ evutil_closesocket(fake_listener);
+
+ if (bev)
+ bufferevent_free(bev);
+
+ if (close_listener_event_added)
+ event_del(&close_listener_event);
+}
+
+struct timeout_cb_result {
+ struct timeval read_timeout_at;
+ struct timeval write_timeout_at;
+ struct timeval last_wrote_at;
+ int n_read_timeouts;
+ int n_write_timeouts;
+ int total_calls;
+};
+
+static void
+bev_timeout_write_cb(struct bufferevent *bev, void *arg)
+{
+ struct timeout_cb_result *res = arg;
+ evutil_gettimeofday(&res->last_wrote_at, NULL);
+}
+
+static void
+bev_timeout_event_cb(struct bufferevent *bev, short what, void *arg)
+{
+ struct timeout_cb_result *res = arg;
+ ++res->total_calls;
+
+ if ((what & (BEV_EVENT_READING|BEV_EVENT_TIMEOUT))
+ == (BEV_EVENT_READING|BEV_EVENT_TIMEOUT)) {
+ evutil_gettimeofday(&res->read_timeout_at, NULL);
+ ++res->n_read_timeouts;
+ }
+ if ((what & (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT))
+ == (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT)) {
+ evutil_gettimeofday(&res->write_timeout_at, NULL);
+ ++res->n_write_timeouts;
+ }
+}
+
+static void
+test_bufferevent_timeouts(void *arg)
+{
+ /* "arg" is a string containing "pair" and/or "filter". */
+ struct bufferevent *bev1 = NULL, *bev2 = NULL;
+ struct basic_test_data *data = arg;
+ int use_pair = 0, use_filter = 0;
+ struct timeval tv_w, tv_r, started_at;
+ struct timeout_cb_result res1, res2;
+ char buf[1024];
+
+ memset(&res1, 0, sizeof(res1));
+ memset(&res2, 0, sizeof(res2));
+
+ if (strstr((char*)data->setup_data, "pair"))
+ use_pair = 1;
+ if (strstr((char*)data->setup_data, "filter"))
+ use_filter = 1;
+
+ if (use_pair) {
+ struct bufferevent *p[2];
+ tt_int_op(0, ==, bufferevent_pair_new(data->base, 0, p));
+ bev1 = p[0];
+ bev2 = p[1];
+ } else {
+ bev1 = bufferevent_socket_new(data->base, data->pair[0], 0);
+ bev2 = bufferevent_socket_new(data->base, data->pair[1], 0);
+ }
+
+ tt_assert(bev1);
+ tt_assert(bev2);
+
+ if (use_filter) {
+ struct bufferevent *bevf1, *bevf2;
+ bevf1 = bufferevent_filter_new(bev1, NULL, NULL,
+ BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
+ bevf2 = bufferevent_filter_new(bev2, NULL, NULL,
+ BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
+ tt_assert(bevf1);
+ tt_assert(bevf2);
+ bev1 = bevf1;
+ bev2 = bevf2;
+ }
+
+ /* Do this nice and early. */
+ bufferevent_disable(bev2, EV_READ);
+
+ /* bev1 will try to write and read. Both will time out. */
+ evutil_gettimeofday(&started_at, NULL);
+ tv_w.tv_sec = tv_r.tv_sec = 0;
+ tv_w.tv_usec = 100*1000;
+ tv_r.tv_usec = 150*1000;
+ bufferevent_setcb(bev1, NULL, bev_timeout_write_cb,
+ bev_timeout_event_cb, &res1);
+ bufferevent_setwatermark(bev1, EV_WRITE, 1024*1024+10, 0);
+ bufferevent_set_timeouts(bev1, &tv_r, &tv_w);
+ if (use_pair) {
+ /* For a pair, the fact that the other side isn't reading
+ * makes the writer stall */
+ bufferevent_write(bev1, "ABCDEFG", 7);
+ } else {
+ /* For a real socket, the kernel's TCP buffers can eat a
+ * fair number of bytes; make sure that at some point we
+ * have some bytes that will stall. */
+ struct evbuffer *output = bufferevent_get_output(bev1);
+ int i;
+ memset(buf, 0xbb, sizeof(buf));
+ for (i=0;i<1024;++i) {
+ evbuffer_add_reference(output, buf, sizeof(buf),
+ NULL, NULL);
+ }
+ }
+ bufferevent_enable(bev1, EV_READ|EV_WRITE);
+
+ /* bev2 has nothing to say, and isn't listening. */
+ bufferevent_setcb(bev2, NULL, bev_timeout_write_cb,
+ bev_timeout_event_cb, &res2);
+ tv_w.tv_sec = tv_r.tv_sec = 0;
+ tv_w.tv_usec = 200*1000;
+ tv_r.tv_usec = 100*1000;
+ bufferevent_set_timeouts(bev2, &tv_r, &tv_w);
+ bufferevent_enable(bev2, EV_WRITE);
+
+ tv_r.tv_sec = 1;
+ tv_r.tv_usec = 0;
+
+ event_base_loopexit(data->base, &tv_r);
+ event_base_dispatch(data->base);
+
+ /* XXXX Test that actually reading or writing a little resets the
+ * timeouts. */
+
+ /* Each buf1 timeout happens, and happens only once. */
+ tt_want(res1.n_read_timeouts);
+ tt_want(res1.n_write_timeouts);
+ tt_want(res1.n_read_timeouts == 1);
+ tt_want(res1.n_write_timeouts == 1);
+
+ test_timeval_diff_eq(&started_at, &res1.read_timeout_at, 150);
+ test_timeval_diff_eq(&started_at, &res1.write_timeout_at, 100);
+
+end:
+ if (bev1)
+ bufferevent_free(bev1);
+ if (bev2)
+ bufferevent_free(bev2);
+}
+
+struct testcase_t bufferevent_testcases[] = {
+
+ LEGACY(bufferevent, TT_ISOLATED),
+ LEGACY(bufferevent_pair, TT_ISOLATED),
+ LEGACY(bufferevent_watermarks, TT_ISOLATED),
+ LEGACY(bufferevent_pair_watermarks, TT_ISOLATED),
+ LEGACY(bufferevent_filters, TT_ISOLATED),
+ LEGACY(bufferevent_pair_filters, TT_ISOLATED),
+ { "bufferevent_connect", test_bufferevent_connect, TT_FORK|TT_NEED_BASE,
+ &basic_setup, (void*)"" },
+ { "bufferevent_connect_defer", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"defer" },
+ { "bufferevent_connect_lock", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, (void*)"lock" },
+ { "bufferevent_connect_lock_defer", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup,
+ (void*)"defer lock" },
+ { "bufferevent_connect_unlocked_cbs", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup,
+ (void*)"lock defer unlocked" },
+ { "bufferevent_connect_fail", test_bufferevent_connect_fail,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "bufferevent_timeout", test_bufferevent_timeouts,
+ TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR, &basic_setup, (void*)"" },
+ { "bufferevent_timeout_pair", test_bufferevent_timeouts,
+ TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"pair" },
+ { "bufferevent_timeout_filter", test_bufferevent_timeouts,
+ TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter" },
+ { "bufferevent_timeout_filter_pair", test_bufferevent_timeouts,
+ TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter pair" },
+#ifdef _EVENT_HAVE_LIBZ
+ LEGACY(bufferevent_zlib, TT_ISOLATED),
+#else
+ { "bufferevent_zlib", NULL, TT_SKIP, NULL, NULL },
+#endif
+
+ END_OF_TESTCASES,
+};
+
+struct testcase_t bufferevent_iocp_testcases[] = {
+
+ LEGACY(bufferevent, TT_ISOLATED|TT_ENABLE_IOCP),
+ LEGACY(bufferevent_watermarks, TT_ISOLATED|TT_ENABLE_IOCP),
+ LEGACY(bufferevent_filters, TT_ISOLATED|TT_ENABLE_IOCP),
+ { "bufferevent_connect", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, (void*)"" },
+ { "bufferevent_connect_defer", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, (void*)"defer" },
+ { "bufferevent_connect_lock", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE|TT_NEED_THREADS|TT_ENABLE_IOCP, &basic_setup,
+ (void*)"lock" },
+ { "bufferevent_connect_lock_defer", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE|TT_NEED_THREADS|TT_ENABLE_IOCP, &basic_setup,
+ (void*)"defer lock" },
+ { "bufferevent_connect_fail", test_bufferevent_connect_fail,
+ TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL },
+ { "bufferevent_connect_nonblocking", test_bufferevent_connect,
+ TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup,
+ (void*)"unset_connectex" },
+
+ END_OF_TESTCASES,
+};
diff --git a/libevent-2.0.20-stable/test/regress_dns.c b/libevent-2.0.20-stable/test/regress_dns.c
new file mode 100644
index 0000000..9a2e4d7
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress_dns.c
@@ -0,0 +1,1855 @@
+/*
+ * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <ws2tcpip.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#endif
+#ifdef _EVENT_HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event2/dns.h"
+#include "event2/dns_compat.h"
+#include "event2/dns_struct.h"
+#include "event2/event.h"
+#include "event2/event_compat.h"
+#include "event2/event_struct.h"
+#include "event2/util.h"
+#include "event2/listener.h"
+#include "event2/bufferevent.h"
+#include "log-internal.h"
+#include "regress.h"
+#include "regress_testutils.h"
+
+#include "../util-internal.h"
+
+static int dns_ok = 0;
+static int dns_got_cancel = 0;
+static int dns_err = 0;
+
+
+static void
+dns_gethostbyname_cb(int result, char type, int count, int ttl,
+ void *addresses, void *arg)
+{
+ dns_ok = dns_err = 0;
+
+ if (result == DNS_ERR_TIMEOUT) {
+ printf("[Timed out] ");
+ dns_err = result;
+ goto out;
+ }
+
+ if (result != DNS_ERR_NONE) {
+ printf("[Error code %d] ", result);
+ goto out;
+ }
+
+ TT_BLATHER(("type: %d, count: %d, ttl: %d: ", type, count, ttl));
+
+ switch (type) {
+ case DNS_IPv6_AAAA: {
+#if defined(_EVENT_HAVE_STRUCT_IN6_ADDR) && defined(_EVENT_HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN)
+ struct in6_addr *in6_addrs = addresses;
+ char buf[INET6_ADDRSTRLEN+1];
+ int i;
+ /* a resolution that's not valid does not help */
+ if (ttl < 0)
+ goto out;
+ for (i = 0; i < count; ++i) {
+ const char *b = inet_ntop(AF_INET6, &in6_addrs[i], buf,sizeof(buf));
+ if (b)
+ TT_BLATHER(("%s ", b));
+ else
+ TT_BLATHER(("%s ", strerror(errno)));
+ }
+#endif
+ break;
+ }
+ case DNS_IPv4_A: {
+ struct in_addr *in_addrs = addresses;
+ int i;
+ /* a resolution that's not valid does not help */
+ if (ttl < 0)
+ goto out;
+ for (i = 0; i < count; ++i)
+ TT_BLATHER(("%s ", inet_ntoa(in_addrs[i])));
+ break;
+ }
+ case DNS_PTR:
+ /* may get at most one PTR */
+ if (count != 1)
+ goto out;
+
+ TT_BLATHER(("%s ", *(char **)addresses));
+ break;
+ default:
+ goto out;
+ }
+
+ dns_ok = type;
+
+out:
+ if (arg == NULL)
+ event_loopexit(NULL);
+ else
+ event_base_loopexit((struct event_base *)arg, NULL);
+}
+
+static void
+dns_gethostbyname(void)
+{
+ dns_ok = 0;
+ evdns_resolve_ipv4("www.monkey.org", 0, dns_gethostbyname_cb, NULL);
+ event_dispatch();
+
+ tt_int_op(dns_ok, ==, DNS_IPv4_A);
+ test_ok = dns_ok;
+end:
+ ;
+}
+
+static void
+dns_gethostbyname6(void)
+{
+ dns_ok = 0;
+ evdns_resolve_ipv6("www.ietf.org", 0, dns_gethostbyname_cb, NULL);
+ event_dispatch();
+
+ if (!dns_ok && dns_err == DNS_ERR_TIMEOUT) {
+ tt_skip();
+ }
+
+ tt_int_op(dns_ok, ==, DNS_IPv6_AAAA);
+ test_ok = 1;
+end:
+ ;
+}
+
+static void
+dns_gethostbyaddr(void)
+{
+ struct in_addr in;
+ in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */
+ dns_ok = 0;
+ evdns_resolve_reverse(&in, 0, dns_gethostbyname_cb, NULL);
+ event_dispatch();
+
+ tt_int_op(dns_ok, ==, DNS_PTR);
+ test_ok = dns_ok;
+end:
+ ;
+}
+
+static void
+dns_resolve_reverse(void *ptr)
+{
+ struct in_addr in;
+ struct event_base *base = event_base_new();
+ struct evdns_base *dns = evdns_base_new(base, 1/* init name servers */);
+ struct evdns_request *req = NULL;
+
+ tt_assert(base);
+ tt_assert(dns);
+ in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */
+ dns_ok = 0;
+
+ req = evdns_base_resolve_reverse(
+ dns, &in, 0, dns_gethostbyname_cb, base);
+ tt_assert(req);
+
+ event_base_dispatch(base);
+
+ tt_int_op(dns_ok, ==, DNS_PTR);
+
+end:
+ if (dns)
+ evdns_base_free(dns, 0);
+ if (base)
+ event_base_free(base);
+}
+
+static int n_server_responses = 0;
+
+static void
+dns_server_request_cb(struct evdns_server_request *req, void *data)
+{
+ int i, r;
+ const char TEST_ARPA[] = "11.11.168.192.in-addr.arpa";
+ const char TEST_IN6[] =
+ "f.e.f.e." "0.0.0.0." "0.0.0.0." "1.1.1.1."
+ "a.a.a.a." "0.0.0.0." "0.0.0.0." "0.f.f.f.ip6.arpa";
+
+ for (i = 0; i < req->nquestions; ++i) {
+ const int qtype = req->questions[i]->type;
+ const int qclass = req->questions[i]->dns_question_class;
+ const char *qname = req->questions[i]->name;
+
+ struct in_addr ans;
+ ans.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */
+ if (qtype == EVDNS_TYPE_A &&
+ qclass == EVDNS_CLASS_INET &&
+ !evutil_ascii_strcasecmp(qname, "zz.example.com")) {
+ r = evdns_server_request_add_a_reply(req, qname,
+ 1, &ans.s_addr, 12345);
+ if (r<0)
+ dns_ok = 0;
+ } else if (qtype == EVDNS_TYPE_AAAA &&
+ qclass == EVDNS_CLASS_INET &&
+ !evutil_ascii_strcasecmp(qname, "zz.example.com")) {
+ char addr6[17] = "abcdefghijklmnop";
+ r = evdns_server_request_add_aaaa_reply(req,
+ qname, 1, addr6, 123);
+ if (r<0)
+ dns_ok = 0;
+ } else if (qtype == EVDNS_TYPE_PTR &&
+ qclass == EVDNS_CLASS_INET &&
+ !evutil_ascii_strcasecmp(qname, TEST_ARPA)) {
+ r = evdns_server_request_add_ptr_reply(req, NULL,
+ qname, "ZZ.EXAMPLE.COM", 54321);
+ if (r<0)
+ dns_ok = 0;
+ } else if (qtype == EVDNS_TYPE_PTR &&
+ qclass == EVDNS_CLASS_INET &&
+ !evutil_ascii_strcasecmp(qname, TEST_IN6)){
+ r = evdns_server_request_add_ptr_reply(req, NULL,
+ qname,
+ "ZZ-INET6.EXAMPLE.COM", 54322);
+ if (r<0)
+ dns_ok = 0;
+ } else if (qtype == EVDNS_TYPE_A &&
+ qclass == EVDNS_CLASS_INET &&
+ !evutil_ascii_strcasecmp(qname, "drop.example.com")) {
+ if (evdns_server_request_drop(req)<0)
+ dns_ok = 0;
+ return;
+ } else {
+ printf("Unexpected question %d %d \"%s\" ",
+ qtype, qclass, qname);
+ dns_ok = 0;
+ }
+ }
+ r = evdns_server_request_respond(req, 0);
+ if (r<0) {
+ printf("Couldn't send reply. ");
+ dns_ok = 0;
+ }
+}
+
+static void
+dns_server_gethostbyname_cb(int result, char type, int count, int ttl,
+ void *addresses, void *arg)
+{
+ if (result == DNS_ERR_CANCEL) {
+ if (arg != (void*)(char*)90909) {
+ printf("Unexpected cancelation");
+ dns_ok = 0;
+ }
+ dns_got_cancel = 1;
+ goto out;
+ }
+ if (result != DNS_ERR_NONE) {
+ printf("Unexpected result %d. ", result);
+ dns_ok = 0;
+ goto out;
+ }
+ if (count != 1) {
+ printf("Unexpected answer count %d. ", count);
+ dns_ok = 0;
+ goto out;
+ }
+ switch (type) {
+ case DNS_IPv4_A: {
+ struct in_addr *in_addrs = addresses;
+ if (in_addrs[0].s_addr != htonl(0xc0a80b0bUL) || ttl != 12345) {
+ printf("Bad IPv4 response \"%s\" %d. ",
+ inet_ntoa(in_addrs[0]), ttl);
+ dns_ok = 0;
+ goto out;
+ }
+ break;
+ }
+ case DNS_IPv6_AAAA: {
+#if defined (_EVENT_HAVE_STRUCT_IN6_ADDR) && defined(_EVENT_HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN)
+ struct in6_addr *in6_addrs = addresses;
+ char buf[INET6_ADDRSTRLEN+1];
+ if (memcmp(&in6_addrs[0].s6_addr, "abcdefghijklmnop", 16)
+ || ttl != 123) {
+ const char *b = inet_ntop(AF_INET6, &in6_addrs[0],buf,sizeof(buf));
+ printf("Bad IPv6 response \"%s\" %d. ", b, ttl);
+ dns_ok = 0;
+ goto out;
+ }
+#endif
+ break;
+ }
+ case DNS_PTR: {
+ char **addrs = addresses;
+ if (arg != (void*)6) {
+ if (strcmp(addrs[0], "ZZ.EXAMPLE.COM") ||
+ ttl != 54321) {
+ printf("Bad PTR response \"%s\" %d. ",
+ addrs[0], ttl);
+ dns_ok = 0;
+ goto out;
+ }
+ } else {
+ if (strcmp(addrs[0], "ZZ-INET6.EXAMPLE.COM") ||
+ ttl != 54322) {
+ printf("Bad ipv6 PTR response \"%s\" %d. ",
+ addrs[0], ttl);
+ dns_ok = 0;
+ goto out;
+ }
+ }
+ break;
+ }
+ default:
+ printf("Bad response type %d. ", type);
+ dns_ok = 0;
+ }
+ out:
+ if (++n_server_responses == 3) {
+ event_loopexit(NULL);
+ }
+}
+
+static void
+dns_server(void)
+{
+ evutil_socket_t sock=-1;
+ struct sockaddr_in my_addr;
+ struct sockaddr_storage ss;
+ ev_socklen_t slen;
+ struct evdns_server_port *port=NULL;
+ struct in_addr resolve_addr;
+ struct in6_addr resolve_addr6;
+ struct evdns_base *base=NULL;
+ struct evdns_request *req=NULL;
+
+ dns_ok = 1;
+
+ base = evdns_base_new(NULL, 0);
+
+ /* Now configure a nameserver port. */
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock<0) {
+ tt_abort_perror("socket");
+ }
+
+ evutil_make_socket_nonblocking(sock);
+
+ memset(&my_addr, 0, sizeof(my_addr));
+ my_addr.sin_family = AF_INET;
+ my_addr.sin_port = 0; /* kernel picks */
+ my_addr.sin_addr.s_addr = htonl(0x7f000001UL);
+ if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) {
+ tt_abort_perror("bind");
+ }
+ slen = sizeof(ss);
+ if (getsockname(sock, (struct sockaddr*)&ss, &slen) < 0) {
+ tt_abort_perror("getsockname");
+ }
+
+ port = evdns_add_server_port(sock, 0, dns_server_request_cb, NULL);
+
+ /* Add ourself as the only nameserver, and make sure we really are
+ * the only nameserver. */
+ evdns_base_nameserver_sockaddr_add(base, (struct sockaddr*)&ss, slen, 0);
+ tt_int_op(evdns_base_count_nameservers(base), ==, 1);
+
+ /* Send some queries. */
+ evdns_base_resolve_ipv4(base, "zz.example.com", DNS_QUERY_NO_SEARCH,
+ dns_server_gethostbyname_cb, NULL);
+ evdns_base_resolve_ipv6(base, "zz.example.com", DNS_QUERY_NO_SEARCH,
+ dns_server_gethostbyname_cb, NULL);
+ resolve_addr.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */
+ evdns_base_resolve_reverse(base, &resolve_addr, 0,
+ dns_server_gethostbyname_cb, NULL);
+ memcpy(resolve_addr6.s6_addr,
+ "\xff\xf0\x00\x00\x00\x00\xaa\xaa"
+ "\x11\x11\x00\x00\x00\x00\xef\xef", 16);
+ evdns_base_resolve_reverse_ipv6(base, &resolve_addr6, 0,
+ dns_server_gethostbyname_cb, (void*)6);
+
+ req = evdns_base_resolve_ipv4(base,
+ "drop.example.com", DNS_QUERY_NO_SEARCH,
+ dns_server_gethostbyname_cb, (void*)(char*)90909);
+
+ evdns_cancel_request(base, req);
+
+ event_dispatch();
+
+ tt_assert(dns_got_cancel);
+ test_ok = dns_ok;
+
+end:
+ if (port)
+ evdns_close_server_port(port);
+ if (sock >= 0)
+ evutil_closesocket(sock);
+ if (base)
+ evdns_base_free(base, 0);
+}
+
+static int n_replies_left;
+static struct event_base *exit_base;
+
+struct generic_dns_callback_result {
+ int result;
+ char type;
+ int count;
+ int ttl;
+ size_t addrs_len;
+ void *addrs;
+ char addrs_buf[256];
+};
+
+static void
+generic_dns_callback(int result, char type, int count, int ttl, void *addresses,
+ void *arg)
+{
+ size_t len;
+ struct generic_dns_callback_result *res = arg;
+ res->result = result;
+ res->type = type;
+ res->count = count;
+ res->ttl = ttl;
+
+ if (type == DNS_IPv4_A)
+ len = count * 4;
+ else if (type == DNS_IPv6_AAAA)
+ len = count * 16;
+ else if (type == DNS_PTR)
+ len = strlen(addresses)+1;
+ else {
+ res->addrs_len = len = 0;
+ res->addrs = NULL;
+ }
+ if (len) {
+ res->addrs_len = len;
+ if (len > 256)
+ len = 256;
+ memcpy(res->addrs_buf, addresses, len);
+ res->addrs = res->addrs_buf;
+ }
+
+ if (--n_replies_left == 0)
+ event_base_loopexit(exit_base, NULL);
+}
+
+static struct regress_dns_server_table search_table[] = {
+ { "host.a.example.com", "err", "3", 0 },
+ { "host.b.example.com", "err", "3", 0 },
+ { "host.c.example.com", "A", "11.22.33.44", 0 },
+ { "host2.a.example.com", "err", "3", 0 },
+ { "host2.b.example.com", "A", "200.100.0.100", 0 },
+ { "host2.c.example.com", "err", "3", 0 },
+ { "hostn.a.example.com", "errsoa", "0", 0 },
+ { "hostn.b.example.com", "errsoa", "3", 0 },
+ { "hostn.c.example.com", "err", "0", 0 },
+
+ { "host", "err", "3", 0 },
+ { "host2", "err", "3", 0 },
+ { "*", "err", "3", 0 },
+ { NULL, NULL, NULL, 0 }
+};
+
+static void
+dns_search_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evdns_base *dns = NULL;
+ ev_uint16_t portnum = 0;
+ char buf[64];
+
+ struct generic_dns_callback_result r[8];
+
+ tt_assert(regress_dnsserver(base, &portnum, search_table));
+ evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
+
+ dns = evdns_base_new(base, 0);
+ tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
+
+ evdns_base_search_add(dns, "a.example.com");
+ evdns_base_search_add(dns, "b.example.com");
+ evdns_base_search_add(dns, "c.example.com");
+
+ n_replies_left = sizeof(r)/sizeof(r[0]);
+ exit_base = base;
+
+ evdns_base_resolve_ipv4(dns, "host", 0, generic_dns_callback, &r[0]);
+ evdns_base_resolve_ipv4(dns, "host2", 0, generic_dns_callback, &r[1]);
+ evdns_base_resolve_ipv4(dns, "host", DNS_NO_SEARCH, generic_dns_callback, &r[2]);
+ evdns_base_resolve_ipv4(dns, "host2", DNS_NO_SEARCH, generic_dns_callback, &r[3]);
+ evdns_base_resolve_ipv4(dns, "host3", 0, generic_dns_callback, &r[4]);
+ evdns_base_resolve_ipv4(dns, "hostn.a.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[5]);
+ evdns_base_resolve_ipv4(dns, "hostn.b.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[6]);
+ evdns_base_resolve_ipv4(dns, "hostn.c.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[7]);
+
+ event_base_dispatch(base);
+
+ tt_int_op(r[0].type, ==, DNS_IPv4_A);
+ tt_int_op(r[0].count, ==, 1);
+ tt_int_op(((ev_uint32_t*)r[0].addrs)[0], ==, htonl(0x0b16212c));
+ tt_int_op(r[1].type, ==, DNS_IPv4_A);
+ tt_int_op(r[1].count, ==, 1);
+ tt_int_op(((ev_uint32_t*)r[1].addrs)[0], ==, htonl(0xc8640064));
+ tt_int_op(r[2].result, ==, DNS_ERR_NOTEXIST);
+ tt_int_op(r[3].result, ==, DNS_ERR_NOTEXIST);
+ tt_int_op(r[4].result, ==, DNS_ERR_NOTEXIST);
+ tt_int_op(r[5].result, ==, DNS_ERR_NODATA);
+ tt_int_op(r[5].ttl, ==, 42);
+ tt_int_op(r[6].result, ==, DNS_ERR_NOTEXIST);
+ tt_int_op(r[6].ttl, ==, 42);
+ tt_int_op(r[7].result, ==, DNS_ERR_NODATA);
+ tt_int_op(r[7].ttl, ==, 0);
+
+end:
+ if (dns)
+ evdns_base_free(dns, 0);
+
+ regress_clean_dnsserver();
+}
+
+static int request_count = 0;
+static struct evdns_request *current_req = NULL;
+
+static void
+search_cancel_server_cb(struct evdns_server_request *req, void *data)
+{
+ const char *question;
+
+ if (req->nquestions != 1)
+ TT_DIE(("Only handling one question at a time; got %d",
+ req->nquestions));
+
+ question = req->questions[0]->name;
+
+ TT_BLATHER(("got question, %s", question));
+
+ tt_assert(request_count > 0);
+ tt_assert(!evdns_server_request_respond(req, 3));
+
+ if (!--request_count)
+ evdns_cancel_request(NULL, current_req);
+
+end:
+ ;
+}
+
+static void
+dns_search_cancel_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evdns_base *dns = NULL;
+ struct evdns_server_port *port = NULL;
+ ev_uint16_t portnum = 0;
+ struct generic_dns_callback_result r1;
+ char buf[64];
+
+ port = regress_get_dnsserver(base, &portnum, NULL,
+ search_cancel_server_cb, NULL);
+ tt_assert(port);
+ evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
+
+ dns = evdns_base_new(base, 0);
+ tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
+
+ evdns_base_search_add(dns, "a.example.com");
+ evdns_base_search_add(dns, "b.example.com");
+ evdns_base_search_add(dns, "c.example.com");
+ evdns_base_search_add(dns, "d.example.com");
+
+ exit_base = base;
+ request_count = 3;
+ n_replies_left = 1;
+
+ current_req = evdns_base_resolve_ipv4(dns, "host", 0,
+ generic_dns_callback, &r1);
+ event_base_dispatch(base);
+
+ tt_int_op(r1.result, ==, DNS_ERR_CANCEL);
+
+end:
+ if (port)
+ evdns_close_server_port(port);
+ if (dns)
+ evdns_base_free(dns, 0);
+}
+
+static void
+fail_server_cb(struct evdns_server_request *req, void *data)
+{
+ const char *question;
+ int *count = data;
+ struct in_addr in;
+
+ /* Drop the first N requests that we get. */
+ if (*count > 0) {
+ --*count;
+ tt_want(! evdns_server_request_drop(req));
+ return;
+ }
+
+ if (req->nquestions != 1)
+ TT_DIE(("Only handling one question at a time; got %d",
+ req->nquestions));
+
+ question = req->questions[0]->name;
+
+ if (!evutil_ascii_strcasecmp(question, "google.com")) {
+ /* Detect a probe, and get out of the loop. */
+ event_base_loopexit(exit_base, NULL);
+ }
+
+ evutil_inet_pton(AF_INET, "16.32.64.128", &in);
+ evdns_server_request_add_a_reply(req, question, 1, &in.s_addr,
+ 100);
+ tt_assert(! evdns_server_request_respond(req, 0))
+ return;
+end:
+ tt_want(! evdns_server_request_drop(req));
+}
+
+static void
+dns_retry_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evdns_server_port *port = NULL;
+ struct evdns_base *dns = NULL;
+ int drop_count = 2;
+ ev_uint16_t portnum = 0;
+ char buf[64];
+
+ struct generic_dns_callback_result r1;
+
+ port = regress_get_dnsserver(base, &portnum, NULL,
+ fail_server_cb, &drop_count);
+ tt_assert(port);
+ evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
+
+ dns = evdns_base_new(base, 0);
+ tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
+ tt_assert(! evdns_base_set_option(dns, "timeout", "0.3"));
+ tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "10"));
+ tt_assert(! evdns_base_set_option(dns, "initial-probe-timeout", "0.5"));
+
+ evdns_base_resolve_ipv4(dns, "host.example.com", 0,
+ generic_dns_callback, &r1);
+
+ n_replies_left = 1;
+ exit_base = base;
+
+ event_base_dispatch(base);
+
+ tt_int_op(drop_count, ==, 0);
+
+ tt_int_op(r1.type, ==, DNS_IPv4_A);
+ tt_int_op(r1.count, ==, 1);
+ tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x10204080));
+
+ /* Now try again, but this time have the server get treated as
+ * failed, so we can send it a test probe. */
+ drop_count = 4;
+ tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "3"));
+ tt_assert(! evdns_base_set_option(dns, "attempts:", "4"));
+ memset(&r1, 0, sizeof(r1));
+
+ evdns_base_resolve_ipv4(dns, "host.example.com", 0,
+ generic_dns_callback, &r1);
+
+ n_replies_left = 2;
+
+ /* This will run until it answers the "google.com" probe request. */
+ event_base_dispatch(base);
+
+ /* We'll treat the server as failed here. */
+ tt_int_op(r1.result, ==, DNS_ERR_TIMEOUT);
+
+ /* It should work this time. */
+ tt_int_op(drop_count, ==, 0);
+ evdns_base_resolve_ipv4(dns, "host.example.com", 0,
+ generic_dns_callback, &r1);
+
+ event_base_dispatch(base);
+ tt_int_op(r1.result, ==, DNS_ERR_NONE);
+ tt_int_op(r1.type, ==, DNS_IPv4_A);
+ tt_int_op(r1.count, ==, 1);
+ tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x10204080));
+
+end:
+ if (dns)
+ evdns_base_free(dns, 0);
+ if (port)
+ evdns_close_server_port(port);
+}
+
+static struct regress_dns_server_table internal_error_table[] = {
+ /* Error 4 (NOTIMPL) makes us reissue the request to another server
+ if we can.
+
+ XXXX we should reissue under a much wider set of circumstances!
+ */
+ { "foof.example.com", "err", "4", 0 },
+ { NULL, NULL, NULL, 0 }
+};
+
+static struct regress_dns_server_table reissue_table[] = {
+ { "foof.example.com", "A", "240.15.240.15", 0 },
+ { NULL, NULL, NULL, 0 }
+};
+
+static void
+dns_reissue_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evdns_server_port *port1 = NULL, *port2 = NULL;
+ struct evdns_base *dns = NULL;
+ struct generic_dns_callback_result r1;
+ ev_uint16_t portnum1 = 0, portnum2=0;
+ char buf1[64], buf2[64];
+
+ port1 = regress_get_dnsserver(base, &portnum1, NULL,
+ regress_dns_server_cb, internal_error_table);
+ tt_assert(port1);
+ port2 = regress_get_dnsserver(base, &portnum2, NULL,
+ regress_dns_server_cb, reissue_table);
+ tt_assert(port2);
+ evutil_snprintf(buf1, sizeof(buf1), "127.0.0.1:%d", (int)portnum1);
+ evutil_snprintf(buf2, sizeof(buf2), "127.0.0.1:%d", (int)portnum2);
+
+ dns = evdns_base_new(base, 0);
+ tt_assert(!evdns_base_nameserver_ip_add(dns, buf1));
+ tt_assert(! evdns_base_set_option(dns, "timeout:", "0.3"));
+ tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "2"));
+ tt_assert(! evdns_base_set_option(dns, "attempts:", "5"));
+
+ memset(&r1, 0, sizeof(r1));
+ evdns_base_resolve_ipv4(dns, "foof.example.com", 0,
+ generic_dns_callback, &r1);
+
+ /* Add this after, so that we are sure to get a reissue. */
+ tt_assert(!evdns_base_nameserver_ip_add(dns, buf2));
+
+ n_replies_left = 1;
+ exit_base = base;
+
+ event_base_dispatch(base);
+ tt_int_op(r1.result, ==, DNS_ERR_NONE);
+ tt_int_op(r1.type, ==, DNS_IPv4_A);
+ tt_int_op(r1.count, ==, 1);
+ tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0xf00ff00f));
+
+ /* Make sure we dropped at least once. */
+ tt_int_op(internal_error_table[0].seen, >, 0);
+
+end:
+ if (dns)
+ evdns_base_free(dns, 0);
+ if (port1)
+ evdns_close_server_port(port1);
+ if (port2)
+ evdns_close_server_port(port2);
+}
+
+#if 0
+static void
+dumb_bytes_fn(char *p, size_t n)
+{
+ unsigned i;
+ /* This gets us 6 bits of entropy per transaction ID, which means we
+ * will have probably have collisions and need to pick again. */
+ for (i=0;i<n;++i)
+ p[i] = (char)(rand() & 7);
+}
+#endif
+
+static void
+dns_inflight_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evdns_base *dns = NULL;
+ ev_uint16_t portnum = 0;
+ char buf[64];
+
+ struct generic_dns_callback_result r[20];
+ int i;
+
+ tt_assert(regress_dnsserver(base, &portnum, reissue_table));
+ evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
+
+ dns = evdns_base_new(base, 0);
+ tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
+ tt_assert(! evdns_base_set_option(dns, "max-inflight:", "3"));
+ tt_assert(! evdns_base_set_option(dns, "randomize-case:", "0"));
+
+ for (i=0;i<20;++i)
+ evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r[i]);
+
+ n_replies_left = 20;
+ exit_base = base;
+
+ event_base_dispatch(base);
+
+ for (i=0;i<20;++i) {
+ tt_int_op(r[i].type, ==, DNS_IPv4_A);
+ tt_int_op(r[i].count, ==, 1);
+ tt_int_op(((ev_uint32_t*)r[i].addrs)[0], ==, htonl(0xf00ff00f));
+ }
+
+end:
+ if (dns)
+ evdns_base_free(dns, 0);
+ regress_clean_dnsserver();
+}
+
+/* === Test for bufferevent_socket_connect_hostname */
+
+static int total_connected_or_failed = 0;
+static int total_n_accepted = 0;
+static struct event_base *be_connect_hostname_base = NULL;
+
+/* Implements a DNS server for the connect_hostname test and the
+ * getaddrinfo_async test */
+static void
+be_getaddrinfo_server_cb(struct evdns_server_request *req, void *data)
+{
+ int i;
+ int *n_got_p=data;
+ int added_any=0;
+ ++*n_got_p;
+
+ for (i=0;i<req->nquestions;++i) {
+ const int qtype = req->questions[i]->type;
+ const int qclass = req->questions[i]->dns_question_class;
+ const char *qname = req->questions[i]->name;
+ struct in_addr ans;
+ struct in6_addr ans6;
+ memset(&ans6, 0, sizeof(ans6));
+
+ if (qtype == EVDNS_TYPE_A &&
+ qclass == EVDNS_CLASS_INET &&
+ !evutil_ascii_strcasecmp(qname, "nobodaddy.example.com")) {
+ ans.s_addr = htonl(0x7f000001);
+ evdns_server_request_add_a_reply(req, qname,
+ 1, &ans.s_addr, 2000);
+ added_any = 1;
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "nosuchplace.example.com")) {
+ /* ok, just say notfound. */
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "both.example.com")) {
+ if (qtype == EVDNS_TYPE_A) {
+ ans.s_addr = htonl(0x50502020);
+ evdns_server_request_add_a_reply(req, qname,
+ 1, &ans.s_addr, 2000);
+ added_any = 1;
+ } else if (qtype == EVDNS_TYPE_AAAA) {
+ ans6.s6_addr[0] = 0x80;
+ ans6.s6_addr[1] = 0xff;
+ ans6.s6_addr[14] = 0xbb;
+ ans6.s6_addr[15] = 0xbb;
+ evdns_server_request_add_aaaa_reply(req, qname,
+ 1, &ans6.s6_addr, 2000);
+ added_any = 1;
+ }
+ evdns_server_request_add_cname_reply(req, qname,
+ "both-canonical.example.com", 1000);
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "v4only.example.com") ||
+ !evutil_ascii_strcasecmp(qname, "v4assert.example.com")) {
+ if (qtype == EVDNS_TYPE_A) {
+ ans.s_addr = htonl(0x12345678);
+ evdns_server_request_add_a_reply(req, qname,
+ 1, &ans.s_addr, 2000);
+ added_any = 1;
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "v4assert.example.com")) {
+ TT_FAIL(("Got an AAAA request for v4assert"));
+ }
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "v6only.example.com") ||
+ !evutil_ascii_strcasecmp(qname, "v6assert.example.com")) {
+ if (qtype == EVDNS_TYPE_AAAA) {
+ ans6.s6_addr[0] = 0x0b;
+ ans6.s6_addr[1] = 0x0b;
+ ans6.s6_addr[14] = 0xf0;
+ ans6.s6_addr[15] = 0x0d;
+ evdns_server_request_add_aaaa_reply(req, qname,
+ 1, &ans6.s6_addr, 2000);
+ added_any = 1;
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "v6assert.example.com")) {
+ TT_FAIL(("Got a A request for v6assert"));
+ }
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "v6timeout.example.com")) {
+ if (qtype == EVDNS_TYPE_A) {
+ ans.s_addr = htonl(0xabcdef01);
+ evdns_server_request_add_a_reply(req, qname,
+ 1, &ans.s_addr, 2000);
+ added_any = 1;
+ } else if (qtype == EVDNS_TYPE_AAAA) {
+ /* Let the v6 request time out.*/
+ evdns_server_request_drop(req);
+ return;
+ }
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "v4timeout.example.com")) {
+ if (qtype == EVDNS_TYPE_AAAA) {
+ ans6.s6_addr[0] = 0x0a;
+ ans6.s6_addr[1] = 0x0a;
+ ans6.s6_addr[14] = 0xff;
+ ans6.s6_addr[15] = 0x01;
+ evdns_server_request_add_aaaa_reply(req, qname,
+ 1, &ans6.s6_addr, 2000);
+ added_any = 1;
+ } else if (qtype == EVDNS_TYPE_A) {
+ /* Let the v4 request time out.*/
+ evdns_server_request_drop(req);
+ return;
+ }
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "v6timeout-nonexist.example.com")) {
+ if (qtype == EVDNS_TYPE_A) {
+ /* Fall through, give an nexist. */
+ } else if (qtype == EVDNS_TYPE_AAAA) {
+ /* Let the v6 request time out.*/
+ evdns_server_request_drop(req);
+ return;
+ }
+ } else if (!evutil_ascii_strcasecmp(qname,
+ "all-timeout.example.com")) {
+ /* drop all requests */
+ evdns_server_request_drop(req);
+ return;
+ } else {
+ TT_GRIPE(("Got weird request for %s",qname));
+ }
+ }
+ if (added_any)
+ evdns_server_request_respond(req, 0);
+ else
+ evdns_server_request_respond(req, 3);
+}
+
+/* Implements a listener for connect_hostname test. */
+static void
+nil_accept_cb(struct evconnlistener *l, evutil_socket_t fd, struct sockaddr *s,
+ int socklen, void *arg)
+{
+ int *p = arg;
+ (*p)++;
+ ++total_n_accepted;
+ /* don't do anything with the socket; let it close when we exit() */
+ if (total_n_accepted >= 3 && total_connected_or_failed >= 5)
+ event_base_loopexit(be_connect_hostname_base,
+ NULL);
+}
+
+struct be_conn_hostname_result {
+ int dnserr;
+ int what;
+};
+
+/* Bufferevent event callback for the connect_hostname test: remembers what
+ * event we got. */
+static void
+be_connect_hostname_event_cb(struct bufferevent *bev, short what, void *ctx)
+{
+ struct be_conn_hostname_result *got = ctx;
+ if (!got->what) {
+ TT_BLATHER(("Got a bufferevent event %d", what));
+ got->what = what;
+
+ if ((what & BEV_EVENT_CONNECTED) || (what & BEV_EVENT_ERROR)) {
+ int r;
+ if ((r = bufferevent_socket_get_dns_error(bev))) {
+ got->dnserr = r;
+ TT_BLATHER(("DNS error %d: %s", r,
+ evutil_gai_strerror(r)));
+ } ++total_connected_or_failed;
+ TT_BLATHER(("Got %d connections or errors.", total_connected_or_failed));
+
+ if (total_n_accepted >= 3 && total_connected_or_failed >= 5)
+ event_base_loopexit(be_connect_hostname_base,
+ NULL);
+ }
+ } else {
+ TT_FAIL(("Two events on one bufferevent. %d,%d",
+ got->what, (int)what));
+ }
+}
+
+static void
+test_bufferevent_connect_hostname(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct evconnlistener *listener = NULL;
+ struct bufferevent *be1=NULL, *be2=NULL, *be3=NULL, *be4=NULL, *be5=NULL;
+ struct be_conn_hostname_result be1_outcome={0,0}, be2_outcome={0,0},
+ be3_outcome={0,0}, be4_outcome={0,0}, be5_outcome={0,0};
+ int expect_err5;
+ struct evdns_base *dns=NULL;
+ struct evdns_server_port *port=NULL;
+ struct sockaddr_in sin;
+ int listener_port=-1;
+ ev_uint16_t dns_port=0;
+ int n_accept=0, n_dns=0;
+ char buf[128];
+
+ be_connect_hostname_base = data->base;
+
+ /* Bind an address and figure out what port it's on. */
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
+ sin.sin_port = 0;
+ listener = evconnlistener_new_bind(data->base, nil_accept_cb,
+ &n_accept,
+ LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC,
+ -1, (struct sockaddr *)&sin, sizeof(sin));
+ tt_assert(listener);
+ listener_port = regress_get_socket_port(
+ evconnlistener_get_fd(listener));
+
+ port = regress_get_dnsserver(data->base, &dns_port, NULL,
+ be_getaddrinfo_server_cb, &n_dns);
+ tt_assert(port);
+ tt_int_op(dns_port, >=, 0);
+
+ /* Start an evdns_base that uses the server as its resolver. */
+ dns = evdns_base_new(data->base, 0);
+ evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)dns_port);
+ evdns_base_nameserver_ip_add(dns, buf);
+
+ /* Now, finally, at long last, launch the bufferevents. One should do
+ * a failing lookup IP, one should do a successful lookup by IP,
+ * and one should do a successful lookup by hostname. */
+ be1 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
+ be2 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
+ be3 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
+ be4 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
+ be5 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
+
+ bufferevent_setcb(be1, NULL, NULL, be_connect_hostname_event_cb,
+ &be1_outcome);
+ bufferevent_setcb(be2, NULL, NULL, be_connect_hostname_event_cb,
+ &be2_outcome);
+ bufferevent_setcb(be3, NULL, NULL, be_connect_hostname_event_cb,
+ &be3_outcome);
+ bufferevent_setcb(be4, NULL, NULL, be_connect_hostname_event_cb,
+ &be4_outcome);
+ bufferevent_setcb(be5, NULL, NULL, be_connect_hostname_event_cb,
+ &be5_outcome);
+
+ /* Launch an async resolve that will fail. */
+ tt_assert(!bufferevent_socket_connect_hostname(be1, dns, AF_INET,
+ "nosuchplace.example.com", listener_port));
+ /* Connect to the IP without resolving. */
+ tt_assert(!bufferevent_socket_connect_hostname(be2, dns, AF_INET,
+ "127.0.0.1", listener_port));
+ /* Launch an async resolve that will succeed. */
+ tt_assert(!bufferevent_socket_connect_hostname(be3, dns, AF_INET,
+ "nobodaddy.example.com", listener_port));
+ /* Use the blocking resolver. This one will fail if your resolver
+ * can't resolve localhost to 127.0.0.1 */
+ tt_assert(!bufferevent_socket_connect_hostname(be4, NULL, AF_INET,
+ "localhost", listener_port));
+ /* Use the blocking resolver with a nonexistent hostname. */
+ tt_assert(!bufferevent_socket_connect_hostname(be5, NULL, AF_INET,
+ "nonesuch.nowhere.example.com", 80));
+ {
+ /* The blocking resolver will use the system nameserver, which
+ * might tell us anything. (Yes, some twits even pretend that
+ * example.com is real.) Let's see what answer to expect. */
+ struct evutil_addrinfo hints, *ai = NULL;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ expect_err5 = evutil_getaddrinfo(
+ "nonesuch.nowhere.example.com", "80", &hints, &ai);
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(be1_outcome.what, ==, BEV_EVENT_ERROR);
+ tt_int_op(be1_outcome.dnserr, ==, EVUTIL_EAI_NONAME);
+ tt_int_op(be2_outcome.what, ==, BEV_EVENT_CONNECTED);
+ tt_int_op(be2_outcome.dnserr, ==, 0);
+ tt_int_op(be3_outcome.what, ==, BEV_EVENT_CONNECTED);
+ tt_int_op(be3_outcome.dnserr, ==, 0);
+ tt_int_op(be4_outcome.what, ==, BEV_EVENT_CONNECTED);
+ tt_int_op(be4_outcome.dnserr, ==, 0);
+ if (expect_err5) {
+ tt_int_op(be5_outcome.what, ==, BEV_EVENT_ERROR);
+ tt_int_op(be5_outcome.dnserr, ==, expect_err5);
+ }
+
+ tt_int_op(n_accept, ==, 3);
+ tt_int_op(n_dns, ==, 2);
+
+end:
+ if (listener)
+ evconnlistener_free(listener);
+ if (port)
+ evdns_close_server_port(port);
+ if (dns)
+ evdns_base_free(dns, 0);
+ if (be1)
+ bufferevent_free(be1);
+ if (be2)
+ bufferevent_free(be2);
+ if (be3)
+ bufferevent_free(be3);
+ if (be4)
+ bufferevent_free(be4);
+ if (be5)
+ bufferevent_free(be5);
+}
+
+
+struct gai_outcome {
+ int err;
+ struct evutil_addrinfo *ai;
+};
+
+static int n_gai_results_pending = 0;
+static struct event_base *exit_base_on_no_pending_results = NULL;
+
+static void
+gai_cb(int err, struct evutil_addrinfo *res, void *ptr)
+{
+ struct gai_outcome *go = ptr;
+ go->err = err;
+ go->ai = res;
+ if (--n_gai_results_pending <= 0 && exit_base_on_no_pending_results)
+ event_base_loopexit(exit_base_on_no_pending_results, NULL);
+ if (n_gai_results_pending < 900)
+ TT_BLATHER(("Got an answer; expecting %d more.",
+ n_gai_results_pending));
+}
+
+static void
+cancel_gai_cb(evutil_socket_t fd, short what, void *ptr)
+{
+ struct evdns_getaddrinfo_request *r = ptr;
+ evdns_getaddrinfo_cancel(r);
+}
+
+static void
+test_getaddrinfo_async(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct evutil_addrinfo hints, *a;
+ struct gai_outcome local_outcome;
+ struct gai_outcome a_out[12];
+ int i;
+ struct evdns_getaddrinfo_request *r;
+ char buf[128];
+ struct evdns_server_port *port = NULL;
+ ev_uint16_t dns_port = 0;
+ int n_dns_questions = 0;
+
+ struct evdns_base *dns_base = evdns_base_new(data->base, 0);
+ tt_assert(dns_base);
+
+ /* for localhost */
+ evdns_base_load_hosts(dns_base, NULL);
+
+ memset(a_out, 0, sizeof(a_out));
+ memset(&local_outcome, 0, sizeof(local_outcome));
+
+ n_gai_results_pending = 10000; /* don't think about exiting yet. */
+
+ /* 1. Try some cases that will never hit the asynchronous resolver. */
+ /* 1a. Simple case with a symbolic service name */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ memset(&local_outcome, 0, sizeof(local_outcome));
+ r = evdns_getaddrinfo(dns_base, "1.2.3.4", "http",
+ &hints, gai_cb, &local_outcome);
+ tt_assert(! r);
+ if (!local_outcome.err) {
+ tt_ptr_op(local_outcome.ai,!=,NULL);
+ test_ai_eq(local_outcome.ai, "1.2.3.4:80", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(local_outcome.ai);
+ local_outcome.ai = NULL;
+ } else {
+ TT_BLATHER(("Apparently we have no getservbyname."));
+ }
+
+ /* 1b. EVUTIL_AI_NUMERICHOST is set */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = EVUTIL_AI_NUMERICHOST;
+ memset(&local_outcome, 0, sizeof(local_outcome));
+ r = evdns_getaddrinfo(dns_base, "www.google.com", "80",
+ &hints, gai_cb, &local_outcome);
+ tt_int_op(r,==,0);
+ tt_int_op(local_outcome.err,==,EVUTIL_EAI_NONAME);
+ tt_ptr_op(local_outcome.ai,==,NULL);
+
+ /* 1c. We give a numeric address (ipv6) */
+ memset(&hints, 0, sizeof(hints));
+ memset(&local_outcome, 0, sizeof(local_outcome));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_protocol = IPPROTO_TCP;
+ r = evdns_getaddrinfo(dns_base, "f::f", "8008",
+ &hints, gai_cb, &local_outcome);
+ tt_assert(!r);
+ tt_int_op(local_outcome.err,==,0);
+ tt_assert(local_outcome.ai);
+ tt_ptr_op(local_outcome.ai->ai_next,==,NULL);
+ test_ai_eq(local_outcome.ai, "[f::f]:8008", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(local_outcome.ai);
+ local_outcome.ai = NULL;
+
+ /* 1d. We give a numeric address (ipv4) */
+ memset(&hints, 0, sizeof(hints));
+ memset(&local_outcome, 0, sizeof(local_outcome));
+ hints.ai_family = PF_UNSPEC;
+ r = evdns_getaddrinfo(dns_base, "5.6.7.8", NULL,
+ &hints, gai_cb, &local_outcome);
+ tt_assert(!r);
+ tt_int_op(local_outcome.err,==,0);
+ tt_assert(local_outcome.ai);
+ a = ai_find_by_protocol(local_outcome.ai, IPPROTO_TCP);
+ tt_assert(a);
+ test_ai_eq(a, "5.6.7.8", SOCK_STREAM, IPPROTO_TCP);
+ a = ai_find_by_protocol(local_outcome.ai, IPPROTO_UDP);
+ tt_assert(a);
+ test_ai_eq(a, "5.6.7.8", SOCK_DGRAM, IPPROTO_UDP);
+ evutil_freeaddrinfo(local_outcome.ai);
+ local_outcome.ai = NULL;
+
+ /* 1e. nodename is NULL (bind) */
+ memset(&hints, 0, sizeof(hints));
+ memset(&local_outcome, 0, sizeof(local_outcome));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = EVUTIL_AI_PASSIVE;
+ r = evdns_getaddrinfo(dns_base, NULL, "9090",
+ &hints, gai_cb, &local_outcome);
+ tt_assert(!r);
+ tt_int_op(local_outcome.err,==,0);
+ tt_assert(local_outcome.ai);
+ /* we should get a v4 address of 0.0.0.0... */
+ a = ai_find_by_family(local_outcome.ai, PF_INET);
+ tt_assert(a);
+ test_ai_eq(a, "0.0.0.0:9090", SOCK_DGRAM, IPPROTO_UDP);
+ /* ... and a v6 address of ::0 */
+ a = ai_find_by_family(local_outcome.ai, PF_INET6);
+ tt_assert(a);
+ test_ai_eq(a, "[::]:9090", SOCK_DGRAM, IPPROTO_UDP);
+ evutil_freeaddrinfo(local_outcome.ai);
+ local_outcome.ai = NULL;
+
+ /* 1f. nodename is NULL (connect) */
+ memset(&hints, 0, sizeof(hints));
+ memset(&local_outcome, 0, sizeof(local_outcome));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ r = evdns_getaddrinfo(dns_base, NULL, "2",
+ &hints, gai_cb, &local_outcome);
+ tt_assert(!r);
+ tt_int_op(local_outcome.err,==,0);
+ tt_assert(local_outcome.ai);
+ /* we should get a v4 address of 127.0.0.1 .... */
+ a = ai_find_by_family(local_outcome.ai, PF_INET);
+ tt_assert(a);
+ test_ai_eq(a, "127.0.0.1:2", SOCK_STREAM, IPPROTO_TCP);
+ /* ... and a v6 address of ::1 */
+ a = ai_find_by_family(local_outcome.ai, PF_INET6);
+ tt_assert(a);
+ test_ai_eq(a, "[::1]:2", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(local_outcome.ai);
+ local_outcome.ai = NULL;
+
+ /* 1g. We find localhost immediately. (pf_unspec) */
+ memset(&hints, 0, sizeof(hints));
+ memset(&local_outcome, 0, sizeof(local_outcome));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ r = evdns_getaddrinfo(dns_base, "LOCALHOST", "80",
+ &hints, gai_cb, &local_outcome);
+ tt_assert(!r);
+ tt_int_op(local_outcome.err,==,0);
+ tt_assert(local_outcome.ai);
+ /* we should get a v4 address of 127.0.0.1 .... */
+ a = ai_find_by_family(local_outcome.ai, PF_INET);
+ tt_assert(a);
+ test_ai_eq(a, "127.0.0.1:80", SOCK_STREAM, IPPROTO_TCP);
+ /* ... and a v6 address of ::1 */
+ a = ai_find_by_family(local_outcome.ai, PF_INET6);
+ tt_assert(a);
+ test_ai_eq(a, "[::1]:80", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(local_outcome.ai);
+ local_outcome.ai = NULL;
+
+ /* 1g. We find localhost immediately. (pf_inet6) */
+ memset(&hints, 0, sizeof(hints));
+ memset(&local_outcome, 0, sizeof(local_outcome));
+ hints.ai_family = PF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ r = evdns_getaddrinfo(dns_base, "LOCALHOST", "9999",
+ &hints, gai_cb, &local_outcome);
+ tt_assert(! r);
+ tt_int_op(local_outcome.err,==,0);
+ tt_assert(local_outcome.ai);
+ a = local_outcome.ai;
+ test_ai_eq(a, "[::1]:9999", SOCK_STREAM, IPPROTO_TCP);
+ tt_ptr_op(a->ai_next, ==, NULL);
+ evutil_freeaddrinfo(local_outcome.ai);
+ local_outcome.ai = NULL;
+
+ /* 2. Okay, now we can actually test the asynchronous resolver. */
+ /* Start a dummy local dns server... */
+ port = regress_get_dnsserver(data->base, &dns_port, NULL,
+ be_getaddrinfo_server_cb, &n_dns_questions);
+ tt_assert(port);
+ tt_int_op(dns_port, >=, 0);
+ /* ... and tell the evdns_base about it. */
+ evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", dns_port);
+ evdns_base_nameserver_ip_add(dns_base, buf);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = EVUTIL_AI_CANONNAME;
+ /* 0: Request for both.example.com should return both addresses. */
+ r = evdns_getaddrinfo(dns_base, "both.example.com", "8000",
+ &hints, gai_cb, &a_out[0]);
+ tt_assert(r);
+
+ /* 1: Request for v4only.example.com should return one address. */
+ r = evdns_getaddrinfo(dns_base, "v4only.example.com", "8001",
+ &hints, gai_cb, &a_out[1]);
+ tt_assert(r);
+
+ /* 2: Request for v6only.example.com should return one address. */
+ hints.ai_flags = 0;
+ r = evdns_getaddrinfo(dns_base, "v6only.example.com", "8002",
+ &hints, gai_cb, &a_out[2]);
+ tt_assert(r);
+
+ /* 3: PF_INET request for v4assert.example.com should not generate a
+ * v6 request. The server will fail the test if it does. */
+ hints.ai_family = PF_INET;
+ r = evdns_getaddrinfo(dns_base, "v4assert.example.com", "8003",
+ &hints, gai_cb, &a_out[3]);
+ tt_assert(r);
+
+ /* 4: PF_INET6 request for v6assert.example.com should not generate a
+ * v4 request. The server will fail the test if it does. */
+ hints.ai_family = PF_INET6;
+ r = evdns_getaddrinfo(dns_base, "v6assert.example.com", "8004",
+ &hints, gai_cb, &a_out[4]);
+ tt_assert(r);
+
+ /* 5: PF_INET request for nosuchplace.example.com should give NEXIST. */
+ hints.ai_family = PF_INET;
+ r = evdns_getaddrinfo(dns_base, "nosuchplace.example.com", "8005",
+ &hints, gai_cb, &a_out[5]);
+ tt_assert(r);
+
+ /* 6: PF_UNSPEC request for nosuchplace.example.com should give NEXIST.
+ */
+ hints.ai_family = PF_UNSPEC;
+ r = evdns_getaddrinfo(dns_base, "nosuchplace.example.com", "8006",
+ &hints, gai_cb, &a_out[6]);
+ tt_assert(r);
+
+ /* 7: PF_UNSPEC request for v6timeout.example.com should give an ipv4
+ * address only. */
+ hints.ai_family = PF_UNSPEC;
+ r = evdns_getaddrinfo(dns_base, "v6timeout.example.com", "8007",
+ &hints, gai_cb, &a_out[7]);
+ tt_assert(r);
+
+ /* 8: PF_UNSPEC request for v6timeout-nonexist.example.com should give
+ * a NEXIST */
+ hints.ai_family = PF_UNSPEC;
+ r = evdns_getaddrinfo(dns_base, "v6timeout-nonexist.example.com",
+ "8008", &hints, gai_cb, &a_out[8]);
+ tt_assert(r);
+
+ /* 9: AI_ADDRCONFIG should at least not crash. Can't test it more
+ * without knowing what kind of internet we have. */
+ hints.ai_flags |= EVUTIL_AI_ADDRCONFIG;
+ r = evdns_getaddrinfo(dns_base, "both.example.com",
+ "8009", &hints, gai_cb, &a_out[9]);
+ tt_assert(r);
+
+ /* 10: PF_UNSPEC for v4timeout.example.com should give an ipv6 address
+ * only. */
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = 0;
+ r = evdns_getaddrinfo(dns_base, "v4timeout.example.com", "8010",
+ &hints, gai_cb, &a_out[10]);
+ tt_assert(r);
+
+ /* 11: timeout.example.com: cancel it after 100 msec. */
+ r = evdns_getaddrinfo(dns_base, "all-timeout.example.com", "8011",
+ &hints, gai_cb, &a_out[11]);
+ tt_assert(r);
+ {
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100*1000; /* 100 msec */
+ event_base_once(data->base, -1, EV_TIMEOUT, cancel_gai_cb,
+ r, &tv);
+ }
+
+ /* XXXXX There are more tests we could do, including:
+
+ - A test to elicit NODATA.
+
+ */
+
+ n_gai_results_pending = 12;
+ exit_base_on_no_pending_results = data->base;
+
+ event_base_dispatch(data->base);
+
+ /* 0: both.example.com */
+ tt_int_op(a_out[0].err, ==, 0);
+ tt_assert(a_out[0].ai);
+ tt_assert(a_out[0].ai->ai_next);
+ tt_assert(!a_out[0].ai->ai_next->ai_next);
+ a = ai_find_by_family(a_out[0].ai, PF_INET);
+ tt_assert(a);
+ test_ai_eq(a, "80.80.32.32:8000", SOCK_STREAM, IPPROTO_TCP);
+ a = ai_find_by_family(a_out[0].ai, PF_INET6);
+ tt_assert(a);
+ test_ai_eq(a, "[80ff::bbbb]:8000", SOCK_STREAM, IPPROTO_TCP);
+ tt_assert(a_out[0].ai->ai_canonname);
+ tt_str_op(a_out[0].ai->ai_canonname, ==, "both-canonical.example.com");
+
+ /* 1: v4only.example.com */
+ tt_int_op(a_out[1].err, ==, 0);
+ tt_assert(a_out[1].ai);
+ tt_assert(! a_out[1].ai->ai_next);
+ test_ai_eq(a_out[1].ai, "18.52.86.120:8001", SOCK_STREAM, IPPROTO_TCP);
+ tt_assert(a_out[1].ai->ai_canonname == NULL);
+
+
+ /* 2: v6only.example.com */
+ tt_int_op(a_out[2].err, ==, 0);
+ tt_assert(a_out[2].ai);
+ tt_assert(! a_out[2].ai->ai_next);
+ test_ai_eq(a_out[2].ai, "[b0b::f00d]:8002", SOCK_STREAM, IPPROTO_TCP);
+
+ /* 3: v4assert.example.com */
+ tt_int_op(a_out[3].err, ==, 0);
+ tt_assert(a_out[3].ai);
+ tt_assert(! a_out[3].ai->ai_next);
+ test_ai_eq(a_out[3].ai, "18.52.86.120:8003", SOCK_STREAM, IPPROTO_TCP);
+
+ /* 4: v6assert.example.com */
+ tt_int_op(a_out[4].err, ==, 0);
+ tt_assert(a_out[4].ai);
+ tt_assert(! a_out[4].ai->ai_next);
+ test_ai_eq(a_out[4].ai, "[b0b::f00d]:8004", SOCK_STREAM, IPPROTO_TCP);
+
+ /* 5: nosuchplace.example.com (inet) */
+ tt_int_op(a_out[5].err, ==, EVUTIL_EAI_NONAME);
+ tt_assert(! a_out[5].ai);
+
+ /* 6: nosuchplace.example.com (unspec) */
+ tt_int_op(a_out[6].err, ==, EVUTIL_EAI_NONAME);
+ tt_assert(! a_out[6].ai);
+
+ /* 7: v6timeout.example.com */
+ tt_int_op(a_out[7].err, ==, 0);
+ tt_assert(a_out[7].ai);
+ tt_assert(! a_out[7].ai->ai_next);
+ test_ai_eq(a_out[7].ai, "171.205.239.1:8007", SOCK_STREAM, IPPROTO_TCP);
+
+ /* 8: v6timeout-nonexist.example.com */
+ tt_int_op(a_out[8].err, ==, EVUTIL_EAI_NONAME);
+ tt_assert(! a_out[8].ai);
+
+ /* 9: both (ADDRCONFIG) */
+ tt_int_op(a_out[9].err, ==, 0);
+ tt_assert(a_out[9].ai);
+ a = ai_find_by_family(a_out[9].ai, PF_INET);
+ if (a)
+ test_ai_eq(a, "80.80.32.32:8009", SOCK_STREAM, IPPROTO_TCP);
+ else
+ tt_assert(ai_find_by_family(a_out[9].ai, PF_INET6));
+ a = ai_find_by_family(a_out[9].ai, PF_INET6);
+ if (a)
+ test_ai_eq(a, "[80ff::bbbb]:8009", SOCK_STREAM, IPPROTO_TCP);
+ else
+ tt_assert(ai_find_by_family(a_out[9].ai, PF_INET));
+
+ /* 10: v4timeout.example.com */
+ tt_int_op(a_out[10].err, ==, 0);
+ tt_assert(a_out[10].ai);
+ tt_assert(! a_out[10].ai->ai_next);
+ test_ai_eq(a_out[10].ai, "[a0a::ff01]:8010", SOCK_STREAM, IPPROTO_TCP);
+
+ /* 11: cancelled request. */
+ tt_int_op(a_out[11].err, ==, EVUTIL_EAI_CANCEL);
+ tt_assert(a_out[11].ai == NULL);
+
+end:
+ if (local_outcome.ai)
+ evutil_freeaddrinfo(local_outcome.ai);
+ for (i=0;i<10;++i) {
+ if (a_out[i].ai)
+ evutil_freeaddrinfo(a_out[i].ai);
+ }
+ if (port)
+ evdns_close_server_port(port);
+ if (dns_base)
+ evdns_base_free(dns_base, 0);
+}
+
+struct gaic_request_status {
+ int magic;
+ struct event_base *base;
+ struct evdns_base *dns_base;
+ struct evdns_getaddrinfo_request *request;
+ struct event cancel_event;
+ int canceled;
+};
+
+#define GAIC_MAGIC 0x1234abcd
+
+static int pending = 0;
+
+static void
+gaic_cancel_request_cb(evutil_socket_t fd, short what, void *arg)
+{
+ struct gaic_request_status *status = arg;
+
+ tt_assert(status->magic == GAIC_MAGIC);
+ status->canceled = 1;
+ evdns_getaddrinfo_cancel(status->request);
+ return;
+end:
+ event_base_loopexit(status->base, NULL);
+}
+
+static void
+gaic_server_cb(struct evdns_server_request *req, void *arg)
+{
+ ev_uint32_t answer = 0x7f000001;
+ tt_assert(req->nquestions);
+ evdns_server_request_add_a_reply(req, req->questions[0]->name, 1,
+ &answer, 100);
+ evdns_server_request_respond(req, 0);
+ return;
+end:
+ evdns_server_request_respond(req, DNS_ERR_REFUSED);
+}
+
+
+static void
+gaic_getaddrinfo_cb(int result, struct evutil_addrinfo *res, void *arg)
+{
+ struct gaic_request_status *status = arg;
+ struct event_base *base = status->base;
+ tt_assert(status->magic == GAIC_MAGIC);
+
+ if (result == EVUTIL_EAI_CANCEL) {
+ tt_assert(status->canceled);
+ }
+ event_del(&status->cancel_event);
+
+ memset(status, 0xf0, sizeof(*status));
+ free(status);
+
+end:
+ if (--pending <= 0)
+ event_base_loopexit(base, NULL);
+}
+
+static void
+gaic_launch(struct event_base *base, struct evdns_base *dns_base)
+{
+ struct gaic_request_status *status = calloc(1,sizeof(*status));
+ struct timeval tv = { 0, 10000 };
+ status->magic = GAIC_MAGIC;
+ status->base = base;
+ status->dns_base = dns_base;
+ event_assign(&status->cancel_event, base, -1, 0, gaic_cancel_request_cb,
+ status);
+ status->request = evdns_getaddrinfo(dns_base,
+ "foobar.bazquux.example.com", "80", NULL, gaic_getaddrinfo_cb,
+ status);
+ event_add(&status->cancel_event, &tv);
+ ++pending;
+}
+
+#ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
+/* FIXME: We should move this to regress_main.c if anything else needs it.*/
+
+/* Trivial replacements for malloc/free/realloc to check for memory leaks.
+ * Not threadsafe. */
+static int allocated_chunks = 0;
+
+static void *
+cnt_malloc(size_t sz)
+{
+ allocated_chunks += 1;
+ return malloc(sz);
+}
+
+static void *
+cnt_realloc(void *old, size_t sz)
+{
+ if (!old)
+ allocated_chunks += 1;
+ if (!sz)
+ allocated_chunks -= 1;
+ return realloc(old, sz);
+}
+
+static void
+cnt_free(void *ptr)
+{
+ allocated_chunks -= 1;
+ free(ptr);
+}
+
+struct testleak_env_t {
+ struct event_base *base;
+ struct evdns_base *dns_base;
+ struct evdns_request *req;
+ struct generic_dns_callback_result r;
+};
+
+static void *
+testleak_setup(const struct testcase_t *testcase)
+{
+ struct testleak_env_t *env;
+
+ allocated_chunks = 0;
+ event_set_mem_functions(cnt_malloc, cnt_realloc, cnt_free);
+ event_enable_debug_mode();
+
+ /* not mm_calloc: we don't want to mess with the count. */
+ env = calloc(1, sizeof(struct testleak_env_t));
+ env->base = event_base_new();
+ env->dns_base = evdns_base_new(env->base, 0);
+ env->req = evdns_base_resolve_ipv4(
+ env->dns_base, "example.com", DNS_QUERY_NO_SEARCH,
+ generic_dns_callback, &env->r);
+ return env;
+}
+
+static int
+testleak_cleanup(const struct testcase_t *testcase, void *env_)
+{
+ int ok = 0;
+ struct testleak_env_t *env = env_;
+ tt_assert(env);
+#ifdef _EVENT_DISABLE_DEBUG_MODE
+ tt_int_op(allocated_chunks, ==, 0);
+#else
+ /* FIXME: that's `1' because of event_debug_map_HT_GROW */
+ tt_int_op(allocated_chunks, ==, 1);
+#endif
+ ok = 1;
+end:
+ if (env) {
+ if (env->dns_base)
+ evdns_base_free(env->dns_base, 0);
+ if (env->base)
+ event_base_free(env->base);
+ free(env);
+ }
+ return ok;
+}
+
+static struct testcase_setup_t testleak_funcs = {
+ testleak_setup, testleak_cleanup
+};
+
+static void
+test_dbg_leak_cancel(void *env_)
+{
+ /* cancel, loop, free/dns, free/base */
+ struct testleak_env_t *env = env_;
+ int send_err_shutdown = 1;
+ evdns_cancel_request(env->dns_base, env->req);
+ env->req = 0;
+
+ /* `req` is freed in callback, that's why one loop is required. */
+ event_base_loop(env->base, EVLOOP_NONBLOCK);
+
+ /* send_err_shutdown means nothing as soon as our request is
+ * already canceled */
+ evdns_base_free(env->dns_base, send_err_shutdown);
+ env->dns_base = 0;
+ event_base_free(env->base);
+ env->base = 0;
+}
+
+static void
+test_dbg_leak_shutdown(void *env_)
+{
+ /* free/dns, loop, free/base */
+ struct testleak_env_t *env = env_;
+ int send_err_shutdown = 1;
+
+ /* `req` is freed both with `send_err_shutdown` and without it,
+ * the only difference is `evdns_callback` call */
+ env->req = 0;
+
+ evdns_base_free(env->dns_base, send_err_shutdown);
+ env->dns_base = 0;
+
+ /* `req` is freed in callback, that's why one loop is required */
+ event_base_loop(env->base, EVLOOP_NONBLOCK);
+ event_base_free(env->base);
+ env->base = 0;
+}
+#endif
+
+static void
+test_getaddrinfo_async_cancel_stress(void *ptr)
+{
+ struct event_base *base;
+ struct evdns_base *dns_base = NULL;
+ struct evdns_server_port *server = NULL;
+ evutil_socket_t fd = -1;
+ struct sockaddr_in sin;
+ struct sockaddr_storage ss;
+ ev_socklen_t slen;
+ int i;
+
+ base = event_base_new();
+ dns_base = evdns_base_new(base, 0);
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = 0;
+ sin.sin_addr.s_addr = htonl(0x7f000001);
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ tt_abort_perror("socket");
+ }
+ evutil_make_socket_nonblocking(fd);
+ if (bind(fd, (struct sockaddr*)&sin, sizeof(sin))<0) {
+ tt_abort_perror("bind");
+ }
+ server = evdns_add_server_port_with_base(base, fd, 0, gaic_server_cb,
+ base);
+
+ memset(&ss, 0, sizeof(ss));
+ slen = sizeof(ss);
+ if (getsockname(fd, (struct sockaddr*)&ss, &slen)<0) {
+ tt_abort_perror("getsockname");
+ }
+ evdns_base_nameserver_sockaddr_add(dns_base,
+ (struct sockaddr*)&ss, slen, 0);
+
+ for (i = 0; i < 1000; ++i) {
+ gaic_launch(base, dns_base);
+ }
+
+ event_base_dispatch(base);
+
+end:
+ if (dns_base)
+ evdns_base_free(dns_base, 1);
+ if (server)
+ evdns_close_server_port(server);
+ if (fd >= 0)
+ evutil_closesocket(fd);
+}
+
+
+#define DNS_LEGACY(name, flags) \
+ { #name, run_legacy_test_fn, flags|TT_LEGACY, &legacy_setup, \
+ dns_##name }
+
+struct testcase_t dns_testcases[] = {
+ DNS_LEGACY(server, TT_FORK|TT_NEED_BASE),
+ DNS_LEGACY(gethostbyname, TT_FORK|TT_NEED_BASE|TT_NEED_DNS),
+ DNS_LEGACY(gethostbyname6, TT_FORK|TT_NEED_BASE|TT_NEED_DNS),
+ DNS_LEGACY(gethostbyaddr, TT_FORK|TT_NEED_BASE|TT_NEED_DNS),
+ { "resolve_reverse", dns_resolve_reverse, TT_FORK, NULL, NULL },
+ { "search", dns_search_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "search_cancel", dns_search_cancel_test,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "retry", dns_retry_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "reissue", dns_reissue_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "inflight", dns_inflight_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+ { "bufferevent_connect_hostname", test_bufferevent_connect_hostname,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+
+ { "getaddrinfo_async", test_getaddrinfo_async,
+ TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"" },
+ { "getaddrinfo_cancel_stress", test_getaddrinfo_async_cancel_stress,
+ TT_FORK, NULL, NULL },
+
+#ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
+ { "leak_shutdown", test_dbg_leak_shutdown, TT_FORK, &testleak_funcs, NULL },
+ { "leak_cancel", test_dbg_leak_cancel, TT_FORK, &testleak_funcs, NULL },
+#endif
+
+ END_OF_TESTCASES
+};
+
diff --git a/libevent-2.0.20-stable/test/regress_et.c b/libevent-2.0.20-stable/test/regress_et.c
new file mode 100644
index 0000000..3ddd9ed
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress_et.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "../util-internal.h"
+#include "event2/event-config.h"
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _EVENT_HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef WIN32
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include "event2/event.h"
+#include "event2/util.h"
+
+#include "regress.h"
+
+static int was_et = 0;
+
+static void
+read_cb(evutil_socket_t fd, short event, void *arg)
+{
+ char buf;
+ int len;
+
+ len = recv(fd, &buf, sizeof(buf), 0);
+
+ called++;
+ if (event & EV_ET)
+ was_et = 1;
+
+ if (!len)
+ event_del(arg);
+}
+
+#ifndef SHUT_WR
+#define SHUT_WR 1
+#endif
+
+#ifdef WIN32
+#define LOCAL_SOCKETPAIR_AF AF_INET
+#else
+#define LOCAL_SOCKETPAIR_AF AF_UNIX
+#endif
+
+static void
+test_edgetriggered(void *et)
+{
+ struct event *ev = NULL;
+ struct event_base *base = NULL;
+ const char *test = "test string";
+ evutil_socket_t pair[2] = {-1,-1};
+ int supports_et;
+
+ /* On Linux 3.2.1 (at least, as patched by Fedora and tested by Nick),
+ * doing a "recv" on an AF_UNIX socket resets the readability of the
+ * socket, even though there is no state change, so we don't actually
+ * get edge-triggered behavior. Yuck! Linux 3.1.9 didn't have this
+ * problem.
+ */
+#ifdef __linux__
+ if (evutil_ersatz_socketpair(AF_INET, SOCK_STREAM, 0, pair) == -1) {
+ tt_abort_perror("socketpair");
+ }
+#else
+ if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair) == -1) {
+ tt_abort_perror("socketpair");
+ }
+#endif
+
+ called = was_et = 0;
+
+ tt_int_op(send(pair[0], test, (int)strlen(test)+1, 0), >, 0);
+ shutdown(pair[0], SHUT_WR);
+
+ /* Initalize the event library */
+ base = event_base_new();
+
+ if (!strcmp(event_base_get_method(base), "epoll") ||
+ !strcmp(event_base_get_method(base), "epoll (with changelist)") ||
+ !strcmp(event_base_get_method(base), "kqueue"))
+ supports_et = 1;
+ else
+ supports_et = 0;
+
+ TT_BLATHER(("Checking for edge-triggered events with %s, which should %s"
+ "support edge-triggering", event_base_get_method(base),
+ supports_et?"":"not "));
+
+ /* Initalize one event */
+ ev = event_new(base, pair[1], EV_READ|EV_ET|EV_PERSIST, read_cb, &ev);
+
+ event_add(ev, NULL);
+
+ /* We're going to call the dispatch function twice. The first invocation
+ * will read a single byte from pair[1] in either case. If we're edge
+ * triggered, we'll only see the event once (since we only see transitions
+ * from no data to data), so the second invocation of event_base_loop will
+ * do nothing. If we're level triggered, the second invocation of
+ * event_base_loop will also activate the event (because there's still
+ * data to read). */
+ event_base_loop(base,EVLOOP_NONBLOCK|EVLOOP_ONCE);
+ event_base_loop(base,EVLOOP_NONBLOCK|EVLOOP_ONCE);
+
+ if (supports_et) {
+ tt_int_op(called, ==, 1);
+ tt_assert(was_et);
+ } else {
+ tt_int_op(called, ==, 2);
+ tt_assert(!was_et);
+ }
+
+ end:
+ if (ev) {
+ event_del(ev);
+ event_free(ev);
+ }
+ if (base)
+ event_base_free(base);
+ evutil_closesocket(pair[0]);
+ evutil_closesocket(pair[1]);
+}
+
+static void
+test_edgetriggered_mix_error(void *data_)
+{
+ struct basic_test_data *data = data_;
+ struct event_base *base = NULL;
+ struct event *ev_et=NULL, *ev_lt=NULL;
+
+#ifdef _EVENT_DISABLE_DEBUG_MODE
+ if (1)
+ tt_skip();
+#endif
+
+ event_enable_debug_mode();
+
+ base = event_base_new();
+
+ /* try mixing edge-triggered and level-triggered to make sure it fails*/
+ ev_et = event_new(base, data->pair[0], EV_READ|EV_ET, read_cb, ev_et);
+ tt_assert(ev_et);
+ ev_lt = event_new(base, data->pair[0], EV_READ, read_cb, ev_lt);
+ tt_assert(ev_lt);
+
+ /* Add edge-triggered, then level-triggered. Get an error. */
+ tt_int_op(0, ==, event_add(ev_et, NULL));
+ tt_int_op(-1, ==, event_add(ev_lt, NULL));
+ tt_int_op(EV_READ, ==, event_pending(ev_et, EV_READ, NULL));
+ tt_int_op(0, ==, event_pending(ev_lt, EV_READ, NULL));
+
+ tt_int_op(0, ==, event_del(ev_et));
+ /* Add level-triggered, then edge-triggered. Get an error. */
+ tt_int_op(0, ==, event_add(ev_lt, NULL));
+ tt_int_op(-1, ==, event_add(ev_et, NULL));
+ tt_int_op(EV_READ, ==, event_pending(ev_lt, EV_READ, NULL));
+ tt_int_op(0, ==, event_pending(ev_et, EV_READ, NULL));
+
+end:
+ if (ev_et)
+ event_free(ev_et);
+ if (ev_lt)
+ event_free(ev_lt);
+ if (base)
+ event_base_free(base);
+}
+
+struct testcase_t edgetriggered_testcases[] = {
+ { "et", test_edgetriggered, TT_FORK, NULL, NULL },
+ { "et_mix_error", test_edgetriggered_mix_error,
+ TT_FORK|TT_NEED_SOCKETPAIR|TT_NO_LOGS, &basic_setup, NULL },
+ END_OF_TESTCASES
+};
diff --git a/libevent-2.0.20-stable/test/regress_http.c b/libevent-2.0.20-stable/test/regress_http.c
new file mode 100644
index 0000000..cc3bf27
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress_http.c
@@ -0,0 +1,3621 @@
+/*
+ * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event2/dns.h"
+
+#include "event2/event.h"
+#include "event2/http.h"
+#include "event2/buffer.h"
+#include "event2/bufferevent.h"
+#include "event2/util.h"
+#include "log-internal.h"
+#include "util-internal.h"
+#include "http-internal.h"
+#include "regress.h"
+#include "regress_testutils.h"
+
+static struct evhttp *http;
+/* set if a test needs to call loopexit on a base */
+static struct event_base *exit_base;
+
+static char const BASIC_REQUEST_BODY[] = "This is funny";
+
+static void http_basic_cb(struct evhttp_request *req, void *arg);
+static void http_chunked_cb(struct evhttp_request *req, void *arg);
+static void http_post_cb(struct evhttp_request *req, void *arg);
+static void http_put_cb(struct evhttp_request *req, void *arg);
+static void http_delete_cb(struct evhttp_request *req, void *arg);
+static void http_delay_cb(struct evhttp_request *req, void *arg);
+static void http_large_delay_cb(struct evhttp_request *req, void *arg);
+static void http_badreq_cb(struct evhttp_request *req, void *arg);
+static void http_dispatcher_cb(struct evhttp_request *req, void *arg);
+static int
+http_bind(struct evhttp *myhttp, ev_uint16_t *pport)
+{
+ int port;
+ struct evhttp_bound_socket *sock;
+
+ sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", *pport);
+ if (sock == NULL)
+ event_errx(1, "Could not start web server");
+
+ port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock));
+ if (port < 0)
+ return -1;
+ *pport = (ev_uint16_t) port;
+
+ return 0;
+}
+
+static struct evhttp *
+http_setup(ev_uint16_t *pport, struct event_base *base)
+{
+ struct evhttp *myhttp;
+
+ /* Try a few different ports */
+ myhttp = evhttp_new(base);
+
+ if (http_bind(myhttp, pport) < 0)
+ return NULL;
+
+ /* Register a callback for certain types of requests */
+ evhttp_set_cb(myhttp, "/test", http_basic_cb, base);
+ evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, base);
+ evhttp_set_cb(myhttp, "/streamed", http_chunked_cb, base);
+ evhttp_set_cb(myhttp, "/postit", http_post_cb, base);
+ evhttp_set_cb(myhttp, "/putit", http_put_cb, base);
+ evhttp_set_cb(myhttp, "/deleteit", http_delete_cb, base);
+ evhttp_set_cb(myhttp, "/delay", http_delay_cb, base);
+ evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, base);
+ evhttp_set_cb(myhttp, "/badrequest", http_badreq_cb, base);
+ evhttp_set_cb(myhttp, "/", http_dispatcher_cb, base);
+ return (myhttp);
+}
+
+#ifndef NI_MAXSERV
+#define NI_MAXSERV 1024
+#endif
+
+static evutil_socket_t
+http_connect(const char *address, u_short port)
+{
+ /* Stupid code for connecting */
+ struct evutil_addrinfo ai, *aitop;
+ char strport[NI_MAXSERV];
+
+ struct sockaddr *sa;
+ int slen;
+ evutil_socket_t fd;
+
+ memset(&ai, 0, sizeof(ai));
+ ai.ai_family = AF_INET;
+ ai.ai_socktype = SOCK_STREAM;
+ evutil_snprintf(strport, sizeof(strport), "%d", port);
+ if (evutil_getaddrinfo(address, strport, &ai, &aitop) != 0) {
+ event_warn("getaddrinfo");
+ return (-1);
+ }
+ sa = aitop->ai_addr;
+ slen = aitop->ai_addrlen;
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd == -1)
+ event_err(1, "socket failed");
+
+ evutil_make_socket_nonblocking(fd);
+ if (connect(fd, sa, slen) == -1) {
+#ifdef WIN32
+ int tmp_err = WSAGetLastError();
+ if (tmp_err != WSAEINPROGRESS && tmp_err != WSAEINVAL &&
+ tmp_err != WSAEWOULDBLOCK)
+ event_err(1, "connect failed");
+#else
+ if (errno != EINPROGRESS)
+ event_err(1, "connect failed");
+#endif
+ }
+
+ evutil_freeaddrinfo(aitop);
+
+ return (fd);
+}
+
+/* Helper: do a strcmp on the contents of buf and the string s. */
+static int
+evbuffer_datacmp(struct evbuffer *buf, const char *s)
+{
+ size_t b_sz = evbuffer_get_length(buf);
+ size_t s_sz = strlen(s);
+ unsigned char *d;
+ int r;
+
+ if (b_sz < s_sz)
+ return -1;
+
+ d = evbuffer_pullup(buf, s_sz);
+ if ((r = memcmp(d, s, s_sz)))
+ return r;
+
+ if (b_sz > s_sz)
+ return 1;
+ else
+ return 0;
+}
+
+/* Helper: Return true iff buf contains s */
+static int
+evbuffer_contains(struct evbuffer *buf, const char *s)
+{
+ struct evbuffer_ptr ptr;
+ ptr = evbuffer_search(buf, s, strlen(s), NULL);
+ return ptr.pos != -1;
+}
+
+static void
+http_readcb(struct bufferevent *bev, void *arg)
+{
+ const char *what = BASIC_REQUEST_BODY;
+ struct event_base *my_base = arg;
+
+ if (evbuffer_contains(bufferevent_get_input(bev), what)) {
+ struct evhttp_request *req = evhttp_request_new(NULL, NULL);
+ enum message_read_status done;
+
+ /* req->kind = EVHTTP_RESPONSE; */
+ done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
+ if (done != ALL_DATA_READ)
+ goto out;
+
+ done = evhttp_parse_headers(req, bufferevent_get_input(bev));
+ if (done != ALL_DATA_READ)
+ goto out;
+
+ if (done == 1 &&
+ evhttp_find_header(evhttp_request_get_input_headers(req),
+ "Content-Type") != NULL)
+ test_ok++;
+
+ out:
+ evhttp_request_free(req);
+ bufferevent_disable(bev, EV_READ);
+ if (exit_base)
+ event_base_loopexit(exit_base, NULL);
+ else if (my_base)
+ event_base_loopexit(my_base, NULL);
+ else {
+ fprintf(stderr, "No way to exit loop!\n");
+ exit(1);
+ }
+ }
+}
+
+static void
+http_writecb(struct bufferevent *bev, void *arg)
+{
+ if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
+ /* enable reading of the reply */
+ bufferevent_enable(bev, EV_READ);
+ test_ok++;
+ }
+}
+
+static void
+http_errorcb(struct bufferevent *bev, short what, void *arg)
+{
+ test_ok = -2;
+ event_base_loopexit(arg, NULL);
+}
+
+static void
+http_basic_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *evb = evbuffer_new();
+ int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
+ event_debug(("%s: called\n", __func__));
+ evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
+
+ /* For multi-line headers test */
+ {
+ const char *multi =
+ evhttp_find_header(evhttp_request_get_input_headers(req),"X-multi");
+ if (multi) {
+ if (strcmp("END", multi + strlen(multi) - 3) == 0)
+ test_ok++;
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Last"))
+ test_ok++;
+ }
+ }
+
+ /* injecting a bad content-length */
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Negative"))
+ evhttp_add_header(evhttp_request_get_output_headers(req),
+ "Content-Length", "-100");
+
+ /* allow sending of an empty reply */
+ evhttp_send_reply(req, HTTP_OK, "Everything is fine",
+ !empty ? evb : NULL);
+
+ evbuffer_free(evb);
+}
+
+static char const* const CHUNKS[] = {
+ "This is funny",
+ "but not hilarious.",
+ "bwv 1052"
+};
+
+struct chunk_req_state {
+ struct event_base *base;
+ struct evhttp_request *req;
+ int i;
+};
+
+static void
+http_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
+{
+ struct evbuffer *evb = evbuffer_new();
+ struct chunk_req_state *state = arg;
+ struct timeval when = { 0, 0 };
+
+ evbuffer_add_printf(evb, "%s", CHUNKS[state->i]);
+ evhttp_send_reply_chunk(state->req, evb);
+ evbuffer_free(evb);
+
+ if (++state->i < (int) (sizeof(CHUNKS)/sizeof(CHUNKS[0]))) {
+ event_base_once(state->base, -1, EV_TIMEOUT,
+ http_chunked_trickle_cb, state, &when);
+ } else {
+ evhttp_send_reply_end(state->req);
+ free(state);
+ }
+}
+
+static void
+http_chunked_cb(struct evhttp_request *req, void *arg)
+{
+ struct timeval when = { 0, 0 };
+ struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));
+ event_debug(("%s: called\n", __func__));
+
+ memset(state, 0, sizeof(struct chunk_req_state));
+ state->req = req;
+ state->base = arg;
+
+ if (strcmp(evhttp_request_get_uri(req), "/streamed") == 0) {
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Length", "39");
+ }
+
+ /* generate a chunked/streamed reply */
+ evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");
+
+ /* but trickle it across several iterations to ensure we're not
+ * assuming it comes all at once */
+ event_base_once(arg, -1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
+}
+
+static void
+http_complete_write(evutil_socket_t fd, short what, void *arg)
+{
+ struct bufferevent *bev = arg;
+ const char *http_request = "host\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+ bufferevent_write(bev, http_request, strlen(http_request));
+}
+
+static void
+http_basic_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct timeval tv;
+ struct bufferevent *bev;
+ evutil_socket_t fd;
+ const char *http_request;
+ ev_uint16_t port = 0, port2 = 0;
+
+ test_ok = 0;
+
+ http = http_setup(&port, data->base);
+
+ /* bind to a second socket */
+ if (http_bind(http, &port2) == -1) {
+ fprintf(stdout, "FAILED (bind)\n");
+ exit(1);
+ }
+
+ fd = http_connect("127.0.0.1", port);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, http_readcb, http_writecb,
+ http_errorcb, data->base);
+
+ /* first half of the http request */
+ http_request =
+ "GET /test HTTP/1.1\r\n"
+ "Host: some";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+ evutil_timerclear(&tv);
+ tv.tv_usec = 10000;
+ event_base_once(data->base,
+ -1, EV_TIMEOUT, http_complete_write, bev, &tv);
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 3);
+
+ /* connect to the second port */
+ bufferevent_free(bev);
+ evutil_closesocket(fd);
+
+ fd = http_connect("127.0.0.1", port2);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, http_readcb, http_writecb,
+ http_errorcb, data->base);
+
+ http_request =
+ "GET /test HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 5);
+
+ /* Connect to the second port again. This time, send an absolute uri. */
+ bufferevent_free(bev);
+ evutil_closesocket(fd);
+
+ fd = http_connect("127.0.0.1", port2);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, http_readcb, http_writecb,
+ http_errorcb, data->base);
+
+ http_request =
+ "GET http://somehost.net/test HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 7);
+
+ evhttp_free(http);
+ end:
+ ;
+}
+
+static void
+http_delay_reply(evutil_socket_t fd, short what, void *arg)
+{
+ struct evhttp_request *req = arg;
+
+ evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
+
+ ++test_ok;
+}
+
+static void
+http_delay_cb(struct evhttp_request *req, void *arg)
+{
+ struct timeval tv;
+ evutil_timerclear(&tv);
+ tv.tv_sec = 0;
+ tv.tv_usec = 200 * 1000;
+
+ event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
+}
+
+static void
+http_badreq_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *buf = evbuffer_new();
+
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/xml; charset=UTF-8");
+ evbuffer_add_printf(buf, "Hello, %s!", "127.0.0.1");
+
+ evhttp_send_reply(req, HTTP_OK, "OK", buf);
+ evbuffer_free(buf);
+}
+
+static void
+http_badreq_errorcb(struct bufferevent *bev, short what, void *arg)
+{
+ event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
+ /* ignore */
+}
+
+#ifndef SHUT_WR
+#ifdef WIN32
+#define SHUT_WR SD_SEND
+#else
+#define SHUT_WR 1
+#endif
+#endif
+
+static void
+http_badreq_readcb(struct bufferevent *bev, void *arg)
+{
+ const char *what = "Hello, 127.0.0.1";
+ const char *bad_request = "400 Bad Request";
+
+ if (evbuffer_contains(bufferevent_get_input(bev), bad_request)) {
+ TT_FAIL(("%s:bad request detected", __func__));
+ bufferevent_disable(bev, EV_READ);
+ event_base_loopexit(arg, NULL);
+ return;
+ }
+
+ if (evbuffer_contains(bufferevent_get_input(bev), what)) {
+ struct evhttp_request *req = evhttp_request_new(NULL, NULL);
+ enum message_read_status done;
+
+ /* req->kind = EVHTTP_RESPONSE; */
+ done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
+ if (done != ALL_DATA_READ)
+ goto out;
+
+ done = evhttp_parse_headers(req, bufferevent_get_input(bev));
+ if (done != ALL_DATA_READ)
+ goto out;
+
+ if (done == 1 &&
+ evhttp_find_header(evhttp_request_get_input_headers(req),
+ "Content-Type") != NULL)
+ test_ok++;
+
+ out:
+ evhttp_request_free(req);
+ evbuffer_drain(bufferevent_get_input(bev), evbuffer_get_length(bufferevent_get_input(bev)));
+ }
+
+ shutdown(bufferevent_getfd(bev), SHUT_WR);
+}
+
+static void
+http_badreq_successcb(evutil_socket_t fd, short what, void *arg)
+{
+ event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
+ event_base_loopexit(exit_base, NULL);
+}
+
+static void
+http_bad_request_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct timeval tv;
+ struct bufferevent *bev = NULL;
+ evutil_socket_t fd;
+ const char *http_request;
+ ev_uint16_t port=0, port2=0;
+
+ test_ok = 0;
+ exit_base = data->base;
+
+ http = http_setup(&port, data->base);
+
+ /* bind to a second socket */
+ if (http_bind(http, &port2) == -1)
+ TT_DIE(("Bind socket failed"));
+
+ /* NULL request test */
+ fd = http_connect("127.0.0.1", port);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
+ http_badreq_errorcb, data->base);
+ bufferevent_enable(bev, EV_READ);
+
+ /* real NULL request */
+ http_request = "";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ shutdown(fd, SHUT_WR);
+ timerclear(&tv);
+ tv.tv_usec = 10000;
+ event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
+
+ event_base_dispatch(data->base);
+
+ bufferevent_free(bev);
+ evutil_closesocket(fd);
+
+ if (test_ok != 0) {
+ fprintf(stdout, "FAILED\n");
+ exit(1);
+ }
+
+ /* Second answer (BAD REQUEST) on connection close */
+
+ /* connect to the second port */
+ fd = http_connect("127.0.0.1", port2);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
+ http_badreq_errorcb, data->base);
+ bufferevent_enable(bev, EV_READ);
+
+ /* first half of the http request */
+ http_request =
+ "GET /badrequest HTTP/1.0\r\n" \
+ "Connection: Keep-Alive\r\n" \
+ "\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ timerclear(&tv);
+ tv.tv_usec = 10000;
+ event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(test_ok, ==, 2);
+
+end:
+ evhttp_free(http);
+ if (bev)
+ bufferevent_free(bev);
+}
+
+static struct evhttp_connection *delayed_client;
+
+static void
+http_large_delay_cb(struct evhttp_request *req, void *arg)
+{
+ struct timeval tv;
+ evutil_timerclear(&tv);
+ tv.tv_sec = 3;
+
+ event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
+ evhttp_connection_fail(delayed_client, EVCON_HTTP_EOF);
+}
+
+/*
+ * HTTP DELETE test, just piggyback on the basic test
+ */
+
+static void
+http_delete_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *evb = evbuffer_new();
+ int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
+
+ /* Expecting a DELETE request */
+ if (evhttp_request_get_command(req) != EVHTTP_REQ_DELETE) {
+ fprintf(stdout, "FAILED (delete type)\n");
+ exit(1);
+ }
+
+ event_debug(("%s: called\n", __func__));
+ evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
+
+ /* allow sending of an empty reply */
+ evhttp_send_reply(req, HTTP_OK, "Everything is fine",
+ !empty ? evb : NULL);
+
+ evbuffer_free(evb);
+}
+
+static void
+http_delete_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev;
+ evutil_socket_t fd;
+ const char *http_request;
+ ev_uint16_t port = 0;
+
+ test_ok = 0;
+
+ http = http_setup(&port, data->base);
+
+ fd = http_connect("127.0.0.1", port);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, http_readcb, http_writecb,
+ http_errorcb, data->base);
+
+ http_request =
+ "DELETE /deleteit HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ bufferevent_free(bev);
+ evutil_closesocket(fd);
+
+ evhttp_free(http);
+
+ tt_int_op(test_ok, ==, 2);
+ end:
+ ;
+}
+
+static void
+http_allowed_methods_eventcb(struct bufferevent *bev, short what, void *arg)
+{
+ char **output = arg;
+ if ((what & (BEV_EVENT_ERROR|BEV_EVENT_EOF))) {
+ char buf[4096];
+ int n;
+ n = evbuffer_remove(bufferevent_get_input(bev), buf,
+ sizeof(buf)-1);
+ if (n >= 0) {
+ buf[n]='\0';
+ if (*output)
+ free(*output);
+ *output = strdup(buf);
+ }
+ event_base_loopexit(exit_base, NULL);
+ }
+}
+
+static void
+http_allowed_methods_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev1, *bev2, *bev3;
+ evutil_socket_t fd1, fd2, fd3;
+ const char *http_request;
+ char *result1=NULL, *result2=NULL, *result3=NULL;
+ ev_uint16_t port = 0;
+
+ exit_base = data->base;
+ test_ok = 0;
+
+ http = http_setup(&port, data->base);
+
+ fd1 = http_connect("127.0.0.1", port);
+
+ /* GET is out; PATCH is in. */
+ evhttp_set_allowed_methods(http, EVHTTP_REQ_PATCH);
+
+ /* Stupid thing to send a request */
+ bev1 = bufferevent_socket_new(data->base, fd1, 0);
+ bufferevent_enable(bev1, EV_READ|EV_WRITE);
+ bufferevent_setcb(bev1, NULL, NULL,
+ http_allowed_methods_eventcb, &result1);
+
+ http_request =
+ "GET /index.html HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev1, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ fd2 = http_connect("127.0.0.1", port);
+
+ bev2 = bufferevent_socket_new(data->base, fd2, 0);
+ bufferevent_enable(bev2, EV_READ|EV_WRITE);
+ bufferevent_setcb(bev2, NULL, NULL,
+ http_allowed_methods_eventcb, &result2);
+
+ http_request =
+ "PATCH /test HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev2, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ fd3 = http_connect("127.0.0.1", port);
+
+ bev3 = bufferevent_socket_new(data->base, fd3, 0);
+ bufferevent_enable(bev3, EV_READ|EV_WRITE);
+ bufferevent_setcb(bev3, NULL, NULL,
+ http_allowed_methods_eventcb, &result3);
+
+ http_request =
+ "FLOOP /test HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev3, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ bufferevent_free(bev1);
+ bufferevent_free(bev2);
+ bufferevent_free(bev3);
+ evutil_closesocket(fd1);
+ evutil_closesocket(fd2);
+ evutil_closesocket(fd3);
+
+ evhttp_free(http);
+
+ /* Method known but disallowed */
+ tt_assert(result1);
+ tt_assert(!strncmp(result1, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
+
+ /* Method known and allowed */
+ tt_assert(result2);
+ tt_assert(!strncmp(result2, "HTTP/1.1 200 ", strlen("HTTP/1.1 200 ")));
+
+ /* Method unknown */
+ tt_assert(result3);
+ tt_assert(!strncmp(result3, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
+
+ end:
+ if (result1)
+ free(result1);
+ if (result2)
+ free(result2);
+ if (result3)
+ free(result3);
+}
+
+static void http_request_done(struct evhttp_request *, void *);
+static void http_request_empty_done(struct evhttp_request *, void *);
+
+static void
+_http_connection_test(struct basic_test_data *data, int persistent)
+{
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+
+ test_ok = 0;
+
+ http = http_setup(&port, data->base);
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ tt_assert(evhttp_connection_get_base(evcon) == data->base);
+
+ exit_base = data->base;
+ /*
+ * At this point, we want to schedule a request to the HTTP
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ fprintf(stdout, "FAILED\n");
+ exit(1);
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok);
+
+ /* try to make another request over the same connection */
+ test_ok = 0;
+
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /*
+ * if our connections are not supposed to be persistent; request
+ * a close from the server.
+ */
+ if (!persistent)
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ tt_abort_msg("couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ /* make another request: request empty reply */
+ test_ok = 0;
+
+ req = evhttp_request_new(http_request_empty_done, data->base);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+http_connection_test(void *arg)
+{
+ _http_connection_test(arg, 0);
+}
+static void
+http_persist_connection_test(void *arg)
+{
+ _http_connection_test(arg, 1);
+}
+
+static struct regress_dns_server_table search_table[] = {
+ { "localhost", "A", "127.0.0.1", 0 },
+ { NULL, NULL, NULL, 0 }
+};
+
+static void
+http_connection_async_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct evdns_base *dns_base = NULL;
+ ev_uint16_t portnum = 0;
+ char address[64];
+
+ exit_base = data->base;
+ tt_assert(regress_dnsserver(data->base, &portnum, search_table));
+
+ dns_base = evdns_base_new(data->base, 0/* init name servers */);
+ tt_assert(dns_base);
+
+ /* Add ourself as the only nameserver, and make sure we really are
+ * the only nameserver. */
+ evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
+ evdns_base_nameserver_ip_add(dns_base, address);
+
+ test_ok = 0;
+
+ http = http_setup(&port, data->base);
+
+ evcon = evhttp_connection_base_new(data->base, dns_base, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /*
+ * At this point, we want to schedule a request to the HTTP
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ fprintf(stdout, "FAILED\n");
+ exit(1);
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok);
+
+ /* try to make another request over the same connection */
+ test_ok = 0;
+
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /*
+ * if our connections are not supposed to be persistent; request
+ * a close from the server.
+ */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ tt_abort_msg("couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ /* make another request: request empty reply */
+ test_ok = 0;
+
+ req = evhttp_request_new(http_request_empty_done, data->base);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+ if (dns_base)
+ evdns_base_free(dns_base, 0);
+ regress_clean_dnsserver();
+}
+
+static void
+http_request_never_call(struct evhttp_request *req, void *arg)
+{
+ fprintf(stdout, "FAILED\n");
+ exit(1);
+}
+
+static void
+http_do_cancel(evutil_socket_t fd, short what, void *arg)
+{
+ struct evhttp_request *req = arg;
+ struct timeval tv;
+ struct event_base *base;
+ evutil_timerclear(&tv);
+ tv.tv_sec = 0;
+ tv.tv_usec = 500 * 1000;
+
+ base = evhttp_connection_get_base(evhttp_request_get_connection(req));
+ evhttp_cancel_request(req);
+
+ event_base_loopexit(base, &tv);
+
+ ++test_ok;
+}
+
+static void
+http_cancel_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct timeval tv;
+
+ exit_base = data->base;
+
+ test_ok = 0;
+
+ http = http_setup(&port, data->base);
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /*
+ * At this point, we want to schedule a request to the HTTP
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_request_never_call, NULL);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/delay"),
+ !=, -1);
+
+ evutil_timerclear(&tv);
+ tv.tv_sec = 0;
+ tv.tv_usec = 100 * 1000;
+
+ event_base_once(data->base, -1, EV_TIMEOUT, http_do_cancel, req, &tv);
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(test_ok, ==, 2);
+
+ /* try to make another request over the same connection */
+ test_ok = 0;
+
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
+ !=, -1);
+
+ event_base_dispatch(data->base);
+
+ /* make another request: request empty reply */
+ test_ok = 0;
+
+ req = evhttp_request_new(http_request_empty_done, data->base);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
+
+ /* We give ownership of the request to the connection */
+ tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
+ !=, -1);
+
+ event_base_dispatch(data->base);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+http_request_done(struct evhttp_request *req, void *arg)
+{
+ const char *what = arg;
+
+ if (evhttp_request_get_response_code(req) != HTTP_OK) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ EVUTIL_ASSERT(exit_base);
+ event_base_loopexit(exit_base, NULL);
+}
+
+static void
+http_request_expect_error(struct evhttp_request *req, void *arg)
+{
+ if (evhttp_request_get_response_code(req) == HTTP_OK) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ EVUTIL_ASSERT(arg);
+ event_base_loopexit(arg, NULL);
+}
+
+/* test virtual hosts */
+static void
+http_virtual_host_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct evhttp *second = NULL, *third = NULL;
+ evutil_socket_t fd;
+ struct bufferevent *bev;
+ const char *http_request;
+
+ exit_base = data->base;
+
+ http = http_setup(&port, data->base);
+
+ /* virtual host */
+ second = evhttp_new(NULL);
+ evhttp_set_cb(second, "/funnybunny", http_basic_cb, NULL);
+ third = evhttp_new(NULL);
+ evhttp_set_cb(third, "/blackcoffee", http_basic_cb, NULL);
+
+ if (evhttp_add_virtual_host(http, "foo.com", second) == -1) {
+ tt_abort_msg("Couldn't add vhost");
+ }
+
+ if (evhttp_add_virtual_host(http, "bar.*.foo.com", third) == -1) {
+ tt_abort_msg("Couldn't add wildcarded vhost");
+ }
+
+ /* add some aliases to the vhosts */
+ tt_assert(evhttp_add_server_alias(second, "manolito.info") == 0);
+ tt_assert(evhttp_add_server_alias(third, "bonkers.org") == 0);
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /* make a request with a different host and expect an error */
+ req = evhttp_request_new(http_request_expect_error, data->base);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+ "/funnybunny") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 1);
+
+ test_ok = 0;
+
+ /* make a request with the right host and expect a response */
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "foo.com");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+ "/funnybunny") == -1) {
+ fprintf(stdout, "FAILED\n");
+ exit(1);
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 1);
+
+ test_ok = 0;
+
+ /* make a request with the right host and expect a response */
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bar.magic.foo.com");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+ "/blackcoffee") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 1)
+
+ test_ok = 0;
+
+ /* make a request with the right host and expect a response */
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "manolito.info");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+ "/funnybunny") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 1)
+
+ test_ok = 0;
+
+ /* make a request with the right host and expect a response */
+ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+
+ /* Add the Host header. This time with the optional port. */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bonkers.org:8000");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+ "/blackcoffee") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 1)
+
+ test_ok = 0;
+
+ /* Now make a raw request with an absolute URI. */
+ fd = http_connect("127.0.0.1", port);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, http_readcb, http_writecb,
+ http_errorcb, NULL);
+
+ /* The host in the URI should override the Host: header */
+ http_request =
+ "GET http://manolito.info/funnybunny HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(test_ok, ==, 2);
+
+ bufferevent_free(bev);
+ evutil_closesocket(fd);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+
+
+/* test date header and content length */
+
+static void
+http_request_empty_done(struct evhttp_request *req, void *arg)
+{
+ if (evhttp_request_get_response_code(req) != HTTP_OK) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "Date") == NULL) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length") == NULL) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (strcmp(evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length"),
+ "0")) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ EVUTIL_ASSERT(arg);
+ event_base_loopexit(arg, NULL);
+}
+
+/*
+ * HTTP DISPATCHER test
+ */
+
+void
+http_dispatcher_cb(struct evhttp_request *req, void *arg)
+{
+
+ struct evbuffer *evb = evbuffer_new();
+ event_debug(("%s: called\n", __func__));
+ evbuffer_add_printf(evb, "DISPATCHER_TEST");
+
+ evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
+
+ evbuffer_free(evb);
+}
+
+static void
+http_dispatcher_test_done(struct evhttp_request *req, void *arg)
+{
+ struct event_base *base = arg;
+ const char *what = "DISPATCHER_TEST";
+
+ if (evhttp_request_get_response_code(req) != HTTP_OK) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
+ fprintf(stderr, "FAILED (content type)\n");
+ exit(1);
+ }
+
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
+ fprintf(stderr, "FAILED (length %lu vs %lu)\n",
+ (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
+ exit(1);
+ }
+
+ if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
+ fprintf(stderr, "FAILED (data)\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ event_base_loopexit(base, NULL);
+}
+
+static void
+http_dispatcher_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+
+ test_ok = 0;
+
+ http = http_setup(&port, data->base);
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /* also bind to local host */
+ evhttp_connection_set_local_address(evcon, "127.0.0.1");
+
+ /*
+ * At this point, we want to schedule an HTTP GET request
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_dispatcher_test_done, data->base);
+ tt_assert(req);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+
+/*
+ * HTTP POST test.
+ */
+
+void http_postrequest_done(struct evhttp_request *, void *);
+
+#define POST_DATA "Okay. Not really printf"
+
+static void
+http_post_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+
+ test_ok = 0;
+
+ http = http_setup(&port, data->base);
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /*
+ * At this point, we want to schedule an HTTP POST request
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_postrequest_done, data->base);
+ tt_assert(req);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+ evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(test_ok, ==, 1);
+
+ test_ok = 0;
+
+ req = evhttp_request_new(http_postrequest_done, data->base);
+ tt_assert(req);
+
+ /* Now try with 100-continue. */
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
+ evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(test_ok, ==, 1);
+
+ evhttp_connection_free(evcon);
+ evhttp_free(http);
+
+ end:
+ ;
+}
+
+void
+http_post_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *evb;
+ event_debug(("%s: called\n", __func__));
+
+ /* Yes, we are expecting a post request */
+ if (evhttp_request_get_command(req) != EVHTTP_REQ_POST) {
+ fprintf(stdout, "FAILED (post type)\n");
+ exit(1);
+ }
+
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(POST_DATA)) {
+ fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
+ (unsigned long) evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long) strlen(POST_DATA));
+ exit(1);
+ }
+
+ if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), POST_DATA) != 0) {
+ fprintf(stdout, "FAILED (data)\n");
+ fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
+ fprintf(stdout, "Want:%s\n", POST_DATA);
+ exit(1);
+ }
+
+ evb = evbuffer_new();
+ evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
+
+ evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
+
+ evbuffer_free(evb);
+}
+
+void
+http_postrequest_done(struct evhttp_request *req, void *arg)
+{
+ const char *what = BASIC_REQUEST_BODY;
+ struct event_base *base = arg;
+
+ if (req == NULL) {
+ fprintf(stderr, "FAILED (timeout)\n");
+ exit(1);
+ }
+
+ if (evhttp_request_get_response_code(req) != HTTP_OK) {
+
+ fprintf(stderr, "FAILED (response code)\n");
+ exit(1);
+ }
+
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
+ fprintf(stderr, "FAILED (content type)\n");
+ exit(1);
+ }
+
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
+ fprintf(stderr, "FAILED (length %lu vs %lu)\n",
+ (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
+ exit(1);
+ }
+
+ if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
+ fprintf(stderr, "FAILED (data)\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ event_base_loopexit(base, NULL);
+}
+
+/*
+ * HTTP PUT test, basically just like POST, but ...
+ */
+
+void http_putrequest_done(struct evhttp_request *, void *);
+
+#define PUT_DATA "Hi, I'm some PUT data"
+
+static void
+http_put_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+
+ test_ok = 0;
+
+ http = http_setup(&port, data->base);
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /*
+ * Schedule the HTTP PUT request
+ */
+
+ req = evhttp_request_new(http_putrequest_done, data->base);
+ tt_assert(req);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "someotherhost");
+ evbuffer_add_printf(evhttp_request_get_output_buffer(req), PUT_DATA);
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_PUT, "/putit") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ evhttp_connection_free(evcon);
+ evhttp_free(http);
+
+ tt_int_op(test_ok, ==, 1);
+ end:
+ ;
+}
+
+void
+http_put_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *evb;
+ event_debug(("%s: called\n", __func__));
+
+ /* Expecting a PUT request */
+ if (evhttp_request_get_command(req) != EVHTTP_REQ_PUT) {
+ fprintf(stdout, "FAILED (put type)\n");
+ exit(1);
+ }
+
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(PUT_DATA)) {
+ fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
+ (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(PUT_DATA));
+ exit(1);
+ }
+
+ if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), PUT_DATA) != 0) {
+ fprintf(stdout, "FAILED (data)\n");
+ fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
+ fprintf(stdout, "Want:%s\n", PUT_DATA);
+ exit(1);
+ }
+
+ evb = evbuffer_new();
+ evbuffer_add_printf(evb, "That ain't funny");
+
+ evhttp_send_reply(req, HTTP_OK, "Everything is great", evb);
+
+ evbuffer_free(evb);
+}
+
+void
+http_putrequest_done(struct evhttp_request *req, void *arg)
+{
+ struct event_base *base = arg;
+ const char *what = "That ain't funny";
+
+ if (req == NULL) {
+ fprintf(stderr, "FAILED (timeout)\n");
+ exit(1);
+ }
+
+ if (evhttp_request_get_response_code(req) != HTTP_OK) {
+
+ fprintf(stderr, "FAILED (response code)\n");
+ exit(1);
+ }
+
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
+ fprintf(stderr, "FAILED (content type)\n");
+ exit(1);
+ }
+
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
+ fprintf(stderr, "FAILED (length %lu vs %lu)\n",
+ (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
+ exit(1);
+ }
+
+
+ if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
+ fprintf(stderr, "FAILED (data)\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ event_base_loopexit(base, NULL);
+}
+
+static void
+http_failure_readcb(struct bufferevent *bev, void *arg)
+{
+ const char *what = "400 Bad Request";
+ if (evbuffer_contains(bufferevent_get_input(bev), what)) {
+ test_ok = 2;
+ bufferevent_disable(bev, EV_READ);
+ event_base_loopexit(arg, NULL);
+ }
+}
+
+/*
+ * Testing that the HTTP server can deal with a malformed request.
+ */
+static void
+http_failure_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev;
+ evutil_socket_t fd;
+ const char *http_request;
+ ev_uint16_t port = 0;
+
+ test_ok = 0;
+
+ http = http_setup(&port, data->base);
+
+ fd = http_connect("127.0.0.1", port);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, http_failure_readcb, http_writecb,
+ http_errorcb, data->base);
+
+ http_request = "illegal request\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ bufferevent_free(bev);
+ evutil_closesocket(fd);
+
+ evhttp_free(http);
+
+ tt_int_op(test_ok, ==, 2);
+ end:
+ ;
+}
+
+static void
+close_detect_done(struct evhttp_request *req, void *arg)
+{
+ struct timeval tv;
+ tt_assert(req);
+ tt_assert(evhttp_request_get_response_code(req) == HTTP_OK);
+
+ test_ok = 1;
+
+ end:
+ evutil_timerclear(&tv);
+ tv.tv_sec = 3;
+ event_base_loopexit(arg, &tv);
+}
+
+static void
+close_detect_launch(evutil_socket_t fd, short what, void *arg)
+{
+ struct evhttp_connection *evcon = arg;
+ struct event_base *base = evhttp_connection_get_base(evcon);
+ struct evhttp_request *req;
+
+ req = evhttp_request_new(close_detect_done, base);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ tt_fail_msg("Couldn't make request");
+ }
+}
+
+static void
+close_detect_cb(struct evhttp_request *req, void *arg)
+{
+ struct evhttp_connection *evcon = arg;
+ struct event_base *base = evhttp_connection_get_base(evcon);
+ struct timeval tv;
+
+ if (req != NULL && evhttp_request_get_response_code(req) != HTTP_OK) {
+ tt_abort_msg("Failed");
+ }
+
+ evutil_timerclear(&tv);
+ tv.tv_sec = 3; /* longer than the http time out */
+
+ /* launch a new request on the persistent connection in 3 seconds */
+ event_base_once(base, -1, EV_TIMEOUT, close_detect_launch, evcon, &tv);
+ end:
+ ;
+}
+
+
+static void
+_http_close_detection(struct basic_test_data *data, int with_delay)
+{
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+
+ test_ok = 0;
+ http = http_setup(&port, data->base);
+
+ /* 2 second timeout */
+ evhttp_set_timeout(http, 1);
+
+ evcon = evhttp_connection_base_new(data->base, NULL,
+ "127.0.0.1", port);
+ tt_assert(evcon);
+ delayed_client = evcon;
+
+ /*
+ * At this point, we want to schedule a request to the HTTP
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(close_detect_cb, evcon);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon,
+ req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) {
+ tt_abort_msg("couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ /* at this point, the http server should have no connection */
+ tt_assert(TAILQ_FIRST(&http->connections) == NULL);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+static void
+http_close_detection_test(void *arg)
+{
+ _http_close_detection(arg, 0);
+}
+static void
+http_close_detection_delay_test(void *arg)
+{
+ _http_close_detection(arg, 1);
+}
+
+static void
+http_highport_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ int i = -1;
+ struct evhttp *myhttp = NULL;
+
+ /* Try a few different ports */
+ for (i = 0; i < 50; ++i) {
+ myhttp = evhttp_new(data->base);
+ if (evhttp_bind_socket(myhttp, "127.0.0.1", 65535 - i) == 0) {
+ test_ok = 1;
+ evhttp_free(myhttp);
+ return;
+ }
+ evhttp_free(myhttp);
+ }
+
+ tt_fail_msg("Couldn't get a high port");
+}
+
+static void
+http_bad_header_test(void *ptr)
+{
+ struct evkeyvalq headers;
+
+ TAILQ_INIT(&headers);
+
+ tt_want(evhttp_add_header(&headers, "One", "Two") == 0);
+ tt_want(evhttp_add_header(&headers, "One", "Two\r\n Three") == 0);
+ tt_want(evhttp_add_header(&headers, "One\r", "Two") == -1);
+ tt_want(evhttp_add_header(&headers, "One\n", "Two") == -1);
+ tt_want(evhttp_add_header(&headers, "One", "Two\r") == -1);
+ tt_want(evhttp_add_header(&headers, "One", "Two\n") == -1);
+
+ evhttp_clear_headers(&headers);
+}
+
+static int validate_header(
+ const struct evkeyvalq* headers,
+ const char *key, const char *value)
+{
+ const char *real_val = evhttp_find_header(headers, key);
+ tt_assert(real_val != NULL);
+ tt_want(strcmp(real_val, value) == 0);
+end:
+ return (0);
+}
+
+static void
+http_parse_query_test(void *ptr)
+{
+ struct evkeyvalq headers;
+ int r;
+
+ TAILQ_INIT(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=test", &headers);
+ tt_want(validate_header(&headers, "q", "test") == 0);
+ tt_int_op(r, ==, 0);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers);
+ tt_want(validate_header(&headers, "q", "test") == 0);
+ tt_want(validate_header(&headers, "foo", "bar") == 0);
+ tt_int_op(r, ==, 0);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=test+foo", &headers);
+ tt_want(validate_header(&headers, "q", "test foo") == 0);
+ tt_int_op(r, ==, 0);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers);
+ tt_want(validate_header(&headers, "q", "test\nfoo") == 0);
+ tt_int_op(r, ==, 0);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers);
+ tt_want(validate_header(&headers, "q", "test\rfoo") == 0);
+ tt_int_op(r, ==, 0);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=test&&q2", &headers);
+ tt_int_op(r, ==, -1);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=test+this", &headers);
+ tt_want(validate_header(&headers, "q", "test this") == 0);
+ tt_int_op(r, ==, 0);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=test&q2=foo", &headers);
+ tt_int_op(r, ==, 0);
+ tt_want(validate_header(&headers, "q", "test") == 0);
+ tt_want(validate_header(&headers, "q2", "foo") == 0);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q&q2=foo", &headers);
+ tt_int_op(r, ==, -1);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=foo&q2", &headers);
+ tt_int_op(r, ==, -1);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=foo&q2&q3=x", &headers);
+ tt_int_op(r, ==, -1);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query("http://www.test.com/?q=&q2=&q3=", &headers);
+ tt_int_op(r, ==, 0);
+ tt_want(validate_header(&headers, "q", "") == 0);
+ tt_want(validate_header(&headers, "q2", "") == 0);
+ tt_want(validate_header(&headers, "q3", "") == 0);
+ evhttp_clear_headers(&headers);
+
+end:
+ evhttp_clear_headers(&headers);
+}
+
+static void
+http_parse_uri_test(void *ptr)
+{
+ const int nonconform = (ptr != NULL);
+ const unsigned parse_flags =
+ nonconform ? EVHTTP_URI_NONCONFORMANT : 0;
+ struct evhttp_uri *uri = NULL;
+ char url_tmp[4096];
+#define URI_PARSE(uri) \
+ evhttp_uri_parse_with_flags((uri), parse_flags)
+
+#define TT_URI(want) do { \
+ char *ret = evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)); \
+ tt_want(ret != NULL); \
+ tt_want(ret == url_tmp); \
+ if (strcmp(ret,want) != 0) \
+ TT_FAIL(("\"%s\" != \"%s\"",ret,want)); \
+ } while(0)
+
+ tt_want(evhttp_uri_join(NULL, 0, 0) == NULL);
+ tt_want(evhttp_uri_join(NULL, url_tmp, 0) == NULL);
+ tt_want(evhttp_uri_join(NULL, url_tmp, sizeof(url_tmp)) == NULL);
+
+ /* bad URIs: parsing */
+#define BAD(s) do { \
+ if (URI_PARSE(s) != NULL) \
+ TT_FAIL(("Expected error parsing \"%s\"",s)); \
+ } while(0)
+ /* Nonconformant URIs we can parse: parsing */
+#define NCF(s) do { \
+ uri = URI_PARSE(s); \
+ if (uri != NULL && !nonconform) { \
+ TT_FAIL(("Expected error parsing \"%s\"",s)); \
+ } else if (uri == NULL && nonconform) { \
+ TT_FAIL(("Couldn't parse nonconformant URI \"%s\"", \
+ s)); \
+ } \
+ if (uri) { \
+ tt_want(evhttp_uri_join(uri, url_tmp, \
+ sizeof(url_tmp))); \
+ evhttp_uri_free(uri); \
+ } \
+ } while(0)
+
+ NCF("http://www.test.com/ why hello");
+ NCF("http://www.test.com/why-hello\x01");
+ NCF("http://www.test.com/why-hello?\x01");
+ NCF("http://www.test.com/why-hello#\x01");
+ BAD("http://www.\x01.test.com/why-hello");
+ BAD("http://www.%7test.com/why-hello");
+ NCF("http://www.test.com/why-hell%7o");
+ BAD("h%3ttp://www.test.com/why-hello");
+ NCF("http://www.test.com/why-hello%7");
+ NCF("http://www.test.com/why-hell%7o");
+ NCF("http://www.test.com/foo?ba%r");
+ NCF("http://www.test.com/foo#ba%r");
+ BAD("99:99/foo");
+ BAD("http://www.test.com:999x/");
+ BAD("http://www.test.com:x/");
+ BAD("http://[hello-there]/");
+ BAD("http://[::1]]/");
+ BAD("http://[::1/");
+ BAD("http://[foob/");
+ BAD("http://[/");
+ BAD("http://[ffff:ffff:ffff:ffff:Ffff:ffff:ffff:"
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff]/");
+ BAD("http://[vX.foo]/");
+ BAD("http://[vX.foo]/");
+ BAD("http://[v.foo]/");
+ BAD("http://[v5.fo%o]/");
+ BAD("http://[v5X]/");
+ BAD("http://[v5]/");
+ BAD("http://[]/");
+ BAD("http://f\x01red@www.example.com/");
+ BAD("http://f%0red@www.example.com/");
+ BAD("http://www.example.com:9999999999999999999999999999999999999/");
+ BAD("http://www.example.com:hihi/");
+ BAD("://www.example.com/");
+
+ /* bad URIs: joining */
+ uri = evhttp_uri_new();
+ tt_want(0==evhttp_uri_set_host(uri, "www.example.com"));
+ tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) != NULL);
+ /* not enough space: */
+ tt_want(evhttp_uri_join(uri, url_tmp, 3) == NULL);
+ /* host is set, but path doesn't start with "/": */
+ tt_want(0==evhttp_uri_set_path(uri, "hi_mom"));
+ tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) == NULL);
+ tt_want(evhttp_uri_join(uri, NULL, sizeof(url_tmp))==NULL);
+ tt_want(evhttp_uri_join(uri, url_tmp, 0)==NULL);
+ evhttp_uri_free(uri);
+ uri = URI_PARSE("mailto:foo@bar");
+ tt_want(uri != NULL);
+ tt_want(evhttp_uri_get_host(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(!strcmp(evhttp_uri_get_scheme(uri), "mailto"));
+ tt_want(!strcmp(evhttp_uri_get_path(uri), "foo@bar"));
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("mailto:foo@bar");
+ evhttp_uri_free(uri);
+
+ uri = evhttp_uri_new();
+ /* Bad URI usage: setting invalid values */
+ tt_want(-1 == evhttp_uri_set_scheme(uri,""));
+ tt_want(-1 == evhttp_uri_set_scheme(uri,"33"));
+ tt_want(-1 == evhttp_uri_set_scheme(uri,"hi!"));
+ tt_want(-1 == evhttp_uri_set_userinfo(uri,"hello@"));
+ tt_want(-1 == evhttp_uri_set_host(uri,"[1.2.3.4]"));
+ tt_want(-1 == evhttp_uri_set_host(uri,"["));
+ tt_want(-1 == evhttp_uri_set_host(uri,"www.[foo].com"));
+ tt_want(-1 == evhttp_uri_set_port(uri,-3));
+ tt_want(-1 == evhttp_uri_set_path(uri,"hello?world"));
+ tt_want(-1 == evhttp_uri_set_query(uri,"hello#world"));
+ tt_want(-1 == evhttp_uri_set_fragment(uri,"hello#world"));
+ /* Valid URI usage: setting valid values */
+ tt_want(0 == evhttp_uri_set_scheme(uri,"http"));
+ tt_want(0 == evhttp_uri_set_scheme(uri,NULL));
+ tt_want(0 == evhttp_uri_set_userinfo(uri,"username:pass"));
+ tt_want(0 == evhttp_uri_set_userinfo(uri,NULL));
+ tt_want(0 == evhttp_uri_set_host(uri,"www.example.com"));
+ tt_want(0 == evhttp_uri_set_host(uri,"1.2.3.4"));
+ tt_want(0 == evhttp_uri_set_host(uri,"[1:2:3:4::]"));
+ tt_want(0 == evhttp_uri_set_host(uri,"[v7.wobblewobble]"));
+ tt_want(0 == evhttp_uri_set_host(uri,NULL));
+ tt_want(0 == evhttp_uri_set_host(uri,""));
+ tt_want(0 == evhttp_uri_set_port(uri, -1));
+ tt_want(0 == evhttp_uri_set_port(uri, 80));
+ tt_want(0 == evhttp_uri_set_port(uri, 65535));
+ tt_want(0 == evhttp_uri_set_path(uri, ""));
+ tt_want(0 == evhttp_uri_set_path(uri, "/documents/public/index.html"));
+ tt_want(0 == evhttp_uri_set_path(uri, NULL));
+ tt_want(0 == evhttp_uri_set_query(uri, "key=val&key2=val2"));
+ tt_want(0 == evhttp_uri_set_query(uri, "keyvalblarg"));
+ tt_want(0 == evhttp_uri_set_query(uri, ""));
+ tt_want(0 == evhttp_uri_set_query(uri, NULL));
+ tt_want(0 == evhttp_uri_set_fragment(uri, ""));
+ tt_want(0 == evhttp_uri_set_fragment(uri, "here?i?am"));
+ tt_want(0 == evhttp_uri_set_fragment(uri, NULL));
+ evhttp_uri_free(uri);
+
+ /* Valid parsing */
+ uri = URI_PARSE("http://www.test.com/?q=t%33est");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=t%33est") == 0);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("http://www.test.com/?q=t%33est");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("http://%77ww.test.com");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "%77ww.test.com") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("http://%77ww.test.com");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("http://www.test.com?q=test");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("http://www.test.com?q=test");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("http://www.test.com#fragment");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want_str_op(evhttp_uri_get_fragment(uri), ==, "fragment");
+ TT_URI("http://www.test.com#fragment");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("http://8000/");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "8000") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("http://8000/");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("http://:8000/");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == 8000);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("http://:8000/");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("http://www.test.com:/"); /* empty port */
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
+ tt_want_str_op(evhttp_uri_get_path(uri), ==, "/");
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("http://www.test.com/");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("http://www.test.com:"); /* empty port 2 */
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("http://www.test.com");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("ftp://www.test.com/?q=test");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("ftp://www.test.com/?q=test");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("ftp://[::1]:999/?q=test");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "[::1]") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == 999);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("ftp://[::1]:999/?q=test");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("ftp://[ff00::127.0.0.1]/?q=test");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "[ff00::127.0.0.1]") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("ftp://[ff00::127.0.0.1]/?q=test");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("ftp://[v99.not_(any:time)_soon]/?q=test");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "[v99.not_(any:time)_soon]") == 0);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("ftp://[v99.not_(any:time)_soon]/?q=test");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
+ tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user:pass") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
+ tt_want(evhttp_uri_get_port(uri) == 42);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=test&s=some+thing") == 0);
+ tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
+ TT_URI("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("scheme://user@foo.com/#fragment");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
+ tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
+ TT_URI("scheme://user@foo.com/#fragment");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("scheme://%75ser@foo.com/#frag@ment");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
+ tt_want(strcmp(evhttp_uri_get_userinfo(uri), "%75ser") == 0);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(strcmp(evhttp_uri_get_fragment(uri), "frag@ment") == 0);
+ TT_URI("scheme://%75ser@foo.com/#frag@ment");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("file:///some/path/to/the/file");
+ tt_want(strcmp(evhttp_uri_get_scheme(uri), "file") == 0);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the/file") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("file:///some/path/to/the/file");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("///some/path/to/the-file");
+ tt_want(uri != NULL);
+ tt_want(evhttp_uri_get_scheme(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the-file") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("///some/path/to/the-file");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("/s:ome/path/to/the-file?q=99#fred");
+ tt_want(uri != NULL);
+ tt_want(evhttp_uri_get_scheme(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_host(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "/s:ome/path/to/the-file") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=99") == 0);
+ tt_want(strcmp(evhttp_uri_get_fragment(uri), "fred") == 0);
+ TT_URI("/s:ome/path/to/the-file?q=99#fred");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("relative/path/with/co:lon");
+ tt_want(uri != NULL);
+ tt_want(evhttp_uri_get_scheme(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_host(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "relative/path/with/co:lon") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(evhttp_uri_get_fragment(uri) == NULL);
+ TT_URI("relative/path/with/co:lon");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("bob?q=99&q2=q?33#fr?ed");
+ tt_want(uri != NULL);
+ tt_want(evhttp_uri_get_scheme(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_host(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "bob") == 0);
+ tt_want(strcmp(evhttp_uri_get_query(uri), "q=99&q2=q?33") == 0);
+ tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
+ TT_URI("bob?q=99&q2=q?33#fr?ed");
+ evhttp_uri_free(uri);
+
+ uri = URI_PARSE("#fr?ed");
+ tt_want(uri != NULL);
+ tt_want(evhttp_uri_get_scheme(uri) == NULL);
+ tt_want(evhttp_uri_get_userinfo(uri) == NULL);
+ tt_want(evhttp_uri_get_host(uri) == NULL);
+ tt_want(evhttp_uri_get_port(uri) == -1);
+ tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
+ tt_want(evhttp_uri_get_query(uri) == NULL);
+ tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
+ TT_URI("#fr?ed");
+ evhttp_uri_free(uri);
+#undef URI_PARSE
+#undef TT_URI
+#undef BAD
+}
+
+static void
+http_uriencode_test(void *ptr)
+{
+ char *s=NULL, *s2=NULL;
+ size_t sz;
+
+#define ENC(from,want,plus) do { \
+ s = evhttp_uriencode((from), -1, (plus)); \
+ tt_assert(s); \
+ tt_str_op(s,==,(want)); \
+ sz = -1; \
+ s2 = evhttp_uridecode((s), (plus), &sz); \
+ tt_assert(s2); \
+ tt_str_op(s2,==,(from)); \
+ tt_int_op(sz,==,strlen(from)); \
+ free(s); \
+ free(s2); \
+ s = s2 = NULL; \
+ } while (0)
+
+#define DEC(from,want,dp) do { \
+ s = evhttp_uridecode((from),(dp),&sz); \
+ tt_assert(s); \
+ tt_str_op(s,==,(want)); \
+ tt_int_op(sz,==,strlen(want)); \
+ free(s); \
+ s = NULL; \
+ } while (0)
+
+#define OLD_DEC(from,want) do { \
+ s = evhttp_decode_uri((from)); \
+ tt_assert(s); \
+ tt_str_op(s,==,(want)); \
+ free(s); \
+ s = NULL; \
+ } while (0)
+
+
+ ENC("Hello", "Hello",0);
+ ENC("99", "99",0);
+ ENC("", "",0);
+ ENC(
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",0);
+ ENC(" ", "%20",0);
+ ENC(" ", "+",1);
+ ENC("\xff\xf0\xe0", "%FF%F0%E0",0);
+ ENC("\x01\x19", "%01%19",1);
+ ENC("http://www.ietf.org/rfc/rfc3986.txt",
+ "http%3A%2F%2Fwww.ietf.org%2Frfc%2Frfc3986.txt",1);
+
+ ENC("1+2=3", "1%2B2%3D3",1);
+ ENC("1+2=3", "1%2B2%3D3",0);
+
+ /* Now try encoding with internal NULs. */
+ s = evhttp_uriencode("hello\0world", 11, 0);
+ tt_assert(s);
+ tt_str_op(s,==,"hello%00world");
+ free(s);
+ s = NULL;
+
+ /* Now try out some decoding cases that we don't generate with
+ * encode_uri: Make sure that malformed stuff doesn't crash... */
+ DEC("%%xhello th+ere \xff",
+ "%%xhello th+ere \xff", 0);
+ /* Make sure plus decoding works */
+ DEC("plus+should%20work+", "plus should work ",1);
+ /* Try some lowercase hex */
+ DEC("%f0%a0%b0", "\xf0\xa0\xb0",1);
+
+ /* Try an internal NUL. */
+ sz = 0;
+ s = evhttp_uridecode("%00%00x%00%00", 1, &sz);
+ tt_int_op(sz,==,5);
+ tt_assert(!memcmp(s, "\0\0x\0\0", 5));
+ free(s);
+ s = NULL;
+
+ /* Try with size == NULL */
+ sz = 0;
+ s = evhttp_uridecode("%00%00x%00%00", 1, NULL);
+ tt_assert(!memcmp(s, "\0\0x\0\0", 5));
+ free(s);
+ s = NULL;
+
+ /* Test out the crazy old behavior of the deprecated
+ * evhttp_decode_uri */
+ OLD_DEC("http://example.com/normal+path/?key=val+with+spaces",
+ "http://example.com/normal+path/?key=val with spaces");
+
+end:
+ if (s)
+ free(s);
+ if (s2)
+ free(s2);
+#undef ENC
+#undef DEC
+#undef OLD_DEC
+}
+
+static void
+http_base_test(void *ptr)
+{
+ struct event_base *base = NULL;
+ struct bufferevent *bev;
+ evutil_socket_t fd;
+ const char *http_request;
+ ev_uint16_t port = 0;
+
+ test_ok = 0;
+ base = event_base_new();
+ http = http_setup(&port, base);
+
+ fd = http_connect("127.0.0.1", port);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(base, fd, 0);
+ bufferevent_setcb(bev, http_readcb, http_writecb,
+ http_errorcb, base);
+ bufferevent_base_set(base, bev);
+
+ http_request =
+ "GET /test HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ event_base_dispatch(base);
+
+ bufferevent_free(bev);
+ evutil_closesocket(fd);
+
+ evhttp_free(http);
+
+ tt_int_op(test_ok, ==, 2);
+
+end:
+ if (base)
+ event_base_free(base);
+}
+
+/*
+ * the server is just going to close the connection if it times out during
+ * reading the headers.
+ */
+
+static void
+http_incomplete_readcb(struct bufferevent *bev, void *arg)
+{
+ test_ok = -1;
+ event_base_loopexit(exit_base,NULL);
+}
+
+static void
+http_incomplete_errorcb(struct bufferevent *bev, short what, void *arg)
+{
+ if (what == (BEV_EVENT_READING|BEV_EVENT_EOF))
+ test_ok++;
+ else
+ test_ok = -2;
+ event_base_loopexit(exit_base,NULL);
+}
+
+static void
+http_incomplete_writecb(struct bufferevent *bev, void *arg)
+{
+ if (arg != NULL) {
+ evutil_socket_t fd = *(evutil_socket_t *)arg;
+ /* terminate the write side to simulate EOF */
+ shutdown(fd, SHUT_WR);
+ }
+ if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
+ /* enable reading of the reply */
+ bufferevent_enable(bev, EV_READ);
+ test_ok++;
+ }
+}
+
+static void
+_http_incomplete_test(struct basic_test_data *data, int use_timeout)
+{
+ struct bufferevent *bev;
+ evutil_socket_t fd;
+ const char *http_request;
+ ev_uint16_t port = 0;
+ struct timeval tv_start, tv_end;
+
+ exit_base = data->base;
+
+ test_ok = 0;
+
+ http = http_setup(&port, data->base);
+ evhttp_set_timeout(http, 1);
+
+ fd = http_connect("127.0.0.1", port);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev,
+ http_incomplete_readcb, http_incomplete_writecb,
+ http_incomplete_errorcb, use_timeout ? NULL : &fd);
+
+ http_request =
+ "GET /test HTTP/1.1\r\n"
+ "Host: somehost\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ evutil_gettimeofday(&tv_start, NULL);
+
+ event_base_dispatch(data->base);
+
+ evutil_gettimeofday(&tv_end, NULL);
+ evutil_timersub(&tv_end, &tv_start, &tv_end);
+
+ bufferevent_free(bev);
+ if (use_timeout) {
+ evutil_closesocket(fd);
+ }
+
+ evhttp_free(http);
+
+ if (use_timeout && tv_end.tv_sec >= 3) {
+ tt_abort_msg("time");
+ } else if (!use_timeout && tv_end.tv_sec >= 1) {
+ /* we should be done immediately */
+ tt_abort_msg("time");
+ }
+
+ tt_int_op(test_ok, ==, 2);
+ end:
+ ;
+}
+static void
+http_incomplete_test(void *arg)
+{
+ _http_incomplete_test(arg, 0);
+}
+static void
+http_incomplete_timeout_test(void *arg)
+{
+ _http_incomplete_test(arg, 1);
+}
+
+/*
+ * the server is going to reply with chunked data.
+ */
+
+static void
+http_chunked_readcb(struct bufferevent *bev, void *arg)
+{
+ /* nothing here */
+}
+
+static void
+http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
+{
+ if (!test_ok)
+ goto out;
+
+ test_ok = -1;
+
+ if ((what & BEV_EVENT_EOF) != 0) {
+ struct evhttp_request *req = evhttp_request_new(NULL, NULL);
+ const char *header;
+ enum message_read_status done;
+
+ /* req->kind = EVHTTP_RESPONSE; */
+ done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
+ if (done != ALL_DATA_READ)
+ goto out;
+
+ done = evhttp_parse_headers(req, bufferevent_get_input(bev));
+ if (done != ALL_DATA_READ)
+ goto out;
+
+ header = evhttp_find_header(evhttp_request_get_input_headers(req), "Transfer-Encoding");
+ if (header == NULL || strcmp(header, "chunked"))
+ goto out;
+
+ header = evhttp_find_header(evhttp_request_get_input_headers(req), "Connection");
+ if (header == NULL || strcmp(header, "close"))
+ goto out;
+
+ header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
+ if (header == NULL)
+ goto out;
+ /* 13 chars */
+ if (strcmp(header, "d")) {
+ free((void*)header);
+ goto out;
+ }
+ free((void*)header);
+
+ if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 13),
+ "This is funny", 13))
+ goto out;
+
+ evbuffer_drain(bufferevent_get_input(bev), 13 + 2);
+
+ header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
+ if (header == NULL)
+ goto out;
+ /* 18 chars */
+ if (strcmp(header, "12"))
+ goto out;
+ free((char *)header);
+
+ if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 18),
+ "but not hilarious.", 18))
+ goto out;
+
+ evbuffer_drain(bufferevent_get_input(bev), 18 + 2);
+
+ header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
+ if (header == NULL)
+ goto out;
+ /* 8 chars */
+ if (strcmp(header, "8")) {
+ free((void*)header);
+ goto out;
+ }
+ free((char *)header);
+
+ if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 8),
+ "bwv 1052.", 8))
+ goto out;
+
+ evbuffer_drain(bufferevent_get_input(bev), 8 + 2);
+
+ header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
+ if (header == NULL)
+ goto out;
+ /* 0 chars */
+ if (strcmp(header, "0")) {
+ free((void*)header);
+ goto out;
+ }
+ free((void *)header);
+
+ test_ok = 2;
+
+ evhttp_request_free(req);
+ }
+
+out:
+ event_base_loopexit(arg, NULL);
+}
+
+static void
+http_chunked_writecb(struct bufferevent *bev, void *arg)
+{
+ if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
+ /* enable reading of the reply */
+ bufferevent_enable(bev, EV_READ);
+ test_ok++;
+ }
+}
+
+static void
+http_chunked_request_done(struct evhttp_request *req, void *arg)
+{
+ if (evhttp_request_get_response_code(req) != HTTP_OK) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evhttp_find_header(evhttp_request_get_input_headers(req),
+ "Transfer-Encoding") == NULL) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 13 + 18 + 8) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (strncmp((char *)evbuffer_pullup(evhttp_request_get_input_buffer(req), 13 + 18 + 8),
+ "This is funnybut not hilarious.bwv 1052",
+ 13 + 18 + 8)) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ event_base_loopexit(arg, NULL);
+}
+
+static void
+http_chunk_out_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev;
+ evutil_socket_t fd;
+ const char *http_request;
+ ev_uint16_t port = 0;
+ struct timeval tv_start, tv_end;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ int i;
+
+ exit_base = data->base;
+ test_ok = 0;
+
+ http = http_setup(&port, data->base);
+
+ fd = http_connect("127.0.0.1", port);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev,
+ http_chunked_readcb, http_chunked_writecb,
+ http_chunked_errorcb, data->base);
+
+ http_request =
+ "GET /chunked HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ evutil_gettimeofday(&tv_start, NULL);
+
+ event_base_dispatch(data->base);
+
+ bufferevent_free(bev);
+
+ evutil_gettimeofday(&tv_end, NULL);
+ evutil_timersub(&tv_end, &tv_start, &tv_end);
+
+ tt_int_op(tv_end.tv_sec, <, 1);
+
+ tt_int_op(test_ok, ==, 2);
+
+ /* now try again with the regular connection object */
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /* make two requests to check the keepalive behavior */
+ for (i = 0; i < 2; i++) {
+ test_ok = 0;
+ req = evhttp_request_new(http_chunked_request_done,data->base);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req,
+ EVHTTP_REQ_GET, "/chunked") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_ok == 1);
+ }
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+http_stream_out_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+
+ test_ok = 0;
+ exit_base = data->base;
+
+ http = http_setup(&port, data->base);
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /*
+ * At this point, we want to schedule a request to the HTTP
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_request_done,
+ (void *)"This is funnybut not hilarious.bwv 1052");
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/streamed")
+ == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+http_stream_in_chunk(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *reply = arg;
+
+ if (evhttp_request_get_response_code(req) != HTTP_OK) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ evbuffer_add_buffer(reply, evhttp_request_get_input_buffer(req));
+}
+
+static void
+http_stream_in_done(struct evhttp_request *req, void *arg)
+{
+ if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ event_base_loopexit(exit_base, NULL);
+}
+
+/**
+ * Makes a request and reads the response in chunks.
+ */
+static void
+_http_stream_in_test(struct basic_test_data *data, char const *url,
+ size_t expected_len, char const *expected)
+{
+ struct evhttp_connection *evcon;
+ struct evbuffer *reply = evbuffer_new();
+ struct evhttp_request *req = NULL;
+ ev_uint16_t port = 0;
+
+ exit_base = data->base;
+ http = http_setup(&port, data->base);
+
+ evcon = evhttp_connection_base_new(data->base, NULL,"127.0.0.1", port);
+ tt_assert(evcon);
+
+ req = evhttp_request_new(http_stream_in_done, reply);
+ evhttp_request_set_chunked_cb(req, http_stream_in_chunk);
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, url) == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ if (evbuffer_get_length(reply) != expected_len) {
+ TT_DIE(("reply length %lu; expected %lu; FAILED (%s)\n",
+ (unsigned long)evbuffer_get_length(reply),
+ (unsigned long)expected_len,
+ (char*)evbuffer_pullup(reply, -1)));
+ }
+
+ if (memcmp(evbuffer_pullup(reply, -1), expected, expected_len) != 0) {
+ tt_abort_msg("Memory mismatch");
+ }
+
+ test_ok = 1;
+ end:
+ if (reply)
+ evbuffer_free(reply);
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+http_stream_in_test(void *arg)
+{
+ _http_stream_in_test(arg, "/chunked", 13 + 18 + 8,
+ "This is funnybut not hilarious.bwv 1052");
+
+ _http_stream_in_test(arg, "/test", strlen(BASIC_REQUEST_BODY),
+ BASIC_REQUEST_BODY);
+}
+
+static void
+http_stream_in_cancel_chunk(struct evhttp_request *req, void *arg)
+{
+ tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_OK);
+
+ end:
+ evhttp_cancel_request(req);
+ event_base_loopexit(arg, NULL);
+}
+
+static void
+http_stream_in_cancel_done(struct evhttp_request *req, void *arg)
+{
+ /* should never be called */
+ tt_fail_msg("In cancel done");
+}
+
+static void
+http_stream_in_cancel_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct evhttp_connection *evcon;
+ struct evhttp_request *req = NULL;
+ ev_uint16_t port = 0;
+
+ http = http_setup(&port, data->base);
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ req = evhttp_request_new(http_stream_in_cancel_done, data->base);
+ evhttp_request_set_chunked_cb(req, http_stream_in_cancel_chunk);
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/chunked") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ test_ok = 1;
+ end:
+ evhttp_connection_free(evcon);
+ evhttp_free(http);
+
+}
+
+static void
+http_connection_fail_done(struct evhttp_request *req, void *arg)
+{
+ /* An ENETUNREACH error results in an unrecoverable
+ * evhttp_connection error (see evhttp_connection_fail()). The
+ * connection will be reset, and the user will be notified with a NULL
+ * req parameter. */
+ tt_assert(!req);
+
+ test_ok = 1;
+
+ end:
+ event_base_loopexit(arg, NULL);
+}
+
+/* Test unrecoverable evhttp_connection errors by generating an ENETUNREACH
+ * error on connection. */
+static void
+http_connection_fail_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+
+ exit_base = data->base;
+ test_ok = 0;
+
+ /* auto detect a port */
+ http = http_setup(&port, data->base);
+ evhttp_free(http);
+ http = NULL;
+
+ /* Pick an unroutable address. This administratively scoped multicast
+ * address should do when working with TCP. */
+ evcon = evhttp_connection_base_new(data->base, NULL, "239.10.20.30", 80);
+ tt_assert(evcon);
+
+ /*
+ * At this point, we want to schedule an HTTP GET request
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_connection_fail_done, data->base);
+ tt_assert(req);
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(test_ok, ==, 1);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+}
+
+static void
+http_connection_retry_done(struct evhttp_request *req, void *arg)
+{
+ tt_assert(req);
+ tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK);
+ if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") != NULL) {
+ tt_abort_msg("(content type)\n");
+ }
+
+ tt_uint_op(evbuffer_get_length(evhttp_request_get_input_buffer(req)), ==, 0);
+
+ test_ok = 1;
+ end:
+ event_base_loopexit(arg,NULL);
+}
+
+static struct event_base *http_make_web_server_base=NULL;
+static void
+http_make_web_server(evutil_socket_t fd, short what, void *arg)
+{
+ ev_uint16_t port = *(ev_uint16_t*)arg;
+ http = http_setup(&port, http_make_web_server_base);
+}
+
+static void
+http_connection_retry_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct timeval tv, tv_start, tv_end;
+
+ exit_base = data->base;
+ test_ok = 0;
+
+ /* auto detect a port */
+ http = http_setup(&port, data->base);
+ evhttp_free(http);
+ http = NULL;
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ evhttp_connection_set_timeout(evcon, 1);
+ /* also bind to local host */
+ evhttp_connection_set_local_address(evcon, "127.0.0.1");
+
+ /*
+ * At this point, we want to schedule an HTTP GET request
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_connection_retry_done, data->base);
+ tt_assert(req);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+ "/?arg=val") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ evutil_gettimeofday(&tv_start, NULL);
+ event_base_dispatch(data->base);
+ evutil_gettimeofday(&tv_end, NULL);
+ evutil_timersub(&tv_end, &tv_start, &tv_end);
+ tt_int_op(tv_end.tv_sec, <, 1);
+
+ tt_int_op(test_ok, ==, 1);
+
+ /*
+ * now test the same but with retries
+ */
+ test_ok = 0;
+
+ evhttp_connection_set_timeout(evcon, 1);
+ evhttp_connection_set_retries(evcon, 1);
+
+ req = evhttp_request_new(http_connection_retry_done, data->base);
+ tt_assert(req);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+ "/?arg=val") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ evutil_gettimeofday(&tv_start, NULL);
+ event_base_dispatch(data->base);
+ evutil_gettimeofday(&tv_end, NULL);
+ evutil_timersub(&tv_end, &tv_start, &tv_end);
+ tt_int_op(tv_end.tv_sec, >, 1);
+ tt_int_op(tv_end.tv_sec, <, 6);
+
+ tt_assert(test_ok == 1);
+
+ /*
+ * now test the same but with retries and give it a web server
+ * at the end
+ */
+ test_ok = 0;
+
+ evhttp_connection_set_timeout(evcon, 1);
+ evhttp_connection_set_retries(evcon, 3);
+
+ req = evhttp_request_new(http_dispatcher_test_done, data->base);
+ tt_assert(req);
+
+ /* Add the information that we care about */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+ "/?arg=val") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ /* start up a web server one second after the connection tried
+ * to send a request
+ */
+ evutil_timerclear(&tv);
+ tv.tv_sec = 1;
+ http_make_web_server_base = data->base;
+ event_base_once(data->base, -1, EV_TIMEOUT, http_make_web_server, &port, &tv);
+
+ evutil_gettimeofday(&tv_start, NULL);
+ event_base_dispatch(data->base);
+ evutil_gettimeofday(&tv_end, NULL);
+
+ evutil_timersub(&tv_end, &tv_start, &tv_end);
+
+ tt_int_op(tv_end.tv_sec, >, 1);
+ tt_int_op(tv_end.tv_sec, <, 6);
+
+ tt_int_op(test_ok, ==, 1);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+http_primitives(void *ptr)
+{
+ char *escaped = NULL;
+ struct evhttp *http = NULL;
+
+ escaped = evhttp_htmlescape("<script>");
+ tt_assert(escaped);
+ tt_str_op(escaped, ==, "&lt;script&gt;");
+ free(escaped);
+
+ escaped = evhttp_htmlescape("\"\'&");
+ tt_assert(escaped);
+ tt_str_op(escaped, ==, "&quot;&#039;&amp;");
+
+ http = evhttp_new(NULL);
+ tt_assert(http);
+ tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, 0);
+ tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, -1);
+ tt_int_op(evhttp_del_cb(http, "/test"), ==, 0);
+ tt_int_op(evhttp_del_cb(http, "/test"), ==, -1);
+ tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, 0);
+
+ end:
+ if (escaped)
+ free(escaped);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+http_multi_line_header_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev= NULL;
+ evutil_socket_t fd = -1;
+ const char *http_start_request;
+ ev_uint16_t port = 0;
+
+ test_ok = 0;
+
+ http = http_setup(&port, data->base);
+
+ fd = http_connect("127.0.0.1", port);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, http_readcb, http_writecb,
+ http_errorcb, data->base);
+
+ http_start_request =
+ "GET /test HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "X-Multi: aaaaaaaa\r\n"
+ " a\r\n"
+ "\tEND\r\n"
+ "X-Last: last\r\n"
+ "\r\n";
+
+ bufferevent_write(bev, http_start_request, strlen(http_start_request));
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(test_ok, ==, 4);
+ end:
+ if (bev)
+ bufferevent_free(bev);
+ if (fd >= 0)
+ evutil_closesocket(fd);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+http_request_bad(struct evhttp_request *req, void *arg)
+{
+ if (req != NULL) {
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ event_base_loopexit(arg, NULL);
+}
+
+static void
+http_negative_content_length_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+
+ test_ok = 0;
+
+ http = http_setup(&port, data->base);
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /*
+ * At this point, we want to schedule a request to the HTTP
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_request_bad, data->base);
+
+ /* Cause the response to have a negative content-length */
+ evhttp_add_header(evhttp_request_get_output_headers(req), "X-Negative", "makeitso");
+
+ /* We give ownership of the request to the connection */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+
+ event_base_dispatch(data->base);
+
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+
+
+static void
+http_data_length_constraints_test_done(struct evhttp_request *req, void *arg)
+{
+ tt_assert(req);
+ tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_BADREQUEST);
+end:
+ event_base_loopexit(arg, NULL);
+}
+
+static void
+http_large_entity_test_done(struct evhttp_request *req, void *arg)
+{
+ tt_assert(req);
+ tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_ENTITYTOOLARGE);
+end:
+ event_base_loopexit(arg, NULL);
+}
+
+static void
+http_data_length_constraints_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ ev_uint16_t port = 0;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ char long_str[8192];
+
+ test_ok = 0;
+
+ http = http_setup(&port, data->base);
+
+ evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+ tt_assert(evcon);
+
+ /* also bind to local host */
+ evhttp_connection_set_local_address(evcon, "127.0.0.1");
+
+ /*
+ * At this point, we want to schedule an HTTP GET request
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
+ tt_assert(req);
+
+ memset(long_str, 'a', 8192);
+ long_str[8191] = '\0';
+ /* Add the information that we care about */
+ evhttp_set_max_headers_size(http, 8191);
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Longheader", long_str);
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+ event_base_dispatch(data->base);
+
+ req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
+ tt_assert(req);
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ /* GET /?arg=verylongvalue HTTP/1.1 */
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, long_str) == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+ event_base_dispatch(data->base);
+
+ evhttp_set_max_body_size(http, 8190);
+ req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+ evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+ event_base_dispatch(data->base);
+
+ req = evhttp_request_new(http_large_entity_test_done, data->base);
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
+ evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
+ tt_abort_msg("Couldn't make request");
+ }
+ event_base_dispatch(data->base);
+
+ test_ok = 1;
+ end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+ if (http)
+ evhttp_free(http);
+}
+
+/*
+ * Testing client reset of server chunked connections
+ */
+
+struct terminate_state {
+ struct event_base *base;
+ struct evhttp_request *req;
+ struct bufferevent *bev;
+ evutil_socket_t fd;
+ int gotclosecb: 1;
+};
+
+static void
+terminate_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
+{
+ struct terminate_state *state = arg;
+ struct evbuffer *evb;
+ struct timeval tv;
+
+ if (evhttp_request_get_connection(state->req) == NULL) {
+ test_ok = 1;
+ evhttp_request_free(state->req);
+ event_base_loopexit(state->base,NULL);
+ return;
+ }
+
+ evb = evbuffer_new();
+ evbuffer_add_printf(evb, "%p", evb);
+ evhttp_send_reply_chunk(state->req, evb);
+ evbuffer_free(evb);
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 3000;
+ EVUTIL_ASSERT(state);
+ EVUTIL_ASSERT(state->base);
+ event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
+}
+
+static void
+terminate_chunked_close_cb(struct evhttp_connection *evcon, void *arg)
+{
+ struct terminate_state *state = arg;
+ state->gotclosecb = 1;
+}
+
+static void
+terminate_chunked_cb(struct evhttp_request *req, void *arg)
+{
+ struct terminate_state *state = arg;
+ struct timeval tv;
+
+ /* we want to know if this connection closes on us */
+ evhttp_connection_set_closecb(
+ evhttp_request_get_connection(req),
+ terminate_chunked_close_cb, arg);
+
+ state->req = req;
+
+ evhttp_send_reply_start(req, HTTP_OK, "OK");
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 3000;
+ event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
+}
+
+static void
+terminate_chunked_client(evutil_socket_t fd, short event, void *arg)
+{
+ struct terminate_state *state = arg;
+ bufferevent_free(state->bev);
+ evutil_closesocket(state->fd);
+}
+
+static void
+terminate_readcb(struct bufferevent *bev, void *arg)
+{
+ /* just drop the data */
+ evbuffer_drain(bufferevent_get_input(bev), -1);
+}
+
+
+static void
+http_terminate_chunked_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev = NULL;
+ struct timeval tv;
+ const char *http_request;
+ ev_uint16_t port = 0;
+ evutil_socket_t fd = -1;
+ struct terminate_state terminate_state;
+
+ test_ok = 0;
+
+ http = http_setup(&port, data->base);
+ evhttp_del_cb(http, "/test");
+ tt_assert(evhttp_set_cb(http, "/test",
+ terminate_chunked_cb, &terminate_state) == 0);
+
+ fd = http_connect("127.0.0.1", port);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, terminate_readcb, http_writecb,
+ http_errorcb, data->base);
+
+ memset(&terminate_state, 0, sizeof(terminate_state));
+ terminate_state.base = data->base;
+ terminate_state.fd = fd;
+ terminate_state.bev = bev;
+ terminate_state.gotclosecb = 0;
+
+ /* first half of the http request */
+ http_request =
+ "GET /test HTTP/1.1\r\n"
+ "Host: some\r\n\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+ evutil_timerclear(&tv);
+ tv.tv_usec = 10000;
+ event_base_once(data->base, -1, EV_TIMEOUT, terminate_chunked_client, &terminate_state,
+ &tv);
+
+ event_base_dispatch(data->base);
+
+ if (terminate_state.gotclosecb == 0)
+ test_ok = 0;
+
+ end:
+ if (fd >= 0)
+ evutil_closesocket(fd);
+ if (http)
+ evhttp_free(http);
+}
+
+#define HTTP_LEGACY(name) \
+ { #name, run_legacy_test_fn, TT_ISOLATED|TT_LEGACY, &legacy_setup, \
+ http_##name##_test }
+
+#define HTTP(name) \
+ { #name, http_##name##_test, TT_ISOLATED, &basic_setup, NULL }
+
+struct testcase_t http_testcases[] = {
+ { "primitives", http_primitives, 0, NULL, NULL },
+ { "base", http_base_test, TT_FORK, NULL, NULL },
+ { "bad_headers", http_bad_header_test, 0, NULL, NULL },
+ { "parse_query", http_parse_query_test, 0, NULL, NULL },
+ { "parse_uri", http_parse_uri_test, 0, NULL, NULL },
+ { "parse_uri_nc", http_parse_uri_test, 0, &basic_setup, (void*)"nc" },
+ { "uriencode", http_uriencode_test, 0, NULL, NULL },
+ HTTP(basic),
+ HTTP(cancel),
+ HTTP(virtual_host),
+ HTTP(post),
+ HTTP(put),
+ HTTP(delete),
+ HTTP(allowed_methods),
+ HTTP(failure),
+ HTTP(connection),
+ HTTP(persist_connection),
+ HTTP(connection_async),
+ HTTP(close_detection),
+ HTTP(close_detection_delay),
+ HTTP(bad_request),
+ HTTP(incomplete),
+ HTTP(incomplete_timeout),
+ HTTP(terminate_chunked),
+
+ HTTP(highport),
+ HTTP(dispatcher),
+ HTTP(multi_line_header),
+ HTTP(negative_content_length),
+ HTTP(chunk_out),
+ HTTP(stream_out),
+
+ HTTP(stream_in),
+ HTTP(stream_in_cancel),
+
+ HTTP(connection_fail),
+ HTTP(connection_retry),
+ HTTP(data_length_constraints),
+
+ END_OF_TESTCASES
+};
+
diff --git a/libevent-2.0.20-stable/test/regress_iocp.c b/libevent-2.0.20-stable/test/regress_iocp.c
new file mode 100644
index 0000000..916d322
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress_iocp.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "event2/event.h"
+#include "event2/thread.h"
+#include "event2/buffer.h"
+#include "event2/buffer_compat.h"
+#include "event2/bufferevent.h"
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#include "regress.h"
+#include "tinytest.h"
+#include "tinytest_macros.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winsock2.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include "iocp-internal.h"
+#include "evbuffer-internal.h"
+#include "evthread-internal.h"
+
+/* FIXME remove these ones */
+#include <sys/queue.h>
+#include "event2/event_struct.h"
+#include "event-internal.h"
+
+#define MAX_CALLS 16
+
+static void *count_lock = NULL, *count_cond = NULL;
+static int count = 0;
+
+static void
+count_init(void)
+{
+ EVTHREAD_ALLOC_LOCK(count_lock, 0);
+ EVTHREAD_ALLOC_COND(count_cond);
+
+ tt_assert(count_lock);
+ tt_assert(count_cond);
+
+end:
+ ;
+}
+
+static void
+count_free(void)
+{
+ EVTHREAD_FREE_LOCK(count_lock, 0);
+ EVTHREAD_FREE_COND(count_cond);
+}
+
+static void
+count_incr(void)
+{
+ EVLOCK_LOCK(count_lock, 0);
+ count++;
+ EVTHREAD_COND_BROADCAST(count_cond);
+ EVLOCK_UNLOCK(count_lock, 0);
+}
+
+static int
+count_wait_for(int i, int ms)
+{
+ struct timeval tv;
+ DWORD elapsed;
+ int rv = -1;
+
+ EVLOCK_LOCK(count_lock, 0);
+ while (ms > 0 && count != i) {
+ tv.tv_sec = 0;
+ tv.tv_usec = ms * 1000;
+ elapsed = GetTickCount();
+ EVTHREAD_COND_WAIT_TIMED(count_cond, count_lock, &tv);
+ elapsed = GetTickCount() - elapsed;
+ ms -= elapsed;
+ }
+ if (count == i)
+ rv = 0;
+ EVLOCK_UNLOCK(count_lock, 0);
+
+ return rv;
+}
+
+struct dummy_overlapped {
+ struct event_overlapped eo;
+ void *lock;
+ int call_count;
+ uintptr_t keys[MAX_CALLS];
+ ev_ssize_t sizes[MAX_CALLS];
+};
+
+static void
+dummy_cb(struct event_overlapped *o, uintptr_t key, ev_ssize_t n, int ok)
+{
+ struct dummy_overlapped *d_o =
+ EVUTIL_UPCAST(o, struct dummy_overlapped, eo);
+
+ EVLOCK_LOCK(d_o->lock, 0);
+ if (d_o->call_count < MAX_CALLS) {
+ d_o->keys[d_o->call_count] = key;
+ d_o->sizes[d_o->call_count] = n;
+ }
+ d_o->call_count++;
+ EVLOCK_UNLOCK(d_o->lock, 0);
+
+ count_incr();
+}
+
+static int
+pair_is_in(struct dummy_overlapped *o, uintptr_t key, ev_ssize_t n)
+{
+ int i;
+ int result = 0;
+ EVLOCK_LOCK(o->lock, 0);
+ for (i=0; i < o->call_count; ++i) {
+ if (o->keys[i] == key && o->sizes[i] == n) {
+ result = 1;
+ break;
+ }
+ }
+ EVLOCK_UNLOCK(o->lock, 0);
+ return result;
+}
+
+static void
+test_iocp_port(void *ptr)
+{
+ struct event_iocp_port *port = NULL;
+ struct dummy_overlapped o1, o2;
+
+ memset(&o1, 0, sizeof(o1));
+ memset(&o2, 0, sizeof(o2));
+
+ count_init();
+ EVTHREAD_ALLOC_LOCK(o1.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ EVTHREAD_ALLOC_LOCK(o2.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+
+ tt_assert(o1.lock);
+ tt_assert(o2.lock);
+
+ event_overlapped_init(&o1.eo, dummy_cb);
+ event_overlapped_init(&o2.eo, dummy_cb);
+
+ port = event_iocp_port_launch(0);
+ tt_assert(port);
+
+ tt_assert(!event_iocp_activate_overlapped(port, &o1.eo, 10, 100));
+ tt_assert(!event_iocp_activate_overlapped(port, &o2.eo, 20, 200));
+
+ tt_assert(!event_iocp_activate_overlapped(port, &o1.eo, 11, 101));
+ tt_assert(!event_iocp_activate_overlapped(port, &o2.eo, 21, 201));
+
+ tt_assert(!event_iocp_activate_overlapped(port, &o1.eo, 12, 102));
+ tt_assert(!event_iocp_activate_overlapped(port, &o2.eo, 22, 202));
+
+ tt_assert(!event_iocp_activate_overlapped(port, &o1.eo, 13, 103));
+ tt_assert(!event_iocp_activate_overlapped(port, &o2.eo, 23, 203));
+
+ tt_int_op(count_wait_for(8, 2000), ==, 0);
+
+ tt_want(!event_iocp_shutdown(port, 2000));
+
+ tt_int_op(o1.call_count, ==, 4);
+ tt_int_op(o2.call_count, ==, 4);
+
+ tt_want(pair_is_in(&o1, 10, 100));
+ tt_want(pair_is_in(&o1, 11, 101));
+ tt_want(pair_is_in(&o1, 12, 102));
+ tt_want(pair_is_in(&o1, 13, 103));
+
+ tt_want(pair_is_in(&o2, 20, 200));
+ tt_want(pair_is_in(&o2, 21, 201));
+ tt_want(pair_is_in(&o2, 22, 202));
+ tt_want(pair_is_in(&o2, 23, 203));
+
+end:
+ EVTHREAD_FREE_LOCK(o1.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ EVTHREAD_FREE_LOCK(o2.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ count_free();
+}
+
+static struct evbuffer *rbuf = NULL, *wbuf = NULL;
+
+static void
+read_complete(struct event_overlapped *eo, uintptr_t key,
+ ev_ssize_t nbytes, int ok)
+{
+ tt_assert(ok);
+ evbuffer_commit_read(rbuf, nbytes);
+ count_incr();
+end:
+ ;
+}
+
+static void
+write_complete(struct event_overlapped *eo, uintptr_t key,
+ ev_ssize_t nbytes, int ok)
+{
+ tt_assert(ok);
+ evbuffer_commit_write(wbuf, nbytes);
+ count_incr();
+end:
+ ;
+}
+
+static void
+test_iocp_evbuffer(void *ptr)
+{
+ struct event_overlapped rol, wol;
+ struct basic_test_data *data = ptr;
+ struct event_iocp_port *port = NULL;
+ struct evbuffer *buf=NULL;
+ struct evbuffer_chain *chain;
+ char junk[1024];
+ int i;
+
+ count_init();
+ event_overlapped_init(&rol, read_complete);
+ event_overlapped_init(&wol, write_complete);
+
+ for (i = 0; i < (int)sizeof(junk); ++i)
+ junk[i] = (char)(i);
+
+ rbuf = evbuffer_overlapped_new(data->pair[0]);
+ wbuf = evbuffer_overlapped_new(data->pair[1]);
+ evbuffer_enable_locking(rbuf, NULL);
+ evbuffer_enable_locking(wbuf, NULL);
+
+ port = event_iocp_port_launch(0);
+ tt_assert(port);
+ tt_assert(rbuf);
+ tt_assert(wbuf);
+
+ tt_assert(!event_iocp_port_associate(port, data->pair[0], 100));
+ tt_assert(!event_iocp_port_associate(port, data->pair[1], 100));
+
+ for (i=0;i<10;++i)
+ evbuffer_add(wbuf, junk, sizeof(junk));
+
+ buf = evbuffer_new();
+ tt_assert(buf != NULL);
+ evbuffer_add(rbuf, junk, sizeof(junk));
+ tt_assert(!evbuffer_launch_read(rbuf, 2048, &rol));
+ evbuffer_add_buffer(buf, rbuf);
+ tt_int_op(evbuffer_get_length(buf), ==, sizeof(junk));
+ for (chain = buf->first; chain; chain = chain->next)
+ tt_int_op(chain->flags & EVBUFFER_MEM_PINNED_ANY, ==, 0);
+ tt_assert(!evbuffer_get_length(rbuf));
+ tt_assert(!evbuffer_launch_write(wbuf, 512, &wol));
+
+ tt_int_op(count_wait_for(2, 2000), ==, 0);
+
+ tt_int_op(evbuffer_get_length(rbuf),==,512);
+
+ /* FIXME Actually test some stuff here. */
+
+ tt_want(!event_iocp_shutdown(port, 2000));
+end:
+ count_free();
+ evbuffer_free(rbuf);
+ evbuffer_free(wbuf);
+ if (buf) evbuffer_free(buf);
+}
+
+static int got_readcb = 0;
+
+static void
+async_readcb(struct bufferevent *bev, void *arg)
+{
+ /* Disabling read should cause the loop to quit */
+ bufferevent_disable(bev, EV_READ);
+ got_readcb++;
+}
+
+static void
+test_iocp_bufferevent_async(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event_iocp_port *port = NULL;
+ struct bufferevent *bea1=NULL, *bea2=NULL;
+ char buf[128];
+ size_t n;
+
+ event_base_start_iocp(data->base, 0);
+ port = event_base_get_iocp(data->base);
+ tt_assert(port);
+
+ bea1 = bufferevent_async_new(data->base, data->pair[0],
+ BEV_OPT_DEFER_CALLBACKS);
+ bea2 = bufferevent_async_new(data->base, data->pair[1],
+ BEV_OPT_DEFER_CALLBACKS);
+ tt_assert(bea1);
+ tt_assert(bea2);
+
+ bufferevent_setcb(bea2, async_readcb, NULL, NULL, NULL);
+ bufferevent_enable(bea1, EV_WRITE);
+ bufferevent_enable(bea2, EV_READ);
+
+ bufferevent_write(bea1, "Hello world", strlen("Hello world")+1);
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(got_readcb, ==, 1);
+ n = bufferevent_read(bea2, buf, sizeof(buf)-1);
+ buf[n]='\0';
+ tt_str_op(buf, ==, "Hello world");
+
+end:
+ bufferevent_free(bea1);
+ bufferevent_free(bea2);
+}
+
+
+struct testcase_t iocp_testcases[] = {
+ { "port", test_iocp_port, TT_FORK|TT_NEED_THREADS, &basic_setup, NULL },
+ { "evbuffer", test_iocp_evbuffer,
+ TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_THREADS,
+ &basic_setup, NULL },
+ { "bufferevent_async", test_iocp_bufferevent_async,
+ TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_THREADS|TT_NEED_BASE,
+ &basic_setup, NULL },
+ END_OF_TESTCASES
+};
diff --git a/libevent-2.0.20-stable/test/regress_listener.c b/libevent-2.0.20-stable/test/regress_listener.c
new file mode 100644
index 0000000..8938546
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress_listener.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#include <sys/types.h>
+
+#ifndef WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+# ifdef _XOPEN_SOURCE_EXTENDED
+# include <arpa/inet.h>
+# endif
+#include <unistd.h>
+#endif
+
+#include <string.h>
+
+#include "event2/listener.h"
+#include "event2/event.h"
+#include "event2/util.h"
+
+#include "regress.h"
+#include "tinytest.h"
+#include "tinytest_macros.h"
+#include "util-internal.h"
+
+static void
+acceptcb(struct evconnlistener *listener, evutil_socket_t fd,
+ struct sockaddr *addr, int socklen, void *arg)
+{
+ int *ptr = arg;
+ --*ptr;
+ TT_BLATHER(("Got one for %p", ptr));
+ evutil_closesocket(fd);
+
+ if (! *ptr)
+ evconnlistener_disable(listener);
+}
+
+static void
+regress_pick_a_port(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evconnlistener *listener1 = NULL, *listener2 = NULL;
+ struct sockaddr_in sin;
+ int count1 = 2, count2 = 1;
+ struct sockaddr_storage ss1, ss2;
+ struct sockaddr_in *sin1, *sin2;
+ ev_socklen_t slen1 = sizeof(ss1), slen2 = sizeof(ss2);
+ unsigned int flags =
+ LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC;
+
+ evutil_socket_t fd1 = -1, fd2 = -1, fd3 = -1;
+
+ if (data->setup_data && strstr((char*)data->setup_data, "ts")) {
+ flags |= LEV_OPT_THREADSAFE;
+ }
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
+ sin.sin_port = 0; /* "You pick!" */
+
+ listener1 = evconnlistener_new_bind(base, acceptcb, &count1,
+ flags, -1, (struct sockaddr *)&sin, sizeof(sin));
+ tt_assert(listener1);
+ listener2 = evconnlistener_new_bind(base, acceptcb, &count2,
+ flags, -1, (struct sockaddr *)&sin, sizeof(sin));
+ tt_assert(listener2);
+
+ tt_int_op(evconnlistener_get_fd(listener1), >=, 0);
+ tt_int_op(evconnlistener_get_fd(listener2), >=, 0);
+ tt_assert(getsockname(evconnlistener_get_fd(listener1),
+ (struct sockaddr*)&ss1, &slen1) == 0);
+ tt_assert(getsockname(evconnlistener_get_fd(listener2),
+ (struct sockaddr*)&ss2, &slen2) == 0);
+ tt_int_op(ss1.ss_family, ==, AF_INET);
+ tt_int_op(ss2.ss_family, ==, AF_INET);
+
+ sin1 = (struct sockaddr_in*)&ss1;
+ sin2 = (struct sockaddr_in*)&ss2;
+ tt_int_op(ntohl(sin1->sin_addr.s_addr), ==, 0x7f000001);
+ tt_int_op(ntohl(sin2->sin_addr.s_addr), ==, 0x7f000001);
+ tt_int_op(sin1->sin_port, !=, sin2->sin_port);
+
+ tt_ptr_op(evconnlistener_get_base(listener1), ==, base);
+ tt_ptr_op(evconnlistener_get_base(listener2), ==, base);
+
+ fd1 = fd2 = fd3 = -1;
+ evutil_socket_connect(&fd1, (struct sockaddr*)&ss1, slen1);
+ evutil_socket_connect(&fd2, (struct sockaddr*)&ss1, slen1);
+ evutil_socket_connect(&fd3, (struct sockaddr*)&ss2, slen2);
+
+#ifdef WIN32
+ Sleep(100); /* XXXX this is a stupid stopgap. */
+#endif
+ event_base_dispatch(base);
+
+ tt_int_op(count1, ==, 0);
+ tt_int_op(count2, ==, 0);
+
+end:
+ if (fd1>=0)
+ EVUTIL_CLOSESOCKET(fd1);
+ if (fd2>=0)
+ EVUTIL_CLOSESOCKET(fd2);
+ if (fd3>=0)
+ EVUTIL_CLOSESOCKET(fd3);
+ if (listener1)
+ evconnlistener_free(listener1);
+ if (listener2)
+ evconnlistener_free(listener2);
+}
+
+static void
+errorcb(struct evconnlistener *lis, void *data_)
+{
+ int *data = data_;
+ *data = 1000;
+ evconnlistener_disable(lis);
+}
+
+static void
+regress_listener_error(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evconnlistener *listener = NULL;
+ int count = 1;
+ unsigned int flags = LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE;
+
+ if (data->setup_data && strstr((char*)data->setup_data, "ts")) {
+ flags |= LEV_OPT_THREADSAFE;
+ }
+
+ /* send, so that pair[0] will look 'readable'*/
+ tt_int_op(send(data->pair[1], "hello", 5, 0), >, 0);
+
+ /* Start a listener with a bogus socket. */
+ listener = evconnlistener_new(base, acceptcb, &count,
+ flags, 0,
+ data->pair[0]);
+ tt_assert(listener);
+
+ evconnlistener_set_error_cb(listener, errorcb);
+
+ tt_assert(listener);
+
+ event_base_dispatch(base);
+ tt_int_op(count,==,1000); /* set by error cb */
+
+end:
+ if (listener)
+ evconnlistener_free(listener);
+}
+
+struct testcase_t listener_testcases[] = {
+
+ { "randport", regress_pick_a_port, TT_FORK|TT_NEED_BASE,
+ &basic_setup, NULL},
+
+ { "randport_ts", regress_pick_a_port, TT_FORK|TT_NEED_BASE,
+ &basic_setup, (char*)"ts"},
+
+ { "error", regress_listener_error,
+ TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR,
+ &basic_setup, NULL},
+
+ { "error_ts", regress_listener_error,
+ TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR,
+ &basic_setup, (char*)"ts"},
+
+ END_OF_TESTCASES,
+};
+
+struct testcase_t listener_iocp_testcases[] = {
+ { "randport", regress_pick_a_port,
+ TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP,
+ &basic_setup, NULL},
+
+ { "error", regress_listener_error,
+ TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR|TT_ENABLE_IOCP,
+ &basic_setup, NULL},
+
+ END_OF_TESTCASES,
+};
diff --git a/libevent-2.0.20-stable/test/regress_main.c b/libevent-2.0.20-stable/test/regress_main.c
new file mode 100644
index 0000000..e32afff
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress_main.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+#if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
+#if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \
+ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
+#define FORK_BREAKS_GCOV
+#include <vproc.h>
+#endif
+#endif
+
+#include "event2/event-config.h"
+
+#ifdef _EVENT___func__
+#define __func__ _EVENT___func__
+#endif
+
+#if 0
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#include <signal.h>
+#include <errno.h>
+#endif
+
+#include <sys/types.h>
+#ifdef _EVENT_HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifndef WIN32
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "event2/util.h"
+#include "event2/event.h"
+#include "event2/event_compat.h"
+#include "event2/dns.h"
+#include "event2/dns_compat.h"
+#include "event2/thread.h"
+
+#include "event2/event-config.h"
+#include "regress.h"
+#include "tinytest.h"
+#include "tinytest_macros.h"
+#include "../iocp-internal.h"
+#include "../event-internal.h"
+
+long
+timeval_msec_diff(const struct timeval *start, const struct timeval *end)
+{
+ long ms = end->tv_sec - start->tv_sec;
+ ms *= 1000;
+ ms += ((end->tv_usec - start->tv_usec)+500) / 1000;
+ return ms;
+
+}
+
+/* ============================================================ */
+/* Code to wrap up old legacy test cases that used setup() and cleanup().
+ *
+ * Not all of the tests designated "legacy" are ones that used setup() and
+ * cleanup(), of course. A test is legacy it it uses setup()/cleanup(), OR
+ * if it wants to find its event base/socketpair in global variables (ugh),
+ * OR if it wants to communicate success/failure through test_ok.
+ */
+
+/* This is set to true if we're inside a legacy test wrapper. It lets the
+ setup() and cleanup() functions in regress.c know they're not needed.
+ */
+int in_legacy_test_wrapper = 0;
+
+static void dnslogcb(int w, const char *m)
+{
+ TT_BLATHER(("%s", m));
+}
+
+/* creates a temporary file with the data in it */
+int
+regress_make_tmpfile(const void *data, size_t datalen)
+{
+#ifndef WIN32
+ char tmpfilename[32];
+ int fd;
+ strcpy(tmpfilename, "/tmp/eventtmp.XXXXXX");
+#ifdef _EVENT_HAVE_UMASK
+ umask(0077);
+#endif
+ fd = mkstemp(tmpfilename);
+ if (fd == -1)
+ return (-1);
+ if (write(fd, data, datalen) != (int)datalen) {
+ close(fd);
+ return (-1);
+ }
+ lseek(fd, 0, SEEK_SET);
+ /* remove it from the file system */
+ unlink(tmpfilename);
+ return (fd);
+#else
+ /* XXXX actually delete the file later */
+ char tmpfilepath[MAX_PATH];
+ char tmpfilename[MAX_PATH];
+ DWORD r, written;
+ int tries = 16;
+ HANDLE h;
+ r = GetTempPathA(MAX_PATH, tmpfilepath);
+ if (r > MAX_PATH || r == 0)
+ return (-1);
+ for (; tries > 0; --tries) {
+ r = GetTempFileNameA(tmpfilepath, "LIBEVENT", 0, tmpfilename);
+ if (r == 0)
+ return (-1);
+ h = CreateFileA(tmpfilename, GENERIC_READ|GENERIC_WRITE,
+ 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (h != INVALID_HANDLE_VALUE)
+ break;
+ }
+ if (tries == 0)
+ return (-1);
+ written = 0;
+ WriteFile(h, data, (DWORD)datalen, &written, NULL);
+ /* Closing the fd returned by this function will indeed close h. */
+ return _open_osfhandle((intptr_t)h,_O_RDONLY);
+#endif
+}
+
+#ifndef _WIN32
+pid_t
+regress_fork(void)
+{
+ pid_t pid = fork();
+#ifdef FORK_BREAKS_GCOV
+ vproc_transaction_begin(0);
+#endif
+ return pid;
+}
+#endif
+
+static void
+ignore_log_cb(int s, const char *msg)
+{
+}
+
+static void *
+basic_test_setup(const struct testcase_t *testcase)
+{
+ struct event_base *base = NULL;
+ evutil_socket_t spair[2] = { -1, -1 };
+ struct basic_test_data *data = NULL;
+
+#ifndef WIN32
+ if (testcase->flags & TT_ENABLE_IOCP_FLAG)
+ return (void*)TT_SKIP;
+#endif
+
+ if (testcase->flags & TT_NEED_THREADS) {
+ if (!(testcase->flags & TT_FORK))
+ return NULL;
+#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
+ if (evthread_use_pthreads())
+ exit(1);
+#elif defined(EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED)
+ if (evthread_use_windows_threads())
+ exit(1);
+#else
+ return (void*)TT_SKIP;
+#endif
+ }
+
+ if (testcase->flags & TT_NEED_SOCKETPAIR) {
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, spair) == -1) {
+ fprintf(stderr, "%s: socketpair\n", __func__);
+ exit(1);
+ }
+
+ if (evutil_make_socket_nonblocking(spair[0]) == -1) {
+ fprintf(stderr, "fcntl(O_NONBLOCK)");
+ exit(1);
+ }
+
+ if (evutil_make_socket_nonblocking(spair[1]) == -1) {
+ fprintf(stderr, "fcntl(O_NONBLOCK)");
+ exit(1);
+ }
+ }
+ if (testcase->flags & TT_NEED_BASE) {
+ if (testcase->flags & TT_LEGACY)
+ base = event_init();
+ else
+ base = event_base_new();
+ if (!base)
+ exit(1);
+ }
+ if (testcase->flags & TT_ENABLE_IOCP_FLAG) {
+ if (event_base_start_iocp(base, 0)<0) {
+ event_base_free(base);
+ return (void*)TT_SKIP;
+ }
+ }
+
+ if (testcase->flags & TT_NEED_DNS) {
+ evdns_set_log_fn(dnslogcb);
+ if (evdns_init())
+ return NULL; /* fast failure */ /*XXX asserts. */
+ }
+
+ if (testcase->flags & TT_NO_LOGS)
+ event_set_log_callback(ignore_log_cb);
+
+ data = calloc(1, sizeof(*data));
+ if (!data)
+ exit(1);
+ data->base = base;
+ data->pair[0] = spair[0];
+ data->pair[1] = spair[1];
+ data->setup_data = testcase->setup_data;
+ return data;
+}
+
+static int
+basic_test_cleanup(const struct testcase_t *testcase, void *ptr)
+{
+ struct basic_test_data *data = ptr;
+
+ if (testcase->flags & TT_NO_LOGS)
+ event_set_log_callback(NULL);
+
+ if (testcase->flags & TT_NEED_SOCKETPAIR) {
+ if (data->pair[0] != -1)
+ evutil_closesocket(data->pair[0]);
+ if (data->pair[1] != -1)
+ evutil_closesocket(data->pair[1]);
+ }
+
+ if (testcase->flags & TT_NEED_DNS) {
+ evdns_shutdown(0);
+ }
+
+ if (testcase->flags & TT_NEED_BASE) {
+ if (data->base) {
+ event_base_assert_ok(data->base);
+ event_base_free(data->base);
+ }
+ }
+
+ free(data);
+
+ return 1;
+}
+
+const struct testcase_setup_t basic_setup = {
+ basic_test_setup, basic_test_cleanup
+};
+
+/* The "data" for a legacy test is just a pointer to the void fn(void)
+ function implementing the test case. We need to set up some globals,
+ though, since that's where legacy tests expect to find a socketpair
+ (sometimes) and a global event_base (sometimes).
+ */
+static void *
+legacy_test_setup(const struct testcase_t *testcase)
+{
+ struct basic_test_data *data = basic_test_setup(testcase);
+ if (data == (void*)TT_SKIP || data == NULL)
+ return data;
+ global_base = data->base;
+ pair[0] = data->pair[0];
+ pair[1] = data->pair[1];
+ data->legacy_test_fn = testcase->setup_data;
+ return data;
+}
+
+/* This function is the implementation of every legacy test case. It
+ sets test_ok to 0, invokes the test function, and tells tinytest that
+ the test failed if the test didn't set test_ok to 1.
+ */
+void
+run_legacy_test_fn(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ test_ok = called = 0;
+
+ in_legacy_test_wrapper = 1;
+ data->legacy_test_fn(); /* This part actually calls the test */
+ in_legacy_test_wrapper = 0;
+
+ if (!test_ok)
+ tt_abort_msg("Legacy unit test failed");
+
+end:
+ test_ok = 0;
+}
+
+/* This function doesn't have to clean up ptr (which is just a pointer
+ to the test function), but it may need to close the socketpair or
+ free the event_base.
+ */
+static int
+legacy_test_cleanup(const struct testcase_t *testcase, void *ptr)
+{
+ int r = basic_test_cleanup(testcase, ptr);
+ pair[0] = pair[1] = -1;
+ global_base = NULL;
+ return r;
+}
+
+const struct testcase_setup_t legacy_setup = {
+ legacy_test_setup, legacy_test_cleanup
+};
+
+/* ============================================================ */
+
+#if (!defined(_EVENT_HAVE_PTHREADS) && !defined(WIN32)) || defined(_EVENT_DISABLE_THREAD_SUPPORT)
+struct testcase_t thread_testcases[] = {
+ { "basic", NULL, TT_SKIP, NULL, NULL },
+ END_OF_TESTCASES
+};
+#endif
+
+struct testgroup_t testgroups[] = {
+ { "main/", main_testcases },
+ { "heap/", minheap_testcases },
+ { "et/", edgetriggered_testcases },
+ { "evbuffer/", evbuffer_testcases },
+ { "signal/", signal_testcases },
+ { "util/", util_testcases },
+ { "bufferevent/", bufferevent_testcases },
+ { "http/", http_testcases },
+ { "dns/", dns_testcases },
+ { "evtag/", evtag_testcases },
+ { "rpc/", rpc_testcases },
+ { "thread/", thread_testcases },
+ { "listener/", listener_testcases },
+#ifdef WIN32
+ { "iocp/", iocp_testcases },
+ { "iocp/bufferevent/", bufferevent_iocp_testcases },
+ { "iocp/listener/", listener_iocp_testcases },
+#endif
+#ifdef _EVENT_HAVE_OPENSSL
+ { "ssl/", ssl_testcases },
+#endif
+ END_OF_GROUPS
+};
+
+int
+main(int argc, const char **argv)
+{
+#ifdef WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+#endif
+
+#ifndef WIN32
+ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+ return 1;
+#endif
+
+#ifdef WIN32
+ tinytest_skip(testgroups, "http/connection_retry");
+#endif
+
+#ifndef _EVENT_DISABLE_THREAD_SUPPORT
+ if (!getenv("EVENT_NO_DEBUG_LOCKS"))
+ evthread_enable_lock_debuging();
+#endif
+
+ if (tinytest_main(argc,argv,testgroups))
+ return 1;
+
+ return 0;
+}
+
diff --git a/libevent-2.0.20-stable/test/regress_minheap.c b/libevent-2.0.20-stable/test/regress_minheap.c
new file mode 100644
index 0000000..049d22a
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress_minheap.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include "event2/event_struct.h"
+
+#include "tinytest.h"
+#include "tinytest_macros.h"
+#include "../minheap-internal.h"
+
+static void
+set_random_timeout(struct event *ev)
+{
+ ev->ev_timeout.tv_sec = rand();
+ ev->ev_timeout.tv_usec = rand() & 0xfffff;
+ ev->ev_timeout_pos.min_heap_idx = -1;
+}
+
+static void
+check_heap(struct min_heap *heap)
+{
+ unsigned i;
+ for (i = 1; i < heap->n; ++i) {
+ unsigned parent_idx = (i-1)/2;
+ tt_want(evutil_timercmp(&heap->p[i]->ev_timeout,
+ &heap->p[parent_idx]->ev_timeout, >=));
+ }
+}
+
+static void
+test_heap_randomized(void *ptr)
+{
+ struct min_heap heap;
+ struct event *inserted[1024];
+ struct event *e, *last_e;
+ int i;
+
+ min_heap_ctor(&heap);
+
+ for (i = 0; i < 1024; ++i) {
+ inserted[i] = malloc(sizeof(struct event));
+ set_random_timeout(inserted[i]);
+ min_heap_push(&heap, inserted[i]);
+ }
+ check_heap(&heap);
+
+ tt_assert(min_heap_size(&heap) == 1024);
+
+ for (i = 0; i < 512; ++i) {
+ min_heap_erase(&heap, inserted[i]);
+ if (0 == (i % 32))
+ check_heap(&heap);
+ }
+ tt_assert(min_heap_size(&heap) == 512);
+
+ last_e = min_heap_pop(&heap);
+ while (1) {
+ e = min_heap_pop(&heap);
+ if (!e)
+ break;
+ tt_want(evutil_timercmp(&last_e->ev_timeout,
+ &e->ev_timeout, <=));
+ }
+ tt_assert(min_heap_size(&heap) == 0);
+end:
+ for (i = 0; i < 1024; ++i)
+ free(inserted[i]);
+
+ min_heap_dtor(&heap);
+}
+
+struct testcase_t minheap_testcases[] = {
+ { "randomized", test_heap_randomized, 0, NULL, NULL },
+ END_OF_TESTCASES
+};
diff --git a/libevent-2.0.20-stable/test/regress_rpc.c b/libevent-2.0.20-stable/test/regress_rpc.c
new file mode 100644
index 0000000..7604ca4
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress_rpc.c
@@ -0,0 +1,898 @@
+/*
+ * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* The old tests here need assertions to work. */
+#undef NDEBUG
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "event2/buffer.h"
+#include "event2/event.h"
+#include "event2/event_compat.h"
+#include "event2/http.h"
+#include "event2/http_compat.h"
+#include "event2/http_struct.h"
+#include "event2/rpc.h"
+#include "event2/rpc.h"
+#include "event2/rpc_struct.h"
+#include "event2/tag.h"
+#include "log-internal.h"
+
+#include "regress.gen.h"
+
+#include "regress.h"
+#include "regress_testutils.h"
+
+#ifndef NO_PYTHON_EXISTS
+
+static struct evhttp *
+http_setup(ev_uint16_t *pport)
+{
+ struct evhttp *myhttp;
+ ev_uint16_t port;
+ struct evhttp_bound_socket *sock;
+
+ myhttp = evhttp_new(NULL);
+ if (!myhttp)
+ event_errx(1, "Could not start web server");
+
+ /* Try a few different ports */
+ sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", 0);
+ if (!sock)
+ event_errx(1, "Couldn't open web port");
+
+ port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock));
+
+ *pport = port;
+ return (myhttp);
+}
+
+EVRPC_HEADER(Message, msg, kill)
+EVRPC_HEADER(NeverReply, msg, kill)
+
+EVRPC_GENERATE(Message, msg, kill)
+EVRPC_GENERATE(NeverReply, msg, kill)
+
+static int need_input_hook = 0;
+static int need_output_hook = 0;
+
+static void
+MessageCb(EVRPC_STRUCT(Message)* rpc, void *arg)
+{
+ struct kill* kill_reply = rpc->reply;
+
+ if (need_input_hook) {
+ struct evhttp_request* req = EVRPC_REQUEST_HTTP(rpc);
+ const char *header = evhttp_find_header(
+ req->input_headers, "X-Hook");
+ assert(header);
+ assert(strcmp(header, "input") == 0);
+ }
+
+ /* we just want to fill in some non-sense */
+ EVTAG_ASSIGN(kill_reply, weapon, "dagger");
+ EVTAG_ASSIGN(kill_reply, action, "wave around like an idiot");
+
+ /* no reply to the RPC */
+ EVRPC_REQUEST_DONE(rpc);
+}
+
+static EVRPC_STRUCT(NeverReply) *saved_rpc;
+
+static void
+NeverReplyCb(EVRPC_STRUCT(NeverReply)* rpc, void *arg)
+{
+ test_ok += 1;
+ saved_rpc = rpc;
+}
+
+static void
+rpc_setup(struct evhttp **phttp, ev_uint16_t *pport, struct evrpc_base **pbase)
+{
+ ev_uint16_t port;
+ struct evhttp *http = NULL;
+ struct evrpc_base *base = NULL;
+
+ http = http_setup(&port);
+ base = evrpc_init(http);
+
+ EVRPC_REGISTER(base, Message, msg, kill, MessageCb, NULL);
+ EVRPC_REGISTER(base, NeverReply, msg, kill, NeverReplyCb, NULL);
+
+ *phttp = http;
+ *pport = port;
+ *pbase = base;
+
+ need_input_hook = 0;
+ need_output_hook = 0;
+}
+
+static void
+rpc_teardown(struct evrpc_base *base)
+{
+ assert(EVRPC_UNREGISTER(base, Message) == 0);
+ assert(EVRPC_UNREGISTER(base, NeverReply) == 0);
+
+ evrpc_free(base);
+}
+
+static void
+rpc_postrequest_failure(struct evhttp_request *req, void *arg)
+{
+ if (req->response_code != HTTP_SERVUNAVAIL) {
+
+ fprintf(stderr, "FAILED (response code)\n");
+ exit(1);
+ }
+
+ test_ok = 1;
+ event_loopexit(NULL);
+}
+
+/*
+ * Test a malformed payload submitted as an RPC
+ */
+
+static void
+rpc_basic_test(void)
+{
+ ev_uint16_t port;
+ struct evhttp *http = NULL;
+ struct evrpc_base *base = NULL;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+
+ rpc_setup(&http, &port, &base);
+
+ evcon = evhttp_connection_new("127.0.0.1", port);
+ tt_assert(evcon);
+
+ /*
+ * At this point, we want to schedule an HTTP POST request
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(rpc_postrequest_failure, NULL);
+ tt_assert(req);
+
+ /* Add the information that we care about */
+ evhttp_add_header(req->output_headers, "Host", "somehost");
+ evbuffer_add_printf(req->output_buffer, "Some Nonsense");
+
+ if (evhttp_make_request(evcon, req,
+ EVHTTP_REQ_POST,
+ "/.rpc.Message") == -1) {
+ tt_abort();
+ }
+
+ test_ok = 0;
+
+ event_dispatch();
+
+ evhttp_connection_free(evcon);
+
+ rpc_teardown(base);
+
+ tt_assert(test_ok == 1);
+
+end:
+ evhttp_free(http);
+}
+
+static void
+rpc_postrequest_done(struct evhttp_request *req, void *arg)
+{
+ struct kill* kill_reply = NULL;
+
+ if (req->response_code != HTTP_OK) {
+ fprintf(stderr, "FAILED (response code)\n");
+ exit(1);
+ }
+
+ kill_reply = kill_new();
+
+ if ((kill_unmarshal(kill_reply, req->input_buffer)) == -1) {
+ fprintf(stderr, "FAILED (unmarshal)\n");
+ exit(1);
+ }
+
+ kill_free(kill_reply);
+
+ test_ok = 1;
+ event_loopexit(NULL);
+}
+
+static void
+rpc_basic_message(void)
+{
+ ev_uint16_t port;
+ struct evhttp *http = NULL;
+ struct evrpc_base *base = NULL;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp_request *req = NULL;
+ struct msg *msg;
+
+ rpc_setup(&http, &port, &base);
+
+ evcon = evhttp_connection_new("127.0.0.1", port);
+ tt_assert(evcon);
+
+ /*
+ * At this point, we want to schedule an HTTP POST request
+ * server using our make request method.
+ */
+
+ req = evhttp_request_new(rpc_postrequest_done, NULL);
+ if (req == NULL) {
+ fprintf(stdout, "FAILED\n");
+ exit(1);
+ }
+
+ /* Add the information that we care about */
+ evhttp_add_header(req->output_headers, "Host", "somehost");
+
+ /* set up the basic message */
+ msg = msg_new();
+ EVTAG_ASSIGN(msg, from_name, "niels");
+ EVTAG_ASSIGN(msg, to_name, "tester");
+ msg_marshal(req->output_buffer, msg);
+ msg_free(msg);
+
+ if (evhttp_make_request(evcon, req,
+ EVHTTP_REQ_POST,
+ "/.rpc.Message") == -1) {
+ fprintf(stdout, "FAILED\n");
+ exit(1);
+ }
+
+ test_ok = 0;
+
+ event_dispatch();
+
+ evhttp_connection_free(evcon);
+
+ rpc_teardown(base);
+
+end:
+ evhttp_free(http);
+}
+
+static struct evrpc_pool *
+rpc_pool_with_connection(ev_uint16_t port)
+{
+ struct evhttp_connection *evcon;
+ struct evrpc_pool *pool;
+
+ pool = evrpc_pool_new(NULL);
+ assert(pool != NULL);
+
+ evcon = evhttp_connection_new("127.0.0.1", port);
+ assert(evcon != NULL);
+
+ evrpc_pool_add_connection(pool, evcon);
+
+ return (pool);
+}
+
+static void
+GotKillCb(struct evrpc_status *status,
+ struct msg *msg, struct kill *kill, void *arg)
+{
+ char *weapon;
+ char *action;
+
+ if (need_output_hook) {
+ struct evhttp_request *req = status->http_req;
+ const char *header = evhttp_find_header(
+ req->input_headers, "X-Pool-Hook");
+ assert(header);
+ assert(strcmp(header, "ran") == 0);
+ }
+
+ if (status->error != EVRPC_STATUS_ERR_NONE)
+ goto done;
+
+ if (EVTAG_GET(kill, weapon, &weapon) == -1) {
+ fprintf(stderr, "get weapon\n");
+ goto done;
+ }
+ if (EVTAG_GET(kill, action, &action) == -1) {
+ fprintf(stderr, "get action\n");
+ goto done;
+ }
+
+ if (strcmp(weapon, "dagger"))
+ goto done;
+
+ if (strcmp(action, "wave around like an idiot"))
+ goto done;
+
+ test_ok += 1;
+
+done:
+ event_loopexit(NULL);
+}
+
+static void
+GotKillCbTwo(struct evrpc_status *status,
+ struct msg *msg, struct kill *kill, void *arg)
+{
+ char *weapon;
+ char *action;
+
+ if (status->error != EVRPC_STATUS_ERR_NONE)
+ goto done;
+
+ if (EVTAG_GET(kill, weapon, &weapon) == -1) {
+ fprintf(stderr, "get weapon\n");
+ goto done;
+ }
+ if (EVTAG_GET(kill, action, &action) == -1) {
+ fprintf(stderr, "get action\n");
+ goto done;
+ }
+
+ if (strcmp(weapon, "dagger"))
+ goto done;
+
+ if (strcmp(action, "wave around like an idiot"))
+ goto done;
+
+ test_ok += 1;
+
+done:
+ if (test_ok == 2)
+ event_loopexit(NULL);
+}
+
+static int
+rpc_hook_add_header(void *ctx, struct evhttp_request *req,
+ struct evbuffer *evbuf, void *arg)
+{
+ const char *hook_type = arg;
+ if (strcmp("input", hook_type) == 0)
+ evhttp_add_header(req->input_headers, "X-Hook", hook_type);
+ else
+ evhttp_add_header(req->output_headers, "X-Hook", hook_type);
+
+ assert(evrpc_hook_get_connection(ctx) != NULL);
+
+ return (EVRPC_CONTINUE);
+}
+
+static int
+rpc_hook_add_meta(void *ctx, struct evhttp_request *req,
+ struct evbuffer *evbuf, void *arg)
+{
+ evrpc_hook_add_meta(ctx, "meta", "test", 5);
+
+ assert(evrpc_hook_get_connection(ctx) != NULL);
+
+ return (EVRPC_CONTINUE);
+}
+
+static int
+rpc_hook_remove_header(void *ctx, struct evhttp_request *req,
+ struct evbuffer *evbuf, void *arg)
+{
+ const char *header = evhttp_find_header(req->input_headers, "X-Hook");
+ void *data = NULL;
+ size_t data_len = 0;
+
+ assert(header != NULL);
+ assert(strcmp(header, arg) == 0);
+
+ evhttp_remove_header(req->input_headers, "X-Hook");
+ evhttp_add_header(req->input_headers, "X-Pool-Hook", "ran");
+
+ assert(evrpc_hook_find_meta(ctx, "meta", &data, &data_len) == 0);
+ assert(data != NULL);
+ assert(data_len == 5);
+
+ assert(evrpc_hook_get_connection(ctx) != NULL);
+
+ return (EVRPC_CONTINUE);
+}
+
+static void
+rpc_basic_client(void)
+{
+ ev_uint16_t port;
+ struct evhttp *http = NULL;
+ struct evrpc_base *base = NULL;
+ struct evrpc_pool *pool = NULL;
+ struct msg *msg = NULL;
+ struct kill *kill = NULL;
+
+ rpc_setup(&http, &port, &base);
+
+ need_input_hook = 1;
+ need_output_hook = 1;
+
+ assert(evrpc_add_hook(base, EVRPC_INPUT, rpc_hook_add_header, (void*)"input")
+ != NULL);
+ assert(evrpc_add_hook(base, EVRPC_OUTPUT, rpc_hook_add_header, (void*)"output")
+ != NULL);
+
+ pool = rpc_pool_with_connection(port);
+
+ assert(evrpc_add_hook(pool, EVRPC_OUTPUT, rpc_hook_add_meta, NULL));
+ assert(evrpc_add_hook(pool, EVRPC_INPUT, rpc_hook_remove_header, (void*)"output"));
+
+ /* set up the basic message */
+ msg = msg_new();
+ EVTAG_ASSIGN(msg, from_name, "niels");
+ EVTAG_ASSIGN(msg, to_name, "tester");
+
+ kill = kill_new();
+
+ EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
+
+ test_ok = 0;
+
+ event_dispatch();
+
+ tt_assert(test_ok == 1);
+
+ /* we do it twice to make sure that reuse works correctly */
+ kill_clear(kill);
+
+ EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
+
+ event_dispatch();
+
+ tt_assert(test_ok == 2);
+
+ /* we do it trice to make sure other stuff works, too */
+ kill_clear(kill);
+
+ {
+ struct evrpc_request_wrapper *ctx =
+ EVRPC_MAKE_CTX(Message, msg, kill,
+ pool, msg, kill, GotKillCb, NULL);
+ evrpc_make_request(ctx);
+ }
+
+ event_dispatch();
+
+ rpc_teardown(base);
+
+ tt_assert(test_ok == 3);
+
+end:
+ if (msg)
+ msg_free(msg);
+ if (kill)
+ kill_free(kill);
+
+ if (pool)
+ evrpc_pool_free(pool);
+ if (http)
+ evhttp_free(http);
+
+ need_input_hook = 0;
+ need_output_hook = 0;
+}
+
+/*
+ * We are testing that the second requests gets send over the same
+ * connection after the first RPCs completes.
+ */
+static void
+rpc_basic_queued_client(void)
+{
+ ev_uint16_t port;
+ struct evhttp *http = NULL;
+ struct evrpc_base *base = NULL;
+ struct evrpc_pool *pool = NULL;
+ struct msg *msg=NULL;
+ struct kill *kill_one=NULL, *kill_two=NULL;
+
+ rpc_setup(&http, &port, &base);
+
+ pool = rpc_pool_with_connection(port);
+
+ /* set up the basic message */
+ msg = msg_new();
+ EVTAG_ASSIGN(msg, from_name, "niels");
+ EVTAG_ASSIGN(msg, to_name, "tester");
+
+ kill_one = kill_new();
+ kill_two = kill_new();
+
+ EVRPC_MAKE_REQUEST(Message, pool, msg, kill_one, GotKillCbTwo, NULL);
+ EVRPC_MAKE_REQUEST(Message, pool, msg, kill_two, GotKillCb, NULL);
+
+ test_ok = 0;
+
+ event_dispatch();
+
+ rpc_teardown(base);
+
+ tt_assert(test_ok == 2);
+
+end:
+ if (msg)
+ msg_free(msg);
+ if (kill_one)
+ kill_free(kill_one);
+ if (kill_two)
+ kill_free(kill_two);
+
+ if (pool)
+ evrpc_pool_free(pool);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+GotErrorCb(struct evrpc_status *status,
+ struct msg *msg, struct kill *kill, void *arg)
+{
+ if (status->error != EVRPC_STATUS_ERR_TIMEOUT)
+ goto done;
+
+ /* should never be complete but just to check */
+ if (kill_complete(kill) == 0)
+ goto done;
+
+ test_ok += 1;
+
+done:
+ event_loopexit(NULL);
+}
+
+/* we just pause the rpc and continue it in the next callback */
+
+struct _rpc_hook_ctx {
+ void *vbase;
+ void *ctx;
+};
+
+static int hook_pause_cb_called=0;
+
+static void
+rpc_hook_pause_cb(evutil_socket_t fd, short what, void *arg)
+{
+ struct _rpc_hook_ctx *ctx = arg;
+ ++hook_pause_cb_called;
+ evrpc_resume_request(ctx->vbase, ctx->ctx, EVRPC_CONTINUE);
+ free(arg);
+}
+
+static int
+rpc_hook_pause(void *ctx, struct evhttp_request *req, struct evbuffer *evbuf,
+ void *arg)
+{
+ struct _rpc_hook_ctx *tmp = malloc(sizeof(*tmp));
+ struct timeval tv;
+
+ assert(tmp != NULL);
+ tmp->vbase = arg;
+ tmp->ctx = ctx;
+
+ memset(&tv, 0, sizeof(tv));
+ event_once(-1, EV_TIMEOUT, rpc_hook_pause_cb, tmp, &tv);
+ return EVRPC_PAUSE;
+}
+
+static void
+rpc_basic_client_with_pause(void)
+{
+ ev_uint16_t port;
+ struct evhttp *http = NULL;
+ struct evrpc_base *base = NULL;
+ struct evrpc_pool *pool = NULL;
+ struct msg *msg = NULL;
+ struct kill *kill= NULL;
+
+ rpc_setup(&http, &port, &base);
+
+ assert(evrpc_add_hook(base, EVRPC_INPUT, rpc_hook_pause, base));
+ assert(evrpc_add_hook(base, EVRPC_OUTPUT, rpc_hook_pause, base));
+
+ pool = rpc_pool_with_connection(port);
+
+ assert(evrpc_add_hook(pool, EVRPC_INPUT, rpc_hook_pause, pool));
+ assert(evrpc_add_hook(pool, EVRPC_OUTPUT, rpc_hook_pause, pool));
+
+ /* set up the basic message */
+ msg = msg_new();
+ EVTAG_ASSIGN(msg, from_name, "niels");
+ EVTAG_ASSIGN(msg, to_name, "tester");
+
+ kill = kill_new();
+
+ EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
+
+ test_ok = 0;
+
+ event_dispatch();
+
+ tt_int_op(test_ok, ==, 1);
+ tt_int_op(hook_pause_cb_called, ==, 4);
+
+end:
+ if (base)
+ rpc_teardown(base);
+
+ if (msg)
+ msg_free(msg);
+ if (kill)
+ kill_free(kill);
+
+ if (pool)
+ evrpc_pool_free(pool);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+rpc_client_timeout(void)
+{
+ ev_uint16_t port;
+ struct evhttp *http = NULL;
+ struct evrpc_base *base = NULL;
+ struct evrpc_pool *pool = NULL;
+ struct msg *msg = NULL;
+ struct kill *kill = NULL;
+
+ rpc_setup(&http, &port, &base);
+
+ pool = rpc_pool_with_connection(port);
+
+ /* set the timeout to 5 seconds */
+ evrpc_pool_set_timeout(pool, 5);
+
+ /* set up the basic message */
+ msg = msg_new();
+ EVTAG_ASSIGN(msg, from_name, "niels");
+ EVTAG_ASSIGN(msg, to_name, "tester");
+
+ kill = kill_new();
+
+ EVRPC_MAKE_REQUEST(NeverReply, pool, msg, kill, GotErrorCb, NULL);
+
+ test_ok = 0;
+
+ event_dispatch();
+
+ /* free the saved RPC structure up */
+ EVRPC_REQUEST_DONE(saved_rpc);
+
+ rpc_teardown(base);
+
+ tt_assert(test_ok == 2);
+
+end:
+ if (msg)
+ msg_free(msg);
+ if (kill)
+ kill_free(kill);
+
+ if (pool)
+ evrpc_pool_free(pool);
+ if (http)
+ evhttp_free(http);
+}
+
+static void
+rpc_test(void)
+{
+ struct msg *msg = NULL, *msg2 = NULL;
+ struct kill *attack = NULL;
+ struct run *run = NULL;
+ struct evbuffer *tmp = evbuffer_new();
+ struct timeval tv_start, tv_end;
+ ev_uint32_t tag;
+ int i;
+
+ msg = msg_new();
+
+ tt_assert(msg);
+
+ EVTAG_ASSIGN(msg, from_name, "niels");
+ EVTAG_ASSIGN(msg, to_name, "phoenix");
+
+ if (EVTAG_GET(msg, attack, &attack) == -1) {
+ tt_abort_msg("Failed to set kill message.");
+ }
+
+ EVTAG_ASSIGN(attack, weapon, "feather");
+ EVTAG_ASSIGN(attack, action, "tickle");
+ for (i = 0; i < 3; ++i) {
+ if (EVTAG_ARRAY_ADD_VALUE(attack, how_often, i) == NULL) {
+ tt_abort_msg("Failed to add how_often.");
+ }
+ }
+
+ evutil_gettimeofday(&tv_start, NULL);
+ for (i = 0; i < 1000; ++i) {
+ run = EVTAG_ARRAY_ADD(msg, run);
+ if (run == NULL) {
+ tt_abort_msg("Failed to add run message.");
+ }
+ EVTAG_ASSIGN(run, how, "very fast but with some data in it");
+ EVTAG_ASSIGN(run, fixed_bytes,
+ (ev_uint8_t*)"012345678901234567890123");
+
+ if (EVTAG_ARRAY_ADD_VALUE(
+ run, notes, "this is my note") == NULL) {
+ tt_abort_msg("Failed to add note.");
+ }
+ if (EVTAG_ARRAY_ADD_VALUE(run, notes, "pps") == NULL) {
+ tt_abort_msg("Failed to add note");
+ }
+
+ EVTAG_ASSIGN(run, large_number, 0xdead0a0bcafebeefLL);
+ EVTAG_ARRAY_ADD_VALUE(run, other_numbers, 0xdead0a0b);
+ EVTAG_ARRAY_ADD_VALUE(run, other_numbers, 0xbeefcafe);
+ }
+
+ if (msg_complete(msg) == -1)
+ tt_abort_msg("Failed to make complete message.");
+
+ evtag_marshal_msg(tmp, 0xdeaf, msg);
+
+ if (evtag_peek(tmp, &tag) == -1)
+ tt_abort_msg("Failed to peak tag.");
+
+ if (tag != 0xdeaf)
+ TT_DIE(("Got incorrect tag: %0x.", (unsigned)tag));
+
+ msg2 = msg_new();
+ if (evtag_unmarshal_msg(tmp, 0xdeaf, msg2) == -1)
+ tt_abort_msg("Failed to unmarshal message.");
+
+ evutil_gettimeofday(&tv_end, NULL);
+ evutil_timersub(&tv_end, &tv_start, &tv_end);
+ TT_BLATHER(("(%.1f us/add) ",
+ (float)tv_end.tv_sec/(float)i * 1000000.0 +
+ tv_end.tv_usec / (float)i));
+
+ if (!EVTAG_HAS(msg2, from_name) ||
+ !EVTAG_HAS(msg2, to_name) ||
+ !EVTAG_HAS(msg2, attack)) {
+ tt_abort_msg("Missing data structures.");
+ }
+
+ if (EVTAG_GET(msg2, attack, &attack) == -1) {
+ tt_abort_msg("Could not get attack.");
+ }
+
+ if (EVTAG_ARRAY_LEN(msg2, run) != i) {
+ tt_abort_msg("Wrong number of run messages.");
+ }
+
+ /* get the very first run message */
+ if (EVTAG_ARRAY_GET(msg2, run, 0, &run) == -1) {
+ tt_abort_msg("Failed to get run msg.");
+ } else {
+ /* verify the notes */
+ char *note_one, *note_two;
+ ev_uint64_t large_number;
+ ev_uint32_t short_number;
+
+ if (EVTAG_ARRAY_LEN(run, notes) != 2) {
+ tt_abort_msg("Wrong number of note strings.");
+ }
+
+ if (EVTAG_ARRAY_GET(run, notes, 0, &note_one) == -1 ||
+ EVTAG_ARRAY_GET(run, notes, 1, &note_two) == -1) {
+ tt_abort_msg("Could not get note strings.");
+ }
+
+ if (strcmp(note_one, "this is my note") ||
+ strcmp(note_two, "pps")) {
+ tt_abort_msg("Incorrect note strings encoded.");
+ }
+
+ if (EVTAG_GET(run, large_number, &large_number) == -1 ||
+ large_number != 0xdead0a0bcafebeefLL) {
+ tt_abort_msg("Incorrrect large_number.");
+ }
+
+ if (EVTAG_ARRAY_LEN(run, other_numbers) != 2) {
+ tt_abort_msg("Wrong number of other_numbers.");
+ }
+
+ if (EVTAG_ARRAY_GET(
+ run, other_numbers, 0, &short_number) == -1) {
+ tt_abort_msg("Could not get short number.");
+ }
+ tt_uint_op(short_number, ==, 0xdead0a0b);
+
+ }
+ tt_int_op(EVTAG_ARRAY_LEN(attack, how_often), ==, 3);
+
+ for (i = 0; i < 3; ++i) {
+ ev_uint32_t res;
+ if (EVTAG_ARRAY_GET(attack, how_often, i, &res) == -1) {
+ TT_DIE(("Cannot get %dth how_often msg.", i));
+ }
+ if ((int)res != i) {
+ TT_DIE(("Wrong message encoded %d != %d", i, res));
+ }
+ }
+
+ test_ok = 1;
+end:
+ if (msg)
+ msg_free(msg);
+ if (msg2)
+ msg_free(msg2);
+ if (tmp)
+ evbuffer_free(tmp);
+}
+
+#define RPC_LEGACY(name) \
+ { #name, run_legacy_test_fn, TT_FORK|TT_NEED_BASE|TT_LEGACY, \
+ &legacy_setup, \
+ rpc_##name }
+#else
+/* NO_PYTHON_EXISTS */
+
+#define RPC_LEGACY(name) \
+ { #name, NULL, TT_SKIP, NULL, NULL }
+
+#endif
+
+struct testcase_t rpc_testcases[] = {
+ RPC_LEGACY(basic_test),
+ RPC_LEGACY(basic_message),
+ RPC_LEGACY(basic_client),
+ RPC_LEGACY(basic_queued_client),
+ RPC_LEGACY(basic_client_with_pause),
+ RPC_LEGACY(client_timeout),
+ RPC_LEGACY(test),
+
+ END_OF_TESTCASES,
+};
diff --git a/libevent-2.0.20-stable/test/regress_ssl.c b/libevent-2.0.20-stable/test/regress_ssl.c
new file mode 100644
index 0000000..8e0087a
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress_ssl.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#ifndef WIN32
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#include "event2/util.h"
+#include "event2/event.h"
+#include "event2/bufferevent_ssl.h"
+#include "event2/buffer.h"
+#include "event2/listener.h"
+
+#include "regress.h"
+#include "tinytest.h"
+#include "tinytest_macros.h"
+
+#include <openssl/ssl.h>
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+
+#include <string.h>
+
+/* A short pre-generated key, to save the cost of doing an RSA key generation
+ * step during the unit tests. It's only 512 bits long, and it is published
+ * in this file, so you would have to be very foolish to consider using it in
+ * your own code. */
+static const char KEY[] =
+ "-----BEGIN RSA PRIVATE KEY-----\n"
+ "MIIBOgIBAAJBAKibTEzXjj+sqpipePX1lEk5BNFuL/dDBbw8QCXgaJWikOiKHeJq\n"
+ "3FQ0OmCnmpkdsPFE4x3ojYmmdgE2i0dJwq0CAwEAAQJAZ08gpUS+qE1IClps/2gG\n"
+ "AAer6Bc31K2AaiIQvCSQcH440cp062QtWMC3V5sEoWmdLsbAHFH26/9ZHn5zAflp\n"
+ "gQIhANWOx/UYeR8HD0WREU5kcuSzgzNLwUErHLzxP7U6aojpAiEAyh2H35CjN/P7\n"
+ "NhcZ4QYw3PeUWpqgJnaE/4i80BSYkSUCIQDLHFhLYLJZ80HwHTADif/ISn9/Ow6b\n"
+ "p6BWh3DbMar/eQIgBPS6azH5vpp983KXkNv9AL4VZi9ac/b+BeINdzC6GP0CIDmB\n"
+ "U6GFEQTZ3IfuiVabG5pummdC4DNbcdI+WKrSFNmQ\n"
+ "-----END RSA PRIVATE KEY-----\n";
+
+static EVP_PKEY *
+getkey(void)
+{
+ EVP_PKEY *key;
+ BIO *bio;
+
+ /* new read-only BIO backed by KEY. */
+ bio = BIO_new_mem_buf((char*)KEY, -1);
+ tt_assert(bio);
+
+ key = PEM_read_bio_PrivateKey(bio,NULL,NULL,NULL);
+ BIO_free(bio);
+ tt_assert(key);
+
+ return key;
+end:
+ return NULL;
+}
+
+static X509 *
+getcert(void)
+{
+ /* Dummy code to make a quick-and-dirty valid certificate with
+ OpenSSL. Don't copy this code into your own program! It does a
+ number of things in a stupid and insecure way. */
+ X509 *x509 = NULL;
+ X509_NAME *name = NULL;
+ EVP_PKEY *key = getkey();
+ int nid;
+ time_t now = time(NULL);
+
+ tt_assert(key);
+
+ x509 = X509_new();
+ tt_assert(x509);
+ tt_assert(0 != X509_set_version(x509, 2));
+ tt_assert(0 != ASN1_INTEGER_set(X509_get_serialNumber(x509),
+ (long)now));
+
+ name = X509_NAME_new();
+ tt_assert(name);
+ nid = OBJ_txt2nid("commonName");
+ tt_assert(NID_undef != nid);
+ tt_assert(0 != X509_NAME_add_entry_by_NID(
+ name, nid, MBSTRING_ASC, (unsigned char*)"example.com",
+ -1, -1, 0));
+
+ X509_set_subject_name(x509, name);
+ X509_set_issuer_name(x509, name);
+
+ X509_time_adj(X509_get_notBefore(x509), 0, &now);
+ now += 3600;
+ X509_time_adj(X509_get_notAfter(x509), 0, &now);
+ X509_set_pubkey(x509, key);
+ tt_assert(0 != X509_sign(x509, key, EVP_sha1()));
+
+ return x509;
+end:
+ X509_free(x509);
+ return NULL;
+}
+
+static SSL_CTX *the_ssl_ctx = NULL;
+
+static SSL_CTX *
+get_ssl_ctx(void)
+{
+ if (the_ssl_ctx)
+ return the_ssl_ctx;
+ return (the_ssl_ctx = SSL_CTX_new(SSLv23_method()));
+}
+
+static void
+init_ssl(void)
+{
+ SSL_library_init();
+ ERR_load_crypto_strings();
+ SSL_load_error_strings();
+ OpenSSL_add_all_algorithms();
+}
+
+/* ====================
+ Here's a simple test: we read a number from the input, increment it, and
+ reply, until we get to 1001.
+*/
+
+static int test_is_done = 0;
+static int n_connected = 0;
+static int got_close = 0;
+static int got_error = 0;
+static int renegotiate_at = -1;
+static int stop_when_connected = 0;
+static int pending_connect_events = 0;
+static struct event_base *exit_base = NULL;
+
+static void
+respond_to_number(struct bufferevent *bev, void *ctx)
+{
+ struct evbuffer *b = bufferevent_get_input(bev);
+ char *line;
+ int n;
+ line = evbuffer_readln(b, NULL, EVBUFFER_EOL_LF);
+ if (! line)
+ return;
+ n = atoi(line);
+ if (n <= 0)
+ TT_FAIL(("Bad number: %s", line));
+ TT_BLATHER(("The number was %d", n));
+ if (n == 1001) {
+ ++test_is_done;
+ bufferevent_free(bev); /* Should trigger close on other side. */
+ return;
+ }
+ if (!strcmp(ctx, "client") && n == renegotiate_at) {
+ SSL_renegotiate(bufferevent_openssl_get_ssl(bev));
+ }
+ ++n;
+ evbuffer_add_printf(bufferevent_get_output(bev),
+ "%d\n", n);
+ TT_BLATHER(("Done reading; now writing."));
+ bufferevent_enable(bev, EV_WRITE);
+ bufferevent_disable(bev, EV_READ);
+}
+
+static void
+done_writing_cb(struct bufferevent *bev, void *ctx)
+{
+ struct evbuffer *b = bufferevent_get_output(bev);
+ if (evbuffer_get_length(b))
+ return;
+ TT_BLATHER(("Done writing."));
+ bufferevent_disable(bev, EV_WRITE);
+ bufferevent_enable(bev, EV_READ);
+}
+
+static void
+eventcb(struct bufferevent *bev, short what, void *ctx)
+{
+ TT_BLATHER(("Got event %d", (int)what));
+ if (what & BEV_EVENT_CONNECTED) {
+ SSL *ssl;
+ X509 *peer_cert;
+ ++n_connected;
+ ssl = bufferevent_openssl_get_ssl(bev);
+ tt_assert(ssl);
+ peer_cert = SSL_get_peer_certificate(ssl);
+ if (0==strcmp(ctx, "server")) {
+ tt_assert(peer_cert == NULL);
+ } else {
+ tt_assert(peer_cert != NULL);
+ }
+ if (stop_when_connected) {
+ if (--pending_connect_events == 0)
+ event_base_loopexit(exit_base, NULL);
+ }
+ } else if (what & BEV_EVENT_EOF) {
+ TT_BLATHER(("Got a good EOF"));
+ ++got_close;
+ bufferevent_free(bev);
+ } else if (what & BEV_EVENT_ERROR) {
+ TT_BLATHER(("Got an error."));
+ ++got_error;
+ bufferevent_free(bev);
+ }
+end:
+ ;
+}
+
+static void
+open_ssl_bufevs(struct bufferevent **bev1_out, struct bufferevent **bev2_out,
+ struct event_base *base, int is_open, int flags, SSL *ssl1, SSL *ssl2,
+ int *fd_pair, struct bufferevent **underlying_pair)
+{
+ int state1 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_CONNECTING;
+ int state2 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_ACCEPTING;
+ if (fd_pair) {
+ *bev1_out = bufferevent_openssl_socket_new(
+ base, fd_pair[0], ssl1, state1, flags);
+ *bev2_out = bufferevent_openssl_socket_new(
+ base, fd_pair[1], ssl2, state2, flags);
+ } else {
+ *bev1_out = bufferevent_openssl_filter_new(
+ base, underlying_pair[0], ssl1, state1, flags);
+ *bev2_out = bufferevent_openssl_filter_new(
+ base, underlying_pair[1], ssl2, state2, flags);
+
+ }
+ bufferevent_setcb(*bev1_out, respond_to_number, done_writing_cb,
+ eventcb, (void*)"client");
+ bufferevent_setcb(*bev2_out, respond_to_number, done_writing_cb,
+ eventcb, (void*)"server");
+}
+
+static void
+regress_bufferevent_openssl(void *arg)
+{
+ struct basic_test_data *data = arg;
+
+ struct bufferevent *bev1, *bev2;
+ SSL *ssl1, *ssl2;
+ X509 *cert = getcert();
+ EVP_PKEY *key = getkey();
+ const int start_open = strstr((char*)data->setup_data, "open")!=NULL;
+ const int filter = strstr((char*)data->setup_data, "filter")!=NULL;
+ int flags = BEV_OPT_DEFER_CALLBACKS;
+ struct bufferevent *bev_ll[2] = { NULL, NULL };
+ int *fd_pair = NULL;
+
+ tt_assert(cert);
+ tt_assert(key);
+
+ init_ssl();
+
+ ssl1 = SSL_new(get_ssl_ctx());
+ ssl2 = SSL_new(get_ssl_ctx());
+
+ SSL_use_certificate(ssl2, cert);
+ SSL_use_PrivateKey(ssl2, key);
+
+ if (! start_open)
+ flags |= BEV_OPT_CLOSE_ON_FREE;
+
+ if (strstr((char*)data->setup_data, "renegotiate"))
+ renegotiate_at = 600;
+
+ if (!filter) {
+ tt_assert(strstr((char*)data->setup_data, "socketpair"));
+ fd_pair = data->pair;
+ } else {
+ bev_ll[0] = bufferevent_socket_new(data->base, data->pair[0],
+ BEV_OPT_CLOSE_ON_FREE);
+ bev_ll[1] = bufferevent_socket_new(data->base, data->pair[1],
+ BEV_OPT_CLOSE_ON_FREE);
+ }
+
+ open_ssl_bufevs(&bev1, &bev2, data->base, 0, flags, ssl1, ssl2,
+ fd_pair, bev_ll);
+
+ if (!filter) {
+ tt_int_op(bufferevent_getfd(bev1), ==, data->pair[0]);
+ } else {
+ tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev_ll[0]);
+ }
+
+ if (start_open) {
+ pending_connect_events = 2;
+ stop_when_connected = 1;
+ exit_base = data->base;
+ event_base_dispatch(data->base);
+ /* Okay, now the renegotiation is done. Make new
+ * bufferevents to test opening in BUFFEREVENT_SSL_OPEN */
+ flags |= BEV_OPT_CLOSE_ON_FREE;
+ bufferevent_free(bev1);
+ bufferevent_free(bev2);
+ bev1 = bev2 = NULL;
+ open_ssl_bufevs(&bev1, &bev2, data->base, 1, flags, ssl1, ssl2,
+ fd_pair, bev_ll);
+ }
+
+ bufferevent_enable(bev1, EV_READ|EV_WRITE);
+ bufferevent_enable(bev2, EV_READ|EV_WRITE);
+
+ evbuffer_add_printf(bufferevent_get_output(bev1), "1\n");
+
+ event_base_dispatch(data->base);
+
+ tt_assert(test_is_done == 1);
+ tt_assert(n_connected == 2);
+
+ /* We don't handle shutdown properly yet.
+ tt_int_op(got_close, ==, 1);
+ tt_int_op(got_error, ==, 0);
+ */
+end:
+ return;
+}
+
+static void
+acceptcb(struct evconnlistener *listener, evutil_socket_t fd,
+ struct sockaddr *addr, int socklen, void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev;
+ SSL *ssl = SSL_new(get_ssl_ctx());
+
+ SSL_use_certificate(ssl, getcert());
+ SSL_use_PrivateKey(ssl, getkey());
+
+ bev = bufferevent_openssl_socket_new(
+ data->base,
+ fd,
+ ssl,
+ BUFFEREVENT_SSL_ACCEPTING,
+ BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
+
+ bufferevent_setcb(bev, respond_to_number, NULL, eventcb,
+ (void*)"server");
+
+ bufferevent_enable(bev, EV_READ|EV_WRITE);
+
+ /* Only accept once, then disable ourself. */
+ evconnlistener_disable(listener);
+}
+
+static void
+regress_bufferevent_openssl_connect(void *arg)
+{
+ struct basic_test_data *data = arg;
+
+ struct event_base *base = data->base;
+
+ struct evconnlistener *listener;
+ struct bufferevent *bev;
+ struct sockaddr_in sin;
+ struct sockaddr_storage ss;
+ ev_socklen_t slen;
+
+ init_ssl();
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(0x7f000001);
+
+ memset(&ss, 0, sizeof(ss));
+ slen = sizeof(ss);
+
+ listener = evconnlistener_new_bind(base, acceptcb, data,
+ LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
+ -1, (struct sockaddr *)&sin, sizeof(sin));
+
+ tt_assert(listener);
+ tt_assert(evconnlistener_get_fd(listener) >= 0);
+
+ bev = bufferevent_openssl_socket_new(
+ data->base, -1, SSL_new(get_ssl_ctx()),
+ BUFFEREVENT_SSL_CONNECTING,
+ BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
+ tt_assert(bev);
+
+ bufferevent_setcb(bev, respond_to_number, NULL, eventcb,
+ (void*)"client");
+
+ tt_assert(getsockname(evconnlistener_get_fd(listener),
+ (struct sockaddr*)&ss, &slen) == 0);
+ tt_assert(slen == sizeof(struct sockaddr_in));
+ tt_int_op(((struct sockaddr*)&ss)->sa_family, ==, AF_INET);
+ tt_int_op(((struct sockaddr*)&ss)->sa_family, ==, AF_INET);
+
+ tt_assert(0 ==
+ bufferevent_socket_connect(bev, (struct sockaddr*)&ss, slen));
+ evbuffer_add_printf(bufferevent_get_output(bev), "1\n");
+ bufferevent_enable(bev, EV_READ|EV_WRITE);
+
+ event_base_dispatch(base);
+end:
+ ;
+}
+
+struct testcase_t ssl_testcases[] = {
+
+ { "bufferevent_socketpair", regress_bufferevent_openssl, TT_ISOLATED,
+ &basic_setup, (void*)"socketpair" },
+ { "bufferevent_filter", regress_bufferevent_openssl,
+ TT_ISOLATED,
+ &basic_setup, (void*)"filter" },
+ { "bufferevent_renegotiate_socketpair", regress_bufferevent_openssl,
+ TT_ISOLATED,
+ &basic_setup, (void*)"socketpair renegotiate" },
+ { "bufferevent_renegotiate_filter", regress_bufferevent_openssl,
+ TT_ISOLATED,
+ &basic_setup, (void*)"filter renegotiate" },
+ { "bufferevent_socketpair_startopen", regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup, (void*)"socketpair open" },
+ { "bufferevent_filter_startopen", regress_bufferevent_openssl,
+ TT_ISOLATED, &basic_setup, (void*)"filter open" },
+
+ { "bufferevent_connect", regress_bufferevent_openssl_connect,
+ TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+
+ END_OF_TESTCASES,
+};
diff --git a/libevent-2.0.20-stable/test/regress_testutils.c b/libevent-2.0.20-stable/test/regress_testutils.c
new file mode 100644
index 0000000..c70c9a1
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress_testutils.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2010-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <ws2tcpip.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#endif
+#ifdef _EVENT_HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event2/dns.h"
+#include "event2/dns_struct.h"
+#include "event2/event.h"
+#include "event2/event_compat.h"
+#include "event2/util.h"
+#include "event2/listener.h"
+#include "event2/bufferevent.h"
+#include "log-internal.h"
+#include "regress.h"
+#include "regress_testutils.h"
+
+#include "../util-internal.h"
+
+/* globals */
+static struct evdns_server_port *dns_port;
+evutil_socket_t dns_sock = -1;
+
+/* Helper: return the port that a socket is bound on, in host order. */
+int
+regress_get_socket_port(evutil_socket_t fd)
+{
+ struct sockaddr_storage ss;
+ ev_socklen_t socklen = sizeof(ss);
+ if (getsockname(fd, (struct sockaddr*)&ss, &socklen) != 0)
+ return -1;
+ if (ss.ss_family == AF_INET)
+ return ntohs( ((struct sockaddr_in*)&ss)->sin_port);
+ else if (ss.ss_family == AF_INET6)
+ return ntohs( ((struct sockaddr_in6*)&ss)->sin6_port);
+ else
+ return -1;
+}
+
+struct evdns_server_port *
+regress_get_dnsserver(struct event_base *base,
+ ev_uint16_t *portnum,
+ evutil_socket_t *psock,
+ evdns_request_callback_fn_type cb,
+ void *arg)
+{
+ struct evdns_server_port *port = NULL;
+ evutil_socket_t sock;
+ struct sockaddr_in my_addr;
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ tt_abort_perror("socket");
+ }
+
+ evutil_make_socket_nonblocking(sock);
+
+ memset(&my_addr, 0, sizeof(my_addr));
+ my_addr.sin_family = AF_INET;
+ my_addr.sin_port = htons(*portnum);
+ my_addr.sin_addr.s_addr = htonl(0x7f000001UL);
+ if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) {
+ evutil_closesocket(sock);
+ tt_abort_perror("bind");
+ }
+ port = evdns_add_server_port_with_base(base, sock, 0, cb, arg);
+ if (!*portnum)
+ *portnum = regress_get_socket_port(sock);
+ if (psock)
+ *psock = sock;
+
+ return port;
+end:
+ return NULL;
+}
+
+void
+regress_clean_dnsserver(void)
+{
+ if (dns_port)
+ evdns_close_server_port(dns_port);
+ if (dns_sock >= 0)
+ evutil_closesocket(dns_sock);
+}
+
+void
+regress_dns_server_cb(struct evdns_server_request *req, void *data)
+{
+ struct regress_dns_server_table *tab = data;
+ const char *question;
+
+ if (req->nquestions != 1)
+ TT_DIE(("Only handling one question at a time; got %d",
+ req->nquestions));
+
+ question = req->questions[0]->name;
+
+ while (tab->q && evutil_ascii_strcasecmp(question, tab->q) &&
+ strcmp("*", tab->q))
+ ++tab;
+ if (tab->q == NULL)
+ TT_DIE(("Unexpected question: '%s'", question));
+
+ ++tab->seen;
+
+ if (!strcmp(tab->anstype, "err")) {
+ int err = atoi(tab->ans);
+ tt_assert(! evdns_server_request_respond(req, err));
+ return;
+ } else if (!strcmp(tab->anstype, "errsoa")) {
+ int err = atoi(tab->ans);
+ char soa_record[] =
+ "\x04" "dns1" "\x05" "icann" "\x03" "org" "\0"
+ "\x0a" "hostmaster" "\x05" "icann" "\x03" "org" "\0"
+ "\x77\xde\x5e\xba" /* serial */
+ "\x00\x00\x1c\x20" /* refreshtime = 2h */
+ "\x00\x00\x0e\x10" /* retry = 1h */
+ "\x00\x12\x75\x00" /* expiration = 14d */
+ "\x00\x00\x0e\x10" /* min.ttl = 1h */
+ ;
+ evdns_server_request_add_reply(
+ req, EVDNS_AUTHORITY_SECTION,
+ "example.com", EVDNS_TYPE_SOA, EVDNS_CLASS_INET,
+ 42, sizeof(soa_record) - 1, 0, soa_record);
+ tt_assert(! evdns_server_request_respond(req, err));
+ return;
+ } else if (!strcmp(tab->anstype, "A")) {
+ struct in_addr in;
+ if (!evutil_inet_pton(AF_INET, tab->ans, &in)) {
+ TT_DIE(("Bad A value %s in table", tab->ans));
+ }
+ evdns_server_request_add_a_reply(req, question, 1, &in.s_addr,
+ 100);
+ } else if (!strcmp(tab->anstype, "AAAA")) {
+ struct in6_addr in6;
+ if (!evutil_inet_pton(AF_INET6, tab->ans, &in6)) {
+ TT_DIE(("Bad AAAA value %s in table", tab->ans));
+ }
+ evdns_server_request_add_aaaa_reply(req,
+ question, 1, &in6.s6_addr, 100);
+ } else {
+ TT_DIE(("Weird table entry with type '%s'", tab->anstype));
+ }
+ tt_assert(! evdns_server_request_respond(req, 0))
+ return;
+end:
+ tt_want(! evdns_server_request_drop(req));
+}
+
+int
+regress_dnsserver(struct event_base *base, ev_uint16_t *port,
+ struct regress_dns_server_table *search_table)
+{
+ dns_port = regress_get_dnsserver(base, port, &dns_sock,
+ regress_dns_server_cb, search_table);
+ return dns_port != NULL;
+}
+
+int
+regress_get_listener_addr(struct evconnlistener *lev,
+ struct sockaddr *sa, ev_socklen_t *socklen)
+{
+ evutil_socket_t s = evconnlistener_get_fd(lev);
+ if (s <= 0)
+ return -1;
+ return getsockname(s, sa, socklen);
+}
diff --git a/libevent-2.0.20-stable/test/regress_testutils.h b/libevent-2.0.20-stable/test/regress_testutils.h
new file mode 100644
index 0000000..1f09427
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress_testutils.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2010-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TESTUTILS_H
+#define _TESTUTILS_H
+
+#include "event2/dns.h"
+
+struct regress_dns_server_table {
+ const char *q;
+ const char *anstype;
+ const char *ans;
+ int seen;
+};
+
+struct evdns_server_port *
+regress_get_dnsserver(struct event_base *base,
+ ev_uint16_t *portnum,
+ evutil_socket_t *psock,
+ evdns_request_callback_fn_type cb,
+ void *arg);
+
+/* Helper: return the port that a socket is bound on, in host order. */
+int regress_get_socket_port(evutil_socket_t fd);
+
+/* used to look up pre-canned responses in a search table */
+void regress_dns_server_cb(
+ struct evdns_server_request *req, void *data);
+
+/* globally allocates a dns server that serves from a search table */
+int regress_dnsserver(struct event_base *base, ev_uint16_t *port,
+ struct regress_dns_server_table *seach_table);
+
+/* clean up the global dns server resources */
+void regress_clean_dnsserver(void);
+
+struct evconnlistener;
+struct sockaddr;
+int regress_get_listener_addr(struct evconnlistener *lev,
+ struct sockaddr *sa, ev_socklen_t *socklen);
+
+#endif /* _TESTUTILS_H */
+
diff --git a/libevent-2.0.20-stable/test/regress_thread.c b/libevent-2.0.20-stable/test/regress_thread.c
new file mode 100644
index 0000000..1acf682
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress_thread.c
@@ -0,0 +1,511 @@
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* The old tests here need assertions to work. */
+#undef NDEBUG
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _EVENT_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef _EVENT_HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifdef _EVENT_HAVE_PTHREADS
+#include <pthread.h>
+#elif defined(WIN32)
+#include <process.h>
+#endif
+#include <assert.h>
+#ifdef _EVENT_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <time.h>
+
+#include "sys/queue.h"
+
+#include "event2/util.h"
+#include "event2/event.h"
+#include "event2/event_struct.h"
+#include "event2/thread.h"
+#include "evthread-internal.h"
+#include "event-internal.h"
+#include "defer-internal.h"
+#include "regress.h"
+#include "tinytest_macros.h"
+
+#ifdef _EVENT_HAVE_PTHREADS
+#define THREAD_T pthread_t
+#define THREAD_FN void *
+#define THREAD_RETURN() return (NULL)
+#define THREAD_START(threadvar, fn, arg) \
+ pthread_create(&(threadvar), NULL, fn, arg)
+#define THREAD_JOIN(th) pthread_join(th, NULL)
+#else
+#define THREAD_T HANDLE
+#define THREAD_FN unsigned __stdcall
+#define THREAD_RETURN() return (0)
+#define THREAD_START(threadvar, fn, arg) do { \
+ uintptr_t threadhandle = _beginthreadex(NULL,0,fn,(arg),0,NULL); \
+ (threadvar) = (HANDLE) threadhandle; \
+ } while (0)
+#define THREAD_JOIN(th) WaitForSingleObject(th, INFINITE)
+#endif
+
+struct cond_wait {
+ void *lock;
+ void *cond;
+};
+
+static void
+wake_all_timeout(evutil_socket_t fd, short what, void *arg)
+{
+ struct cond_wait *cw = arg;
+ EVLOCK_LOCK(cw->lock, 0);
+ EVTHREAD_COND_BROADCAST(cw->cond);
+ EVLOCK_UNLOCK(cw->lock, 0);
+
+}
+
+static void
+wake_one_timeout(evutil_socket_t fd, short what, void *arg)
+{
+ struct cond_wait *cw = arg;
+ EVLOCK_LOCK(cw->lock, 0);
+ EVTHREAD_COND_SIGNAL(cw->cond);
+ EVLOCK_UNLOCK(cw->lock, 0);
+}
+
+#define NUM_THREADS 100
+#define NUM_ITERATIONS 100
+void *count_lock;
+static int count;
+
+static THREAD_FN
+basic_thread(void *arg)
+{
+ struct cond_wait cw;
+ struct event_base *base = arg;
+ struct event ev;
+ int i = 0;
+
+ EVTHREAD_ALLOC_LOCK(cw.lock, 0);
+ EVTHREAD_ALLOC_COND(cw.cond);
+ assert(cw.lock);
+ assert(cw.cond);
+
+ evtimer_assign(&ev, base, wake_all_timeout, &cw);
+ for (i = 0; i < NUM_ITERATIONS; i++) {
+ struct timeval tv;
+ evutil_timerclear(&tv);
+ tv.tv_sec = 0;
+ tv.tv_usec = 3000;
+
+ EVLOCK_LOCK(cw.lock, 0);
+ /* we need to make sure that event does not happen before
+ * we get to wait on the conditional variable */
+ assert(evtimer_add(&ev, &tv) == 0);
+
+ assert(EVTHREAD_COND_WAIT(cw.cond, cw.lock) == 0);
+ EVLOCK_UNLOCK(cw.lock, 0);
+
+ EVLOCK_LOCK(count_lock, 0);
+ ++count;
+ EVLOCK_UNLOCK(count_lock, 0);
+ }
+
+ /* exit the loop only if all threads fired all timeouts */
+ EVLOCK_LOCK(count_lock, 0);
+ if (count >= NUM_THREADS * NUM_ITERATIONS)
+ event_base_loopexit(base, NULL);
+ EVLOCK_UNLOCK(count_lock, 0);
+
+ EVTHREAD_FREE_LOCK(cw.lock, 0);
+ EVTHREAD_FREE_COND(cw.cond);
+
+ THREAD_RETURN();
+}
+
+static int notification_fd_used = 0;
+#ifndef WIN32
+static int got_sigchld = 0;
+static void
+sigchld_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct timeval tv;
+ struct event_base *base = arg;
+
+ got_sigchld++;
+ tv.tv_usec = 100000;
+ tv.tv_sec = 0;
+ event_base_loopexit(base, &tv);
+}
+
+
+static void
+notify_fd_cb(evutil_socket_t fd, short event, void *arg)
+{
+ ++notification_fd_used;
+}
+#endif
+
+static void
+thread_basic(void *arg)
+{
+ THREAD_T threads[NUM_THREADS];
+ struct event ev;
+ struct timeval tv;
+ int i;
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+
+ struct event *notification_event = NULL;
+ struct event *sigchld_event = NULL;
+
+ EVTHREAD_ALLOC_LOCK(count_lock, 0);
+ tt_assert(count_lock);
+
+ tt_assert(base);
+ if (evthread_make_base_notifiable(base)<0) {
+ tt_abort_msg("Couldn't make base notifiable!");
+ }
+
+#ifndef WIN32
+ if (data->setup_data && !strcmp(data->setup_data, "forking")) {
+ pid_t pid;
+ int status;
+ sigchld_event = evsignal_new(base, SIGCHLD, sigchld_cb, base);
+ /* This piggybacks on the th_notify_fd weirdly, and looks
+ * inside libevent internals. Not a good idea in non-testing
+ * code! */
+ notification_event = event_new(base,
+ base->th_notify_fd[0], EV_READ|EV_PERSIST, notify_fd_cb,
+ NULL);
+ event_add(sigchld_event, NULL);
+ event_add(notification_event, NULL);
+
+ if ((pid = fork()) == 0) {
+ event_del(notification_event);
+ if (event_reinit(base) < 0) {
+ TT_FAIL(("reinit"));
+ exit(1);
+ }
+ event_assign(notification_event, base,
+ base->th_notify_fd[0], EV_READ|EV_PERSIST,
+ notify_fd_cb, NULL);
+ event_add(notification_event, NULL);
+ goto child;
+ }
+
+ event_base_dispatch(base);
+
+ if (waitpid(pid, &status, 0) == -1)
+ tt_abort_perror("waitpid");
+ TT_BLATHER(("Waitpid okay\n"));
+
+ tt_assert(got_sigchld);
+ tt_int_op(notification_fd_used, ==, 0);
+
+ goto end;
+ }
+
+child:
+#endif
+ for (i = 0; i < NUM_THREADS; ++i)
+ THREAD_START(threads[i], basic_thread, base);
+
+ evtimer_assign(&ev, base, NULL, NULL);
+ evutil_timerclear(&tv);
+ tv.tv_sec = 1000;
+ event_add(&ev, &tv);
+
+ event_base_dispatch(base);
+
+ for (i = 0; i < NUM_THREADS; ++i)
+ THREAD_JOIN(threads[i]);
+
+ event_del(&ev);
+
+ tt_int_op(count, ==, NUM_THREADS * NUM_ITERATIONS);
+
+ EVTHREAD_FREE_LOCK(count_lock, 0);
+
+ TT_BLATHER(("notifiations==%d", notification_fd_used));
+
+end:
+
+ if (notification_event)
+ event_free(notification_event);
+ if (sigchld_event)
+ event_free(sigchld_event);
+}
+
+#undef NUM_THREADS
+#define NUM_THREADS 10
+
+struct alerted_record {
+ struct cond_wait *cond;
+ struct timeval delay;
+ struct timeval alerted_at;
+ int timed_out;
+};
+
+static THREAD_FN
+wait_for_condition(void *arg)
+{
+ struct alerted_record *rec = arg;
+ int r;
+
+ EVLOCK_LOCK(rec->cond->lock, 0);
+ if (rec->delay.tv_sec || rec->delay.tv_usec) {
+ r = EVTHREAD_COND_WAIT_TIMED(rec->cond->cond, rec->cond->lock,
+ &rec->delay);
+ } else {
+ r = EVTHREAD_COND_WAIT(rec->cond->cond, rec->cond->lock);
+ }
+ EVLOCK_UNLOCK(rec->cond->lock, 0);
+
+ evutil_gettimeofday(&rec->alerted_at, NULL);
+ if (r == 1)
+ rec->timed_out = 1;
+
+ THREAD_RETURN();
+}
+
+static void
+thread_conditions_simple(void *arg)
+{
+ struct timeval tv_signal, tv_timeout, tv_broadcast;
+ struct alerted_record alerted[NUM_THREADS];
+ THREAD_T threads[NUM_THREADS];
+ struct cond_wait cond;
+ int i;
+ struct timeval launched_at;
+ struct event wake_one;
+ struct event wake_all;
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ int n_timed_out=0, n_signal=0, n_broadcast=0;
+
+ tv_signal.tv_sec = tv_timeout.tv_sec = tv_broadcast.tv_sec = 0;
+ tv_signal.tv_usec = 30*1000;
+ tv_timeout.tv_usec = 150*1000;
+ tv_broadcast.tv_usec = 500*1000;
+
+ EVTHREAD_ALLOC_LOCK(cond.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
+ EVTHREAD_ALLOC_COND(cond.cond);
+ tt_assert(cond.lock);
+ tt_assert(cond.cond);
+ for (i = 0; i < NUM_THREADS; ++i) {
+ memset(&alerted[i], 0, sizeof(struct alerted_record));
+ alerted[i].cond = &cond;
+ }
+
+ /* Threads 5 and 6 will be allowed to time out */
+ memcpy(&alerted[5].delay, &tv_timeout, sizeof(tv_timeout));
+ memcpy(&alerted[6].delay, &tv_timeout, sizeof(tv_timeout));
+
+ evtimer_assign(&wake_one, base, wake_one_timeout, &cond);
+ evtimer_assign(&wake_all, base, wake_all_timeout, &cond);
+
+ evutil_gettimeofday(&launched_at, NULL);
+
+ /* Launch the threads... */
+ for (i = 0; i < NUM_THREADS; ++i) {
+ THREAD_START(threads[i], wait_for_condition, &alerted[i]);
+ }
+
+ /* Start the timers... */
+ tt_int_op(event_add(&wake_one, &tv_signal), ==, 0);
+ tt_int_op(event_add(&wake_all, &tv_broadcast), ==, 0);
+
+ /* And run for a bit... */
+ event_base_dispatch(base);
+
+ /* And wait till the threads are done. */
+ for (i = 0; i < NUM_THREADS; ++i)
+ THREAD_JOIN(threads[i]);
+
+ /* Now, let's see what happened. At least one of 5 or 6 should
+ * have timed out. */
+ n_timed_out = alerted[5].timed_out + alerted[6].timed_out;
+ tt_int_op(n_timed_out, >=, 1);
+ tt_int_op(n_timed_out, <=, 2);
+
+ for (i = 0; i < NUM_THREADS; ++i) {
+ const struct timeval *target_delay;
+ struct timeval target_time, actual_delay;
+ if (alerted[i].timed_out) {
+ TT_BLATHER(("%d looks like a timeout\n", i));
+ target_delay = &tv_timeout;
+ tt_assert(i == 5 || i == 6);
+ } else if (evutil_timerisset(&alerted[i].alerted_at)) {
+ long diff1,diff2;
+ evutil_timersub(&alerted[i].alerted_at,
+ &launched_at, &actual_delay);
+ diff1 = timeval_msec_diff(&actual_delay,
+ &tv_signal);
+ diff2 = timeval_msec_diff(&actual_delay,
+ &tv_broadcast);
+ if (abs(diff1) < abs(diff2)) {
+ TT_BLATHER(("%d looks like a signal\n", i));
+ target_delay = &tv_signal;
+ ++n_signal;
+ } else {
+ TT_BLATHER(("%d looks like a broadcast\n", i));
+ target_delay = &tv_broadcast;
+ ++n_broadcast;
+ }
+ } else {
+ TT_FAIL(("Thread %d never got woken", i));
+ continue;
+ }
+ evutil_timeradd(target_delay, &launched_at, &target_time);
+ test_timeval_diff_leq(&target_time, &alerted[i].alerted_at,
+ 0, 50);
+ }
+ tt_int_op(n_broadcast + n_signal + n_timed_out, ==, NUM_THREADS);
+ tt_int_op(n_signal, ==, 1);
+
+end:
+ ;
+}
+
+#define CB_COUNT 128
+#define QUEUE_THREAD_COUNT 8
+
+#ifdef WIN32
+#define SLEEP_MS(ms) Sleep(ms)
+#else
+#define SLEEP_MS(ms) usleep((ms) * 1000)
+#endif
+
+struct deferred_test_data {
+ struct deferred_cb cbs[CB_COUNT];
+ struct deferred_cb_queue *queue;
+};
+
+static time_t timer_start = 0;
+static time_t timer_end = 0;
+static unsigned callback_count = 0;
+static THREAD_T load_threads[QUEUE_THREAD_COUNT];
+static struct deferred_test_data deferred_data[QUEUE_THREAD_COUNT];
+
+static void
+deferred_callback(struct deferred_cb *cb, void *arg)
+{
+ SLEEP_MS(1);
+ callback_count += 1;
+}
+
+static THREAD_FN
+load_deferred_queue(void *arg)
+{
+ struct deferred_test_data *data = arg;
+ size_t i;
+
+ for (i = 0; i < CB_COUNT; ++i) {
+ event_deferred_cb_init(&data->cbs[i], deferred_callback, NULL);
+ event_deferred_cb_schedule(data->queue, &data->cbs[i]);
+ SLEEP_MS(1);
+ }
+
+ THREAD_RETURN();
+}
+
+static void
+timer_callback(evutil_socket_t fd, short what, void *arg)
+{
+ timer_end = time(NULL);
+}
+
+static void
+start_threads_callback(evutil_socket_t fd, short what, void *arg)
+{
+ int i;
+
+ for (i = 0; i < QUEUE_THREAD_COUNT; ++i) {
+ THREAD_START(load_threads[i], load_deferred_queue,
+ &deferred_data[i]);
+ }
+}
+
+static void
+thread_deferred_cb_skew(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct timeval tv_timer = {4, 0};
+ struct deferred_cb_queue *queue;
+ time_t elapsed;
+ int i;
+
+ queue = event_base_get_deferred_cb_queue(data->base);
+ tt_assert(queue);
+
+ for (i = 0; i < QUEUE_THREAD_COUNT; ++i)
+ deferred_data[i].queue = queue;
+
+ timer_start = time(NULL);
+ event_base_once(data->base, -1, EV_TIMEOUT, timer_callback, NULL,
+ &tv_timer);
+ event_base_once(data->base, -1, EV_TIMEOUT, start_threads_callback,
+ NULL, NULL);
+ event_base_dispatch(data->base);
+
+ elapsed = timer_end - timer_start;
+ TT_BLATHER(("callback count, %u", callback_count));
+ TT_BLATHER(("elapsed time, %u", (unsigned)elapsed));
+ /* XXX be more intelligent here. just make sure skew is
+ * within 2 seconds for now. */
+ tt_assert(elapsed >= 4 && elapsed <= 6);
+
+end:
+ for (i = 0; i < QUEUE_THREAD_COUNT; ++i)
+ THREAD_JOIN(load_threads[i]);
+}
+
+#define TEST(name) \
+ { #name, thread_##name, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE, \
+ &basic_setup, NULL }
+
+struct testcase_t thread_testcases[] = {
+ { "basic", thread_basic, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE,
+ &basic_setup, NULL },
+#ifndef WIN32
+ { "forking", thread_basic, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE,
+ &basic_setup, (char*)"forking" },
+#endif
+ TEST(conditions_simple),
+ TEST(deferred_cb_skew),
+ END_OF_TESTCASES
+};
+
diff --git a/libevent-2.0.20-stable/test/regress_util.c b/libevent-2.0.20-stable/test/regress_util.c
new file mode 100644
index 0000000..71830a6
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress_util.c
@@ -0,0 +1,1094 @@
+/*
+ * Copyright (c) 2009-2012 Nick Mathewson and Niels Provos
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <ws2tcpip.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+
+#ifndef WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#endif
+#ifdef _EVENT_HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#ifdef _EVENT_HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "event2/event.h"
+#include "event2/util.h"
+#include "../ipv6-internal.h"
+#include "../util-internal.h"
+#include "../log-internal.h"
+#include "../strlcpy-internal.h"
+
+#include "regress.h"
+
+enum entry_status { NORMAL, CANONICAL, BAD };
+
+/* This is a big table of results we expect from generating and parsing */
+static struct ipv4_entry {
+ const char *addr;
+ ev_uint32_t res;
+ enum entry_status status;
+} ipv4_entries[] = {
+ { "1.2.3.4", 0x01020304u, CANONICAL },
+ { "255.255.255.255", 0xffffffffu, CANONICAL },
+ { "256.0.0.0", 0, BAD },
+ { "ABC", 0, BAD },
+ { "1.2.3.4.5", 0, BAD },
+ { "176.192.208.244", 0xb0c0d0f4, CANONICAL },
+ { NULL, 0, BAD },
+};
+
+static struct ipv6_entry {
+ const char *addr;
+ ev_uint32_t res[4];
+ enum entry_status status;
+} ipv6_entries[] = {
+ { "::", { 0, 0, 0, 0, }, CANONICAL },
+ { "0:0:0:0:0:0:0:0", { 0, 0, 0, 0, }, NORMAL },
+ { "::1", { 0, 0, 0, 1, }, CANONICAL },
+ { "::1.2.3.4", { 0, 0, 0, 0x01020304, }, CANONICAL },
+ { "ffff:1::", { 0xffff0001u, 0, 0, 0, }, CANONICAL },
+ { "ffff:0000::", { 0xffff0000u, 0, 0, 0, }, NORMAL },
+ { "ffff::1234", { 0xffff0000u, 0, 0, 0x1234, }, CANONICAL },
+ { "0102::1.2.3.4", {0x01020000u, 0, 0, 0x01020304u }, NORMAL },
+ { "::9:c0a8:1:1", { 0, 0, 0x0009c0a8u, 0x00010001u }, CANONICAL },
+ { "::ffff:1.2.3.4", { 0, 0, 0x000ffffu, 0x01020304u }, CANONICAL },
+ { "FFFF::", { 0xffff0000u, 0, 0, 0 }, NORMAL },
+ { "foobar.", { 0, 0, 0, 0 }, BAD },
+ { "foobar", { 0, 0, 0, 0 }, BAD },
+ { "fo:obar", { 0, 0, 0, 0 }, BAD },
+ { "ffff", { 0, 0, 0, 0 }, BAD },
+ { "fffff::", { 0, 0, 0, 0 }, BAD },
+ { "fffff::", { 0, 0, 0, 0 }, BAD },
+ { "::1.0.1.1000", { 0, 0, 0, 0 }, BAD },
+ { "1:2:33333:4::", { 0, 0, 0, 0 }, BAD },
+ { "1:2:3:4:5:6:7:8:9", { 0, 0, 0, 0 }, BAD },
+ { "1::2::3", { 0, 0, 0, 0 }, BAD },
+ { ":::1", { 0, 0, 0, 0 }, BAD },
+ { NULL, { 0, 0, 0, 0, }, BAD },
+};
+
+static void
+regress_ipv4_parse(void *ptr)
+{
+ int i;
+ for (i = 0; ipv4_entries[i].addr; ++i) {
+ char written[128];
+ struct ipv4_entry *ent = &ipv4_entries[i];
+ struct in_addr in;
+ int r;
+ r = evutil_inet_pton(AF_INET, ent->addr, &in);
+ if (r == 0) {
+ if (ent->status != BAD) {
+ TT_FAIL(("%s did not parse, but it's a good address!",
+ ent->addr));
+ }
+ continue;
+ }
+ if (ent->status == BAD) {
+ TT_FAIL(("%s parsed, but we expected an error", ent->addr));
+ continue;
+ }
+ if (ntohl(in.s_addr) != ent->res) {
+ TT_FAIL(("%s parsed to %lx, but we expected %lx", ent->addr,
+ (unsigned long)ntohl(in.s_addr),
+ (unsigned long)ent->res));
+ continue;
+ }
+ if (ent->status == CANONICAL) {
+ const char *w = evutil_inet_ntop(AF_INET, &in, written,
+ sizeof(written));
+ if (!w) {
+ TT_FAIL(("Tried to write out %s; got NULL.", ent->addr));
+ continue;
+ }
+ if (strcmp(written, ent->addr)) {
+ TT_FAIL(("Tried to write out %s; got %s",
+ ent->addr, written));
+ continue;
+ }
+ }
+
+ }
+
+}
+
+static void
+regress_ipv6_parse(void *ptr)
+{
+#ifdef AF_INET6
+ int i, j;
+
+ for (i = 0; ipv6_entries[i].addr; ++i) {
+ char written[128];
+ struct ipv6_entry *ent = &ipv6_entries[i];
+ struct in6_addr in6;
+ int r;
+ r = evutil_inet_pton(AF_INET6, ent->addr, &in6);
+ if (r == 0) {
+ if (ent->status != BAD)
+ TT_FAIL(("%s did not parse, but it's a good address!",
+ ent->addr));
+ continue;
+ }
+ if (ent->status == BAD) {
+ TT_FAIL(("%s parsed, but we expected an error", ent->addr));
+ continue;
+ }
+ for (j = 0; j < 4; ++j) {
+ /* Can't use s6_addr32 here; some don't have it. */
+ ev_uint32_t u =
+ (in6.s6_addr[j*4 ] << 24) |
+ (in6.s6_addr[j*4+1] << 16) |
+ (in6.s6_addr[j*4+2] << 8) |
+ (in6.s6_addr[j*4+3]);
+ if (u != ent->res[j]) {
+ TT_FAIL(("%s did not parse as expected.", ent->addr));
+ continue;
+ }
+ }
+ if (ent->status == CANONICAL) {
+ const char *w = evutil_inet_ntop(AF_INET6, &in6, written,
+ sizeof(written));
+ if (!w) {
+ TT_FAIL(("Tried to write out %s; got NULL.", ent->addr));
+ continue;
+ }
+ if (strcmp(written, ent->addr)) {
+ TT_FAIL(("Tried to write out %s; got %s", ent->addr, written));
+ continue;
+ }
+ }
+
+ }
+#else
+ TT_BLATHER(("Skipping IPv6 address parsing."));
+#endif
+}
+
+static struct sa_port_ent {
+ const char *parse;
+ int safamily;
+ const char *addr;
+ int port;
+} sa_port_ents[] = {
+ { "[ffff::1]:1000", AF_INET6, "ffff::1", 1000 },
+ { "[ffff::1]", AF_INET6, "ffff::1", 0 },
+ { "[ffff::1", 0, NULL, 0 },
+ { "[ffff::1]:65599", 0, NULL, 0 },
+ { "[ffff::1]:0", 0, NULL, 0 },
+ { "[ffff::1]:-1", 0, NULL, 0 },
+ { "::1", AF_INET6, "::1", 0 },
+ { "1:2::1", AF_INET6, "1:2::1", 0 },
+ { "192.168.0.1:50", AF_INET, "192.168.0.1", 50 },
+ { "1.2.3.4", AF_INET, "1.2.3.4", 0 },
+ { NULL, 0, NULL, 0 },
+};
+
+static void
+regress_sockaddr_port_parse(void *ptr)
+{
+ struct sockaddr_storage ss;
+ int i, r;
+
+ for (i = 0; sa_port_ents[i].parse; ++i) {
+ struct sa_port_ent *ent = &sa_port_ents[i];
+ int len = sizeof(ss);
+ memset(&ss, 0, sizeof(ss));
+ r = evutil_parse_sockaddr_port(ent->parse, (struct sockaddr*)&ss, &len);
+ if (r < 0) {
+ if (ent->safamily)
+ TT_FAIL(("Couldn't parse %s!", ent->parse));
+ continue;
+ } else if (! ent->safamily) {
+ TT_FAIL(("Shouldn't have been able to parse %s!", ent->parse));
+ continue;
+ }
+ if (ent->safamily == AF_INET) {
+ struct sockaddr_in sin;
+ memset(&sin, 0, sizeof(sin));
+#ifdef _EVENT_HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+ sin.sin_len = sizeof(sin);
+#endif
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(ent->port);
+ r = evutil_inet_pton(AF_INET, ent->addr, &sin.sin_addr);
+ if (1 != r) {
+ TT_FAIL(("Couldn't parse ipv4 target %s.", ent->addr));
+ } else if (memcmp(&sin, &ss, sizeof(sin))) {
+ TT_FAIL(("Parse for %s was not as expected.", ent->parse));
+ } else if (len != sizeof(sin)) {
+ TT_FAIL(("Length for %s not as expected.",ent->parse));
+ }
+ } else {
+ struct sockaddr_in6 sin6;
+ memset(&sin6, 0, sizeof(sin6));
+#ifdef _EVENT_HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
+ sin6.sin6_len = sizeof(sin6);
+#endif
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons(ent->port);
+ r = evutil_inet_pton(AF_INET6, ent->addr, &sin6.sin6_addr);
+ if (1 != r) {
+ TT_FAIL(("Couldn't parse ipv6 target %s.", ent->addr));
+ } else if (memcmp(&sin6, &ss, sizeof(sin6))) {
+ TT_FAIL(("Parse for %s was not as expected.", ent->parse));
+ } else if (len != sizeof(sin6)) {
+ TT_FAIL(("Length for %s not as expected.",ent->parse));
+ }
+ }
+ }
+}
+
+
+static void
+regress_sockaddr_port_format(void *ptr)
+{
+ struct sockaddr_storage ss;
+ int len;
+ const char *cp;
+ char cbuf[128];
+ int r;
+
+ len = sizeof(ss);
+ r = evutil_parse_sockaddr_port("192.168.1.1:80",
+ (struct sockaddr*)&ss, &len);
+ tt_int_op(r,==,0);
+ cp = evutil_format_sockaddr_port(
+ (struct sockaddr*)&ss, cbuf, sizeof(cbuf));
+ tt_ptr_op(cp,==,cbuf);
+ tt_str_op(cp,==,"192.168.1.1:80");
+
+ len = sizeof(ss);
+ r = evutil_parse_sockaddr_port("[ff00::8010]:999",
+ (struct sockaddr*)&ss, &len);
+ tt_int_op(r,==,0);
+ cp = evutil_format_sockaddr_port(
+ (struct sockaddr*)&ss, cbuf, sizeof(cbuf));
+ tt_ptr_op(cp,==,cbuf);
+ tt_str_op(cp,==,"[ff00::8010]:999");
+
+ ss.ss_family=99;
+ cp = evutil_format_sockaddr_port(
+ (struct sockaddr*)&ss, cbuf, sizeof(cbuf));
+ tt_ptr_op(cp,==,cbuf);
+ tt_str_op(cp,==,"<addr with socktype 99>");
+end:
+ ;
+}
+
+static struct sa_pred_ent {
+ const char *parse;
+
+ int is_loopback;
+} sa_pred_entries[] = {
+ { "127.0.0.1", 1 },
+ { "127.0.3.2", 1 },
+ { "128.1.2.3", 0 },
+ { "18.0.0.1", 0 },
+ { "129.168.1.1", 0 },
+
+ { "::1", 1 },
+ { "::0", 0 },
+ { "f::1", 0 },
+ { "::501", 0 },
+ { NULL, 0 },
+
+};
+
+static void
+test_evutil_sockaddr_predicates(void *ptr)
+{
+ struct sockaddr_storage ss;
+ int r, i;
+
+ for (i=0; sa_pred_entries[i].parse; ++i) {
+ struct sa_pred_ent *ent = &sa_pred_entries[i];
+ int len = sizeof(ss);
+
+ r = evutil_parse_sockaddr_port(ent->parse, (struct sockaddr*)&ss, &len);
+
+ if (r<0) {
+ TT_FAIL(("Couldn't parse %s!", ent->parse));
+ continue;
+ }
+
+ /* sockaddr_is_loopback */
+ if (ent->is_loopback != evutil_sockaddr_is_loopback((struct sockaddr*)&ss)) {
+ TT_FAIL(("evutil_sockaddr_loopback(%s) not as expected",
+ ent->parse));
+ }
+ }
+}
+
+static void
+test_evutil_strtoll(void *ptr)
+{
+ const char *s;
+ char *endptr;
+
+ tt_want(evutil_strtoll("5000000000", NULL, 10) ==
+ ((ev_int64_t)5000000)*1000);
+ tt_want(evutil_strtoll("-5000000000", NULL, 10) ==
+ ((ev_int64_t)5000000)*-1000);
+ s = " 99999stuff";
+ tt_want(evutil_strtoll(s, &endptr, 10) == (ev_int64_t)99999);
+ tt_want(endptr == s+6);
+ tt_want(evutil_strtoll("foo", NULL, 10) == 0);
+ }
+
+static void
+test_evutil_snprintf(void *ptr)
+{
+ char buf[16];
+ int r;
+ ev_uint64_t u64 = ((ev_uint64_t)1000000000)*200;
+ ev_int64_t i64 = -1 * (ev_int64_t) u64;
+ size_t size = 8000;
+ ev_ssize_t ssize = -9000;
+
+ r = evutil_snprintf(buf, sizeof(buf), "%d %d", 50, 100);
+ tt_str_op(buf, ==, "50 100");
+ tt_int_op(r, ==, 6);
+
+ r = evutil_snprintf(buf, sizeof(buf), "longish %d", 1234567890);
+ tt_str_op(buf, ==, "longish 1234567");
+ tt_int_op(r, ==, 18);
+
+ r = evutil_snprintf(buf, sizeof(buf), EV_U64_FMT, EV_U64_ARG(u64));
+ tt_str_op(buf, ==, "200000000000");
+ tt_int_op(r, ==, 12);
+
+ r = evutil_snprintf(buf, sizeof(buf), EV_I64_FMT, EV_I64_ARG(i64));
+ tt_str_op(buf, ==, "-200000000000");
+ tt_int_op(r, ==, 13);
+
+ r = evutil_snprintf(buf, sizeof(buf), EV_SIZE_FMT" "EV_SSIZE_FMT,
+ EV_SIZE_ARG(size), EV_SSIZE_ARG(ssize));
+ tt_str_op(buf, ==, "8000 -9000");
+ tt_int_op(r, ==, 10);
+
+ end:
+ ;
+}
+
+static void
+test_evutil_casecmp(void *ptr)
+{
+ tt_int_op(evutil_ascii_strcasecmp("ABC", "ABC"), ==, 0);
+ tt_int_op(evutil_ascii_strcasecmp("ABC", "abc"), ==, 0);
+ tt_int_op(evutil_ascii_strcasecmp("ABC", "abcd"), <, 0);
+ tt_int_op(evutil_ascii_strcasecmp("ABC", "abb"), >, 0);
+ tt_int_op(evutil_ascii_strcasecmp("ABCd", "abc"), >, 0);
+
+ tt_int_op(evutil_ascii_strncasecmp("Libevent", "LibEvEnT", 100), ==, 0);
+ tt_int_op(evutil_ascii_strncasecmp("Libevent", "LibEvEnT", 4), ==, 0);
+ tt_int_op(evutil_ascii_strncasecmp("Libevent", "LibEXXXX", 4), ==, 0);
+ tt_int_op(evutil_ascii_strncasecmp("Libevent", "LibE", 4), ==, 0);
+ tt_int_op(evutil_ascii_strncasecmp("Libe", "LibEvEnT", 4), ==, 0);
+ tt_int_op(evutil_ascii_strncasecmp("Lib", "LibEvEnT", 4), <, 0);
+ tt_int_op(evutil_ascii_strncasecmp("abc", "def", 99), <, 0);
+ tt_int_op(evutil_ascii_strncasecmp("Z", "qrst", 1), >, 0);
+end:
+ ;
+}
+
+static int logsev = 0;
+static char *logmsg = NULL;
+
+static void
+logfn(int severity, const char *msg)
+{
+ logsev = severity;
+ tt_want(msg);
+ if (msg) {
+ if (logmsg)
+ free(logmsg);
+ logmsg = strdup(msg);
+ }
+}
+
+static int fatal_want_severity = 0;
+static const char *fatal_want_message = NULL;
+static void
+fatalfn(int exitcode)
+{
+ if (logsev != fatal_want_severity ||
+ !logmsg ||
+ strcmp(logmsg, fatal_want_message))
+ exit(0);
+ else
+ exit(exitcode);
+}
+
+#ifndef WIN32
+#define CAN_CHECK_ERR
+static void
+check_error_logging(void (*fn)(void), int wantexitcode,
+ int wantseverity, const char *wantmsg)
+{
+ pid_t pid;
+ int status = 0, exitcode;
+ fatal_want_severity = wantseverity;
+ fatal_want_message = wantmsg;
+ if ((pid = regress_fork()) == 0) {
+ /* child process */
+ fn();
+ exit(0); /* should be unreachable. */
+ } else {
+ wait(&status);
+ exitcode = WEXITSTATUS(status);
+ tt_int_op(wantexitcode, ==, exitcode);
+ }
+end:
+ ;
+}
+
+static void
+errx_fn(void)
+{
+ event_errx(2, "Fatal error; too many kumquats (%d)", 5);
+}
+
+static void
+err_fn(void)
+{
+ errno = ENOENT;
+ event_err(5,"Couldn't open %s", "/very/bad/file");
+}
+
+static void
+sock_err_fn(void)
+{
+ evutil_socket_t fd = socket(AF_INET, SOCK_STREAM, 0);
+#ifdef WIN32
+ EVUTIL_SET_SOCKET_ERROR(WSAEWOULDBLOCK);
+#else
+ errno = EAGAIN;
+#endif
+ event_sock_err(20, fd, "Unhappy socket");
+}
+#endif
+
+static void
+test_evutil_log(void *ptr)
+{
+ evutil_socket_t fd = -1;
+ char buf[128];
+
+ event_set_log_callback(logfn);
+ event_set_fatal_callback(fatalfn);
+#define RESET() do { \
+ logsev = 0; \
+ if (logmsg) free(logmsg); \
+ logmsg = NULL; \
+ } while (0)
+#define LOGEQ(sev,msg) do { \
+ tt_int_op(logsev,==,sev); \
+ tt_assert(logmsg != NULL); \
+ tt_str_op(logmsg,==,msg); \
+ } while (0)
+
+#ifdef CAN_CHECK_ERR
+ /* We need to disable these tests for now. Previously, the logging
+ * module didn't enforce the requirement that a fatal callback
+ * actually exit. Now, it exits no matter what, so if we wan to
+ * reinstate these tests, we'll need to fork for each one. */
+ check_error_logging(errx_fn, 2, _EVENT_LOG_ERR,
+ "Fatal error; too many kumquats (5)");
+ RESET();
+#endif
+
+ event_warnx("Far too many %s (%d)", "wombats", 99);
+ LOGEQ(_EVENT_LOG_WARN, "Far too many wombats (99)");
+ RESET();
+
+ event_msgx("Connecting lime to coconut");
+ LOGEQ(_EVENT_LOG_MSG, "Connecting lime to coconut");
+ RESET();
+
+ event_debug(("A millisecond passed! We should log that!"));
+#ifdef USE_DEBUG
+ LOGEQ(_EVENT_LOG_DEBUG, "A millisecond passed! We should log that!");
+#else
+ tt_int_op(logsev,==,0);
+ tt_ptr_op(logmsg,==,NULL);
+#endif
+ RESET();
+
+ /* Try with an errno. */
+ errno = ENOENT;
+ event_warn("Couldn't open %s", "/bad/file");
+ evutil_snprintf(buf, sizeof(buf),
+ "Couldn't open /bad/file: %s",strerror(ENOENT));
+ LOGEQ(_EVENT_LOG_WARN,buf);
+ RESET();
+
+#ifdef CAN_CHECK_ERR
+ evutil_snprintf(buf, sizeof(buf),
+ "Couldn't open /very/bad/file: %s",strerror(ENOENT));
+ check_error_logging(err_fn, 5, _EVENT_LOG_ERR, buf);
+ RESET();
+#endif
+
+ /* Try with a socket errno. */
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+#ifdef WIN32
+ evutil_snprintf(buf, sizeof(buf),
+ "Unhappy socket: %s",
+ evutil_socket_error_to_string(WSAEWOULDBLOCK));
+ EVUTIL_SET_SOCKET_ERROR(WSAEWOULDBLOCK);
+#else
+ evutil_snprintf(buf, sizeof(buf),
+ "Unhappy socket: %s", strerror(EAGAIN));
+ errno = EAGAIN;
+#endif
+ event_sock_warn(fd, "Unhappy socket");
+ LOGEQ(_EVENT_LOG_WARN, buf);
+ RESET();
+
+#ifdef CAN_CHECK_ERR
+ check_error_logging(sock_err_fn, 20, _EVENT_LOG_ERR, buf);
+ RESET();
+#endif
+
+#undef RESET
+#undef LOGEQ
+end:
+ if (logmsg)
+ free(logmsg);
+ if (fd >= 0)
+ evutil_closesocket(fd);
+}
+
+static void
+test_evutil_strlcpy(void *arg)
+{
+ char buf[8];
+
+ /* Successful case. */
+ tt_int_op(5, ==, strlcpy(buf, "Hello", sizeof(buf)));
+ tt_str_op(buf, ==, "Hello");
+
+ /* Overflow by a lot. */
+ tt_int_op(13, ==, strlcpy(buf, "pentasyllabic", sizeof(buf)));
+ tt_str_op(buf, ==, "pentasy");
+
+ /* Overflow by exactly one. */
+ tt_int_op(8, ==, strlcpy(buf, "overlong", sizeof(buf)));
+ tt_str_op(buf, ==, "overlon");
+end:
+ ;
+}
+
+struct example_struct {
+ const char *a;
+ const char *b;
+ long c;
+};
+
+static void
+test_evutil_upcast(void *arg)
+{
+ struct example_struct es1;
+ const char **cp;
+ es1.a = "World";
+ es1.b = "Hello";
+ es1.c = -99;
+
+ tt_int_op(evutil_offsetof(struct example_struct, b), ==, sizeof(char*));
+
+ cp = &es1.b;
+ tt_ptr_op(EVUTIL_UPCAST(cp, struct example_struct, b), ==, &es1);
+
+end:
+ ;
+}
+
+static void
+test_evutil_integers(void *arg)
+{
+ ev_int64_t i64;
+ ev_uint64_t u64;
+ ev_int32_t i32;
+ ev_uint32_t u32;
+ ev_int16_t i16;
+ ev_uint16_t u16;
+ ev_int8_t i8;
+ ev_uint8_t u8;
+
+ void *ptr;
+ ev_intptr_t iptr;
+ ev_uintptr_t uptr;
+
+ ev_ssize_t ssize;
+
+ tt_int_op(sizeof(u64), ==, 8);
+ tt_int_op(sizeof(i64), ==, 8);
+ tt_int_op(sizeof(u32), ==, 4);
+ tt_int_op(sizeof(i32), ==, 4);
+ tt_int_op(sizeof(u16), ==, 2);
+ tt_int_op(sizeof(i16), ==, 2);
+ tt_int_op(sizeof(u8), ==, 1);
+ tt_int_op(sizeof(i8), ==, 1);
+
+ tt_int_op(sizeof(ev_ssize_t), ==, sizeof(size_t));
+ tt_int_op(sizeof(ev_intptr_t), >=, sizeof(void *));
+ tt_int_op(sizeof(ev_uintptr_t), ==, sizeof(intptr_t));
+
+ u64 = 1000000000;
+ u64 *= 1000000000;
+ tt_assert(u64 / 1000000000 == 1000000000);
+ i64 = -1000000000;
+ i64 *= 1000000000;
+ tt_assert(i64 / 1000000000 == -1000000000);
+
+ u64 = EV_UINT64_MAX;
+ i64 = EV_INT64_MAX;
+ tt_assert(u64 > 0);
+ tt_assert(i64 > 0);
+ u64++;
+ i64++;
+ tt_assert(u64 == 0);
+ tt_assert(i64 == EV_INT64_MIN);
+ tt_assert(i64 < 0);
+
+ u32 = EV_UINT32_MAX;
+ i32 = EV_INT32_MAX;
+ tt_assert(u32 > 0);
+ tt_assert(i32 > 0);
+ u32++;
+ i32++;
+ tt_assert(u32 == 0);
+ tt_assert(i32 == EV_INT32_MIN);
+ tt_assert(i32 < 0);
+
+ u16 = EV_UINT16_MAX;
+ i16 = EV_INT16_MAX;
+ tt_assert(u16 > 0);
+ tt_assert(i16 > 0);
+ u16++;
+ i16++;
+ tt_assert(u16 == 0);
+ tt_assert(i16 == EV_INT16_MIN);
+ tt_assert(i16 < 0);
+
+ u8 = EV_UINT8_MAX;
+ i8 = EV_INT8_MAX;
+ tt_assert(u8 > 0);
+ tt_assert(i8 > 0);
+ u8++;
+ i8++;
+ tt_assert(u8 == 0);
+ tt_assert(i8 == EV_INT8_MIN);
+ tt_assert(i8 < 0);
+
+ ssize = EV_SSIZE_MAX;
+ tt_assert(ssize > 0);
+ ssize++;
+ tt_assert(ssize < 0);
+ tt_assert(ssize == EV_SSIZE_MIN);
+
+ ptr = &ssize;
+ iptr = (ev_intptr_t)ptr;
+ uptr = (ev_uintptr_t)ptr;
+ ptr = (void *)iptr;
+ tt_assert(ptr == &ssize);
+ ptr = (void *)uptr;
+ tt_assert(ptr == &ssize);
+
+ iptr = -1;
+ tt_assert(iptr < 0);
+end:
+ ;
+}
+
+struct evutil_addrinfo *
+ai_find_by_family(struct evutil_addrinfo *ai, int family)
+{
+ while (ai) {
+ if (ai->ai_family == family)
+ return ai;
+ ai = ai->ai_next;
+ }
+ return NULL;
+}
+
+struct evutil_addrinfo *
+ai_find_by_protocol(struct evutil_addrinfo *ai, int protocol)
+{
+ while (ai) {
+ if (ai->ai_protocol == protocol)
+ return ai;
+ ai = ai->ai_next;
+ }
+ return NULL;
+}
+
+
+int
+_test_ai_eq(const struct evutil_addrinfo *ai, const char *sockaddr_port,
+ int socktype, int protocol, int line)
+{
+ struct sockaddr_storage ss;
+ int slen = sizeof(ss);
+ int gotport;
+ char buf[128];
+ memset(&ss, 0, sizeof(ss));
+ if (socktype > 0)
+ tt_int_op(ai->ai_socktype, ==, socktype);
+ if (protocol > 0)
+ tt_int_op(ai->ai_protocol, ==, protocol);
+
+ if (evutil_parse_sockaddr_port(
+ sockaddr_port, (struct sockaddr*)&ss, &slen)<0) {
+ TT_FAIL(("Couldn't parse expected address %s on line %d",
+ sockaddr_port, line));
+ return -1;
+ }
+ if (ai->ai_family != ss.ss_family) {
+ TT_FAIL(("Address family %d did not match %d on line %d",
+ ai->ai_family, ss.ss_family, line));
+ return -1;
+ }
+ if (ai->ai_addr->sa_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in*)ai->ai_addr;
+ evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf));
+ gotport = ntohs(sin->sin_port);
+ if (ai->ai_addrlen != sizeof(struct sockaddr_in)) {
+ TT_FAIL(("Addr size mismatch on line %d", line));
+ return -1;
+ }
+ } else {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)ai->ai_addr;
+ evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, sizeof(buf));
+ gotport = ntohs(sin6->sin6_port);
+ if (ai->ai_addrlen != sizeof(struct sockaddr_in6)) {
+ TT_FAIL(("Addr size mismatch on line %d", line));
+ return -1;
+ }
+ }
+ if (evutil_sockaddr_cmp(ai->ai_addr, (struct sockaddr*)&ss, 1)) {
+ TT_FAIL(("Wanted %s, got %s:%d on line %d", sockaddr_port,
+ buf, gotport, line));
+ return -1;
+ } else {
+ TT_BLATHER(("Wanted %s, got %s:%d on line %d", sockaddr_port,
+ buf, gotport, line));
+ }
+ return 0;
+end:
+ TT_FAIL(("Test failed on line %d", line));
+ return -1;
+}
+
+static void
+test_evutil_rand(void *arg)
+{
+ char buf1[32];
+ char buf2[32];
+ int counts[256];
+ int i, j, k, n=0;
+
+ memset(buf2, 0, sizeof(buf2));
+ memset(counts, 0, sizeof(counts));
+
+ for (k=0;k<32;++k) {
+ /* Try a few different start and end points; try to catch
+ * the various misaligned cases of arc4random_buf */
+ int startpoint = _evutil_weakrand() % 4;
+ int endpoint = 32 - (_evutil_weakrand() % 4);
+
+ memset(buf2, 0, sizeof(buf2));
+
+ /* Do 6 runs over buf1, or-ing the result into buf2 each
+ * time, to make sure we're setting each byte that we mean
+ * to set. */
+ for (i=0;i<8;++i) {
+ memset(buf1, 0, sizeof(buf1));
+ evutil_secure_rng_get_bytes(buf1 + startpoint,
+ endpoint-startpoint);
+ n += endpoint - startpoint;
+ for (j=0; j<32; ++j) {
+ if (j >= startpoint && j < endpoint) {
+ buf2[j] |= buf1[j];
+ ++counts[(unsigned char)buf1[j]];
+ } else {
+ tt_assert(buf1[j] == 0);
+ tt_int_op(buf1[j], ==, 0);
+
+ }
+ }
+ }
+
+ /* This will give a false positive with P=(256**8)==(2**64)
+ * for each character. */
+ for (j=startpoint;j<endpoint;++j) {
+ tt_int_op(buf2[j], !=, 0);
+ }
+ }
+
+ /* for (i=0;i<256;++i) { printf("%3d %2d\n", i, counts[i]); } */
+end:
+ ;
+}
+
+static void
+test_evutil_getaddrinfo(void *arg)
+{
+ struct evutil_addrinfo *ai = NULL, *a;
+ struct evutil_addrinfo hints;
+
+ struct sockaddr_in6 *sin6;
+ struct sockaddr_in *sin;
+ char buf[128];
+ const char *cp;
+ int r;
+
+ /* Try using it as a pton. */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ r = evutil_getaddrinfo("1.2.3.4", "8080", &hints, &ai);
+ tt_int_op(r, ==, 0);
+ tt_assert(ai);
+ tt_ptr_op(ai->ai_next, ==, NULL); /* no ambiguity */
+ test_ai_eq(ai, "1.2.3.4:8080", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_protocol = IPPROTO_UDP;
+ r = evutil_getaddrinfo("1001:b0b::f00f", "4321", &hints, &ai);
+ tt_int_op(r, ==, 0);
+ tt_assert(ai);
+ tt_ptr_op(ai->ai_next, ==, NULL); /* no ambiguity */
+ test_ai_eq(ai, "[1001:b0b::f00f]:4321", SOCK_DGRAM, IPPROTO_UDP);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+
+ /* Try out the behavior of nodename=NULL */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_INET;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_flags = EVUTIL_AI_PASSIVE; /* as if for bind */
+ r = evutil_getaddrinfo(NULL, "9999", &hints, &ai);
+ tt_int_op(r,==,0);
+ tt_assert(ai);
+ tt_ptr_op(ai->ai_next, ==, NULL);
+ test_ai_eq(ai, "0.0.0.0:9999", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+ hints.ai_flags = 0; /* as if for connect */
+ r = evutil_getaddrinfo(NULL, "9998", &hints, &ai);
+ tt_assert(ai);
+ tt_int_op(r,==,0);
+ test_ai_eq(ai, "127.0.0.1:9998", SOCK_STREAM, IPPROTO_TCP);
+ tt_ptr_op(ai->ai_next, ==, NULL);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+
+ hints.ai_flags = 0; /* as if for connect */
+ hints.ai_family = PF_INET6;
+ r = evutil_getaddrinfo(NULL, "9997", &hints, &ai);
+ tt_assert(ai);
+ tt_int_op(r,==,0);
+ tt_ptr_op(ai->ai_next, ==, NULL);
+ test_ai_eq(ai, "[::1]:9997", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+
+ hints.ai_flags = EVUTIL_AI_PASSIVE; /* as if for bind. */
+ hints.ai_family = PF_INET6;
+ r = evutil_getaddrinfo(NULL, "9996", &hints, &ai);
+ tt_assert(ai);
+ tt_int_op(r,==,0);
+ tt_ptr_op(ai->ai_next, ==, NULL);
+ test_ai_eq(ai, "[::]:9996", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+
+ /* Now try an unspec one. We should get a v6 and a v4. */
+ hints.ai_family = PF_UNSPEC;
+ r = evutil_getaddrinfo(NULL, "9996", &hints, &ai);
+ tt_assert(ai);
+ tt_int_op(r,==,0);
+ a = ai_find_by_family(ai, PF_INET6);
+ tt_assert(a);
+ test_ai_eq(a, "[::]:9996", SOCK_STREAM, IPPROTO_TCP);
+ a = ai_find_by_family(ai, PF_INET);
+ tt_assert(a);
+ test_ai_eq(a, "0.0.0.0:9996", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+
+ /* Try out AI_NUMERICHOST: successful case. Also try
+ * multiprotocol. */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = EVUTIL_AI_NUMERICHOST;
+ r = evutil_getaddrinfo("1.2.3.4", NULL, &hints, &ai);
+ tt_int_op(r, ==, 0);
+ a = ai_find_by_protocol(ai, IPPROTO_TCP);
+ tt_assert(a);
+ test_ai_eq(a, "1.2.3.4", SOCK_STREAM, IPPROTO_TCP);
+ a = ai_find_by_protocol(ai, IPPROTO_UDP);
+ tt_assert(a);
+ test_ai_eq(a, "1.2.3.4", SOCK_DGRAM, IPPROTO_UDP);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+
+ /* Try the failing case of AI_NUMERICHOST */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = EVUTIL_AI_NUMERICHOST;
+ r = evutil_getaddrinfo("www.google.com", "80", &hints, &ai);
+ tt_int_op(r, ==, EVUTIL_EAI_NONAME);
+ tt_int_op(ai, ==, NULL);
+
+ /* Try symbolic service names wit AI_NUMERICSERV */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = EVUTIL_AI_NUMERICSERV;
+ r = evutil_getaddrinfo("1.2.3.4", "http", &hints, &ai);
+ tt_int_op(r,==,EVUTIL_EAI_NONAME);
+
+ /* Try symbolic service names */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ r = evutil_getaddrinfo("1.2.3.4", "http", &hints, &ai);
+ if (r!=0) {
+ TT_DECLARE("SKIP", ("Symbolic service names seem broken."));
+ } else {
+ tt_assert(ai);
+ test_ai_eq(ai, "1.2.3.4:80", SOCK_STREAM, IPPROTO_TCP);
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+ }
+
+ /* Now do some actual lookups. */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_INET;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_socktype = SOCK_STREAM;
+ r = evutil_getaddrinfo("www.google.com", "80", &hints, &ai);
+ if (r != 0) {
+ TT_DECLARE("SKIP", ("Couldn't resolve www.google.com"));
+ } else {
+ tt_assert(ai);
+ tt_int_op(ai->ai_family, ==, PF_INET);
+ tt_int_op(ai->ai_protocol, ==, IPPROTO_TCP);
+ tt_int_op(ai->ai_socktype, ==, SOCK_STREAM);
+ tt_int_op(ai->ai_addrlen, ==, sizeof(struct sockaddr_in));
+ sin = (struct sockaddr_in*)ai->ai_addr;
+ tt_int_op(sin->sin_family, ==, AF_INET);
+ tt_int_op(sin->sin_port, ==, htons(80));
+ tt_int_op(sin->sin_addr.s_addr, !=, 0xffffffff);
+
+ cp = evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf));
+ TT_BLATHER(("www.google.com resolved to %s",
+ cp?cp:"<unwriteable>"));
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+ }
+
+ hints.ai_family = PF_INET6;
+ r = evutil_getaddrinfo("ipv6.google.com", "80", &hints, &ai);
+ if (r != 0) {
+ TT_BLATHER(("Couldn't do an ipv6 lookup for ipv6.google.com"));
+ } else {
+ tt_assert(ai);
+ tt_int_op(ai->ai_family, ==, PF_INET6);
+ tt_int_op(ai->ai_addrlen, ==, sizeof(struct sockaddr_in6));
+ sin6 = (struct sockaddr_in6*)ai->ai_addr;
+ tt_int_op(sin6->sin6_port, ==, htons(80));
+
+ cp = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf,
+ sizeof(buf));
+ TT_BLATHER(("ipv6.google.com resolved to %s",
+ cp?cp:"<unwriteable>"));
+ }
+
+end:
+ if (ai)
+ evutil_freeaddrinfo(ai);
+}
+
+#ifdef WIN32
+static void
+test_evutil_loadsyslib(void *arg)
+{
+ HANDLE h=NULL;
+
+ h = evutil_load_windows_system_library(TEXT("kernel32.dll"));
+ tt_assert(h);
+
+end:
+ if (h)
+ CloseHandle(h);
+
+}
+#endif
+
+struct testcase_t util_testcases[] = {
+ { "ipv4_parse", regress_ipv4_parse, 0, NULL, NULL },
+ { "ipv6_parse", regress_ipv6_parse, 0, NULL, NULL },
+ { "sockaddr_port_parse", regress_sockaddr_port_parse, 0, NULL, NULL },
+ { "sockaddr_port_format", regress_sockaddr_port_format, 0, NULL, NULL },
+ { "sockaddr_predicates", test_evutil_sockaddr_predicates, 0,NULL,NULL },
+ { "evutil_snprintf", test_evutil_snprintf, 0, NULL, NULL },
+ { "evutil_strtoll", test_evutil_strtoll, 0, NULL, NULL },
+ { "evutil_casecmp", test_evutil_casecmp, 0, NULL, NULL },
+ { "strlcpy", test_evutil_strlcpy, 0, NULL, NULL },
+ { "log", test_evutil_log, TT_FORK, NULL, NULL },
+ { "upcast", test_evutil_upcast, 0, NULL, NULL },
+ { "integers", test_evutil_integers, 0, NULL, NULL },
+ { "rand", test_evutil_rand, TT_FORK, NULL, NULL },
+ { "getaddrinfo", test_evutil_getaddrinfo, TT_FORK, NULL, NULL },
+#ifdef WIN32
+ { "loadsyslib", test_evutil_loadsyslib, TT_FORK, NULL, NULL },
+#endif
+ END_OF_TESTCASES,
+};
+
diff --git a/libevent-2.0.20-stable/test/regress_zlib.c b/libevent-2.0.20-stable/test/regress_zlib.c
new file mode 100644
index 0000000..887a685
--- /dev/null
+++ b/libevent-2.0.20-stable/test/regress_zlib.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2008-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* The old tests here need assertions to work. */
+#undef NDEBUG
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <netdb.h>
+#endif
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+#include <errno.h>
+
+#include "event2/util.h"
+#include "event2/event.h"
+#include "event2/event_compat.h"
+#include "event2/buffer.h"
+#include "event2/bufferevent.h"
+
+#include "regress.h"
+
+/* zlib 1.2.4 and 1.2.5 do some "clever" things with macros. Instead of
+ saying "(defined(FOO) ? FOO : 0)" they like to say "FOO-0", on the theory
+ that nobody will care if the compile outputs a no-such-identifier warning.
+
+ Sorry, but we like -Werror over here, so I guess we need to define these.
+ I hope that zlib 1.2.6 doesn't break these too.
+*/
+#ifndef _LARGEFILE64_SOURCE
+#define _LARGEFILE64_SOURCE 0
+#endif
+#ifndef _LFS64_LARGEFILE
+#define _LFS64_LARGEFILE 0
+#endif
+#ifndef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 0
+#endif
+#ifndef off64_t
+#define off64_t ev_int64_t
+#endif
+
+#include <zlib.h>
+
+static int infilter_calls;
+static int outfilter_calls;
+static int readcb_finished;
+static int writecb_finished;
+static int errorcb_invoked;
+
+/*
+ * Zlib filters
+ */
+
+static void
+zlib_deflate_free(void *ctx)
+{
+ z_streamp p = ctx;
+
+ assert(deflateEnd(p) == Z_OK);
+}
+
+static void
+zlib_inflate_free(void *ctx)
+{
+ z_streamp p = ctx;
+
+ assert(inflateEnd(p) == Z_OK);
+}
+
+static int
+getstate(enum bufferevent_flush_mode state)
+{
+ switch (state) {
+ case BEV_FINISHED:
+ return Z_FINISH;
+ case BEV_FLUSH:
+ return Z_SYNC_FLUSH;
+ case BEV_NORMAL:
+ default:
+ return Z_NO_FLUSH;
+ }
+}
+
+/*
+ * The input filter is triggered only on new input read from the network.
+ * That means all input data needs to be consumed or the filter needs to
+ * initiate its own triggering via a timeout.
+ */
+static enum bufferevent_filter_result
+zlib_input_filter(struct evbuffer *src, struct evbuffer *dst,
+ ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
+{
+ struct evbuffer_iovec v_in[1];
+ struct evbuffer_iovec v_out[1];
+ int nread, nwrite;
+ int res, n;
+
+ z_streamp p = ctx;
+
+ do {
+ /* let's do some decompression */
+ n = evbuffer_peek(src, -1, NULL, v_in, 1);
+ if (n) {
+ p->avail_in = v_in[0].iov_len;
+ p->next_in = v_in[0].iov_base;
+ } else {
+ p->avail_in = 0;
+ p->next_in = 0;
+ }
+
+ evbuffer_reserve_space(dst, 4096, v_out, 1);
+ p->next_out = v_out[0].iov_base;
+ p->avail_out = v_out[0].iov_len;
+
+ /* we need to flush zlib if we got a flush */
+ res = inflate(p, getstate(state));
+
+ /* let's figure out how much was compressed */
+ nread = v_in[0].iov_len - p->avail_in;
+ nwrite = v_out[0].iov_len - p->avail_out;
+
+ evbuffer_drain(src, nread);
+ v_out[0].iov_len = nwrite;
+ evbuffer_commit_space(dst, v_out, 1);
+
+ if (res==Z_BUF_ERROR) {
+ /* We're out of space, or out of decodeable input.
+ Only if nwrite == 0 assume the latter.
+ */
+ if (nwrite == 0)
+ return BEV_NEED_MORE;
+ } else {
+ assert(res == Z_OK || res == Z_STREAM_END);
+ }
+
+ } while (evbuffer_get_length(src) > 0);
+
+ ++infilter_calls;
+
+ return (BEV_OK);
+}
+
+static enum bufferevent_filter_result
+zlib_output_filter(struct evbuffer *src, struct evbuffer *dst,
+ ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
+{
+ struct evbuffer_iovec v_in[1];
+ struct evbuffer_iovec v_out[1];
+ int nread, nwrite;
+ int res, n;
+
+ z_streamp p = ctx;
+
+ do {
+ /* let's do some compression */
+ n = evbuffer_peek(src, -1, NULL, v_in, 1);
+ if (n) {
+ p->avail_in = v_in[0].iov_len;
+ p->next_in = v_in[0].iov_base;
+ } else {
+ p->avail_in = 0;
+ p->next_in = 0;
+ }
+
+ evbuffer_reserve_space(dst, 4096, v_out, 1);
+ p->next_out = v_out[0].iov_base;
+ p->avail_out = v_out[0].iov_len;
+
+ /* we need to flush zlib if we got a flush */
+ res = deflate(p, getstate(state));
+
+ /* let's figure out how much was decompressed */
+ nread = v_in[0].iov_len - p->avail_in;
+ nwrite = v_out[0].iov_len - p->avail_out;
+
+ evbuffer_drain(src, nread);
+ v_out[0].iov_len = nwrite;
+ evbuffer_commit_space(dst, v_out, 1);
+
+ if (res==Z_BUF_ERROR) {
+ /* We're out of space, or out of decodeable input.
+ Only if nwrite == 0 assume the latter.
+ */
+ if (nwrite == 0)
+ return BEV_NEED_MORE;
+ } else {
+ assert(res == Z_OK || res == Z_STREAM_END);
+ }
+
+ } while (evbuffer_get_length(src) > 0);
+
+ ++outfilter_calls;
+
+ return (BEV_OK);
+}
+
+/*
+ * simple bufferevent test (over transparent zlib treatment)
+ */
+
+static void
+readcb(struct bufferevent *bev, void *arg)
+{
+ if (evbuffer_get_length(bufferevent_get_input(bev)) == 8333) {
+ struct evbuffer *evbuf = evbuffer_new();
+ assert(evbuf != NULL);
+
+ /* gratuitous test of bufferevent_read_buffer */
+ bufferevent_read_buffer(bev, evbuf);
+
+ bufferevent_disable(bev, EV_READ);
+
+ if (evbuffer_get_length(evbuf) == 8333) {
+ ++readcb_finished;
+ }
+
+ evbuffer_free(evbuf);
+ }
+}
+
+static void
+writecb(struct bufferevent *bev, void *arg)
+{
+ if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
+ ++writecb_finished;
+ }
+}
+
+static void
+errorcb(struct bufferevent *bev, short what, void *arg)
+{
+ errorcb_invoked = 1;
+}
+
+void
+test_bufferevent_zlib(void *arg)
+{
+ struct bufferevent *bev1=NULL, *bev2=NULL;
+ char buffer[8333];
+ z_stream z_input, z_output;
+ int i, pair[2]={-1,-1}, r;
+ (void)arg;
+
+ infilter_calls = outfilter_calls = readcb_finished = writecb_finished
+ = errorcb_invoked = 0;
+
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
+ tt_abort_perror("socketpair");
+ }
+
+ evutil_make_socket_nonblocking(pair[0]);
+ evutil_make_socket_nonblocking(pair[1]);
+
+ bev1 = bufferevent_socket_new(NULL, pair[0], 0);
+ bev2 = bufferevent_socket_new(NULL, pair[1], 0);
+
+ memset(&z_output, 0, sizeof(z_output));
+ r = deflateInit(&z_output, Z_DEFAULT_COMPRESSION);
+ tt_int_op(r, ==, Z_OK);
+ memset(&z_input, 0, sizeof(z_input));
+ r = inflateInit(&z_input);
+ tt_int_op(r, ==, Z_OK);
+
+ /* initialize filters */
+ bev1 = bufferevent_filter_new(bev1, NULL, zlib_output_filter,
+ BEV_OPT_CLOSE_ON_FREE, zlib_deflate_free, &z_output);
+ bev2 = bufferevent_filter_new(bev2, zlib_input_filter,
+ NULL, BEV_OPT_CLOSE_ON_FREE, zlib_inflate_free, &z_input);
+ bufferevent_setcb(bev1, readcb, writecb, errorcb, NULL);
+ bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL);
+
+ bufferevent_disable(bev1, EV_READ);
+ bufferevent_enable(bev1, EV_WRITE);
+
+ bufferevent_enable(bev2, EV_READ);
+
+ for (i = 0; i < (int)sizeof(buffer); i++)
+ buffer[i] = i;
+
+ /* break it up into multiple buffer chains */
+ bufferevent_write(bev1, buffer, 1800);
+ bufferevent_write(bev1, buffer + 1800, sizeof(buffer) - 1800);
+
+ /* we are done writing - we need to flush everything */
+ bufferevent_flush(bev1, EV_WRITE, BEV_FINISHED);
+
+ event_dispatch();
+
+ tt_want(infilter_calls);
+ tt_want(outfilter_calls);
+ tt_want(readcb_finished);
+ tt_want(writecb_finished);
+ tt_want(!errorcb_invoked);
+
+ test_ok = 1;
+end:
+ if (bev1)
+ bufferevent_free(bev1);
+ if (bev2)
+ bufferevent_free(bev2);
+
+ if (pair[0] >= 0)
+ evutil_closesocket(pair[0]);
+ if (pair[1] >= 0)
+ evutil_closesocket(pair[1]);
+}
diff --git a/libevent-2.0.20-stable/test/rpcgen_wrapper.sh b/libevent-2.0.20-stable/test/rpcgen_wrapper.sh
new file mode 100755
index 0000000..a60331c
--- /dev/null
+++ b/libevent-2.0.20-stable/test/rpcgen_wrapper.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# libevent rpcgen_wrapper.sh
+# Transforms event_rpcgen.py failure into success for make, only if
+# regress.gen.c and regress.gen.h already exist in $srcdir. This
+# is needed for "make distcheck" to pass the read-only $srcdir build,
+# as with read-only sources fresh from tarball, regress.gen.[ch] will
+# be correct in $srcdir but unwritable. This previously triggered
+# Makefile.am to create stub regress.gen.c and regress.gen.h in the
+# distcheck _build directory, which were then detected as leftover
+# files in the build tree after distclean, breaking distcheck.
+# Note that regress.gen.[ch] are not in fresh git clones, making
+# working Python a requirement for make distcheck of a git tree.
+
+exit_updated() {
+ echo "Updated ${srcdir}\regress.gen.c and ${srcdir}\regress.gen.h"
+ exit 0
+}
+
+exit_reuse() {
+ echo "event_rpcgen.py failed, ${srcdir}\regress.gen.\[ch\] will be reused." >&2
+ exit 0
+}
+
+exit_failed() {
+ echo "Could not generate regress.gen.\[ch\] using event_rpcgen.sh" >&2
+ exit 1
+}
+
+srcdir=$1
+srcdir=${srcdir:-.}
+${srcdir}/../event_rpcgen.py ${srcdir}/regress.rpc
+case "$?" in
+ 0)
+ exit_updated
+ ;;
+ *)
+ test -r ${srcdir}/regress.gen.c -a -r ${srcdir}/regress.gen.h && \
+ exit_reuse
+ exit_failed
+ ;;
+esac
diff --git a/libevent-2.0.20-stable/test/test-changelist.c b/libevent-2.0.20-stable/test/test-changelist.c
new file mode 100644
index 0000000..48ff9b1
--- /dev/null
+++ b/libevent-2.0.20-stable/test/test-changelist.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2010-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "event2/event-config.h"
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef _EVENT_HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event2/event.h"
+#include "event2/util.h"
+#include <time.h>
+
+struct cpu_usage_timer {
+#ifdef WIN32
+ HANDLE thread;
+ FILETIME usertimeBegin;
+ FILETIME kerneltimeBegin;
+#else
+ clock_t ticksBegin;
+#endif
+ struct timeval timeBegin;
+};
+static void
+start_cpu_usage_timer(struct cpu_usage_timer *timer)
+{
+#ifdef WIN32
+ int r;
+ FILETIME createtime, exittime;
+ timer->thread = GetCurrentThread();
+ r = GetThreadTimes(timer->thread, &createtime, &exittime,
+ &timer->usertimeBegin, &timer->kerneltimeBegin);
+ if (r==0) printf("GetThreadTimes failed.");
+#else
+ timer->ticksBegin = clock();
+#endif
+
+ evutil_gettimeofday(&timer->timeBegin, NULL);
+}
+#ifdef WIN32
+static ev_int64_t
+filetime_to_100nsec(const FILETIME *ft)
+{
+ /* Number of 100-nanosecond units */
+ ev_int64_t n = ft->dwHighDateTime;
+ n <<= 32;
+ n += ft->dwLowDateTime;
+ return n;
+}
+static double
+filetime_diff(const FILETIME *ftStart, const FILETIME *ftEnd)
+{
+ ev_int64_t s, e, diff;
+ double r;
+ s = filetime_to_100nsec(ftStart);
+ e = filetime_to_100nsec(ftEnd);
+ diff = e - s;
+ r = (double) diff;
+ return r / 1.0e7;
+}
+#endif
+
+static void
+get_cpu_usage(struct cpu_usage_timer *timer, double *secElapsedOut,
+ double *secUsedOut, double *usageOut)
+{
+#ifdef WIN32
+ double usertime_seconds, kerneltime_seconds;
+ FILETIME createtime, exittime, usertimeEnd, kerneltimeEnd;
+ int r;
+#else
+ clock_t ticksEnd;
+#endif
+ struct timeval timeEnd, timeDiff;
+ double secondsPassed, secondsUsed;
+
+#ifdef WIN32
+ r = GetThreadTimes(timer->thread, &createtime, &exittime,
+ &usertimeEnd, &kerneltimeEnd);
+ if (r==0) printf("GetThreadTimes failed.");
+ usertime_seconds = filetime_diff(&timer->usertimeBegin, &usertimeEnd);
+ kerneltime_seconds = filetime_diff(&timer->kerneltimeBegin, &kerneltimeEnd);
+ secondsUsed = kerneltime_seconds + usertime_seconds;
+#else
+ ticksEnd = clock();
+ secondsUsed = (ticksEnd - timer->ticksBegin) / (double)CLOCKS_PER_SEC;
+#endif
+ evutil_gettimeofday(&timeEnd, NULL);
+ evutil_timersub(&timeEnd, &timer->timeBegin, &timeDiff);
+ secondsPassed = timeDiff.tv_sec + (timeDiff.tv_usec / 1.0e6);
+
+ *secElapsedOut = secondsPassed;
+ *secUsedOut = secondsUsed;
+ *usageOut = secondsUsed / secondsPassed;
+}
+
+static void
+write_cb(evutil_socket_t fd, short event, void *arg)
+{
+ printf("write callback. should only see this once\n");
+
+ /* got what we want remove the event */
+ event_del(*(struct event**)arg);
+
+ /* opps changed my mind add it back again */
+ event_add(*(struct event**)arg,NULL);
+
+ /* not a good day for decisiveness, I really didn't want it after all */
+ event_del(*(struct event**)arg);
+
+}
+
+static void
+timeout_cb(evutil_socket_t fd, short event, void *arg)
+{
+ printf("timeout fired, time to end test\n");
+ event_del(*(struct event**)arg);
+ return;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct event* ev;
+ struct event* timeout;
+ struct event_base* base;
+
+ evutil_socket_t pair[2];
+ struct timeval tv;
+ struct cpu_usage_timer timer;
+
+ double usage, secPassed, secUsed;
+
+#ifdef WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+#endif
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
+ return (1);
+
+ /* Initalize the event library */
+ base = event_base_new();
+
+ /* Initalize a timeout to terminate the test */
+ timeout = evtimer_new(base,timeout_cb,&timeout);
+ /* and watch for writability on one end of the pipe */
+ ev = event_new(base,pair[1],EV_WRITE | EV_PERSIST, write_cb, &ev);
+
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+
+ evtimer_add(timeout, &tv);
+
+ event_add(ev, NULL);
+
+ start_cpu_usage_timer(&timer);
+
+ event_base_dispatch(base);
+
+ event_free(ev);
+ event_free(timeout);
+ event_base_free(base);
+
+ get_cpu_usage(&timer, &secPassed, &secUsed, &usage);
+
+ /* attempt to calculate our cpu usage over the test should be
+ virtually nil */
+
+ printf("usec used=%d, usec passed=%d, cpu usage=%.2f%%\n",
+ (int)(secUsed*1e6),
+ (int)(secPassed*1e6),
+ usage*100);
+
+ if (usage > 50.0) /* way too high */
+ return 1;
+
+ return 0;
+}
+
diff --git a/libevent-2.0.20-stable/test/test-eof.c b/libevent-2.0.20-stable/test/test-eof.c
new file mode 100644
index 0000000..47da694
--- /dev/null
+++ b/libevent-2.0.20-stable/test/test-eof.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef _EVENT_HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <event.h>
+#include <evutil.h>
+
+#ifdef _EVENT___func__
+#define __func__ _EVENT___func__
+#endif
+
+int test_okay = 1;
+int called = 0;
+struct timeval timeout = {60, 0};
+
+static void
+read_cb(evutil_socket_t fd, short event, void *arg)
+{
+ char buf[256];
+ int len;
+
+ if (EV_TIMEOUT & event) {
+ printf("%s: Timeout!\n", __func__);
+ exit(1);
+ }
+
+ len = recv(fd, buf, sizeof(buf), 0);
+
+ printf("%s: read %d%s\n", __func__,
+ len, len ? "" : " - means EOF");
+
+ if (len) {
+ if (!called)
+ event_add(arg, &timeout);
+ } else if (called == 1)
+ test_okay = 0;
+
+ called++;
+}
+
+#ifndef SHUT_WR
+#define SHUT_WR 1
+#endif
+
+int
+main(int argc, char **argv)
+{
+ struct event ev;
+ const char *test = "test string";
+ evutil_socket_t pair[2];
+
+#ifdef WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+#endif
+
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
+ return (1);
+
+
+ if (send(pair[0], test, (int)strlen(test)+1, 0) < 0)
+ return (1);
+ shutdown(pair[0], SHUT_WR);
+
+ /* Initalize the event library */
+ event_init();
+
+ /* Initalize one event */
+ event_set(&ev, pair[1], EV_READ | EV_TIMEOUT, read_cb, &ev);
+
+ event_add(&ev, &timeout);
+
+ event_dispatch();
+
+ return (test_okay);
+}
+
diff --git a/libevent-2.0.20-stable/test/test-init.c b/libevent-2.0.20-stable/test/test-init.c
new file mode 100644
index 0000000..2dfa865
--- /dev/null
+++ b/libevent-2.0.20-stable/test/test-init.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef _EVENT_HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef WIN32
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <event.h>
+
+int
+main(int argc, char **argv)
+{
+#ifdef WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+#endif
+
+ /* Initalize the event library */
+ event_init();
+
+ return (0);
+}
+
diff --git a/libevent-2.0.20-stable/test/test-ratelim.c b/libevent-2.0.20-stable/test/test-ratelim.c
new file mode 100644
index 0000000..d0a9d2f
--- /dev/null
+++ b/libevent-2.0.20-stable/test/test-ratelim.c
@@ -0,0 +1,479 @@
+/*
+ * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <math.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+# ifdef _XOPEN_SOURCE_EXTENDED
+# include <arpa/inet.h>
+# endif
+#endif
+#include <signal.h>
+
+#include "event2/bufferevent.h"
+#include "event2/buffer.h"
+#include "event2/event.h"
+#include "event2/util.h"
+#include "event2/listener.h"
+#include "event2/thread.h"
+
+#include "../util-internal.h"
+
+static int cfg_verbose = 0;
+static int cfg_help = 0;
+
+static int cfg_n_connections = 30;
+static int cfg_duration = 5;
+static int cfg_connlimit = 0;
+static int cfg_grouplimit = 0;
+static int cfg_tick_msec = 1000;
+static int cfg_min_share = -1;
+
+static int cfg_connlimit_tolerance = -1;
+static int cfg_grouplimit_tolerance = -1;
+static int cfg_stddev_tolerance = -1;
+
+#ifdef _WIN32
+static int cfg_enable_iocp = 0;
+#endif
+
+static struct timeval cfg_tick = { 0, 500*1000 };
+
+static struct ev_token_bucket_cfg *conn_bucket_cfg = NULL;
+static struct ev_token_bucket_cfg *group_bucket_cfg = NULL;
+struct bufferevent_rate_limit_group *ratelim_group = NULL;
+static double seconds_per_tick = 0.0;
+
+struct client_state {
+ size_t queued;
+ ev_uint64_t received;
+};
+
+static int n_echo_conns_open = 0;
+
+static void
+loud_writecb(struct bufferevent *bev, void *ctx)
+{
+ struct client_state *cs = ctx;
+ struct evbuffer *output = bufferevent_get_output(bev);
+ char buf[1024];
+#ifdef WIN32
+ int r = rand() % 256;
+#else
+ int r = random() % 256;
+#endif
+ memset(buf, r, sizeof(buf));
+ while (evbuffer_get_length(output) < 8192) {
+ evbuffer_add(output, buf, sizeof(buf));
+ cs->queued += sizeof(buf);
+ }
+}
+
+static void
+discard_readcb(struct bufferevent *bev, void *ctx)
+{
+ struct client_state *cs = ctx;
+ struct evbuffer *input = bufferevent_get_input(bev);
+ size_t len = evbuffer_get_length(input);
+ evbuffer_drain(input, len);
+ cs->received += len;
+}
+
+static void
+write_on_connectedcb(struct bufferevent *bev, short what, void *ctx)
+{
+ if (what & BEV_EVENT_CONNECTED) {
+ loud_writecb(bev, ctx);
+ /* XXXX this shouldn't be needed. */
+ bufferevent_enable(bev, EV_READ|EV_WRITE);
+ }
+}
+
+static void
+echo_readcb(struct bufferevent *bev, void *ctx)
+{
+ struct evbuffer *input = bufferevent_get_input(bev);
+ struct evbuffer *output = bufferevent_get_output(bev);
+
+ evbuffer_add_buffer(output, input);
+ if (evbuffer_get_length(output) > 1024000)
+ bufferevent_disable(bev, EV_READ);
+}
+
+static void
+echo_writecb(struct bufferevent *bev, void *ctx)
+{
+ struct evbuffer *output = bufferevent_get_output(bev);
+ if (evbuffer_get_length(output) < 512000)
+ bufferevent_enable(bev, EV_READ);
+}
+
+static void
+echo_eventcb(struct bufferevent *bev, short what, void *ctx)
+{
+ if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
+ --n_echo_conns_open;
+ bufferevent_free(bev);
+ }
+}
+
+static void
+echo_listenercb(struct evconnlistener *listener, evutil_socket_t newsock,
+ struct sockaddr *sourceaddr, int socklen, void *ctx)
+{
+ struct event_base *base = ctx;
+ int flags = BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE;
+ struct bufferevent *bev;
+
+ bev = bufferevent_socket_new(base, newsock, flags);
+ bufferevent_setcb(bev, echo_readcb, echo_writecb, echo_eventcb, NULL);
+ if (conn_bucket_cfg)
+ bufferevent_set_rate_limit(bev, conn_bucket_cfg);
+ if (ratelim_group)
+ bufferevent_add_to_rate_limit_group(bev, ratelim_group);
+ ++n_echo_conns_open;
+ bufferevent_enable(bev, EV_READ|EV_WRITE);
+}
+
+static int
+test_ratelimiting(void)
+{
+ struct event_base *base;
+ struct sockaddr_in sin;
+ struct evconnlistener *listener;
+
+ struct sockaddr_storage ss;
+ ev_socklen_t slen;
+
+ struct bufferevent **bevs;
+ struct client_state *states;
+ struct bufferevent_rate_limit_group *group = NULL;
+
+ int i;
+
+ struct timeval tv;
+
+ ev_uint64_t total_received;
+ double total_sq_persec, total_persec;
+ double variance;
+ double expected_total_persec = -1.0, expected_avg_persec = -1.0;
+ int ok = 1;
+ struct event_config *base_cfg;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
+ sin.sin_port = 0; /* unspecified port */
+
+ if (0)
+ event_enable_debug_mode();
+
+ base_cfg = event_config_new();
+
+#ifdef _WIN32
+ if (cfg_enable_iocp) {
+ evthread_use_windows_threads();
+ event_config_set_flag(base_cfg, EVENT_BASE_FLAG_STARTUP_IOCP);
+ }
+#endif
+
+ base = event_base_new_with_config(base_cfg);
+ event_config_free(base_cfg);
+
+ listener = evconnlistener_new_bind(base, echo_listenercb, base,
+ LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1,
+ (struct sockaddr *)&sin, sizeof(sin));
+
+ slen = sizeof(ss);
+ if (getsockname(evconnlistener_get_fd(listener), (struct sockaddr *)&ss,
+ &slen) < 0) {
+ perror("getsockname");
+ return 1;
+ }
+
+ if (cfg_connlimit > 0) {
+ conn_bucket_cfg = ev_token_bucket_cfg_new(
+ cfg_connlimit, cfg_connlimit * 4,
+ cfg_connlimit, cfg_connlimit * 4,
+ &cfg_tick);
+ assert(conn_bucket_cfg);
+ }
+
+ if (cfg_grouplimit > 0) {
+ group_bucket_cfg = ev_token_bucket_cfg_new(
+ cfg_grouplimit, cfg_grouplimit * 4,
+ cfg_grouplimit, cfg_grouplimit * 4,
+ &cfg_tick);
+ group = ratelim_group = bufferevent_rate_limit_group_new(
+ base, group_bucket_cfg);
+ expected_total_persec = cfg_grouplimit;
+ expected_avg_persec = cfg_grouplimit / cfg_n_connections;
+ if (cfg_connlimit > 0 && expected_avg_persec > cfg_connlimit)
+ expected_avg_persec = cfg_connlimit;
+ if (cfg_min_share >= 0)
+ bufferevent_rate_limit_group_set_min_share(
+ ratelim_group, cfg_min_share);
+ }
+
+ if (expected_avg_persec < 0 && cfg_connlimit > 0)
+ expected_avg_persec = cfg_connlimit;
+
+ if (expected_avg_persec > 0)
+ expected_avg_persec /= seconds_per_tick;
+ if (expected_total_persec > 0)
+ expected_total_persec /= seconds_per_tick;
+
+ bevs = calloc(cfg_n_connections, sizeof(struct bufferevent *));
+ states = calloc(cfg_n_connections, sizeof(struct client_state));
+
+ for (i = 0; i < cfg_n_connections; ++i) {
+ bevs[i] = bufferevent_socket_new(base, -1,
+ BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE);
+ assert(bevs[i]);
+ bufferevent_setcb(bevs[i], discard_readcb, loud_writecb,
+ write_on_connectedcb, &states[i]);
+ bufferevent_enable(bevs[i], EV_READ|EV_WRITE);
+ bufferevent_socket_connect(bevs[i], (struct sockaddr *)&ss,
+ slen);
+ }
+
+ tv.tv_sec = cfg_duration - 1;
+ tv.tv_usec = 995000;
+
+ event_base_loopexit(base, &tv);
+
+ event_base_dispatch(base);
+
+ ratelim_group = NULL; /* So no more responders get added */
+
+ for (i = 0; i < cfg_n_connections; ++i) {
+ bufferevent_free(bevs[i]);
+ }
+ evconnlistener_free(listener);
+
+ /* Make sure no new echo_conns get added to the group. */
+ ratelim_group = NULL;
+
+ /* This should get _everybody_ freed */
+ while (n_echo_conns_open) {
+ printf("waiting for %d conns\n", n_echo_conns_open);
+ tv.tv_sec = 0;
+ tv.tv_usec = 300000;
+ event_base_loopexit(base, &tv);
+ event_base_dispatch(base);
+ }
+
+ if (group)
+ bufferevent_rate_limit_group_free(group);
+
+ total_received = 0;
+ total_persec = 0.0;
+ total_sq_persec = 0.0;
+ for (i=0; i < cfg_n_connections; ++i) {
+ double persec = states[i].received;
+ persec /= cfg_duration;
+ total_received += states[i].received;
+ total_persec += persec;
+ total_sq_persec += persec*persec;
+ printf("%d: %f per second\n", i+1, persec);
+ }
+ printf(" total: %f per second\n",
+ ((double)total_received)/cfg_duration);
+ if (expected_total_persec > 0) {
+ double diff = expected_total_persec -
+ ((double)total_received/cfg_duration);
+ printf(" [Off by %lf]\n", diff);
+ if (cfg_grouplimit_tolerance > 0 &&
+ fabs(diff) > cfg_grouplimit_tolerance) {
+ fprintf(stderr, "Group bandwidth out of bounds\n");
+ ok = 0;
+ }
+ }
+
+ printf(" average: %f per second\n",
+ (((double)total_received)/cfg_duration)/cfg_n_connections);
+ if (expected_avg_persec > 0) {
+ double diff = expected_avg_persec - (((double)total_received)/cfg_duration)/cfg_n_connections;
+ printf(" [Off by %lf]\n", diff);
+ if (cfg_connlimit_tolerance > 0 &&
+ fabs(diff) > cfg_connlimit_tolerance) {
+ fprintf(stderr, "Connection bandwidth out of bounds\n");
+ ok = 0;
+ }
+ }
+
+ variance = total_sq_persec/cfg_n_connections - total_persec*total_persec/(cfg_n_connections*cfg_n_connections);
+
+ printf(" stddev: %f per second\n", sqrt(variance));
+ if (cfg_stddev_tolerance > 0 &&
+ sqrt(variance) > cfg_stddev_tolerance) {
+ fprintf(stderr, "Connection variance out of bounds\n");
+ ok = 0;
+ }
+
+ event_base_free(base);
+ free(bevs);
+ free(states);
+
+ return ok ? 0 : 1;
+}
+
+static struct option {
+ const char *name; int *ptr; int min; int isbool;
+} options[] = {
+ { "-v", &cfg_verbose, 0, 1 },
+ { "-h", &cfg_help, 0, 1 },
+ { "-n", &cfg_n_connections, 1, 0 },
+ { "-d", &cfg_duration, 1, 0 },
+ { "-c", &cfg_connlimit, 0, 0 },
+ { "-g", &cfg_grouplimit, 0, 0 },
+ { "-t", &cfg_tick_msec, 10, 0 },
+ { "--min-share", &cfg_min_share, 0, 0 },
+ { "--check-connlimit", &cfg_connlimit_tolerance, 0, 0 },
+ { "--check-grouplimit", &cfg_grouplimit_tolerance, 0, 0 },
+ { "--check-stddev", &cfg_stddev_tolerance, 0, 0 },
+#ifdef _WIN32
+ { "--iocp", &cfg_enable_iocp, 0, 1 },
+#endif
+ { NULL, NULL, -1, 0 },
+};
+
+static int
+handle_option(int argc, char **argv, int *i, const struct option *opt)
+{
+ long val;
+ char *endptr = NULL;
+ if (opt->isbool) {
+ *opt->ptr = 1;
+ return 0;
+ }
+ if (*i + 1 == argc) {
+ fprintf(stderr, "Too few arguments to '%s'\n",argv[*i]);
+ return -1;
+ }
+ val = strtol(argv[*i+1], &endptr, 10);
+ if (*argv[*i+1] == '\0' || !endptr || *endptr != '\0') {
+ fprintf(stderr, "Couldn't parse numeric value '%s'\n",
+ argv[*i+1]);
+ return -1;
+ }
+ if (val < opt->min || val > 0x7fffffff) {
+ fprintf(stderr, "Value '%s' is out-of-range'\n",
+ argv[*i+1]);
+ return -1;
+ }
+ *opt->ptr = (int)val;
+ ++*i;
+ return 0;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+"test-ratelim [-v] [-n INT] [-d INT] [-c INT] [-g INT] [-t INT]\n\n"
+"Pushes bytes through a number of possibly rate-limited connections, and\n"
+"displays average throughput.\n\n"
+" -n INT: Number of connections to open (default: 30)\n"
+" -d INT: Duration of the test in seconds (default: 5 sec)\n");
+ fprintf(stderr,
+" -c INT: Connection-rate limit applied to each connection in bytes per second\n"
+" (default: None.)\n"
+" -g INT: Group-rate limit applied to sum of all usage in bytes per second\n"
+" (default: None.)\n"
+" -t INT: Granularity of timing, in milliseconds (default: 1000 msec)\n");
+}
+
+int
+main(int argc, char **argv)
+{
+ int i,j;
+ double ratio;
+
+#ifdef WIN32
+ WORD wVersionRequested = MAKEWORD(2,2);
+ WSADATA wsaData;
+ int err;
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+#endif
+
+#ifndef WIN32
+ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+ return 1;
+#endif
+ for (i = 1; i < argc; ++i) {
+ for (j = 0; options[j].name; ++j) {
+ if (!strcmp(argv[i],options[j].name)) {
+ if (handle_option(argc,argv,&i,&options[j])<0)
+ return 1;
+ goto again;
+ }
+ }
+ fprintf(stderr, "Unknown option '%s'\n", argv[i]);
+ usage();
+ return 1;
+ again:
+ ;
+ }
+ if (cfg_help) {
+ usage();
+ return 0;
+ }
+
+ cfg_tick.tv_sec = cfg_tick_msec / 1000;
+ cfg_tick.tv_usec = (cfg_tick_msec % 1000)*1000;
+
+ seconds_per_tick = ratio = cfg_tick_msec / 1000.0;
+
+ cfg_connlimit *= ratio;
+ cfg_grouplimit *= ratio;
+
+ {
+ struct timeval tv;
+ evutil_gettimeofday(&tv, NULL);
+#ifdef WIN32
+ srand(tv.tv_usec);
+#else
+ srandom(tv.tv_usec);
+#endif
+ }
+
+#ifndef _EVENT_DISABLE_THREAD_SUPPORT
+ evthread_enable_lock_debuging();
+#endif
+
+ return test_ratelimiting();
+}
diff --git a/libevent-2.0.20-stable/test/test-time.c b/libevent-2.0.20-stable/test/test-time.c
new file mode 100644
index 0000000..8f0bd62
--- /dev/null
+++ b/libevent-2.0.20-stable/test/test-time.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef WIN32
+#include <unistd.h>
+#include <sys/time.h>
+#endif
+#include <errno.h>
+
+#include "event2/event.h"
+#include "event2/event_compat.h"
+#include "event2/event_struct.h"
+
+int called = 0;
+
+#define NEVENT 20000
+
+struct event *ev[NEVENT];
+
+static int
+rand_int(int n)
+{
+#ifdef WIN32
+ return (int)(rand() % n);
+#else
+ return (int)(random() % n);
+#endif
+}
+
+static void
+time_cb(evutil_socket_t fd, short event, void *arg)
+{
+ struct timeval tv;
+ int i, j;
+
+ called++;
+
+ if (called < 10*NEVENT) {
+ for (i = 0; i < 10; i++) {
+ j = rand_int(NEVENT);
+ tv.tv_sec = 0;
+ tv.tv_usec = rand_int(50000);
+ if (tv.tv_usec % 2)
+ evtimer_add(ev[j], &tv);
+ else
+ evtimer_del(ev[j]);
+ }
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ struct timeval tv;
+ int i;
+#ifdef WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+#endif
+
+ /* Initalize the event library */
+ event_init();
+
+ for (i = 0; i < NEVENT; i++) {
+ ev[i] = malloc(sizeof(struct event));
+
+ /* Initalize one event */
+ evtimer_set(ev[i], time_cb, ev[i]);
+ tv.tv_sec = 0;
+ tv.tv_usec = rand_int(50000);
+ evtimer_add(ev[i], &tv);
+ }
+
+ event_dispatch();
+
+ return (called < NEVENT);
+}
+
diff --git a/libevent-2.0.20-stable/test/test-weof.c b/libevent-2.0.20-stable/test/test-weof.c
new file mode 100644
index 0000000..dfdd3f0
--- /dev/null
+++ b/libevent-2.0.20-stable/test/test-weof.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef _EVENT_HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+
+#include "event2/event.h"
+#include "event2/event_struct.h"
+#include "event2/event_compat.h"
+#include "event2/util.h"
+
+#ifdef _EVENT___func__
+#define __func__ _EVENT___func__
+#endif
+
+evutil_socket_t pair[2];
+int test_okay = 1;
+int called = 0;
+
+static void
+write_cb(evutil_socket_t fd, short event, void *arg)
+{
+ const char *test = "test string";
+ int len;
+
+ len = send(fd, test, (int)strlen(test) + 1, 0);
+
+ printf("%s: write %d%s\n", __func__,
+ len, len ? "" : " - means EOF");
+
+ if (len > 0) {
+ if (!called)
+ event_add(arg, NULL);
+ evutil_closesocket(pair[0]);
+ } else if (called == 1)
+ test_okay = 0;
+
+ called++;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct event ev;
+
+#ifdef WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+#endif
+
+#ifndef WIN32
+ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+ return (1);
+#endif
+
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
+ return (1);
+
+ /* Initalize the event library */
+ event_init();
+
+ /* Initalize one event */
+ event_set(&ev, pair[1], EV_WRITE, write_cb, &ev);
+
+ event_add(&ev, NULL);
+
+ event_dispatch();
+
+ return (test_okay);
+}
+
diff --git a/libevent-2.0.20-stable/test/test.sh b/libevent-2.0.20-stable/test/test.sh
new file mode 100755
index 0000000..08a4cdd
--- /dev/null
+++ b/libevent-2.0.20-stable/test/test.sh
@@ -0,0 +1,163 @@
+#!/bin/sh
+
+FAILED=no
+
+if test "x$TEST_OUTPUT_FILE" = "x"
+then
+ TEST_OUTPUT_FILE=/dev/null
+fi
+
+# /bin/echo is a little more likely to support -n than sh's builtin echo,
+# printf is even more likely
+if test "`printf %s hello 2>&1`" = "hello"
+then
+ ECHO_N="printf %s"
+else
+ if test -x /bin/echo
+ then
+ ECHO_N="/bin/echo -n"
+ else
+ ECHO_N="echo -n"
+ fi
+fi
+
+if test "$TEST_OUTPUT_FILE" != "/dev/null"
+then
+ touch "$TEST_OUTPUT_FILE" || exit 1
+fi
+
+TEST_DIR=.
+
+T=`echo "$0" | sed -e 's/test.sh$//'`
+if test -x "$T/test-init"
+then
+ TEST_DIR="$T"
+fi
+
+setup () {
+ EVENT_NOKQUEUE=yes; export EVENT_NOKQUEUE
+ EVENT_NODEVPOLL=yes; export EVENT_NODEVPOLL
+ EVENT_NOPOLL=yes; export EVENT_NOPOLL
+ EVENT_NOSELECT=yes; export EVENT_NOSELECT
+ EVENT_NOEPOLL=yes; export EVENT_NOEPOLL
+ unset EVENT_EPOLL_USE_CHANGELIST
+ EVENT_NOEVPORT=yes; export EVENT_NOEVPORT
+ EVENT_NOWIN32=yes; export EVENT_NOWIN32
+}
+
+announce () {
+ echo "$@"
+ echo "$@" >>"$TEST_OUTPUT_FILE"
+}
+
+announce_n () {
+ $ECHO_N "$@"
+ echo "$@" >>"$TEST_OUTPUT_FILE"
+}
+
+
+run_tests () {
+ if $TEST_DIR/test-init 2>>"$TEST_OUTPUT_FILE" ;
+ then
+ true
+ else
+ announce Skipping test
+ return
+ fi
+
+ announce_n " test-eof: "
+ if $TEST_DIR/test-eof >>"$TEST_OUTPUT_FILE" ;
+ then
+ announce OKAY ;
+ else
+ announce FAILED ;
+ FAILED=yes
+ fi
+ announce_n " test-weof: "
+ if $TEST_DIR/test-weof >>"$TEST_OUTPUT_FILE" ;
+ then
+ announce OKAY ;
+ else
+ announce FAILED ;
+ FAILED=yes
+ fi
+ announce_n " test-time: "
+ if $TEST_DIR/test-time >>"$TEST_OUTPUT_FILE" ;
+ then
+ announce OKAY ;
+ else
+ announce FAILED ;
+ FAILED=yes
+ fi
+ announce_n " test-changelist: "
+ if $TEST_DIR/test-changelist >>"$TEST_OUTPUT_FILE" ;
+ then
+ announce OKAY ;
+ else
+ announce FAILED ;
+ FAILED=yes
+ fi
+ test -x $TEST_DIR/regress || return
+ announce_n " regress: "
+ if test "$TEST_OUTPUT_FILE" = "/dev/null" ;
+ then
+ $TEST_DIR/regress --quiet
+ else
+ $TEST_DIR/regress >>"$TEST_OUTPUT_FILE"
+ fi
+ if test "$?" = "0" ;
+ then
+ announce OKAY ;
+ else
+ announce FAILED ;
+ FAILED=yes
+ fi
+}
+
+announce "Running tests:"
+
+# Need to do this by hand?
+setup
+unset EVENT_NOEVPORT
+announce "EVPORT"
+run_tests
+
+setup
+unset EVENT_NOKQUEUE
+announce "KQUEUE"
+run_tests
+
+setup
+unset EVENT_NOEPOLL
+announce "EPOLL"
+run_tests
+
+setup
+unset EVENT_NOEPOLL
+EVENT_EPOLL_USE_CHANGELIST=yes; export EVENT_EPOLL_USE_CHANGELIST
+announce "EPOLL (changelist)"
+run_tests
+
+setup
+unset EVENT_NODEVPOLL
+announce "DEVPOLL"
+run_tests
+
+setup
+unset EVENT_NOPOLL
+announce "POLL"
+run_tests
+
+setup
+unset EVENT_NOSELECT
+announce "SELECT"
+run_tests
+
+setup
+unset EVENT_NOWIN32
+announce "WIN32"
+run_tests
+
+if test "$FAILED" = "yes"; then
+ exit 1
+fi
diff --git a/libevent-2.0.20-stable/test/tinytest.c b/libevent-2.0.20-stable/test/tinytest.c
new file mode 100644
index 0000000..065bd62
--- /dev/null
+++ b/libevent-2.0.20-stable/test/tinytest.c
@@ -0,0 +1,400 @@
+/* tinytest.c -- Copyright 2009-2012 Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef TINYTEST_LOCAL
+#include "tinytest_local.h"
+#endif
+
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#endif
+
+#if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
+#if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \
+ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
+/* Workaround for a stupid bug in OSX 10.6 */
+#define FORK_BREAKS_GCOV
+#include <vproc.h>
+#endif
+#endif
+
+#ifndef __GNUC__
+#define __attribute__(x)
+#endif
+
+#include "tinytest.h"
+#include "tinytest_macros.h"
+
+#define LONGEST_TEST_NAME 16384
+
+static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
+static int n_ok = 0; /**< Number of tests that have passed */
+static int n_bad = 0; /**< Number of tests that have failed. */
+static int n_skipped = 0; /**< Number of tests that have been skipped. */
+
+static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
+static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
+static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
+const char *verbosity_flag = "";
+
+enum outcome { SKIP=2, OK=1, FAIL=0 };
+static enum outcome cur_test_outcome = 0;
+const char *cur_test_prefix = NULL; /**< prefix of the current test group */
+/** Name of the current test, if we haven't logged is yet. Used for --quiet */
+const char *cur_test_name = NULL;
+
+#ifdef WIN32
+/* Copy of argv[0] for win32. */
+static char commandname[MAX_PATH+1];
+#endif
+
+static void usage(struct testgroup_t *groups, int list_groups)
+ __attribute__((noreturn));
+
+static enum outcome
+_testcase_run_bare(const struct testcase_t *testcase)
+{
+ void *env = NULL;
+ int outcome;
+ if (testcase->setup) {
+ env = testcase->setup->setup_fn(testcase);
+ if (!env)
+ return FAIL;
+ else if (env == (void*)TT_SKIP)
+ return SKIP;
+ }
+
+ cur_test_outcome = OK;
+ testcase->fn(env);
+ outcome = cur_test_outcome;
+
+ if (testcase->setup) {
+ if (testcase->setup->cleanup_fn(testcase, env) == 0)
+ outcome = FAIL;
+ }
+
+ return outcome;
+}
+
+#define MAGIC_EXITCODE 42
+
+static enum outcome
+_testcase_run_forked(const struct testgroup_t *group,
+ const struct testcase_t *testcase)
+{
+#ifdef WIN32
+ /* Fork? On Win32? How primitive! We'll do what the smart kids do:
+ we'll invoke our own exe (whose name we recall from the command
+ line) with a command line that tells it to run just the test we
+ want, and this time without forking.
+
+ (No, threads aren't an option. The whole point of forking is to
+ share no state between tests.)
+ */
+ int ok;
+ char buffer[LONGEST_TEST_NAME+256];
+ STARTUPINFOA si;
+ PROCESS_INFORMATION info;
+ DWORD exitcode;
+
+ if (!in_tinytest_main) {
+ printf("\nERROR. On Windows, _testcase_run_forked must be"
+ " called from within tinytest_main.\n");
+ abort();
+ }
+ if (opt_verbosity>0)
+ printf("[forking] ");
+
+ snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s",
+ commandname, verbosity_flag, group->prefix, testcase->name);
+
+ memset(&si, 0, sizeof(si));
+ memset(&info, 0, sizeof(info));
+ si.cb = sizeof(si);
+
+ ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
+ 0, NULL, NULL, &si, &info);
+ if (!ok) {
+ printf("CreateProcess failed!\n");
+ return 0;
+ }
+ WaitForSingleObject(info.hProcess, INFINITE);
+ GetExitCodeProcess(info.hProcess, &exitcode);
+ CloseHandle(info.hProcess);
+ CloseHandle(info.hThread);
+ if (exitcode == 0)
+ return OK;
+ else if (exitcode == MAGIC_EXITCODE)
+ return SKIP;
+ else
+ return FAIL;
+#else
+ int outcome_pipe[2];
+ pid_t pid;
+ (void)group;
+
+ if (pipe(outcome_pipe))
+ perror("opening pipe");
+
+ if (opt_verbosity>0)
+ printf("[forking] ");
+ pid = fork();
+#ifdef FORK_BREAKS_GCOV
+ vproc_transaction_begin(0);
+#endif
+ if (!pid) {
+ /* child. */
+ int test_r, write_r;
+ char b[1];
+ close(outcome_pipe[0]);
+ test_r = _testcase_run_bare(testcase);
+ assert(0<=(int)test_r && (int)test_r<=2);
+ b[0] = "NYS"[test_r];
+ write_r = (int)write(outcome_pipe[1], b, 1);
+ if (write_r != 1) {
+ perror("write outcome to pipe");
+ exit(1);
+ }
+ exit(0);
+ return FAIL; /* unreachable */
+ } else {
+ /* parent */
+ int status, r;
+ char b[1];
+ /* Close this now, so that if the other side closes it,
+ * our read fails. */
+ close(outcome_pipe[1]);
+ r = (int)read(outcome_pipe[0], b, 1);
+ if (r == 0) {
+ printf("[Lost connection!] ");
+ return 0;
+ } else if (r != 1) {
+ perror("read outcome from pipe");
+ }
+ waitpid(pid, &status, 0);
+ close(outcome_pipe[0]);
+ return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
+ }
+#endif
+}
+
+int
+testcase_run_one(const struct testgroup_t *group,
+ const struct testcase_t *testcase)
+{
+ enum outcome outcome;
+
+ if (testcase->flags & TT_SKIP) {
+ if (opt_verbosity>0)
+ printf("%s%s: SKIPPED\n",
+ group->prefix, testcase->name);
+ ++n_skipped;
+ return SKIP;
+ }
+
+ if (opt_verbosity>0 && !opt_forked) {
+ printf("%s%s: ", group->prefix, testcase->name);
+ } else {
+ if (opt_verbosity==0) printf(".");
+ cur_test_prefix = group->prefix;
+ cur_test_name = testcase->name;
+ }
+
+ if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
+ outcome = _testcase_run_forked(group, testcase);
+ } else {
+ outcome = _testcase_run_bare(testcase);
+ }
+
+ if (outcome == OK) {
+ ++n_ok;
+ if (opt_verbosity>0 && !opt_forked)
+ puts(opt_verbosity==1?"OK":"");
+ } else if (outcome == SKIP) {
+ ++n_skipped;
+ if (opt_verbosity>0 && !opt_forked)
+ puts("SKIPPED");
+ } else {
+ ++n_bad;
+ if (!opt_forked)
+ printf("\n [%s FAILED]\n", testcase->name);
+ }
+
+ if (opt_forked) {
+ exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
+ return 1; /* unreachable */
+ } else {
+ return (int)outcome;
+ }
+}
+
+int
+_tinytest_set_flag(struct testgroup_t *groups, const char *arg, unsigned long flag)
+{
+ int i, j;
+ size_t length = LONGEST_TEST_NAME;
+ char fullname[LONGEST_TEST_NAME];
+ int found=0;
+ if (strstr(arg, ".."))
+ length = strstr(arg,"..")-arg;
+ for (i=0; groups[i].prefix; ++i) {
+ for (j=0; groups[i].cases[j].name; ++j) {
+ snprintf(fullname, sizeof(fullname), "%s%s",
+ groups[i].prefix, groups[i].cases[j].name);
+ if (!flag) /* Hack! */
+ printf(" %s\n", fullname);
+ if (!strncmp(fullname, arg, length)) {
+ groups[i].cases[j].flags |= flag;
+ ++found;
+ }
+ }
+ }
+ return found;
+}
+
+static void
+usage(struct testgroup_t *groups, int list_groups)
+{
+ puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
+ puts(" Specify tests by name, or using a prefix ending with '..'");
+ puts(" To skip a test, list give its name prefixed with a colon.");
+ puts(" Use --list-tests for a list of tests.");
+ if (list_groups) {
+ puts("Known tests are:");
+ _tinytest_set_flag(groups, "..", 0);
+ }
+ exit(0);
+}
+
+int
+tinytest_main(int c, const char **v, struct testgroup_t *groups)
+{
+ int i, j, n=0;
+
+#ifdef WIN32
+ const char *sp = strrchr(v[0], '.');
+ const char *extension = "";
+ if (!sp || stricmp(sp, ".exe"))
+ extension = ".exe"; /* Add an exe so CreateProcess will work */
+ snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension);
+ commandname[MAX_PATH]='\0';
+#endif
+ for (i=1; i<c; ++i) {
+ if (v[i][0] == '-') {
+ if (!strcmp(v[i], "--RUNNING-FORKED")) {
+ opt_forked = 1;
+ } else if (!strcmp(v[i], "--no-fork")) {
+ opt_nofork = 1;
+ } else if (!strcmp(v[i], "--quiet")) {
+ opt_verbosity = -1;
+ verbosity_flag = "--quiet";
+ } else if (!strcmp(v[i], "--verbose")) {
+ opt_verbosity = 2;
+ verbosity_flag = "--verbose";
+ } else if (!strcmp(v[i], "--terse")) {
+ opt_verbosity = 0;
+ verbosity_flag = "--terse";
+ } else if (!strcmp(v[i], "--help")) {
+ usage(groups, 0);
+ } else if (!strcmp(v[i], "--list-tests")) {
+ usage(groups, 1);
+ } else {
+ printf("Unknown option %s. Try --help\n",v[i]);
+ return -1;
+ }
+ } else {
+ const char *test = v[i];
+ int flag = _TT_ENABLED;
+ if (test[0] == ':') {
+ ++test;
+ flag = TT_SKIP;
+ } else {
+ ++n;
+ }
+ if (!_tinytest_set_flag(groups, test, flag)) {
+ printf("No such test as %s!\n", v[i]);
+ return -1;
+ }
+ }
+ }
+ if (!n)
+ _tinytest_set_flag(groups, "..", _TT_ENABLED);
+
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ ++in_tinytest_main;
+ for (i=0; groups[i].prefix; ++i)
+ for (j=0; groups[i].cases[j].name; ++j)
+ if (groups[i].cases[j].flags & _TT_ENABLED)
+ testcase_run_one(&groups[i],
+ &groups[i].cases[j]);
+
+ --in_tinytest_main;
+
+ if (opt_verbosity==0)
+ puts("");
+
+ if (n_bad)
+ printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
+ n_bad+n_ok,n_skipped);
+ else if (opt_verbosity >= 1)
+ printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped);
+
+ return (n_bad == 0) ? 0 : 1;
+}
+
+int
+_tinytest_get_verbosity(void)
+{
+ return opt_verbosity;
+}
+
+void
+_tinytest_set_test_failed(void)
+{
+ if (opt_verbosity <= 0 && cur_test_name) {
+ if (opt_verbosity==0) puts("");
+ printf("%s%s: ", cur_test_prefix, cur_test_name);
+ cur_test_name = NULL;
+ }
+ cur_test_outcome = 0;
+}
+
+void
+_tinytest_set_test_skipped(void)
+{
+ if (cur_test_outcome==OK)
+ cur_test_outcome = SKIP;
+}
+
diff --git a/libevent-2.0.20-stable/test/tinytest.h b/libevent-2.0.20-stable/test/tinytest.h
new file mode 100644
index 0000000..7ce7858
--- /dev/null
+++ b/libevent-2.0.20-stable/test/tinytest.h
@@ -0,0 +1,87 @@
+/* tinytest.h -- Copyright 2009-2012 Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TINYTEST_H
+#define _TINYTEST_H
+
+/** Flag for a test that needs to run in a subprocess. */
+#define TT_FORK (1<<0)
+/** Runtime flag for a test we've decided to skip. */
+#define TT_SKIP (1<<1)
+/** Internal runtime flag for a test we've decided to run. */
+#define _TT_ENABLED (1<<2)
+/** If you add your own flags, make them start at this point. */
+#define TT_FIRST_USER_FLAG (1<<3)
+
+typedef void (*testcase_fn)(void *);
+
+struct testcase_t;
+
+/** Functions to initialize/teardown a structure for a testcase. */
+struct testcase_setup_t {
+ /** Return a new structure for use by a given testcase. */
+ void *(*setup_fn)(const struct testcase_t *);
+ /** Clean/free a structure from setup_fn. Return 1 if ok, 0 on err. */
+ int (*cleanup_fn)(const struct testcase_t *, void *);
+};
+
+/** A single test-case that you can run. */
+struct testcase_t {
+ const char *name; /**< An identifier for this case. */
+ testcase_fn fn; /**< The function to run to implement this case. */
+ unsigned long flags; /**< Bitfield of TT_* flags. */
+ const struct testcase_setup_t *setup; /**< Optional setup/cleanup fns*/
+ void *setup_data; /**< Extra data usable by setup function */
+};
+#define END_OF_TESTCASES { NULL, NULL, 0, NULL, NULL }
+
+/** A group of tests that are selectable together. */
+struct testgroup_t {
+ const char *prefix; /**< Prefix to prepend to testnames. */
+ struct testcase_t *cases; /** Array, ending with END_OF_TESTCASES */
+};
+#define END_OF_GROUPS { NULL, NULL}
+
+/** Implementation: called from a test to indicate failure, before logging. */
+void _tinytest_set_test_failed(void);
+/** Implementation: called from a test to indicate that we're skipping. */
+void _tinytest_set_test_skipped(void);
+/** Implementation: return 0 for quiet, 1 for normal, 2 for loud. */
+int _tinytest_get_verbosity(void);
+/** Implementation: Set a flag on tests matching a name; returns number
+ * of tests that matched. */
+int _tinytest_set_flag(struct testgroup_t *, const char *, unsigned long);
+
+/** Set all tests in 'groups' matching the name 'named' to be skipped. */
+#define tinytest_skip(groups, named) \
+ _tinytest_set_flag(groups, named, TT_SKIP)
+
+/** Run a single testcase in a single group. */
+int testcase_run_one(const struct testgroup_t *,const struct testcase_t *);
+/** Run a set of testcases from an END_OF_GROUPS-terminated array of groups,
+ as selected from the command line. */
+int tinytest_main(int argc, const char **argv, struct testgroup_t *groups);
+
+#endif
diff --git a/libevent-2.0.20-stable/test/tinytest_local.h b/libevent-2.0.20-stable/test/tinytest_local.h
new file mode 100644
index 0000000..1a7f75e
--- /dev/null
+++ b/libevent-2.0.20-stable/test/tinytest_local.h
@@ -0,0 +1,12 @@
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+#include "event2/util.h"
+#include "util-internal.h"
+
+#ifdef snprintf
+#undef snprintf
+#endif
+#define snprintf evutil_snprintf
diff --git a/libevent-2.0.20-stable/test/tinytest_macros.h b/libevent-2.0.20-stable/test/tinytest_macros.h
new file mode 100644
index 0000000..1a07ad1
--- /dev/null
+++ b/libevent-2.0.20-stable/test/tinytest_macros.h
@@ -0,0 +1,184 @@
+/* tinytest_macros.h -- Copyright 2009-2012 Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TINYTEST_MACROS_H
+#define _TINYTEST_MACROS_H
+
+/* Helpers for defining statement-like macros */
+#define TT_STMT_BEGIN do {
+#define TT_STMT_END } while (0)
+
+/* Redefine this if your test functions want to abort with something besides
+ * "goto end;" */
+#ifndef TT_EXIT_TEST_FUNCTION
+#define TT_EXIT_TEST_FUNCTION TT_STMT_BEGIN goto end; TT_STMT_END
+#endif
+
+/* Redefine this if you want to note success/failure in some different way. */
+#ifndef TT_DECLARE
+#define TT_DECLARE(prefix, args) \
+ TT_STMT_BEGIN \
+ printf("\n %s %s:%d: ",prefix,__FILE__,__LINE__); \
+ printf args ; \
+ TT_STMT_END
+#endif
+
+/* Announce a failure. Args are parenthesized printf args. */
+#define TT_GRIPE(args) TT_DECLARE("FAIL", args)
+
+/* Announce a non-failure if we're verbose. */
+#define TT_BLATHER(args) \
+ TT_STMT_BEGIN \
+ if (_tinytest_get_verbosity()>1) TT_DECLARE(" OK", args); \
+ TT_STMT_END
+
+#define TT_DIE(args) \
+ TT_STMT_BEGIN \
+ _tinytest_set_test_failed(); \
+ TT_GRIPE(args); \
+ TT_EXIT_TEST_FUNCTION; \
+ TT_STMT_END
+
+#define TT_FAIL(args) \
+ TT_STMT_BEGIN \
+ _tinytest_set_test_failed(); \
+ TT_GRIPE(args); \
+ TT_STMT_END
+
+/* Fail and abort the current test for the reason in msg */
+#define tt_abort_printf(msg) TT_DIE(msg)
+#define tt_abort_perror(op) TT_DIE(("%s: %s [%d]",(op),strerror(errno), errno))
+#define tt_abort_msg(msg) TT_DIE(("%s", msg))
+#define tt_abort() TT_DIE(("%s", "(Failed.)"))
+
+/* Fail but do not abort the current test for the reason in msg. */
+#define tt_fail_printf(msg) TT_FAIL(msg)
+#define tt_fail_perror(op) TT_FAIL(("%s: %s [%d]",(op),strerror(errno), errno))
+#define tt_fail_msg(msg) TT_FAIL(("%s", msg))
+#define tt_fail() TT_FAIL(("%s", "(Failed.)"))
+
+/* End the current test, and indicate we are skipping it. */
+#define tt_skip() \
+ TT_STMT_BEGIN \
+ _tinytest_set_test_skipped(); \
+ TT_EXIT_TEST_FUNCTION; \
+ TT_STMT_END
+
+#define _tt_want(b, msg, fail) \
+ TT_STMT_BEGIN \
+ if (!(b)) { \
+ _tinytest_set_test_failed(); \
+ TT_GRIPE(("%s",msg)); \
+ fail; \
+ } else { \
+ TT_BLATHER(("%s",msg)); \
+ } \
+ TT_STMT_END
+
+/* Assert b, but do not stop the test if b fails. Log msg on failure. */
+#define tt_want_msg(b, msg) \
+ _tt_want(b, msg, );
+
+/* Assert b and stop the test if b fails. Log msg on failure. */
+#define tt_assert_msg(b, msg) \
+ _tt_want(b, msg, TT_EXIT_TEST_FUNCTION);
+
+/* Assert b, but do not stop the test if b fails. */
+#define tt_want(b) tt_want_msg( (b), "want("#b")")
+/* Assert b, and stop the test if b fails. */
+#define tt_assert(b) tt_assert_msg((b), "assert("#b")")
+
+#define tt_assert_test_fmt_type(a,b,str_test,type,test,printf_type,printf_fmt, \
+ setup_block,cleanup_block,die_on_fail) \
+ TT_STMT_BEGIN \
+ type _val1 = (type)(a); \
+ type _val2 = (type)(b); \
+ int _tt_status = (test); \
+ if (!_tt_status || _tinytest_get_verbosity()>1) { \
+ printf_type _print; \
+ printf_type _print1; \
+ printf_type _print2; \
+ type _value = _val1; \
+ setup_block; \
+ _print1 = _print; \
+ _value = _val2; \
+ setup_block; \
+ _print2 = _print; \
+ TT_DECLARE(_tt_status?" OK":"FAIL", \
+ ("assert(%s): "printf_fmt" vs "printf_fmt, \
+ str_test, _print1, _print2)); \
+ _print = _print1; \
+ cleanup_block; \
+ _print = _print2; \
+ cleanup_block; \
+ if (!_tt_status) { \
+ _tinytest_set_test_failed(); \
+ die_on_fail ; \
+ } \
+ } \
+ TT_STMT_END
+
+#define tt_assert_test_type(a,b,str_test,type,test,fmt,die_on_fail) \
+ tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt, \
+ {_print=_value;},{},die_on_fail)
+
+/* Helper: assert that a op b, when cast to type. Format the values with
+ * printf format fmt on failure. */
+#define tt_assert_op_type(a,op,b,type,fmt) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,type,(_val1 op _val2),fmt, \
+ TT_EXIT_TEST_FUNCTION)
+
+#define tt_int_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,long,(_val1 op _val2), \
+ "%ld",TT_EXIT_TEST_FUNCTION)
+
+#define tt_uint_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \
+ (_val1 op _val2),"%lu",TT_EXIT_TEST_FUNCTION)
+
+#define tt_ptr_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,void*, \
+ (_val1 op _val2),"%p",TT_EXIT_TEST_FUNCTION)
+
+#define tt_str_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \
+ (strcmp(_val1,_val2) op 0),"<%s>",TT_EXIT_TEST_FUNCTION)
+
+#define tt_want_int_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,long,(_val1 op _val2),"%ld",(void)0)
+
+#define tt_want_uint_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \
+ (_val1 op _val2),"%lu",(void)0)
+
+#define tt_want_ptr_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,void*, \
+ (_val1 op _val2),"%p",(void)0)
+
+#define tt_want_str_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \
+ (strcmp(_val1,_val2) op 0),"<%s>",(void)0)
+
+#endif