From 75cceac7017a24e33d65f917155ad0d8b15ef178 Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Wed, 20 Jul 2011 10:17:20 +0200 Subject: [PATCH] Update libevent to 2.0.12 --- libevent/ChangeLog | 120 +++++++++ libevent/Makefile.am | 45 ++-- libevent/README | 15 +- libevent/WIN32-Code/event2/event-config.h | 7 +- libevent/arc4random.c | 6 +- libevent/bufferevent-internal.h | 15 ++ libevent/bufferevent.c | 18 ++ libevent/bufferevent_async.c | 9 + libevent/bufferevent_filter.c | 1 + libevent/bufferevent_openssl.c | 1 + libevent/bufferevent_sock.c | 1 + libevent/configure.in | 244 +++++++++++++++--- libevent/evdns.c | 25 +- libevent/event-internal.h | 12 +- libevent/event.c | 35 ++- libevent/event_iocp.c | 4 + libevent/evmap.c | 2 +- libevent/evport.c | 18 +- libevent/evrpc.c | 8 +- libevent/evthread.c | 1 + libevent/evthread_win32.c | 4 + libevent/evutil.c | 72 +++++- libevent/http.c | 300 ++++++++++++++++++---- libevent/include/Makefile.am | 11 +- libevent/include/event2/event.h | 18 +- libevent/include/event2/http.h | 33 ++- libevent/ipv6-internal.h | 9 + libevent/kqueue.c | 46 +++- libevent/libevent_openssl.pc.in | 2 +- libevent/listener.c | 4 + libevent/sample/Makefile.am | 4 +- libevent/sample/dns-example.c | 8 +- libevent/sample/hello-world.c | 3 + libevent/sample/http-server.c | 18 +- libevent/select.c | 42 ++- libevent/test/Makefile.am | 29 ++- libevent/test/bench.c | 9 +- libevent/test/bench_cascade.c | 9 +- libevent/test/bench_httpclient.c | 14 +- libevent/test/regress.c | 29 ++- libevent/test/regress_buffer.c | 2 + libevent/test/regress_bufferevent.c | 2 +- libevent/test/regress_dns.c | 9 +- libevent/test/regress_http.c | 178 +++++++++---- libevent/test/regress_listener.c | 3 + libevent/test/regress_ssl.c | 1 + libevent/test/regress_testutils.c | 2 + libevent/test/regress_zlib.c | 24 +- libevent/test/test-eof.c | 12 +- libevent/test/test-ratelim.c | 5 + libevent/test/test.sh | 17 +- libevent/test/tinytest_local.h | 3 + libevent/util-internal.h | 27 +- libevent/whatsnew-2.0.txt | 2 +- 54 files changed, 1266 insertions(+), 272 deletions(-) diff --git a/libevent/ChangeLog b/libevent/ChangeLog index 18e4a6b0..d8dc3b1c 100644 --- a/libevent/ChangeLog +++ b/libevent/ChangeLog @@ -1,3 +1,123 @@ +Changes in version 2.0.12-stable (4 Jun 2011) +BUGFIXES + o Fix a warn-and-fail bug in kqueue by providing kevent() room to report errors (28317a0) + o Fix an assert-inducing fencepost bug in the select backend (d90149d) + o Fix failing http assertion introducd in commit 0d6622e (0848814 Kevin Ko) + o Fix a bug that prevented us from configuring IPv6 nameservers. (74760f1) + o Prevent size_t overflow in evhttp_htmlescape. (06c51cd Mansour Moufid) + o Added several checks for under/overflow conditions in evhttp_handle_chunked_read (a279272 Mark Ellzey) + o Added overflow checks in evhttp_read_body and evhttp_get_body (84560fc Mark Ellzey) + +DOCUMENTATION: + o Add missing words to EVLOOP_NONBLOCK documentation (9556a7d) + +BUILD FIXES + o libssl depends on libcrypto, not the other way around. (274dd03 Peter Rosin) + o Libtool brings in the dependencies of libevent_openssl.la automatically (7b819f2 Peter Rosin) + o Use OPENSSL_LIBS in Makefile.am (292092e Sebastian Hahn) + o Move the win32 detection in configure.in (ceb03b9 Sebastian Hahn) + o Correctly detect openssl on windows (6619385 Sebastian Hahn) + o Fix a compile warning with zlib 1.2.4 and 1.2.5 (5786b91 Sebastian Hahn) + o Fix compilation with GCC 2, which had no __builtin_expect (09d39a1 Dave Hart) + o Fix new warnings from GCC 4.6 (06a714f) + o Link with -lshell32 and -ladvapi32 on Win32. (86090ee Peter Rosin) + o Make the tests build when OpenSSL is not available. (07c41be Peter Rosin) + o Bring in the compile script from automake, if needed. (f3c7a4c Peter Rosin) + o MSVC does not provide S_ISDIR, so provide it manually. (70be7d1 Peter Rosin) + o unistd.h and sys/time.h might not exist. (fe93022 Peter Rosin) + o Make sure TINYTEST_LOCAL is defined when building tinytest.c (8fa030c Peter Rosin) + o Fix winsock2.h #include issues with MSVC (3d768dc Peter Rosin) + o Use evutil_gettimeofday instead of relying on the system gettimeofday. (0de87fe Peter Rosin) + o Always use evutil_snprintf, even if OS provides it (d1b2d11 Sebastian Hahn) + o InitializeCriticalSectionAndSpinCount requires _WIN32_WINNT >= 0x0403. (816115a Peter Rosin) + o cygwin: make it possible to build DLLs (d54d3fc) + + + +Changes in version 2.0.11-stable (27 Apr 2011) + [Autogenerated from the Git log, sorted and cleaned by hand.] +BUGFIXES: + o Fix evport handling of POLLHUP and POLLERR (b42ce4b) + o Fix compilation on Windows with NDEBUG (cb8059d) + o Check for POLLERR, POLLHUP and POLLNVAL for Solaris event ports (0144886 Trond Norbye) + o Detect and handle more allocation failures. (666b096 Jardel Weyrich) + o Use event_err() only if the failure is truly unrecoverable. (3f8d22a Jardel Weyrich) + o Handle resize failures in the select backend better. (83e805a) + o Correctly free selectop fields when select_resize fails in select_init (0c0ec0b) + o Make --enable-gcc-warnings a no-op if not using gcc (3267703) + o Fix a type error in our (unused) arc4random_stir() (f736198) + o Correctly detect and stop non-chunked http requests when the body is too long (63a715e) + o Have event_base_gettimeofday_cached() always return wall-clock time (a459ef7) + o Workaround for http crash bug 3078187 (5dc5662 Tomash Brechko) + o Fix incorrect assertions and possible use-after-free in evrpc_free() (4b8f02f Christophe Fillot) + o Reset outgoing http connection when read data in idle state. (272823f Tomash Brechko) + o Fix subtle recursion in evhttp_connection_cb_cleanup(). (218cf19 Tomash Brechko) + o Fix the case when failed evhttp_make_request() leaved request in the queue. (0d6622e Tomash Brechko) + o Fix a crash bug in evdns server circular list code (00e91b3) + o Handle calloc failure in evdns. (Found by Dave Hart) (364291e) + o Fix a memory leak on win32 socket->event map. (b4f89f0) + o Add a forgotten NULL check to evhttp_parse_headers (12311ff Sebastian Hahn) + o Fix possible NULL-deref in evdns_cancel_request (5208544 Sebastian Hahn) + +PORTABILITY: + o Fall back to sscanf if we have no other way to implement strtoll (453317b) + o Build correctly on platforms without sockaddr_storage (9184563) + o Try to build correctly on platforms with no IPv6 support (713c254) + o Build on systems without AI_PASSIVE (cb92113) + o Fix http unit test on non-windows platforms without getaddrinfo (6092f12) + o Do not check for gethostbyname_r versions if we have getaddrinfo (c1260b0) + o Include arpa/inet.h as needed on HPUX (10c834c Harlan Stenn) + o Include util-internal.h as needed to build on platforms with no sockaddr_storage (bbf5515 Harlan Stenn) + o Check for getservbyname even if not on win32. (af08a94 Harlan Stenn) + o Add -D_OSF_SOURCE to fix hpux builds (0b33479 Harlan Stenn) + o Check for allocation failures in apply_socktype_protocol_hack (637d17a) + o Fix the check for multicast or broadcast addresses in evutil_check_interfaces (1a21d7b) + o Avoid a free(NULL) if out-of-memory in evdns_getaddrinfo. Found by Dave Hart (3417f68) + +DEFENSIVE PROGRAMMING: + o Add compile-time check for AF_UNSPEC==PF_UNSPEC (3c8f4e7) + +BUGS IN TESTS: + o Fix test.sh output on solaris (b4f89b6 Dave Hart) + o Make test-eof fail with a timeout if we never get an eof. (05a2c22 Harlan Stenn) + o Use %s with printf in test.sh (039b9bd) + o Add an assert to appease clang's static analyzer (b0ff7eb Sebastian Hahn) + o Add a forgotten return value check in the unit tests (3819b62 Sebastian Hahn) + o Actually send NULL request in http_bad_request_test (b693c32 Sebastian Hahn) + o add some (void) casts for unused variables (65707d7 Sebastian Hahn) + o Refactor test_getaddrinfo_async_cancel_stress() (48c44a6 Sebastian Hahn) + o Be nice and "handle" error return values in sample code (4bac793 Sebastian Hahn) + o Check return value of evbuffer_add_cb in tests (93a1abb Sebastian Hahn) + o Remote some dead code from dns-example.c (744c745 Sebastian Hahn) + o Zero a struct sockaddr_in before using it (646f9fe Sebastian Hahn) + +BUILD FIXES: + o Fix warnings about AC_LANG_PROGRAM usage (f663112 Sebastian Hahn) + o Skip check for zlib if we have no zlib.h (a317c06 Harlan Stenn) + o Fix autoconf bracket issues; make check for getaddrinfo include netdb.h (833e5e9 Harlan Stenn) + o Correct an AM_CFLAGS to an AM_CPPFLAGS in test/Makefile.am (9c469db Dave Hart) + o Fix make distcheck & installation of libevent 1 headers (b5a1f9f Dave Hart) + o Fix compilation under LLVM/clang with --enable-gcc-warnings (ad9ff58 Sebastian Hahn) + +FEATURES: + o Make URI parser able to tolerate nonconformant URIs. (95060b5) + +DOCUMENTATION: + o Clarify event_set_mem_functions doc (926f816) + o Correct evhttp_del_accept_socket documentation on whether socket is closed (f665924) + o fix spelling mistake in whatsnew-2.0.txt (deb2f73) + o Fix sample/http-server ipv6 fixes (eb692be) + o Comment internal headers used in sample code. (4eb281c) + o Be explicit about how long event loops run in event.h documentation (f95bafb) + o Add comment to configure.in to explain gc-sections test logic (c621359) + o Fix a couple of memory leaks in samples/http-server.c. Found by Dave Hart. (2e9f665) + +BUILD IMPROVEMENTS: + o Use the gcc -ffunction-segments feature to allow gc when linking with static libevent (0965c56 Dave Hart) + o Add configure options to disable installation, regression tests (49e9bb7 Dave Hart) + + + Changes in version 2.0.10-stable (16 Dec 2010) [Autogenerated from the Git log, sorted and cleaned by hand.] BUGFIXES diff --git a/libevent/Makefile.am b/libevent/Makefile.am index dda19b22..bf3ae500 100644 --- a/libevent/Makefile.am +++ b/libevent/Makefile.am @@ -32,7 +32,7 @@ RELEASE = -release 2.0 # # Once an RC is out, DO NOT MAKE ANY ABI-BREAKING CHANGES IN THAT SERIES # UNLESS YOU REALLY REALLY HAVE TO. -VERSION_INFO = 5:1:0 +VERSION_INFO = 6:1:1 # History: RELEASE VERSION_INFO # 2.0.1-alpha -- 2.0 1:0:0 @@ -44,8 +44,9 @@ VERSION_INFO = 5:1:0 # 2.0.7-rc -- 2.0 3:0:1 # 2.0.8-rc -- 2.0 4:0:2 # 2.0.9-rc -- 2.0 5:0:0 (ABI changed slightly) -# Planned: # 2.0.10-stable-- 2.0 5:1:0 (No ABI change) +# 2.0.11-stable-- 2.0 6:0:1 (ABI changed, backward-compatible) +# 2.0.12-stable-- 2.0 6:1:1 (No ABI change) # # For Libevent 2.1: # 2.1.1-alpha -- 2.1 1:0:0 @@ -72,7 +73,7 @@ VERSION_INFO = 5:1:0 dist_bin_SCRIPTS = event_rpcgen.py pkgconfigdir=$(libdir)/pkgconfig -pkgconfig_DATA=libevent.pc +LIBEVENT_PKGCONFIG=libevent.pc # These sources are conditionally added by configure.in or conditionally # included from other files. @@ -89,21 +90,28 @@ EXTRA_DIST = \ Makefile.nmake test/Makefile.nmake \ $(PLATFORM_DEPENDENT_SRC) -lib_LTLIBRARIES = libevent.la libevent_core.la libevent_extra.la +LIBEVENT_LIBS_LA = libevent.la libevent_core.la libevent_extra.la if PTHREADS -lib_LTLIBRARIES += libevent_pthreads.la -pkgconfig_DATA += libevent_pthreads.pc +LIBEVENT_LIBS_LA += libevent_pthreads.la +LIBEVENT_PKGCONFIG += libevent_pthreads.pc endif if OPENSSL -lib_LTLIBRARIES += libevent_openssl.la -pkgconfig_DATA += libevent_openssl.pc +LIBEVENT_LIBS_LA += libevent_openssl.la +LIBEVENT_PKGCONFIG += libevent_openssl.pc +endif + +if INSTALL_LIBEVENT +lib_LTLIBRARIES = $(LIBEVENT_LIBS_LA) +pkgconfig_DATA = $(LIBEVENT_PKGCONFIG) +else +noinst_LTLIBRARIES = $(LIBEVENT_LIBS_LA) endif SUBDIRS = . include sample test if BUILD_WIN32 -SYS_LIBS = -lws2_32 +SYS_LIBS = -lws2_32 -lshell32 -ladvapi32 SYS_SRC = win32select.c evthread_win32.c buffer_iocp.c event_iocp.c \ bufferevent_async.c SYS_INCLUDES = -IWIN32-Code @@ -165,7 +173,7 @@ CORE_SRC = event.c evthread.c buffer.c \ evmap.c log.c evutil.c evutil_rand.c strlcpy.c $(SYS_SRC) EXTRA_SRC = event_tagging.c http.c evdns.c evrpc.c -if BUILD_WIN32 +if BUILD_WITH_NO_UNDEFINED NO_UNDEFINED = -no-undefined MAYBE_CORE = libevent_core.la else @@ -173,7 +181,7 @@ NO_UNDEFINED = MAYBE_CORE = endif -GENERIC_LDFLAGS = -static +GENERIC_LDFLAGS = -version-info $(VERSION_INFO) $(RELEASE) $(NO_UNDEFINED) libevent_la_SOURCES = $(CORE_SRC) $(EXTRA_SRC) libevent_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS) @@ -185,6 +193,7 @@ libevent_core_la_LDFLAGS = $(GENERIC_LDFLAGS) if PTHREADS libevent_pthreads_la_SOURCES = evthread_pthread.c +libevent_pthreads_la_LIBADD = $(MAYBE_CORE) libevent_pthreads_la_LDFLAGS = $(GENERIC_LDFLAGS) endif @@ -194,7 +203,7 @@ libevent_extra_la_LDFLAGS = $(GENERIC_LDFLAGS) if OPENSSL libevent_openssl_la_SOURCES = bufferevent_openssl.c -libevent_openssl_la_LIBADD = $(MAYBE_CORE) -lcrypto -lssl +libevent_openssl_la_LIBADD = $(MAYBE_CORE) $(OPENSSL_LIBS) libevent_openssl_la_LDFLAGS = $(GENERIC_LDFLAGS) endif @@ -209,9 +218,15 @@ noinst_HEADERS = util-internal.h mm-internal.h ipv6-internal.h \ WIN32-Code/tree.h \ compat/sys/queue.h -include_HEADERS = event.h evhttp.h evdns.h evrpc.h evutil.h +EVENT1_HDRS = event.h evhttp.h evdns.h evrpc.h evutil.h -INCLUDES = -I$(srcdir)/compat -I$(srcdir)/include -I./include $(SYS_INCLUDES) +if INSTALL_LIBEVENT +include_HEADERS = $(EVENT1_HDRS) +else +noinst_HEADERS += $(EVENT1_HDRS) +endif + +AM_CPPFLAGS = -I$(srcdir)/compat -I$(srcdir)/include -I./include $(SYS_INCLUDES) verify: check @@ -221,5 +236,3 @@ FORCE: DISTCLEANFILES = *~ libevent.pc ./include/event2/event-config.h -install: - diff --git a/libevent/README b/libevent/README index 5ee7d969..bed2121a 100644 --- a/libevent/README +++ b/libevent/README @@ -82,6 +82,7 @@ fixing bugs: Denis Bilenko Julien Blache Kevin Bowling + Tomash Brechko Kelly Brock Ralph Castain Shuo Chen @@ -92,20 +93,24 @@ fixing bugs: Mihai Draghicioiu Mark Ellzey Shie Erlich + Christophe Fillot Alexander von Gernler Artur Grabowski + Dave Hart Michael Herf Sebastian Hahn Aaron Hopkins Tani Hosokawa Claudio Jeker Evan Jones - Valery Kyholodov + Phua Keat + Kevin Ko + Brian Koehmstedt Marko Kreen + Valery Kyholodov Scott Lamb Christopher Layne Adam Langley - Christopher Layne Philip Lewis Zhou Li David Libenzi @@ -119,6 +124,7 @@ fixing bugs: Andrey Matveev Caitlin Mercer Dagobert Michelsen + Mansour Moufid Felix Nawothnig Trond Norbye Linus Nordberg @@ -133,18 +139,23 @@ fixing bugs: Dimitre Piskyulev Pavel Plesov Jon Poland + Robert Ransom Bert JW Regeer + Peter Rosin Hanna Schroeter Ralf Schmitt Mike Smellie Kevin Springborn + Harlan Stenn Ferenc Szalai Dug Song + Dongsheng Song Brodie Thiesfield Jason Toffaletti Bas Verhoeven Constantine Verutin Zack Weinberg + Jardel Weyrich Taral propanbutan mmadia diff --git a/libevent/WIN32-Code/event2/event-config.h b/libevent/WIN32-Code/event2/event-config.h index 8a441074..7c022d65 100644 --- a/libevent/WIN32-Code/event2/event-config.h +++ b/libevent/WIN32-Code/event2/event-config.h @@ -192,6 +192,9 @@ /* Define to 1 if `sin_len' is member of `struct sockaddr_in'. */ /* #undef _EVENT_HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ +/* Define to 1 if the system has the type `struct sockaddr_storage'. */ +#define _EVENT_HAVE_STRUCT_SOCKADDR_STORAGE 1 + /* Define to 1 if you have the header file. */ /* #undef _EVENT_HAVE_SYS_DEVPOLL_H */ @@ -274,7 +277,7 @@ /* #undef _EVENT_HAVE_WORKING_KQUEUE */ /* Numeric representation of the version */ -#define _EVENT_NUMERIC_VERSION 0x02000a00 +#define _EVENT_NUMERIC_VERSION 0x02000c00 /* Name of package */ #define _EVENT_PACKAGE "libevent" @@ -331,7 +334,7 @@ #define _EVENT_TIME_WITH_SYS_TIME 1 /* Version number of package */ -#define _EVENT_VERSION "2.0.10-stable" +#define _EVENT_VERSION "2.0.12-stable" /* Define to appropriate substitue if compiler doesnt have __func__ */ #define _EVENT___func__ __FUNCTION__ diff --git a/libevent/arc4random.c b/libevent/arc4random.c index b6d2c5b3..4833169a 100644 --- a/libevent/arc4random.c +++ b/libevent/arc4random.c @@ -352,7 +352,7 @@ arc4_seed(void) return ok ? 0 : -1; } -static void +static int arc4_stir(void) { int i; @@ -363,6 +363,8 @@ arc4_stir(void) } arc4_seed(); + if (!arc4_seeded_ok) + return -1; /* * Discard early keystream, as per recommendations in @@ -385,6 +387,8 @@ arc4_stir(void) for (i = 0; i < 12*256; i++) (void)arc4_getbyte(); arc4_count = BYTES_BEFORE_RESEED; + + return 0; } diff --git a/libevent/bufferevent-internal.h b/libevent/bufferevent-internal.h index 9d84e739..71711a36 100644 --- a/libevent/bufferevent-internal.h +++ b/libevent/bufferevent-internal.h @@ -36,6 +36,7 @@ extern "C" { #include "evthread-internal.h" #include "event2/thread.h" #include "ratelim-internal.h" +#include "event2/bufferevent_struct.h" /* These flags are reasons that we might be declining to actually enable reading or writing on a bufferevent. @@ -287,6 +288,20 @@ void bufferevent_unsuspend_write(struct bufferevent *bufev, bufferevent_suspend_ #define bufferevent_wm_unsuspend_read(b) \ bufferevent_unsuspend_read((b), BEV_SUSPEND_WM) +/* + Disable a bufferevent. Equivalent to bufferevent_disable(), but + first resets 'connecting' flag to force EV_WRITE down for sure. + + XXXX this method will go away in the future; try not to add new users. + See comment in evhttp_connection_reset() for discussion. + + @param bufev the bufferevent to be disabled + @param event any combination of EV_READ | EV_WRITE. + @return 0 if successful, or -1 if an error occurred + @see bufferevent_disable() + */ +int bufferevent_disable_hard(struct bufferevent *bufev, short event); + /** Internal: Set up locking on a bufferevent. If lock is set, use it. * Otherwise, use a new lock. */ int bufferevent_enable_locking(struct bufferevent *bufev, void *lock); diff --git a/libevent/bufferevent.c b/libevent/bufferevent.c index 4c9e38fa..9855d183 100644 --- a/libevent/bufferevent.c +++ b/libevent/bufferevent.c @@ -473,6 +473,24 @@ bufferevent_settimeout(struct bufferevent *bufev, } +int +bufferevent_disable_hard(struct bufferevent *bufev, short event) +{ + int r = 0; + struct bufferevent_private *bufev_private = + EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); + + BEV_LOCK(bufev); + bufev->enabled &= ~event; + + bufev_private->connecting = 0; + if (bufev->be_ops->disable(bufev, event) < 0) + r = -1; + + BEV_UNLOCK(bufev); + return r; +} + int bufferevent_disable(struct bufferevent *bufev, short event) { diff --git a/libevent/bufferevent_async.c b/libevent/bufferevent_async.c index b7284fda..76a16162 100644 --- a/libevent/bufferevent_async.c +++ b/libevent/bufferevent_async.c @@ -63,6 +63,11 @@ #include "util-internal.h" #include "iocp-internal.h" +#ifndef SO_UPDATE_CONNECT_CONTEXT +/* Mingw is sometimes missing this */ +#define SO_UPDATE_CONNECT_CONTEXT 0x7010 +#endif + /* prototypes */ static int be_async_enable(struct bufferevent *, short); static int be_async_disable(struct bufferevent *, short); @@ -403,11 +408,15 @@ connect_complete(struct event_overlapped *eo, ev_uintptr_t key, { struct bufferevent_async *bev_a = upcast_connect(eo); struct bufferevent *bev = &bev_a->bev.bev; + evutil_socket_t sock; BEV_LOCK(bev); EVUTIL_ASSERT(bev_a->bev.connecting); bev_a->bev.connecting = 0; + sock = _evbuffer_overlapped_get_fd(bev_a->bev.bev.input); + /* XXXX Handle error? */ + setsockopt(sock, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0); if (ok) bufferevent_async_set_connected(bev); diff --git a/libevent/bufferevent_filter.c b/libevent/bufferevent_filter.c index 6886aca0..7f19eb9a 100644 --- a/libevent/bufferevent_filter.c +++ b/libevent/bufferevent_filter.c @@ -428,6 +428,7 @@ be_filter_readcb(struct bufferevent *underlying, void *_me) /* XXXX use return value */ res = be_filter_process_input(bevf, state, &processed_any); + (void)res; /* XXX This should be in process_input, not here. There are * other places that can call process-input, and they should diff --git a/libevent/bufferevent_openssl.c b/libevent/bufferevent_openssl.c index 3d9a7701..02a6222a 100644 --- a/libevent/bufferevent_openssl.c +++ b/libevent/bufferevent_openssl.c @@ -1013,6 +1013,7 @@ be_openssl_outbuf_cb(struct evbuffer *buf, consider_writing(bev_ssl); } /* XXX Handle r < 0 */ + (void)r; } diff --git a/libevent/bufferevent_sock.c b/libevent/bufferevent_sock.c index 1d76ea14..6aff91ea 100644 --- a/libevent/bufferevent_sock.c +++ b/libevent/bufferevent_sock.c @@ -451,6 +451,7 @@ bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai, /* XXX use the other addrinfos? */ /* XXX use this return value */ r = bufferevent_socket_connect(bev, ai->ai_addr, (int)ai->ai_addrlen); + (void)r; _bufferevent_decref_and_unlock(bev); evutil_freeaddrinfo(ai); } diff --git a/libevent/configure.in b/libevent/configure.in index 7b8f2af6..5e142c90 100644 --- a/libevent/configure.in +++ b/libevent/configure.in @@ -5,17 +5,30 @@ AC_INIT(event.c) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE(libevent,2.0.10-stable) +AM_INIT_AUTOMAKE(libevent,2.0.12-stable) AM_CONFIG_HEADER(config.h) -AC_DEFINE(NUMERIC_VERSION, 0x02000a00, [Numeric representation of the version]) +AC_DEFINE(NUMERIC_VERSION, 0x02000c00, [Numeric representation of the version]) dnl Initialize prefix. if test "$prefix" = "NONE"; then prefix="/usr/local" fi +AC_CANONICAL_BUILD +AC_CANONICAL_HOST +dnl the 'build' machine is where we run configure and compile +dnl the 'host' machine is where the resulting stuff runs. + +case "$host_os" in + + osf5*) + CFLAGS="$CFLAGS -D_OSF_SOURCE" + ;; +esac + dnl Checks for programs. AC_PROG_CC +AM_PROG_CC_C_O AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MKDIR_P @@ -44,6 +57,16 @@ AC_ARG_ENABLE(openssl, AC_ARG_ENABLE(debug-mode, AS_HELP_STRING(--disable-debug-mode, disable support for running in debug mode), [], [enable_debug_mode=yes]) +AC_ARG_ENABLE([libevent-install], + AS_HELP_STRING([--disable-libevent-install, disable installation of libevent]), + [], [enable_libevent_install=yes]) +AC_ARG_ENABLE([libevent-regress], + AS_HELP_STRING([--disable-libevent-regress, skip regress in make check]), + [], [enable_libevent_regress=yes]) +AC_ARG_ENABLE([function-sections], + AS_HELP_STRING([--enable-function-sections, make static library allow smaller binaries with --gc-sections]), + [], [enable_function_sections=no]) + AC_PROG_LIBTOOL @@ -53,6 +76,8 @@ dnl the command line with --enable-shared and --disable-shared. dnl AC_DISABLE_SHARED AC_SUBST(LIBTOOL_DEPS) +AM_CONDITIONAL([BUILD_REGRESS], [test "$enable_libevent_regress" = "yes"]) + dnl Checks for libraries. AC_SEARCH_LIBS([inet_ntoa], [nsl]) AC_SEARCH_LIBS([socket], [socket]) @@ -60,6 +85,35 @@ AC_SEARCH_LIBS([inet_aton], [resolv]) AC_SEARCH_LIBS([clock_gettime], [rt]) AC_SEARCH_LIBS([sendfile], [sendfile]) +dnl - check if the macro WIN32 is defined on this compiler. +dnl - (this is how we check for a windows version of GCC) +AC_MSG_CHECKING(for WIN32) +AC_TRY_COMPILE(, + [ +#ifndef WIN32 +die horribly +#endif + ], + bwin32=true; AC_MSG_RESULT(yes), + bwin32=false; AC_MSG_RESULT(no), +) + +dnl - check if the macro __CYGWIN__ is defined on this compiler. +dnl - (this is how we check for a cygwin version of GCC) +AC_MSG_CHECKING(for CYGWIN) +AC_TRY_COMPILE(, + [ +#ifndef __CYGWIN__ +die horribly +#endif + ], + cygwin=true; AC_MSG_RESULT(yes), + cygwin=false; AC_MSG_RESULT(no), +) + +AC_CHECK_HEADERS([zlib.h]) + +if test "x$ac_cv_header_zlib_h" = "xyes"; then dnl Determine if we have zlib for regression tests dnl Don't put this one in LIBS save_LIBS="$LIBS" @@ -72,25 +126,40 @@ AC_SEARCH_LIBS([inflateEnd], [z], AC_DEFINE(HAVE_LIBZ, 1, [Define if the system has zlib])]) LIBS="$save_LIBS" AC_SUBST(ZLIB_LIBS) +fi AM_CONDITIONAL(ZLIB_REGRESS, [test "$have_zlib" = "yes"]) dnl See if we have openssl. This doesn't go in LIBS either. +if test "$bwin32" = true; then + EV_LIB_WS32=-lws2_32 + EV_LIB_GDI=-lgdi32 +else + EV_LIB_WS32= + EV_LIB_GDI= +fi +AC_SUBST(EV_LIB_WS32) +AC_SUBST(EV_LIB_GDI) + +AC_CHECK_HEADERS([openssl/bio.h]) + if test "$enable_openssl" = "yes"; then save_LIBS="$LIBS" LIBS="" OPENSSL_LIBS="" have_openssl=no AC_SEARCH_LIBS([SSL_new], [ssl], - [have_openssl=yes - OPENSSL_LIBS="$LIBS" - AC_DEFINE(HAVE_OPENSSL, 1, [Define if the system has openssl])]) + [have_openssl=yes + OPENSSL_LIBS="$LIBS -lcrypto $EV_LIB_GDI $EV_LIB_WS32" + AC_DEFINE(HAVE_OPENSSL, 1, [Define if the system has openssl])], + [have_openssl=no], + [-lcrypto $EV_LIB_GDI $EV_LIB_WS32]) LIBS="$save_LIBS" AC_SUBST(OPENSSL_LIBS) fi dnl Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS(fcntl.h stdarg.h inttypes.h stdint.h stddef.h poll.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/param.h sys/ioctl.h sys/select.h sys/devpoll.h port.h netinet/in.h netinet/in6.h sys/socket.h sys/uio.h arpa/inet.h sys/eventfd.h sys/mman.h sys/sendfile.h sys/wait.h netdb.h) +AC_CHECK_HEADERS([fcntl.h stdarg.h inttypes.h stdint.h stddef.h poll.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/param.h sys/ioctl.h sys/select.h sys/devpoll.h port.h netinet/in.h netinet/in6.h sys/socket.h sys/uio.h arpa/inet.h sys/eventfd.h sys/mman.h sys/sendfile.h sys/wait.h netdb.h]) AC_CHECK_HEADERS(sys/sysctl.h, [], [], [ #ifdef HAVE_SYS_PARAM_H #include @@ -174,20 +243,9 @@ if test "x$ac_cv_header_sys_sysctl_h" = "xyes"; then ) fi -dnl - check if the macro WIN32 is defined on this compiler. -dnl - (this is how we check for a windows version of GCC) -AC_MSG_CHECKING(for WIN32) -AC_TRY_COMPILE(, - [ -#ifndef WIN32 -die horribly -#endif - ], - bwin32=true; AC_MSG_RESULT(yes), - bwin32=false; AC_MSG_RESULT(no), -) - AM_CONDITIONAL(BUILD_WIN32, test x$bwin32 = xtrue) +AM_CONDITIONAL(BUILD_CYGWIN, test x$cygwin = xtrue) +AM_CONDITIONAL(BUILD_WITH_NO_UNDEFINED, test x$bwin32 = xtrue || test x$cygwin = xtrue) if test x$bwin32 = xtrue; then AC_SEARCH_LIBS([getservbyname],[ws2_32]) @@ -199,8 +257,32 @@ AC_C_INLINE AC_HEADER_TIME dnl Checks for library functions. -AC_CHECK_FUNCS(gettimeofday vasprintf fcntl clock_gettime strtok_r strsep getaddrinfo getnameinfo strlcpy inet_ntop inet_pton signal sigaction strtoll inet_aton pipe eventfd sendfile mmap splice arc4random arc4random_buf issetugid geteuid getegid getservbyname getprotobynumber setenv unsetenv putenv) +AC_CHECK_FUNCS([gettimeofday vasprintf fcntl clock_gettime strtok_r strsep]) +AC_CHECK_FUNCS([getnameinfo strlcpy inet_ntop inet_pton signal sigaction strtoll inet_aton pipe eventfd sendfile mmap splice arc4random arc4random_buf issetugid geteuid getegid getprotobynumber setenv unsetenv putenv]) + +AC_CACHE_CHECK( + [for getaddrinfo], + [libevent_cv_getaddrinfo], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ + #ifdef HAVE_NETDB_H + #include + #endif + ]], + [[ + getaddrinfo; + ]] + )], + [libevent_cv_getaddrinfo=yes], + [libevent_cv_getaddrinfo=no] + )] +) +if test "$libevent_cv_getaddrinfo" = "yes" ; then + AC_DEFINE([HAVE_GETADDRINFO], [1], [Do we have getaddrinfo()?]) +else +AC_CHECK_FUNCS([getservbyname]) # Check for gethostbyname_r in all its glorious incompatible versions. # (This is cut-and-pasted from Tor, which based its logic on # Python's configure.in.) @@ -211,14 +293,14 @@ AC_CHECK_FUNC(gethostbyname_r, [ AC_MSG_CHECKING([how many arguments gethostbyname_r() wants]) OLD_CFLAGS=$CFLAGS CFLAGS="$CFLAGS $MY_CPPFLAGS $MY_THREAD_CPPFLAGS $MY_CFLAGS" - AC_COMPILE_IFELSE(AC_LANG_PROGRAM([ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include ], [[ char *cp1, *cp2; struct hostent *h1, *h2; int i1, i2; (void)gethostbyname_r(cp1,h1,cp2,i1,&h2,&i2); - ]]),[ + ]])],[ AC_DEFINE(HAVE_GETHOSTBYNAME_R) AC_DEFINE(HAVE_GETHOSTBYNAME_R_6_ARG, 1, [Define this if gethostbyname_r takes 6 arguments]) @@ -257,6 +339,7 @@ AC_CHECK_FUNC(gethostbyname_r, [ CFLAGS=$OLD_CFLAGS ]) +fi AC_CHECK_SIZEOF(long) @@ -443,7 +526,7 @@ AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(size_t) AC_CHECK_SIZEOF(void *) -AC_CHECK_TYPES([struct in6_addr, struct sockaddr_in6, sa_family_t, struct addrinfo], , , +AC_CHECK_TYPES([struct in6_addr, struct sockaddr_in6, sa_family_t, struct addrinfo, struct sockaddr_storage], , , [#define _GNU_SOURCE #include #ifdef HAVE_NETINET_IN_H @@ -559,22 +642,32 @@ AM_CONDITIONAL(OPENSSL, [test "$enable_openssl" != "no" && test "$have_openssl" # Add some more warnings which we use in development but not in the # released versions. (Some relevant gcc versions can't handle these.) -if test x$enable_gcc_warnings = xyes; then +if test x$enable_gcc_warnings = xyes && test "$GCC" = "yes"; then - AC_COMPILE_IFELSE(AC_LANG_PROGRAM([], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [ #if !defined(__GNUC__) || (__GNUC__ < 4) #error -#endif]), have_gcc4=yes, have_gcc4=no) +#endif])], have_gcc4=yes, have_gcc4=no) - AC_COMPILE_IFELSE(AC_LANG_PROGRAM([], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [ #if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 2) #error -#endif]), have_gcc42=yes, have_gcc42=no) +#endif])], have_gcc42=yes, have_gcc42=no) - AC_COMPILE_IFELSE(AC_LANG_PROGRAM([], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [ #if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) #error -#endif]), have_gcc45=yes, have_gcc45=no) +#endif])], have_gcc45=yes, have_gcc45=no) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [ +#if !defined(__clang__) +#error +#endif])], have_clang=yes, have_clang=no) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [ +#if !defined(__clang__) || (__clang_major__ > 2) || (__clang_major__ == 2 && __clang_minor__ > 9) +#error +#endif])], have_clang29orlower=yes, have_clang29orlower=no) CFLAGS="$CFLAGS -W -Wfloat-equal -Wundef -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings -Wredundant-decls -Wchar-subscripts -Wcomment -Wformat -Wwrite-strings -Wmissing-declarations -Wredundant-decls -Wnested-externs -Wbad-function-cast -Wswitch-enum -Werror" CFLAGS="$CFLAGS -Wno-unused-parameter -Wstrict-aliasing" @@ -587,17 +680,106 @@ if test x$enable_gcc_warnings = xyes; then if test x$have_gcc42 = xyes ; then # These warnings break gcc 4.0.2 and work on gcc 4.2 - CFLAGS="$CFLAGS -Waddress -Wnormalized=id -Woverride-init" + CFLAGS="$CFLAGS -Waddress" + fi + + if test x$have_gcc42 = xyes && test x$have_clang29orlower = xno; then + # These warnings break gcc 4.0.2 and clang, but work on gcc 4.2 + # We only disable these for clang 2.9 and lower, in case they are + # supported in later versions. + CFLAGS="$CFLAGS -Wnormalized=id -Woverride-init" fi if test x$have_gcc45 = xyes ; then # These warnings work on gcc 4.5 CFLAGS="$CFLAGS -Wlogical-op" fi + + if test x$have_clang = xyes; then + # Disable the unused-function warnings, because these trigger + # for minheap-internal.h related code. + CFLAGS="$CFLAGS -Wno-unused-function" + fi + ##This will break the world on some 64-bit architectures # CFLAGS="$CFLAGS -Winline" fi +LIBEVENT_GC_SECTIONS= +if test "$GCC" = yes && test "$enable_function_sections" = yes ; then + AC_CACHE_CHECK( + [if linker supports omitting unused code and data], + [libevent_cv_gc_sections_runs], + [ + dnl NetBSD will link but likely not run with --gc-sections + dnl http://bugs.ntp.org/1844 + dnl http://gnats.netbsd.org/40401 + dnl --gc-sections causes attempt to load as linux elf, with + dnl wrong syscalls in place. Test a little gauntlet of + dnl simple stdio read code checking for errors, expecting + dnl enough syscall differences that the NetBSD code will + dnl fail even with Linux emulation working as designed. + dnl A shorter test could be refined by someone with access + dnl to a NetBSD host with Linux emulation working. + origCFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wl,--gc-sections" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ + #include + #include + ]], + [[ + FILE * fpC; + char buf[32]; + size_t cch; + int read_success_once; + + fpC = fopen("conftest.c", "r"); + if (NULL == fpC) + exit(1); + do { + cch = fread(buf, sizeof(buf), 1, fpC); + read_success_once |= (0 != cch); + } while (0 != cch); + if (!read_success_once) + exit(2); + if (!feof(fpC)) + exit(3); + if (0 != fclose(fpC)) + exit(4); + + exit(EXIT_SUCCESS); + ]] + )], + [ + dnl We have to do this invocation manually so that we can + dnl get the output of conftest.err to make sure it doesn't + dnl mention gc-sections. + if test "X$cross_compiling" = "Xyes" || grep gc-sections conftest.err ; then + libevent_cv_gc_sections_runs=no + else + libevent_cv_gc_sections_runs=no + ./conftest >/dev/null 2>&1 && libevent_cv_gc_sections_runs=yes + fi + ], + [libevent_cv_gc_sections_runs=no] + ) + CFLAGS="$origCFLAGS" + AS_UNSET([origCFLAGS]) + ] + ) + case "$libevent_cv_gc_sections_runs" in + yes) + CFLAGS="-ffunction-sections -fdata-sections $CFLAGS" + LIBEVENT_GC_SECTIONS="-Wl,--gc-sections" + ;; + esac +fi +AC_SUBST([LIBEVENT_GC_SECTIONS]) + +AM_CONDITIONAL([INSTALL_LIBEVENT], [test "$enable_libevent_install" = "yes"]) + AC_CONFIG_FILES( [libevent.pc libevent_openssl.pc libevent_pthreads.pc] ) AC_OUTPUT(Makefile include/Makefile test/Makefile sample/Makefile) diff --git a/libevent/evdns.c b/libevent/evdns.c index a1636a14..6dd3dc92 100644 --- a/libevent/evdns.c +++ b/libevent/evdns.c @@ -794,6 +794,12 @@ reply_schedule_callback(struct request *const req, u32 ttl, u32 err, struct repl { struct deferred_reply_callback *d = mm_calloc(1, sizeof(*d)); + if (!d) { + event_warn("%s: Couldn't allocate space for deferred callback.", + __func__); + return; + } + ASSERT_LOCKED(req->base); d->request_type = req->request_type; @@ -1144,6 +1150,9 @@ request_parse(u8 *packet, int length, struct evdns_server_port *port, struct soc GET16(answers); GET16(authority); GET16(additional); + (void)answers; + (void)additional; + (void)authority; if (flags & 0x8000) return -1; /* Must not be an answer. */ flags &= 0x0110; /* Only RD and CD get preserved. */ @@ -1993,7 +2002,7 @@ server_request_free(struct server_request *req) EVDNS_LOCK(req->port); lock=1; if (req->port->pending_replies == req) { - if (req->next_pending) + if (req->next_pending && req->next_pending != req) req->port->pending_replies = req->next_pending; else req->port->pending_replies = NULL; @@ -2387,7 +2396,7 @@ _evdns_nameserver_add_impl(struct evdns_base *base, const struct sockaddr *addre evtimer_assign(&ns->timeout_event, ns->base->event_base, nameserver_prod_callback, ns); - ns->socket = socket(PF_INET, SOCK_DGRAM, 0); + ns->socket = socket(address->sa_family, SOCK_DGRAM, 0); if (ns->socket < 0) { err = 1; goto out1; } evutil_make_socket_closeonexec(ns->socket); evutil_make_socket_nonblocking(ns->socket); @@ -2693,10 +2702,13 @@ evdns_cancel_request(struct evdns_base *base, struct evdns_request *handle) { struct request *req; + if (!handle->current_req) + return; + if (!base) { /* This redundancy is silly; can we fix it? (Not for 2.0) XXXX */ base = handle->base; - if (!base && handle->current_req) + if (!base) base = handle->current_req->base; } @@ -3069,6 +3081,10 @@ search_request_new(struct evdns_base *base, struct evdns_request *handle, } EVUTIL_ASSERT(handle->search_origname == NULL); handle->search_origname = mm_strdup(name); + if (handle->search_origname == NULL) { + /* XXX Should we dealloc req? If yes, how? */ + return NULL; + } handle->search_state = base->global_search_state; handle->search_flags = flags; base->global_search_state->refcount++; @@ -4306,7 +4322,8 @@ evdns_getaddrinfo_gotresolve(int result, char type, int count, evdns_cancel_request(NULL, other_req->r); } data->user_cb(EVUTIL_EAI_MEMORY, NULL, data->user_data); - evutil_freeaddrinfo(res); + if (res) + evutil_freeaddrinfo(res); if (other_req->r == NULL) free_getaddrinfo_request(data); diff --git a/libevent/event-internal.h b/libevent/event-internal.h index e3da33da..12ca8bc1 100644 --- a/libevent/event-internal.h +++ b/libevent/event-internal.h @@ -32,6 +32,7 @@ extern "C" { #endif #include "event2/event-config.h" +#include #include #include "event2/event_struct.h" #include "minheap-internal.h" @@ -235,9 +236,18 @@ struct event_base { /** Priority queue of events with timeouts. */ struct min_heap timeheap; - /** Stored timeval: used to avoid calling gettimeofday too often. */ + /** Stored timeval: used to avoid calling gettimeofday/clock_gettime + * too often. */ struct timeval tv_cache; +#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + /** Difference between internal time (maybe from clock_gettime) and + * gettimeofday. */ + struct timeval tv_clock_diff; + /** Second in which we last updated tv_clock_diff, in monotonic time. */ + time_t last_updated_clock_diff; +#endif + #ifndef _EVENT_DISABLE_THREAD_SUPPORT /* threading support */ /** The thread currently running the event_loop for this base */ diff --git a/libevent/event.c b/libevent/event.c index fedb9c73..41c7d8f4 100644 --- a/libevent/event.c +++ b/libevent/event.c @@ -330,6 +330,10 @@ detect_monotonic(void) #endif } +/* How often (in seconds) do we check for changes in wall clock time relative + * to monotonic time? Set this to -1 for 'never.' */ +#define CLOCK_SYNC_INTERVAL -1 + /** Set 'tp' to the current time according to 'base'. We must hold the lock * on 'base'. If there is a cached time, return it. Otherwise, use * clock_gettime or gettimeofday as appropriate to find out the right time. @@ -354,6 +358,14 @@ gettime(struct event_base *base, struct timeval *tp) tp->tv_sec = ts.tv_sec; tp->tv_usec = ts.tv_nsec / 1000; + if (base->last_updated_clock_diff + CLOCK_SYNC_INTERVAL + < ts.tv_sec) { + struct timeval tv; + evutil_gettimeofday(&tv,NULL); + evutil_timersub(&tv, tp, &base->tv_clock_diff); + base->last_updated_clock_diff = ts.tv_sec; + } + return (0); } #endif @@ -372,7 +384,16 @@ event_base_gettimeofday_cached(struct event_base *base, struct timeval *tv) } EVBASE_ACQUIRE_LOCK(base, th_base_lock); - r = gettime(base, tv); + if (base->tv_cache.tv_sec == 0) { + r = evutil_gettimeofday(tv, NULL); + } else { +#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + evutil_timeradd(&base->tv_cache, &base->tv_clock_diff, tv); +#else + *tv = base->tv_cache; +#endif + r = 0; + } EVBASE_RELEASE_LOCK(base, th_base_lock); return r; } @@ -1778,7 +1799,6 @@ event_priority_set(struct event *ev, int pri) int event_pending(const struct event *ev, short event, struct timeval *tv) { - struct timeval now, res; int flags = 0; _event_debug_assert_is_setup(ev); @@ -1795,12 +1815,13 @@ event_pending(const struct event *ev, short event, struct timeval *tv) /* See if there is a timeout that we should report */ if (tv != NULL && (flags & event & EV_TIMEOUT)) { struct timeval tmp = ev->ev_timeout; - event_base_gettimeofday_cached(ev->ev_base, &now); tmp.tv_usec &= MICROSECONDS_MASK; - evutil_timersub(&tmp, &now, &res); - /* correctly remap to real time */ - evutil_gettimeofday(&now, NULL); - evutil_timeradd(&now, &res, tv); +#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + /* correctly remamp to real time */ + evutil_timeradd(&ev->ev_base->tv_clock_diff, &tmp, tv); +#else + *tv = tmp; +#endif } return (flags & event); diff --git a/libevent/event_iocp.c b/libevent/event_iocp.c index 254ed90d..75fe4627 100644 --- a/libevent/event_iocp.c +++ b/libevent/event_iocp.c @@ -24,6 +24,10 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef _WIN32_WINNT +/* Minimum required for InitializeCriticalSectionAndSpinCount */ +#define _WIN32_WINNT 0x0403 +#endif #include #include #include diff --git a/libevent/evmap.c b/libevent/evmap.c index 5521626c..ebedb788 100644 --- a/libevent/evmap.c +++ b/libevent/evmap.c @@ -148,6 +148,7 @@ void evmap_io_clear(struct event_io_map *ctx) next = HT_NEXT_RMV(event_io_map, ctx, ent); mm_free(this); } + HT_CLEAR(event_io_map, ctx); /* remove all storage held by the ctx. */ } #endif @@ -163,7 +164,6 @@ void evmap_io_clear(struct event_io_map *ctx) #define GET_SIGNAL_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len) \ do { \ if ((map)->entries[slot] == NULL) { \ - EVUTIL_ASSERT(ctor != NULL); \ (map)->entries[slot] = \ mm_calloc(1,sizeof(struct type)+fdinfo_len); \ EVUTIL_ASSERT((map)->entries[slot] != NULL); \ diff --git a/libevent/evport.c b/libevent/evport.c index 4301a39c..f1da73d5 100644 --- a/libevent/evport.c +++ b/libevent/evport.c @@ -336,10 +336,20 @@ evport_dispatch(struct event_base *base, struct timeval *tv) * (because we have to pass this to the callback) */ res = 0; - if (pevt->portev_events & POLLIN) - res |= EV_READ; - if (pevt->portev_events & POLLOUT) - res |= EV_WRITE; + if (pevt->portev_events & (POLLERR|POLLHUP)) { + res = EV_READ | EV_WRITE; + } else { + if (pevt->portev_events & POLLIN) + res |= EV_READ; + if (pevt->portev_events & POLLOUT) + res |= EV_WRITE; + } + + /* + * Check for the error situations or a hangup situation + */ + if (pevt->portev_events & (POLLERR|POLLHUP|POLLNVAL)) + res |= EV_READ|EV_WRITE; EVUTIL_ASSERT(epdp->ed_nevents > fd); fdi = &(epdp->ed_fds[fd]); diff --git a/libevent/evrpc.c b/libevent/evrpc.c index 9d692994..e11892dc 100644 --- a/libevent/evrpc.c +++ b/libevent/evrpc.c @@ -98,7 +98,7 @@ evrpc_free(struct evrpc_base *base) while ((rpc = TAILQ_FIRST(&base->registered_rpcs)) != NULL) { r = evrpc_unregister_rpc(base, rpc->uri); - EVUTIL_ASSERT(r); + EVUTIL_ASSERT(r == 0); } while ((pause = TAILQ_FIRST(&base->paused_requests)) != NULL) { TAILQ_REMOVE(&base->paused_requests, pause, next); @@ -263,9 +263,6 @@ evrpc_unregister_rpc(struct evrpc_base *base, const char *name) } TAILQ_REMOVE(&base->registered_rpcs, rpc, next); - mm_free((char *)rpc->uri); - mm_free(rpc); - registered_uri = evrpc_construct_uri(name); /* remove the http server callback */ @@ -273,6 +270,9 @@ evrpc_unregister_rpc(struct evrpc_base *base, const char *name) EVUTIL_ASSERT(r == 0); mm_free(registered_uri); + + mm_free((char *)rpc->uri); + mm_free(rpc); return (0); } diff --git a/libevent/evthread.c b/libevent/evthread.c index 35f14b2b..2cfb76e9 100644 --- a/libevent/evthread.c +++ b/libevent/evthread.c @@ -217,6 +217,7 @@ debug_cond_wait(void *_cond, void *_lock, const struct timeval *tv) { int r; struct debug_lock *lock = _lock; + EVUTIL_ASSERT(lock); EVLOCK_ASSERT_LOCKED(_lock); evthread_debug_lock_mark_unlocked(0, lock); r = _original_cond_fns.wait_condition(_cond, lock->lock, tv); diff --git a/libevent/evthread_win32.c b/libevent/evthread_win32.c index bd72be15..18dca6d4 100644 --- a/libevent/evthread_win32.c +++ b/libevent/evthread_win32.c @@ -26,6 +26,10 @@ #include "event2/event-config.h" #ifdef WIN32 +#ifndef _WIN32_WINNT +/* Minimum required for InitializeCriticalSectionAndSpinCount */ +#define _WIN32_WINNT 0x0403 +#endif #include #define WIN32_LEAN_AND_MEAN #include diff --git a/libevent/evutil.c b/libevent/evutil.c index b769acc2..9d9863a2 100644 --- a/libevent/evutil.c +++ b/libevent/evutil.c @@ -351,6 +351,8 @@ evutil_strtoll(const char *s, char **endptr, int base) r = (ev_int64_t) _atoi64(s); while (isspace(*s)) ++s; + if (*s == '-') + ++s; while (isdigit(*s)) ++s; if (endptr) @@ -358,6 +360,36 @@ evutil_strtoll(const char *s, char **endptr, int base) return r; #elif defined(WIN32) return (ev_int64_t) _strtoi64(s, endptr, base); +#elif defined(_EVENT_SIZEOF_LONG_LONG) && _EVENT_SIZEOF_LONG_LONG == 8 + long long r; + int n; + if (base != 10 && base != 16) + return 0; + if (base == 10) { + n = sscanf(s, "%lld", &r); + } else { + unsigned long long ru=0; + n = sscanf(s, "%llx", &ru); + if (ru > EV_INT64_MAX) + return 0; + r = (long long) ru; + } + if (n != 1) + return 0; + while (EVUTIL_ISSPACE(*s)) + ++s; + if (*s == '-') + ++s; + if (base == 10) { + while (EVUTIL_ISDIGIT(*s)) + ++s; + } else { + while (EVUTIL_ISXDIGIT(*s)) + ++s; + } + if (endptr) + *endptr = (char*) s; + return r; #else #error "I don't know how to parse 64-bit integers." #endif @@ -479,6 +511,15 @@ evutil_socket_finished_connecting(evutil_socket_t fd) set by evutil_check_interfaces. */ static int have_checked_interfaces, had_ipv4_address, had_ipv6_address; +/* Macro: True iff the IPv4 address 'addr', in host order, is in 127.0.0.0/8 + */ +#define EVUTIL_V4ADDR_IS_LOCALHOST(addr) (((addr)>>24) == 127) + +/* Macro: True iff the IPv4 address 'addr', in host order, is a class D + * (multiclass) address. + */ +#define EVUTIL_V4ADDR_IS_CLASSD(addr) ((((addr)>>24) & 0xf0) == 0xe0) + /* Test whether we have an ipv4 interface and an ipv6 interface. Return 0 if * the test seemed successful. */ static int @@ -522,8 +563,9 @@ evutil_check_interfaces(int force_recheck) getsockname(fd, (struct sockaddr*)&sin_out, &sin_out_len) == 0) { /* We might have an IPv4 interface. */ ev_uint32_t addr = ntohl(sin_out.sin_addr.s_addr); - if (addr == 0 || (addr&0xff000000) == 127 || - (addr & 0xff) == 255 || (addr & 0xf0) == 14) { + if (addr == 0 || + EVUTIL_V4ADDR_IS_LOCALHOST(addr) || + EVUTIL_V4ADDR_IS_CLASSD(addr)) { evutil_inet_ntop(AF_INET, &sin_out.sin_addr, buf, sizeof(buf)); /* This is a reserved, ipv4compat, ipv4map, loopback, @@ -721,6 +763,10 @@ evutil_getaddrinfo_infer_protocols(struct evutil_addrinfo *hints) } } +#if AF_UNSPEC != PF_UNSPEC +#error "I cannot build on a system where AF_UNSPEC != PF_UNSPEC" +#endif + /** Implements the part of looking up hosts by name that's common to both * the blocking and nonblocking resolver: * - Adjust 'hints' to have a reasonable socktype and protocol. @@ -771,7 +817,7 @@ evutil_getaddrinfo_common(const char *nodename, const char *servname, memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(port); - if (hints->ai_flags & AI_PASSIVE) { + if (hints->ai_flags & EVUTIL_AI_PASSIVE) { /* Bind to :: */ } else { /* connect to ::1 */ @@ -788,7 +834,7 @@ evutil_getaddrinfo_common(const char *nodename, const char *servname, memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(port); - if (hints->ai_flags & AI_PASSIVE) { + if (hints->ai_flags & EVUTIL_AI_PASSIVE) { /* Bind to 0.0.0.0 */ } else { /* connect to 127.0.0.1 */ @@ -958,8 +1004,13 @@ addrinfo_from_hostent(const struct hostent *ent, res = evutil_addrinfo_append(res, ai); } - if (res && ((hints->ai_flags & EVUTIL_AI_CANONNAME) && ent->h_name)) + if (res && ((hints->ai_flags & EVUTIL_AI_CANONNAME) && ent->h_name)) { res->ai_canonname = mm_strdup(ent->h_name); + if (res->ai_canonname == NULL) { + evutil_freeaddrinfo(res); + return NULL; + } + } return res; } @@ -1083,7 +1134,7 @@ apply_numeric_port_hack(int port, struct evutil_addrinfo **ai) } } -static void +static int apply_socktype_protocol_hack(struct evutil_addrinfo *ai) { struct evutil_addrinfo *ai_new; @@ -1092,6 +1143,8 @@ apply_socktype_protocol_hack(struct evutil_addrinfo *ai) if (ai->ai_socktype || ai->ai_protocol) continue; ai_new = mm_malloc(sizeof(*ai_new)); + if (!ai_new) + return -1; memcpy(ai_new, ai, sizeof(*ai_new)); ai->ai_socktype = SOCK_STREAM; ai->ai_protocol = IPPROTO_TCP; @@ -1101,6 +1154,7 @@ apply_socktype_protocol_hack(struct evutil_addrinfo *ai) ai_new->ai_next = ai->ai_next; ai->ai_next = ai_new; } + return 0; } #endif @@ -1191,7 +1245,11 @@ evutil_getaddrinfo(const char *nodename, const char *servname, apply_numeric_port_hack(portnum, res); if (need_socktype_protocol_hack()) { - apply_socktype_protocol_hack(*res); + if (apply_socktype_protocol_hack(*res) < 0) { + evutil_freeaddrinfo(*res); + *res = NULL; + return EVUTIL_EAI_MEMORY; + } } return err; #else diff --git a/libevent/http.c b/libevent/http.c index f8de3b37..b97485f6 100644 --- a/libevent/http.c +++ b/libevent/http.c @@ -56,6 +56,9 @@ #ifdef _EVENT_HAVE_NETINET_IN_H #include #endif +#ifdef _EVENT_HAVE_ARPA_INET_H +#include +#endif #ifdef _EVENT_HAVE_NETDB_H #include #endif @@ -97,6 +100,7 @@ #include "util-internal.h" #include "http-internal.h" #include "mm-internal.h" +#include "bufferevent-internal.h" #ifndef _EVENT_HAVE_GETNAMEINFO #define NI_MAXSERV 32 @@ -215,29 +219,30 @@ strsep(char **s, const char *del) } #endif -static const char * -html_replace(char ch, char *buf) +static size_t +html_replace(const char ch, const char **escaped) { switch (ch) { case '<': - return "<"; + *escaped = "<"; + return 4; case '>': - return ">"; + *escaped = ">"; + return 4; case '"': - return """; + *escaped = """; + return 6; case '\'': - return "'"; + *escaped = "'"; + return 6; case '&': - return "&"; + *escaped = "&"; + return 5; default: break; } - /* Echo the character back */ - buf[0] = ch; - buf[1] = '\0'; - - return buf; + return 1; } /* @@ -251,21 +256,34 @@ char * evhttp_htmlescape(const char *html) { size_t i; - size_t new_size = 0, old_size = strlen(html); + size_t new_size = 0, old_size = 0; char *escaped_html, *p; - char scratch_space[2]; - for (i = 0; i < old_size; ++i) - new_size += strlen(html_replace(html[i], scratch_space)); + if (html == NULL) + return (NULL); + + old_size = strlen(html); + for (i = 0; i < old_size; ++i) { + const char *replaced = NULL; + const size_t replace_size = html_replace(html[i], &replaced); + if (replace_size > EV_SIZE_MAX - new_size) { + event_warn("%s: html_replace overflow", __func__); + return (NULL); + } + new_size += replace_size; + } + if (new_size == EV_SIZE_MAX) + return (NULL); p = escaped_html = mm_malloc(new_size + 1); if (escaped_html == NULL) { - event_warn("%s: malloc(%ld)", __func__, (long)(new_size + 1)); + event_warn("%s: malloc(%lu)", __func__, + (unsigned long)(new_size + 1)); return (NULL); } for (i = 0; i < old_size; ++i) { - const char *replaced = html_replace(html[i], scratch_space); - size_t len = strlen(replaced); + const char *replaced = &html[i]; + const size_t len = html_replace(html[i], &replaced); memcpy(p, replaced, len); p += len; } @@ -822,9 +840,23 @@ evhttp_connection_done(struct evhttp_connection *evcon) static enum message_read_status evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf) { - ev_ssize_t len; + if (req == NULL || buf == NULL) { + return DATA_CORRUPTED; + } + + while (1) { + size_t buflen; + + if ((buflen = evbuffer_get_length(buf)) == 0) { + break; + } + + /* evbuffer_get_length returns size_t, but len variable is ssize_t, + * check for overflow conditions */ + if (buflen > EV_SSIZE_MAX) { + return DATA_CORRUPTED; + } - while ((len = evbuffer_get_length(buf)) > 0) { if (req->ntoread < 0) { /* Read chunk size */ ev_int64_t ntoread; @@ -847,11 +879,18 @@ evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf) /* could not get chunk size */ return (DATA_CORRUPTED); } + + /* ntoread is signed int64, body_size is unsigned size_t, check for under/overflow conditions */ + if ((ev_uint64_t)ntoread > EV_SIZE_MAX - req->body_size) { + return DATA_CORRUPTED; + } + if (req->body_size + (size_t)ntoread > req->evcon->max_body_size) { /* failed body length test */ event_debug(("Request body is too long")); return (DATA_TOO_LONG); } + req->body_size += (size_t)ntoread; req->ntoread = ntoread; if (req->ntoread == 0) { @@ -861,12 +900,17 @@ evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf) continue; } + /* req->ntoread is signed int64, len is ssize_t, based on arch, + * ssize_t could only be 32b, check for these conditions */ + if (req->ntoread > EV_SSIZE_MAX) { + return DATA_CORRUPTED; + } + /* don't have enough to complete a chunk; wait for more */ - if (len < req->ntoread) + if (req->ntoread > 0 && buflen < (ev_uint64_t)req->ntoread) return (MORE_DATA_EXPECTED); /* Completed chunk */ - /* XXXX fixme: what if req->ntoread is > SIZE_T_MAX? */ evbuffer_remove_buffer(buf, req->input_buffer, (size_t)req->ntoread); req->ntoread = -1; if (req->chunk_cb != NULL) { @@ -934,13 +978,19 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req) } } else if (req->ntoread < 0) { /* Read until connection close. */ + if ((size_t)(req->body_size + evbuffer_get_length(buf)) < req->body_size) { + evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER); + return; + } + req->body_size += evbuffer_get_length(buf); evbuffer_add_buffer(req->input_buffer, buf); - } else if (req->chunk_cb != NULL || - evbuffer_get_length(buf) >= (size_t)req->ntoread) { + } else if (req->chunk_cb != NULL || evbuffer_get_length(buf) >= (size_t)req->ntoread) { + /* XXX: the above get_length comparison has to be fixed for overflow conditions! */ /* We've postponed moving the data until now, but we're * about to use it. */ size_t n = evbuffer_get_length(buf); + if (n > (size_t) req->ntoread) n = (size_t) req->ntoread; req->ntoread -= n; @@ -948,7 +998,10 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req) evbuffer_remove_buffer(buf, req->input_buffer, n); } - if (req->body_size > req->evcon->max_body_size) { + if (req->body_size > req->evcon->max_body_size || + (!req->chunked && req->ntoread >= 0 && + (size_t)req->ntoread > req->evcon->max_body_size)) { + /* XXX: The above casted comparison must checked for overflow */ /* failed body length test */ event_debug(("Request body is too long")); evhttp_connection_fail(evcon, @@ -1015,9 +1068,24 @@ evhttp_read_cb(struct bufferevent *bufev, void *arg) case EVCON_READING_TRAILER: evhttp_read_trailer(evcon, req); break; + case EVCON_IDLE: + { +#ifdef USE_DEBUG + struct evbuffer *input; + size_t total_len; + + input = bufferevent_get_input(evcon->bufev); + total_len = evbuffer_get_length(input); + event_debug(("%s: read %d bytes in EVCON_IDLE state," + " resetting connection", + __func__, (int)total_len)); +#endif + + evhttp_connection_reset(evcon); + } + break; case EVCON_DISCONNECTED: case EVCON_CONNECTING: - case EVCON_IDLE: case EVCON_WRITING: default: event_errx(1, "%s: illegal connection state %d", @@ -1110,7 +1178,7 @@ evhttp_connection_set_local_address(struct evhttp_connection *evcon, if (evcon->bind_address) mm_free(evcon->bind_address); if ((evcon->bind_address = mm_strdup(address)) == NULL) - event_err(1, "%s: strdup", __func__); + event_warn("%s: strdup", __func__); } void @@ -1151,7 +1219,18 @@ evhttp_connection_reset(struct evhttp_connection *evcon) { struct evbuffer *tmp; - bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE); + /* XXXX This is not actually an optimal fix. Instead we ought to have + an API for "stop connecting", or use bufferevent_setfd to turn off + connecting. But for Libevent 2.0, this seems like a minimal change + least likely to disrupt the rest of the bufferevent and http code. + + Why is this here? If the fd is set in the bufferevent, and the + bufferevent is connecting, then you can't actually stop the + bufferevent from trying to connect with bufferevent_disable(). The + connect will never trigger, since we close the fd, but the timeout + might. That caused an assertion failure in evhttp_connection_fail. + */ + bufferevent_disable_hard(evcon->bufev, EV_READ|EV_WRITE); if (evcon->fd != -1) { /* inform interested parties about connection close */ @@ -1200,6 +1279,8 @@ evhttp_connection_retry(evutil_socket_t fd, short what, void *arg) static void evhttp_connection_cb_cleanup(struct evhttp_connection *evcon) { + struct evcon_requestq requests; + if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) { evtimer_assign(&evcon->retry_ev, evcon->base, evhttp_connection_retry, evcon); /* XXXX handle failure from evhttp_add_event */ @@ -1211,10 +1292,23 @@ evhttp_connection_cb_cleanup(struct evhttp_connection *evcon) } evhttp_connection_reset(evcon); - /* for now, we just signal all requests by executing their callbacks */ + /* + * User callback can do evhttp_make_request() on the same + * evcon so new request will be added to evcon->requests. To + * avoid freeing it prematurely we iterate over the copy of + * the queue. + */ + TAILQ_INIT(&requests); while (TAILQ_FIRST(&evcon->requests) != NULL) { struct evhttp_request *request = TAILQ_FIRST(&evcon->requests); TAILQ_REMOVE(&evcon->requests, request, next); + TAILQ_INSERT_TAIL(&requests, request, next); + } + + /* for now, we just signal all requests by executing their callbacks */ + while (TAILQ_FIRST(&requests) != NULL) { + struct evhttp_request *request = TAILQ_FIRST(&requests); + TAILQ_REMOVE(&requests, request, next); request->evcon = NULL; /* we might want to set an error here */ @@ -1472,7 +1566,8 @@ evhttp_parse_request_line(struct evhttp_request *req, char *line) return (-1); } - if ((req->uri_elems = evhttp_uri_parse(req->uri)) == NULL) { + if ((req->uri_elems = evhttp_uri_parse_with_flags(req->uri, + EVHTTP_URI_NONCONFORMANT)) == NULL) { return -1; } @@ -1731,7 +1826,8 @@ evhttp_parse_headers(struct evhttp_request *req, struct evbuffer* buffer) } if (status == MORE_DATA_EXPECTED) { - if (req->headers_size + evbuffer_get_length(buffer) > req->evcon->max_headers_size) + if (req->evcon != NULL && + req->headers_size + evbuffer_get_length(buffer) > req->evcon->max_headers_size) return (DATA_TOO_LONG); } @@ -1846,11 +1942,12 @@ evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req) no, we should respond with an error. For now, just optimistically tell the client to send their message body. */ - if (req->ntoread > 0 && - (size_t)req->ntoread > req->evcon->max_body_size) { - evhttp_send_error(req, HTTP_ENTITYTOOLARGE, - NULL); - return; + if (req->ntoread > 0) { + /* ntoread is ev_int64_t, max_body_size is ev_uint64_t */ + if ((req->evcon->max_body_size <= EV_INT64_MAX) && (ev_uint64_t)req->ntoread > req->evcon->max_body_size) { + evhttp_send_error(req, HTTP_ENTITYTOOLARGE, NULL); + return; + } } if (!evbuffer_get_length(bufferevent_get_input(evcon->bufev))) evhttp_send_continue(evcon, req); @@ -2145,11 +2242,20 @@ evhttp_make_request(struct evhttp_connection *evcon, req->evcon = evcon; EVUTIL_ASSERT(!(req->flags & EVHTTP_REQ_OWN_CONNECTION)); - TAILQ_INSERT_TAIL(&evcon->requests, req, next); + TAILQ_INSERT_TAIL(&evcon->requests, req, next); /* If the connection object is not connected; make it so */ - if (!evhttp_connected(evcon)) - return (evhttp_connection_connect(evcon)); + if (!evhttp_connected(evcon)) { + int res = evhttp_connection_connect(evcon); + /* evhttp_connection_fail(), which is called through + * evhttp_connection_connect(), assumes that req lies in + * evcon->requests. Thus, enqueue the request in advance and r + * it in the error case. */ + if (res != 0) + TAILQ_REMOVE(&evcon->requests, req, next); + + return res; + } /* * If it's connected already and we are the first in the queue, @@ -2491,6 +2597,10 @@ evhttp_response_code(struct evhttp_request *req, int code, const char *reason) if (reason == NULL) reason = evhttp_response_phrase_internal(code); req->response_code_line = mm_strdup(reason); + if (req->response_code_line == NULL) { + event_warn("%s: strdup", __func__); + /* XXX what else can we do? */ + } } void @@ -3280,6 +3390,11 @@ evhttp_set_cb(struct evhttp *http, const char *uri, } http_cb->what = mm_strdup(uri); + if (http_cb->what == NULL) { + event_warn("%s: strdup", __func__); + mm_free(http_cb); + return (-3); + } http_cb->cb = cb; http_cb->cbarg = cbarg; @@ -3768,6 +3883,7 @@ bind_socket(const char *address, ev_uint16_t port, int reuse) } struct evhttp_uri { + unsigned flags; char *scheme; /* scheme; e.g http, ftp etc */ char *userinfo; /* userinfo (typically username:pass), or NULL */ char *host; /* hostname, IP address, or NULL */ @@ -3786,7 +3902,13 @@ evhttp_uri_new(void) return uri; } -/* Return true of the string starting at s and ending immediately before eos +void +evhttp_uri_set_flags(struct evhttp_uri *uri, unsigned flags) +{ + uri->flags = flags; +} + +/* Return true if the string starting at s and ending immediately before eos * is a valid URI scheme according to RFC3986 */ static int @@ -3911,6 +4033,10 @@ parse_authority(struct evhttp_uri *uri, char *s, char *eos) EVUTIL_ASSERT(eos); if (eos == s) { uri->host = mm_strdup(""); + if (uri->host == NULL) { + event_warn("%s: strdup", __func__); + return -1; + } return 0; } @@ -3922,6 +4048,10 @@ parse_authority(struct evhttp_uri *uri, char *s, char *eos) return -1; *cp++ = '\0'; uri->userinfo = mm_strdup(s); + if (uri->userinfo == NULL) { + event_warn("%s: strdup", __func__); + return -1; + } } else { cp = s; } @@ -3949,6 +4079,10 @@ parse_authority(struct evhttp_uri *uri, char *s, char *eos) return -1; } uri->host = mm_malloc(eos-cp+1); + if (uri->host == NULL) { + event_warn("%s: malloc", __func__); + return -1; + } memcpy(uri->host, cp, eos-cp); uri->host[eos-cp] = '\0'; return 0; @@ -3966,13 +4100,41 @@ end_of_authority(char *cp) return cp; } +enum uri_part { + PART_PATH, + PART_QUERY, + PART_FRAGMENT +}; + /* Return the character after the longest prefix of 'cp' that matches... * *pchar / "/" if allow_qchars is false, or - * *(pchar / "/" / "?") if allow_chars is true. + * *(pchar / "/" / "?") if allow_qchars is true. */ static char * -end_of_path(char *cp, int allow_qchars) +end_of_path(char *cp, enum uri_part part, unsigned flags) { + if (flags & EVHTTP_URI_NONCONFORMANT) { + /* If NONCONFORMANT: + * Path is everything up to a # or ? or nul. + * Query is everything up a # or nul + * Fragment is everything up to a nul. + */ + switch (part) { + case PART_PATH: + while (*cp && *cp != '#' && *cp != '?') + ++cp; + break; + case PART_QUERY: + while (*cp && *cp != '#') + ++cp; + break; + case PART_FRAGMENT: + cp += strlen(cp); + break; + }; + return cp; + } + while (*cp) { if (CHAR_IS_UNRESERVED(*cp) || strchr(SUBDELIMS, *cp) || @@ -3981,7 +4143,7 @@ end_of_path(char *cp, int allow_qchars) else if (*cp == '%' && EVUTIL_ISXDIGIT(cp[1]) && EVUTIL_ISXDIGIT(cp[2])) cp += 3; - else if (*cp == '?' && allow_qchars) + else if (*cp == '?' && part != PART_PATH) ++cp; else return cp; @@ -4004,6 +4166,12 @@ path_matches_noscheme(const char *cp) struct evhttp_uri * evhttp_uri_parse(const char *source_uri) +{ + return evhttp_uri_parse_with_flags(source_uri, 0); +} + +struct evhttp_uri * +evhttp_uri_parse_with_flags(const char *source_uri, unsigned flags) { char *readbuf = NULL, *readp = NULL, *token = NULL, *query = NULL; char *path = NULL, *fragment = NULL; @@ -4011,14 +4179,15 @@ evhttp_uri_parse(const char *source_uri) struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri)); if (uri == NULL) { - event_err(1, "%s: calloc", __func__); + event_warn("%s: calloc", __func__); goto err; } uri->port = -1; + uri->flags = flags; readbuf = mm_strdup(source_uri); if (readbuf == NULL) { - event_err(1, "%s: strdup", __func__); + event_warn("%s: strdup", __func__); goto err; } @@ -4031,7 +4200,6 @@ evhttp_uri_parse(const char *source_uri) URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] relative-ref = relative-part [ "?" query ] [ "#" fragment ] - */ /* 1. scheme: */ @@ -4039,7 +4207,10 @@ evhttp_uri_parse(const char *source_uri) if (token && scheme_ok(readp,token)) { *token = '\0'; uri->scheme = mm_strdup(readp); - + if (uri->scheme == NULL) { + event_warn("%s: strdup", __func__); + goto err; + } readp = token+1; /* eat : */ } @@ -4058,21 +4229,21 @@ evhttp_uri_parse(const char *source_uri) /* 3. Query: path-abempty, path-absolute, path-rootless, or path-empty */ path = readp; - readp = end_of_path(path, 0); + readp = end_of_path(path, PART_PATH, flags); /* Query */ if (*readp == '?') { *readp = '\0'; ++readp; query = readp; - readp = end_of_path(readp, 1); + readp = end_of_path(readp, PART_QUERY, flags); } /* fragment */ if (*readp == '#') { *readp = '\0'; ++readp; fragment = readp; - readp = end_of_path(readp, 1); + readp = end_of_path(readp, PART_FRAGMENT, flags); } if (*readp != '\0') { goto err; @@ -4096,11 +4267,25 @@ evhttp_uri_parse(const char *source_uri) EVUTIL_ASSERT(path); uri->path = mm_strdup(path); + if (uri->path == NULL) { + event_warn("%s: strdup", __func__); + goto err; + } - if (query) + if (query) { uri->query = mm_strdup(query); - if (fragment) + if (uri->query == NULL) { + event_warn("%s: strdup", __func__); + goto err; + } + } + if (fragment) { uri->fragment = mm_strdup(fragment); + if (uri->fragment == NULL) { + event_warn("%s: strdup", __func__); + goto err; + } + } mm_free(readbuf); @@ -4286,12 +4471,13 @@ evhttp_uri_set_port(struct evhttp_uri *uri, int port) uri->port = port; return 0; } -#define end_of_cpath(cp,aq) ((const char*)(end_of_path(((char*)(cp)), (aq)))) +#define end_of_cpath(cp,p,f) \ + ((const char*)(end_of_path(((char*)(cp)), (p), (f)))) int evhttp_uri_set_path(struct evhttp_uri *uri, const char *path) { - if (path && end_of_cpath(path, 0) != path+strlen(path)) + if (path && end_of_cpath(path, PART_PATH, uri->flags) != path+strlen(path)) return -1; _URI_SET_STR(path); @@ -4300,7 +4486,7 @@ evhttp_uri_set_path(struct evhttp_uri *uri, const char *path) int evhttp_uri_set_query(struct evhttp_uri *uri, const char *query) { - if (query && end_of_cpath(query, 1) != query+strlen(query)) + if (query && end_of_cpath(query, PART_QUERY, uri->flags) != query+strlen(query)) return -1; _URI_SET_STR(query); return 0; @@ -4308,7 +4494,7 @@ evhttp_uri_set_query(struct evhttp_uri *uri, const char *query) int evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment) { - if (fragment && end_of_cpath(fragment, 1) != fragment+strlen(fragment)) + if (fragment && end_of_cpath(fragment, PART_FRAGMENT, uri->flags) != fragment+strlen(fragment)) return -1; _URI_SET_STR(fragment); return 0; diff --git a/libevent/include/Makefile.am b/libevent/include/Makefile.am index b109ff79..fbf459eb 100644 --- a/libevent/include/Makefile.am +++ b/libevent/include/Makefile.am @@ -28,7 +28,14 @@ EVENT2_EXPORT = \ EXTRA_SRC = $(EVENT2_EXPORT) -nobase_include_HEADERS = $(EVENT2_EXPORT) +## Without the nobase_ prefixing, Automake would strip "event2/" from +## the source header filename to derive the installed header filename. +## With nobase_ the installed path is $(includedir)/event2/ev*.h. +if INSTALL_LIBEVENT +nobase_include_HEADERS = $(EVENT2_EXPORT) nobase_nodist_include_HEADERS = ./event2/event-config.h - +else +noinst_HEADERS = $(EVENT2_EXPORT) +nodist_noinst_HEADERS = ./event2/event-config.h +endif diff --git a/libevent/include/event2/event.h b/libevent/include/event2/event.h index 4b05b325..3850318f 100644 --- a/libevent/include/event2/event.h +++ b/libevent/include/event2/event.h @@ -107,6 +107,10 @@ int event_reinit(struct event_base *base); /** Threadsafe event dispatching loop. + This loop will run the event base until either there are no more added + events, or until something calls event_base_loopbreak() or + evenet_base_loopexit(). + @param eb the event_base structure returned by event_init() @see event_init(), event_dispatch() */ @@ -322,14 +326,14 @@ void event_set_fatal_callback(event_fatal_cb cb); int event_base_set(struct event_base *, struct event *); /** - event_loop() flags + event_base_loop() flags */ /*@{*/ /** Block until we have an active event, then exit once all active events * have had their callbacks run. */ #define EVLOOP_ONCE 0x01 /** Do not block: see which events are ready now, run the callbacks - * highest-priority ones, then exit. */ + * of the highest-priority ones, then exit. */ #define EVLOOP_NONBLOCK 0x02 /*@}*/ @@ -338,6 +342,11 @@ int event_base_set(struct event_base *, struct event *); This is a more flexible version of event_base_dispatch(). + By default, this loop will run the event base until either there are no more + added events, or until something calls event_base_loopbreak() or + evenet_base_loopexit(). You can override this behavior with the 'flags' + argument. + @param eb the event_base structure returned by event_init() @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK @return 0 if successful, -1 if an error occurred, or 1 if no events were @@ -748,8 +757,9 @@ const struct timeval *event_base_init_common_timeout(struct event_base *base, Note that all memory returned from Libevent will be allocated by the replacement functions rather than by malloc() and realloc(). Thus, if you - have replaced those functions, it may not be appropriate to free() memory - that you get from Libevent. + have replaced those functions, it will not be appropriate to free() memory + that you get from Libevent. Instead, you must use the free_fn replacement + that you provided. @param malloc_fn A replacement for malloc. @param realloc_fn A replacement for realloc diff --git a/libevent/include/event2/http.h b/libevent/include/event2/http.h index e05c3bff..322240d9 100644 --- a/libevent/include/event2/http.h +++ b/libevent/include/event2/http.h @@ -154,7 +154,10 @@ struct evconnlistener *evhttp_bound_socket_get_listener(struct evhttp_bound_sock * This may be useful when a socket has been sent via file descriptor passing * and is no longer needed by the current process. * - * This function does not close the socket. + * If you created this bound socket with evhttp_bind_socket_with_handle or + * evhttp_accept_socket_with_handle, this function closes the fd you provided. + * If you created this bound socket with evhttp_bind_listener, this function + * frees the listener you provided. * * \a bound_socket is an invalid pointer after this call returns. * @@ -707,6 +710,12 @@ char *evhttp_htmlescape(const char *html); */ struct evhttp_uri *evhttp_uri_new(void); +/** + * Changes the flags set on a given URI. See EVHTTP_URI_* for + * a list of flags. + **/ +void evhttp_uri_set_flags(struct evhttp_uri *uri, unsigned flags); + /** Return the scheme of an evhttp_uri, or NULL if there is no scheme has * been set and the evhttp_uri contains a Relative-Ref. */ const char *evhttp_uri_get_scheme(const struct evhttp_uri *uri); @@ -792,9 +801,29 @@ int evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment); * accepts all of them as valid. * * @param source_uri the request URI + * @param flags Zero or more EVHTTP_URI_* flags to affect the behavior + * of the parser. * @return uri container to hold parsed data, or NULL if there is error * @see evhttp_uri_free() */ +struct evhttp_uri *evhttp_uri_parse_with_flags(const char *source_uri, + unsigned flags); + +/** Tolerate URIs that do not conform to RFC3986. + * + * Unfortunately, some HTTP clients generate URIs that, according to RFC3986, + * are not conformant URIs. If you need to support these URIs, you can + * do so by passing this flag to evhttp_uri_parse_with_flags. + * + * Currently, these changes are: + *
    + *
  • Nonconformant URIs are allowed to contain otherwise unreasonable + * characters in their path, query, and fragment components. + *
