+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
#
# 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
# 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
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.
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
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
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)
if PTHREADS
libevent_pthreads_la_SOURCES = evthread_pthread.c
+libevent_pthreads_la_LIBADD = $(MAYBE_CORE)
libevent_pthreads_la_LDFLAGS = $(GENERIC_LDFLAGS)
endif
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
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
DISTCLEANFILES = *~ libevent.pc ./include/event2/event-config.h
-install:
-
Denis Bilenko
Julien Blache
Kevin Bowling
+ Tomash Brechko
Kelly Brock
Ralph Castain
Shuo Chen
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
Andrey Matveev
Caitlin Mercer
Dagobert Michelsen
+ Mansour Moufid
Felix Nawothnig
Trond Norbye
Linus Nordberg
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
/* 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 <sys/devpoll.h> header file. */
/* #undef _EVENT_HAVE_SYS_DEVPOLL_H */
/* #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"
#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__
return ok ? 0 : -1;
}
-static void
+static int
arc4_stir(void)
{
int i;
}
arc4_seed();
+ if (!arc4_seeded_ok)
+ return -1;
/*
* Discard early keystream, as per recommendations in
for (i = 0; i < 12*256; i++)
(void)arc4_getbyte();
arc4_count = BYTES_BEFORE_RESEED;
+
+ return 0;
}
#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.
#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);
}
+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)
{
#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);
{
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);
/* 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
consider_writing(bev_ssl);
}
/* XXX Handle r < 0 */
+ (void)r;
}
/* 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);
}
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
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
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])
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"
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 <sys/param.h>
)
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])
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 <netdb.h>
+ #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.)
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 <netdb.h>
], [[
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])
CFLAGS=$OLD_CFLAGS
])
+fi
AC_CHECK_SIZEOF(long)
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 <sys/types.h>
#ifdef HAVE_NETINET_IN_H
# 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"
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 <stdlib.h>
+ #include <stdio.h>
+ ]],
+ [[
+ 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)
{
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;
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. */
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;
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);
{
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;
}
}
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++;
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);
#endif
#include "event2/event-config.h"
+#include <time.h>
#include <sys/queue.h>
#include "event2/event_struct.h"
#include "minheap-internal.h"
/** 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 */
#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.
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
}
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;
}
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);
/* 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);
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#ifndef _WIN32_WINNT
+/* Minimum required for InitializeCriticalSectionAndSpinCount */
+#define _WIN32_WINNT 0x0403
+#endif
#include <winsock2.h>
#include <windows.h>
#include <process.h>
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
#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); \
* (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]);
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);
}
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 */
EVUTIL_ASSERT(r == 0);
mm_free(registered_uri);
+
+ mm_free((char *)rpc->uri);
+ mm_free(rpc);
return (0);
}
{
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);
#include "event2/event-config.h"
#ifdef WIN32
+#ifndef _WIN32_WINNT
+/* Minimum required for InitializeCriticalSectionAndSpinCount */
+#define _WIN32_WINNT 0x0403
+#endif
#include <winsock2.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
r = (ev_int64_t) _atoi64(s);
while (isspace(*s))
++s;
+ if (*s == '-')
+ ++s;
while (isdigit(*s))
++s;
if (endptr)
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
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
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,
}
}
+#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.
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 */
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 */
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;
}
}
}
-static void
+static int
apply_socktype_protocol_hack(struct evutil_addrinfo *ai)
{
struct evutil_addrinfo *ai_new;
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;
ai_new->ai_next = ai->ai_next;
ai->ai_next = ai_new;
}
+ return 0;
}
#endif
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
#ifdef _EVENT_HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
+#ifdef _EVENT_HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
#ifdef _EVENT_HAVE_NETDB_H
#include <netdb.h>
#endif
#include "util-internal.h"
#include "http-internal.h"
#include "mm-internal.h"
+#include "bufferevent-internal.h"
#ifndef _EVENT_HAVE_GETNAMEINFO
#define NI_MAXSERV 32
}
#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;
}
/*
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;
}
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;
/* 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) {
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) {
}
} 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;
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,
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",
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
{
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 */
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 */
}
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 */
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;
}
}
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);
}
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);
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,
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
}
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;
}
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 */
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
EVUTIL_ASSERT(eos);
if (eos == s) {
uri->host = mm_strdup("");
+ if (uri->host == NULL) {
+ event_warn("%s: strdup", __func__);
+ return -1;
+ }
return 0;
}
return -1;
*cp++ = '\0';
uri->userinfo = mm_strdup(s);
+ if (uri->userinfo == NULL) {
+ event_warn("%s: strdup", __func__);
+ return -1;
+ }
} else {
cp = s;
}
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;
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) ||
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;
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;
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;
}
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
relative-ref = relative-part [ "?" query ] [ "#" fragment ]
-
*/
/* 1. scheme: */
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 : */
}
/* 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;
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);
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);
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;
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;
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
/**
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()
*/
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
/*@}*/
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
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
* 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.
*
*/
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);
* 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:
+ * <ul>
+ * <li> Nonconformant URIs are allowed to contain otherwise unreasonable
+ * characters in their path, query, and fragment components.
+ * </ul>
+ */
+#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);
/**
* @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);
#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
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)
{
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,
}
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);
Requires: libevent
Conflicts:
Libs: -L${libdir} -levent_openssl
-Libs.private: @LIBS@ -lcrypto -lssl
+Libs.private: @LIBS@ -lssl -lcrypto
Cflags: -I${includedir}
#include "event2/event-config.h"
#ifdef WIN32
+#ifndef _WIN32_WINNT
+/* Minimum required for InitializeCriticalSectionAndSpinCount */
+#define _WIN32_WINNT 0x0403
+#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <mswsock.h>
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
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:
#include <event2/event-config.h>
+/* Compatibility for possible missing IPv6 declarations */
+#include "../ipv6-internal.h"
+
#include <sys/types.h>
#ifdef WIN32
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));
printf("[%d] %s: %s\n",i,name,buf);
}
}
- if (ai_first)
- evutil_freeaddrinfo(ai_first);
}
static void
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);
#include <signal.h>
#ifndef WIN32
#include <netinet/in.h>
+# ifdef _XOPEN_SOURCE_EXTENDED
+# include <arpa/inet.h>
+# endif
#include <sys/socket.h>
#endif
#include <windows.h>
#include <io.h>
#include <fcntl.h>
+#ifndef S_ISDIR
+#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
+#endif
#else
#include <sys/stat.h>
#include <sys/socket.h>
#ifdef _EVENT_HAVE_NETINET_IN_H
#include <netinet/in.h>
+# ifdef _XOPEN_SOURCE_EXTENDED
+# include <arpa/inet.h>
+# endif
#endif
+/* Compatibility for possible missing IPv6 declarations */
+#include "../util-internal.h"
+
#ifdef WIN32
#define stat _stat
#define fstat _fstat
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;
if (!(d = opendir(whole_path)))
goto err;
#endif
- close(fd);
evbuffer_add_printf(evb, "<html>\n <head>\n"
" <title>%s</title>\n"
}
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
};
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)
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);
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;
}
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))
return (0);
}
-
static int
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;
}
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)
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);
+}
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
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"
#include <sys/types.h>
#include <sys/stat.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
+#endif
#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <sys/socket.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#ifdef _EVENT_HAVE_UNISTD_H
#include <unistd.h>
+#endif
#include <errno.h>
#include <event.h>
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);
}
#include <sys/types.h>
#include <sys/stat.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
+#endif
#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <sys/socket.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#ifdef _EVENT_HAVE_UNISTD_H
#include <unistd.h>
+#endif
#include <errno.h>
#include <event.h>
}
/* measurements includes event setup */
- gettimeofday(&ts, NULL);
+ evutil_gettimeofday(&ts, NULL);
/* provide a default timeout for events */
evutil_timerclear(&tv_timeout);
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) {
#else
#include <sys/socket.h>
#include <netinet/in.h>
+# ifdef _XOPEN_SOURCE_EXTENDED
+# include <arpa/inet.h>
+# endif
#endif
#include <stdlib.h>
+#include <string.h>
#include <errno.h>
#include "event2/event.h"
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);
struct request_info *ri;
+ memset(&sin, 0, sizeof(sin));
+
++total_n_launched;
sin.sin_family = AF_INET;
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);
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;
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. */
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
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:
{ "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 },
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);
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));
#include "regress.h"
#include "regress_testutils.h"
+#include "../util-internal.h"
+
static int dns_ok = 0;
static int dns_got_cancel = 0;
static int dns_err = 0;
}
static void
-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;
{ "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
};
#ifdef WIN32
#include <winsock2.h>
+#include <ws2tcpip.h>
#include <windows.h>
#endif
#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"
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)
#endif
}
-#ifndef WIN32
- freeaddrinfo(aitop);
-#endif
+ evutil_freeaddrinfo(aitop);
return (fd);
}
/* real NULL request */
http_request = "";
+ bufferevent_write(bev, http_request, strlen(http_request));
+
shutdown(fd, SHUT_WR);
timerclear(&tv);
tv.tv_usec = 10000;
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)); \
/* 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/");
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);
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);
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);
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);
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);
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);
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);
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), ==, "/");
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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
}
+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)
{
{ "bad_headers", http_bad_header_test, 0, NULL, NULL },
{ "parse_query", http_parse_query_test, 0, NULL, NULL },
{ "parse_uri", http_parse_uri_test, 0, NULL, NULL },
+ { "parse_uri_nc", http_parse_uri_test, 0, &basic_setup, (void*)"nc" },
{ "uriencode", http_uriencode_test, 0, NULL, NULL },
HTTP(basic),
HTTP(cancel),
HTTP(stream_in),
HTTP(stream_in_cancel),
+ HTTP(connection_fail),
HTTP(connection_retry),
HTTP(data_length_constraints),
#ifndef WIN32
#include <sys/socket.h>
#include <netinet/in.h>
+# ifdef _XOPEN_SOURCE_EXTENDED
+# include <arpa/inet.h>
+# endif
#include <unistd.h>
#endif
#endif
#ifndef WIN32
+#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#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;
#include <stdlib.h>
#include <string.h>
-#include <zlib.h>
#include <assert.h>
#include <errno.h>
#include "regress.h"
+/* zlib 1.2.4 and 1.2.5 do some "clever" things with macros. Instead of
+ saying "(defined(FOO) ? FOO : 0)" they like to say "FOO-0", on the theory
+ that nobody will care if the compile outputs a no-such-identifier warning.
+
+ Sorry, but we like -Werror over here, so I guess we need to define these.
+ I hope that zlib 1.2.6 doesn't break these too.
+*/
+#ifndef _LARGEFILE64_SOURCE
+#define _LARGEFILE64_SOURCE 0
+#endif
+#ifndef _LFS64_LARGEFILE
+#define _LFS64_LARGEFILE 0
+#endif
+#ifndef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 0
+#endif
+#ifndef off64_t
+#define off64_t ev_int64_t
+#endif
+
+#include <zlib.h>
+
static int infilter_calls;
static int outfilter_calls;
static int readcb_finished;
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,
int test_okay = 1;
int called = 0;
+struct timeval timeout = {60, 0};
static void
read_cb(evutil_socket_t fd, short event, void *arg)
char buf[256];
int len;
+ if (EV_TIMEOUT & event) {
+ printf("%s: Timeout!\n", __func__);
+ exit(1);
+ }
+
len = recv(fd, buf, sizeof(buf), 0);
printf("%s: read %d%s\n", __func__,
if (len) {
if (!called)
- event_add(arg, NULL);
+ event_add(arg, &timeout);
} else if (called == 1)
test_okay = 0;
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();
#else
#include <sys/socket.h>
#include <netinet/in.h>
+# ifdef _XOPEN_SOURCE_EXTENDED
+# include <arpa/inet.h>
+# endif
#endif
#include <signal.h>
#include "event2/listener.h"
#include "event2/thread.h"
+#include "../util-internal.h"
+
static int cfg_verbose = 0;
static int cfg_help = 0;
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"
}
announce_n () {
- $ECHO -n "$@"
+ $ECHO_N "$@"
echo "$@" >>"$TEST_OUTPUT_FILE"
}
announce FAILED ;
FAILED=yes
fi
+ test -x $TEST_DIR/regress || return
announce_n " regress: "
if test "$TEST_OUTPUT_FILE" = "/dev/null" ;
then
#include "event2/util.h"
#include "util-internal.h"
+#ifdef snprintf
+#undef snprintf
+#endif
#define snprintf evutil_snprintf
#endif
#include "event2/util.h"
+#include "ipv6-internal.h"
+
#ifdef __cplusplus
extern "C" {
#endif
/* 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
/* 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)
#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. */
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