+ */ +#define EVHTTP_URI_NONCONFORMANT 0x01 + +/** Alias for evhttp_uri_parse_with_flags(source_uri, 0) */ struct evhttp_uri *evhttp_uri_parse(const char *source_uri); /** @@ -817,7 +846,7 @@ void evhttp_uri_free(struct evhttp_uri *uri); * @param buf destination buffer * @param limit destination buffer size * @return an joined uri as string or NULL on error - @see evhttp_uri_parse() + * @see evhttp_uri_parse() */ char *evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit); diff --git a/libevent/ipv6-internal.h b/libevent/ipv6-internal.h index 7d6fb736..1f272a0d 100644 --- a/libevent/ipv6-internal.h +++ b/libevent/ipv6-internal.h @@ -59,12 +59,21 @@ typedef int sa_family_t; #ifndef _EVENT_HAVE_STRUCT_SOCKADDR_IN6 struct sockaddr_in6 { + /* This will fail if we find a struct sockaddr that doesn't have + * sa_family as the first element. */ sa_family_t sin6_family; ev_uint16_t sin6_port; struct in6_addr sin6_addr; }; #endif +#ifndef AF_INET6 +#define AF_INET6 3333 +#endif +#ifndef PF_INET6 +#define PF_INET6 AF_INET6 +#endif + #ifdef __cplusplus } #endif diff --git a/libevent/kqueue.c b/libevent/kqueue.c index 92012982..8b486346 100644 --- a/libevent/kqueue.c +++ b/libevent/kqueue.c @@ -228,6 +228,23 @@ kq_build_changes_list(const struct event_changelist *changelist, return n_changes; } +static int +kq_grow_events(struct kqop *kqop, size_t new_size) +{ + struct kevent *newresult; + + newresult = mm_realloc(kqop->events, + new_size * sizeof(struct kevent)); + + if (newresult) { + kqop->events = newresult; + kqop->events_size = new_size; + return 0; + } else { + return -1; + } +} + static int kq_dispatch(struct event_base *base, struct timeval *tv) { @@ -255,6 +272,25 @@ kq_dispatch(struct event_base *base, struct timeval *tv) changes = kqop->changes; kqop->changes = NULL; + /* Make sure that 'events' is at least as long as the list of changes: + * otherwise errors in the changes can get reported as a -1 return + * value from kevent() rather than as EV_ERROR events in the events + * array. + * + * (We could instead handle -1 return values from kevent() by + * retrying with a smaller changes array or a larger events array, + * but this approach seems less risky for now.) + */ + if (kqop->events_size < n_changes) { + int new_size = kqop->events_size; + do { + new_size *= 2; + } while (new_size < n_changes); + + kq_grow_events(kqop, new_size); + events = kqop->events; + } + EVBASE_RELEASE_LOCK(base, th_base_lock); res = kevent(kqop->kq, changes, n_changes, @@ -319,17 +355,9 @@ kq_dispatch(struct event_base *base, struct timeval *tv) } if (res == kqop->events_size) { - struct kevent *newresult; - int size = kqop->events_size; /* We used all the events space that we have. Maybe we should make it bigger. */ - size *= 2; - newresult = mm_realloc(kqop->events, - size * sizeof(struct kevent)); - if (newresult) { - kqop->events = newresult; - kqop->events_size = size; - } + kq_grow_events(kqop, kqop->events_size * 2); } return (0); diff --git a/libevent/libevent_openssl.pc.in b/libevent/libevent_openssl.pc.in index 0fe7cb60..9624cf24 100644 --- a/libevent/libevent_openssl.pc.in +++ b/libevent/libevent_openssl.pc.in @@ -11,6 +11,6 @@ Version: @VERSION@ Requires: libevent Conflicts: Libs: -L${libdir} -levent_openssl -Libs.private: @LIBS@ -lcrypto -lssl +Libs.private: @LIBS@ -lssl -lcrypto Cflags: -I${includedir} diff --git a/libevent/listener.c b/libevent/listener.c index d0911bdb..5db2cb73 100644 --- a/libevent/listener.c +++ b/libevent/listener.c @@ -29,6 +29,10 @@ #include "event2/event-config.h" #ifdef WIN32 +#ifndef _WIN32_WINNT +/* Minimum required for InitializeCriticalSectionAndSpinCount */ +#define _WIN32_WINNT 0x0403 +#endif #include #include #include diff --git a/libevent/sample/Makefile.am b/libevent/sample/Makefile.am index 0071d26f..4ade6aab 100644 --- a/libevent/sample/Makefile.am +++ b/libevent/sample/Makefile.am @@ -1,6 +1,6 @@ AUTOMAKE_OPTIONS = foreign no-dependencies -LDADD = ../libevent.la +LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la AM_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat -I$(top_srcdir)/include -I../include noinst_PROGRAMS = event-test time-test signal-test dns-example hello-world http-server @@ -15,7 +15,7 @@ http_server_sources = http-server.c if OPENSSL noinst_PROGRAMS += le-proxy le_proxy_sources = le-proxy.c -le_proxy_LDADD = $(LDADD) ../libevent_openssl.la -lcrypto -lssl +le_proxy_LDADD = $(LDADD) ../libevent_openssl.la endif verify: diff --git a/libevent/sample/dns-example.c b/libevent/sample/dns-example.c index 55318215..f2c1e020 100644 --- a/libevent/sample/dns-example.c +++ b/libevent/sample/dns-example.c @@ -7,6 +7,9 @@ #include +/* Compatibility for possible missing IPv6 declarations */ +#include "../ipv6-internal.h" + #include #ifdef WIN32 @@ -69,7 +72,6 @@ static void gai_callback(int err, struct evutil_addrinfo *ai, void *arg) { const char *name = arg; - struct evutil_addrinfo *ai_first = NULL; int i; if (err) { printf("%s: %s\n", name, evutil_gai_strerror(err)); @@ -92,8 +94,6 @@ gai_callback(int err, struct evutil_addrinfo *ai, void *arg) printf("[%d] %s: %s\n",i,name,buf); } } - if (ai_first) - evutil_freeaddrinfo(ai_first); } static void @@ -117,6 +117,8 @@ evdns_server_callback(struct evdns_server_request *req, void *data) printf(" -- replying for %s (PTR)\n", req->questions[i]->name); r = evdns_server_request_add_ptr_reply(req, NULL, req->questions[i]->name, "foo.bar.example.com", 10); + if (r<0) + printf("ugh, no luck"); } else { printf(" -- skipping %s [%d %d]\n", req->questions[i]->name, req->questions[i]->type, req->questions[i]->dns_question_class); diff --git a/libevent/sample/hello-world.c b/libevent/sample/hello-world.c index 90df85f7..d40af529 100644 --- a/libevent/sample/hello-world.c +++ b/libevent/sample/hello-world.c @@ -13,6 +13,9 @@ #include #ifndef WIN32 #include +# ifdef _XOPEN_SOURCE_EXTENDED +# include +# endif #include #endif diff --git a/libevent/sample/http-server.c b/libevent/sample/http-server.c index f9e84d1c..75caa414 100644 --- a/libevent/sample/http-server.c +++ b/libevent/sample/http-server.c @@ -19,6 +19,9 @@ #include #include #include +#ifndef S_ISDIR +#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR) +#endif #else #include #include @@ -36,8 +39,14 @@ #ifdef _EVENT_HAVE_NETINET_IN_H #include +# ifdef _XOPEN_SOURCE_EXTENDED +# include +# endif #endif +/* Compatibility for possible missing IPv6 declarations */ +#include "../util-internal.h" + #ifdef WIN32 #define stat _stat #define fstat _fstat @@ -138,7 +147,7 @@ dump_request_cb(struct evhttp_request *req, void *arg) static void send_document_cb(struct evhttp_request *req, void *arg) { - struct evbuffer *evb; + struct evbuffer *evb = NULL; const char *docroot = arg; const char *uri = evhttp_request_get_uri(req); struct evhttp_uri *decoded = NULL; @@ -223,7 +232,6 @@ send_document_cb(struct evhttp_request *req, void *arg) if (!(d = opendir(whole_path))) goto err; #endif - close(fd); evbuffer_add_printf(evb, "\n \n" " %s\n" @@ -280,18 +288,20 @@ send_document_cb(struct evhttp_request *req, void *arg) } evhttp_send_reply(req, 200, "OK", evb); - evbuffer_free(evb); - return; + goto done; err: evhttp_send_error(req, 404, "Document was not found"); if (fd>=0) close(fd); +done: if (decoded) evhttp_uri_free(decoded); if (decoded_path) free(decoded_path); if (whole_path) free(whole_path); + if (evb) + evbuffer_free(evb); } static void diff --git a/libevent/select.c b/libevent/select.c index 527462ca..892ddfaf 100644 --- a/libevent/select.c +++ b/libevent/select.c @@ -90,6 +90,7 @@ const struct eventop selectops = { }; static int select_resize(struct selectop *sop, int fdsz); +static void select_free_selectop(struct selectop *sop); static void * select_init(struct event_base *base) @@ -99,7 +100,10 @@ select_init(struct event_base *base) if (!(sop = mm_calloc(1, sizeof(struct selectop)))) return (NULL); - select_resize(sop, howmany(32 + 1, NFDBITS)*sizeof(fd_mask)); + if (select_resize(sop, howmany(32 + 1, NFDBITS)*sizeof(fd_mask))) { + select_free_selectop(sop); + return (NULL); + } evsig_init(base); @@ -128,11 +132,14 @@ select_dispatch(struct event_base *base, struct timeval *tv) size_t sz = sop->event_fdsz; if (!(readset_out = mm_realloc(sop->event_readset_out, sz))) return (-1); + sop->event_readset_out = readset_out; if (!(writeset_out = mm_realloc(sop->event_writeset_out, sz))) { - mm_free(readset_out); + /* We don't free readset_out here, since it was + * already successfully reallocated. The next time + * we call select_dispatch, the realloc will be a + * no-op. */ return (-1); } - sop->event_readset_out = readset_out; sop->event_writeset_out = writeset_out; sop->resize_out_sets = 0; } @@ -165,9 +172,9 @@ select_dispatch(struct event_base *base, struct timeval *tv) event_debug(("%s: select reports %d", __func__, res)); check_selectop(sop); - i = random() % (nfds+1); - for (j = 0; j <= nfds; ++j) { - if (++i >= nfds+1) + i = random() % nfds; + for (j = 0; j < nfds; ++j) { + if (++i >= nfds) i = 0; res = 0; if (FD_ISSET(i, sop->event_readset_out)) @@ -185,7 +192,6 @@ select_dispatch(struct event_base *base, struct timeval *tv) return (0); } - static int select_resize(struct selectop *sop, int fdsz) { @@ -198,8 +204,15 @@ select_resize(struct selectop *sop, int fdsz) if ((readset_in = mm_realloc(sop->event_readset_in, fdsz)) == NULL) goto error; sop->event_readset_in = readset_in; - if ((writeset_in = mm_realloc(sop->event_writeset_in, fdsz)) == NULL) + if ((writeset_in = mm_realloc(sop->event_writeset_in, fdsz)) == NULL) { + /* Note that this will leave event_readset_in expanded. + * That's okay; we wouldn't want to free it, since that would + * change the semantics of select_resize from "expand the + * readset_in and writeset_in, or return -1" to "expand the + * *set_in members, or trash them and return -1." + */ goto error; + } sop->event_writeset_in = writeset_in; sop->resize_out_sets = 1; @@ -292,11 +305,8 @@ select_del(struct event_base *base, int fd, short old, short events, void *p) } static void -select_dealloc(struct event_base *base) +select_free_selectop(struct selectop *sop) { - struct selectop *sop = base->evbase; - - evsig_dealloc(base); if (sop->event_readset_in) mm_free(sop->event_readset_in); if (sop->event_writeset_in) @@ -309,3 +319,11 @@ select_dealloc(struct event_base *base) memset(sop, 0, sizeof(struct selectop)); mm_free(sop); } + +static void +select_dealloc(struct event_base *base) +{ + evsig_dealloc(base); + + select_free_selectop(base->evbase); +} diff --git a/libevent/test/Makefile.am b/libevent/test/Makefile.am index 97682fb4..b867501f 100644 --- a/libevent/test/Makefile.am +++ b/libevent/test/Makefile.am @@ -1,17 +1,25 @@ AUTOMAKE_OPTIONS = foreign -AM_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat -I$(top_srcdir)/include -I../include -DTINYTEST_LOCAL +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 test.sh -noinst_PROGRAMS = test-init test-eof test-weof test-time regress \ +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 = regress.gen.c regress.gen.h +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 @@ -45,24 +53,23 @@ if BUILD_WIN32 regress_SOURCES += regress_iocp.c endif -regress_LDADD = ../libevent.la $(PTHREAD_LIBS) $(ZLIB_LIBS) -regress_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat \ - -I$(top_srcdir)/include -I../include $(PTHREAD_CFLAGS) $(ZLIB_CFLAGS) +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 -lcrypto -lssl +regress_LDADD += ../libevent_openssl.la endif bench_SOURCES = bench.c -bench_LDADD = ../libevent.la +bench_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la bench_cascade_SOURCES = bench_cascade.c -bench_cascade_LDADD = ../libevent.la +bench_cascade_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la bench_http_SOURCES = bench_http.c -bench_http_LDADD = ../libevent.la +bench_http_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la bench_httpclient_SOURCES = bench_httpclient.c -bench_httpclient_LDADD = ../libevent_core.la +bench_httpclient_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent_core.la regress.gen.c regress.gen.h: regress.rpc $(top_srcdir)/event_rpcgen.py $(top_srcdir)/event_rpcgen.py $(srcdir)/regress.rpc || echo "No Python installed" diff --git a/libevent/test/bench.c b/libevent/test/bench.c index 59cb6df5..d0f831b9 100644 --- a/libevent/test/bench.c +++ b/libevent/test/bench.c @@ -37,8 +37,11 @@ #include #include +#ifdef _EVENT_HAVE_SYS_TIME_H #include +#endif #ifdef WIN32 +#define WIN32_LEAN_AND_MEAN #include #else #include @@ -49,7 +52,9 @@ #include #include #include +#ifdef _EVENT_HAVE_UNISTD_H #include +#endif #include #include @@ -102,12 +107,12 @@ run_once(void) count = 0; writes = num_writes; { int xcount = 0; - gettimeofday(&ts, NULL); + evutil_gettimeofday(&ts, NULL); do { event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK); xcount++; } while (count != fired); - gettimeofday(&te, NULL); + evutil_gettimeofday(&te, NULL); if (xcount != count) fprintf(stderr, "Xcount: %d, Rcount: %d\n", xcount, count); } diff --git a/libevent/test/bench_cascade.c b/libevent/test/bench_cascade.c index 6b508ef1..c25255ed 100644 --- a/libevent/test/bench_cascade.c +++ b/libevent/test/bench_cascade.c @@ -29,8 +29,11 @@ #include #include +#ifdef _EVENT_HAVE_SYS_TIME_H #include +#endif #ifdef WIN32 +#define WIN32_LEAN_AND_MEAN #include #else #include @@ -41,7 +44,9 @@ #include #include #include +#ifdef _EVENT_HAVE_UNISTD_H #include +#endif #include #include @@ -92,7 +97,7 @@ run_once(int num_pipes) } /* measurements includes event setup */ - gettimeofday(&ts, NULL); + evutil_gettimeofday(&ts, NULL); /* provide a default timeout for events */ evutil_timerclear(&tv_timeout); @@ -111,7 +116,7 @@ run_once(int num_pipes) event_dispatch(); - gettimeofday(&te, NULL); + evutil_gettimeofday(&te, NULL); evutil_timersub(&te, &ts, &te); for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { diff --git a/libevent/test/bench_httpclient.c b/libevent/test/bench_httpclient.c index 19f025f1..25db4a7d 100644 --- a/libevent/test/bench_httpclient.c +++ b/libevent/test/bench_httpclient.c @@ -31,8 +31,12 @@ #else #include #include +# ifdef _XOPEN_SOURCE_EXTENDED +# include +# endif #endif #include +#include #include #include "event2/event.h" @@ -84,7 +88,7 @@ errorcb(struct bufferevent *b, short what, void *arg) if (what & BEV_EVENT_EOF) { ++total_n_handled; total_n_bytes += ri->n_read; - gettimeofday(&now, NULL); + evutil_gettimeofday(&now, NULL); evutil_timersub(&now, &ri->started, &diff); evutil_timeradd(&diff, &total_time, &total_time); @@ -127,6 +131,8 @@ launch_request(void) struct request_info *ri; + memset(&sin, 0, sizeof(sin)); + ++total_n_launched; sin.sin_family = AF_INET; @@ -146,7 +152,7 @@ launch_request(void) ri = malloc(sizeof(*ri)); ri->n_read = 0; - gettimeofday(&ri->started, NULL); + evutil_gettimeofday(&ri->started, NULL); b = bufferevent_socket_new(base, sock, BEV_OPT_CLOSE_ON_FREE); @@ -178,11 +184,11 @@ main(int argc, char **argv) perror("launch"); } - gettimeofday(&start, NULL); + evutil_gettimeofday(&start, NULL); event_base_dispatch(base); - gettimeofday(&end, NULL); + evutil_gettimeofday(&end, NULL); evutil_timersub(&end, &start, &total); usec = total_time.tv_sec * 1000000 + total_time.tv_usec; diff --git a/libevent/test/regress.c b/libevent/test/regress.c index ee6962fc..0987809a 100644 --- a/libevent/test/regress.c +++ b/libevent/test/regress.c @@ -2204,7 +2204,7 @@ many_event_cb(evutil_socket_t fd, short event, void *arg) static void test_many_events(void *arg) { - /* Try 70 events that should all be aready at once. This will + /* 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. */ @@ -2212,14 +2212,25 @@ test_many_events(void *arg) 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 @@ -2228,15 +2239,20 @@ test_many_events(void *arg) 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, many_event_cb, - &called[i]); + 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, EVLOOP_NONBLOCK); + event_base_loop(base, loopflags); for (i = 0; i < MANY; ++i) { - tt_int_op(called[i], ==, 1); + if (one_at_a_time) + tt_int_op(called[i], ==, MANY - i + 1); + else + tt_int_op(called[i], ==, 1); } end: @@ -2303,7 +2319,8 @@ struct testcase_t main_testcases[] = { { "dup_fd", test_dup_fd, TT_ISOLATED, &basic_setup, NULL }, #endif { "mm_functions", test_mm_functions, TT_FORK, NULL, NULL }, - BASIC(many_events, TT_ISOLATED), + { "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 }, diff --git a/libevent/test/regress_buffer.c b/libevent/test/regress_buffer.c index 4f4a8303..327210b0 100644 --- a/libevent/test/regress_buffer.c +++ b/libevent/test/regress_buffer.c @@ -1140,7 +1140,9 @@ test_evbuffer_callbacks(void *ptr) 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); diff --git a/libevent/test/regress_bufferevent.c b/libevent/test/regress_bufferevent.c index a120e516..d737b48d 100644 --- a/libevent/test/regress_bufferevent.c +++ b/libevent/test/regress_bufferevent.c @@ -551,7 +551,7 @@ want_fail_eventcb(struct bufferevent *bev, short what, void *ctx) if (what & BEV_EVENT_ERROR) { s = bufferevent_getfd(bev); err = evutil_socket_error_to_string(evutil_socket_geterror(s)); - TT_BLATHER(("connection failure %s", err)); + TT_BLATHER(("connection failure on %d: %s", s, err)); test_ok = 1; } else { TT_FAIL(("didn't fail? what %hd", what)); diff --git a/libevent/test/regress_dns.c b/libevent/test/regress_dns.c index 255f613a..7868bbb3 100644 --- a/libevent/test/regress_dns.c +++ b/libevent/test/regress_dns.c @@ -71,6 +71,8 @@ #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; @@ -1624,10 +1626,9 @@ gaic_launch(struct event_base *base, struct evdns_base *dns_base) } static void -test_getaddrinfo_async_cancel_stress(void *arg) +test_getaddrinfo_async_cancel_stress(void *ptr) { - struct basic_test_data *data = arg; - struct event_base *base = data->base; + struct event_base *base; struct evdns_base *dns_base = NULL; struct evdns_server_port *server = NULL; evutil_socket_t fd = -1; @@ -1699,7 +1700,7 @@ struct testcase_t dns_testcases[] = { { "getaddrinfo_async", test_getaddrinfo_async, TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"" }, { "getaddrinfo_cancel_stress", test_getaddrinfo_async_cancel_stress, - TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"" }, + TT_FORK, NULL, NULL }, END_OF_TESTCASES }; diff --git a/libevent/test/regress_http.c b/libevent/test/regress_http.c index 99e9f938..0aef4d74 100644 --- a/libevent/test/regress_http.c +++ b/libevent/test/regress_http.c @@ -27,6 +27,7 @@ #ifdef WIN32 #include +#include #include #endif @@ -56,6 +57,7 @@ #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" @@ -128,38 +130,23 @@ static evutil_socket_t http_connect(const char *address, u_short port) { /* Stupid code for connecting */ -#ifdef WIN32 - struct hostent *he; - struct sockaddr_in sin; -#else - struct addrinfo ai, *aitop; + struct evutil_addrinfo ai, *aitop; char strport[NI_MAXSERV]; -#endif + struct sockaddr *sa; int slen; evutil_socket_t fd; -#ifdef WIN32 - if (!(he = gethostbyname(address))) { - event_warn("gethostbyname"); - } - memcpy(&sin.sin_addr, he->h_addr_list[0], he->h_length); - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - slen = sizeof(struct sockaddr_in); - sa = (struct sockaddr*)&sin; -#else memset(&ai, 0, sizeof(ai)); ai.ai_family = AF_INET; ai.ai_socktype = SOCK_STREAM; evutil_snprintf(strport, sizeof(strport), "%d", port); - if (getaddrinfo(address, strport, &ai, &aitop) != 0) { + if (evutil_getaddrinfo(address, strport, &ai, &aitop) != 0) { event_warn("getaddrinfo"); return (-1); } sa = aitop->ai_addr; slen = aitop->ai_addrlen; -#endif fd = socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) @@ -178,9 +165,7 @@ http_connect(const char *address, u_short port) #endif } -#ifndef WIN32 - freeaddrinfo(aitop); -#endif + evutil_freeaddrinfo(aitop); return (fd); } @@ -586,6 +571,8 @@ http_bad_request_test(void *arg) /* real NULL request */ http_request = ""; + bufferevent_write(bev, http_request, strlen(http_request)); + shutdown(fd, SHUT_WR); timerclear(&tv); tv.tv_usec = 10000; @@ -2006,8 +1993,13 @@ end: 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)); \ @@ -2023,21 +2015,37 @@ http_parse_uri_test(void *ptr) /* bad URIs: parsing */ #define BAD(s) do { \ - if (evhttp_uri_parse(s) != NULL) \ + if (URI_PARSE(s) != NULL) \ TT_FAIL(("Expected error parsing \"%s\"",s)); \ } while(0) - BAD("http://www.test.com/ why hello"); - BAD("http://www.test.com/why-hello\x01"); - BAD("http://www.test.com/why-hello?\x01"); - BAD("http://www.test.com/why-hello#\x01"); + /* 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"); - BAD("http://www.test.com/why-hell%7o"); + NCF("http://www.test.com/why-hell%7o"); BAD("h%3ttp://www.test.com/why-hello"); - BAD("http://www.test.com/why-hello%7"); - BAD("http://www.test.com/why-hell%7o"); - BAD("http://www.test.com/foo?ba%r"); - BAD("http://www.test.com/foo#ba%r"); + 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/"); @@ -2073,7 +2081,7 @@ http_parse_uri_test(void *ptr) 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 = evhttp_uri_parse("mailto:foo@bar"); + 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); @@ -2125,7 +2133,7 @@ http_parse_uri_test(void *ptr) evhttp_uri_free(uri); /* Valid parsing */ - uri = evhttp_uri_parse("http://www.test.com/?q=t%33est"); + 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); @@ -2136,7 +2144,7 @@ http_parse_uri_test(void *ptr) TT_URI("http://www.test.com/?q=t%33est"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("http://%77ww.test.com"); + 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); @@ -2147,7 +2155,7 @@ http_parse_uri_test(void *ptr) TT_URI("http://%77ww.test.com"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("http://www.test.com?q=test"); + 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); @@ -2158,7 +2166,7 @@ http_parse_uri_test(void *ptr) TT_URI("http://www.test.com?q=test"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("http://www.test.com#fragment"); + 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); @@ -2169,7 +2177,7 @@ http_parse_uri_test(void *ptr) TT_URI("http://www.test.com#fragment"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("http://8000/"); + 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); @@ -2180,7 +2188,7 @@ http_parse_uri_test(void *ptr) TT_URI("http://8000/"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("http://:8000/"); + 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); @@ -2191,7 +2199,7 @@ http_parse_uri_test(void *ptr) TT_URI("http://:8000/"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("http://www.test.com:/"); /* empty port */ + 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), ==, "/"); @@ -2202,7 +2210,7 @@ http_parse_uri_test(void *ptr) TT_URI("http://www.test.com/"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("http://www.test.com:"); /* empty port 2 */ + 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); @@ -2213,7 +2221,7 @@ http_parse_uri_test(void *ptr) TT_URI("http://www.test.com"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("ftp://www.test.com/?q=test"); + 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); @@ -2224,7 +2232,7 @@ http_parse_uri_test(void *ptr) TT_URI("ftp://www.test.com/?q=test"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("ftp://[::1]:999/?q=test"); + 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); @@ -2235,7 +2243,7 @@ http_parse_uri_test(void *ptr) TT_URI("ftp://[::1]:999/?q=test"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("ftp://[ff00::127.0.0.1]/?q=test"); + 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); @@ -2246,7 +2254,7 @@ http_parse_uri_test(void *ptr) TT_URI("ftp://[ff00::127.0.0.1]/?q=test"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("ftp://[v99.not_(any:time)_soon]/?q=test"); + 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); @@ -2257,7 +2265,7 @@ http_parse_uri_test(void *ptr) TT_URI("ftp://[v99.not_(any:time)_soon]/?q=test"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment"); + 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); @@ -2268,7 +2276,7 @@ http_parse_uri_test(void *ptr) TT_URI("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("scheme://user@foo.com/#fragment"); + 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); @@ -2279,7 +2287,7 @@ http_parse_uri_test(void *ptr) TT_URI("scheme://user@foo.com/#fragment"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("scheme://%75ser@foo.com/#frag@ment"); + 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); @@ -2290,7 +2298,7 @@ http_parse_uri_test(void *ptr) TT_URI("scheme://%75ser@foo.com/#frag@ment"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("file:///some/path/to/the/file"); + 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); @@ -2301,7 +2309,7 @@ http_parse_uri_test(void *ptr) TT_URI("file:///some/path/to/the/file"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("///some/path/to/the-file"); + 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); @@ -2313,7 +2321,7 @@ http_parse_uri_test(void *ptr) TT_URI("///some/path/to/the-file"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("/s:ome/path/to/the-file?q=99#fred"); + 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); @@ -2325,7 +2333,7 @@ http_parse_uri_test(void *ptr) TT_URI("/s:ome/path/to/the-file?q=99#fred"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("relative/path/with/co:lon"); + 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); @@ -2337,7 +2345,7 @@ http_parse_uri_test(void *ptr) TT_URI("relative/path/with/co:lon"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("bob?q=99&q2=q?33#fr?ed"); + 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); @@ -2349,7 +2357,7 @@ http_parse_uri_test(void *ptr) TT_URI("bob?q=99&q2=q?33#fr?ed"); evhttp_uri_free(uri); - uri = evhttp_uri_parse("#fr?ed"); + 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); @@ -2360,6 +2368,9 @@ http_parse_uri_test(void *ptr) 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 @@ -2996,6 +3007,65 @@ http_stream_in_cancel_test(void *arg) } +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) { @@ -3505,6 +3575,7 @@ struct testcase_t http_testcases[] = { { "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), @@ -3534,6 +3605,7 @@ struct testcase_t http_testcases[] = { HTTP(stream_in), HTTP(stream_in_cancel), + HTTP(connection_fail), HTTP(connection_retry), HTTP(data_length_constraints), diff --git a/libevent/test/regress_listener.c b/libevent/test/regress_listener.c index 1438f3aa..44fee7f4 100644 --- a/libevent/test/regress_listener.c +++ b/libevent/test/regress_listener.c @@ -34,6 +34,9 @@ #ifndef WIN32 #include #include +# ifdef _XOPEN_SOURCE_EXTENDED +# include +# endif #include #endif diff --git a/libevent/test/regress_ssl.c b/libevent/test/regress_ssl.c index e16bf8b3..6bc5f320 100644 --- a/libevent/test/regress_ssl.c +++ b/libevent/test/regress_ssl.c @@ -30,6 +30,7 @@ #endif #ifndef WIN32 +#include #include #include #endif diff --git a/libevent/test/regress_testutils.c b/libevent/test/regress_testutils.c index b5bef1ab..8902e631 100644 --- a/libevent/test/regress_testutils.c +++ b/libevent/test/regress_testutils.c @@ -68,6 +68,8 @@ #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; diff --git a/libevent/test/regress_zlib.c b/libevent/test/regress_zlib.c index 158d0d61..6dd7bf8f 100644 --- a/libevent/test/regress_zlib.c +++ b/libevent/test/regress_zlib.c @@ -46,7 +46,6 @@ #include #include -#include #include #include @@ -58,6 +57,28 @@ #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 + static int infilter_calls; static int outfilter_calls; static int readcb_finished; @@ -276,6 +297,7 @@ test_bufferevent_zlib(void *arg) 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, diff --git a/libevent/test/test-eof.c b/libevent/test/test-eof.c index 90b40938..417476e8 100644 --- a/libevent/test/test-eof.c +++ b/libevent/test/test-eof.c @@ -32,6 +32,7 @@ int test_okay = 1; int called = 0; +struct timeval timeout = {60, 0}; static void read_cb(evutil_socket_t fd, short event, void *arg) @@ -39,6 +40,11 @@ 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__, @@ -46,7 +52,7 @@ read_cb(evutil_socket_t fd, short event, void *arg) if (len) { if (!called) - event_add(arg, NULL); + event_add(arg, &timeout); } else if (called == 1) test_okay = 0; @@ -85,9 +91,9 @@ main(int argc, char **argv) event_init(); /* Initalize one event */ - event_set(&ev, pair[1], EV_READ, read_cb, &ev); + event_set(&ev, pair[1], EV_READ | EV_TIMEOUT, read_cb, &ev); - event_add(&ev, NULL); + event_add(&ev, &timeout); event_dispatch(); diff --git a/libevent/test/test-ratelim.c b/libevent/test/test-ratelim.c index 824434e0..bbbd7608 100644 --- a/libevent/test/test-ratelim.c +++ b/libevent/test/test-ratelim.c @@ -36,6 +36,9 @@ #else #include #include +# ifdef _XOPEN_SOURCE_EXTENDED +# include +# endif #endif #include @@ -46,6 +49,8 @@ #include "event2/listener.h" #include "event2/thread.h" +#include "../util-internal.h" + static int cfg_verbose = 0; static int cfg_help = 0; diff --git a/libevent/test/test.sh b/libevent/test/test.sh index 48deb9b1..08a4cddb 100755 --- a/libevent/test/test.sh +++ b/libevent/test/test.sh @@ -7,12 +7,18 @@ then TEST_OUTPUT_FILE=/dev/null fi -# /bin/echo is a little more likely to support -n than sh's builtin echo. -if test -x /bin/echo +# /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=/bin/echo + ECHO_N="printf %s" else - ECHO=echo + 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" @@ -45,7 +51,7 @@ announce () { } announce_n () { - $ECHO -n "$@" + $ECHO_N "$@" echo "$@" >>"$TEST_OUTPUT_FILE" } @@ -91,6 +97,7 @@ run_tests () { announce FAILED ; FAILED=yes fi + test -x $TEST_DIR/regress || return announce_n " regress: " if test "$TEST_OUTPUT_FILE" = "/dev/null" ; then diff --git a/libevent/test/tinytest_local.h b/libevent/test/tinytest_local.h index 9f80fcd7..1a7f75ef 100644 --- a/libevent/test/tinytest_local.h +++ b/libevent/test/tinytest_local.h @@ -6,4 +6,7 @@ #include "event2/util.h" #include "util-internal.h" +#ifdef snprintf +#undef snprintf +#endif #define snprintf evutil_snprintf diff --git a/libevent/util-internal.h b/libevent/util-internal.h index cb76ee4f..fe9ff356 100644 --- a/libevent/util-internal.h +++ b/libevent/util-internal.h @@ -38,6 +38,8 @@ #endif #include "event2/util.h" +#include "ipv6-internal.h" + #ifdef __cplusplus extern "C" { #endif @@ -52,9 +54,13 @@ extern "C" { /* A good no-op to use in macro definitions. */ #define _EVUTIL_NIL_STMT ((void)0) -/* Suppresses the compiler's "unused variable" warnings for unused assert. */ +/* A no-op that tricks the compiler into thinking a condition is used while + * definitely not making any code for it. Used to compile out asserts while + * avoiding "unused variable" warnings. The "!" forces the compiler to + * do the sizeof() on an int, in case "condition" is a bitfield value. + */ #define _EVUTIL_NIL_CONDITION(condition) do { \ - (void)sizeof(condition); \ + (void)sizeof(!(condition)); \ } while(0) /* Internal use only: macros to match patterns of error codes in a @@ -173,7 +179,7 @@ long _evutil_weakrand(void); /* Evaluates to the same boolean value as 'p', and hints to the compiler that * we expect this value to be false. */ -#ifdef __GNUC__ +#if defined(__GNUC__) && __GNUC__ >= 3 /* gcc 3.0 or later */ #define EVUTIL_UNLIKELY(p) __builtin_expect(!!(p),0) #else #define EVUTIL_UNLIKELY(p) (p) @@ -201,6 +207,21 @@ long _evutil_weakrand(void); #define EVUTIL_FAILURE_CHECK(cond) EVUTIL_UNLIKELY(cond) #endif +#ifndef _EVENT_HAVE_STRUCT_SOCKADDR_STORAGE +/* Replacement for sockaddr storage that we can use internally on platforms + * that lack it. It is not space-efficient, but neither is sockaddr_storage. + */ +struct sockaddr_storage { + union { + struct sockaddr ss_sa; + struct sockaddr_in ss_sin; + struct sockaddr_in6 ss_sin6; + char ss_padding[128]; + } ss_union; +}; +#define ss_family ss_union.ss_sa.sa_family +#endif + /* Internal addrinfo error code. This one is returned from only from * evutil_getaddrinfo_common, when we are sure that we'll have to hit a DNS * server. */ diff --git a/libevent/whatsnew-2.0.txt b/libevent/whatsnew-2.0.txt index 3b4cfbdb..5ad6b979 100644 --- a/libevent/whatsnew-2.0.txt +++ b/libevent/whatsnew-2.0.txt @@ -75,7 +75,7 @@ What's New In Libevent 2.0 so far: evutil.h) will continue to work by including the corresponding new headers. Old code should not be broken by this change. -2.2. New thread-safe, binary-compatibile, harder-to-mess-up APIs +2.2. New thread-safe, binary-compatible, harder-to-mess-up APIs Some aspects of the historical Libevent API have encouraged non-threadsafe code, or forced code built against one version of Libevent -- 2.39.2