summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore21
-rw-r--r--.travis.yml16
-rw-r--r--CMakeLists.txt1153
-rw-r--r--ChangeLog254
-rw-r--r--Makefile.am10
-rw-r--r--Makefile.nmake2
-rw-r--r--README225
-rw-r--r--README.md318
-rw-r--r--WIN32-Code/getopt.c149
-rw-r--r--WIN32-Code/getopt.h33
-rw-r--r--WIN32-Code/getopt_long.c233
-rw-r--r--WIN32-Code/nmake/evconfig-private.h (renamed from WIN32-Code/evconfig-private.h)0
-rw-r--r--WIN32-Code/nmake/event2/event-config.h (renamed from WIN32-Code/event2/event-config.h)7
-rw-r--r--WIN32-Code/tree.h677
-rw-r--r--buffer.c2
-rw-r--r--bufferevent-internal.h32
-rw-r--r--bufferevent.c84
-rw-r--r--bufferevent_async.c25
-rw-r--r--bufferevent_filter.c75
-rw-r--r--bufferevent_openssl.c30
-rw-r--r--bufferevent_pair.c20
-rw-r--r--bufferevent_sock.c22
-rw-r--r--changelist-internal.h1
-rw-r--r--cmake/COPYING-CMAKE-SCRIPTS22
-rw-r--r--cmake/CheckFileOffsetBits.c14
-rw-r--r--cmake/CheckFileOffsetBits.cmake43
-rw-r--r--cmake/CheckFunctionExistsEx.c30
-rw-r--r--cmake/CheckFunctionExistsEx.cmake69
-rw-r--r--cmake/CheckPrototypeDefinition.c.in29
-rw-r--r--cmake/CheckPrototypeDefinition.cmake85
-rw-r--r--cmake/CheckWorkingKqueue.cmake52
-rw-r--r--cmake/CodeCoverage.cmake162
-rw-r--r--cmake/Copyright.txt57
-rw-r--r--cmake/LibeventConfig.cmake.in17
-rw-r--r--cmake/LibeventConfigVersion.cmake.in11
-rw-r--r--configure.ac18
-rw-r--r--epoll.c209
-rw-r--r--epoll_sub.c13
-rw-r--r--epolltable-internal.h1166
-rw-r--r--evconfig-private.h.cmake35
-rw-r--r--evdns.c47
-rw-r--r--event-config.h.cmake499
-rw-r--r--event-internal.h6
-rw-r--r--event.c150
-rw-r--r--event_tagging.c15
-rw-r--r--evmap.c57
-rw-r--r--evrpc-internal.h1
-rw-r--r--evrpc.c12
-rw-r--r--evutil.c30
-rw-r--r--http.c39
-rw-r--r--include/event2/buffer.h68
-rw-r--r--include/event2/buffer_compat.h5
-rw-r--r--include/event2/bufferevent.h124
-rw-r--r--include/event2/bufferevent_ssl.h9
-rw-r--r--include/event2/dns.h51
-rw-r--r--include/event2/event.h151
-rw-r--r--include/event2/event_compat.h10
-rw-r--r--include/event2/http.h143
-rw-r--r--include/event2/http_struct.h15
-rw-r--r--include/event2/listener.h11
-rw-r--r--include/event2/tag.h22
-rw-r--r--include/event2/thread.h10
-rw-r--r--include/event2/util.h26
-rw-r--r--include/event2/visibility.h55
-rw-r--r--include/include.am3
-rw-r--r--kqueue.c17
-rwxr-xr-xmake_epoll_table.py66
-rw-r--r--sample/dns-example.c2
-rw-r--r--sample/http-server.c7
-rw-r--r--sample/https-client.c109
-rw-r--r--sample/include.am2
-rw-r--r--sample/le-proxy.c5
-rw-r--r--sample/openssl_hostname_validation.c4
-rw-r--r--test/Makefile.nmake8
-rw-r--r--test/bench.c17
-rw-r--r--test/bench_cascade.c19
-rw-r--r--test/bench_http.c6
-rw-r--r--test/include.am4
-rw-r--r--test/regress.c282
-rw-r--r--test/regress_buffer.c34
-rw-r--r--test/regress_bufferevent.c155
-rw-r--r--test/regress_dns.c5
-rw-r--r--test/regress_finalize.c1
-rw-r--r--test/regress_http.c152
-rw-r--r--test/regress_rpc.c9
-rw-r--r--test/regress_ssl.c5
-rw-r--r--test/regress_util.c36
-rw-r--r--test/regress_zlib.c17
-rw-r--r--test/test-changelist.c3
-rw-r--r--test/test-closed.c117
-rw-r--r--test/test-fdleak.c20
-rwxr-xr-xtest/test.sh2
-rw-r--r--test/tinytest.c33
-rw-r--r--test/tinytest.h2
-rw-r--r--test/tinytest_demo.c3
-rw-r--r--test/tinytest_macros.h27
-rw-r--r--util-internal.h5
-rw-r--r--whatsnew-2.1.txt53
98 files changed, 6752 insertions, 1455 deletions
diff --git a/.gitignore b/.gitignore
index dad74e7a..522c5df3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,6 +41,8 @@ TAGS
libevent.pc
libevent_pthreads.pc
libevent_openssl.pc
+*.log
+*.trs
## The initial / makes these files only get ignored in particular directories.
/autom4te.cache
@@ -55,6 +57,7 @@ libevent_openssl.pc
/aclocal.m4
/compile
/doxygen
+/config.cache
/config.guess
/config.log
/config.status
@@ -82,6 +85,7 @@ libevent_openssl.pc
/sample/signal-test
/sample/time-test
+/test-driver
/test/bench
/test/bench_cascade
/test/bench_http
@@ -92,10 +96,27 @@ libevent_openssl.pc
/test/rpcgen-attempted
/test/test-dumpevents
/test/test-eof
+/test/test-closed
/test/test-init
/test/test-ratelim
+/test/test-script.sh
/test/test-time
/test/test-weof
/test/test-changelist
/test/test-fdleak
+
+# Files generated by cmake
+/CMakeCache.txt
+/CMakeFiles/
+/CTestTestfile.cmake
+/DartConfiguration.tcl
+/LibeventConfig.cmake
+/LibeventConfigVersion.cmake
+/LibeventTargets.cmake
+/bin/
+/cmake_install.cmake
+/include/evconfig-private.h
+/lib/
+/tmp/
+/verify_tests.sh
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..6f10ff62
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,16 @@
+env:
+ matrix:
+ - EVENT_BUILD_METHOD=cmake EVENT_CMAKE_OPTIONS=""
+ - EVENT_BUILD_METHOD=cmake EVENT_CMAKE_OPTIONS="-DEVENT__DISABLE_OPENSSL=ON"
+ - EVENT_BUILD_METHOD=cmake EVENT_CMAKE_OPTIONS="-DEVENT__DISABLE_THREAD_SUPPORT=ON"
+ - EVENT_BUILD_METHOD=autotools
+language: c
+compiler:
+ - gcc
+ - clang
+install:
+ - sudo apt-get update -qq
+ - sudo apt-get install -y -qq zlib1g-dev libssl-dev build-essential automake autoconf cmake
+script:
+ - if [ "$EVENT_BUILD_METHOD" = "autotools" ]; then ./autogen.sh && ./configure && make && make verify; fi
+ - if [ "$EVENT_BUILD_METHOD" = "cmake" ]; then mkdir build && cd build && cmake .. $EVENT_CMAKE_OPTIONS && cmake --build . && CTEST_OUTPUT_ON_FAILURE=1 cmake --build . --target verify; fi
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 00000000..124dc86a
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,1153 @@
+#
+# Libevent CMake project
+#
+# Based on initial work by:
+# Alexey Ozeritsky
+#
+# Additional changes:
+# Brodie Thiesfield
+# Joakim Soderberg
+# Trond Norbye
+# Sergei Nikulov
+#
+# Build example:
+#
+# cd libevent
+# md build
+# cd build
+# cmake -G "Visual Studio 10" ..
+# start libevent.sln
+#
+cmake_minimum_required(VERSION 2.8.0 FATAL_ERROR)
+
+# get rid of the extra default configurations
+set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Limited configurations" FORCE)
+
+project(libevent C)
+
+set(EVENT_VERSION_MAJOR 2)
+set(EVENT_VERSION_MINOR 1)
+set(EVENT_VERSION_PATCH 4)
+set(EVENT_NUMERIC_VERSION 0x02010401)
+set(EVENT_VERSION_DEVTAG "-dev")
+
+set(EVENT_ABI_MAJOR 2)
+set(EVENT_ABI_MINOR 1)
+set(EVENT_ABI_PATCH 4)
+set(EVENT_ABI_LIBVERSION "${EVENT_ABI_MAJOR}.${EVENT_ABI_MINOR}.${EVENT_ABI_PATCH}")
+
+set(EVENT_VERSION "${EVENT_VERSION_MAJOR}.${EVENT_VERSION_MINOR}.${EVENT_VERSION_PATCH}-alpha${EVENT_VERSION_DEVTAG}")
+set(EVENT_PACKAGE_VERSION "${EVENT_VERSION_MAJOR}.${EVENT_VERSION_MINOR}.${EVENT_VERSION_PATCH}")
+
+option(EVENT__BUILD_SHARED_LIBRARIES "Define if libevent should be built with shared libraries instead of archives" OFF)
+option(EVENT__DISABLE_DEBUG_MODE "Define if libevent should build without support for a debug mode" OFF)
+option(EVENT__ENABLE_VERBOSE_DEBUG "Enables verbose debugging" OFF)
+option(EVENT__DISABLE_MM_REPLACEMENT "Define if libevent should not allow replacing the mm functions" OFF)
+option(EVENT__DISABLE_THREAD_SUPPORT "Define if libevent should not be compiled with thread support" OFF)
+option(EVENT__DISABLE_OPENSSL "Define if libevent should build without support for OpenSSL encrpytion" OFF)
+option(EVENT__DISABLE_BENCHMARK "Defines if libevent should build without the benchmark exectuables" OFF)
+option(EVENT__DISABLE_TESTS "If tests should be compiled or not" OFF)
+option(EVENT__DISABLE_REGRESS "Disable the regress tests" OFF)
+option(EVENT__FORCE_KQUEUE_CHECK "When crosscompiling forces running a test program that verifies that Kqueue works with pipes. Note that this requires you to manually run the test program on the the cross compilation target to verify that it works. See cmake documentation for try_run for more details" OFF)
+option(EVENT__COVERAGE "Enable running gcov to get a test coverage report (only works with GCC/CLang). Make sure to enable -DCMAKE_BUILD_TYPE=Debug as well." OFF)
+# TODO: Add --disable-largefile omit support for large files
+
+# Put the libaries and binaries that get built into directories at the
+# top of the build tree rather than in hard-to-find leaf directories.
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
+include(CheckFunctionExistsEx)
+include(CheckFileOffsetBits)
+include(CheckFunctionExists)
+include(CheckIncludeFile)
+include(CheckIncludeFiles)
+include(CheckTypeSize)
+include(CheckVariableExists)
+include(CheckSymbolExists)
+include(CheckStructHasMember)
+include(CheckCSourceCompiles)
+include(CheckPrototypeDefinition)
+
+if (EVENT__ENABLE_VERBOSE_DEBUG)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_DEBUG=1")
+endif()
+
+# Setup compiler flags for coverage.
+if (EVENT__COVERAGE)
+ if(NOT CMAKE_COMPILER_IS_GNUCC)
+ if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ message(FATAL_ERROR "Trying to compile coverage support (--DEVENT__COVERAGE) but compiler is not GNU gcc! Aborting... You can set this on the command line using CC=/usr/bin/gcc CXX=/usr/bin/g++ cmake <options> ..")
+ endif()
+ endif()
+
+ if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
+ message(FATAL_ERROR "Code coverage results with an optimised (non-Debug) build may be misleading! Add -DCMAKE_BUILD_TYPE=Debug")
+ endif()
+
+ message("Setting coverage compiler flags")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
+endif()
+
+# GCC specific options.
+if (CMAKE_COMPILER_IS_GNUCC)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
+
+ option(EVENT__DISABLE_GCC_WARNINGS "Disable verbose warnings with GCC" OFF)
+ if (EVENT__DISABLE_GCC_WARNINGS)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
+ endif()
+
+ option(EVENT__ENABLE_GCC_HARDENING "Enable compiler security checks" OFF)
+ if (EVENT__ENABLE_GCC_HARDENING)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2 -fstack-protector-all -fwrapv -fPIE -Wstack-protector --param ssp-buffer-size=1")
+ endif()
+
+ option(EVENT__ENABLE_GCC_FUNCTION_SECTIONS "Enable gcc function sections" OFF)
+ if (EVENT__ENABLE_GCC_FUNCTION_SECTIONS)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections")
+ # TODO: Add --gc-sections support. We need some checks for NetBSD to ensure this works.
+ endif()
+
+ option(EVENT__ENABLE_GCC_WARNINGS "Make all GCC warnings into errors" OFF)
+ if (EVENT__ENABLE_GCC_WARNINGS)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
+ endif()
+
+ # We need to test for at least gcc 2.95 here, because older versions don't
+ # have -fno-strict-aliasing
+ execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
+ OUTPUT_VARIABLE GCC_VERSION)
+ if (GCC_VERSION VERSION_GREATER 2.95)
+ message(STATUS "GCC Version >= 2.95 enabling no-strict-aliasing")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing")
+ endif()
+endif()
+
+if (APPLE)
+ # Get rid of deprecated warnings for OpenSSL on OSX 10.7 and greater.
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=deprecated-declarations")
+ # Get rid of "clang: warning: argument unused during compilation: -I etc
+ if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Qunused-arguments")
+ endif()
+endif()
+
+# Winsock.
+if(WIN32)
+ set(CMAKE_EXTRA_INCLUDE_FILES winsock2.h ws2tcpip.h)
+ set(CMAKE_REQUIRED_LIBRARIES ws2_32.lib)
+ set(CMAKE_REQUIRED_DEFINITIONS -FIwinsock2.h -FIws2tcpip.h)
+endif()
+
+# Check if _GNU_SOURCE is available.
+CHECK_SYMBOL_EXISTS(__GNU_LIBRARY__ "features.h" _GNU_SOURCE)
+
+if (_GNU_SOURCE)
+ add_definitions(-D_GNU_SOURCE)
+endif()
+
+CHECK_INCLUDE_FILE(sys/types.h EVENT__HAVE_SYS_TYPES_H)
+if(EVENT__HAVE_SYS_TYPES_H)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES sys/types.h)
+endif()
+
+CHECK_INCLUDE_FILE(sys/socket.h EVENT__HAVE_SYS_SOCKET_H)
+if(EVENT__HAVE_SYS_SOCKET_H)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES sys/socket.h)
+endif()
+
+CHECK_INCLUDE_FILE(netinet/in.h EVENT__HAVE_NETINET_IN_H)
+if(EVENT__HAVE_NETINET_IN_H)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES netinet/in.h)
+endif()
+
+CHECK_INCLUDE_FILE(netinet/in6.h EVENT__HAVE_NETINET_IN6_H)
+if(EVENT__HAVE_NETINET_IN6_H)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES netinet/in6.h)
+endif()
+
+CHECK_INCLUDE_FILE(unistd.h EVENT__HAVE_UNISTD_H)
+CHECK_INCLUDE_FILE(netdb.h EVENT__HAVE_NETDB_H)
+CHECK_INCLUDE_FILE(dlfcn.h EVENT__HAVE_DLFCN_H)
+CHECK_INCLUDE_FILE(arpa/inet.h EVENT__HAVE_ARPA_INET_H)
+CHECK_INCLUDE_FILE(fcntl.h EVENT__HAVE_FCNTL_H)
+if(EVENT__HAVE_FCNTL_H)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES fcntl.h)
+endif()
+CHECK_INCLUDE_FILE(inttypes.h EVENT__HAVE_INTTYPES_H)
+CHECK_INCLUDE_FILE(memory.h EVENT__HAVE_MEMORY_H)
+CHECK_INCLUDE_FILE(poll.h EVENT__HAVE_POLL_H)
+CHECK_INCLUDE_FILE(port.h EVENT__HAVE_PORT_H)
+if(EVENT__HAVE_PORT_H)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES port.h)
+endif()
+CHECK_INCLUDE_FILE(signal.h EVENT__HAVE_SIGNAL_H)
+CHECK_INCLUDE_FILE(stdarg.h EVENT__HAVE_STDARG_H)
+CHECK_INCLUDE_FILE(stddef.h EVENT__HAVE_STDDEF_H)
+CHECK_INCLUDE_FILE(stdint.h EVENT__HAVE_STDINT_H)
+CHECK_INCLUDE_FILE(stdlib.h EVENT__HAVE_STDLIB_H)
+CHECK_INCLUDE_FILE(strings.h EVENT__HAVE_STRINGS_H)
+CHECK_INCLUDE_FILE(string.h EVENT__HAVE_STRING_H)
+CHECK_INCLUDE_FILE(sys/devpoll.h EVENT__HAVE_SYS_DEVPOLL_H)
+CHECK_INCLUDE_FILE(sys/epoll.h EVENT__HAVE_SYS_EPOLL_H)
+CHECK_INCLUDE_FILE(sys/eventfd.h EVENT__HAVE_SYS_EVENTFD_H)
+CHECK_INCLUDE_FILE(sys/event.h EVENT__HAVE_SYS_EVENT_H)
+CHECK_INCLUDE_FILE(sys/ioctl.h EVENT__HAVE_SYS_IOCTL_H)
+CHECK_INCLUDE_FILE(sys/mman.h EVENT__HAVE_SYS_MMAN_H)
+CHECK_INCLUDE_FILE(sys/param.h EVENT__HAVE_SYS_PARAM_H)
+CHECK_INCLUDE_FILE(sys/queue.h EVENT__HAVE_SYS_QUEUE_H)
+CHECK_INCLUDE_FILE(sys/select.h EVENT__HAVE_SYS_SELECT_H)
+CHECK_INCLUDE_FILE(sys/sendfile.h EVENT__HAVE_SYS_SENDFILE_H)
+CHECK_INCLUDE_FILE(sys/stat.h EVENT__HAVE_SYS_STAT_H)
+CHECK_INCLUDE_FILE(sys/time.h EVENT__HAVE_SYS_TIME_H)
+if(EVENT__HAVE_SYS_TIME_H)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES sys/time.h)
+endif()
+CHECK_INCLUDE_FILE(sys/uio.h EVENT__HAVE_SYS_UIO_H)
+CHECK_INCLUDE_FILES("sys/types.h;ifaddrs.h" EVENT__HAVE_IFADDRS_H)
+CHECK_INCLUDE_FILE(mach/mach_time.h EVENT__HAVE_MACH_MACH_TIME_H)
+CHECK_INCLUDE_FILE(netdb.h EVENT__HAVE_NETDB_H)
+CHECK_INCLUDE_FILE(netinet/tcp.h EVENT__HAVE_NETINET_TCP_H)
+CHECK_INCLUDE_FILE(sys/wait.h EVENT__HAVE_SYS_WAIT_H)
+CHECK_INCLUDE_FILE(sys/resource.h EVENT__HAVE_SYS_RESOURCE_H)
+CHECK_INCLUDE_FILE(sys/sysctl.h EVENT__HAVE_SYS_SYSCTL_H)
+CHECK_INCLUDE_FILE(sys/timerfd.h EVENT__HAVE_SYS_TIMERFD_H)
+
+
+CHECK_FUNCTION_EXISTS_EX(epoll_create EVENT__HAVE_EPOLL)
+CHECK_FUNCTION_EXISTS_EX(epoll_ctl EVENT__HAVE_EPOLL_CTL)
+CHECK_FUNCTION_EXISTS_EX(eventfd EVENT__HAVE_EVENTFD)
+CHECK_FUNCTION_EXISTS_EX(clock_gettime EVENT__HAVE_CLOCK_GETTIME)
+CHECK_FUNCTION_EXISTS_EX(fcntl EVENT__HAVE_FCNTL)
+CHECK_FUNCTION_EXISTS_EX(getaddrinfo EVENT__HAVE_GETADDRINFO)
+CHECK_FUNCTION_EXISTS_EX(getnameinfo EVENT__HAVE_GETNAMEINFO)
+CHECK_FUNCTION_EXISTS_EX(gettimeofday EVENT__HAVE_GETTIMEOFDAY)
+CHECK_FUNCTION_EXISTS_EX(getprotobynumber EVENT__HAVE_GETPROTOBYNUMBER)
+CHECK_FUNCTION_EXISTS_EX(getservbyname EVENT__HAVE_GETSERVBYNAME)
+CHECK_FUNCTION_EXISTS_EX(inet_ntop EVENT__HAVE_INET_NTOP)
+CHECK_FUNCTION_EXISTS_EX(inet_pton EVENT__HAVE_INET_PTON)
+CHECK_FUNCTION_EXISTS_EX(kqueue EVENT__HAVE_KQUEUE)
+CHECK_FUNCTION_EXISTS_EX(mmap EVENT__HAVE_MMAP)
+CHECK_FUNCTION_EXISTS_EX(pipe EVENT__HAVE_PIPE)
+CHECK_FUNCTION_EXISTS_EX(pipe2 EVENT__HAVE_PIPE2)
+CHECK_FUNCTION_EXISTS_EX(poll EVENT__HAVE_POLL)
+CHECK_FUNCTION_EXISTS_EX(port_create EVENT__HAVE_PORT_CREATE)
+CHECK_FUNCTION_EXISTS_EX(sendfile EVENT__HAVE_SENDFILE)
+CHECK_FUNCTION_EXISTS_EX(sigaction EVENT__HAVE_SIGACTION)
+CHECK_FUNCTION_EXISTS_EX(signal EVENT__HAVE_SIGNAL)
+CHECK_FUNCTION_EXISTS_EX(splice EVENT__HAVE_SPLICE)
+CHECK_FUNCTION_EXISTS_EX(strlcpy EVENT__HAVE_STRLCPY)
+CHECK_FUNCTION_EXISTS_EX(strsep EVENT__HAVE_STRSEP)
+CHECK_FUNCTION_EXISTS_EX(strtok_r EVENT__HAVE_STRTOK_R)
+CHECK_FUNCTION_EXISTS_EX(strtoll EVENT__HAVE_STRTOLL)
+CHECK_FUNCTION_EXISTS_EX(vasprintf EVENT__HAVE_VASPRINTF)
+CHECK_FUNCTION_EXISTS_EX(sysctl EVENT__HAVE_SYSCTL)
+CHECK_FUNCTION_EXISTS_EX(accept4 EVENT__HAVE_ACCEPT4)
+CHECK_FUNCTION_EXISTS_EX(arc4random EVENT__HAVE_ARC4RANDOM)
+CHECK_FUNCTION_EXISTS_EX(arc4random_buf EVENT__HAVE_ARC4RANDOM_BUF)
+CHECK_FUNCTION_EXISTS_EX(epoll_create1 EVENT__HAVE_EPOLL_CREATE1)
+CHECK_FUNCTION_EXISTS_EX(getegid EVENT__HAVE_GETEGID)
+CHECK_FUNCTION_EXISTS_EX(geteuid EVENT__HAVE_GETEUID)
+CHECK_FUNCTION_EXISTS_EX(getifaddrs EVENT__HAVE_GETIFADDRS)
+CHECK_FUNCTION_EXISTS_EX(issetugid EVENT__HAVE_ISSETUGID)
+CHECK_FUNCTION_EXISTS_EX(mach_absolute_time EVENT__HAVE_MACH_ABSOLUTE_TIME)
+CHECK_FUNCTION_EXISTS_EX(nanosleep EVENT__HAVE_NANOSLEEP)
+CHECK_FUNCTION_EXISTS_EX(usleep EVENT__HAVE_USLEEP)
+CHECK_FUNCTION_EXISTS_EX(timeradd EVENT__HAVE_TIMERADD)
+CHECK_FUNCTION_EXISTS_EX(timerclear EVENT__HAVE_TIMERCLEAR)
+CHECK_FUNCTION_EXISTS_EX(timercmp EVENT__HAVE_TIMERCMP)
+CHECK_FUNCTION_EXISTS_EX(timerfd_create HAVE_TIMERFD_CREATE)
+CHECK_FUNCTION_EXISTS_EX(timerisset EVENT__HAVE_TIMERISSET)
+CHECK_FUNCTION_EXISTS_EX(putenv EVENT__HAVE_PUTENV)
+CHECK_FUNCTION_EXISTS_EX(setenv EVENT__HAVE_SETENV)
+CHECK_FUNCTION_EXISTS_EX(setrlimit EVENT__HAVE_SETRLIMIT)
+CHECK_FUNCTION_EXISTS_EX(umask EVENT__HAVE_UMASK)
+CHECK_FUNCTION_EXISTS_EX(unsetenv EVENT__HAVE_UNSETENV)
+
+# Get the gethostbyname_r prototype.
+CHECK_FUNCTION_EXISTS_EX(gethostbyname_r EVENT__HAVE_GETHOSTBYNAME_R)
+
+if(EVENT__HAVE_GETHOSTBYNAME_R)
+ CHECK_PROTOTYPE_DEFINITION(gethostbyname_r
+ "int gethostbyname_r(const char *name, struct hostent *hp, struct hostent_data *hdata)"
+ "0"
+ "netdb.h"
+ EVENT__HAVE_GETHOSTBYNAME_R_3_ARG)
+
+ CHECK_PROTOTYPE_DEFINITION(gethostbyname_r
+ "struct hostent *gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen, int *herr)"
+ "NULL"
+ "netdb.h"
+ EVENT__HAVE_GETHOSTBYNAME_R_5_ARG)
+
+ CHECK_PROTOTYPE_DEFINITION(gethostbyname_r
+ "int gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen, struct hostent **result, int *herr)"
+ "0"
+ "netdb.h"
+ EVENT__HAVE_GETHOSTBYNAME_R_6_ARG)
+endif()
+
+if(HAVE_PORT_H AND HAVE_PORT_CREATE)
+ set(EVENT__HAVE_EVENT_PORTS 1)
+endif()
+
+if(NOT WIN32)
+ CHECK_FUNCTION_EXISTS_EX(select EVENT__HAVE_SELECT)
+endif()
+
+CHECK_TYPE_SIZE("uint8_t" EVENT__HAVE_UINT8_T)
+CHECK_TYPE_SIZE("uint16_t" EVENT__HAVE_UINT16_T)
+CHECK_TYPE_SIZE("uint32_t" EVENT__HAVE_UINT32_T)
+CHECK_TYPE_SIZE("uint64_t" EVENT__HAVE_UINT64_T)
+CHECK_TYPE_SIZE("short" EVENT__SIZEOF_SHORT BUILTIN_TYPES_ONLY)
+CHECK_TYPE_SIZE("int" EVENT__SIZEOF_INT BUILTIN_TYPES_ONLY)
+CHECK_TYPE_SIZE("unsigned" EVENT__SIZEOF_UNSIGNED BUILTIN_TYPES_ONLY)
+CHECK_TYPE_SIZE("unsigned int" EVENT__SIZEOF_UNSIGNED_INT BUILTIN_TYPES_ONLY)
+CHECK_TYPE_SIZE("long" EVENT__SIZEOF_LONG BUILTIN_TYPES_ONLY)
+CHECK_TYPE_SIZE("long long" EVENT__SIZEOF_LONG_LONG BUILTIN_TYPES_ONLY)
+
+if(WIN32)
+ # These aren't available until Windows Vista.
+ # But you can still link them. They just won't be found when running the exe.
+ set(EVENT__HAVE_INET_NTOP 0)
+ set(EVENT__HAVE_INET_PTON 0)
+endif()
+
+# Check for different inline keyword versions.
+foreach(KEYWORD "inline" "__inline__" "__inline")
+ set(CMAKE_REQUIRED_DEFINITIONS "-DKEYWORD=${KEYWORD}")
+ CHECK_C_SOURCE_COMPILES(
+ "
+ #include <stdio.h>
+ KEYWORD void a() {}
+ int main(int argc, char **argv) { a(); return 0; }
+ " HAVE_${KEYWORD})
+endforeach()
+
+if (NOT HAVE_inline)
+ if (HAVE___inline__)
+ set(EVENT__inline __inline__)
+ elseif(HAVE___inline)
+ set(EVENT__inline __inline)
+ endif()
+endif()
+set(CMAKE_REQUIRED_DEFINITIONS "")
+
+# Check for different function name macros.
+foreach(KEYWORD "__func__" "__FUNCTION__")
+ set(CMAKE_REQUIRED_DEFINITIONS "-DKEYWORD=${KEYWORD}")
+ CHECK_C_SOURCE_COMPILES(
+ "
+ #include <stdio.h>
+ int main(int argc, char **argv) { const char *cp = KEYWORD; return 0; }
+ " HAVE_${KEYWORD})
+endforeach()
+set(CMAKE_REQUIRED_DEFINITIONS "")
+
+if (NOT HAVE___func__)
+ if (HAVE___FUNCTION__)
+ set(EVENT____func__ __FUNCTION__)
+ else()
+ # Substitute for __func__
+ set(EVENT____func__ __FILE__)
+ endif()
+endif()
+
+CHECK_SYMBOL_EXISTS(TAILQ_FOREACH sys/queue.h EVENT__HAVE_TAILQFOREACH)
+CHECK_SYMBOL_EXISTS(CTL_KERN sys/sysctl.h EVENT__HAVE_DECL_CTL_KERN)
+CHECK_SYMBOL_EXISTS(KERN_ARND sys/sysctl.h EVENT__HAVE_DECL_KERN_ARND)
+CHECK_SYMBOL_EXISTS(KERN_RANDOM sys/sysctl.h EVENT__HAVE_DECL_KERN_RANDOM)
+CHECK_SYMBOL_EXISTS(RANDOM_UUID sys/sysctl.h EVENT__HAVE_DECL_RANDOM_UUID)
+CHECK_SYMBOL_EXISTS(F_SETFD fcntl.h EVENT__HAVE_SETFD)
+
+CHECK_TYPE_SIZE(fd_mask EVENT__HAVE_FD_MASK)
+
+CHECK_TYPE_SIZE(size_t EVENT__SIZEOF_SIZE_T)
+if(NOT EVENT__SIZEOF_SIZE_T)
+ set(EVENT__size_t unsigned)
+ set(EVENT__SIZEOF_SIZE_T ${EVENT__SIZEOF_UNSIGNED})
+endif()
+
+CHECK_TYPE_SIZE("off_t" EVENT__SIZEOF_OFF_T)
+
+CHECK_TYPE_SIZE(ssize_t EVENT__SIZEOF_SSIZE_T)
+CHECK_TYPE_SIZE(SSIZE_T EVENT__SIZEOF_UPPERCASE_SSIZE_T)
+if(NOT EVENT__SIZEOF_SSIZE_T)
+ if(EVENT__SIZEOF_UPPERCASE_SSIZE_T)
+ set(EVENT__ssize_t SSIZE_T)
+ set(EVENT__SIZEOF_SSIZE_T ${EVENT__SIZEOF_UPPERCASE_SSIZE_T})
+ else()
+ set(EVENT__ssize_t int)
+ set(EVENT__SIZEOF_SSIZE_T ${EVENT__SIZEOF_INT})
+ endif()
+endif()
+
+CHECK_TYPE_SIZE(socklen_t EVENT__SIZEOF_SOCKLEN_T)
+if(NOT EVENT__SIZEOF_SOCKLEN_T)
+ set(EVENT__socklen_t "unsigned int")
+ set(EVENT__SIZEOF_SOCKLEN_T ${EVENT__SIZEOF_UNSIGNED_INT})
+endif()
+
+CHECK_TYPE_SIZE(pid_t EVENT__SIZEOF_PID_T)
+if(NOT EVENT__SIZEOF_PID_T)
+ set(EVENT__pid_t int)
+ set(EVENT__SIZEOF_PID_T ${EVENT__SIZEOF_INT})
+endif()
+
+CHECK_TYPE_SIZE(pthread_t EVENT__SIZEOF_PTHREAD_T)
+
+if(EVENT__HAVE_CLOCK_GETTIME)
+ set(EVENT__DNS_USE_CPU_CLOCK_FOR_ID 1)
+endif()
+
+CHECK_TYPE_SIZE("uintptr_t" EVENT__HAVE_UINTPTR_T)
+CHECK_TYPE_SIZE("void *" EVENT__SIZEOF_VOID_P)
+
+# Tests file offset bits.
+# TODO: Add AIX test for if -D_LARGE_FILES is needed.
+CHECK_FILE_OFFSET_BITS()
+set(EVENT___FILE_OFFSET_BITS _FILE_OFFSET_BITS)
+
+# Verify kqueue works with pipes.
+if (EVENT__HAVE_KQUEUE)
+ if (CMAKE_CROSSCOMPILING AND NOT EVENT__FORCE_KQUEUE_CHECK)
+ message(WARNING "Cannot check if kqueue works with pipes when crosscompiling, use EVENT__FORCE_KQUEUE_CHECK to be sure (this requires manually running a test program on the cross compilation target)")
+ set(EVENT__HAVE_WORKING_KQUEUE 1)
+ else()
+ message("Checking if kqueue works with pipes...")
+ include(CheckWorkingKqueue)
+ endif()
+endif()
+
+CHECK_SYMBOL_EXISTS(_MINIX "stdio.h" EVENT___MINIX)
+CHECK_SYMBOL_EXISTS(_POSIX_1_SOURCE "stdio.h" EVENT___POSIX_1_SOURCE)
+CHECK_SYMBOL_EXISTS(_POSIX_SOURCE "stdio.h" EVENT___POSIX_SOURCE)
+
+if(EVENT__HAVE_NETDB_H)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES netdb.h)
+ CHECK_TYPE_SIZE("struct addrinfo" EVENT__HAVE_STRUCT_ADDRINFO)
+elseif(WIN32)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES ws2tcpip.h)
+ CHECK_TYPE_SIZE("struct addrinfo" EVENT__HAVE_STRUCT_ADDRINFO)
+endif()
+
+# Check for sockaddr structure sizes.
+set(SOCKADDR_HEADERS)
+
+if (WIN32)
+ set(CMAKE_REQUIRED_DEFINITIONS "-DWIN32_LEAN_AND_MEAN")
+ if (_MSC_VER LESS 1300)
+ set(SOCKADDR_HEADERS winsock.h)
+ else()
+ set(SOCKADDR_HEADERS winsock2.h ws2tcpip.h)
+ endif()
+else()
+ if (EVENT__HAVE_NETINET_IN_H)
+ set(SOCKADDR_HEADERS ${SOCKADDR_HEADERS} netinet/in.h)
+ endif()
+
+ if (EVENT__HAVE_NETINET_IN6_H)
+ set(SOCKADDR_HEADERS ${SOCKADDR_HEADERS} netinet/in6.h)
+ endif()
+
+ if (EVENT__HAVE_SYS_SOCKET_H)
+ set(SOCKADDR_HEADERS ${SOCKADDR_HEADERS} sys/socket.h)
+ endif()
+
+ if (EVENT__HAVE_NETDB_H)
+ set(SOCKADDR_HEADERS ${SOCKADDR_HEADERS} netdb.h)
+ endif()
+endif()
+
+CHECK_TYPE_SIZE("struct in6_addr" EVENT__HAVE_STRUCT_IN6_ADDR)
+if(EVENT__HAVE_STRUCT_IN6_ADDR)
+ CHECK_STRUCT_HAS_MEMBER("struct in6_addr" s6_addr16 "${SOCKADDR_HEADERS}" EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR16)
+ CHECK_STRUCT_HAS_MEMBER("struct in6_addr" s6_addr32 "${SOCKADDR_HEADERS}" EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR32)
+endif()
+
+CHECK_TYPE_SIZE("sa_family_t" EVENT__HAVE_SA_FAMILY_T)
+CHECK_TYPE_SIZE("struct sockaddr_in6" EVENT__HAVE_STRUCT_SOCKADDR_IN6)
+if(EVENT__HAVE_STRUCT_SOCKADDR_IN6)
+ CHECK_STRUCT_HAS_MEMBER("struct sockaddr_in6" sin6_len "${SOCKADDR_HEADERS}" EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN)
+ CHECK_STRUCT_HAS_MEMBER("struct sockaddr_in6" sin_len "${SOCKADDR_HEADERS}" EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN)
+endif()
+
+CHECK_TYPE_SIZE("struct sockaddr_storage" EVENT__HAVE_STRUCT_SOCKADDR_STORAGE)
+if(EVENT__HAVE_STRUCT_SOCKADDR_STORAGE)
+ CHECK_STRUCT_HAS_MEMBER("struct sockaddr_storage" ss_family "${SOCKADDR_HEADERS}" EVENT__HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY)
+ CHECK_STRUCT_HAS_MEMBER("struct sockaddr_storage" __ss_family "${SOCKADDR_HEADERS}" EVENT__HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY)
+endif()
+
+# Group the source files.
+set(HDR_PRIVATE
+ bufferevent-internal.h
+ changelist-internal.h
+ defer-internal.h
+ epolltable-internal.h
+ evbuffer-internal.h
+ event-internal.h
+ evmap-internal.h
+ evrpc-internal.h
+ evsignal-internal.h
+ evthread-internal.h
+ ht-internal.h
+ http-internal.h
+ iocp-internal.h
+ ipv6-internal.h
+ log-internal.h
+ minheap-internal.h
+ mm-internal.h
+ ratelim-internal.h
+ strlcpy-internal.h
+ util-internal.h
+ evconfig-private.h
+ compat/sys/queue.h
+ )
+
+set(HDR_COMPAT
+ include/evdns.h
+ include/evrpc.h
+ include/event.h
+ include/evhttp.h
+ include/evutil.h
+ )
+
+set(HDR_PUBLIC
+ include/event2/buffer.h
+ include/event2/bufferevent.h
+ include/event2/bufferevent_compat.h
+ include/event2/bufferevent_struct.h
+ include/event2/buffer_compat.h
+ include/event2/dns.h
+ include/event2/dns_compat.h
+ include/event2/dns_struct.h
+ include/event2/event.h
+ include/event2/event_compat.h
+ include/event2/event_struct.h
+ include/event2/http.h
+ include/event2/http_compat.h
+ include/event2/http_struct.h
+ include/event2/keyvalq_struct.h
+ include/event2/listener.h
+ include/event2/rpc.h
+ include/event2/rpc_compat.h
+ include/event2/rpc_struct.h
+ include/event2/tag.h
+ include/event2/tag_compat.h
+ include/event2/thread.h
+ include/event2/util.h
+ include/event2/visibility.h
+ ${PROJECT_BINARY_DIR}/include/event2/event-config.h
+ )
+
+set(SRC_CORE
+ buffer.c
+ bufferevent.c
+ bufferevent_filter.c
+ bufferevent_pair.c
+ bufferevent_ratelim.c
+ bufferevent_sock.c
+ event.c
+ evmap.c
+ evthread.c
+ evutil.c
+ evutil_rand.c
+ evutil_time.c
+ listener.c
+ log.c
+ signal.c
+ strlcpy.c
+ )
+
+if(EVENT__HAVE_SELECT)
+ list(APPEND SRC_CORE select.c)
+endif()
+
+if(EVENT__HAVE_POLL)
+ list(APPEND SRC_CORE poll.c)
+endif()
+
+if(EVENT__HAVE_KQUEUE)
+ list(APPEND SRC_CORE kqueue.c)
+endif()
+
+if(EVENT__HAVE_DEVPOLL)
+ list(APPEND SRC_CORE devpoll.c)
+endif()
+
+if(EVENT__HAVE_EPOLL)
+ list(APPEND SRC_CORE epoll_sub.c epoll.c)
+endif()
+
+if(EVENT__HAVE_EVENT_PORTS)
+ list(APPEND SRC_CORE evport.c)
+endif()
+
+if (NOT EVENT__DISABLE_OPENSSL)
+ find_package(OpenSSL REQUIRED)
+ set(EVENT__HAVE_OPENSSL 1)
+ message("OpenSSL include: ${OPENSSL_INCLUDE_DIR}")
+ message("OpenSSL lib: ${OPENSSL_LIBRARIES}")
+ include_directories(${OPENSSL_INCLUDE_DIR})
+ list(APPEND SRC_CORE bufferevent_openssl.c)
+ list(APPEND HDR_PUBLIC include/event2/bufferevent_ssl.h)
+ list(APPEND LIB_APPS ${OPENSSL_LIBRARIES})
+endif()
+
+if (NOT EVENT__DISABLE_THREAD_SUPPORT)
+ if (WIN32)
+ list(APPEND SRC_CORE evthread_win32.c)
+ else()
+ find_package(Threads REQUIRED)
+ if (NOT CMAKE_USE_PTHREADS_INIT)
+ message(FATAL_ERROR "Failed to find Pthreads, set EVENT__DISABLE_THREAD_SUPPORT to turn off thread support")
+ endif()
+ set(EVENT__HAVE_PTHREADS 1)
+ list(APPEND SRC_CORE evthread_pthread.c)
+ list(APPEND LIB_APPS ${CMAKE_THREAD_LIBS_INIT})
+ endif()
+endif()
+
+if (NOT EVENT__DISABLE_TESTS)
+ # Zlib is only used for testing.
+ find_package(ZLIB)
+
+ if (ZLIB_LIBRARY)
+ set(EVENT__HAVE_ZLIB 1)
+ set(EVENT__HAVE_ZLIB_H)
+ include_directories(${ZLIB_INCLUDE_DIRS})
+ list(APPEND LIB_APPS ${ZLIB_LIBRARIES})
+ endif()
+endif()
+
+set(SRC_EXTRA
+ event_tagging.c
+ http.c
+ evdns.c
+ evrpc.c
+ )
+
+add_definitions(-DHAVE_CONFIG_H)
+
+# We use BEFORE here so we don't accidentally look in system directories
+# first for some previous versions of the headers that are installed.
+include_directories(BEFORE ${PROJECT_SOURCE_DIR}
+ ${PROJECT_SOURCE_DIR}/compat
+ ${PROJECT_SOURCE_DIR}/include)
+
+if(WIN32)
+ list(APPEND SRC_CORE
+ buffer_iocp.c
+ bufferevent_async.c
+ event_iocp.c
+ evthread_win32.c
+ win32select.c
+ )
+
+ list(APPEND HDR_PRIVATE WIN32-Code/getopt.h)
+
+ set(EVENT__DNS_USE_FTIME_FOR_ID 1)
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE)
+ set(LIB_PLATFORM ws2_32)
+ include_directories(./WIN32-Code)
+endif()
+
+if (UNIX)
+ list(APPEND LIB_PLATFORM m)
+endif()
+
+source_group("Headers Private" FILES ${HDR_PRIVATE})
+source_group("Header Compat" FILES ${HDR_COMPAT})
+source_group("Headers Public" FILES ${HDR_PUBLIC})
+source_group("Source Core" FILES ${SRC_CORE})
+source_group("Source Extra" FILES ${SRC_EXTRA})
+
+# Generate the configure headers.
+# (Place them in the build dir so we don't polute the source tree with generated files).
+include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include)
+
+if (EVENT__BUILD_SHARED_LIBRARIES)
+ set(EVENT__LIBRARY_TYPE SHARED)
+
+ if (CMAKE_COMPILER_IS_GNUC)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
+ elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
+ elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "SunPro")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -xldscope=hidden")
+ endif ()
+ set(EVENT__NEED_DLLIMPORT 1)
+
+else (EVENT__BUILD_SHARED_LIBRARIES)
+ set(EVENT__LIBRARY_TYPE STATIC)
+endif (EVENT__BUILD_SHARED_LIBRARIES)
+
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/event-config.h.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/include/event2/event-config.h)
+
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/evconfig-private.h.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/include/evconfig-private.h)
+
+#
+# Create the libraries.
+#
+
+# TODO: Add dynamic versions of the libraries as well.
+add_library(event_core ${EVENT__LIBRARY_TYPE}
+ ${HDR_PRIVATE}
+ ${HDR_COMPAT}
+ ${HDR_PUBLIC}
+ ${SRC_CORE}
+ )
+
+add_library(event_extra ${EVENT__LIBRARY_TYPE}
+ ${HDR_PRIVATE}
+ ${HDR_COMPAT}
+ ${HDR_PUBLIC}
+ ${SRC_CORE}
+ ${SRC_EXTRA}
+ )
+
+# library exists for historical reasons; it contains the contents of
+# both libevent_core and libevent_extra. You shouldn’t use it; it may
+# go away in a future version of Libevent.
+add_library(event ${EVENT__LIBRARY_TYPE}
+ ${HDR_PRIVATE}
+ ${HDR_COMPAT}
+ ${HDR_PUBLIC}
+ ${SRC_CORE}
+ ${SRC_EXTRA}
+ )
+
+if (EVENT__BUILD_SHARED_LIBRARIES)
+ target_link_libraries(event_core ${OPENSSL_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${LIB_PLATFORM})
+
+ target_link_libraries(event ${OPENSSL_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${LIB_PLATFORM})
+
+ target_link_libraries(event_extra ${OPENSSL_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${LIB_PLATFORM})
+
+ set_target_properties(event PROPERTIES SOVERSION ${EVENT_ABI_LIBVERSION})
+ set_target_properties(event_core PROPERTIES SOVERSION ${EVENT_ABI_LIBVERSION})
+ set_target_properties(event_extra PROPERTIES SOVERSION ${EVENT_ABI_LIBVERSION})
+
+endif (EVENT__BUILD_SHARED_LIBRARIES)
+
+#
+# Samples.
+#
+
+if (NOT EVENT__DISABLE_SAMPLES)
+ set(SAMPLES
+ dns-example
+ event-read-fifo
+ hello-world
+ signal-test
+ http-server
+ time-test)
+
+ if (NOT EVENT__DISABLE_OPENSSL AND OPENSSL_LIBRARIES)
+ # Special sample with more than one file.
+ add_executable(https-client
+ sample/https-client.c
+ sample/openssl_hostname_validation.c
+ sample/hostcheck.c)
+ target_link_libraries(https-client event_extra ${LIB_APPS} ${LIB_PLATFORM})
+ add_dependencies(https-client event_extra)
+
+ # Requires OpenSSL.
+ list(APPEND SAMPLES le-proxy)
+ endif()
+
+ foreach(SAMPLE ${SAMPLES})
+ add_executable(${SAMPLE} sample/${SAMPLE}.c)
+ target_link_libraries(${SAMPLE} event_extra ${LIB_APPS} ${LIB_PLATFORM})
+ add_dependencies(${SAMPLE} event_extra)
+ endforeach()
+endif()
+
+if (NOT EVENT__DISABLE_BENCHMARK)
+ foreach (BENCHMARK bench bench_cascade bench_http bench_httpclient)
+ set(BENCH_SRC test/${BENCHMARK}.c)
+
+ if (WIN32)
+ list(APPEND BENCH_SRC WIN32-Code/getopt.c WIN32-Code/getopt_long.c)
+ endif()
+
+ add_executable(${BENCHMARK} ${BENCH_SRC})
+ target_link_libraries(${BENCHMARK} event_extra ${LIB_PLATFORM})
+ add_dependencies(${BENCHMARK} event_extra)
+ endforeach()
+endif()
+
+if (NOT EVENT__DISABLE_TESTS)
+
+ #
+ # Generate Regress tests.
+ #
+ if (NOT EVENT__DISABLE_REGRESS)
+
+ # (We require python to generate the regress tests)
+ find_package(PythonInterp)
+ if (PYTHONINTERP_FOUND AND PYTHON_VERSION_STRING VERSION_LESS "3.0.0")
+ set(__FOUND_USABLE_PYTHON 1)
+ endif()
+
+ if (__FOUND_USABLE_PYTHON)
+ message("Generating regress tests...")
+ add_definitions(-DTINYTEST_LOCAL)
+ add_custom_command(
+ OUTPUT
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/regress.gen.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/regress.gen.h
+ DEPENDS
+ event_rpcgen.py
+ test/regress.rpc
+ COMMAND ${PYTHON_EXECUTABLE} ../event_rpcgen.py regress.rpc
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test
+ )
+
+ list(APPEND SRC_REGRESS
+ test/regress.c
+ test/regress.gen.c
+ test/regress.gen.h
+ test/regress_buffer.c
+ test/regress_bufferevent.c
+ test/regress_dns.c
+ test/regress_et.c
+ test/regress_finalize.c
+ test/regress_http.c
+ test/regress_listener.c
+ test/regress_main.c
+ test/regress_minheap.c
+ test/regress_rpc.c
+ test/regress_testutils.c
+ test/regress_testutils.h
+ test/regress_util.c
+ test/tinytest.c
+ ${SRC_CORE}
+ ${SRC_EXTRA}
+ )
+
+ if (WIN32)
+ list(APPEND SRC_REGRESS test/regress_iocp.c)
+ list(APPEND SRC_REGRESS test/regress_thread.c)
+ endif()
+
+ if (CMAKE_USE_PTHREADS_INIT)
+ list(APPEND SRC_REGRESS test/regress_thread.c)
+ endif()
+
+ if (ZLIB_LIBRARY)
+ list(APPEND SRC_REGRESS test/regress_zlib.c)
+ endif()
+
+ if (OPENSSL_LIBRARIES)
+ list(APPEND SRC_REGRESS test/regress_ssl.c)
+ endif()
+
+ add_executable(regress ${SRC_REGRESS})
+ # While building the test suite we don't want the visibility
+ # header trying to "dllimport" the symbols on windows (it
+ # generates a ton of warnings due to different link
+ # attributes for all of the symbols)
+ SET_TARGET_PROPERTIES(regress PROPERTIES COMPILE_DEFINITIONS
+ "EVENT_BUILDING_REGRESS_TEST=1")
+
+ target_link_libraries(regress ${LIB_APPS} ${LIB_PLATFORM})
+ else()
+ message(WARNING "No suitable Python interpreter found, cannot generate regress tests!")
+ endif()
+ endif()
+
+ #
+ # Test programs.
+ #
+ set(TESTPROGS test-changelist
+ test-eof
+ test-fdleak
+ test-init
+ test-time
+ test-weof)
+
+ set(ALL_TESTPROGS ${TESTPROGS} test-dumpevents test-ratelim)
+
+ # Create test program executables.
+ foreach (TESTPROG ${ALL_TESTPROGS})
+ add_executable(${TESTPROG} test/${TESTPROG}.c)
+ target_link_libraries(${TESTPROG} event_extra ${LIB_PLATFORM})
+ add_dependencies(${TESTPROG} event_extra)
+ endforeach()
+
+ #
+ # We run all tests with the different backends turned on one at a time.
+ #
+
+ # Add event backends based on system introspection result.
+ set(BACKENDS "")
+
+ if (EVENT__HAVE_EPOLL)
+ list(APPEND BACKENDS EPOLL)
+ endif()
+
+ if (EVENT__HAVE_SELECT)
+ list(APPEND BACKENDS SELECT)
+ endif()
+
+ if (EVENT__HAVE_POLL)
+ list(APPEND BACKENDS POLL)
+ endif()
+
+ if (EVENT__HAVE_KQUEUE)
+ list(APPEND BACKENDS KQUEUE)
+ endif()
+
+ if (EVENT__HAVE_EVENT_PORTS)
+ list(APPEND BACKENDS EVPORT)
+ endif()
+
+ if (EVENT__HAVE_DEVPOLL)
+ list(APPEND BACKENDS DEVPOLL)
+ endif()
+
+ if (WIN32)
+ list(APPEND BACKENDS WIN32)
+ endif()
+
+ message("Available event backends: ${BACKENDS}")
+
+ # Default environment variables turns off all event systems,
+ # then we enable each one, one at a time when creating the tests.
+ set(DEFAULT_TEST_ENV_VARS "EVENT_SHOW_METHOD=1;")
+ foreach(BACKEND ${BACKENDS})
+ set(BACKEND_ENV_VAR "EVENT_NO${BACKEND}=1")
+ list(APPEND DEFAULT_TEST_ENV_VARS "${BACKEND_ENV_VAR}")
+ endforeach()
+
+ # Macro that creates the ctest test for a backend.
+ macro(add_backend_test BACKEND_TEST_NAME ENV_VARS)
+ set(TEST_NAMES "")
+
+ foreach (TESTPROG ${TESTPROGS})
+ set(TEST_NAME ${TESTPROG}__${BACKEND_TEST_NAME})
+ add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTPROG})
+ list(APPEND TEST_NAMES ${TEST_NAME})
+ set_tests_properties(${TEST_NAME} PROPERTIES ENVIRONMENT "${ENV_VARS}")
+ endforeach()
+
+ # Dump events test.
+ if (__FOUND_USABLE_PYTHON)
+ set(TEST_NAME test-dumpevents__${BACKEND_TEST_NAME})
+ add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-dumpevents | ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/check-dumpevents.py)
+ set_tests_properties(${TEST_NAME} PROPERTIES ENVIRONMENT "${ENV_VARS}")
+ else()
+ message(WARNING "test-dumpevents will be run without output check since python was not found!")
+ set(TEST_NAME test-dumpevents__${BACKEND_TEST_NAME}_no_check)
+ add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-dumpevents)
+ set_tests_properties(${TEST_NAME} PROPERTIES ENVIRONMENT "${ENV_VARS}")
+ endif()
+
+ # Regress tests.
+ if (NOT EVENT__DISABLE_REGRESS AND __FOUND_USABLE_PYTHON)
+ set(TEST_NAME regress__${BACKEND_TEST_NAME})
+ add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/regress)
+ set_tests_properties(${TEST_NAME} PROPERTIES ENVIRONMENT "${ENV_VARS}")
+ endif()
+ endmacro()
+
+ # Add the tests for each backend.
+ foreach(BACKEND ${BACKENDS})
+ # Enable this backend only.
+ set(BACKEND_ENV_VARS ${DEFAULT_TEST_ENV_VARS})
+ list(REMOVE_ITEM BACKEND_ENV_VARS EVENT_NO${BACKEND}=1)
+
+ # Epoll has some extra settings.
+ if (${BACKEND} STREQUAL "EPOLL")
+ add_backend_test(timerfd_${BACKEND} "${BACKEND_ENV_VARS};EVENT_PRECISE_TIMER=1")
+ add_backend_test(changelist_${BACKEND} "${BACKEND_ENV_VARS};EVENT_EPOLL_USE_CHANGELIST=yes")
+ add_backend_test(timerfd_changelist_${BACKEND} "${BACKEND_ENV_VARS};EVENT_EPOLL_USE_CHANGELIST=yes;EVENT_PRECISE_TIMER=1")
+ else()
+ add_backend_test(${BACKEND} "${BACKEND_ENV_VARS}")
+ endif()
+ endforeach()
+
+ #
+ # Rate limiter tests.
+ #
+
+ # Group limits, no connection limit.
+ add_test(test-ratelim__group_lim ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-ratelim -g 30000 -n 30 -t 100 --check-grouplimit 1000 --check-stddev 100)
+
+ # Connection limit, no group limit.
+ add_test(test-ratelim__con_lim ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-ratelim -c 1000 -n 30 -t 100 --check-connlimit 50 --check-stddev 50)
+
+ # Connection limit and group limit.
+ add_test(test-ratelim__group_con_lim ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-ratelim -c 1000 -g 30000 -n 30 -t 100 --check-grouplimit 1000 --check-connlimit 50 --check-stddev 50)
+
+ # Connection limit and group limit with independent drain.
+ add_test(test-ratelim__group_con_lim_drain ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-ratelim -c 1000 -g 35000 -n 30 -t 100 -G 500 --check-grouplimit 1000 --check-connlimit 50 --check-stddev 50)
+
+ # Add a "make verify" target, same as for autoconf.
+ # (Important! This will unset all EVENT_NO* environment variables.
+ # If they are set in the shell the tests are running using simply "ctest" or "make test" will fail)
+ if (WIN32)
+ # Windows doesn't have "unset". But you can use "set VAR=" instead.
+ # We need to guard against the possibility taht EVENT_NOWIN32 is set, and all test failing
+ # since no event backend being available.
+ file(TO_NATIVE_PATH ${CMAKE_CTEST_COMMAND} WINDOWS_CTEST_COMMAND)
+
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/tmp/verify_tests.bat
+ "
+ set EVENT_NOWIN32=
+ \"${WINDOWS_CTEST_COMMAND}\"
+ ")
+
+ message("${WINDOWS_CTEST_COMMAND}")
+ file(COPY ${CMAKE_CURRENT_BINARY_DIR}/tmp/verify_tests.bat
+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
+ FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
+
+ file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/verify_tests.bat" VERIFY_PATH)
+
+ add_custom_target(verify COMMAND "${VERIFY_PATH}"
+ DEPENDS event ${ALL_TESTPROGS})
+ else()
+ # On some platforms doing exec(unset) as CMake does won't work, so make sure
+ # we run the unset command in a shell instead.
+ # First we write the script contents.
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/tmp/verify_tests.sh
+ "
+ #!/bin/bash
+ unset EVENT_NOEPOLL; unset EVENT_NOPOLL; unset EVENT_NOSELECT; unset EVENT_NOWIN32; unset EVENT_NOEVPORT; unset EVENT_NOKQUEUE; unset EVENT_NODEVPOLL
+ ${CMAKE_CTEST_COMMAND}
+ ")
+
+ # Then we copy the file (this allows us to set execute permission on it)
+ file(COPY ${CMAKE_CURRENT_BINARY_DIR}/tmp/verify_tests.sh
+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
+ FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
+
+ # Create the target that runs the script.
+ add_custom_target(verify COMMAND ${CMAKE_CURRENT_BINARY_DIR}/verify_tests.sh
+ DEPENDS event ${ALL_TESTPROGS})
+ endif()
+
+ if (NOT EVENT__DISABLE_REGRESS AND __FOUND_USABLE_PYTHON)
+ add_dependencies(verify regress)
+ endif()
+
+ if (EVENT__COVERAGE)
+ include(CodeCoverage)
+
+ setup_target_for_coverage(
+ verify_coverage # Coverage target name "make verify_coverage"
+ make # Test runner.
+ coverage # Output directory.
+ verify) # Arguments passed to test runner. "make verify"
+ endif()
+
+ enable_testing()
+
+ include(CTest)
+endif()
+
+#
+# Installation preparation.
+#
+
+# Allow the user to override installation directories.
+set(EVENT_INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries")
+set(EVENT_INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables")
+set(EVENT_INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files")
+
+if(WIN32 AND NOT CYGWIN)
+ set(DEF_INSTALL_CMAKE_DIR cmake)
+else()
+ set(DEF_INSTALL_CMAKE_DIR lib/cmake/libevent)
+endif()
+
+set(EVENT_INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files")
+
+# Make sure the paths are absolute.
+foreach(p LIB BIN INCLUDE CMAKE)
+ set(var EVENT_INSTALL_${p}_DIR)
+ if(NOT IS_ABSOLUTE "${${var}}")
+ set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}")
+ endif()
+endforeach()
+
+# Export targets (This is used for other CMake projects to easily find the libraries and include files).
+export(TARGETS event event_extra event_core
+ FILE "${PROJECT_BINARY_DIR}/LibeventTargets.cmake")
+export(PACKAGE libevent)
+
+# Generate the config file for the build-tree.
+set(EVENT__INCLUDE_DIRS
+ "${PROJECT_SOURCE_DIR}/include"
+ "${PROJECT_BINARY_DIR}/include")
+set(LIBEVENT_INCLUDE_DIRS ${EVENT__INCLUDE_DIRS} CACHE PATH "Libevent include directories")
+configure_file(${PROJECT_SOURCE_DIR}/cmake/LibeventConfig.cmake.in
+ ${PROJECT_BINARY_DIR}/LibeventConfig.cmake
+ @ONLY)
+
+# Generate the config file for the installation tree.
+file(RELATIVE_PATH
+ REL_INCLUDE_DIR
+ "${EVENT_INSTALL_CMAKE_DIR}"
+ "${EVENT_INSTALL_INCLUDE_DIR}") # Calculate the relative directory from the Cmake dir.
+
+# Note the EVENT_CMAKE_DIR is defined in LibeventConfig.cmake.in,
+# we escape it here so it's evaluated when it is included instead
+# so that the include dirs are givenrelative to where the
+# config file is located.
+set(EVENT__INCLUDE_DIRS
+ "\${EVENT_CMAKE_DIR}/${REL_INCLUDE_DIR}")
+configure_file(${PROJECT_SOURCE_DIR}/cmake/LibeventConfig.cmake.in
+ ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/LibeventConfig.cmake
+ @ONLY)
+
+# Generate version info for both build-tree and install-tree.
+configure_file(${PROJECT_SOURCE_DIR}/cmake/LibeventConfigVersion.cmake.in
+ ${PROJECT_BINARY_DIR}/LibeventConfigVersion.cmake
+ @ONLY)
+
+# Define the public headers.
+set_target_properties(event event_core event_extra
+ PROPERTIES PUBLIC_HEADER "${HDR_PUBLIC}")
+
+#
+# Install targets.
+#
+install(TARGETS event event_core event_extra
+ EXPORT LibeventTargets
+ RUNTIME DESTINATION "${EVENT_INSTALL_BIN_DIR}" COMPONENT bin
+ LIBRARY DESTINATION "${EVENT_INSTALL_LIB_DIR}" COMPONENT lib
+ ARCHIVE DESTINATION "${EVENT_INSTALL_LIB_DIR}" COMPONENT lib
+ PUBLIC_HEADER DESTINATION "${EVENT_INSTALL_INCLUDE_DIR}/event2" COMPONENT dev)
+# Install compat headers
+install(FILES ${HDR_COMPAT}
+ DESTINATION "${EVENT_INSTALL_INCLUDE_DIR}"
+ COMPONENT dev)
+
+# Install the configs.
+install(FILES
+ ${PROJECT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/LibeventConfig.cmake
+ ${PROJECT_BINARY_DIR}/LibeventConfigVersion.cmake
+ DESTINATION "${EVENT_INSTALL_CMAKE_DIR}" COMPONENT dev)
+
+
+# Install exports for the install-tree.
+install(EXPORT LibeventTargets
+ DESTINATION "${EVENT_INSTALL_CMAKE_DIR}" COMPONENT dev)
+
+set(LIBEVENT_LIBRARIES event event_core event_extra CACHE STRING "Libevent libraries")
diff --git a/ChangeLog b/ChangeLog
index 368d2a14..a21cabe2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,256 @@
-Changes in version 2.1.4-{alpha,beta,rc} (?? ??? 2013)
+Changes in version 2.1.5-alpha (?? ??? 2014)
+
+
+Changes in version 2.1.4-alpha (21 Mar 2014)
+
+ Libevent 2.1.4-alpha adds a number of new miscellaneous APIs to make
+ Libevent more useful, including support for early close detection with
+ epoll via EPOLLRDHUP, triggering bufferevent callbacks, adding more
+ evhttp callbacks, and more. There are also numerous bugfixes, including
+ a number for finalize-related issues from 2.1.3-alpha; and an
+ alternative (non-primary!) cmake-based build mechanism.
+
+ New APIs (core)
+ o Added event_base_get_num_events() (0fa107d Mobai Zhang)
+ o New event_base_active_by_fd API (865a142 Greg Hazel, 5c9da9a, 87fa2b0)
+ o Add event_base_active_by_signal by analogy (4865943)
+ o Add access to max event count stats (5173bef, efbd3dc, 26230a2
+ Andrew Sweeney)
+ o Implemented EV_CLOSED event for epoll backend
+ (EPOLLRDHUP). (b1b69ac Diego Giagio, 53d2793, 43ffcf6, dfe1e52
+ Marcin Juszkiewicz, ff26633 Joakim Soderberg, 3908a5e)
+
+ New APIs (evutil_secure_rng)
+ o Add evutil_secure_rng_set_urandom_device_file (2bbb5d7)
+
+ New APIs (bufferevents)
+ o Add function to fetch underlying ratelimit cfg (4b3d5af Mark Ellzey)
+ o Pass and return const for bufferevent_get_token_bucket_cfg (1c77fbb
+ Mark Ellzey)
+ o Add watermark introspection (4ce242b Ondřej Kuzník)
+ o Add an option to trigger bufferevent I/O callbacks (61ee18b Ondřej Kuzník)
+ o Add an option to trigger bufferevent event callbacks (a7384c7
+ Ondřej Kuzník)
+ o Clarifications in response to merge req. comments (bd41947 Ondřej
+ Kuzník)
+ o Minor optimizations on bufferevent_trigger options (a3172a4)
+
+ New APIs (evhttp)
+ o Add evhttp_connection_get_server(). (a7f82a3 Maxime Henrion)
+ o add a http default content type option (5a5acd9 Nicolas Martyanoff)
+ o http: implement new evhttp_connection_get_addr() api. (0c7f040 Azat
+ Khuzhin)
+ o Add a variant of evhttp_send_reply_chunk() with a callback on
+ evhttp_write_buffer() (8d8decf Julien BLACHE)
+ o Allow registering callback for parsing HTTP headers (b0bd7fe Balint Reczey)
+ o Provide on request complete callback facility (b083ca0 Andrew Sweeney)
+ o evhttp_request_set_on_complete_cb to be more specific about what
+ the function actually does and usage (da86dda Andrew Sweeney)
+ o Update unit test to make sure that the callback happens after the
+ output data is written (b85f398 Andrew Sweeney)
+
+ Features (evdns)
+ o bug fix for issues #293 evdns_base_load_hosts doesn't remove
+ outdated addresses (954d2f9, f03d353, 45eba6f Kuldeep Gupta)
+
+ Features: (cmake build support)
+ o Initial CMake commit. (e415196 Joakim Soderberg)
+ o Add all tests and benchmarks to CMake project. (e9fc014 Joakim Soderberg)
+ o More work on adding tests to CMake project (99c1dc3 Joakim Soderberg)
+ o Generate a dummy evconfig-private.h so things build
+ properly. (ce14def Joakim Soderberg)
+ o Link libm on unix platforms. (58fcd42 Joakim Soderberg)
+ o Added some GCC specific options. (19222e5 Joakim Soderberg)
+ o Use evutil_closesocket instead. (dbf2b51 Joakim Soderberg)
+ o Add copyright and licensing files for CMake modules. (c259d53
+ Joakim Soderberg)
+ o Only include WIN32 getopt where it is used. (9bbce0b Joakim Soderberg)
+ o Fix bench_cascade program on Windows. (78da644 Joakim Soderberg)
+ o Don't segfault on no found event backend. (8f2af50 Joakim Soderberg)
+ o Only test the event backends available on the system. (7ea4159
+ Joakim Soderberg)
+ o Added a "make verify" target. (e053c4f Joakim Soderberg)
+ o Fix the make "verify" target on Windows. (67e5d74 Joakim Soderberg)
+ o Get rid of deprecation warnings for OpenSSL on OSX 10.7+ (69c3516
+ Joakim Söderberg)
+ o Fix kqueue support. (a831f2f Joakim Söderberg)
+ o Added a test for testing if kqueue works with pipes. (2799b35
+ Joakim Söderberg)
+ o Change the BSD license from 4 to 3-clause. (86df3ed Joakim Soderberg)
+ o Minimum required python version is 2.4. (968e97b Joakim Soderberg)
+ o Get rid of unknown pragma warnings. (0ef1d04 Joakim Soderberg)
+ o Add a "make verify_coverage" target generation coverage
+ info. (f2483f8 Joakim Soderberg)
+ o Fix the "make verify" target on NetBSD (4ac086a Joakim Soderberg)
+ o Only look for ZLib when it is used (if tests are
+ included). (f780593 Joakim Soderberg)
+ o Added EVENT__ENABLE_GCC_WARNINGS, turns all warnings into
+ errors. (dd413bd Joakim Soderberg)
+ o Add CMake config and install targets. (f3446ed Joakim Soderberg)
+ o Fix typo (4b754df Joakim Soderberg)
+ o Some work on making it possible to simply do add_subdirectory() on
+ the project. (49ab363 Joakim Soderberg)
+ o Set USE_DEBUG=1 on EVENT__ENABLE_VERBOSE_DEBUG (fd42e70 Joakim Soderberg)
+ o Fix so that old nmake project still builds. (24d6466 Joakim
+ Soderberg)
+ o Rename README to README.md and use markdown to format. (d2bc39a
+ Joakim Soderberg)
+ o Update README with CMake build instructions. (604b8cc Joakim Soderberg)
+ o Clean up the README some. (8d4cb35 JoakimSoderberg)
+ o Forgotten headers for old nmake project compatability. (8697b99
+ Joakim Soderberg)
+ o Change all uses of WIN32 to _WIN32 (4e14395 Joakim Söderberg)
+ o Fix include bug. (2024467 Joakim Söderberg)
+ o Check if we're on OSX before disabling deprecation in le-proxy
+ (8b40a5b Joakim Söderberg)
+ o Fix broken autotools build. (ae1bd82 Joakim Söderberg)
+ o Disclaimerize cmake a little in the README (d03b5bf)
+ o Fix CMake compile when OpenSSL is disabled. (e423d42 Joakim
+ Söderberg)
+ o CMake: Get rid of python not found warning when regress tests
+ turned off. (d38d798 Joakim Söderberg)
+ o Fix https-client compilation on Windows. (d7be788 Joakim Soderberg)
+ o Guard against EVENT_NOWIN32 being set during testing. (f1715b4
+ Joakim Soderberg)
+ o Check for OSX when checking for clang. (e212c54 Joakim Soderberg)
+ o Added a Travis-CI configuration file. (8c0f0a9 Joakim Soderberg)
+ o Added -Qunused-arguments for clang on macosx (ed99d92 Trond Norbye)
+ o Rename event_extras to event_extra (a0dd5df Trond Norbye)
+ o Add option to build shared library (4545fa9 Trond Norbye)
+ o Add -Qunused-arguments for clang on macos (b56611d Trond Norbye)
+ o Add cmake-related files to .gitignore (e061321 Trond Norbye)
+ o Export event_extra not event_extras. (2b41bcf Joakim Söderberg)
+
+ Bugfixes (core)
+ o If evsel->del() fails, don't leave the evmap in an inconsistent
+ state (9b5a527 Maxime Henrion)
+ o Move event_debug_note_teardown_ before mm_free. (69b5c64)
+ o Check CLOCK_MONOTONIC_* at runtime if needed. (911abf3)
+ o Fix reinit of fds with EV_WRITE but not EV_READ. (ebfd8a8 maksqwe)
+ o Tweaked callbacks to prevent race condition
+ (https://github.com/libevent/libevent/issues/104) (40830f1, 2ea15ed
+ John Ohl)
+ o Move assert(ev) to before we use ev in EV_CLOSURE_EVENT_FINALIZE
+ case (9805972)
+
+ Bugfixes (evhttp)
+ o Fix a double close() bug in evhttp when the underlying bufferevent uses
+ BEV_OPT_CLOSE_ON_FREE. (31db8a0 Maxime Henrion)
+ o Fix an unlikely but possible error case for http connections (f22049e)
+ o Avoid racy bufferevent activation (5eb1788 Nate Rosenblum)
+
+ Bugfixes on 2.0 (Windows)
+ o Use windows vsnprintf fixup logic on all windows environments (e826f19)
+ o libevent/win32_dealloc() : fix sizeof(pointer) vs sizeof(*pointer)
+ (b8f5980 Frank Denis)
+
+ Bugfixes (evutil_secure_rng)
+ o When we seed from /proc/sys/kernel/random/uuid, count it as success
+ (e35b540)
+ o We should return after arc4random_buf() (1ea1f26 Makoto Kato)
+ o Avoid other RNG initialization FS reads when urandom file is
+ specified (9695e9c)
+ o Really remove RNG seeds from the stack (f5ced88)
+ o Fix another arc4random_buf-related warning (e64a2b0)
+
+ Bugfixes (bufferevents)
+ o Initialize async bufferevent timeout CBs unconditionally (af9b2a7)
+
+ Bugfixes (evdns)
+ o Checking request nameserver for NULL, before using it. (5c710c0
+ Belobrov Andrey)
+ o Fix SEGFAULT after evdns_base_resume if no nameservers
+ installed. (14971a8 Azat Khuzhin)
+ o Actually use the log facility for reporting evdns problems. (e1766a1)
+ o Fix SEGFAULT after evdns_base_resume if no nameservers
+ installed. (f8d7df8 Azat Khuzhin)
+ o fix for ServFail from RIPE Atlas release (62f596b Antony Antony)
+
+ Bugfixes (compilation)
+ o Fix test compilation with nmake: add the gdi.lib dependency (5ba8ab7)
+ o Whoops. It is gdi.lib, not gdi32.lib. (github issue #61) (8ab612e)
+ o Don't use return since return type is void and build error occurs
+ using clang (838161d Makoto Kato)
+ o Use void casts to suppress some "unchecked return value" warns (7080d55)
+ o rpcgen: Generate regress.gen.[c,h] in build rather than src dir
+ (243386c Ross Lagerwall)
+ o Fix a compiler warning when checking for arc4random_buf linker
+ breakage. (5cb3865)
+ o Fix 'make distcheck' by adding regress.gen.[ch] to DISTCLEANFILES
+ (239d834)
+
+ o Fix a c90 warning (c207682)
+ o Fix consts in WIN32-Code/getopt*.[ch] (57abb35)
+
+ Bugfixes (locks, synchronization)
+ o Missed lock acquire/release in event_base_cancel_single_callback_()
+ (d3d999a Azat Khuzhin)
+ o Fix locking in bufferevent_get_options_(). (dbc9cd4 Maxime Henrion)
+
+ Bugfixes (leaks)
+ o Avoid leaking segment mappings when offset is not a page multiple (d409514)
+
+ Testing
+ o Add tests for evdns_base_resume(). (1cd9ff5 Azat Khuzhin)
+ o Fix dns/leak_resume_send_err test. (7e876df Azat Khuzhin)
+ o Add checks for evhttp_connection_get_server() in unit
+ tests. (fbc323b Maxime Henrion)
+ o Fix a (failure-only) null dereference in the unit tests (1104d0b)
+ o Fix a logic error in test_evbuffer_freeze (7765884)
+ o Add missing check to test_evbuffer_file_segment_add_cleanup_cb (eba4506)
+ o Fix some crash-on-fail cases in DNS regression tests (87cd6f0)
+ o DNS tests: add a missing check (f314900)
+ o Finalize tests: add a missing check (82b6956)
+ o test_evutil_rtrim: add another missing check. (e193c95)
+ o regress_main: logging all if env EVENT_DEBUG_LOGGING_ALL isset
+ (611e28b Azat Khuzhin)
+ o regress_http: add tests for evhttp_connection_get_addr() (4dd500c
+ Azat Khuzhin)
+ o Update to the latest version of tinytest (7a80476)
+ o Heap-allocate zlib data structure in regress_zlib tests (4947c18)
+
+ Performance tweaks (core)
+ o Avoid redundant syscall to make a nonblocking socket nonblocking
+ (42c03da Maxime Henrion)
+ o Avoid redundant syscall if making a socket cloexec twice (1f29b18)
+ o Avoid redundant invocations of init_extension_functions for IOCP (3b77d62)
+
+ Documentation
+ o Document that arc4random is not a great cryptographic PRNG. (6e49696)
+ o Small doxygen tweaks (6e67b51)
+ o Try another doxygen tweak (ccf432b)
+ o Clarify event_base_loop exit conditions (031a803)
+ o Fix a typo (be7bf2c Ondřej Kuzník)
+ o Document deferred eventcb behaviour (13a9a02 Ondřej Kuzník)
+ o Typo fixes from Linus Nordberg (cec62cb, 8cd695b)
+ o Fix duplicate paragraph in evbuffer_ptr documentation (58408ee)
+
+ Code Improvements (coverity)
+ o Fix a pile of coverity warnings in the unit tests (867f401)
+ o Fix coverity warnings in benchmark tools. (ff7f739)
+ o Whoops; fix compilation in bench.c (544cf88)
+ o Remove spurious checks in evrpc.c error cases (coverity) (991b362)
+ o Fix a couple of compilation warnings in regress_http.c (860767e)
+ o Fix even more coverity warnings. (d240328)
+ o Stop checking for inet_aton; we don't use it. (f665d5c)
+ o Add an include to evrpc-internal to fix openbsd compilation warning
+ (5e161c6)
+
+ Cleanups
+ o Remove an unreachable return statement in minheap-internal.h (e639a9e)
+ o Refactor evmap_{io,signal}_active_() to tolerate bad inputs (974c60e)
+ o Fix needless bufferevent includes in evdns.c (254c04e)
+ o Fix a couple of "#ifdef WIN32" instances (88ecda3)
+ o Remove unneeded declaration in bufferevent-internal.h (4c8ebcd)
+
+ Sample code
+ o le-proxy: Fail more gracefully if opening listener fails (44b2491)
+ o http-server: drop uri_root from base_url in http-server. (6171e1c Azat Khuzhin)
+ o https-client: POST supported, args supported (c5887f7 Alexey Ozeritsky)
+ o https-client: code cleanup (29af65e Alexey Ozeritsky)
+ o https-client: Small tweaks to https-client.c (90786eb)
+ o https-client: Set hostname for SNI extension (by f69m) (d1976f8)
+ o https-client: add a cast to https-client.c (462e6b6)
diff --git a/Makefile.am b/Makefile.am
index 576a0acd..e2ce2928 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -38,7 +38,7 @@ RELEASE = -release 2.1
#
# Once an RC is out, DO NOT MAKE ANY ABI-BREAKING CHANGES IN THAT SERIES
# UNLESS YOU REALLY REALLY HAVE TO.
-VERSION_INFO = 3:0:0
+VERSION_INFO = 4:0:0
# History: RELEASE VERSION_INFO
# 2.0.1-alpha -- 2.0 1:0:0
@@ -67,6 +67,7 @@ VERSION_INFO = 3:0:0
# 2.1.1-alpha -- 2.1 1:0:0
# 2.1.2-alpha -- 2.1 1:0:0 (should have been 2:0:1)
# 2.1.3-alpha -- 2.1 3:0:0 (ABI changed slightly)
+# 2.1.4-alpha -- 2.1 4:0:0 (ABI changed slightly)
# ABI version history for this package effectively restarts every time
# we change RELEASE. Version 1.4.x had RELEASE of 1.4.
@@ -146,7 +147,7 @@ if BUILD_WIN32
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
+SYS_INCLUDES = -IWIN32-Code -IWIN32-Code/nmake
else
@@ -247,13 +248,14 @@ libevent_openssl_la_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_INCS)
endif
noinst_HEADERS += \
- WIN32-Code/evconfig-private.h \
- WIN32-Code/event2/event-config.h \
+ WIN32-Code/nmake/evconfig-private.h \
+ WIN32-Code/nmake/event2/event-config.h \
WIN32-Code/tree.h \
bufferevent-internal.h \
changelist-internal.h \
compat/sys/queue.h \
defer-internal.h \
+ epolltable-internal.h \
evbuffer-internal.h \
evconfig-private.h \
event-internal.h \
diff --git a/Makefile.nmake b/Makefile.nmake
index 39efbc91..f27cd619 100644
--- a/Makefile.nmake
+++ b/Makefile.nmake
@@ -20,7 +20,7 @@ SSL_CFLAGS=
!ENDIF
# Needed for correctness
-CFLAGS=/IWIN32-Code /Iinclude /Icompat /DHAVE_CONFIG_H /I. $(SSL_CFLAGS)
+CFLAGS=/IWIN32-Code /IWIN32-Code/nmake /Iinclude /Icompat /DHAVE_CONFIG_H /I. $(SSL_CFLAGS)
# For optimization and warnings
CFLAGS=$(CFLAGS) /Ox /W3 /wd4996 /nologo
diff --git a/README b/README
deleted file mode 100644
index 3dfa10a3..00000000
--- a/README
+++ /dev/null
@@ -1,225 +0,0 @@
-0. BUILDING AND INSTALLATION (Briefly)
-
-$ ./configure
-$ make
-$ make verify # (optional)
-$ sudo make install
-
-1. BUILDING AND INSTALLATION (In Depth)
-
-To build libevent, type
-
-$ ./configure && make
-
- (If you got libevent from the git repository, you will
- first need to run the included "autogen.sh" script in order to
- generate the configure script.)
-
-You can run the regression tests by running
-
-$ make verify
-
-Install as root via
-
-# make install
-
-Before reporting any problems, please run the regression tests.
-
-To enable the low-level tracing build the library as:
-
- CFLAGS=-DUSE_DEBUG ./configure [...]
-
-Standard configure flags should work. In particular, see:
-
- --disable-shared Only build static libraries
- --prefix Install all files relative to this directory.
-
-
-The configure script also supports the following flags:
-
- --enable-gcc-warnings Enable extra compiler checking with GCC.
- --disable-malloc-replacement
- Don't let applications replace our memory
- management functions
- --disable-openssl Disable support for OpenSSL encryption.
- --disable-thread-support Don't support multithreaded environments.
-
-2. USEFUL LINKS:
-
-For the latest released version of Libevent, see the official website at
-http://libevent.org/ .
-
-There's a pretty good work-in-progress manual up at
- http://www.wangafu.net/~nickm/libevent-book/ .
-
-For the latest development versions of Libevent, access our Git repository
-via
- "git clone git://levent.git.sourceforge.net/gitroot/levent/libevent"
-
-You can browse the git repository online at
-http://levent.git.sourceforge.net/git/gitweb-index.cgi .
-
-To report bugs, request features, or submit patches to Libevent,
-use the Sourceforge trackers at
-https://sourceforge.net/tracker/?group_id=50884 .
-
-There's also a libevent-users mailing list for talking about Libevent
-use and development: http://archives.seul.org/libevent/users/
-
-3. ACKNOWLEDGMENTS
-
-The following people have helped with suggestions, ideas, code or
-fixing bugs:
-
- Samy Al Bahra
- Jacob Appelbaum
- Arno Bakker
- Weston Andros Adamson
- William Ahern
- Ivan Andropov
- Sergey Avseyev
- Avi Bab
- Joachim Bauch
- Gilad Benjamini
- Stas Bekman
- Denis Bilenko
- Julien Blache
- Kevin Bowling
- Tomash Brechko
- Kelly Brock
- Ralph Castain
- Adrian Chadd
- Lawnstein Chan
- Shuo Chen
- Ka-Hing Cheung
- Andrew Cox
- Paul Croome
- George Danchev
- Andrew Danforth
- Ed Day
- Christopher Davis
- Mike Davis
- Antony Dovgal
- Mihai Draghicioiu
- Alexander Drozdov
- Mark Ellzey
- Shie Erlich
- Leonid Evdokimov
- Juan Pablo Fernandez
- Christophe Fillot
- Mike Frysinger
- Remi Gacogne
- Artem Germanov
- Alexander von Gernler
- Artur Grabowski
- Diwaker Gupta
- Sebastian Hahn
- Dave Hart
- Greg Hazel
- Nicholas Heath
- Michael Herf
- Sebastian Hahn
- Savg He
- Mark Heily
- Maxime Henrion
- Michael Herf
- Greg Hewgill
- Andrew Hochhaus
- Aaron Hopkins
- Tani Hosokawa
- Jamie Iles
- Xiuqiang Jiang
- Claudio Jeker
- Evan Jones
- George Kadianakis
- Phua Keat
- Azat Khuzhin
- Alexander Klauer
- Kevin Ko
- Brian Koehmstedt
- Marko Kreen
- Valery Kyholodov
- Ross Lagerwall
- Scott Lamb
- Christopher Layne
- Adam Langley
- Graham Leggett
- Volker Lendecke
- Philip Lewis
- Zhou Li
- David Libenzi
- Yan Lin
- Moshe Litvin
- Simon Liu
- Mitchell Livingston
- Hagne Mahre
- Lubomir Marinov
- Abilio Marques
- Abel Mathew
- Nick Mathewson
- James Mansion
- Nicholas Marriott
- Andrey Matveev
- Caitlin Mercer
- Dagobert Michelsen
- Andrea Montefusco
- Mansour Moufid
- Mina Naguib
- Felix Nawothnig
- Trond Norbye
- Linus Nordberg
- Richard Nyberg
- Jon Oberheide
- Phil Oleson
- Dave Pacheco
- Derrick Pallas
- Tassilo von Parseval
- Catalin Patulea
- Patrick Pelletier
- Simon Perreault
- Dan Petro
- Pierre Phaneuf
- Amarin Phaosawasdi
- Ryan Phillips
- Dimitre Piskyulev
- Pavel Plesov
- Jon Poland
- Roman Puls
- Nate R
- Robert Ransom
- Bert JW Regeer
- Nate Rosenblum
- Peter Rosin
- Maseeb Abdul Qadir
- Wang Qin
- Alex S
- Gyepi Sam
- Hanna Schroeter
- Ralf Schmitt
- Mike Smellie
- Kevin Springborn
- Nir Soffer
- Harlan Stenn
- Steve Snyder
- Dug Song
- Dongsheng Song
- Hannes Sowa
- Ferenc Szalai
- Brodie Thiesfield
- Jason Toffaletti
- Gisle Vanem
- Bas Verhoeven
- Constantine Verutin
- Colin Watt
- Zack Weinberg
- Jardel Weyrich
- Jay R. Wren
- Zack Weinberg
- Alejo
- Alex
- Taral
- propanbutan
- mmadia
- yangacer
-
-If we have forgotten your name, please contact us.
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..a7c82b01
--- /dev/null
+++ b/README.md
@@ -0,0 +1,318 @@
+# 0. BUILDING AND INSTALLATION (Briefly)
+
+## Autoconf
+
+ $ ./configure
+ $ make
+ $ make verify # (optional)
+ $ sudo make install
+
+## CMake (Windows)
+
+Install CMake: <http://www.cmake.org>
+
+
+ $ md build && cd build
+ $ cmake -G "Visual Studio 10" .. # Or whatever generator you want to use cmake --help for a list.
+ $ start libevent.sln
+
+## CMake (Unix)
+
+ $ mkdir build && cd build
+ $ cmake .. # Default to Unix Makefiles.
+ $ make
+ $ make verify # (optional)
+
+
+# 1. BUILDING AND INSTALLATION (In Depth)
+
+## Autoconf
+
+To build libevent, type
+
+ $ ./configure && make
+
+
+ (If you got libevent from the git repository, you will
+ first need to run the included "autogen.sh" script in order to
+ generate the configure script.)
+
+You can run the regression tests by running
+
+ $ make verify
+
+Install as root via
+
+ $ make install
+
+Before reporting any problems, please run the regression tests.
+
+To enable the low-level tracing build the library as:
+
+ $ CFLAGS=-DUSE_DEBUG ./configure [...]
+
+Standard configure flags should work. In particular, see:
+
+ --disable-shared Only build static libraries
+ --prefix Install all files relative to this directory.
+
+
+The configure script also supports the following flags:
+
+ --enable-gcc-warnings Enable extra compiler checking with GCC.
+ --disable-malloc-replacement
+ Don't let applications replace our memory
+ management functions
+ --disable-openssl Disable support for OpenSSL encryption.
+ --disable-thread-support Don't support multithreaded environments.
+
+## CMake (Windows)
+
+(Note that autoconf is currently the most mature and supported build
+enviroment for libevent; the cmake instructions here are new and
+experimental, though they _should_ be solid. We hope that cmake will
+still be supported in future versions of Libevent, and will try to
+make sure that happens.)
+
+First of all install <http://www.cmake.org>.
+
+To build libevent using Microsoft Visual studio open the "Visual Studio Command prompt" and type:
+
+```
+$ cd <libevent source dir>
+$ mkdir build && cd build
+$ cmake -G "Visual Studio 10" .. # Or whatever generator you want to use cmake --help for a list.
+$ start libevent.sln
+```
+
+In the above, the ".." refers to the dir containing the Libevent source code.
+You can build multiple versions (with different compile time settings) from the same source tree
+by creating other build directories.
+
+It is highly recommended to build "out of source" when using
+CMake instead of "in source" like the normal behaviour of autoconf for this reason.
+
+The "NMake Makefiles" CMake generator can be used to build entirely via the command line.
+
+To get a list of settings available for the project you can type:
+
+```
+$ cmake -LH ..
+```
+
+### GUI
+
+CMake also provides a GUI that lets you specify the source directory and output (binary) directory
+that the build should be placed in.
+
+### OpenSSL support
+
+To build Libevent with OpenSSL support you will need to have OpenSSL binaries available when building,
+these can be found here: <http://www.openssl.org/related/binaries.html>
+
+# 2. USEFUL LINKS:
+
+For the latest released version of Libevent, see the official website at
+<http://libevent.org/> .
+
+There's a pretty good work-in-progress manual up at
+ <http://www.wangafu.net/~nickm/libevent-book/> .
+
+For the latest development versions of Libevent, access our Git repository
+via
+
+```
+$ git clone git://levent.git.sourceforge.net/gitroot/levent/libevent
+```
+
+You can browse the git repository online at:
+
+<http://levent.git.sourceforge.net/git/gitweb-index.cgi>
+
+<https://github.com/libevent/Libevent>
+
+To report bugs, request features, or submit patches to Libevent,
+use the Sourceforge trackers at
+
+<https://sourceforge.net/tracker/?group_id=50884>
+
+There's also a libevent-users mailing list for talking about Libevent
+use and development:
+
+<http://archives.seul.org/libevent/users/>
+
+# 3. ACKNOWLEDGMENTS
+
+The following people have helped with suggestions, ideas, code or
+fixing bugs:
+
+ * Samy Al Bahra
+ * Antony Antony
+ * Jacob Appelbaum
+ * Arno Bakker
+ * Weston Andros Adamson
+ * William Ahern
+ * Ivan Andropov
+ * Sergey Avseyev
+ * Avi Bab
+ * Joachim Bauch
+ * Andrey Belobrov
+ * Gilad Benjamini
+ * Stas Bekman
+ * Denis Bilenko
+ * Julien Blache
+ * Kevin Bowling
+ * Tomash Brechko
+ * Kelly Brock
+ * Ralph Castain
+ * Adrian Chadd
+ * Lawnstein Chan
+ * Shuo Chen
+ * Ka-Hing Cheung
+ * Andrew Cox
+ * Paul Croome
+ * George Danchev
+ * Andrew Danforth
+ * Ed Day
+ * Christopher Davis
+ * Mike Davis
+ * Frank Denis
+ * Antony Dovgal
+ * Mihai Draghicioiu
+ * Alexander Drozdov
+ * Mark Ellzey
+ * Shie Erlich
+ * Leonid Evdokimov
+ * Juan Pablo Fernandez
+ * Christophe Fillot
+ * Mike Frysinger
+ * Remi Gacogne
+ * Artem Germanov
+ * Alexander von Gernler
+ * Diego Giagio
+ * Artur Grabowski
+ * Diwaker Gupta
+ * Kuldeep Gupta
+ * Sebastian Hahn
+ * Dave Hart
+ * Greg Hazel
+ * Nicholas Heath
+ * Michael Herf
+ * Sebastian Hahn
+ * Savg He
+ * Mark Heily
+ * Maxime Henrion
+ * Michael Herf
+ * Greg Hewgill
+ * Andrew Hochhaus
+ * Aaron Hopkins
+ * Tani Hosokawa
+ * Jamie Iles
+ * Xiuqiang Jiang
+ * Claudio Jeker
+ * Evan Jones
+ * Marcin Juszkiewicz
+ * George Kadianakis
+ * Makoto Kato
+ * Phua Keat
+ * Azat Khuzhin
+ * Alexander Klauer
+ * Kevin Ko
+ * Brian Koehmstedt
+ * Marko Kreen
+ * Ondřej Kuzník
+ * Valery Kyholodov
+ * Ross Lagerwall
+ * Scott Lamb
+ * Christopher Layne
+ * Adam Langley
+ * Graham Leggett
+ * Volker Lendecke
+ * Philip Lewis
+ * Zhou Li
+ * David Libenzi
+ * Yan Lin
+ * Moshe Litvin
+ * Simon Liu
+ * Mitchell Livingston
+ * Hagne Mahre
+ * Lubomir Marinov
+ * Abilio Marques
+ * Nicolas Martyanoff
+ * Abel Mathew
+ * Nick Mathewson
+ * James Mansion
+ * Nicholas Marriott
+ * Andrey Matveev
+ * Caitlin Mercer
+ * Dagobert Michelsen
+ * Andrea Montefusco
+ * Mansour Moufid
+ * Mina Naguib
+ * Felix Nawothnig
+ * Trond Norbye
+ * Linus Nordberg
+ * Richard Nyberg
+ * Jon Oberheide
+ * John Ohl
+ * Phil Oleson
+ * Alexey Ozeritsky
+ * Dave Pacheco
+ * Derrick Pallas
+ * Tassilo von Parseval
+ * Catalin Patulea
+ * Patrick Pelletier
+ * Simon Perreault
+ * Dan Petro
+ * Pierre Phaneuf
+ * Amarin Phaosawasdi
+ * Ryan Phillips
+ * Dimitre Piskyulev
+ * Pavel Plesov
+ * Jon Poland
+ * Roman Puls
+ * Nate R
+ * Robert Ransom
+ * Balint Reczey
+ * Bert JW Regeer
+ * Nate Rosenblum
+ * Peter Rosin
+ * Maseeb Abdul Qadir
+ * Wang Qin
+ * Alex S
+ * Gyepi Sam
+ * Hanna Schroeter
+ * Ralf Schmitt
+ * Mike Smellie
+ * Steve Snyder
+ * Nir Soffer
+ * Dug Song
+ * Dongsheng Song
+ * Hannes Sowa
+ * Joakim Soderberg
+ * Joseph Spadavecchia
+ * Kevin Springborn
+ * Harlan Stenn
+ * Andrew Sweeney
+ * Ferenc Szalai
+ * Brodie Thiesfield
+ * Jason Toffaletti
+ * Brian Utterback
+ * Gisle Vanem
+ * Bas Verhoeven
+ * Constantine Verutin
+ * Colin Watt
+ * Zack Weinberg
+ * Jardel Weyrich
+ * Jay R. Wren
+ * Zack Weinberg
+ * Mobai Zhang
+ * Alejo
+ * Alex
+ * Taral
+ * propanbutan
+ * masksqwe
+ * mmadia
+ * yangacer
+
+If we have forgotten your name, please contact us.
diff --git a/WIN32-Code/getopt.c b/WIN32-Code/getopt.c
new file mode 100644
index 00000000..0fcba5d9
--- /dev/null
+++ b/WIN32-Code/getopt.c
@@ -0,0 +1,149 @@
+/* $NetBSD: getopt.c,v 1.16 1999/12/02 13:15:56 kleink Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if 0
+static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#define __P(x) x
+#define _DIAGASSERT(x) assert(x)
+
+#ifdef __weak_alias
+__weak_alias(getopt,_getopt);
+#endif
+
+
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt, /* character checked for validity */
+ optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+
+static char * _progname __P((char *));
+int getopt_internal __P((int, char * const *, const char *));
+
+static char *
+_progname(nargv0)
+ char * nargv0;
+{
+ char * tmp;
+
+ _DIAGASSERT(nargv0 != NULL);
+
+ tmp = strrchr(nargv0, '/');
+ if (tmp)
+ tmp++;
+ else
+ tmp = nargv0;
+ return(tmp);
+}
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt(nargc, nargv, ostr)
+ int nargc;
+ char * const nargv[];
+ const char *ostr;
+{
+ static char *__progname = 0;
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+ __progname = __progname?__progname:_progname(*nargv);
+
+ _DIAGASSERT(nargv != NULL);
+ _DIAGASSERT(ostr != NULL);
+
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc || *(place = nargv[optind]) != '-') {
+ place = EMSG;
+ return (-1);
+ }
+ if (place[1] && *++place == '-' /* found "--" */
+ && place[1] == '\0') {
+ ++optind;
+ place = EMSG;
+ return (-1);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1.
+ */
+ if (optopt == (int)'-')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", __progname, optopt);
+ return (BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ }
+ else { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if (opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ __progname, optopt);
+ return (BADCH);
+ }
+ else /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* dump back option letter */
+}
+
diff --git a/WIN32-Code/getopt.h b/WIN32-Code/getopt.h
new file mode 100644
index 00000000..796f4550
--- /dev/null
+++ b/WIN32-Code/getopt.h
@@ -0,0 +1,33 @@
+#ifndef __GETOPT_H__
+#define __GETOPT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int opterr; /* if error message should be printed */
+extern int optind; /* index into parent argv vector */
+extern int optopt; /* character checked for validity */
+extern int optreset; /* reset getopt */
+extern char *optarg; /* argument associated with option */
+
+struct option
+{
+ const char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+int getopt(int, char**, const char*);
+int getopt_long(int, char**, const char*, const struct option*, int*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GETOPT_H__ */
diff --git a/WIN32-Code/getopt_long.c b/WIN32-Code/getopt_long.c
new file mode 100644
index 00000000..03f0c01a
--- /dev/null
+++ b/WIN32-Code/getopt_long.c
@@ -0,0 +1,233 @@
+
+/*
+ * Copyright (c) 1987, 1993, 1994, 1996
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "getopt.h"
+
+extern int opterr; /* if error message should be printed */
+extern int optind; /* index into parent argv vector */
+extern int optopt; /* character checked for validity */
+extern int optreset; /* reset getopt */
+extern char *optarg; /* argument associated with option */
+
+#define __P(x) x
+#define _DIAGASSERT(x) assert(x)
+
+static char * __progname __P((char *));
+int getopt_internal __P((int, char * const *, const char *));
+
+static char *
+__progname(nargv0)
+ char * nargv0;
+{
+ char * tmp;
+
+ _DIAGASSERT(nargv0 != NULL);
+
+ tmp = strrchr(nargv0, '/');
+ if (tmp)
+ tmp++;
+ else
+ tmp = nargv0;
+ return(tmp);
+}
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_internal(nargc, nargv, ostr)
+ int nargc;
+ char * const *nargv;
+ const char *ostr;
+{
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+
+ _DIAGASSERT(nargv != NULL);
+ _DIAGASSERT(ostr != NULL);
+
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc || *(place = nargv[optind]) != '-') {
+ place = EMSG;
+ return (-1);
+ }
+ if (place[1] && *++place == '-') { /* found "--" */
+ /* ++optind; */
+ place = EMSG;
+ return (-2);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1.
+ */
+ if (optopt == (int)'-')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", __progname(nargv[0]), optopt);
+ return (BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ } else { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ if ((opterr) && (*ostr != ':'))
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ __progname(nargv[0]), optopt);
+ return (BADARG);
+ } else /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* dump back option letter */
+}
+
+#if 0
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt2(nargc, nargv, ostr)
+ int nargc;
+ char * const *nargv;
+ const char *ostr;
+{
+ int retval;
+
+ if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) {
+ retval = -1;
+ ++optind;
+ }
+ return(retval);
+}
+#endif
+
+/*
+ * getopt_long --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long(nargc, nargv, options, long_options, index)
+ int nargc;
+ char ** nargv;
+ const char * options;
+ const struct option * long_options;
+ int * index;
+{
+ int retval;
+
+ _DIAGASSERT(nargv != NULL);
+ _DIAGASSERT(options != NULL);
+ _DIAGASSERT(long_options != NULL);
+ /* index may be NULL */
+
+ if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
+ char *current_argv = nargv[optind++] + 2, *has_equal;
+ int i, current_argv_len, match = -1;
+
+ if (*current_argv == '\0') {
+ return(-1);
+ }
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {
+ current_argv_len = has_equal - current_argv;
+ has_equal++;
+ } else
+ current_argv_len = strlen(current_argv);
+
+ for (i = 0; long_options[i].name; i++) {
+ if (strncmp(current_argv, long_options[i].name, current_argv_len))
+ continue;
+
+ if (strlen(long_options[i].name) == (unsigned)current_argv_len) {
+ match = i;
+ break;
+ }
+ if (match == -1)
+ match = i;
+ }
+ if (match != -1) {
+ if (long_options[match].has_arg == required_argument ||
+ long_options[match].has_arg == optional_argument) {
+ if (has_equal)
+ optarg = has_equal;
+ else
+ optarg = nargv[optind++];
+ }
+ if ((long_options[match].has_arg == required_argument)
+ && (optarg == NULL)) {
+ /*
+ * Missing argument, leading :
+ * indicates no error should be generated
+ */
+ if ((opterr) && (*options != ':'))
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %s\n",
+ __progname(nargv[0]), current_argv);
+ return (BADARG);
+ }
+ } else { /* No matching argument */
+ if ((opterr) && (*options != ':'))
+ (void)fprintf(stderr,
+ "%s: illegal option -- %s\n", __progname(nargv[0]), current_argv);
+ return (BADCH);
+ }
+ if (long_options[match].flag) {
+ *long_options[match].flag = long_options[match].val;
+ retval = 0;
+ } else
+ retval = long_options[match].val;
+ if (index)
+ *index = match;
+ }
+ return(retval);
+}
diff --git a/WIN32-Code/evconfig-private.h b/WIN32-Code/nmake/evconfig-private.h
index 88e20627..88e20627 100644
--- a/WIN32-Code/evconfig-private.h
+++ b/WIN32-Code/nmake/evconfig-private.h
diff --git a/WIN32-Code/event2/event-config.h b/WIN32-Code/nmake/event2/event-config.h
index 43b5c3fb..5ba2d78e 100644
--- a/WIN32-Code/event2/event-config.h
+++ b/WIN32-Code/nmake/event2/event-config.h
@@ -70,9 +70,6 @@
/* Define to 1 if you have the `gettimeofday' function. */
/* #define EVENT__HAVE_GETTIMEOFDAY 1 */
-/* Define to 1 if you have the `inet_aton' function. */
-/* #undef EVENT__HAVE_INET_ATON */
-
/* Define to 1 if you have the `inet_ntop' function. */
/* #undef EVENT__HAVE_INET_NTOP */
@@ -277,7 +274,7 @@
/* #undef EVENT__HAVE_WORKING_KQUEUE */
/* Numeric representation of the version */
-#define EVENT__NUMERIC_VERSION 0x02010301
+#define EVENT__NUMERIC_VERSION 0x02010401
/* Name of package */
#define EVENT__PACKAGE "libevent"
@@ -334,7 +331,7 @@
#define EVENT__TIME_WITH_SYS_TIME 1
/* Version number of package */
-#define EVENT__VERSION "2.1.3-alpha-dev"
+#define EVENT__VERSION "2.1.4-alpha-dev"
/* Define to appropriate substitue if compiler doesnt have __func__ */
#define EVENT____func__ __FUNCTION__
diff --git a/WIN32-Code/tree.h b/WIN32-Code/tree.h
index 585618dd..2ccfbf20 100644
--- a/WIN32-Code/tree.h
+++ b/WIN32-Code/tree.h
@@ -675,680 +675,3 @@ name##_RB_MINMAX(struct name *head, int val) \
(x) = name##_RB_NEXT(x))
#endif /* _SYS_TREE_H_ */
-/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */
-/*
- * Copyright 2002 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _SYS_TREE_H_
-#define _SYS_TREE_H_
-
-/*
- * This file defines data structures for different types of trees:
- * splay trees and red-black trees.
- *
- * A splay tree is a self-organizing data structure. Every operation
- * on the tree causes a splay to happen. The splay moves the requested
- * node to the root of the tree and partly rebalances it.
- *
- * This has the benefit that request locality causes faster lookups as
- * the requested nodes move to the top of the tree. On the other hand,
- * every lookup causes memory writes.
- *
- * The Balance Theorem bounds the total access time for m operations
- * and n inserts on an initially empty tree as O((m + n)lg n). The
- * amortized cost for a sequence of m accesses to a splay tree is O(lg n);
- *
- * A red-black tree is a binary search tree with the node color as an
- * extra attribute. It fulfills a set of conditions:
- * - every search path from the root to a leaf consists of the
- * same number of black nodes,
- * - each red node (except for the root) has a black parent,
- * - each leaf node is black.
- *
- * Every operation on a red-black tree is bounded as O(lg n).
- * The maximum height of a red-black tree is 2lg (n+1).
- */
-
-#define SPLAY_HEAD(name, type) \
-struct name { \
- struct type *sph_root; /* root of the tree */ \
-}
-
-#define SPLAY_INITIALIZER(root) \
- { NULL }
-
-#define SPLAY_INIT(root) do { \
- (root)->sph_root = NULL; \
-} while (0)
-
-#define SPLAY_ENTRY(type) \
-struct { \
- struct type *spe_left; /* left element */ \
- struct type *spe_right; /* right element */ \
-}
-
-#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
-#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
-#define SPLAY_ROOT(head) (head)->sph_root
-#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
-
-/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
-#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
- SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
- SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
- (head)->sph_root = tmp; \
-} while (0)
-
-#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
- SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
- SPLAY_LEFT(tmp, field) = (head)->sph_root; \
- (head)->sph_root = tmp; \
-} while (0)
-
-#define SPLAY_LINKLEFT(head, tmp, field) do { \
- SPLAY_LEFT(tmp, field) = (head)->sph_root; \
- tmp = (head)->sph_root; \
- (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
-} while (0)
-
-#define SPLAY_LINKRIGHT(head, tmp, field) do { \
- SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
- tmp = (head)->sph_root; \
- (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
-} while (0)
-
-#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
- SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
- SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
- SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
- SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
-} while (0)
-
-/* Generates prototypes and inline functions */
-
-#define SPLAY_PROTOTYPE(name, type, field, cmp) \
-void name##_SPLAY(struct name *, struct type *); \
-void name##_SPLAY_MINMAX(struct name *, int); \
-struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
-struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
- \
-/* Finds the node with the same key as elm */ \
-static __inline struct type * \
-name##_SPLAY_FIND(struct name *head, struct type *elm) \
-{ \
- if (SPLAY_EMPTY(head)) \
- return(NULL); \
- name##_SPLAY(head, elm); \
- if ((cmp)(elm, (head)->sph_root) == 0) \
- return (head->sph_root); \
- return (NULL); \
-} \
- \
-static __inline struct type * \
-name##_SPLAY_NEXT(struct name *head, struct type *elm) \
-{ \
- name##_SPLAY(head, elm); \
- if (SPLAY_RIGHT(elm, field) != NULL) { \
- elm = SPLAY_RIGHT(elm, field); \
- while (SPLAY_LEFT(elm, field) != NULL) { \
- elm = SPLAY_LEFT(elm, field); \
- } \
- } else \
- elm = NULL; \
- return (elm); \
-} \
- \
-static __inline struct type * \
-name##_SPLAY_MIN_MAX(struct name *head, int val) \
-{ \
- name##_SPLAY_MINMAX(head, val); \
- return (SPLAY_ROOT(head)); \
-}
-
-/* Main splay operation.
- * Moves node close to the key of elm to top
- */
-#define SPLAY_GENERATE(name, type, field, cmp) \
-struct type * \
-name##_SPLAY_INSERT(struct name *head, struct type *elm) \
-{ \
- if (SPLAY_EMPTY(head)) { \
- SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
- } else { \
- int __comp; \
- name##_SPLAY(head, elm); \
- __comp = (cmp)(elm, (head)->sph_root); \
- if(__comp < 0) { \
- SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
- SPLAY_RIGHT(elm, field) = (head)->sph_root; \
- SPLAY_LEFT((head)->sph_root, field) = NULL; \
- } else if (__comp > 0) { \
- SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
- SPLAY_LEFT(elm, field) = (head)->sph_root; \
- SPLAY_RIGHT((head)->sph_root, field) = NULL; \
- } else \
- return ((head)->sph_root); \
- } \
- (head)->sph_root = (elm); \
- return (NULL); \
-} \
- \
-struct type * \
-name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
-{ \
- struct type *__tmp; \
- if (SPLAY_EMPTY(head)) \
- return (NULL); \
- name##_SPLAY(head, elm); \
- if ((cmp)(elm, (head)->sph_root) == 0) { \
- if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
- (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
- } else { \
- __tmp = SPLAY_RIGHT((head)->sph_root, field); \
- (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
- name##_SPLAY(head, elm); \
- SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
- } \
- return (elm); \
- } \
- return (NULL); \
-} \
- \
-void \
-name##_SPLAY(struct name *head, struct type *elm) \
-{ \
- struct type __node, *__left, *__right, *__tmp; \
- int __comp; \
-\
- SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
- __left = __right = &__node; \
-\
- while ((__comp = (cmp)(elm, (head)->sph_root))) { \
- if (__comp < 0) { \
- __tmp = SPLAY_LEFT((head)->sph_root, field); \
- if (__tmp == NULL) \
- break; \
- if ((cmp)(elm, __tmp) < 0){ \
- SPLAY_ROTATE_RIGHT(head, __tmp, field); \
- if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
- break; \
- } \
- SPLAY_LINKLEFT(head, __right, field); \
- } else if (__comp > 0) { \
- __tmp = SPLAY_RIGHT((head)->sph_root, field); \
- if (__tmp == NULL) \
- break; \
- if ((cmp)(elm, __tmp) > 0){ \
- SPLAY_ROTATE_LEFT(head, __tmp, field); \
- if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
- break; \
- } \
- SPLAY_LINKRIGHT(head, __left, field); \
- } \
- } \
- SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
-} \
- \
-/* Splay with either the minimum or the maximum element \
- * Used to find minimum or maximum element in tree. \
- */ \
-void name##_SPLAY_MINMAX(struct name *head, int __comp) \
-{ \
- struct type __node, *__left, *__right, *__tmp; \
-\
- SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
- __left = __right = &__node; \
-\
- while (1) { \
- if (__comp < 0) { \
- __tmp = SPLAY_LEFT((head)->sph_root, field); \
- if (__tmp == NULL) \
- break; \
- if (__comp < 0){ \
- SPLAY_ROTATE_RIGHT(head, __tmp, field); \
- if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
- break; \
- } \
- SPLAY_LINKLEFT(head, __right, field); \
- } else if (__comp > 0) { \
- __tmp = SPLAY_RIGHT((head)->sph_root, field); \
- if (__tmp == NULL) \
- break; \
- if (__comp > 0) { \
- SPLAY_ROTATE_LEFT(head, __tmp, field); \
- if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
- break; \
- } \
- SPLAY_LINKRIGHT(head, __left, field); \
- } \
- } \
- SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
-}
-
-#define SPLAY_NEGINF -1
-#define SPLAY_INF 1
-
-#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
-#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
-#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
-#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
-#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
- : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
-#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
- : name##_SPLAY_MIN_MAX(x, SPLAY_INF))
-
-#define SPLAY_FOREACH(x, name, head) \
- for ((x) = SPLAY_MIN(name, head); \
- (x) != NULL; \
- (x) = SPLAY_NEXT(name, head, x))
-
-/* Macros that define a red-back tree */
-#define RB_HEAD(name, type) \
-struct name { \
- struct type *rbh_root; /* root of the tree */ \
-}
-
-#define RB_INITIALIZER(root) \
- { NULL }
-
-#define RB_INIT(root) do { \
- (root)->rbh_root = NULL; \
-} while (0)
-
-#define RB_BLACK 0
-#define RB_RED 1
-#define RB_ENTRY(type) \
-struct { \
- struct type *rbe_left; /* left element */ \
- struct type *rbe_right; /* right element */ \
- struct type *rbe_parent; /* parent element */ \
- int rbe_color; /* node color */ \
-}
-
-#define RB_LEFT(elm, field) (elm)->field.rbe_left
-#define RB_RIGHT(elm, field) (elm)->field.rbe_right
-#define RB_PARENT(elm, field) (elm)->field.rbe_parent
-#define RB_COLOR(elm, field) (elm)->field.rbe_color
-#define RB_ROOT(head) (head)->rbh_root
-#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
-
-#define RB_SET(elm, parent, field) do { \
- RB_PARENT(elm, field) = parent; \
- RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
- RB_COLOR(elm, field) = RB_RED; \
-} while (0)
-
-#define RB_SET_BLACKRED(black, red, field) do { \
- RB_COLOR(black, field) = RB_BLACK; \
- RB_COLOR(red, field) = RB_RED; \
-} while (0)
-
-#ifndef RB_AUGMENT
-#define RB_AUGMENT(x)
-#endif
-
-#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
- (tmp) = RB_RIGHT(elm, field); \
- if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \
- RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
- } \
- RB_AUGMENT(elm); \
- if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
- if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
- RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
- else \
- RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
- } else \
- (head)->rbh_root = (tmp); \
- RB_LEFT(tmp, field) = (elm); \
- RB_PARENT(elm, field) = (tmp); \
- RB_AUGMENT(tmp); \
- if ((RB_PARENT(tmp, field))) \
- RB_AUGMENT(RB_PARENT(tmp, field)); \
-} while (0)
-
-#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
- (tmp) = RB_LEFT(elm, field); \
- if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \
- RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
- } \
- RB_AUGMENT(elm); \
- if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
- if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
- RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
- else \
- RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
- } else \
- (head)->rbh_root = (tmp); \
- RB_RIGHT(tmp, field) = (elm); \
- RB_PARENT(elm, field) = (tmp); \
- RB_AUGMENT(tmp); \
- if ((RB_PARENT(tmp, field))) \
- RB_AUGMENT(RB_PARENT(tmp, field)); \
-} while (0)
-
-/* Generates prototypes and inline functions */
-#define RB_PROTOTYPE(name, type, field, cmp) \
-void name##_RB_INSERT_COLOR(struct name *, struct type *); \
-void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
-struct type *name##_RB_REMOVE(struct name *, struct type *); \
-struct type *name##_RB_INSERT(struct name *, struct type *); \
-struct type *name##_RB_FIND(struct name *, struct type *); \
-struct type *name##_RB_NEXT(struct type *); \
-struct type *name##_RB_MINMAX(struct name *, int); \
- \
-
-/* Main rb operation.
- * Moves node close to the key of elm to top
- */
-#define RB_GENERATE(name, type, field, cmp) \
-void \
-name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
-{ \
- struct type *parent, *gparent, *tmp; \
- while ((parent = RB_PARENT(elm, field)) && \
- RB_COLOR(parent, field) == RB_RED) { \
- gparent = RB_PARENT(parent, field); \
- if (parent == RB_LEFT(gparent, field)) { \
- tmp = RB_RIGHT(gparent, field); \
- if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
- RB_COLOR(tmp, field) = RB_BLACK; \
- RB_SET_BLACKRED(parent, gparent, field);\
- elm = gparent; \
- continue; \
- } \
- if (RB_RIGHT(parent, field) == elm) { \
- RB_ROTATE_LEFT(head, parent, tmp, field);\
- tmp = parent; \
- parent = elm; \
- elm = tmp; \
- } \
- RB_SET_BLACKRED(parent, gparent, field); \
- RB_ROTATE_RIGHT(head, gparent, tmp, field); \
- } else { \
- tmp = RB_LEFT(gparent, field); \
- if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
- RB_COLOR(tmp, field) = RB_BLACK; \
- RB_SET_BLACKRED(parent, gparent, field);\
- elm = gparent; \
- continue; \
- } \
- if (RB_LEFT(parent, field) == elm) { \
- RB_ROTATE_RIGHT(head, parent, tmp, field);\
- tmp = parent; \
- parent = elm; \
- elm = tmp; \
- } \
- RB_SET_BLACKRED(parent, gparent, field); \
- RB_ROTATE_LEFT(head, gparent, tmp, field); \
- } \
- } \
- RB_COLOR(head->rbh_root, field) = RB_BLACK; \
-} \
- \
-void \
-name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
-{ \
- struct type *tmp; \
- while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
- elm != RB_ROOT(head)) { \
- if (RB_LEFT(parent, field) == elm) { \
- tmp = RB_RIGHT(parent, field); \
- if (RB_COLOR(tmp, field) == RB_RED) { \
- RB_SET_BLACKRED(tmp, parent, field); \
- RB_ROTATE_LEFT(head, parent, tmp, field);\
- tmp = RB_RIGHT(parent, field); \
- } \
- if ((RB_LEFT(tmp, field) == NULL || \
- RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
- (RB_RIGHT(tmp, field) == NULL || \
- RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
- RB_COLOR(tmp, field) = RB_RED; \
- elm = parent; \
- parent = RB_PARENT(elm, field); \
- } else { \
- if (RB_RIGHT(tmp, field) == NULL || \
- RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
- struct type *oleft; \
- if ((oleft = RB_LEFT(tmp, field)))\
- RB_COLOR(oleft, field) = RB_BLACK;\
- RB_COLOR(tmp, field) = RB_RED; \
- RB_ROTATE_RIGHT(head, tmp, oleft, field);\
- tmp = RB_RIGHT(parent, field); \
- } \
- RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
- RB_COLOR(parent, field) = RB_BLACK; \
- if (RB_RIGHT(tmp, field)) \
- RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
- RB_ROTATE_LEFT(head, parent, tmp, field);\
- elm = RB_ROOT(head); \
- break; \
- } \
- } else { \
- tmp = RB_LEFT(parent, field); \
- if (RB_COLOR(tmp, field) == RB_RED) { \
- RB_SET_BLACKRED(tmp, parent, field); \
- RB_ROTATE_RIGHT(head, parent, tmp, field);\
- tmp = RB_LEFT(parent, field); \
- } \
- if ((RB_LEFT(tmp, field) == NULL || \
- RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
- (RB_RIGHT(tmp, field) == NULL || \
- RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
- RB_COLOR(tmp, field) = RB_RED; \
- elm = parent; \
- parent = RB_PARENT(elm, field); \
- } else { \
- if (RB_LEFT(tmp, field) == NULL || \
- RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
- struct type *oright; \
- if ((oright = RB_RIGHT(tmp, field)))\
- RB_COLOR(oright, field) = RB_BLACK;\
- RB_COLOR(tmp, field) = RB_RED; \
- RB_ROTATE_LEFT(head, tmp, oright, field);\
- tmp = RB_LEFT(parent, field); \
- } \
- RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
- RB_COLOR(parent, field) = RB_BLACK; \
- if (RB_LEFT(tmp, field)) \
- RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
- RB_ROTATE_RIGHT(head, parent, tmp, field);\
- elm = RB_ROOT(head); \
- break; \
- } \
- } \
- } \
- if (elm) \
- RB_COLOR(elm, field) = RB_BLACK; \
-} \
- \
-struct type * \
-name##_RB_REMOVE(struct name *head, struct type *elm) \
-{ \
- struct type *child, *parent, *old = elm; \
- int color; \
- if (RB_LEFT(elm, field) == NULL) \
- child = RB_RIGHT(elm, field); \
- else if (RB_RIGHT(elm, field) == NULL) \
- child = RB_LEFT(elm, field); \
- else { \
- struct type *left; \
- elm = RB_RIGHT(elm, field); \
- while ((left = RB_LEFT(elm, field))) \
- elm = left; \
- child = RB_RIGHT(elm, field); \
- parent = RB_PARENT(elm, field); \
- color = RB_COLOR(elm, field); \
- if (child) \
- RB_PARENT(child, field) = parent; \
- if (parent) { \
- if (RB_LEFT(parent, field) == elm) \
- RB_LEFT(parent, field) = child; \
- else \
- RB_RIGHT(parent, field) = child; \
- RB_AUGMENT(parent); \
- } else \
- RB_ROOT(head) = child; \
- if (RB_PARENT(elm, field) == old) \
- parent = elm; \
- (elm)->field = (old)->field; \
- if (RB_PARENT(old, field)) { \
- if (RB_LEFT(RB_PARENT(old, field), field) == old)\
- RB_LEFT(RB_PARENT(old, field), field) = elm;\
- else \
- RB_RIGHT(RB_PARENT(old, field), field) = elm;\
- RB_AUGMENT(RB_PARENT(old, field)); \
- } else \
- RB_ROOT(head) = elm; \
- RB_PARENT(RB_LEFT(old, field), field) = elm; \
- if (RB_RIGHT(old, field)) \
- RB_PARENT(RB_RIGHT(old, field), field) = elm; \
- if (parent) { \
- left = parent; \
- do { \
- RB_AUGMENT(left); \
- } while ((left = RB_PARENT(left, field))); \
- } \
- goto color; \
- } \
- parent = RB_PARENT(elm, field); \
- color = RB_COLOR(elm, field); \
- if (child) \
- RB_PARENT(child, field) = parent; \
- if (parent) { \
- if (RB_LEFT(parent, field) == elm) \
- RB_LEFT(parent, field) = child; \
- else \
- RB_RIGHT(parent, field) = child; \
- RB_AUGMENT(parent); \
- } else \
- RB_ROOT(head) = child; \
-color: \
- if (color == RB_BLACK) \
- name##_RB_REMOVE_COLOR(head, parent, child); \
- return (old); \
-} \
- \
-/* Inserts a node into the RB tree */ \
-struct type * \
-name##_RB_INSERT(struct name *head, struct type *elm) \
-{ \
- struct type *tmp; \
- struct type *parent = NULL; \
- int comp = 0; \
- tmp = RB_ROOT(head); \
- while (tmp) { \
- parent = tmp; \
- comp = (cmp)(elm, parent); \
- if (comp < 0) \
- tmp = RB_LEFT(tmp, field); \
- else if (comp > 0) \
- tmp = RB_RIGHT(tmp, field); \
- else \
- return (tmp); \
- } \
- RB_SET(elm, parent, field); \
- if (parent != NULL) { \
- if (comp < 0) \
- RB_LEFT(parent, field) = elm; \
- else \
- RB_RIGHT(parent, field) = elm; \
- RB_AUGMENT(parent); \
- } else \
- RB_ROOT(head) = elm; \
- name##_RB_INSERT_COLOR(head, elm); \
- return (NULL); \
-} \
- \
-/* Finds the node with the same key as elm */ \
-struct type * \
-name##_RB_FIND(struct name *head, struct type *elm) \
-{ \
- struct type *tmp = RB_ROOT(head); \
- int comp; \
- while (tmp) { \
- comp = cmp(elm, tmp); \
- if (comp < 0) \
- tmp = RB_LEFT(tmp, field); \
- else if (comp > 0) \
- tmp = RB_RIGHT(tmp, field); \
- else \
- return (tmp); \
- } \
- return (NULL); \
-} \
- \
-struct type * \
-name##_RB_NEXT(struct type *elm) \
-{ \
- if (RB_RIGHT(elm, field)) { \
- elm = RB_RIGHT(elm, field); \
- while (RB_LEFT(elm, field)) \
- elm = RB_LEFT(elm, field); \
- } else { \
- if (RB_PARENT(elm, field) && \
- (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
- elm = RB_PARENT(elm, field); \
- else { \
- while (RB_PARENT(elm, field) && \
- (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
- elm = RB_PARENT(elm, field); \
- elm = RB_PARENT(elm, field); \
- } \
- } \
- return (elm); \
-} \
- \
-struct type * \
-name##_RB_MINMAX(struct name *head, int val) \
-{ \
- struct type *tmp = RB_ROOT(head); \
- struct type *parent = NULL; \
- while (tmp) { \
- parent = tmp; \
- if (val < 0) \
- tmp = RB_LEFT(tmp, field); \
- else \
- tmp = RB_RIGHT(tmp, field); \
- } \
- return (parent); \
-}
-
-#define RB_NEGINF -1
-#define RB_INF 1
-
-#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
-#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
-#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
-#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
-#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
-#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
-
-#define RB_FOREACH(x, name, head) \
- for ((x) = RB_MIN(name, head); \
- (x) != NULL; \
- (x) = name##_RB_NEXT(x))
-
-#endif /* _SYS_TREE_H_ */
diff --git a/buffer.c b/buffer.c
index e603be86..d76e649e 100644
--- a/buffer.c
+++ b/buffer.c
@@ -2485,9 +2485,11 @@ evbuffer_write_atmost(struct evbuffer *buffer, evutil_socket_t fd,
/* XXX(nickm) Don't disable this code until we know if
* the WSARecv code above works. */
void *p = evbuffer_pullup(buffer, howmuch);
+ EVUTIL_ASSERT(p || !howmuch);
n = send(fd, p, howmuch, 0);
#else
void *p = evbuffer_pullup(buffer, howmuch);
+ EVUTIL_ASSERT(p || !howmuch);
n = write(fd, p, howmuch);
#endif
#ifdef USE_SENDFILE
diff --git a/bufferevent-internal.h b/bufferevent-internal.h
index 0c4df871..134bb337 100644
--- a/bufferevent-internal.h
+++ b/bufferevent-internal.h
@@ -340,14 +340,34 @@ int bufferevent_decref_(struct bufferevent *bufev);
int bufferevent_decref_and_unlock_(struct bufferevent *bufev);
/** Internal: If callbacks are deferred and we have a read callback, schedule
- * a readcb. Otherwise just run the readcb. */
-void bufferevent_run_readcb_(struct bufferevent *bufev);
+ * a readcb. Otherwise just run the readcb. Ignores watermarks. */
+void bufferevent_run_readcb_(struct bufferevent *bufev, int options);
/** Internal: If callbacks are deferred and we have a write callback, schedule
- * a writecb. Otherwise just run the writecb. */
-void bufferevent_run_writecb_(struct bufferevent *bufev);
+ * a writecb. Otherwise just run the writecb. Ignores watermarks. */
+void bufferevent_run_writecb_(struct bufferevent *bufev, int options);
/** Internal: If callbacks are deferred and we have an eventcb, schedule
- * it to run with events "what". Otherwise just run the eventcb. */
-void bufferevent_run_eventcb_(struct bufferevent *bufev, short what);
+ * it to run with events "what". Otherwise just run the eventcb.
+ * See bufferevent_trigger_event for meaning of "options". */
+void bufferevent_run_eventcb_(struct bufferevent *bufev, short what, int options);
+
+/** Internal: Run or schedule (if deferred or options contain
+ * BEV_TRIG_DEFER_CALLBACKS) I/O callbacks specified in iotype.
+ * Must already hold the bufev lock. Honors watermarks unless
+ * BEV_TRIG_IGNORE_WATERMARKS is in options. */
+static inline void bufferevent_trigger_nolock_(struct bufferevent *bufev, short iotype, int options);
+
+/* Making this inline since all of the common-case calls to this function in
+ * libevent use constant arguments. */
+static inline void
+bufferevent_trigger_nolock_(struct bufferevent *bufev, short iotype, int options)
+{
+ if ((iotype & EV_READ) && ((options & BEV_TRIG_IGNORE_WATERMARKS) ||
+ evbuffer_get_length(bufev->input) >= bufev->wm_read.low))
+ bufferevent_run_readcb_(bufev, options);
+ if ((iotype & EV_WRITE) && ((options & BEV_TRIG_IGNORE_WATERMARKS) ||
+ evbuffer_get_length(bufev->output) <= bufev->wm_write.low))
+ bufferevent_run_writecb_(bufev, options);
+}
/** Internal: Add the event 'ev' with timeout tv, unless tv is set to 0, in
* which case add ev with no timeout. */
diff --git a/bufferevent.c b/bufferevent.c
index 3cd1ba62..588461a3 100644
--- a/bufferevent.c
+++ b/bufferevent.c
@@ -219,14 +219,14 @@ bufferevent_run_deferred_callbacks_unlocked(struct event_callback *cb, void *arg
void
-bufferevent_run_readcb_(struct bufferevent *bufev)
+bufferevent_run_readcb_(struct bufferevent *bufev, int options)
{
/* Requires that we hold the lock and a reference */
struct bufferevent_private *p =
EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
if (bufev->readcb == NULL)
return;
- if (p->options & BEV_OPT_DEFER_CALLBACKS) {
+ if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) {
p->readcb_pending = 1;
SCHEDULE_DEFERRED(p);
} else {
@@ -235,14 +235,14 @@ bufferevent_run_readcb_(struct bufferevent *bufev)
}
void
-bufferevent_run_writecb_(struct bufferevent *bufev)
+bufferevent_run_writecb_(struct bufferevent *bufev, int options)
{
/* Requires that we hold the lock and a reference */
struct bufferevent_private *p =
EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
if (bufev->writecb == NULL)
return;
- if (p->options & BEV_OPT_DEFER_CALLBACKS) {
+ if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) {
p->writecb_pending = 1;
SCHEDULE_DEFERRED(p);
} else {
@@ -250,15 +250,28 @@ bufferevent_run_writecb_(struct bufferevent *bufev)
}
}
+#define BEV_TRIG_ALL_OPTS ( \
+ BEV_TRIG_IGNORE_WATERMARKS| \
+ BEV_TRIG_DEFER_CALLBACKS \
+ )
+
+void
+bufferevent_trigger(struct bufferevent *bufev, short iotype, int options)
+{
+ bufferevent_incref_and_lock_(bufev);
+ bufferevent_trigger_nolock_(bufev, iotype, options&BEV_TRIG_ALL_OPTS);
+ bufferevent_decref_and_unlock_(bufev);
+}
+
void
-bufferevent_run_eventcb_(struct bufferevent *bufev, short what)
+bufferevent_run_eventcb_(struct bufferevent *bufev, short what, int options)
{
/* Requires that we hold the lock and a reference */
struct bufferevent_private *p =
EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
if (bufev->errorcb == NULL)
return;
- if (p->options & BEV_OPT_DEFER_CALLBACKS) {
+ if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) {
p->eventcb_pending |= what;
p->errno_pending = EVUTIL_SOCKET_ERROR();
SCHEDULE_DEFERRED(p);
@@ -267,6 +280,14 @@ bufferevent_run_eventcb_(struct bufferevent *bufev, short what)
}
}
+void
+bufferevent_trigger_event(struct bufferevent *bufev, short what, int options)
+{
+ bufferevent_incref_and_lock_(bufev);
+ bufferevent_run_eventcb_(bufev, what, options&BEV_TRIG_ALL_OPTS);
+ bufferevent_decref_and_unlock_(bufev);
+}
+
int
bufferevent_init_common_(struct bufferevent_private *bufev_private,
struct event_base *base,
@@ -322,20 +343,18 @@ bufferevent_init_common_(struct bufferevent_private *bufev_private,
event_warnx("UNLOCK_CALLBACKS requires DEFER_CALLBACKS");
return -1;
}
- if (options & BEV_OPT_DEFER_CALLBACKS) {
- if (options & BEV_OPT_UNLOCK_CALLBACKS)
- event_deferred_cb_init_(
- &bufev_private->deferred,
- event_base_get_npriorities(base) / 2,
- bufferevent_run_deferred_callbacks_unlocked,
- bufev_private);
- else
- event_deferred_cb_init_(
- &bufev_private->deferred,
- event_base_get_npriorities(base) / 2,
- bufferevent_run_deferred_callbacks_locked,
- bufev_private);
- }
+ if (options & BEV_OPT_UNLOCK_CALLBACKS)
+ event_deferred_cb_init_(
+ &bufev_private->deferred,
+ event_base_get_npriorities(base) / 2,
+ bufferevent_run_deferred_callbacks_unlocked,
+ bufev_private);
+ else
+ event_deferred_cb_init_(
+ &bufev_private->deferred,
+ event_base_get_npriorities(base) / 2,
+ bufferevent_run_deferred_callbacks_locked,
+ bufev_private);
bufev_private->options = options;
@@ -596,6 +615,27 @@ bufferevent_setwatermark(struct bufferevent *bufev, short events,
BEV_UNLOCK(bufev);
}
+void
+bufferevent_getwatermark(struct bufferevent *bufev, short events,
+ size_t *lowmark, size_t *highmark)
+{
+ BEV_LOCK(bufev);
+ if (events == EV_WRITE) {
+ if (lowmark)
+ *lowmark = bufev->wm_write.low;
+ if (highmark)
+ *highmark = bufev->wm_write.high;
+ }
+
+ if (events == EV_READ) {
+ if (lowmark)
+ *lowmark = bufev->wm_read.low;
+ if (highmark)
+ *highmark = bufev->wm_read.high;
+ }
+ BEV_UNLOCK(bufev);
+}
+
int
bufferevent_flush(struct bufferevent *bufev,
short iotype,
@@ -874,7 +914,7 @@ bufferevent_generic_read_timeout_cb(evutil_socket_t fd, short event, void *ctx)
struct bufferevent *bev = ctx;
bufferevent_incref_and_lock_(bev);
bufferevent_disable(bev, EV_READ);
- bufferevent_run_eventcb_(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_READING);
+ bufferevent_run_eventcb_(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_READING, 0);
bufferevent_decref_and_unlock_(bev);
}
static void
@@ -883,7 +923,7 @@ bufferevent_generic_write_timeout_cb(evutil_socket_t fd, short event, void *ctx)
struct bufferevent *bev = ctx;
bufferevent_incref_and_lock_(bev);
bufferevent_disable(bev, EV_WRITE);
- bufferevent_run_eventcb_(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING);
+ bufferevent_run_eventcb_(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING, 0);
bufferevent_decref_and_unlock_(bev);
}
diff --git a/bufferevent_async.c b/bufferevent_async.c
index 0152fd16..f32573e4 100644
--- a/bufferevent_async.c
+++ b/bufferevent_async.c
@@ -217,7 +217,7 @@ bev_async_consider_writing(struct bufferevent_async *beva)
&beva->write_overlapped)) {
bufferevent_decref_(bev);
beva->ok = 0;
- bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR);
+ bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
} else {
beva->write_in_progress = at_most;
bufferevent_decrement_write_buckets_(&beva->bev, at_most);
@@ -270,7 +270,7 @@ bev_async_consider_reading(struct bufferevent_async *beva)
bufferevent_incref_(bev);
if (evbuffer_launch_read_(bev->input, at_most, &beva->read_overlapped)) {
beva->ok = 0;
- bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR);
+ bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
bufferevent_decref_(bev);
} else {
beva->read_in_progress = at_most;
@@ -428,7 +428,7 @@ connect_complete(struct event_overlapped *eo, ev_uintptr_t key,
bev_async_set_wsa_error(bev, eo);
bufferevent_run_eventcb_(bev,
- ok? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR);
+ ok? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR, 0);
event_base_del_virtual_(bev->ev_base);
@@ -458,17 +458,16 @@ read_complete(struct event_overlapped *eo, ev_uintptr_t key,
if (bev_a->ok) {
if (ok && nbytes) {
BEV_RESET_GENERIC_READ_TIMEOUT(bev);
- if (evbuffer_get_length(bev->input) >= bev->wm_read.low)
- bufferevent_run_readcb_(bev);
+ bufferevent_trigger_nolock_(bev, EV_READ, 0);
bev_async_consider_reading(bev_a);
} else if (!ok) {
what |= BEV_EVENT_ERROR;
bev_a->ok = 0;
- bufferevent_run_eventcb_(bev, what);
+ bufferevent_run_eventcb_(bev, what, 0);
} else if (!nbytes) {
what |= BEV_EVENT_EOF;
bev_a->ok = 0;
- bufferevent_run_eventcb_(bev, what);
+ bufferevent_run_eventcb_(bev, what, 0);
}
}
@@ -502,18 +501,16 @@ write_complete(struct event_overlapped *eo, ev_uintptr_t key,
if (bev_a->ok) {
if (ok && nbytes) {
BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
- if (evbuffer_get_length(bev->output) <=
- bev->wm_write.low)
- bufferevent_run_writecb_(bev);
+ bufferevent_trigger_nolock_(bev, EV_WRITE, 0);
bev_async_consider_writing(bev_a);
} else if (!ok) {
what |= BEV_EVENT_ERROR;
bev_a->ok = 0;
- bufferevent_run_eventcb_(bev, what);
+ bufferevent_run_eventcb_(bev, what, 0);
} else if (!nbytes) {
what |= BEV_EVENT_EOF;
bev_a->ok = 0;
- bufferevent_run_eventcb_(bev, what);
+ bufferevent_run_eventcb_(bev, what, 0);
}
}
@@ -567,9 +564,9 @@ bufferevent_async_new_(struct event_base *base,
event_overlapped_init_(&bev_a->read_overlapped, read_complete);
event_overlapped_init_(&bev_a->write_overlapped, write_complete);
+ bufferevent_init_generic_timeout_cbs_(bev);
+
bev_a->ok = fd >= 0;
- if (bev_a->ok)
- bufferevent_init_generic_timeout_cbs_(bev);
return bev;
err:
diff --git a/bufferevent_filter.c b/bufferevent_filter.c
index cc02230c..4d9be43e 100644
--- a/bufferevent_filter.c
+++ b/bufferevent_filter.c
@@ -376,10 +376,9 @@ be_filter_process_output(struct bufferevent_filtered *bevf,
/* Or if we have filled the underlying output buffer. */
!be_underlying_writebuf_full(bevf,state));
- if (processed &&
- evbuffer_get_length(bufev->output) <= bufev->wm_write.low) {
+ if (processed) {
/* call the write callback.*/
- bufferevent_run_writecb_(bufev);
+ bufferevent_trigger_nolock_(bufev, EV_WRITE, 0);
if (res == BEV_OK &&
(bufev->enabled & EV_WRITE) &&
@@ -426,27 +425,34 @@ be_filter_readcb(struct bufferevent *underlying, void *me_)
enum bufferevent_filter_result res;
enum bufferevent_flush_mode state;
struct bufferevent *bufev = downcast(bevf);
+ struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
int processed_any = 0;
- bufferevent_incref_and_lock_(bufev);
+ BEV_LOCK(bufev);
- if (bevf->got_eof)
- state = BEV_FINISHED;
- else
- state = BEV_NORMAL;
+ // It's possible our refcount is 0 at this point if another thread free'd our filterevent
+ EVUTIL_ASSERT(bufev_private->refcnt >= 0);
- /* XXXX use return value */
- res = be_filter_process_input(bevf, state, &processed_any);
- (void)res;
+ // If our refcount is > 0
+ if (bufev_private->refcnt > 0) {
- /* XXX This should be in process_input, not here. There are
- * other places that can call process-input, and they should
- * force readcb calls as needed. */
- if (processed_any &&
- evbuffer_get_length(bufev->input) >= bufev->wm_read.low)
- bufferevent_run_readcb_(bufev);
+ if (bevf->got_eof)
+ state = BEV_FINISHED;
+ else
+ state = BEV_NORMAL;
- bufferevent_decref_and_unlock_(bufev);
+ /* 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
+ * force readcb calls as needed. */
+ if (processed_any)
+ bufferevent_trigger_nolock_(bufev, EV_READ, 0);
+ }
+
+ BEV_UNLOCK(bufev);
}
/* Called when the underlying socket has drained enough that we can write to
@@ -456,11 +462,20 @@ be_filter_writecb(struct bufferevent *underlying, void *me_)
{
struct bufferevent_filtered *bevf = me_;
struct bufferevent *bev = downcast(bevf);
+ struct bufferevent_private *bufev_private = BEV_UPCAST(bev);
int processed_any = 0;
- bufferevent_incref_and_lock_(bev);
- be_filter_process_output(bevf, BEV_NORMAL, &processed_any);
- bufferevent_decref_and_unlock_(bev);
+ BEV_LOCK(bev);
+
+ // It's possible our refcount is 0 at this point if another thread free'd our filterevent
+ EVUTIL_ASSERT(bufev_private->refcnt >= 0);
+
+ // If our refcount is > 0
+ if (bufev_private->refcnt > 0) {
+ be_filter_process_output(bevf, BEV_NORMAL, &processed_any);
+ }
+
+ BEV_UNLOCK(bev);
}
/* Called when the underlying socket has given us an error */
@@ -469,11 +484,21 @@ be_filter_eventcb(struct bufferevent *underlying, short what, void *me_)
{
struct bufferevent_filtered *bevf = me_;
struct bufferevent *bev = downcast(bevf);
+ struct bufferevent_private *bufev_private = BEV_UPCAST(bev);
+
+ BEV_LOCK(bev);
+
+ // It's possible our refcount is 0 at this point if another thread free'd our filterevent
+ EVUTIL_ASSERT(bufev_private->refcnt >= 0);
+
+ // If our refcount is > 0
+ if (bufev_private->refcnt > 0) {
+
+ /* All we can really to is tell our own eventcb. */
+ bufferevent_run_eventcb_(bev, what, 0);
+ }
- bufferevent_incref_and_lock_(bev);
- /* All we can really to is tell our own eventcb. */
- bufferevent_run_eventcb_(bev, what);
- bufferevent_decref_and_unlock_(bev);
+ BEV_UNLOCK(bev);
}
static int
diff --git a/bufferevent_openssl.c b/bufferevent_openssl.c
index 1ce124f9..423b34f1 100644
--- a/bufferevent_openssl.c
+++ b/bufferevent_openssl.c
@@ -24,6 +24,11 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+// Get rid of OSX 10.7 and greater deprecation warnings.
+#if defined(__APPLE__) && defined(__clang__)
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
#include "event2/event-config.h"
#include "evconfig-private.h"
@@ -533,7 +538,7 @@ conn_closed(struct bufferevent_openssl *bev_ssl, int when, int errcode, int ret)
/* when is BEV_EVENT_{READING|WRITING} */
event = when | event;
- bufferevent_run_eventcb_(&bev_ssl->bev.bev, event);
+ bufferevent_run_eventcb_(&bev_ssl->bev.bev, event, 0);
}
static void
@@ -709,8 +714,7 @@ do_write(struct bufferevent_openssl *bev_ssl, int atmost)
if (bev_ssl->underlying)
BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
- if (evbuffer_get_length(output) <= bev->wm_write.low)
- bufferevent_run_writecb_(bev);
+ bufferevent_trigger_nolock_(bev, EV_WRITE, 0);
}
return result;
}
@@ -824,11 +828,8 @@ consider_reading(struct bufferevent_openssl *bev_ssl)
if (all_result_flags & OP_MADE_PROGRESS) {
struct bufferevent *bev = &bev_ssl->bev.bev;
- struct evbuffer *input = bev->input;
- if (evbuffer_get_length(input) >= bev->wm_read.low) {
- bufferevent_run_readcb_(bev);
- }
+ bufferevent_trigger_nolock_(bev, EV_READ, 0);
}
if (!bev_ssl->underlying) {
@@ -852,11 +853,8 @@ consider_writing(struct bufferevent_openssl *bev_ssl)
r = do_read(bev_ssl, 1024); /* XXXX 1024 is a hack */
if (r & OP_MADE_PROGRESS) {
struct bufferevent *bev = &bev_ssl->bev.bev;
- struct evbuffer *input = bev->input;
- if (evbuffer_get_length(input) >= bev->wm_read.low) {
- bufferevent_run_readcb_(bev);
- }
+ bufferevent_trigger_nolock_(bev, EV_READ, 0);
}
if (r & (OP_ERR|OP_BLOCKED))
break;
@@ -928,7 +926,7 @@ be_openssl_eventcb(struct bufferevent *bev_base, short what, void *ctx)
eat it. */
}
if (event)
- bufferevent_run_eventcb_(&bev_ssl->bev.bev, event);
+ bufferevent_run_eventcb_(&bev_ssl->bev.bev, event, 0);
}
static void
@@ -938,7 +936,7 @@ be_openssl_readeventcb(evutil_socket_t fd, short what, void *ptr)
bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
if (what == EV_TIMEOUT) {
bufferevent_run_eventcb_(&bev_ssl->bev.bev,
- BEV_EVENT_TIMEOUT|BEV_EVENT_READING);
+ BEV_EVENT_TIMEOUT|BEV_EVENT_READING, 0);
} else {
consider_reading(bev_ssl);
}
@@ -952,7 +950,7 @@ be_openssl_writeeventcb(evutil_socket_t fd, short what, void *ptr)
bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
if (what == EV_TIMEOUT) {
bufferevent_run_eventcb_(&bev_ssl->bev.bev,
- BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING);
+ BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING, 0);
} else {
consider_writing(bev_ssl);
}
@@ -1019,7 +1017,7 @@ do_handshake(struct bufferevent_openssl *bev_ssl)
/* Call do_read and do_write as needed */
bufferevent_enable(&bev_ssl->bev.bev, bev_ssl->bev.bev.enabled);
bufferevent_run_eventcb_(&bev_ssl->bev.bev,
- BEV_EVENT_CONNECTED);
+ BEV_EVENT_CONNECTED, 0);
return 1;
} else {
int err = SSL_get_error(bev_ssl->ssl, r);
@@ -1058,7 +1056,7 @@ be_openssl_handshakeeventcb(evutil_socket_t fd, short what, void *ptr)
bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
if (what & EV_TIMEOUT) {
- bufferevent_run_eventcb_(&bev_ssl->bev.bev, BEV_EVENT_TIMEOUT);
+ bufferevent_run_eventcb_(&bev_ssl->bev.bev, BEV_EVENT_TIMEOUT, 0);
} else
do_handshake(bev_ssl);/* XXX handle failure */
bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
diff --git a/bufferevent_pair.c b/bufferevent_pair.c
index 4d467260..4340f237 100644
--- a/bufferevent_pair.c
+++ b/bufferevent_pair.c
@@ -151,7 +151,7 @@ static void
be_pair_transfer(struct bufferevent *src, struct bufferevent *dst,
int ignore_wm)
{
- size_t src_size, dst_size;
+ size_t dst_size;
size_t n;
evbuffer_unfreeze(src->output, 1);
@@ -182,15 +182,8 @@ be_pair_transfer(struct bufferevent *src, struct bufferevent *dst,
BEV_DEL_GENERIC_WRITE_TIMEOUT(dst);
}
- src_size = evbuffer_get_length(src->output);
- dst_size = evbuffer_get_length(dst->input);
-
- if (dst_size >= dst->wm_read.low) {
- bufferevent_run_readcb_(dst);
- }
- if (src_size <= src->wm_write.low) {
- bufferevent_run_writecb_(src);
- }
+ bufferevent_trigger_nolock_(dst, EV_READ, 0);
+ bufferevent_trigger_nolock_(src, EV_WRITE, 0);
done:
evbuffer_freeze(src->output, 1);
evbuffer_freeze(dst->input, 0);
@@ -299,7 +292,7 @@ be_pair_flush(struct bufferevent *bev, short iotype,
be_pair_transfer(bev, partner, 1);
if (mode == BEV_FINISHED) {
- bufferevent_run_eventcb_(partner, iotype|BEV_EVENT_EOF);
+ bufferevent_run_eventcb_(partner, iotype|BEV_EVENT_EOF, 0);
}
decref_and_unlock(bev);
return 0;
@@ -309,13 +302,14 @@ struct bufferevent *
bufferevent_pair_get_partner(struct bufferevent *bev)
{
struct bufferevent_pair *bev_p;
- struct bufferevent *partner;
+ struct bufferevent *partner = NULL;
bev_p = upcast(bev);
if (! bev_p)
return NULL;
incref_and_lock(bev);
- partner = downcast(bev_p->partner);
+ if (bev_p->partner)
+ partner = downcast(bev_p->partner);
decref_and_unlock(bev);
return partner;
}
diff --git a/bufferevent_sock.c b/bufferevent_sock.c
index 5ce4953b..49ebc0be 100644
--- a/bufferevent_sock.c
+++ b/bufferevent_sock.c
@@ -184,8 +184,7 @@ bufferevent_readcb(evutil_socket_t fd, short event, void *arg)
bufferevent_decrement_read_buckets_(bufev_p, res);
/* Invoke the user callback - must always be called last */
- if (evbuffer_get_length(input) >= bufev->wm_read.low)
- bufferevent_run_readcb_(bufev);
+ bufferevent_trigger_nolock_(bufev, EV_READ, 0);
goto done;
@@ -194,7 +193,7 @@ bufferevent_readcb(evutil_socket_t fd, short event, void *arg)
error:
bufferevent_disable(bufev, EV_READ);
- bufferevent_run_eventcb_(bufev, what);
+ bufferevent_run_eventcb_(bufev, what, 0);
done:
bufferevent_decref_and_unlock_(bufev);
@@ -236,7 +235,7 @@ bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
if (c < 0) {
event_del(&bufev->ev_write);
event_del(&bufev->ev_read);
- bufferevent_run_eventcb_(bufev, BEV_EVENT_ERROR);
+ bufferevent_run_eventcb_(bufev, BEV_EVENT_ERROR, 0);
goto done;
} else {
connected = 1;
@@ -245,12 +244,12 @@ bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
event_del(&bufev->ev_write);
bufferevent_async_set_connected_(bufev);
bufferevent_run_eventcb_(bufev,
- BEV_EVENT_CONNECTED);
+ BEV_EVENT_CONNECTED, 0);
goto done;
}
#endif
bufferevent_run_eventcb_(bufev,
- BEV_EVENT_CONNECTED);
+ BEV_EVENT_CONNECTED, 0);
if (!(bufev->enabled & EV_WRITE) ||
bufev_p->write_suspended) {
event_del(&bufev->ev_write);
@@ -294,9 +293,8 @@ bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
* Invoke the user callback if our buffer is drained or below the
* low watermark.
*/
- if ((res || !connected) &&
- evbuffer_get_length(bufev->output) <= bufev->wm_write.low) {
- bufferevent_run_writecb_(bufev);
+ if (res || !connected) {
+ bufferevent_trigger_nolock_(bufev, EV_WRITE, 0);
}
goto done;
@@ -309,7 +307,7 @@ bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
error:
bufferevent_disable(bufev, EV_WRITE);
- bufferevent_run_eventcb_(bufev, what);
+ bufferevent_run_eventcb_(bufev, what, 0);
done:
bufferevent_decref_and_unlock_(bufev);
@@ -426,7 +424,7 @@ bufferevent_socket_connect(struct bufferevent *bev,
goto done;
freesock:
- bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR);
+ bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
if (ownfd)
evutil_closesocket(fd);
/* do something about the error? */
@@ -450,7 +448,7 @@ bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai,
if (result != 0) {
bev_p->dns_error = result;
- bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR);
+ bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
bufferevent_decref_and_unlock_(bev);
if (ai)
evutil_freeaddrinfo(ai);
diff --git a/changelist-internal.h b/changelist-internal.h
index 0ec2eeaf..98fc52ae 100644
--- a/changelist-internal.h
+++ b/changelist-internal.h
@@ -62,6 +62,7 @@ struct event_change {
* and write_change is unused. */
ev_uint8_t read_change;
ev_uint8_t write_change;
+ ev_uint8_t close_change;
};
/* Flags for read_change and write_change. */
diff --git a/cmake/COPYING-CMAKE-SCRIPTS b/cmake/COPYING-CMAKE-SCRIPTS
new file mode 100644
index 00000000..ab3c4d25
--- /dev/null
+++ b/cmake/COPYING-CMAKE-SCRIPTS
@@ -0,0 +1,22 @@
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
diff --git a/cmake/CheckFileOffsetBits.c b/cmake/CheckFileOffsetBits.c
new file mode 100644
index 00000000..d948fecf
--- /dev/null
+++ b/cmake/CheckFileOffsetBits.c
@@ -0,0 +1,14 @@
+#include <sys/types.h>
+
+#define KB ((off_t)1024)
+#define MB ((off_t)1024 * KB)
+#define GB ((off_t)1024 * MB)
+#define TB ((off_t)1024 * GB)
+int t2[(((64 * GB -1) % 671088649) == 268434537)
+ && (((TB - (64 * GB -1) + 255) % 1792151290) == 305159546)? 1: -1];
+
+int main()
+{
+ ;
+ return 0;
+}
diff --git a/cmake/CheckFileOffsetBits.cmake b/cmake/CheckFileOffsetBits.cmake
new file mode 100644
index 00000000..12534401
--- /dev/null
+++ b/cmake/CheckFileOffsetBits.cmake
@@ -0,0 +1,43 @@
+# - Check if _FILE_OFFSET_BITS macro needed for large files
+# CHECK_FILE_OFFSET_BITS ()
+#
+# The following variables may be set before calling this macro to
+# modify the way the check is run:
+#
+# CMAKE_REQUIRED_FLAGS = string of compile command line flags
+# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
+# CMAKE_REQUIRED_INCLUDES = list of include directories
+# Copyright (c) 2009, Michihiro NAKAJIMA
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+#INCLUDE(CheckCSourceCompiles)
+
+GET_FILENAME_COMPONENT(_selfdir_CheckFileOffsetBits
+ "${CMAKE_CURRENT_LIST_FILE}" PATH)
+
+MACRO (CHECK_FILE_OFFSET_BITS)
+ IF(NOT DEFINED _FILE_OFFSET_BITS)
+ MESSAGE(STATUS "Cheking _FILE_OFFSET_BITS for large files")
+ TRY_COMPILE(__WITHOUT_FILE_OFFSET_BITS_64
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${_selfdir_CheckFileOffsetBits}/CheckFileOffsetBits.c
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS})
+ IF(NOT __WITHOUT_FILE_OFFSET_BITS_64)
+ TRY_COMPILE(__WITH_FILE_OFFSET_BITS_64
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${_selfdir_CheckFileOffsetBits}/CheckFileOffsetBits.c
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_FILE_OFFSET_BITS=64)
+ ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64)
+
+ IF(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
+ SET(_FILE_OFFSET_BITS 64 CACHE INTERNAL "_FILE_OFFSET_BITS macro needed for large files")
+ MESSAGE(STATUS "Cheking _FILE_OFFSET_BITS for large files - needed")
+ ELSE(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
+ SET(_FILE_OFFSET_BITS "" CACHE INTERNAL "_FILE_OFFSET_BITS macro needed for large files")
+ MESSAGE(STATUS "Cheking _FILE_OFFSET_BITS for large files - not needed")
+ ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
+ ENDIF(NOT DEFINED _FILE_OFFSET_BITS)
+
+ENDMACRO (CHECK_FILE_OFFSET_BITS)
diff --git a/cmake/CheckFunctionExistsEx.c b/cmake/CheckFunctionExistsEx.c
new file mode 100644
index 00000000..5ee3e591
--- /dev/null
+++ b/cmake/CheckFunctionExistsEx.c
@@ -0,0 +1,30 @@
+#ifdef CHECK_FUNCTION_EXISTS
+
+#ifndef _WIN32
+char CHECK_FUNCTION_EXISTS();
+#endif
+
+#ifdef __CLASSIC_C__
+int main(){
+ int ac;
+ char*av[];
+#else
+int main(int ac, char*av[]){
+#endif
+#ifdef _WIN32
+ void * p = &CHECK_FUNCTION_EXISTS;
+#else
+ CHECK_FUNCTION_EXISTS();
+#endif
+ if(ac > 1000)
+ {
+ return *av[0];
+ }
+ return 0;
+}
+
+#else /* CHECK_FUNCTION_EXISTS */
+
+# error "CHECK_FUNCTION_EXISTS has to specify the function"
+
+#endif /* CHECK_FUNCTION_EXISTS */
diff --git a/cmake/CheckFunctionExistsEx.cmake b/cmake/CheckFunctionExistsEx.cmake
new file mode 100644
index 00000000..f513f4e1
--- /dev/null
+++ b/cmake/CheckFunctionExistsEx.cmake
@@ -0,0 +1,69 @@
+# - Check if a C function can be linked
+# CHECK_FUNCTION_EXISTS(<function> <variable>)
+#
+# Check that the <function> is provided by libraries on the system and
+# store the result in a <variable>. This does not verify that any
+# system header file declares the function, only that it can be found
+# at link time (considure using CheckSymbolExists).
+#
+# The following variables may be set before calling this macro to
+# modify the way the check is run:
+#
+# CMAKE_REQUIRED_FLAGS = string of compile command line flags
+# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
+# CMAKE_REQUIRED_INCLUDES = list of include directories
+# CMAKE_REQUIRED_LIBRARIES = list of libraries to link
+
+#=============================================================================
+# Copyright 2002-2011 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+MACRO(CHECK_FUNCTION_EXISTS_EX FUNCTION VARIABLE)
+ IF("${VARIABLE}" MATCHES "^${VARIABLE}$")
+ SET(MACRO_CHECK_FUNCTION_DEFINITIONS
+ "-DCHECK_FUNCTION_EXISTS=${FUNCTION} ${CMAKE_REQUIRED_FLAGS}")
+ MESSAGE(STATUS "Looking for ${FUNCTION}")
+ IF(CMAKE_REQUIRED_LIBRARIES)
+ SET(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES
+ "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
+ ELSE(CMAKE_REQUIRED_LIBRARIES)
+ SET(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES)
+ ENDIF(CMAKE_REQUIRED_LIBRARIES)
+ IF(CMAKE_REQUIRED_INCLUDES)
+ SET(CHECK_FUNCTION_EXISTS_ADD_INCLUDES
+ "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+ ELSE(CMAKE_REQUIRED_INCLUDES)
+ SET(CHECK_FUNCTION_EXISTS_ADD_INCLUDES)
+ ENDIF(CMAKE_REQUIRED_INCLUDES)
+ TRY_COMPILE(${VARIABLE}
+ ${CMAKE_BINARY_DIR}
+ ${PROJECT_SOURCE_DIR}/cmake/CheckFunctionExistsEx.c
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
+ "${CHECK_FUNCTION_EXISTS_ADD_LIBRARIES}"
+ "${CHECK_FUNCTION_EXISTS_ADD_INCLUDES}"
+ OUTPUT_VARIABLE OUTPUT)
+ IF(${VARIABLE})
+ SET(${VARIABLE} 1 CACHE INTERNAL "Have function ${FUNCTION}")
+ MESSAGE(STATUS "Looking for ${FUNCTION} - found")
+ FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the function ${FUNCTION} exists passed with the following output:\n"
+ "${OUTPUT}\n\n")
+ ELSE(${VARIABLE})
+ MESSAGE(STATUS "Looking for ${FUNCTION} - not found")
+ SET(${VARIABLE} "" CACHE INTERNAL "Have function ${FUNCTION}")
+ FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the function ${FUNCTION} exists failed with the following output:\n"
+ "${OUTPUT}\n\n")
+ ENDIF(${VARIABLE})
+ ENDIF("${VARIABLE}" MATCHES "^${VARIABLE}$")
+ENDMACRO(CHECK_FUNCTION_EXISTS_EX)
diff --git a/cmake/CheckPrototypeDefinition.c.in b/cmake/CheckPrototypeDefinition.c.in
new file mode 100644
index 00000000..a97344ac
--- /dev/null
+++ b/cmake/CheckPrototypeDefinition.c.in
@@ -0,0 +1,29 @@
+@CHECK_PROTOTYPE_DEFINITION_HEADER@
+
+static void cmakeRequireSymbol(int dummy, ...) {
+ (void) dummy;
+}
+
+static void checkSymbol(void) {
+#ifndef @CHECK_PROTOTYPE_DEFINITION_SYMBOL@
+ cmakeRequireSymbol(0, &@CHECK_PROTOTYPE_DEFINITION_SYMBOL@);
+#endif
+}
+
+@CHECK_PROTOTYPE_DEFINITION_PROTO@ {
+ return @CHECK_PROTOTYPE_DEFINITION_RETURN@;
+}
+
+#ifdef __CLASSIC_C__
+int main() {
+ int ac;
+ char*av[];
+#else
+int main(int ac, char *av[]) {
+#endif
+ checkSymbol();
+ if (ac > 1000) {
+ return *av[0];
+ }
+ return 0;
+}
diff --git a/cmake/CheckPrototypeDefinition.cmake b/cmake/CheckPrototypeDefinition.cmake
new file mode 100644
index 00000000..5e6ba4bb
--- /dev/null
+++ b/cmake/CheckPrototypeDefinition.cmake
@@ -0,0 +1,85 @@
+# - Check if the protoype we expect is correct.
+# check_prototype_definition(FUNCTION PROTOTYPE RETURN HEADER VARIABLE)
+#
+# FUNCTION - The name of the function (used to check if prototype exists)
+# PROTOTYPE- The prototype to check.
+# RETURN - The return value of the function.
+# HEADER - The header files required.
+# VARIABLE - The variable to store the result.
+#
+# Example:
+#
+# check_prototype_definition(getpwent_r
+# "struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)"
+# "NULL"
+# "unistd.h;pwd.h"
+# SOLARIS_GETPWENT_R)
+#
+# The following variables may be set before calling this macro to
+# modify the way the check is run:
+#
+# CMAKE_REQUIRED_FLAGS = string of compile command line flags
+# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
+# CMAKE_REQUIRED_INCLUDES = list of include directories
+# CMAKE_REQUIRED_LIBRARIES = list of libraries to link
+
+
+function(CHECK_PROTOTYPE_DEFINITION _FUNCTION _PROTOTYPE _RETURN _HEADER _VARIABLE)
+
+ if ("${_VARIABLE}" MATCHES "^${_VARIABLE}$")
+ set(CHECK_PROTOTYPE_DEFINITION_CONTENT "/* */\n")
+
+ set(CHECK_PROTOTYPE_DEFINITION_FLAGS ${CMAKE_REQUIRED_FLAGS})
+ if (CMAKE_REQUIRED_LIBRARIES)
+ set(CHECK_PROTOTYPE_DEFINITION_LIBS
+ "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
+ else(CMAKE_REQUIRED_LIBRARIES)
+ set(CHECK_PROTOTYPE_DEFINITION_LIBS)
+ endif(CMAKE_REQUIRED_LIBRARIES)
+ if (CMAKE_REQUIRED_INCLUDES)
+ set(CMAKE_SYMBOL_EXISTS_INCLUDES
+ "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+ else(CMAKE_REQUIRED_INCLUDES)
+ set(CMAKE_SYMBOL_EXISTS_INCLUDES)
+ endif(CMAKE_REQUIRED_INCLUDES)
+
+ foreach(_FILE ${_HEADER})
+ set(CHECK_PROTOTYPE_DEFINITION_HEADER
+ "${CHECK_PROTOTYPE_DEFINITION_HEADER}#include <${_FILE}>\n")
+ endforeach(_FILE)
+
+ set(CHECK_PROTOTYPE_DEFINITION_SYMBOL ${_FUNCTION})
+ set(CHECK_PROTOTYPE_DEFINITION_PROTO ${_PROTOTYPE})
+ set(CHECK_PROTOTYPE_DEFINITION_RETURN ${_RETURN})
+
+ # TODO: Fix this. If the Module path has more than one entry, the below will fail.
+ configure_file("${CMAKE_MODULE_PATH}/CheckPrototypeDefinition.c.in"
+ "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckPrototypeDefinition.c" @ONLY)
+
+ file(READ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckPrototypeDefinition.c _SOURCE)
+
+ try_compile(${_VARIABLE}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckPrototypeDefinition.c
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${CHECK_PROTOTYPE_DEFINITION_FLAGS}
+ "${CHECK_PROTOTYPE_DEFINITION_LIBS}"
+ "${CMAKE_SYMBOL_EXISTS_INCLUDES}"
+ OUTPUT_VARIABLE OUTPUT)
+
+ if (${_VARIABLE})
+ set(${_VARIABLE} 1 CACHE INTERNAL "Have correct prototype for ${_FUNCTION}")
+ message(STATUS "Checking prototype ${_FUNCTION} for ${_VARIABLE} - True")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the prototype ${_FUNCTION} exists for ${_VARIABLE} passed with the following output:\n"
+ "${OUTPUT}\n\n")
+ else (${_VARIABLE})
+ message(STATUS "Checking prototype ${_FUNCTION} for ${_VARIABLE} - False")
+ set(${_VARIABLE} 0 CACHE INTERNAL "Have correct prototype for ${_FUNCTION}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the prototype ${_FUNCTION} exists for ${_VARIABLE} failed with the following output:\n"
+ "${OUTPUT}\n\n${_SOURCE}\n\n")
+ endif (${_VARIABLE})
+ endif("${_VARIABLE}" MATCHES "^${_VARIABLE}$")
+
+endfunction(CHECK_PROTOTYPE_DEFINITION)
diff --git a/cmake/CheckWorkingKqueue.cmake b/cmake/CheckWorkingKqueue.cmake
new file mode 100644
index 00000000..47bf4e83
--- /dev/null
+++ b/cmake/CheckWorkingKqueue.cmake
@@ -0,0 +1,52 @@
+include(CheckCSourceRuns)
+
+check_c_source_runs(
+"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/event.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int
+main(int argc, char **argv)
+{
+ int kq;
+ int n;
+ int fd[2];
+ struct kevent ev;
+ struct timespec ts;
+ char buf[8000];
+
+ if (pipe(fd) == -1)
+ exit(1);
+ if (fcntl(fd[1], F_SETFL, O_NONBLOCK) == -1)
+ exit(1);
+
+ while ((n = write(fd[1], buf, sizeof(buf))) == sizeof(buf))
+ ;
+
+ if ((kq = kqueue()) == -1)
+ exit(1);
+
+ memset(&ev, 0, sizeof(ev));
+ ev.ident = fd[1];
+ ev.filter = EVFILT_WRITE;
+ ev.flags = EV_ADD | EV_ENABLE;
+ n = kevent(kq, &ev, 1, NULL, 0, NULL);
+ if (n == -1)
+ exit(1);
+
+ read(fd[0], buf, sizeof(buf));
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ n = kevent(kq, NULL, 0, &ev, 1, &ts);
+ if (n == -1 || n == 0)
+ exit(1);
+
+ exit(0);
+}
+
+" EVENT__HAVE_WORKING_KQUEUE) \ No newline at end of file
diff --git a/cmake/CodeCoverage.cmake b/cmake/CodeCoverage.cmake
new file mode 100644
index 00000000..969f2732
--- /dev/null
+++ b/cmake/CodeCoverage.cmake
@@ -0,0 +1,162 @@
+#
+# Boost Software License - Version 1.0 - August 17th, 2003
+#
+# Permission is hereby granted, free of charge, to any person or organization
+# obtaining a copy of the software and accompanying documentation covered by
+# this license (the "Software") to use, reproduce, display, distribute,
+# execute, and transmit the Software, and to prepare derivative works of the
+# Software, and to permit third-parties to whom the Software is furnished to
+# do so, all subject to the following:
+#
+# The copyright notices in the Software and this entire statement, including
+# the above license grant, this restriction and the following disclaimer,
+# must be included in all copies of the Software, in whole or in part, and
+# all derivative works of the Software, unless such copies or derivative
+# works are solely in the form of machine-executable object code generated by
+# a source language processor.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+# SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+# FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+# 2012-01-31, Lars Bilke
+# - Enable Code Coverage
+#
+# 2013-09-17, Joakim Söderberg
+# - Added support for Clang.
+# - Some additional usage instructions.
+#
+# USAGE:
+# 1. Copy this file into your cmake modules path.
+#
+# 2. Add the following line to your CMakeLists.txt:
+# INCLUDE(CodeCoverage)
+#
+# 3. Set compiler flags to turn off optimization and enable coverage:
+# SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
+# SET(CMAKE_C_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
+#
+# 3. Use the function SETUP_TARGET_FOR_COVERAGE to create a custom make target
+# which runs your test executable and produces a lcov code coverage report:
+# Example:
+# SETUP_TARGET_FOR_COVERAGE(
+# my_coverage_target # Name for custom target.
+# test_driver # Name of the test driver executable that runs the tests.
+# # NOTE! This should always have a ZERO as exit code
+# # otherwise the coverage generation will not complete.
+# coverage # Name of output directory.
+# )
+#
+# 4. Build a Debug build:
+# cmake -DCMAKE_BUILD_TYPE=Debug ..
+# make
+# make my_coverage_target
+#
+#
+
+# Check prereqs
+FIND_PROGRAM( GCOV_PATH gcov )
+FIND_PROGRAM( LCOV_PATH lcov )
+FIND_PROGRAM( GENHTML_PATH genhtml )
+FIND_PROGRAM( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/tests)
+
+IF(NOT GCOV_PATH)
+ MESSAGE(FATAL_ERROR "gcov not found! Aborting...")
+ENDIF() # NOT GCOV_PATH
+
+IF(NOT CMAKE_COMPILER_IS_GNUCC AND NOT CMAKE_COMPILER_IS_GNUCXX)
+ # Clang version 3.0.0 and greater now supports gcov as well.
+ MESSAGE(WARNING "Compiler is not GNU gcc! Clang Version 3.0.0 and greater supports gcov as well, but older versions don't.")
+
+ IF(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ MESSAGE(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
+ ENDIF()
+ENDIF() # NOT CMAKE_COMPILER_IS_GNUCC
+
+IF ( NOT CMAKE_BUILD_TYPE STREQUAL "Debug" )
+ MESSAGE( WARNING "Code coverage results with an optimized (non-Debug) build may be misleading" )
+ENDIF() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
+
+
+# Param _targetname The name of new the custom make target
+# Param _testrunner The name of the target which runs the tests.
+# MUST return ZERO always, even on errors.
+# If not, no coverage report will be created!
+# Param _outputname lcov output is generated as _outputname.info
+# HTML report is generated in _outputname/index.html
+# Optional fourth parameter is passed as arguments to _testrunner
+# Pass them in list form, e.g.: "-j;2" for -j 2
+FUNCTION(SETUP_TARGET_FOR_COVERAGE _targetname _testrunner _outputname)
+
+ IF(NOT LCOV_PATH)
+ MESSAGE(FATAL_ERROR "lcov not found! Aborting...")
+ ENDIF() # NOT LCOV_PATH
+
+ IF(NOT GENHTML_PATH)
+ MESSAGE(FATAL_ERROR "genhtml not found! Aborting...")
+ ENDIF() # NOT GENHTML_PATH
+
+ # Setup target
+ ADD_CUSTOM_TARGET(${_targetname}
+
+ # Cleanup lcov
+ ${LCOV_PATH} --directory . --zerocounters
+
+ # Run tests
+ COMMAND ${_testrunner} ${ARGV3}
+
+ # Capturing lcov counters and generating report
+ COMMAND ${LCOV_PATH} --directory . --capture --output-file ${_outputname}.info
+ COMMAND ${LCOV_PATH} --remove ${_outputname}.info 'tests/*' '/usr/*' --output-file ${_outputname}.info.cleaned
+ COMMAND ${GENHTML_PATH} -o ${_outputname} ${_outputname}.info.cleaned
+ COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info ${_outputname}.info.cleaned
+
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+ COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
+ )
+
+ # Show info where to find the report
+ ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD
+ COMMAND ;
+ COMMENT "Open ./${_outputname}/index.html in your browser to view the coverage report."
+ )
+
+ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE
+
+# Param _targetname The name of new the custom make target
+# Param _testrunner The name of the target which runs the tests
+# Param _outputname cobertura output is generated as _outputname.xml
+# Optional fourth parameter is passed as arguments to _testrunner
+# Pass them in list form, e.g.: "-j;2" for -j 2
+FUNCTION(SETUP_TARGET_FOR_COVERAGE_COBERTURA _targetname _testrunner _outputname)
+
+ IF(NOT PYTHON_EXECUTABLE)
+ MESSAGE(FATAL_ERROR "Python not found! Aborting...")
+ ENDIF() # NOT PYTHON_EXECUTABLE
+
+ IF(NOT GCOVR_PATH)
+ MESSAGE(FATAL_ERROR "gcovr not found! Aborting...")
+ ENDIF() # NOT GCOVR_PATH
+
+ ADD_CUSTOM_TARGET(${_targetname}
+
+ # Run tests
+ ${_testrunner} ${ARGV3}
+
+ # Running gcovr
+ COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} -e '${CMAKE_SOURCE_DIR}/tests/' -o ${_outputname}.xml
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+ COMMENT "Running gcovr to produce Cobertura code coverage report."
+ )
+
+ # Show info where to find the report
+ ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD
+ COMMAND ;
+ COMMENT "Cobertura code coverage report saved in ${_outputname}.xml."
+ )
+
+ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE_COBERTURA
diff --git a/cmake/Copyright.txt b/cmake/Copyright.txt
new file mode 100644
index 00000000..813124f0
--- /dev/null
+++ b/cmake/Copyright.txt
@@ -0,0 +1,57 @@
+CMake - Cross Platform Makefile Generator
+Copyright 2000-2013 Kitware, Inc.
+Copyright 2000-2011 Insight Software Consortium
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the names of Kitware, Inc., the Insight Software Consortium,
+ nor the names of their contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+------------------------------------------------------------------------------
+
+The above copyright and license notice applies to distributions of
+CMake in source and binary form. Some source files contain additional
+notices of original copyright by their contributors; see each source
+for details. Third-party software packages supplied with CMake under
+compatible licenses provide their own copyright notices documented in
+corresponding subdirectories.
+
+------------------------------------------------------------------------------
+
+CMake was initially developed by Kitware with the following sponsorship:
+
+ * National Library of Medicine at the National Institutes of Health
+ as part of the Insight Segmentation and Registration Toolkit (ITK).
+
+ * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel
+ Visualization Initiative.
+
+ * National Alliance for Medical Image Computing (NAMIC) is funded by the
+ National Institutes of Health through the NIH Roadmap for Medical Research,
+ Grant U54 EB005149.
+
+ * Kitware, Inc. \ No newline at end of file
diff --git a/cmake/LibeventConfig.cmake.in b/cmake/LibeventConfig.cmake.in
new file mode 100644
index 00000000..b28cacb5
--- /dev/null
+++ b/cmake/LibeventConfig.cmake.in
@@ -0,0 +1,17 @@
+# - Config file for the Libevent package
+# It defines the following variables
+# LIBEVENT_INCLUDE_DIRS - include directories for FooBar
+# LIBEVENT_LIBRARIES - libraries to link against
+
+# Get the path of the current file.
+get_filename_component(LIBEVENT_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+
+# Set the include directories.
+set(LIBEVENT_INCLUDE_DIRS "@EVENT_INSTALL_INCLUDE_DIR@")
+
+# Include the project Targets file, this contains definitions for IMPORTED targets.
+include(${LIBEVENT_CMAKE_DIR}/LibeventTargets.cmake)
+
+# IMPORTED targets from LibeventTargets.cmake
+set(LIBEVENT_LIBRARIES event event_core event_extra)
+
diff --git a/cmake/LibeventConfigVersion.cmake.in b/cmake/LibeventConfigVersion.cmake.in
new file mode 100644
index 00000000..56371a8f
--- /dev/null
+++ b/cmake/LibeventConfigVersion.cmake.in
@@ -0,0 +1,11 @@
+set(PACKAGE_VERSION "@EVENT_PACKAGE_VERSION@")
+
+# Check whether the requested PACKAGE_FIND_VERSION is compatible
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/configure.ac b/configure.ac
index a0872bc1..8027d6dd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5,7 +5,7 @@ dnl See LICENSE for copying information.
dnl
dnl Original version Dug Song <dugsong@monkey.org>
-AC_INIT(libevent,2.1.3-alpha-dev)
+AC_INIT(libevent,2.1.4-alpha-dev)
AC_PREREQ(2.59)
AC_CONFIG_SRCDIR(event.c)
@@ -14,7 +14,7 @@ AM_INIT_AUTOMAKE
dnl AM_SILENT_RULES req. automake 1.11. [no] defaults V=1
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_CONFIG_HEADERS(config.h evconfig-private.h:evconfig-private.h.in)
-AC_DEFINE(NUMERIC_VERSION, 0x02010301, [Numeric representation of the version])
+AC_DEFINE(NUMERIC_VERSION, 0x02010401, [Numeric representation of the version])
dnl Initialize prefix.
if test "$prefix" = "NONE"; then
@@ -111,6 +111,9 @@ AC_ARG_ENABLE([libevent-install],
AC_ARG_ENABLE([libevent-regress],
AS_HELP_STRING([--disable-libevent-regress, skip regress in make check]),
[], [enable_libevent_regress=yes])
+AC_ARG_ENABLE([samples],
+ AS_HELP_STRING([--disable-samples, skip building of sample programs]),
+ [], [enable_samples=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])
@@ -127,6 +130,7 @@ dnl the command line with --enable-shared and --disable-shared.
dnl AC_DISABLE_SHARED
AC_SUBST(LIBTOOL_DEPS)
+AM_CONDITIONAL([BUILD_SAMPLES], [test "$enable_samples" = "yes"])
AM_CONDITIONAL([BUILD_REGRESS], [test "$enable_libevent_regress" = "yes"])
dnl Checks for libraries.
@@ -340,7 +344,6 @@ AC_CHECK_FUNCS([ \
getnameinfo \
getprotobynumber \
gettimeofday \
- inet_aton \
inet_ntop \
inet_pton \
issetugid \
@@ -817,6 +820,15 @@ if test x$enable_gcc_warnings != xno && test "$GCC" = "yes"; then
# Disable the unused-function warnings, because these trigger
# for minheap-internal.h related code.
CFLAGS="$CFLAGS -Wno-unused-function"
+
+ # clang on macosx emits warnigns for each directory specified which
+ # isn't "used" generating a lot of build noise (typically 3 warnings
+ # per file
+ case "$host_os" in
+ darwin*)
+ CFLAGS="$CFLAGS -Qunused-arguments"
+ ;;
+ esac
fi
##This will break the world on some 64-bit architectures
diff --git a/epoll.c b/epoll.c
index 2d07ff62..aa41f84e 100644
--- a/epoll.c
+++ b/epoll.c
@@ -60,6 +60,18 @@
#include "changelist-internal.h"
#include "time-internal.h"
+/* Since Linux 2.6.17, epoll is able to report about peer half-closed connection
+ using special EPOLLRDHUP flag on a read event.
+*/
+#if !defined(EPOLLRDHUP)
+#define EPOLLRDHUP 0
+#define EARLY_CLOSE_IF_HAVE_RDHUP 0
+#else
+#define EARLY_CLOSE_IF_HAVE_RDHUP EV_FEATURE_EARLY_CLOSE
+#endif
+
+#include "epolltable-internal.h"
+
#if defined(EVENT__HAVE_SYS_TIMERFD_H) && \
defined(EVENT__HAVE_TIMERFD_CREATE) && \
defined(HAVE_POSIX_MONOTONIC) && defined(TFD_NONBLOCK) && \
@@ -92,7 +104,7 @@ static const struct eventop epollops_changelist = {
epoll_dispatch,
epoll_dealloc,
1, /* need reinit */
- EV_FEATURE_ET|EV_FEATURE_O1,
+ EV_FEATURE_ET|EV_FEATURE_O1| EARLY_CLOSE_IF_HAVE_RDHUP,
EVENT_CHANGELIST_FDINFO_SIZE
};
@@ -110,7 +122,7 @@ const struct eventop epollops = {
epoll_dispatch,
epoll_dealloc,
1, /* need reinit */
- EV_FEATURE_ET|EV_FEATURE_O1,
+ EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_EARLY_CLOSE,
0
};
@@ -234,171 +246,6 @@ epoll_op_to_string(int op)
"???";
}
-/*
- Here are the values we're masking off to decide what operations to do.
- Note that since EV_READ|EV_WRITE.
-
- Note also that this table is a little sparse, since ADD+DEL is
- nonsensical ("xxx" in the list below.)
-
- Note also also that we are shifting old_events by only 3 bits, since
- EV_READ is 2 and EV_WRITE is 4.
-
- The table was auto-generated with a python script, according to this
- pseudocode:
-
- If either the read or the write change is add+del:
- This is impossible; Set op==-1, events=0.
- Else, if either the read or the write change is add:
- Set events to 0.
- If the read change is add, or
- (the read change is not del, and ev_read is in old_events):
- Add EPOLLIN to events.
- If the write change is add, or
- (the write change is not del, and ev_write is in old_events):
- Add EPOLLOUT to events.
-
- If old_events is set:
- Set op to EPOLL_CTL_MOD [*1,*2]
- Else:
- Set op to EPOLL_CTL_ADD [*3]
-
- Else, if the read or the write change is del:
- Set op to EPOLL_CTL_DEL.
- If the read change is del:
- If the write change is del:
- Set events to EPOLLIN|EPOLLOUT
- Else if ev_write is in old_events:
- Set events to EPOLLOUT
- Set op to EPOLL_CTL_MOD
- Else
- Set events to EPOLLIN
- Else:
- {The write change is del.}
- If ev_read is in old_events:
- Set events to EPOLLIN
- Set op to EPOLL_CTL_MOD
- Else:
- Set the events to EPOLLOUT
-
- Else:
- There is no read or write change; set op to 0 and events to 0.
-
- The logic is a little tricky, since we had no events set on the fd before,
- we need to set op="ADD" and set events=the events we want to add. If we
- had any events set on the fd before, and we want any events to remain on
- the fd, we need to say op="MOD" and set events=the events we want to
- remain. But if we want to delete the last event, we say op="DEL" and
- set events=(any non-null pointer).
-
- [*1] This MOD is only a guess. MOD might fail with ENOENT if the file was
- closed and a new file was opened with the same fd. If so, we'll retry
- with ADD.
-
- [*2] We can't replace this with a no-op even if old_events is the same as
- the new events: if the file was closed and reopened, we need to retry
- with an ADD. (We do a MOD in this case since "no change" is more
- common than "close and reopen", so we'll usually wind up doing 1
- syscalls instead of 2.)
-
- [*3] This ADD is only a guess. There is a fun Linux kernel issue where if
- you have two fds for the same file (via dup) and you ADD one to an
- epfd, then close it, then re-create it with the same fd (via dup2 or an
- unlucky dup), then try to ADD it again, you'll get an EEXIST, since the
- struct epitem is not actually removed from the struct eventpoll until
- the file itself is closed.
-
- EV_CHANGE_ADD==1
- EV_CHANGE_DEL==2
- EV_READ ==2
- EV_WRITE ==4
- Bit 0: read change is add
- Bit 1: read change is del
- Bit 2: write change is add
- Bit 3: write change is del
- Bit 4: old events had EV_READ
- Bit 5: old events had EV_WRITE
-*/
-
-#define INDEX(c) \
- ( (((c)->read_change&(EV_CHANGE_ADD|EV_CHANGE_DEL))) | \
- (((c)->write_change&(EV_CHANGE_ADD|EV_CHANGE_DEL)) << 2) | \
- (((c)->old_events&(EV_READ|EV_WRITE)) << 3) )
-
-#if EV_READ != 2 || EV_WRITE != 4 || EV_CHANGE_ADD != 1 || EV_CHANGE_DEL != 2
-#error "Libevent's internals changed! Regenerate the op_table in epoll.c"
-#endif
-
-static const struct operation {
- int events;
- int op;
-} op_table[] = {
- { 0, 0 }, /* old= 0, write: 0, read: 0 */
- { EPOLLIN, EPOLL_CTL_ADD }, /* old= 0, write: 0, read:add */
- { EPOLLIN, EPOLL_CTL_DEL }, /* old= 0, write: 0, read:del */
- { 0, -1 }, /* old= 0, write: 0, read:xxx */
- { EPOLLOUT, EPOLL_CTL_ADD }, /* old= 0, write:add, read: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_ADD },/* old= 0, write:add, read:add */
- { EPOLLOUT, EPOLL_CTL_ADD }, /* old= 0, write:add, read:del */
- { 0, -1 }, /* old= 0, write:add, read:xxx */
- { EPOLLOUT, EPOLL_CTL_DEL }, /* old= 0, write:del, read: 0 */
- { EPOLLIN, EPOLL_CTL_ADD }, /* old= 0, write:del, read:add */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },/* old= 0, write:del, read:del */
- { 0, -1 }, /* old= 0, write:del, read:xxx */
- { 0, -1 }, /* old= 0, write:xxx, read: 0 */
- { 0, -1 }, /* old= 0, write:xxx, read:add */
- { 0, -1 }, /* old= 0, write:xxx, read:del */
- { 0, -1 }, /* old= 0, write:xxx, read:xxx */
- { 0, 0 }, /* old= r, write: 0, read: 0 */
- { EPOLLIN, EPOLL_CTL_MOD }, /* old= r, write: 0, read:add */
- { EPOLLIN, EPOLL_CTL_DEL }, /* old= r, write: 0, read:del */
- { 0, -1 }, /* old= r, write: 0, read:xxx */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old= r, write:add, read: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old= r, write:add, read:add */
- { EPOLLOUT, EPOLL_CTL_MOD }, /* old= r, write:add, read:del */
- { 0, -1 }, /* old= r, write:add, read:xxx */
- { EPOLLIN, EPOLL_CTL_MOD }, /* old= r, write:del, read: 0 */
- { EPOLLIN, EPOLL_CTL_MOD }, /* old= r, write:del, read:add */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },/* old= r, write:del, read:del */
- { 0, -1 }, /* old= r, write:del, read:xxx */
- { 0, -1 }, /* old= r, write:xxx, read: 0 */
- { 0, -1 }, /* old= r, write:xxx, read:add */
- { 0, -1 }, /* old= r, write:xxx, read:del */
- { 0, -1 }, /* old= r, write:xxx, read:xxx */
- { 0, 0 }, /* old= w, write: 0, read: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old= w, write: 0, read:add */
- { EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write: 0, read:del */
- { 0, -1 }, /* old= w, write: 0, read:xxx */
- { EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write:add, read: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old= w, write:add, read:add */
- { EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write:add, read:del */
- { 0, -1 }, /* old= w, write:add, read:xxx */
- { EPOLLOUT, EPOLL_CTL_DEL }, /* old= w, write:del, read: 0 */
- { EPOLLIN, EPOLL_CTL_MOD }, /* old= w, write:del, read:add */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },/* old= w, write:del, read:del */
- { 0, -1 }, /* old= w, write:del, read:xxx */
- { 0, -1 }, /* old= w, write:xxx, read: 0 */
- { 0, -1 }, /* old= w, write:xxx, read:add */
- { 0, -1 }, /* old= w, write:xxx, read:del */
- { 0, -1 }, /* old= w, write:xxx, read:xxx */
- { 0, 0 }, /* old=rw, write: 0, read: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old=rw, write: 0, read:add */
- { EPOLLOUT, EPOLL_CTL_MOD }, /* old=rw, write: 0, read:del */
- { 0, -1 }, /* old=rw, write: 0, read:xxx */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old=rw, write:add, read: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old=rw, write:add, read:add */
- { EPOLLOUT, EPOLL_CTL_MOD }, /* old=rw, write:add, read:del */
- { 0, -1 }, /* old=rw, write:add, read:xxx */
- { EPOLLIN, EPOLL_CTL_MOD }, /* old=rw, write:del, read: 0 */
- { EPOLLIN, EPOLL_CTL_MOD }, /* old=rw, write:del, read:add */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },/* old=rw, write:del, read:del */
- { 0, -1 }, /* old=rw, write:del, read:xxx */
- { 0, -1 }, /* old=rw, write:xxx, read: 0 */
- { 0, -1 }, /* old=rw, write:xxx, read:add */
- { 0, -1 }, /* old=rw, write:xxx, read:del */
- { 0, -1 }, /* old=rw, write:xxx, read:xxx */
-};
-
static int
epoll_apply_one_change(struct event_base *base,
struct epollop *epollop,
@@ -408,9 +255,9 @@ epoll_apply_one_change(struct event_base *base,
int op, events = 0;
int idx;
- idx = INDEX(ch);
- op = op_table[idx].op;
- events = op_table[idx].events;
+ idx = EPOLL_OP_TABLE_INDEX(ch);
+ op = epoll_op_table[idx].op;
+ events = epoll_op_table[idx].events;
if (!events) {
EVUTIL_ASSERT(op == 0);
@@ -424,13 +271,14 @@ epoll_apply_one_change(struct event_base *base,
epev.data.fd = ch->fd;
epev.events = events;
if (epoll_ctl(epollop->epfd, op, ch->fd, &epev) == 0) {
- event_debug(("Epoll %s(%d) on fd %d okay. [old events were %d; read change was %d; write change was %d]",
+ event_debug(("Epoll %s(%d) on fd %d okay. [old events were %d; read change was %d; write change was %d; close change was %d]",
epoll_op_to_string(op),
(int)epev.events,
(int)ch->fd,
ch->old_events,
ch->read_change,
- ch->write_change));
+ ch->write_change,
+ ch->close_change));
return 0;
}
@@ -490,7 +338,7 @@ epoll_apply_one_change(struct event_base *base,
break;
}
- event_warn("Epoll %s(%d) on fd %d failed. Old events were %d; read change was %d (%s); write change was %d (%s)",
+ event_warn("Epoll %s(%d) on fd %d failed. Old events were %d; read change was %d (%s); write change was %d (%s); close change was %d (%s)",
epoll_op_to_string(op),
(int)epev.events,
ch->fd,
@@ -498,7 +346,9 @@ epoll_apply_one_change(struct event_base *base,
ch->read_change,
change_to_string(ch->read_change),
ch->write_change,
- change_to_string(ch->write_change));
+ change_to_string(ch->write_change),
+ ch->close_change,
+ change_to_string(ch->close_change));
return -1;
}
@@ -529,13 +379,16 @@ epoll_nochangelist_add(struct event_base *base, evutil_socket_t fd,
struct event_change ch;
ch.fd = fd;
ch.old_events = old;
- ch.read_change = ch.write_change = 0;
+ ch.read_change = ch.write_change = ch.close_change = 0;
if (events & EV_WRITE)
ch.write_change = EV_CHANGE_ADD |
(events & EV_ET);
if (events & EV_READ)
ch.read_change = EV_CHANGE_ADD |
(events & EV_ET);
+ if (events & EV_CLOSED)
+ ch.close_change = EV_CHANGE_ADD |
+ (events & EV_ET);
return epoll_apply_one_change(base, base->evbase, &ch);
}
@@ -547,11 +400,13 @@ epoll_nochangelist_del(struct event_base *base, evutil_socket_t fd,
struct event_change ch;
ch.fd = fd;
ch.old_events = old;
- ch.read_change = ch.write_change = 0;
+ ch.read_change = ch.write_change = ch.close_change = 0;
if (events & EV_WRITE)
ch.write_change = EV_CHANGE_DEL;
if (events & EV_READ)
ch.read_change = EV_CHANGE_DEL;
+ if (events & EV_CLOSED)
+ ch.close_change = EV_CHANGE_DEL;
return epoll_apply_one_change(base, base->evbase, &ch);
}
@@ -636,6 +491,8 @@ epoll_dispatch(struct event_base *base, struct timeval *tv)
ev |= EV_READ;
if (what & EPOLLOUT)
ev |= EV_WRITE;
+ if (what & EPOLLRDHUP)
+ ev |= EV_CLOSED;
}
if (!ev)
diff --git a/epoll_sub.c b/epoll_sub.c
index af35daa7..3f01f6a6 100644
--- a/epoll_sub.c
+++ b/epoll_sub.c
@@ -32,11 +32,20 @@
#include <sys/syscall.h>
#include <sys/epoll.h>
#include <unistd.h>
+#include <errno.h>
int
epoll_create(int size)
{
+#if !defined(__NR_epoll_create) && defined(__NR_epoll_create1)
+ if (size <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ return (syscall(__NR_epoll_create1, 0));
+#else
return (syscall(__NR_epoll_create, size));
+#endif
}
int
@@ -49,5 +58,9 @@ epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
int
epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
{
+#if !defined(__NR_epoll_wait) && defined(__NR_epoll_pwait)
+ return (syscall(__NR_epoll_pwait, epfd, events, maxevents, timeout, NULL, 0));
+#else
return (syscall(__NR_epoll_wait, epfd, events, maxevents, timeout));
+#endif
}
diff --git a/epolltable-internal.h b/epolltable-internal.h
new file mode 100644
index 00000000..da30e097
--- /dev/null
+++ b/epolltable-internal.h
@@ -0,0 +1,1166 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EPOLLTABLE_INTERNAL_H_INCLUDED_
+#define EPOLLTABLE_INTERNAL_H_INCLUDED_
+
+/*
+ Here are the values we're masking off to decide what operations to do.
+ Note that since EV_READ|EV_WRITE.
+
+ Note also that this table is a little sparse, since ADD+DEL is
+ nonsensical ("xxx" in the list below.)
+
+ Note also also that we are shifting old_events by only 5 bits, since
+ EV_READ is 2 and EV_WRITE is 4.
+
+ The table was auto-generated with a python script, according to this
+ pseudocode:[*0]
+
+ If either the read or the write change is add+del:
+ This is impossible; Set op==-1, events=0.
+ Else, if either the read or the write change is add:
+ Set events to 0.
+ If the read change is add, or
+ (the read change is not del, and ev_read is in old_events):
+ Add EPOLLIN to events.
+ If the write change is add, or
+ (the write change is not del, and ev_write is in old_events):
+ Add EPOLLOUT to events.
+
+ If old_events is set:
+ Set op to EPOLL_CTL_MOD [*1,*2]
+ Else:
+ Set op to EPOLL_CTL_ADD [*3]
+
+ Else, if the read or the write change is del:
+ Set op to EPOLL_CTL_DEL.
+ If the read change is del:
+ If the write change is del:
+ Set events to EPOLLIN|EPOLLOUT
+ Else if ev_write is in old_events:
+ Set events to EPOLLOUT
+ Set op to EPOLL_CTL_MOD
+ Else
+ Set events to EPOLLIN
+ Else:
+ {The write change is del.}
+ If ev_read is in old_events:
+ Set events to EPOLLIN
+ Set op to EPOLL_CTL_MOD
+ Else:
+ Set the events to EPOLLOUT
+
+ Else:
+ There is no read or write change; set op to 0 and events to 0.
+
+ The logic is a little tricky, since we had no events set on the fd before,
+ we need to set op="ADD" and set events=the events we want to add. If we
+ had any events set on the fd before, and we want any events to remain on
+ the fd, we need to say op="MOD" and set events=the events we want to
+ remain. But if we want to delete the last event, we say op="DEL" and
+ set events=(any non-null pointer).
+
+ [*0] Actually, the Python script has gotten a bit more complicated, to
+ support EPOLLRDHUP.
+
+ [*1] This MOD is only a guess. MOD might fail with ENOENT if the file was
+ closed and a new file was opened with the same fd. If so, we'll retry
+ with ADD.
+
+ [*2] We can't replace this with a no-op even if old_events is the same as
+ the new events: if the file was closed and reopened, we need to retry
+ with an ADD. (We do a MOD in this case since "no change" is more
+ common than "close and reopen", so we'll usually wind up doing 1
+ syscalls instead of 2.)
+
+ [*3] This ADD is only a guess. There is a fun Linux kernel issue where if
+ you have two fds for the same file (via dup) and you ADD one to an
+ epfd, then close it, then re-create it with the same fd (via dup2 or an
+ unlucky dup), then try to ADD it again, you'll get an EEXIST, since the
+ struct epitem is not actually removed from the struct eventpoll until
+ the file itself is closed.
+
+ EV_CHANGE_ADD==1
+ EV_CHANGE_DEL==2
+ EV_READ ==2
+ EV_WRITE ==4
+ EV_CLOSED ==0x80
+
+ Bit 0: close change is add
+ Bit 1: close change is del
+ Bit 2: read change is add
+ Bit 3: read change is del
+ Bit 4: write change is add
+ Bit 5: write change is del
+ Bit 6: old events had EV_READ
+ Bit 7: old events had EV_WRITE
+ Bit 8: old events had EV_CLOSED
+*/
+
+#define EPOLL_OP_TABLE_INDEX(c) \
+ ( (((c)->close_change&(EV_CHANGE_ADD|EV_CHANGE_DEL))) | \
+ (((c)->read_change&(EV_CHANGE_ADD|EV_CHANGE_DEL)) << 2) | \
+ (((c)->write_change&(EV_CHANGE_ADD|EV_CHANGE_DEL)) << 4) | \
+ (((c)->old_events&(EV_READ|EV_WRITE)) << 5) | \
+ (((c)->old_events&(EV_CLOSED)) << 1) \
+ )
+
+#if EV_READ != 2 || EV_WRITE != 4 || EV_CLOSED != 0x80 || EV_CHANGE_ADD != 1 || EV_CHANGE_DEL != 2
+#error "Libevent's internals changed! Regenerate the op_table in epolltable-internal.h"
+#endif
+
+static const struct operation {
+ int events;
+ int op;
+} epoll_op_table[] = {
+ /* old= 0, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= 0, write: 0, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write: 0, read: 0, close:del */
+ { EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= 0, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= 0, write: 0, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_ADD },
+ /* old= 0, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write: 0, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_ADD },
+ /* old= 0, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= 0, write: 0, read:del, close: 0 */
+ { EPOLLIN, EPOLL_CTL_DEL },
+ /* old= 0, write: 0, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write: 0, read:del, close:del */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= 0, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= 0, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= 0, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= 0, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= 0, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:add, read: 0, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:add, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_ADD },
+ /* old= 0, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= 0, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= 0, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:del, read: 0, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= 0, write:del, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:del, read: 0, close:del */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= 0, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:del, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_ADD },
+ /* old= 0, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_ADD },
+ /* old= 0, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:del, read:del, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= 0, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_ADD },
+ /* old= 0, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= 0, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= 0, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= 0, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= 0, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= 0, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= 0, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= r, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= r, write: 0, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= r, write: 0, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= r, write: 0, read:del, close: 0 */
+ { EPOLLIN, EPOLL_CTL_DEL },
+ /* old= r, write: 0, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write: 0, read:del, close:del */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= r, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= r, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= r, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= r, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= r, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= r, write:add, read: 0, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:add, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= r, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= r, write:add, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= r, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= r, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= r, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= r, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= r, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= r, write:del, read: 0, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write:del, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:del, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= r, write:del, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= r, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= r, write:del, read:del, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= r, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= r, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= r, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= r, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= r, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= r, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= r, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= r, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= r, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= r, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= r, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= r, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= r, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= r, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= r, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= r, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= r, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= r, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= r, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= r, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= r, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= r, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= r, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= w, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= w, write: 0, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= w, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= w, write: 0, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= w, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= w, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= w, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= w, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= w, write:add, read: 0, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:add, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= w, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= w, write:add, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= w, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= w, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= w, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= w, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= w, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= w, write:del, read: 0, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= w, write:del, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:del, read: 0, close:del */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= w, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= w, write:del, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= w, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= w, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= w, write:del, read:del, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= w, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= w, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= w, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= w, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= w, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= w, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= w, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= w, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= w, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= w, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= w, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= w, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= w, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= w, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= w, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= w, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= w, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= w, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= w, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= w, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= w, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= w, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= w, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= rw, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= rw, write: 0, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= rw, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= rw, write: 0, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= rw, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= rw, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= rw, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= rw, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:add, read: 0, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:add, read:del, close: 0 */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= rw, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= rw, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= rw, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:del, read: 0, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:del, read:add, close: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:del, read:del, close: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },
+ /* old= rw, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= rw, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= rw, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= rw, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= rw, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= rw, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= rw, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= rw, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= c, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= c, write: 0, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read: 0, close:del */
+ { EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= c, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= c, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= c, write: 0, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write: 0, read:del, close:del */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= c, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= c, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= c, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= c, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= c, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= c, write:add, read: 0, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= c, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= c, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= c, write:add, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= c, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= c, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= c, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= c, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= c, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= c, write:del, read: 0, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read: 0, close:del */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= c, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= c, write:del, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= c, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= c, write:del, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= c, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= c, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= c, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= c, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= c, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= c, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= c, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= c, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= c, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= c, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= c, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= c, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= c, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= c, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= c, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= c, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= c, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= c, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= c, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= c, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= c, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= c, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cr, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= cr, write: 0, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cr, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cr, write: 0, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write: 0, read:del, close:del */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= cr, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cr, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cr, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cr, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cr, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:add, read: 0, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:add, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cr, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cr, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cr, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:del, read: 0, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:del, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:del, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cr, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= cr, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cr, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cr, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= cr, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= cr, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cr, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cw, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old= cw, write: 0, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cw, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cw, write: 0, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cw, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cw, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cw, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cw, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:add, read: 0, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read: 0, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read: 0, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:add, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old= cw, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cw, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cw, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:del, read: 0, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read: 0, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read: 0, close:del */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= cw, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:del, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:del, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old= cw, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old= cw, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cw, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cw, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old= cw, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old= cw, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old= cw, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old=crw, write: 0, read: 0, close: 0 */
+ { 0, 0 },
+ /* old=crw, write: 0, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read: 0, close:xxx */
+ { 0, 255 },
+ /* old=crw, write: 0, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:add, close:xxx */
+ { 0, 255 },
+ /* old=crw, write: 0, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write: 0, read:del, close:xxx */
+ { 0, 255 },
+ /* old=crw, write: 0, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old=crw, write: 0, read:xxx, close:add */
+ { 0, 255 },
+ /* old=crw, write: 0, read:xxx, close:del */
+ { 0, 255 },
+ /* old=crw, write: 0, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:add, read: 0, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read: 0, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read: 0, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read: 0, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:add, read:add, close: 0 */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:add, close:add */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:add, close:del */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:add, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:add, read:del, close: 0 */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:del, close:add */
+ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:del, close:del */
+ { EPOLLOUT, EPOLL_CTL_MOD },
+ /* old=crw, write:add, read:del, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:add, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:add, read:xxx, close:add */
+ { 0, 255 },
+ /* old=crw, write:add, read:xxx, close:del */
+ { 0, 255 },
+ /* old=crw, write:add, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:del, read: 0, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read: 0, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read: 0, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read: 0, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:del, read:add, close: 0 */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read:add, close:add */
+ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read:add, close:del */
+ { EPOLLIN, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read:add, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:del, read:del, close: 0 */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read:del, close:add */
+ { EPOLLRDHUP, EPOLL_CTL_MOD },
+ /* old=crw, write:del, read:del, close:del */
+ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
+ /* old=crw, write:del, read:del, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:del, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:del, read:xxx, close:add */
+ { 0, 255 },
+ /* old=crw, write:del, read:xxx, close:del */
+ { 0, 255 },
+ /* old=crw, write:del, read:xxx, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:xxx, read: 0, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:xxx, read: 0, close:add */
+ { 0, 255 },
+ /* old=crw, write:xxx, read: 0, close:del */
+ { 0, 255 },
+ /* old=crw, write:xxx, read: 0, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:add, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:add, close:add */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:add, close:del */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:add, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:del, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:del, close:add */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:del, close:del */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:del, close:xxx */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:xxx, close: 0 */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:xxx, close:add */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:xxx, close:del */
+ { 0, 255 },
+ /* old=crw, write:xxx, read:xxx, close:xxx */
+ { 0, 255 },
+};
+
+#endif
diff --git a/evconfig-private.h.cmake b/evconfig-private.h.cmake
new file mode 100644
index 00000000..32f04794
--- /dev/null
+++ b/evconfig-private.h.cmake
@@ -0,0 +1,35 @@
+
+#ifndef EVCONFIG_PRIVATE_H_INCLUDED_
+#define EVCONFIG_PRIVATE_H_INCLUDED_
+
+/* Enable extensions on AIX 3, Interix. */
+#cmakedefine _ALL_SOURCE
+
+/* Enable GNU extensions on systems that have them. */
+#cmakedefine _GNU_SOURCE 1
+
+/* Enable threading extensions on Solaris. */
+#cmakedefine _POSIX_PTHREAD_SEMANTICS 1
+
+/* Enable extensions on HP NonStop. */
+#cmakedefine _TANDEM_SOURCE 1
+
+/* Enable general extensions on Solaris. */
+#cmakedefine __EXTENSIONS__
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#cmakedefine _FILE_OFFSET_BITS 1
+/* Define for large files, on AIX-style hosts. */
+#cmakedefine _LARGE_FILES 1
+
+/* Define to 1 if on MINIX. */
+#cmakedefine _MINIX 1
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+#cmakedefine _POSIX_1_SOURCE 1
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#cmakedefine _POSIX_SOURCE 1
+
+#endif
diff --git a/evdns.c b/evdns.c
index 66a3bff3..4f5fca4d 100644
--- a/evdns.c
+++ b/evdns.c
@@ -92,10 +92,6 @@
#include "event2/event_struct.h"
#include "event2/thread.h"
-#include "event2/bufferevent.h"
-#include "event2/bufferevent_struct.h"
-#include "bufferevent-internal.h"
-
#include "defer-internal.h"
#include "log-internal.h"
#include "mm-internal.h"
@@ -416,6 +412,7 @@ static int evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags,
static int evdns_base_set_option_impl(struct evdns_base *base,
const char *option, const char *val, int flags);
static void evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests);
+static void evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg);
static int strtoint(const char *const str);
@@ -662,6 +659,7 @@ request_finished(struct request *const req, struct request **head, int free_hand
req->ns->requests_inflight == 0 &&
req->base->disable_when_inactive) {
event_del(&req->ns->event);
+ evtimer_del(&req->ns->timeout_event);
}
if (!req->request_appended) {
@@ -907,7 +905,9 @@ reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply)
evutil_format_sockaddr_port_(
(struct sockaddr *)&req->ns->address,
addrbuf, sizeof(addrbuf)));
- break;
+ /* Call the timeout function */
+ evdns_request_timeout_callback(0, 0, req);
+ return;
default:
/* we got a good reply from the nameserver: it is up. */
if (req->handle == req->ns->probe_request) {
@@ -3974,6 +3974,10 @@ evdns_nameserver_free(struct nameserver *server)
event_debug_unassign(&server->event);
if (server->state == 0)
(void) event_del(&server->timeout_event);
+ if (server->probe_request) {
+ evdns_cancel_request(server->base, server->probe_request);
+ server->probe_request = NULL;
+ }
event_debug_unassign(&server->timeout_event);
mm_free(server);
}
@@ -3989,6 +3993,15 @@ evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests)
/* TODO(nickm) we might need to refcount here. */
+ for (server = base->server_head; server; server = server_next) {
+ server_next = server->next;
+ evdns_nameserver_free(server);
+ if (server_next == base->server_head)
+ break;
+ }
+ base->server_head = NULL;
+ base->global_good_nameservers = 0;
+
for (i = 0; i < base->n_req_heads; ++i) {
while (base->req_heads[i]) {
if (fail_requests)
@@ -4003,14 +4016,6 @@ evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests)
}
base->global_requests_inflight = base->global_requests_waiting = 0;
- for (server = base->server_head; server; server = server_next) {
- server_next = server->next;
- evdns_nameserver_free(server);
- if (server_next == base->server_head)
- break;
- }
- base->server_head = NULL;
- base->global_good_nameservers = 0;
if (base->global_search_state) {
for (dom = base->global_search_state->head; dom; dom = dom_next) {
@@ -4045,6 +4050,18 @@ evdns_base_free(struct evdns_base *base, int fail_requests)
}
void
+evdns_base_clear_host_addresses(struct evdns_base *base)
+{
+ struct hosts_entry *victim;
+ EVDNS_LOCK(base);
+ while ((victim = TAILQ_FIRST(&base->hostsdb))) {
+ TAILQ_REMOVE(&base->hostsdb, victim, next);
+ mm_free(victim);
+ }
+ EVDNS_UNLOCK(base);
+}
+
+void
evdns_shutdown(int fail_requests)
{
if (current_base) {
@@ -4652,7 +4669,7 @@ evdns_getaddrinfo(struct evdns_base *dns_base,
data->ipv4_request.r = evdns_base_resolve_ipv4(dns_base,
nodename, 0, evdns_getaddrinfo_gotresolve,
&data->ipv4_request);
- if (want_cname)
+ if (want_cname && data->ipv4_request.r)
data->ipv4_request.r->current_req->put_cname_in_ptr =
&data->cname_result;
}
@@ -4663,7 +4680,7 @@ evdns_getaddrinfo(struct evdns_base *dns_base,
data->ipv6_request.r = evdns_base_resolve_ipv6(dns_base,
nodename, 0, evdns_getaddrinfo_gotresolve,
&data->ipv6_request);
- if (want_cname)
+ if (want_cname && data->ipv6_request.r)
data->ipv6_request.r->current_req->put_cname_in_ptr =
&data->cname_result;
}
diff --git a/event-config.h.cmake b/event-config.h.cmake
new file mode 100644
index 00000000..1efb07ad
--- /dev/null
+++ b/event-config.h.cmake
@@ -0,0 +1,499 @@
+/* event-config.h
+ *
+ * This file was generated by cmake when the makefiles were generated.
+ *
+ * DO NOT EDIT THIS FILE.
+ *
+ * Do not rely on macros in this file existing in later versions.
+ */
+#ifndef EVENT2_EVENT_CONFIG_H_INCLUDED_
+#define EVENT2_EVENT_CONFIG_H_INCLUDED_
+
+/* Numeric representation of the version */
+#define EVENT__NUMERIC_VERSION @EVENT_NUMERIC_VERSION@
+
+#define EVENT__PACKAGE_VERSION @EVENT_PACKAGE_VERSION@
+
+/* Version number of package */
+#define EVENT__VERSION "@EVENT_VERSION@"
+
+/* Name of package */
+#define EVENT__PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define EVENT__PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define EVENT__PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define EVENT__PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define EVENT__PACKAGE_TARNAME ""
+
+/* Define if libevent should build without support for a debug mode */
+#cmakedefine EVENT__DISABLE_DEBUG_MODE 0
+
+/* Define if libevent should not allow replacing the mm functions */
+#cmakedefine EVENT__DISABLE_MM_REPLACEMENT 0
+
+/* Define if libevent should not be compiled with thread support */
+#cmakedefine EVENT__DISABLE_THREAD_SUPPORT 0
+
+/* Define to 1 if you have the `accept4' function. */
+#cmakedefine EVENT__HAVE_ACCEPT4 1
+
+/* Define to 1 if you have the `arc4random' function. */
+#cmakedefine EVENT__HAVE_ARC4RANDOM 1
+
+/* Define to 1 if you have the `arc4random_buf' function. */
+#cmakedefine EVENT__HAVE_ARC4RANDOM_BUF 1
+
+/* Define if clock_gettime is available in libc */
+#cmakedefine EVENT__DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+#cmakedefine EVENT__DNS_USE_GETTIMEOFDAY_FOR_ID 1
+#cmakedefine EVENT__DNS_USE_FTIME_FOR_ID 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#cmakedefine EVENT__HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#cmakedefine EVENT__HAVE_CLOCK_GETTIME 1
+
+/* Define to 1 if you have the declaration of `CTL_KERN'. */
+#cmakedefine EVENT__HAVE_DECL_CTL_KERN 1
+
+/* Define to 1 if you have the declaration of `KERN_ARND'. */
+#cmakedefine EVENT__HAVE_DECL_KERN_ARND 0
+
+/* Define to 1 if you have the declaration of `KERN_RANDOM'. */
+#cmakedefine EVENT__HAVE_DECL_KERN_RANDOM 1
+
+/* Define if /dev/poll is available */
+#cmakedefine EVENT__HAVE_DEVPOLL 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#cmakedefine EVENT__HAVE_NETDB_H 1
+
+/* Define to 1 if fd_mask type is defined */
+#cmakedefine EVENT__HAVE_FD_MASK 1
+
+/* Define to 1 if the <sys/queue.h> header file defines TAILQ_FOREACH. */
+#cmakedefine EVENT__HAVE_TAILQFOREACH 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#cmakedefine EVENT__HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+#cmakedefine EVENT__HAVE_EPOLL 1
+
+/* Define to 1 if you have the `epoll_create1' function. */
+#cmakedefine EVENT__HAVE_EPOLL_CREATE1 1
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+#cmakedefine EVENT__HAVE_EPOLL_CTL 1
+
+/* Define to 1 if you have the `eventfd' function. */
+#cmakedefine EVENT__HAVE_EVENTFD 1
+
+/* Define if your system supports event ports */
+#cmakedefine EVENT__HAVE_EVENT_PORTS 1
+
+/* Define to 1 if you have the `fcntl' function. */
+#cmakedefine EVENT__HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#cmakedefine EVENT__HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#cmakedefine EVENT__HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#cmakedefine EVENT__HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#cmakedefine EVENT__HAVE_GETEUID 1
+
+/* TODO: Check for different gethostname argument counts. CheckPrototypeDefinition.cmake can be used. */
+/* Define this if you have any gethostbyname_r() */
+#cmakedefine EVENT__HAVE_GETHOSTBYNAME_R 1
+
+/* Define this if gethostbyname_r takes 3 arguments */
+#cmakedefine EVENT__HAVE_GETHOSTBYNAME_R_3_ARG 1
+
+/* Define this if gethostbyname_r takes 5 arguments */
+#cmakedefine EVENT__HAVE_GETHOSTBYNAME_R_5_ARG 1
+
+/* Define this if gethostbyname_r takes 6 arguments */
+#cmakedefine EVENT__HAVE_GETHOSTBYNAME_R_6_ARG 1
+
+/* Define to 1 if you have the `getifaddrs' function. */
+#cmakedefine EVENT__HAVE_GETIFADDRS 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#cmakedefine EVENT__HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getprotobynumber' function. */
+#cmakedefine EVENT__HAVE_GETPROTOBYNUMBER 1
+
+/* Define to 1 if you have the `getservbyname' function. */
+#cmakedefine EVENT__HAVE_GETSERVBYNAME 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#cmakedefine EVENT__HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#cmakedefine EVENT__HAVE_IFADDRS_H 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#cmakedefine EVENT__HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the `inet_pton' function. */
+#cmakedefine EVENT__HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#cmakedefine EVENT__HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+#cmakedefine EVENT__HAVE_ISSETUGID 1
+
+/* Define to 1 if you have the `kqueue' function. */
+#cmakedefine EVENT__HAVE_KQUEUE 1
+
+/* Define if the system has zlib */
+#cmakedefine EVENT__HAVE_LIBZ 1
+
+/* Define to 1 if you have the `mach_absolute_time' function. */
+#cmakedefine EVENT__HAVE_MACH_ABSOLUTE_TIME 1
+
+/* Define to 1 if you have the <mach/mach_time.h> header file. */
+#cmakedefine EVENT__HAVE_MACH_MACH_TIME_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#cmakedefine EVENT__HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mmap' function. */
+#cmakedefine EVENT__HAVE_MMAP 1
+
+/* Define to 1 if you have the `nanosleep' function. */
+#cmakedefine EVENT__HAVE_NANOSLEEP 1
+
+/* Define to 1 if you have the `usleep' function. */
+#cmakedefine EVENT__HAVE_USLEEP 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#cmakedefine EVENT__HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+#cmakedefine EVENT__HAVE_NETINET_IN6_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#cmakedefine EVENT__HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#cmakedefine EVENT__HAVE_NETINET_TCP_H 1
+
+/* Define if the system has openssl */
+#cmakedefine EVENT__HAVE_OPENSSL 1
+
+/* Defines if the system has zlib */
+#cmakedefine EVENT__HAVE_ZLIB 1
+
+/* Define to 1 if you have the `pipe' function. */
+#cmakedefine EVENT__HAVE_PIPE 1
+
+/* Define to 1 if you have the `pipe2' function. */
+#cmakedefine EVENT__HAVE_PIPE2 1
+
+/* Define to 1 if you have the `poll' function. */
+#cmakedefine EVENT__HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#cmakedefine EVENT__HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+#cmakedefine EVENT__HAVE_PORT_CREATE 1
+
+/* Define to 1 if you have the <port.h> header file. */
+#cmakedefine EVENT__HAVE_PORT_H 1
+
+/* Define if you have POSIX threads libraries and header files. */
+#cmakedefine EVENT__HAVE_PTHREAD 1
+
+/* Define if we have pthreads on this system */
+#cmakedefine EVENT__HAVE_PTHREADS 1
+
+/* Define to 1 if you have the `putenv' function. */
+#cmakedefine EVENT__HAVE_PUTENV 1
+
+/* Define to 1 if the system has the type `sa_family_t'. */
+#cmakedefine EVENT__HAVE_SA_FAMILY_T 1
+
+/* Define to 1 if you have the `select' function. */
+#cmakedefine EVENT__HAVE_SELECT 1
+
+/* Define to 1 if you have the `setenv' function. */
+#cmakedefine EVENT__HAVE_SETENV 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#cmakedefine EVENT__HAVE_SETFD 1
+
+/* Define to 1 if you have the `setrlimit' function. */
+#cmakedefine EVENT__HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the `sendfile' function. */
+#cmakedefine EVENT__HAVE_SENDFILE 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#cmakedefine EVENT__HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#cmakedefine EVENT__HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#cmakedefine EVENT__HAVE_SIGNAL 1
+
+/* Define to 1 if you have the `splice' function. */
+#cmakedefine EVENT__HAVE_SPLICE 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#cmakedefine EVENT__HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#cmakedefine EVENT__HAVE_STDDEF_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#cmakedefine EVENT__HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#cmakedefine EVENT__HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#cmakedefine EVENT__HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#cmakedefine EVENT__HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#cmakedefine EVENT__HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#cmakedefine EVENT__HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#cmakedefine EVENT__HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#cmakedefine EVENT__HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct addrinfo'. */
+#cmakedefine EVENT__HAVE_STRUCT_ADDRINFO 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#cmakedefine EVENT__HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if `s6_addr16' is member of `struct in6_addr'. */
+#cmakedefine EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR16 1
+
+/* Define to 1 if `s6_addr32' is member of `struct in6_addr'. */
+#cmakedefine EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR32 1
+
+/* Define to 1 if the system has the type `struct sockaddr_in6'. */
+#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_IN6 1
+
+/* Define to 1 if `sin6_len' is member of `struct sockaddr_in6'. */
+#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN 1
+
+/* Define to 1 if `sin_len' is member of `struct sockaddr_in'. */
+#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 1
+
+/* Define to 1 if the system has the type `struct sockaddr_storage'. */
+#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */
+#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1
+
+/* Define to 1 if `__ss_family' is a member of `struct sockaddr_storage'. */
+#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY 1
+
+/* Define to 1 if you have the `sysctl' function. */
+#cmakedefine EVENT__HAVE_SYSCTL 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_DEVPOLL_H 1
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_EPOLL_H 1
+
+/* Define to 1 if you have the <sys/eventfd.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_EVENTFD_H 1
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_EVENT_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/sendfile.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_SENDFILE_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/sysctl.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_SYSCTL_H 1
+
+/* Define to 1 if you have the <sys/timerfd.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_TIMERFD_H */
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/wait.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_WAIT_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#cmakedefine EVENT__HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#cmakedefine EVENT__HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#cmakedefine EVENT__HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#cmakedefine EVENT__HAVE_TIMERCMP 1
+
+/* Define to 1 if you have the `timerfd_create' function. */
+#cmakedefine EVENT__HAVE_TIMERFD_CREATE 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#cmakedefine EVENT__HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#cmakedefine EVENT__HAVE_UINT8_T 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#cmakedefine EVENT__HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#cmakedefine EVENT__HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#cmakedefine EVENT__HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uintptr_t'. */
+#cmakedefine EVENT__HAVE_UINTPTR_T 1
+
+/* Define to 1 if you have the `umask' function. */
+#cmakedefine EVENT__HAVE_UMASK 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#cmakedefine EVENT__HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `unsetenv' function. */
+#cmakedefine EVENT__HAVE_UNSETENV 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#cmakedefine EVENT__HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+#cmakedefine EVENT__HAVE_WORKING_KQUEUE 1
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+#cmakedefine EVENT__PTHREAD_CREATE_JOINABLE ${EVENT__PTHREAD_CREATE_JOINABLE}
+
+/* The size of `pthread_t', as computed by sizeof. */
+#cmakedefine EVENT__SIZEOF_PTHREAD_T ${EVENT__SIZEOF_PTHREAD_T}
+
+/* The size of a `int', as computed by sizeof. */
+#cmakedefine EVENT__SIZEOF_INT ${EVENT__SIZEOF_INT}
+
+/* The size of a `long', as computed by sizeof. */
+#cmakedefine EVENT__SIZEOF_LONG ${EVENT__SIZEOF_LONG}
+
+/* The size of a `long long', as computed by sizeof. */
+#cmakedefine EVENT__SIZEOF_LONG_LONG ${EVENT__SIZEOF_LONG_LONG}
+
+/* The size of `off_t', as computed by sizeof. */
+#cmakedefine EVENT__SIZEOF_OFF_T ${EVENT__SIZEOF_OFF_T}
+
+/* The size of a `short', as computed by sizeof. */
+#cmakedefine EVENT__SIZEOF_SHORT ${EVENT__SIZEOF_SHORT}
+
+/* The size of `size_t', as computed by sizeof. */
+#cmakedefine EVENT__SIZEOF_SIZE_T ${EVENT__SIZEOF_SIZE_T}
+
+/* Define to 1 if you have the ANSI C header files. */
+#cmakedefine EVENT__STDC_HEADERS ${EVENT__STDC_HEADERS}
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#cmakedefine EVENT__TIME_WITH_SYS_TIME ${EVENT__TIME_WITH_SYS_TIME}
+
+/* The size of `socklen_t', as computed by sizeof. */
+#cmakedefine EVENT__SIZEOF_SOCKLEN_T ${EVENT__SIZEOF_SOCKLEN_T}
+
+/* The size of 'void *', as computer by sizeof */
+#cmakedefine EVENT__SIZEOF_VOID_P ${EVENT__SIZEOF_VOID_P}
+
+/* Define to appropriate substitute if compiler doesnt have __func__ */
+#cmakedefine EVENT____func__ ${EVENT____func__}
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#cmakedefine EVENT___FILE_OFFSET_BITS ${EVENT___FILE_OFFSET_BITS}
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef EVENT__const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#cmakedefine EVENT__inline ${EVENT__inline}
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+#cmakedefine EVENT__pid_t ${EVENT__pid_t}
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#cmakedefine EVENT__size_t ${EVENT__size_t}
+
+/* Define to unsigned int if you dont have it */
+#cmakedefine EVENT__socklen_t ${EVENT__socklen_t}
+
+/* Define to `int' if <sys/types.h> does not define. */
+#cmakedefine EVENT__ssize_t ${EVENT__ssize_t}
+
+#cmakedefine EVENT__NEED_DLLIMPORT ${EVENT__NEED_DLLIMPORT}
+
+#endif
diff --git a/event-internal.h b/event-internal.h
index bce96df5..5208fbe0 100644
--- a/event-internal.h
+++ b/event-internal.h
@@ -224,10 +224,16 @@ struct event_base {
/** Number of virtual events */
int virtual_event_count;
+ /** Maximum number of virtual events active */
+ int virtual_event_count_max;
/** Number of total events added to this event_base */
int event_count;
+ /** Maximum number of total events added to this event_base */
+ int event_count_max;
/** Number of total events active in this event_base */
int event_count_active;
+ /** Maximum number of total events active in this event_base */
+ int event_count_active_max;
/** Set if we should terminate the loop once we're done processing
* events. */
diff --git a/event.c b/event.c
index e50616c4..a5e8d0b1 100644
--- a/event.c
+++ b/event.c
@@ -1204,6 +1204,36 @@ event_base_get_num_events(struct event_base *base, unsigned int type)
return r;
}
+int
+event_base_get_max_events(struct event_base *base, unsigned int type, int clear)
+{
+ int r = 0;
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+
+ if (type & EVENT_BASE_COUNT_ACTIVE) {
+ r += base->event_count_active_max;
+ if (clear)
+ base->event_count_active_max = 0;
+ }
+
+ if (type & EVENT_BASE_COUNT_VIRTUAL) {
+ r += base->virtual_event_count_max;
+ if (clear)
+ base->virtual_event_count_max = 0;
+ }
+
+ if (type & EVENT_BASE_COUNT_ADDED) {
+ r += base->event_count_max;
+ if (clear)
+ base->event_count_max = 0;
+ }
+
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+
+ return r;
+}
+
/* Returns true iff we're currently watching any events. */
static int
event_haveevents(struct event_base *base)
@@ -1424,6 +1454,10 @@ done:
static inline void
event_persist_closure(struct event_base *base, struct event *ev)
{
+
+ // Define our callback, we use this to store our callback before it's executed
+ void (*evcb_callback)(evutil_socket_t, short, void *);
+
/* reschedule the persistent event if we have a timeout. */
if (ev->ev_io_timeout.tv_sec || ev->ev_io_timeout.tv_usec) {
/* If there was a timeout, we want it to run at an interval of
@@ -1465,8 +1499,15 @@ event_persist_closure(struct event_base *base, struct event *ev)
run_at.tv_usec |= usec_mask;
event_add_nolock_(ev, &run_at, 1);
}
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- (*ev->ev_callback)(ev->ev_fd, ev->ev_res, ev->ev_arg);
+
+ // Save our callback before we release the lock
+ evcb_callback = *ev->ev_callback;
+
+ // Release the lock
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+
+ // Execute the callback
+ (evcb_callback)(ev->ev_fd, ev->ev_res, ev->ev_arg);
}
/*
@@ -1496,10 +1537,11 @@ event_process_active_single_queue(struct event_base *base,
else
event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
event_debug((
- "event_process_active: event: %p, %s%scall %p",
+ "event_process_active: event: %p, %s%s%scall %p",
ev,
ev->ev_res & EV_READ ? "EV_READ " : " ",
ev->ev_res & EV_WRITE ? "EV_WRITE " : " ",
+ ev->ev_res & EV_CLOSED ? "EV_CLOSED " : " ",
ev->ev_callback));
} else {
event_queue_remove_active(base, evcb);
@@ -1526,34 +1568,42 @@ event_process_active_single_queue(struct event_base *base,
EVUTIL_ASSERT(ev != NULL);
event_persist_closure(base, ev);
break;
- case EV_CLOSURE_EVENT:
+ case EV_CLOSURE_EVENT: {
+ void (*evcb_callback)(evutil_socket_t, short, void *) = *ev->ev_callback;
EVUTIL_ASSERT(ev != NULL);
EVBASE_RELEASE_LOCK(base, th_base_lock);
- (*ev->ev_callback)(
- ev->ev_fd, ev->ev_res, ev->ev_arg);
- break;
- case EV_CLOSURE_CB_SELF:
+ evcb_callback(ev->ev_fd, ev->ev_res, ev->ev_arg);
+ }
+ break;
+ case EV_CLOSURE_CB_SELF: {
+ void (*evcb_selfcb)(struct event_callback *, void *) = evcb->evcb_cb_union.evcb_selfcb;
EVBASE_RELEASE_LOCK(base, th_base_lock);
- evcb->evcb_cb_union.evcb_selfcb(evcb, evcb->evcb_arg);
- break;
+ evcb_selfcb(evcb, evcb->evcb_arg);
+ }
+ break;
case EV_CLOSURE_EVENT_FINALIZE:
- case EV_CLOSURE_EVENT_FINALIZE_FREE:
- base->current_event = NULL;
+ case EV_CLOSURE_EVENT_FINALIZE_FREE: {
+ void (*evcb_evfinalize)(struct event *, void *);
+ int evcb_closure = evcb->evcb_closure;
EVUTIL_ASSERT(ev != NULL);
+ base->current_event = NULL;
+ evcb_evfinalize = ev->ev_evcallback.evcb_cb_union.evcb_evfinalize;
EVUTIL_ASSERT((evcb->evcb_flags & EVLIST_FINALIZING));
EVBASE_RELEASE_LOCK(base, th_base_lock);
- ev->ev_evcallback.evcb_cb_union.evcb_evfinalize(ev, ev->ev_arg);
+ evcb_evfinalize(ev, ev->ev_arg);
event_debug_note_teardown_(ev);
- if (evcb->evcb_closure == EV_CLOSURE_EVENT_FINALIZE_FREE)
+ if (evcb_closure == EV_CLOSURE_EVENT_FINALIZE_FREE)
mm_free(ev);
- break;
- case EV_CLOSURE_CB_FINALIZE:
+ }
+ break;
+ case EV_CLOSURE_CB_FINALIZE: {
+ void (*evcb_cbfinalize)(struct event_callback *, void *) = evcb->evcb_cb_union.evcb_cbfinalize;
base->current_event = NULL;
EVUTIL_ASSERT((evcb->evcb_flags & EVLIST_FINALIZING));
EVBASE_RELEASE_LOCK(base, th_base_lock);
- base->current_event = NULL;
- evcb->evcb_cb_union.evcb_cbfinalize(evcb, evcb->evcb_arg);
- break;
+ evcb_cbfinalize(evcb, evcb->evcb_arg);
+ }
+ break;
default:
EVUTIL_ASSERT(0);
}
@@ -1901,7 +1951,7 @@ event_base_once(struct event_base *base, evutil_socket_t fd, short events,
eonce->cb = callback;
eonce->arg = arg;
- if ((events & (EV_TIMEOUT|EV_SIGNAL|EV_READ|EV_WRITE)) == EV_TIMEOUT) {
+ if ((events & (EV_TIMEOUT|EV_SIGNAL|EV_READ|EV_WRITE|EV_CLOSED)) == EV_TIMEOUT) {
evtimer_assign(&eonce->ev, base, event_once_cb, eonce);
if (tv == NULL || ! evutil_timerisset(tv)) {
@@ -1911,8 +1961,8 @@ event_base_once(struct event_base *base, evutil_socket_t fd, short events,
* it fast (and order-preserving). */
activate = 1;
}
- } else if (events & (EV_READ|EV_WRITE)) {
- events &= EV_READ|EV_WRITE;
+ } else if (events & (EV_READ|EV_WRITE|EV_CLOSED)) {
+ events &= EV_READ|EV_WRITE|EV_CLOSED;
event_assign(&eonce->ev, base, fd, events, event_once_cb, eonce);
} else {
@@ -1962,9 +2012,9 @@ event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, shor
ev->ev_pncalls = NULL;
if (events & EV_SIGNAL) {
- if ((events & (EV_READ|EV_WRITE)) != 0) {
+ if ((events & (EV_READ|EV_WRITE|EV_CLOSED)) != 0) {
event_warnx("%s: EV_SIGNAL is not compatible with "
- "EV_READ or EV_WRITE", __func__);
+ "EV_READ, EV_WRITE or EV_CLOSED", __func__);
return -1;
}
ev->ev_closure = EV_CLOSURE_EVENT_SIGNAL;
@@ -2214,13 +2264,13 @@ event_pending(const struct event *ev, short event, struct timeval *tv)
event_debug_assert_is_setup_(ev);
if (ev->ev_flags & EVLIST_INSERTED)
- flags |= (ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL));
+ flags |= (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL));
if (ev->ev_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))
flags |= ev->ev_res;
if (ev->ev_flags & EVLIST_TIMEOUT)
flags |= EV_TIMEOUT;
- event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_SIGNAL);
+ event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL);
/* See if there is a timeout that we should report */
if (tv != NULL && (flags & event & EV_TIMEOUT)) {
@@ -2434,11 +2484,12 @@ event_add_nolock_(struct event *ev, const struct timeval *tv,
event_debug_assert_is_setup_(ev);
event_debug((
- "event_add: event: %p (fd "EV_SOCK_FMT"), %s%s%scall %p",
+ "event_add: event: %p (fd "EV_SOCK_FMT"), %s%s%s%scall %p",
ev,
EV_SOCK_ARG(ev->ev_fd),
ev->ev_events & EV_READ ? "EV_READ " : " ",
ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
+ ev->ev_events & EV_CLOSED ? "EV_CLOSED " : " ",
tv ? "EV_TIMEOUT " : " ",
ev->ev_callback));
@@ -2472,9 +2523,9 @@ event_add_nolock_(struct event *ev, const struct timeval *tv,
}
#endif
- if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
+ if ((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL)) &&
!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))) {
- if (ev->ev_events & (EV_READ|EV_WRITE))
+ if (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED))
res = evmap_io_add_(base, ev->ev_fd, ev);
else if (ev->ev_events & EV_SIGNAL)
res = evmap_signal_add_(base, (int)ev->ev_fd, ev);
@@ -2701,7 +2752,7 @@ event_del_nolock_(struct event *ev, int blocking)
if (ev->ev_flags & EVLIST_INSERTED) {
event_queue_remove_inserted(base, ev);
- if (ev->ev_events & (EV_READ|EV_WRITE))
+ if (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED))
res = evmap_io_del_(base, ev->ev_fd, ev);
else
res = evmap_signal_del_(base, (int)ev->ev_fd, ev);
@@ -3026,14 +3077,23 @@ timeout_process(struct event_base *base)
#if (EVLIST_INTERNAL >> 4) != 1
#error "Mismatch for value of EVLIST_INTERNAL"
#endif
+
+#ifndef MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#define MAX_EVENT_COUNT(var, v) var = MAX(var, v)
+
/* These are a fancy way to spell
if (flags & EVLIST_INTERNAL)
base->event_count--/++;
*/
#define DECR_EVENT_COUNT(base,flags) \
((base)->event_count -= (~((flags) >> 4) & 1))
-#define INCR_EVENT_COUNT(base,flags) \
- ((base)->event_count += (~((flags) >> 4) & 1))
+#define INCR_EVENT_COUNT(base,flags) do { \
+ ((base)->event_count += (~((flags) >> 4) & 1)); \
+ MAX_EVENT_COUNT((base)->event_count_max, (base)->event_count); \
+} while (0)
static void
event_queue_remove_inserted(struct event_base *base, struct event *ev)
@@ -3203,6 +3263,7 @@ event_queue_insert_active(struct event_base *base, struct event_callback *evcb)
evcb->evcb_flags |= EVLIST_ACTIVE;
base->event_count_active++;
+ MAX_EVENT_COUNT(base->event_count_active_max, base->event_count_active);
EVUTIL_ASSERT(evcb->evcb_pri < base->nactivequeues);
TAILQ_INSERT_TAIL(&base->activequeues[evcb->evcb_pri],
evcb, evcb_active_next);
@@ -3220,6 +3281,7 @@ event_queue_insert_active_later(struct event_base *base, struct event_callback *
INCR_EVENT_COUNT(base, evcb->evcb_flags);
evcb->evcb_flags |= EVLIST_ACTIVE_LATER;
base->event_count_active++;
+ MAX_EVENT_COUNT(base->event_count_active_max, base->event_count_active);
EVUTIL_ASSERT(evcb->evcb_pri < base->nactivequeues);
TAILQ_INSERT_TAIL(&base->active_later_queue, evcb, evcb_active_next);
}
@@ -3561,10 +3623,11 @@ dump_inserted_event_fn(const struct event_base *base, const struct event *e, voi
if (! (e->ev_flags & (EVLIST_INSERTED|EVLIST_TIMEOUT)))
return 0;
- fprintf(output, " %p [%s "EV_SOCK_FMT"]%s%s%s%s%s",
+ fprintf(output, " %p [%s "EV_SOCK_FMT"]%s%s%s%s%s%s",
(void*)e, gloss, EV_SOCK_ARG(e->ev_fd),
(e->ev_events&EV_READ)?" Read":"",
(e->ev_events&EV_WRITE)?" Write":"",
+ (e->ev_events&EV_CLOSED)?" EOF":"",
(e->ev_events&EV_SIGNAL)?" Signal":"",
(e->ev_events&EV_PERSIST)?" Persist":"",
(e->ev_flags&EVLIST_INTERNAL)?" Internal":"");
@@ -3593,10 +3656,11 @@ dump_active_event_fn(const struct event_base *base, const struct event *e, void
if (! (e->ev_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER)))
return 0;
- fprintf(output, " %p [%s "EV_SOCK_FMT", priority=%d]%s%s%s%s active%s%s\n",
+ fprintf(output, " %p [%s "EV_SOCK_FMT", priority=%d]%s%s%s%s%s active%s%s\n",
(void*)e, gloss, EV_SOCK_ARG(e->ev_fd), e->ev_pri,
(e->ev_res&EV_READ)?" Read":"",
(e->ev_res&EV_WRITE)?" Write":"",
+ (e->ev_res&EV_CLOSED)?" EOF":"",
(e->ev_res&EV_SIGNAL)?" Signal":"",
(e->ev_res&EV_TIMEOUT)?" Timeout":"",
(e->ev_flags&EVLIST_INTERNAL)?" [Internal]":"",
@@ -3633,10 +3697,28 @@ event_base_dump_events(struct event_base *base, FILE *output)
}
void
+event_base_active_by_fd(struct event_base *base, evutil_socket_t fd, short events)
+{
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ evmap_io_active_(base, fd, events & (EV_READ|EV_WRITE|EV_CLOSED));
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+}
+
+void
+event_base_active_by_signal(struct event_base *base, int sig)
+{
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ evmap_signal_active_(base, sig, 1);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+}
+
+
+void
event_base_add_virtual_(struct event_base *base)
{
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
base->virtual_event_count++;
+ MAX_EVENT_COUNT(base->virtual_event_count_max, base->virtual_event_count);
EVBASE_RELEASE_LOCK(base, th_base_lock);
}
diff --git a/event_tagging.c b/event_tagging.c
index 7edd3da5..64b100b8 100644
--- a/event_tagging.c
+++ b/event_tagging.c
@@ -207,10 +207,19 @@ decode_tag_internal(ev_uint32_t *ptag, struct evbuffer *evbuf, int dodrain)
*/
data = evbuffer_pullup(
evbuf, len < sizeof(number) + 1 ? len : sizeof(number) + 1);
+ if (!data)
+ return (-1);
while (count++ < len) {
ev_uint8_t lower = *data++;
- number |= (lower & 0x7f) << shift;
+ if (shift >= 28) {
+ /* Make sure it fits into 32 bits */
+ if (shift > 28)
+ return (-1);
+ if ((lower & 0x7f) > 15)
+ return (-1);
+ }
+ number |= (lower & (unsigned)0x7f) << shift;
shift += 7;
if (!(lower & 0x80)) {
@@ -313,6 +322,8 @@ do { \
\
/* XXX(niels): faster? */ \
data = evbuffer_pullup(evbuf, offset + 1) + offset; \
+ if (!data) \
+ return (-1); \
\
nibbles = ((data[0] & 0xf0) >> 4) + 1; \
if (nibbles > maxnibbles || (nibbles >> 1) + 1 > len) \
@@ -320,6 +331,8 @@ do { \
len = (nibbles >> 1) + 1; \
\
data = evbuffer_pullup(evbuf, offset + len) + offset; \
+ if (!data) \
+ return (-1); \
\
while (nibbles > 0) { \
number <<= 4; \
diff --git a/evmap.c b/evmap.c
index 13305feb..3f76dd0a 100644
--- a/evmap.c
+++ b/evmap.c
@@ -59,6 +59,7 @@ struct evmap_io {
struct event_dlist events;
ev_uint16_t nread;
ev_uint16_t nwrite;
+ ev_uint16_t nclose;
};
/* An entry for an evmap_signal list: notes all the events that want to know
@@ -255,6 +256,7 @@ evmap_io_init(struct evmap_io *entry)
LIST_INIT(&entry->events);
entry->nread = 0;
entry->nwrite = 0;
+ entry->nclose = 0;
}
@@ -266,7 +268,7 @@ evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev)
const struct eventop *evsel = base->evsel;
struct event_io_map *io = &base->io;
struct evmap_io *ctx = NULL;
- int nread, nwrite, retval = 0;
+ int nread, nwrite, nclose, retval = 0;
short res = 0, old = 0;
struct event *old_ev;
@@ -286,11 +288,14 @@ evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev)
nread = ctx->nread;
nwrite = ctx->nwrite;
+ nclose = ctx->nclose;
if (nread)
old |= EV_READ;
if (nwrite)
old |= EV_WRITE;
+ if (nclose)
+ old |= EV_CLOSED;
if (ev->ev_events & EV_READ) {
if (++nread == 1)
@@ -300,7 +305,11 @@ evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev)
if (++nwrite == 1)
res |= EV_WRITE;
}
- if (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff)) {
+ if (ev->ev_events & EV_CLOSED) {
+ if (++nclose == 1)
+ res |= EV_CLOSED;
+ }
+ if (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff || nclose > 0xffff)) {
event_warnx("Too many events reading or writing on fd %d",
(int)fd);
return -1;
@@ -326,6 +335,7 @@ evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev)
ctx->nread = (ev_uint16_t) nread;
ctx->nwrite = (ev_uint16_t) nwrite;
+ ctx->nclose = (ev_uint16_t) nclose;
LIST_INSERT_HEAD(&ctx->events, ev, ev_io_next);
return (retval);
@@ -339,7 +349,7 @@ evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev)
const struct eventop *evsel = base->evsel;
struct event_io_map *io = &base->io;
struct evmap_io *ctx;
- int nread, nwrite, retval = 0;
+ int nread, nwrite, nclose, retval = 0;
short res = 0, old = 0;
if (fd < 0)
@@ -356,11 +366,14 @@ evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev)
nread = ctx->nread;
nwrite = ctx->nwrite;
+ nclose = ctx->nclose;
if (nread)
old |= EV_READ;
if (nwrite)
old |= EV_WRITE;
+ if (nclose)
+ old |= EV_CLOSED;
if (ev->ev_events & EV_READ) {
if (--nread == 0)
@@ -372,6 +385,11 @@ evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev)
res |= EV_WRITE;
EVUTIL_ASSERT(nwrite >= 0);
}
+ if (ev->ev_events & EV_CLOSED) {
+ if (--nclose == 0)
+ res |= EV_CLOSED;
+ EVUTIL_ASSERT(nclose >= 0);
+ }
if (res) {
void *extra = ((char*)ctx) + sizeof(struct evmap_io);
@@ -384,6 +402,7 @@ evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev)
ctx->nread = nread;
ctx->nwrite = nwrite;
+ ctx->nclose = nclose;
LIST_REMOVE(ev, ev_io_next);
return (retval);
@@ -397,11 +416,13 @@ evmap_io_active_(struct event_base *base, evutil_socket_t fd, short events)
struct event *ev;
#ifndef EVMAP_USE_HT
- EVUTIL_ASSERT(fd < io->nentries);
+ if (fd < 0 || fd >= io->nentries)
+ return;
#endif
GET_IO_SLOT(ctx, io, fd, evmap_io);
- EVUTIL_ASSERT(ctx);
+ if (NULL == ctx)
+ return;
LIST_FOREACH(ev, &ctx->events, ev_io_next) {
if (ev->ev_events & events)
event_active_nolock_(ev, ev->ev_events & events, 1);
@@ -472,9 +493,12 @@ evmap_signal_active_(struct event_base *base, evutil_socket_t sig, int ncalls)
struct evmap_signal *ctx;
struct event *ev;
- EVUTIL_ASSERT(sig < map->nentries);
+ if (sig < 0 || sig >= map->nentries)
+ return;
GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
+ if (!ctx)
+ return;
LIST_FOREACH(ev, &ctx->events, ev_signal_next)
event_active_nolock_(ev, EV_SIGNAL, ncalls);
}
@@ -584,6 +608,8 @@ evmap_io_reinit_iter_fn(struct event_base *base, evutil_socket_t fd,
events |= EV_READ;
if (ctx->nwrite)
events |= EV_WRITE;
+ if (ctx->nclose)
+ events |= EV_CLOSED;
if (evsel->fdinfo_len)
memset(extra, 0, evsel->fdinfo_len);
if (events &&
@@ -851,6 +877,10 @@ event_changelist_add_(struct event_base *base, evutil_socket_t fd, short old, sh
change->write_change = EV_CHANGE_ADD |
(events & (EV_ET|EV_PERSIST|EV_SIGNAL));
}
+ if (events & EV_CLOSED) {
+ change->close_change = EV_CHANGE_ADD |
+ (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
+ }
event_changelist_check(base);
return (0);
@@ -897,6 +927,12 @@ event_changelist_del_(struct event_base *base, evutil_socket_t fd, short old, sh
else
change->write_change = EV_CHANGE_DEL;
}
+ if (events & EV_CLOSED) {
+ if (!(change->old_events & EV_CLOSED))
+ change->close_change = 0;
+ else
+ change->close_change = EV_CHANGE_DEL;
+ }
event_changelist_check(base);
return (0);
@@ -910,7 +946,7 @@ evmap_io_check_integrity_fn(struct event_base *base, evutil_socket_t fd,
struct evmap_io *io_info, void *arg)
{
struct event *ev;
- int n_read = 0, n_write = 0;
+ int n_read = 0, n_write = 0, n_close = 0;
/* First, make sure the list itself isn't corrupt. Otherwise,
* running LIST_FOREACH could be an exciting adventure. */
@@ -920,15 +956,18 @@ evmap_io_check_integrity_fn(struct event_base *base, evutil_socket_t fd,
EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
EVUTIL_ASSERT(ev->ev_fd == fd);
EVUTIL_ASSERT(!(ev->ev_events & EV_SIGNAL));
- EVUTIL_ASSERT((ev->ev_events & (EV_READ|EV_WRITE)));
+ EVUTIL_ASSERT((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
if (ev->ev_events & EV_READ)
++n_read;
if (ev->ev_events & EV_WRITE)
++n_write;
+ if (ev->ev_events & EV_CLOSED)
+ ++n_close;
}
EVUTIL_ASSERT(n_read == io_info->nread);
EVUTIL_ASSERT(n_write == io_info->nwrite);
+ EVUTIL_ASSERT(n_close == io_info->nclose);
return 0;
}
@@ -947,7 +986,7 @@ evmap_signal_check_integrity_fn(struct event_base *base,
EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
EVUTIL_ASSERT(ev->ev_fd == signum);
EVUTIL_ASSERT((ev->ev_events & EV_SIGNAL));
- EVUTIL_ASSERT(!(ev->ev_events & (EV_READ|EV_WRITE)));
+ EVUTIL_ASSERT(!(ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
}
return 0;
}
diff --git a/evrpc-internal.h b/evrpc-internal.h
index e53d06e0..9eb37638 100644
--- a/evrpc-internal.h
+++ b/evrpc-internal.h
@@ -27,6 +27,7 @@
#ifndef EVRPC_INTERNAL_H_INCLUDED_
#define EVRPC_INTERNAL_H_INCLUDED_
+#include "event2/http.h"
#include "http-internal.h"
struct evrpc;
diff --git a/evrpc.c b/evrpc.c
index 8d8ecc5a..2443ab27 100644
--- a/evrpc.c
+++ b/evrpc.c
@@ -329,8 +329,7 @@ evrpc_request_cb(struct evhttp_request *req, void *arg)
return;
error:
- if (rpc_state != NULL)
- evrpc_reqstate_free_(rpc_state);
+ evrpc_reqstate_free_(rpc_state);
evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
return;
}
@@ -372,8 +371,7 @@ evrpc_request_cb_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
return;
error:
- if (rpc_state != NULL)
- evrpc_reqstate_free_(rpc_state);
+ evrpc_reqstate_free_(rpc_state);
evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
return;
}
@@ -454,8 +452,7 @@ evrpc_request_done(struct evrpc_req_generic *rpc_state)
return;
error:
- if (rpc_state != NULL)
- evrpc_reqstate_free_(rpc_state);
+ evrpc_reqstate_free_(rpc_state);
evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
return;
}
@@ -495,8 +492,7 @@ evrpc_request_done_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
return;
error:
- if (rpc_state != NULL)
- evrpc_reqstate_free_(rpc_state);
+ evrpc_reqstate_free_(rpc_state);
evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
return;
}
diff --git a/evutil.c b/evutil.c
index e49d744f..df93e67f 100644
--- a/evutil.c
+++ b/evutil.c
@@ -652,7 +652,7 @@ evutil_check_ifaddrs(void)
"GetAdaptersInfo", but that's deprecated; let's just try
GetAdaptersAddresses and fall back to connect+getsockname.
*/
- HANDLE lib = evutil_load_windows_system_library_(TEXT("ihplapi.dll"));
+ HMODULE lib = evutil_load_windows_system_library_(TEXT("ihplapi.dll"));
GetAdaptersAddresses_fn_t fn;
ULONG size, res;
IP_ADAPTER_ADDRESSES *addresses = NULL, *address;
@@ -1794,7 +1794,7 @@ evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap)
int r;
if (!buflen)
return 0;
-#if defined(_MSC_VER) || defined(WIN32)
+#if defined(_MSC_VER) || defined(_WIN32)
r = _vsnprintf(buf, buflen, format, ap);
if (r < 0)
r = _vscprintf(format, ap);
@@ -1918,15 +1918,15 @@ evutil_inet_pton(int af, const char *src, void *dst)
return inet_pton(af, src, dst);
#else
if (af == AF_INET) {
- int a,b,c,d;
+ unsigned a,b,c,d;
char more;
struct in_addr *addr = dst;
- if (sscanf(src, "%d.%d.%d.%d%c", &a,&b,&c,&d,&more) != 4)
+ if (sscanf(src, "%u.%u.%u.%u%c", &a,&b,&c,&d,&more) != 4)
return 0;
- if (a < 0 || a > 255) return 0;
- if (b < 0 || b > 255) return 0;
- if (c < 0 || c > 255) return 0;
- if (d < 0 || d > 255) return 0;
+ if (a > 255) return 0;
+ if (b > 255) return 0;
+ if (c > 255) return 0;
+ if (d > 255) return 0;
addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d);
return 1;
#ifdef AF_INET6
@@ -1941,7 +1941,7 @@ evutil_inet_pton(int af, const char *src, void *dst)
else if (!dot)
eow = src+strlen(src);
else {
- int byte1,byte2,byte3,byte4;
+ unsigned byte1,byte2,byte3,byte4;
char more;
for (eow = dot-1; eow >= src && EVUTIL_ISDIGIT_(*eow); --eow)
;
@@ -1949,14 +1949,14 @@ evutil_inet_pton(int af, const char *src, void *dst)
/* We use "scanf" because some platform inet_aton()s are too lax
* about IPv4 addresses of the form "1.2.3" */
- if (sscanf(eow, "%d.%d.%d.%d%c",
+ if (sscanf(eow, "%u.%u.%u.%u%c",
&byte1,&byte2,&byte3,&byte4,&more) != 4)
return 0;
- if (byte1 > 255 || byte1 < 0 ||
- byte2 > 255 || byte2 < 0 ||
- byte3 > 255 || byte3 < 0 ||
- byte4 > 255 || byte4 < 0)
+ if (byte1 > 255 ||
+ byte2 > 255 ||
+ byte3 > 255 ||
+ byte4 > 255)
return 0;
words[6] = (byte1<<8) | byte2;
@@ -2453,7 +2453,7 @@ evutil_hex_char_to_int_(char c)
}
#ifdef _WIN32
-HANDLE
+HMODULE
evutil_load_windows_system_library_(const TCHAR *library_name)
{
TCHAR path[MAX_PATH];
diff --git a/http.c b/http.c
index e8672b77..093dd063 100644
--- a/http.c
+++ b/http.c
@@ -2150,6 +2150,14 @@ evhttp_read_header(struct evhttp_connection *evcon,
/* Disable reading for now */
bufferevent_disable(evcon->bufev, EV_READ);
+ /* Callback can shut down connection with negative return value */
+ if (req->header_cb != NULL) {
+ if ((*req->header_cb)(req, req->cb_arg) < 0) {
+ evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
+ return;
+ }
+ }
+
/* Done reading headers, do the real work */
switch (req->kind) {
case EVHTTP_REQUEST:
@@ -2544,6 +2552,10 @@ evhttp_send_done(struct evhttp_connection *evcon, void *arg)
struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
TAILQ_REMOVE(&evcon->requests, req, next);
+ if (req->on_complete_cb != NULL) {
+ req->on_complete_cb(req, req->on_complete_cb_arg);
+ }
+
need_close =
(REQ_VERSION_BEFORE(req, 1, 1) &&
!evhttp_is_connection_keepalive(req->input_headers))||
@@ -2658,7 +2670,8 @@ evhttp_send_reply_start(struct evhttp_request *req, int code,
}
void
-evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf)
+evhttp_send_reply_chunk_with_cb(struct evhttp_request *req, struct evbuffer *databuf,
+ void (*cb)(struct evhttp_connection *, void *), void *arg)
{
struct evhttp_connection *evcon = req->evcon;
struct evbuffer *output;
@@ -2680,10 +2693,15 @@ evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf)
if (req->chunked) {
evbuffer_add(output, "\r\n", 2);
}
- evhttp_write_buffer(evcon, NULL, NULL);
+ evhttp_write_buffer(evcon, cb, arg);
}
void
+evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf)
+{
+ evhttp_send_reply_chunk_with_cb(req, databuf, NULL, NULL);
+}
+void
evhttp_send_reply_end(struct evhttp_request *req)
{
struct evhttp_connection *evcon = req->evcon;
@@ -3813,12 +3831,27 @@ evhttp_request_set_chunked_cb(struct evhttp_request *req,
}
void
+evhttp_request_set_header_cb(struct evhttp_request *req,
+ int (*cb)(struct evhttp_request *, void *))
+{
+ req->header_cb = cb;
+}
+
+void
evhttp_request_set_error_cb(struct evhttp_request *req,
void (*cb)(enum evhttp_request_error, void *))
{
req->error_cb = cb;
}
+void
+evhttp_request_set_on_complete_cb(struct evhttp_request *req,
+ void (*cb)(struct evhttp_request *, void *), void *cb_arg)
+{
+ req->on_complete_cb = cb;
+ req->on_complete_cb_arg = cb_arg;
+}
+
/*
* Allows for inspection of the request URI
*/
@@ -4256,6 +4289,8 @@ parse_port(const char *s, const char *eos)
portnum = (portnum * 10) + (*s - '0');
if (portnum < 0)
return -1;
+ if (portnum > 65535)
+ return -1;
++s;
}
return portnum;
diff --git a/include/event2/buffer.h b/include/event2/buffer.h
index 712e4d79..03a18984 100644
--- a/include/event2/buffer.h
+++ b/include/event2/buffer.h
@@ -72,6 +72,8 @@
evbuffer_peek() if you don't require that the memory to be contiguous.
*/
+#include <event2/visibility.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -103,13 +105,8 @@ struct evbuffer
Used when repeatedly searching through a buffer. Calling any function
that modifies or re-packs the buffer contents may invalidate all
- evbuffer_ptrs for that buffer. Do not modify these values except with
- evbuffer_ptr_set.
-
- Used when repeatedly searching through a buffer. Calls to any function
- that modifies or re-packs the buffer contents may invalidate all
- evbuffer_ptrs for that buffer. Do not modify these values except with
- evbuffer_ptr_set.
+ evbuffer_ptrs for that buffer. Do not modify or contruct these values
+ except with evbuffer_ptr_set.
An evbuffer_ptr can represent any position from the start of a buffer up
to a position immediately after the end of a buffer.
@@ -151,12 +148,14 @@ struct evbuffer_iovec {
@return a pointer to a newly allocated evbuffer struct, or NULL if an error
occurred
*/
+EVENT2_EXPORT_SYMBOL
struct evbuffer *evbuffer_new(void);
/**
Deallocate storage for an evbuffer.
@param buf pointer to the evbuffer to be freed
*/
+EVENT2_EXPORT_SYMBOL
void evbuffer_free(struct evbuffer *buf);
/**
@@ -171,18 +170,21 @@ void evbuffer_free(struct evbuffer *buf);
@param lock A lock object, or NULL if we should allocate our own.
@return 0 on success, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_enable_locking(struct evbuffer *buf, void *lock);
/**
Acquire the lock on an evbuffer. Has no effect if locking was not enabled
with evbuffer_enable_locking.
*/
+EVENT2_EXPORT_SYMBOL
void evbuffer_lock(struct evbuffer *buf);
/**
Release the lock on an evbuffer. Has no effect if locking was not enabled
with evbuffer_enable_locking.
*/
+EVENT2_EXPORT_SYMBOL
void evbuffer_unlock(struct evbuffer *buf);
@@ -210,6 +212,7 @@ void evbuffer_unlock(struct evbuffer *buf);
* @param flags One or more EVBUFFER_FLAG_* options
* @return 0 on success, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_set_flags(struct evbuffer *buf, ev_uint64_t flags);
/** Change the flags that are set for an evbuffer by removing some.
*
@@ -218,6 +221,7 @@ int evbuffer_set_flags(struct evbuffer *buf, ev_uint64_t flags);
* @param flags One or more EVBUFFER_FLAG_* options
* @return 0 on success, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_clear_flags(struct evbuffer *buf, ev_uint64_t flags);
/**
@@ -226,6 +230,7 @@ int evbuffer_clear_flags(struct evbuffer *buf, ev_uint64_t flags);
@param buf pointer to the evbuffer
@return the number of bytes stored in the evbuffer
*/
+EVENT2_EXPORT_SYMBOL
size_t evbuffer_get_length(const struct evbuffer *buf);
/**
@@ -240,6 +245,7 @@ size_t evbuffer_get_length(const struct evbuffer *buf);
@return 0 if no data is available, otherwise the number of available bytes
in the first buffer chain.
*/
+EVENT2_EXPORT_SYMBOL
size_t evbuffer_get_contiguous_space(const struct evbuffer *buf);
/**
@@ -252,6 +258,7 @@ size_t evbuffer_get_contiguous_space(const struct evbuffer *buf);
@param datlen the new minimum length requirement
@return 0 if successful, or -1 if an error occurred
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_expand(struct evbuffer *buf, size_t datlen);
/**
@@ -287,6 +294,7 @@ int evbuffer_expand(struct evbuffer *buf, size_t datlen);
@return the number of provided extents, or -1 on error.
@see evbuffer_commit_space()
*/
+EVENT2_EXPORT_SYMBOL
int
evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size,
struct evbuffer_iovec *vec, int n_vec);
@@ -312,6 +320,7 @@ evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size,
@return 0 on success, -1 on error
@see evbuffer_reserve_space()
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_commit_space(struct evbuffer *buf,
struct evbuffer_iovec *vec, int n_vecs);
@@ -323,6 +332,7 @@ int evbuffer_commit_space(struct evbuffer *buf,
@param datlen the number of bytes to be copied from the data buffer
@return 0 on success, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen);
@@ -337,6 +347,7 @@ int evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen);
@param datlen the maximum size of the destination buffer
@return the number of bytes read, or -1 if we can't drain the buffer.
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen);
/**
@@ -350,6 +361,7 @@ int evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen);
@param datlen the maximum size of the destination buffer
@return the number of bytes read, or -1 if we can't drain the buffer.
*/
+EVENT2_EXPORT_SYMBOL
ev_ssize_t evbuffer_copyout(struct evbuffer *buf, void *data_out, size_t datlen);
/**
@@ -364,6 +376,7 @@ ev_ssize_t evbuffer_copyout(struct evbuffer *buf, void *data_out, size_t datlen)
@param datlen the maximum size of the destination buffer
@return the number of bytes read, or -1 if we can't drain the buffer.
*/
+EVENT2_EXPORT_SYMBOL
ev_ssize_t evbuffer_copyout_from(struct evbuffer *buf, const struct evbuffer_ptr *pos, void *data_out, size_t datlen);
/**
@@ -379,6 +392,7 @@ ev_ssize_t evbuffer_copyout_from(struct evbuffer *buf, const struct evbuffer_ptr
@param datlen the maximum numbers of bytes to transfer
@return the number of bytes read
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst,
size_t datlen);
@@ -420,6 +434,7 @@ enum evbuffer_eol_style {
* @param eol_style the style of line-ending to use.
* @return pointer to a single line, or NULL if an error occurred
*/
+EVENT2_EXPORT_SYMBOL
char *evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
enum evbuffer_eol_style eol_style);
@@ -435,21 +450,23 @@ char *evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
@see evbuffer_remove_buffer()
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf);
/**
Copy data from one evbuffer into another evbuffer.
-
+
This is a non-destructive add. The data from one buffer is copied
into the other buffer. However, no unnecessary memory copies occur.
-
+
Note that buffers already containing buffer references can't be added
to other buffers.
-
+
@param outbuf the output buffer
@param inbuf the input buffer
@return 0 if successful, or -1 if an error occurred
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_add_buffer_reference(struct evbuffer *outbuf,
struct evbuffer *inbuf);
@@ -477,6 +494,7 @@ typedef void (*evbuffer_ref_cleanup_cb)(const void *data,
@param cleanupfn_arg optional argument to the cleanup callback
@return 0 if successful, or -1 if an error occurred
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_add_reference(struct evbuffer *outbuf,
const void *data, size_t datlen,
evbuffer_ref_cleanup_cb cleanupfn, void *cleanupfn_arg);
@@ -505,6 +523,7 @@ int evbuffer_add_reference(struct evbuffer *outbuf,
@return 0 if successful, or -1 if an error occurred
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_add_file(struct evbuffer *outbuf, int fd, ev_off_t offset,
ev_off_t length);
@@ -576,6 +595,7 @@ typedef void (*evbuffer_file_segment_cleanup_cb)(
@param flags any number of the EVBUF_FS_* flags
@return a new evbuffer_file_segment, or NULL on failure.
**/
+EVENT2_EXPORT_SYMBOL
struct evbuffer_file_segment *evbuffer_file_segment_new(
int fd, ev_off_t offset, ev_off_t length, unsigned flags);
@@ -586,6 +606,7 @@ struct evbuffer_file_segment *evbuffer_file_segment_new(
one or more evbuffers. The evbuffer_file_segment will not be freed
until no more references to it exist.
*/
+EVENT2_EXPORT_SYMBOL
void evbuffer_file_segment_free(struct evbuffer_file_segment *seg);
/**
@@ -595,6 +616,7 @@ void evbuffer_file_segment_free(struct evbuffer_file_segment *seg);
The cleanup callback will be invoked when no more references to the
evbuffer_file_segment exist.
**/
+EVENT2_EXPORT_SYMBOL
void evbuffer_file_segment_add_cleanup_cb(struct evbuffer_file_segment *seg,
evbuffer_file_segment_cleanup_cb cb, void* arg);
@@ -620,6 +642,7 @@ void evbuffer_file_segment_add_cleanup_cb(struct evbuffer_file_segment *seg,
@param length the amount of data to add, or -1 to add it all.
@return 0 on success, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_add_file_segment(struct evbuffer *buf,
struct evbuffer_file_segment *seg, ev_off_t offset, ev_off_t length);
@@ -635,6 +658,7 @@ int evbuffer_add_file_segment(struct evbuffer *buf,
@see evutil_printf(), evbuffer_add_vprintf()
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
#ifdef __GNUC__
__attribute__((format(printf, 2, 3)))
@@ -649,6 +673,7 @@ int evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
@param ap a varargs va_list argument array that will be passed to vprintf(3)
@return The number of bytes added if successful, or -1 if an error occurred.
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
#ifdef __GNUC__
__attribute__((format(printf, 2, 0)))
@@ -663,6 +688,7 @@ int evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
@param len the number of bytes to drain from the beginning of the buffer
@return 0 on success, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_drain(struct evbuffer *buf, size_t len);
@@ -676,6 +702,7 @@ int evbuffer_drain(struct evbuffer *buf, size_t len);
@return the number of bytes written, or -1 if an error occurred
@see evbuffer_read()
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_write(struct evbuffer *buffer, evutil_socket_t fd);
/**
@@ -690,6 +717,7 @@ int evbuffer_write(struct evbuffer *buffer, evutil_socket_t fd);
@return the number of bytes written, or -1 if an error occurred
@see evbuffer_read()
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_write_atmost(struct evbuffer *buffer, evutil_socket_t fd,
ev_ssize_t howmuch);
@@ -702,6 +730,7 @@ int evbuffer_write_atmost(struct evbuffer *buffer, evutil_socket_t fd,
@return the number of bytes read, or -1 if an error occurred
@see evbuffer_write()
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_read(struct evbuffer *buffer, evutil_socket_t fd, int howmuch);
/**
@@ -715,6 +744,7 @@ int evbuffer_read(struct evbuffer *buffer, evutil_socket_t fd, int howmuch);
first occurrence of the string in the buffer after 'start'. The 'pos'
field of the result is -1 if the string was not found.
*/
+EVENT2_EXPORT_SYMBOL
struct evbuffer_ptr evbuffer_search(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start);
/**
@@ -731,6 +761,7 @@ struct evbuffer_ptr evbuffer_search(struct evbuffer *buffer, const char *what, s
first occurrence of the string in the buffer after 'start'. The 'pos'
field of the result is -1 if the string was not found.
*/
+EVENT2_EXPORT_SYMBOL
struct evbuffer_ptr evbuffer_search_range(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start, const struct evbuffer_ptr *end);
/**
@@ -766,6 +797,7 @@ enum evbuffer_ptr_how {
@param how determines how the pointer should be manipulated.
@returns 0 on success or -1 otherwise
*/
+EVENT2_EXPORT_SYMBOL
int
evbuffer_ptr_set(struct evbuffer *buffer, struct evbuffer_ptr *ptr,
size_t position, enum evbuffer_ptr_how how);
@@ -784,6 +816,7 @@ evbuffer_ptr_set(struct evbuffer *buffer, struct evbuffer_ptr *ptr,
first occurrence EOL in the buffer after 'start'. The 'pos'
field of the result is -1 if the string was not found.
*/
+EVENT2_EXPORT_SYMBOL
struct evbuffer_ptr evbuffer_search_eol(struct evbuffer *buffer,
struct evbuffer_ptr *start, size_t *eol_len_out,
enum evbuffer_eol_style eol_style);
@@ -816,6 +849,7 @@ struct evbuffer_ptr evbuffer_search_eol(struct evbuffer *buffer,
than n_vec if we would need more to return all the data that was
requested.
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_peek(struct evbuffer *buffer, ev_ssize_t len,
struct evbuffer_ptr *start_at,
struct evbuffer_iovec *vec_out, int n_vec);
@@ -868,6 +902,7 @@ struct evbuffer_cb_entry;
@param cbarg an argument to be provided to the callback function
@return a handle to the callback on success, or NULL on failure.
*/
+EVENT2_EXPORT_SYMBOL
struct evbuffer_cb_entry *evbuffer_add_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg);
/** Remove a callback from an evbuffer, given a handle returned from
@@ -878,6 +913,7 @@ struct evbuffer_cb_entry *evbuffer_add_cb(struct evbuffer *buffer, evbuffer_cb_f
@return 0 if a callback was removed, or -1 if no matching callback was
found.
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_remove_cb_entry(struct evbuffer *buffer,
struct evbuffer_cb_entry *ent);
@@ -887,6 +923,7 @@ int evbuffer_remove_cb_entry(struct evbuffer *buffer,
@return 0 if a callback was removed, or -1 if no matching callback was
found.
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_remove_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg);
/** If this flag is not set, then a callback is temporarily disabled, and
@@ -903,6 +940,7 @@ int evbuffer_remove_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg
@param flags EVBUFFER_CB_ENABLED to re-enable the callback.
@return 0 on success, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_cb_set_flags(struct evbuffer *buffer,
struct evbuffer_cb_entry *cb, ev_uint32_t flags);
@@ -913,6 +951,7 @@ int evbuffer_cb_set_flags(struct evbuffer *buffer,
@param flags EVBUFFER_CB_ENABLED to disable the callback.
@return 0 on success, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_cb_clear_flags(struct evbuffer *buffer,
struct evbuffer_cb_entry *cb, ev_uint32_t flags);
@@ -926,6 +965,7 @@ int evbuffer_cb_clear_flags(struct evbuffer *buffer,
@param the buffer that the callback is watching.
@param cb the callback we want to suspend.
*/
+EVENT2_EXPORT_SYMBOL
void evbuffer_cb_suspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb);
/** Stop postponing a callback that we postponed with evbuffer_cb_suspend.
@@ -935,6 +975,7 @@ void evbuffer_cb_suspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb);
@param the buffer that the callback is watching.
@param cb the callback we want to stop suspending.
*/
+EVENT2_EXPORT_SYMBOL
void evbuffer_cb_unsuspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb);
#endif
@@ -948,6 +989,7 @@ void evbuffer_cb_unsuspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb
requested more data than is present in the buffer.
*/
+EVENT2_EXPORT_SYMBOL
unsigned char *evbuffer_pullup(struct evbuffer *buf, ev_ssize_t size);
/**
@@ -959,6 +1001,7 @@ unsigned char *evbuffer_pullup(struct evbuffer *buf, ev_ssize_t size);
@return 0 if successful, or -1 otherwise
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_prepend(struct evbuffer *buf, const void *data, size_t size);
/**
@@ -969,6 +1012,7 @@ int evbuffer_prepend(struct evbuffer *buf, const void *data, size_t size);
@param src the evbuffer to prepend; it will be emptied as a result
@return 0 if successful, or -1 otherwise
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_prepend_buffer(struct evbuffer *dst, struct evbuffer* src);
/**
@@ -985,6 +1029,7 @@ int evbuffer_prepend_buffer(struct evbuffer *dst, struct evbuffer* src);
we freeze the back.
@return 0 on success, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_freeze(struct evbuffer *buf, int at_front);
/**
Re-enable calls that modify an evbuffer.
@@ -994,6 +1039,7 @@ int evbuffer_freeze(struct evbuffer *buf, int at_front);
we unfreeze the back.
@return 0 on success, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_unfreeze(struct evbuffer *buf, int at_front);
struct event_base;
@@ -1004,6 +1050,7 @@ struct event_base;
This can be used to serialize all the callbacks to a single thread
of execution.
*/
+EVENT2_EXPORT_SYMBOL
int evbuffer_defer_callbacks(struct evbuffer *buffer, struct event_base *base);
/**
@@ -1019,6 +1066,7 @@ int evbuffer_defer_callbacks(struct evbuffer *buffer, struct event_base *base);
@param n_vec the number of iovec structures.
@return the number of bytes successfully written to the output buffer.
*/
+EVENT2_EXPORT_SYMBOL
size_t evbuffer_add_iovec(struct evbuffer * buffer, struct evbuffer_iovec * vec, int n_vec);
#ifdef __cplusplus
diff --git a/include/event2/buffer_compat.h b/include/event2/buffer_compat.h
index c155332e..c0bdd9d2 100644
--- a/include/event2/buffer_compat.h
+++ b/include/event2/buffer_compat.h
@@ -27,6 +27,8 @@
#ifndef EVENT2_BUFFER_COMPAT_H_INCLUDED_
#define EVENT2_BUFFER_COMPAT_H_INCLUDED_
+#include <event2/visibility.h>
+
/** @file event2/buffer_compat.h
Obsolete and deprecated versions of the functions in buffer.h: provided
@@ -45,6 +47,7 @@
@return pointer to a single line, or NULL if an error occurred
*/
+EVENT2_EXPORT_SYMBOL
char *evbuffer_readline(struct evbuffer *buffer);
/** Type definition for a callback that is invoked whenever data is added or
@@ -88,6 +91,7 @@ typedef void (*evbuffer_cb)(struct evbuffer *buffer, size_t old_len, size_t new_
or NULL to remove all callbacks.
@param cbarg an argument to be provided to the callback function
*/
+EVENT2_EXPORT_SYMBOL
void evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg);
@@ -99,6 +103,7 @@ void evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg);
@param len the length of the search string
@return a pointer to the beginning of the search string, or NULL if the search failed.
*/
+EVENT2_EXPORT_SYMBOL
unsigned char *evbuffer_find(struct evbuffer *buffer, const unsigned char *what, size_t len);
/** deprecated in favor of calling the functions directly */
diff --git a/include/event2/bufferevent.h b/include/event2/bufferevent.h
index 513d3285..46203b04 100644
--- a/include/event2/bufferevent.h
+++ b/include/event2/bufferevent.h
@@ -44,10 +44,10 @@
with bufferevent_enable() and bufferevent_disable().
When reading is enabled, the bufferevent will try to read from the
- file descriptor onto its input buffer, and and call the read callback.
+ file descriptor onto its input buffer, and call the read callback.
When writing is enabled, the bufferevent will try to write data onto its
- file descriptor when writing is enabled, and call the write callback
- when the output buffer is sufficiently drained.
+ file descriptor when the output buffer has enough data, and call the write
+ callback when the output buffer is sufficiently drained.
Bufferevents come in several flavors, including:
@@ -74,6 +74,8 @@
</dl>
*/
+#include <event2/visibility.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -138,6 +140,9 @@ typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);
The event callback is triggered if either an EOF condition or another
unrecoverable error was encountered.
+ For bufferevents with deferred callbacks, this is a bitwise OR of all errors
+ that have happened on the bufferevent since the last callback invocation.
+
@param bev the bufferevent for which the error condition was reached
@param what a conjunction of flags: BEV_EVENT_READING or BEV_EVENT_WRITING
to indicate if the error was encountered on the read or write path,
@@ -181,6 +186,7 @@ enum bufferevent_options {
error occurred
@see bufferevent_free()
*/
+EVENT2_EXPORT_SYMBOL
struct bufferevent *bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options);
/**
@@ -202,6 +208,7 @@ struct bufferevent *bufferevent_socket_new(struct event_base *base, evutil_socke
@param socklen The length of the address
@return 0 on success, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_socket_connect(struct bufferevent *, struct sockaddr *, int);
struct evdns_base;
@@ -231,6 +238,7 @@ struct evdns_base;
may block while it waits for a DNS response. This is probably not
what you want.
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_socket_connect_hostname(struct bufferevent *,
struct evdns_base *, int, const char *, int);
@@ -242,6 +250,7 @@ int bufferevent_socket_connect_hostname(struct bufferevent *,
@return DNS error code.
@see evutil_gai_strerror()
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_socket_get_dns_error(struct bufferevent *bev);
/**
@@ -255,11 +264,13 @@ int bufferevent_socket_get_dns_error(struct bufferevent *bev);
@return 0 if successful, or -1 if an error occurred
@see bufferevent_new()
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev);
/**
Return the event_base used by a bufferevent
*/
+EVENT2_EXPORT_SYMBOL
struct event_base *bufferevent_get_base(struct bufferevent *bev);
/**
@@ -271,6 +282,7 @@ struct event_base *bufferevent_get_base(struct bufferevent *bev);
@param pri the priority to be assigned
@return 0 if successful, or -1 if an error occurred
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_priority_set(struct bufferevent *bufev, int pri);
/**
@@ -278,6 +290,7 @@ int bufferevent_priority_set(struct bufferevent *bufev, int pri);
Only supported for socket bufferevents
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_get_priority(const struct bufferevent *bufev);
/**
@@ -288,6 +301,7 @@ int bufferevent_get_priority(const struct bufferevent *bufev);
@param bufev the bufferevent structure to be freed.
*/
+EVENT2_EXPORT_SYMBOL
void bufferevent_free(struct bufferevent *bufev);
@@ -305,6 +319,7 @@ void bufferevent_free(struct bufferevent *bufev);
(readcb, writecb, and errorcb)
@see bufferevent_new()
*/
+EVENT2_EXPORT_SYMBOL
void bufferevent_setcb(struct bufferevent *bufev,
bufferevent_data_cb readcb, bufferevent_data_cb writecb,
bufferevent_event_cb eventcb, void *cbarg);
@@ -323,6 +338,7 @@ void bufferevent_setcb(struct bufferevent *bufev,
callback argument for the bufferevent.
@see buffervent_setcb()
*/
+EVENT2_EXPORT_SYMBOL
void bufferevent_getcb(struct bufferevent *bufev,
bufferevent_data_cb *readcb_ptr,
bufferevent_data_cb *writecb_ptr,
@@ -336,18 +352,21 @@ void bufferevent_getcb(struct bufferevent *bufev,
@param bufev the bufferevent object for which to change the file descriptor
@param fd the file descriptor to operate on
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_setfd(struct bufferevent *bufev, evutil_socket_t fd);
/**
Returns the file descriptor associated with a bufferevent, or -1 if
no file descriptor is associated with the bufferevent.
*/
+EVENT2_EXPORT_SYMBOL
evutil_socket_t bufferevent_getfd(struct bufferevent *bufev);
/**
Returns the underlying bufferevent associated with a bufferevent (if
the bufferevent is a wrapper), or NULL if there is no underlying bufferevent.
*/
+EVENT2_EXPORT_SYMBOL
struct bufferevent *bufferevent_get_underlying(struct bufferevent *bufev);
/**
@@ -363,6 +382,7 @@ struct bufferevent *bufferevent_get_underlying(struct bufferevent *bufev);
@return 0 if successful, or -1 if an error occurred
@see bufferevent_write_buffer()
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_write(struct bufferevent *bufev,
const void *data, size_t size);
@@ -376,6 +396,7 @@ int bufferevent_write(struct bufferevent *bufev,
@return 0 if successful, or -1 if an error occurred
@see bufferevent_write()
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf);
@@ -389,6 +410,7 @@ int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf);
@param size the size of the data buffer, in bytes
@return the amount of data read, in bytes.
*/
+EVENT2_EXPORT_SYMBOL
size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);
/**
@@ -399,6 +421,7 @@ size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);
@param buf the evbuffer to which to add data
@return 0 if successful, or -1 if an error occurred.
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_read_buffer(struct bufferevent *bufev, struct evbuffer *buf);
/**
@@ -410,6 +433,7 @@ int bufferevent_read_buffer(struct bufferevent *bufev, struct evbuffer *buf);
@return the evbuffer object for the input buffer
*/
+EVENT2_EXPORT_SYMBOL
struct evbuffer *bufferevent_get_input(struct bufferevent *bufev);
/**
@@ -424,6 +448,7 @@ struct evbuffer *bufferevent_get_input(struct bufferevent *bufev);
@return the evbuffer object for the output buffer
*/
+EVENT2_EXPORT_SYMBOL
struct evbuffer *bufferevent_get_output(struct bufferevent *bufev);
/**
@@ -434,6 +459,7 @@ struct evbuffer *bufferevent_get_output(struct bufferevent *bufev);
@return 0 if successful, or -1 if an error occurred
@see bufferevent_disable()
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_enable(struct bufferevent *bufev, short event);
/**
@@ -444,6 +470,7 @@ int bufferevent_enable(struct bufferevent *bufev, short event);
@return 0 if successful, or -1 if an error occurred
@see bufferevent_enable()
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_disable(struct bufferevent *bufev, short event);
/**
@@ -452,6 +479,7 @@ int bufferevent_disable(struct bufferevent *bufev, short event);
@param bufev the bufferevent to inspect
@return A combination of EV_READ | EV_WRITE
*/
+EVENT2_EXPORT_SYMBOL
short bufferevent_get_enabled(struct bufferevent *bufev);
/**
@@ -480,6 +508,7 @@ short bufferevent_get_enabled(struct bufferevent *bufev);
@param timeout_read the read timeout, or NULL
@param timeout_write the write timeout, or NULL
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_set_timeouts(struct bufferevent *bufev,
const struct timeval *timeout_read, const struct timeval *timeout_write);
@@ -501,19 +530,35 @@ int bufferevent_set_timeouts(struct bufferevent *bufev,
@param highmark the high watermark to set
*/
+EVENT2_EXPORT_SYMBOL
void bufferevent_setwatermark(struct bufferevent *bufev, short events,
size_t lowmark, size_t highmark);
/**
+ Retrieves the watermarks for read or write events. Result is undefined if
+ events contains both EV_READ and EV_WRITE.
+
+ @param bufev the bufferevent to be examined
+ @param events EV_READ or EV_WRITE
+ @param lowmark receives the lower watermark if not NULL
+ @param highmark receives the high watermark if not NULL
+*/
+EVENT2_EXPORT_SYMBOL
+void bufferevent_getwatermark(struct bufferevent *bufev, short events,
+ size_t *lowmark, size_t *highmark);
+
+/**
Acquire the lock on a bufferevent. Has no effect if locking was not
enabled with BEV_OPT_THREADSAFE.
*/
+EVENT2_EXPORT_SYMBOL
void bufferevent_lock(struct bufferevent *bufev);
/**
Release the lock on a bufferevent. Has no effect if locking was not
enabled with BEV_OPT_THREADSAFE.
*/
+EVENT2_EXPORT_SYMBOL
void bufferevent_unlock(struct bufferevent *bufev);
/**
@@ -539,11 +584,55 @@ enum bufferevent_flush_mode {
@param mode either BEV_NORMAL or BEV_FLUSH or BEV_FINISHED
@return -1 on failure, 0 if no data was produces, 1 if data was produced
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_flush(struct bufferevent *bufev,
short iotype,
enum bufferevent_flush_mode mode);
/**
+ Flags for bufferevent_trigger(_event) that modify when and how to trigger
+ the callback.
+*/
+enum bufferevent_trigger_options {
+ /** trigger the callback regardless of the watermarks */
+ BEV_TRIG_IGNORE_WATERMARKS = (1<<16),
+
+ /** defer even if the callbacks are not */
+ BEV_TRIG_DEFER_CALLBACKS = BEV_OPT_DEFER_CALLBACKS,
+
+ /* (Note: for internal reasons, these need to be disjoint from
+ * bufferevent_options, except when they mean the same thing. */
+};
+
+/**
+ Triggers bufferevent data callbacks.
+
+ The function will honor watermarks unless options contain
+ BEV_TRIG_IGNORE_WATERMARKS. If the options contain BEV_OPT_DEFER_CALLBACKS,
+ the callbacks are deferred.
+
+ @param bufev the bufferevent object
+ @param iotype either EV_READ or EV_WRITE or both.
+ @param options
+ */
+EVENT2_EXPORT_SYMBOL
+void bufferevent_trigger(struct bufferevent *bufev, short iotype,
+ int options);
+
+/**
+ Triggers the bufferevent event callback.
+
+ If the options contain BEV_OPT_DEFER_CALLBACKS, the callbacks are deferred.
+
+ @param bufev the bufferevent object
+ @param what the flags to pass onto the event callback
+ @param options
+ */
+EVENT2_EXPORT_SYMBOL
+void bufferevent_trigger_event(struct bufferevent *bufev, short what,
+ int options);
+
+/**
@name Filtering support
@{
@@ -598,6 +687,7 @@ typedef enum bufferevent_filter_result (*bufferevent_filter_cb)(
this bufferevent is freed.
@param ctx A context pointer to pass to the filter functions.
*/
+EVENT2_EXPORT_SYMBOL
struct bufferevent *
bufferevent_filter_new(struct bufferevent *underlying,
bufferevent_filter_cb input_filter,
@@ -617,6 +707,7 @@ bufferevent_filter_new(struct bufferevent *underlying,
@param pair A pointer to an array to hold the two new bufferevent objects.
@return 0 on success, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_pair_new(struct event_base *base, int options,
struct bufferevent *pair[2]);
@@ -624,6 +715,7 @@ int bufferevent_pair_new(struct event_base *base, int options,
Given one bufferevent returned by bufferevent_pair_new(), returns the
other one if it still exists. Otherwise returns NULL.
*/
+EVENT2_EXPORT_SYMBOL
struct bufferevent *bufferevent_pair_get_partner(struct bufferevent *bev);
/**
@@ -657,6 +749,7 @@ struct bufferevent_rate_limit_group;
Note that all rate-limits hare are currently best-effort: future versions
of Libevent may implement them more tightly.
*/
+EVENT2_EXPORT_SYMBOL
struct ev_token_bucket_cfg *ev_token_bucket_cfg_new(
size_t read_rate, size_t read_burst,
size_t write_rate, size_t write_burst,
@@ -667,6 +760,7 @@ struct ev_token_bucket_cfg *ev_token_bucket_cfg_new(
Note: 'cfg' is not currently reference-counted; it is not safe to free it
until no bufferevent is using it.
*/
+EVENT2_EXPORT_SYMBOL
void ev_token_bucket_cfg_free(struct ev_token_bucket_cfg *cfg);
/**
@@ -680,6 +774,7 @@ void ev_token_bucket_cfg_free(struct ev_token_bucket_cfg *cfg);
Return 0 on sucess, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_set_rate_limit(struct bufferevent *bev,
struct ev_token_bucket_cfg *cfg);
@@ -700,6 +795,7 @@ int bufferevent_set_rate_limit(struct bufferevent *bev,
They are: socket-based bufferevents (normal and IOCP-based), and SSL-based
bufferevents.
*/
+EVENT2_EXPORT_SYMBOL
struct bufferevent_rate_limit_group *bufferevent_rate_limit_group_new(
struct event_base *base,
const struct ev_token_bucket_cfg *cfg);
@@ -708,6 +804,7 @@ struct bufferevent_rate_limit_group *bufferevent_rate_limit_group_new(
Return 0 on success, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_rate_limit_group_set_cfg(
struct bufferevent_rate_limit_group *,
const struct ev_token_bucket_cfg *);
@@ -728,6 +825,7 @@ int bufferevent_rate_limit_group_set_cfg(
Returns 0 on success, -1 on faulre.
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_rate_limit_group_set_min_share(
struct bufferevent_rate_limit_group *, size_t);
@@ -735,6 +833,7 @@ int bufferevent_rate_limit_group_set_min_share(
Free a rate-limiting group. The group must have no members when
this function is called.
*/
+EVENT2_EXPORT_SYMBOL
void bufferevent_rate_limit_group_free(struct bufferevent_rate_limit_group *);
/**
@@ -747,10 +846,12 @@ void bufferevent_rate_limit_group_free(struct bufferevent_rate_limit_group *);
Return 0 on success and -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_add_to_rate_limit_group(struct bufferevent *bev,
struct bufferevent_rate_limit_group *g);
/** Remove 'bev' from its current rate-limit group (if any). */
+EVENT2_EXPORT_SYMBOL
int bufferevent_remove_from_rate_limit_group(struct bufferevent *bev);
/**
@@ -760,6 +861,7 @@ int bufferevent_remove_from_rate_limit_group(struct bufferevent *bev);
Return 0 on success and -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_set_max_single_read(struct bufferevent *bev, size_t size);
/**
@@ -769,12 +871,15 @@ int bufferevent_set_max_single_read(struct bufferevent *bev, size_t size);
Return 0 on success and -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_set_max_single_write(struct bufferevent *bev, size_t size);
/** Get the current size limit for single read operation. */
+EVENT2_EXPORT_SYMBOL
ev_ssize_t bufferevent_get_max_single_read(struct bufferevent *bev);
/** Get the current size limit for single write operation. */
+EVENT2_EXPORT_SYMBOL
ev_ssize_t bufferevent_get_max_single_write(struct bufferevent *bev);
/**
@@ -788,13 +893,18 @@ ev_ssize_t bufferevent_get_max_single_write(struct bufferevent *bev);
@{
*/
+EVENT2_EXPORT_SYMBOL
ev_ssize_t bufferevent_get_read_limit(struct bufferevent *bev);
+EVENT2_EXPORT_SYMBOL
ev_ssize_t bufferevent_get_write_limit(struct bufferevent *bev);
/*@}*/
+EVENT2_EXPORT_SYMBOL
ev_ssize_t bufferevent_get_max_to_read(struct bufferevent *bev);
+EVENT2_EXPORT_SYMBOL
ev_ssize_t bufferevent_get_max_to_write(struct bufferevent *bev);
+EVENT2_EXPORT_SYMBOL
const struct ev_token_bucket_cfg *bufferevent_get_token_bucket_cfg(const struct bufferevent * bev);
/**
@@ -806,8 +916,10 @@ const struct ev_token_bucket_cfg *bufferevent_get_token_bucket_cfg(const struct
@{
*/
+EVENT2_EXPORT_SYMBOL
ev_ssize_t bufferevent_rate_limit_group_get_read_limit(
struct bufferevent_rate_limit_group *);
+EVENT2_EXPORT_SYMBOL
ev_ssize_t bufferevent_rate_limit_group_get_write_limit(
struct bufferevent_rate_limit_group *);
/*@}*/
@@ -826,7 +938,9 @@ ev_ssize_t bufferevent_rate_limit_group_get_write_limit(
@{
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_decrement_read_limit(struct bufferevent *bev, ev_ssize_t decr);
+EVENT2_EXPORT_SYMBOL
int bufferevent_decrement_write_limit(struct bufferevent *bev, ev_ssize_t decr);
/*@}*/
@@ -843,8 +957,10 @@ int bufferevent_decrement_write_limit(struct bufferevent *bev, ev_ssize_t decr);
@{
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_rate_limit_group_decrement_read(
struct bufferevent_rate_limit_group *, ev_ssize_t);
+EVENT2_EXPORT_SYMBOL
int bufferevent_rate_limit_group_decrement_write(
struct bufferevent_rate_limit_group *, ev_ssize_t);
/*@}*/
@@ -856,6 +972,7 @@ int bufferevent_rate_limit_group_decrement_write(
* Set the variable pointed to by total_read_out to the total number of bytes
* ever read on grp, and the variable pointed to by total_written_out to the
* total number of bytes ever written on grp. */
+EVENT2_EXPORT_SYMBOL
void bufferevent_rate_limit_group_get_totals(
struct bufferevent_rate_limit_group *grp,
ev_uint64_t *total_read_out, ev_uint64_t *total_written_out);
@@ -865,6 +982,7 @@ void bufferevent_rate_limit_group_get_totals(
*
* Reset the number of bytes read or written on grp as given by
* bufferevent_rate_limit_group_reset_totals(). */
+EVENT2_EXPORT_SYMBOL
void
bufferevent_rate_limit_group_reset_totals(
struct bufferevent_rate_limit_group *grp);
diff --git a/include/event2/bufferevent_ssl.h b/include/event2/bufferevent_ssl.h
index 2b7e6141..bf39b844 100644
--- a/include/event2/bufferevent_ssl.h
+++ b/include/event2/bufferevent_ssl.h
@@ -30,7 +30,7 @@
OpenSSL support for bufferevents.
*/
-
+#include <event2/visibility.h>
#include <event2/event-config.h>
#include <event2/bufferevent.h>
#include <event2/util.h>
@@ -64,6 +64,7 @@ enum bufferevent_ssl_state {
@param options One or more bufferevent_options
@return A new bufferevent on success, or NULL on failure
*/
+EVENT2_EXPORT_SYMBOL
struct bufferevent *
bufferevent_openssl_filter_new(struct event_base *base,
struct bufferevent *underlying,
@@ -81,6 +82,7 @@ bufferevent_openssl_filter_new(struct event_base *base,
@param options One or more bufferevent_options
@return A new bufferevent on success, or NULL on failure.
*/
+EVENT2_EXPORT_SYMBOL
struct bufferevent *
bufferevent_openssl_socket_new(struct event_base *base,
evutil_socket_t fd,
@@ -104,18 +106,23 @@ bufferevent_openssl_socket_new(struct event_base *base,
not to use SSL 2.)
*/
+EVENT2_EXPORT_SYMBOL
int bufferevent_openssl_get_allow_dirty_shutdown(struct bufferevent *bev);
+EVENT2_EXPORT_SYMBOL
void bufferevent_openssl_set_allow_dirty_shutdown(struct bufferevent *bev,
int allow_dirty_shutdown);
/** Return the underlying openssl SSL * object for an SSL bufferevent. */
+EVENT2_EXPORT_SYMBOL
struct ssl_st *
bufferevent_openssl_get_ssl(struct bufferevent *bufev);
/** Tells a bufferevent to begin SSL renegotiation. */
+EVENT2_EXPORT_SYMBOL
int bufferevent_ssl_renegotiate(struct bufferevent *bev);
/** Return the most recent OpenSSL error reported on an SSL bufferevent. */
+EVENT2_EXPORT_SYMBOL
unsigned long bufferevent_get_openssl_error(struct bufferevent *bev);
#endif
diff --git a/include/event2/dns.h b/include/event2/dns.h
index edd2a23e..a00c83e6 100644
--- a/include/event2/dns.h
+++ b/include/event2/dns.h
@@ -135,6 +135,8 @@
#ifndef EVENT2_DNS_H_INCLUDED_
#define EVENT2_DNS_H_INCLUDED_
+#include <event2/visibility.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -220,6 +222,7 @@ struct event_base;
@return evdns_base object if successful, or NULL if an error occurred.
@see evdns_base_free()
*/
+EVENT2_EXPORT_SYMBOL
struct evdns_base * evdns_base_new(struct event_base *event_base, int initialize_nameservers);
@@ -235,14 +238,25 @@ struct evdns_base * evdns_base_new(struct event_base *event_base, int initialize
active requests will return DNS_ERR_SHUTDOWN.
@see evdns_base_new()
*/
+EVENT2_EXPORT_SYMBOL
void evdns_base_free(struct evdns_base *base, int fail_requests);
/**
+ Remove all hosts entries that have been loaded into the event_base via
+ evdns_base_load_hosts or via event_base_resolv_conf_parse.
+
+ @param evdns_base the evdns base to remove outdated host addresses from
+ */
+EVENT2_EXPORT_SYMBOL
+void evdns_base_clear_host_addresses(struct evdns_base *base);
+
+/**
Convert a DNS error code to a string.
@param err the DNS error code
@return a string containing an explanation of the error code
*/
+EVENT2_EXPORT_SYMBOL
const char *evdns_err_to_string(int err);
@@ -257,6 +271,7 @@ const char *evdns_err_to_string(int err);
@return 0 if successful, or -1 if an error occurred
@see evdns_base_nameserver_ip_add()
*/
+EVENT2_EXPORT_SYMBOL
int evdns_base_nameserver_add(struct evdns_base *base,
unsigned long int address);
@@ -272,6 +287,7 @@ int evdns_base_nameserver_add(struct evdns_base *base,
@return the number of configured nameservers
@see evdns_base_nameserver_add()
*/
+EVENT2_EXPORT_SYMBOL
int evdns_base_count_nameservers(struct evdns_base *base);
/**
@@ -283,6 +299,7 @@ int evdns_base_count_nameservers(struct evdns_base *base);
@return 0 if successful, or -1 if an error occurred
@see evdns_base_resume()
*/
+EVENT2_EXPORT_SYMBOL
int evdns_base_clear_nameservers_and_suspend(struct evdns_base *base);
@@ -296,6 +313,7 @@ int evdns_base_clear_nameservers_and_suspend(struct evdns_base *base);
@return 0 if successful, or -1 if an error occurred
@see evdns_base_clear_nameservers_and_suspend()
*/
+EVENT2_EXPORT_SYMBOL
int evdns_base_resume(struct evdns_base *base);
/**
@@ -315,12 +333,14 @@ int evdns_base_resume(struct evdns_base *base);
@return 0 if successful, or -1 if an error occurred
@see evdns_base_nameserver_add()
*/
+EVENT2_EXPORT_SYMBOL
int evdns_base_nameserver_ip_add(struct evdns_base *base,
const char *ip_as_string);
/**
Add a nameserver by sockaddr.
**/
+EVENT2_EXPORT_SYMBOL
int
evdns_base_nameserver_sockaddr_add(struct evdns_base *base,
const struct sockaddr *sa, ev_socklen_t len, unsigned flags);
@@ -338,6 +358,7 @@ struct evdns_request;
@return an evdns_request object if successful, or NULL if an error occurred.
@see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6(), evdns_cancel_request()
*/
+EVENT2_EXPORT_SYMBOL
struct evdns_request *evdns_base_resolve_ipv4(struct evdns_base *base, const char *name, int flags, evdns_callback_type callback, void *ptr);
/**
@@ -351,6 +372,7 @@ struct evdns_request *evdns_base_resolve_ipv4(struct evdns_base *base, const cha
@return an evdns_request object if successful, or NULL if an error occurred.
@see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6(), evdns_cancel_request()
*/
+EVENT2_EXPORT_SYMBOL
struct evdns_request *evdns_base_resolve_ipv6(struct evdns_base *base, const char *name, int flags, evdns_callback_type callback, void *ptr);
struct in_addr;
@@ -367,6 +389,7 @@ struct in6_addr;
@return an evdns_request object if successful, or NULL if an error occurred.
@see evdns_resolve_reverse_ipv6(), evdns_cancel_request()
*/
+EVENT2_EXPORT_SYMBOL
struct evdns_request *evdns_base_resolve_reverse(struct evdns_base *base, const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr);
@@ -381,6 +404,7 @@ struct evdns_request *evdns_base_resolve_reverse(struct evdns_base *base, const
@return an evdns_request object if successful, or NULL if an error occurred.
@see evdns_resolve_reverse_ipv6(), evdns_cancel_request()
*/
+EVENT2_EXPORT_SYMBOL
struct evdns_request *evdns_base_resolve_reverse_ipv6(struct evdns_base *base, const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr);
/**
@@ -390,6 +414,7 @@ struct evdns_request *evdns_base_resolve_reverse_ipv6(struct evdns_base *base, c
@param req the evdns_request that was returned by calling a resolve function
@see evdns_base_resolve_ipv4(), evdns_base_resolve_ipv6, evdns_base_resolve_reverse
*/
+EVENT2_EXPORT_SYMBOL
void evdns_cancel_request(struct evdns_base *base, struct evdns_request *req);
/**
@@ -408,6 +433,7 @@ void evdns_cancel_request(struct evdns_base *base, struct evdns_request *req);
@param val the value to be set
@return 0 if successful, or -1 if an error occurred
*/
+EVENT2_EXPORT_SYMBOL
int evdns_base_set_option(struct evdns_base *base, const char *option, const char *val);
@@ -433,6 +459,7 @@ int evdns_base_set_option(struct evdns_base *base, const char *option, const cha
occurred (see above)
@see resolv.conf(3), evdns_config_windows_nameservers()
*/
+EVENT2_EXPORT_SYMBOL
int evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *const filename);
/**
@@ -443,8 +470,12 @@ int evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char
Note that only evdns_getaddrinfo uses the /etc/hosts entries.
+ This function does not replace previously loaded hosts entries; to do that,
+ call evdns_base_clear_host_addresses first.
+
Return 0 on success, negative on failure.
*/
+EVENT2_EXPORT_SYMBOL
int evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname);
/**
@@ -458,6 +489,7 @@ int evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname);
@see evdns_resolv_conf_parse()
*/
#ifdef _WIN32
+EVENT2_EXPORT_SYMBOL
int evdns_base_config_windows_nameservers(struct evdns_base *);
#define EVDNS_BASE_CONFIG_WINDOWS_NAMESERVERS_IMPLEMENTED
#endif
@@ -466,6 +498,7 @@ int evdns_base_config_windows_nameservers(struct evdns_base *);
/**
Clear the list of search domains.
*/
+EVENT2_EXPORT_SYMBOL
void evdns_base_search_clear(struct evdns_base *base);
@@ -474,6 +507,7 @@ void evdns_base_search_clear(struct evdns_base *base);
@param domain the domain to be added to the search list
*/
+EVENT2_EXPORT_SYMBOL
void evdns_base_search_add(struct evdns_base *base, const char *domain);
@@ -485,6 +519,7 @@ void evdns_base_search_add(struct evdns_base *base, const char *domain);
@param ndots the new ndots parameter
*/
+EVENT2_EXPORT_SYMBOL
void evdns_base_search_ndots_set(struct evdns_base *base, const int ndots);
/**
@@ -503,6 +538,7 @@ typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg);
@param fn the callback to be invoked when a log message is generated
*/
+EVENT2_EXPORT_SYMBOL
void evdns_set_log_fn(evdns_debug_log_fn_type fn);
/**
@@ -515,6 +551,7 @@ void evdns_set_log_fn(evdns_debug_log_fn_type fn);
NOTE: This function has no effect in Libevent 2.0.4-alpha and later,
since Libevent now provides its own secure RNG.
*/
+EVENT2_EXPORT_SYMBOL
void evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void));
/**
@@ -526,6 +563,7 @@ void evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void));
NOTE: This function has no effect in Libevent 2.0.4-alpha and later,
since Libevent now provides its own secure RNG.
*/
+EVENT2_EXPORT_SYMBOL
void evdns_set_random_bytes_fn(void (*fn)(char *, size_t));
/*
@@ -579,35 +617,46 @@ typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, vo
@param user_data Data to pass to the callback.
@return an evdns_server_port structure for this server port.
*/
+EVENT2_EXPORT_SYMBOL
struct evdns_server_port *evdns_add_server_port_with_base(struct event_base *base, evutil_socket_t socket, int flags, evdns_request_callback_fn_type callback, void *user_data);
/** Close down a DNS server port, and free associated structures. */
+EVENT2_EXPORT_SYMBOL
void evdns_close_server_port(struct evdns_server_port *port);
/** Sets some flags in a reply we're building.
Allows setting of the AA or RD flags
*/
+EVENT2_EXPORT_SYMBOL
void evdns_server_request_set_flags(struct evdns_server_request *req, int flags);
/* Functions to add an answer to an in-progress DNS reply.
*/
+EVENT2_EXPORT_SYMBOL
int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int dns_class, int ttl, int datalen, int is_name, const char *data);
+EVENT2_EXPORT_SYMBOL
int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl);
+EVENT2_EXPORT_SYMBOL
int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl);
+EVENT2_EXPORT_SYMBOL
int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl);
+EVENT2_EXPORT_SYMBOL
int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl);
/**
Send back a response to a DNS request, and free the request structure.
*/
+EVENT2_EXPORT_SYMBOL
int evdns_server_request_respond(struct evdns_server_request *req, int err);
/**
Free a DNS request without sending back a reply.
*/
+EVENT2_EXPORT_SYMBOL
int evdns_server_request_drop(struct evdns_server_request *req);
struct sockaddr;
/**
Get the address that made a DNS request.
*/
+EVENT2_EXPORT_SYMBOL
int evdns_server_request_get_requesting_addr(struct evdns_server_request *req, struct sockaddr *sa, int addr_len);
/** Callback for evdns_getaddrinfo. */
@@ -632,6 +681,7 @@ struct evdns_getaddrinfo_request;
* - For ai_socktype, we only handle SOCKTYPE_STREAM, SOCKTYPE_UDP, and 0.
* - For ai_protocol, we only handle IPPROTO_TCP, IPPROTO_UDP, and 0.
*/
+EVENT2_EXPORT_SYMBOL
struct evdns_getaddrinfo_request *evdns_getaddrinfo(
struct evdns_base *dns_base,
const char *nodename, const char *servname,
@@ -641,6 +691,7 @@ struct evdns_getaddrinfo_request *evdns_getaddrinfo(
/* Cancel an in-progress evdns_getaddrinfo. This MUST NOT be called after the
* getaddrinfo's callback has been invoked. The resolves will be canceled,
* and the callback will be invoked with the error EVUTIL_EAI_CANCEL. */
+EVENT2_EXPORT_SYMBOL
void evdns_getaddrinfo_cancel(struct evdns_getaddrinfo_request *req);
#ifdef __cplusplus
diff --git a/include/event2/event.h b/include/event2/event.h
index baf0d241..6e2b884d 100644
--- a/include/event2/event.h
+++ b/include/event2/event.h
@@ -54,7 +54,7 @@
@section usage Standard usage
- Every program that uses Libevent must inclurde the <event2/event.h>
+ Every program that uses Libevent must include the <event2/event.h>
header, and pass the -levent flag to the linker. (You can instead link
-levent_core if you only want the main event and buffered IO-based code,
and don't want to link any protocol code.)
@@ -124,9 +124,11 @@
@section timers Timers
Libevent can also be used to create timers that invoke a callback after a
- certain amount of time has expired. The evtimer_new() function returns
+ certain amount of time has expired. The evtimer_new() macro returns
an event struct to use as a timer. To activate the timer, call
evtimer_add(). Timers can be deactivated by calling evtimer_del().
+ (These macros are thin wrappers around event_new(), event_add(),
+ and event_del(); you can also use those instead.)
@section evdns Asynchronous DNS resolution
@@ -180,6 +182,8 @@
Core functions for waiting for and receiving events, and using event bases.
*/
+#include <event2/visibility.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -314,6 +318,7 @@ struct event_config
*
* @see event_debug_unassign()
*/
+EVENT2_EXPORT_SYMBOL
void event_enable_debug_mode(void);
/**
@@ -325,6 +330,7 @@ void event_enable_debug_mode(void);
*
* @see event_enable_debug_mode()
*/
+EVENT2_EXPORT_SYMBOL
void event_debug_unassign(struct event *);
/**
@@ -334,6 +340,7 @@ void event_debug_unassign(struct event *);
*
* @see event_base_free(), event_base_new_with_config()
*/
+EVENT2_EXPORT_SYMBOL
struct event_base *event_base_new(void);
/**
@@ -346,21 +353,23 @@ struct event_base *event_base_new(void);
@return 0 if successful, or -1 if some events could not be re-added.
@see event_base_new()
*/
+EVENT2_EXPORT_SYMBOL
int event_reinit(struct event_base *base);
/**
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
+ This loop will run the event base until either there are no more pending or
+ active, or until something calls event_base_loopbreak() or
event_base_loopexit().
@param base the event_base structure returned by event_base_new() or
event_base_new_with_config()
- @return 0 if successful, -1 if an error occurred, or 1 if no events were
- registered.
+ @return 0 if successful, -1 if an error occurred, or 1 if we exited because
+ no events were pending or active.
@see event_base_loop()
*/
+EVENT2_EXPORT_SYMBOL
int event_base_dispatch(struct event_base *);
/**
@@ -369,6 +378,7 @@ int event_base_dispatch(struct event_base *);
@param eb the event_base structure returned by event_base_new()
@return a string identifying the kernel event mechanism (kqueue, epoll, etc.)
*/
+EVENT2_EXPORT_SYMBOL
const char *event_base_get_method(const struct event_base *);
/**
@@ -383,6 +393,7 @@ const char *event_base_get_method(const struct event_base *);
The end of the array is indicated by a NULL pointer. If an
error is encountered NULL is returned.
*/
+EVENT2_EXPORT_SYMBOL
const char **event_get_supported_methods(void);
/**
@@ -420,9 +431,23 @@ const char **event_get_supported_methods(void);
counts for
@return the number of events specified in the flags
*/
+EVENT2_EXPORT_SYMBOL
int event_base_get_num_events(struct event_base *, unsigned int);
/**
+ Get the maximum number of events in a given event_base as specified in the
+ flags.
+
+ @param eb the event_base structure returned by event_base_new()
+ @param flags a bitwise combination of the kinds of events to aggregate
+ counts for
+ @param clear option used to reset the maximum count.
+ @return the number of events specified in the flags
+ */
+EVENT2_EXPORT_SYMBOL
+int event_base_get_max_events(struct event_base *, unsigned int, int);
+
+/**
Allocates a new event configuration object.
The event configuration object can be used to change the behavior of
@@ -432,6 +457,7 @@ int event_base_get_num_events(struct event_base *, unsigned int);
NULL if an error is encountered.
@see event_base_new_with_config(), event_config_free(), event_config
*/
+EVENT2_EXPORT_SYMBOL
struct event_config *event_config_new(void);
/**
@@ -439,6 +465,7 @@ struct event_config *event_config_new(void);
@param cfg the event configuration object to be freed.
*/
+EVENT2_EXPORT_SYMBOL
void event_config_free(struct event_config *cfg);
/**
@@ -453,6 +480,7 @@ void event_config_free(struct event_config *cfg);
@param method the name of the event method to avoid
@return 0 on success, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int event_config_avoid_method(struct event_config *cfg, const char *method);
/**
@@ -474,7 +502,14 @@ enum event_method_feature {
EV_FEATURE_O1 = 0x02,
/** Require an event method that allows file descriptors as well as
* sockets. */
- EV_FEATURE_FDS = 0x04
+ EV_FEATURE_FDS = 0x04,
+ /** Require an event method that allows you to use EV_CLOSED to detect
+ * connection close without the necessity of reading all the pending data.
+ *
+ * Methods that do support EV_CLOSED may not be able to provide support on
+ * all kernel versions.
+ **/
+ EV_FEATURE_EARLY_CLOSE = 0x08
};
/**
@@ -516,7 +551,7 @@ enum event_base_config_flag {
if you have any fds cloned by dup() or its variants. Doing so
will produce strange and hard-to-diagnose bugs.
- This flag can also be activated by settnig the
+ This flag can also be activated by setting the
EVENT_EPOLL_USE_CHANGELIST environment variable.
This flag has no effect if you wind up using a backend other than
@@ -539,6 +574,7 @@ enum event_base_config_flag {
@see event_method_feature
*/
+EVENT2_EXPORT_SYMBOL
int event_base_get_features(const struct event_base *base);
/**
@@ -563,6 +599,7 @@ int event_base_get_features(const struct event_base *base);
@return 0 on success, -1 on failure.
@see event_method_feature, event_base_new_with_config()
*/
+EVENT2_EXPORT_SYMBOL
int event_config_require_features(struct event_config *cfg, int feature);
/**
@@ -571,6 +608,7 @@ int event_config_require_features(struct event_config *cfg, int feature);
*
* @see event_base_config_flags, event_base_new_with_config()
**/
+EVENT2_EXPORT_SYMBOL
int event_config_set_flag(struct event_config *cfg, int flag);
/**
@@ -582,6 +620,7 @@ int event_config_set_flag(struct event_config *cfg, int flag);
* @param cpus the number of cpus
* @return 0 on success, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int event_config_set_num_cpus_hint(struct event_config *cfg, int cpus);
/**
@@ -612,6 +651,7 @@ int event_config_set_num_cpus_hint(struct event_config *cfg, int cpus);
* for events of priority 1 and above, and so on.
* @return 0 on success, -1 on failure.
**/
+EVENT2_EXPORT_SYMBOL
int event_config_set_max_dispatch_interval(struct event_config *cfg,
const struct timeval *max_interval, int max_callbacks,
int min_priority);
@@ -628,6 +668,7 @@ int event_config_set_max_dispatch_interval(struct event_config *cfg,
or NULL if no event base can be created with the requested event_config.
@see event_base_new(), event_base_free(), event_init(), event_assign()
*/
+EVENT2_EXPORT_SYMBOL
struct event_base *event_base_new_with_config(const struct event_config *);
/**
@@ -641,6 +682,7 @@ struct event_base *event_base_new_with_config(const struct event_config *);
@param eb an event_base to be freed
*/
+EVENT2_EXPORT_SYMBOL
void event_base_free(struct event_base *);
/**
@@ -649,6 +691,7 @@ void event_base_free(struct event_base *);
THIS IS AN EXPERIMENTAL API. IT MIGHT CHANGE BEFORE THE LIBEVENT 2.1 SERIES
BECOMES STABLE.
*/
+EVENT2_EXPORT_SYMBOL
void event_base_free_nofinalize(struct event_base *);
/** @name Log severities
@@ -683,6 +726,7 @@ typedef void (*event_log_cb)(int severity, const char *msg);
NOTE: The function you provide *must not* call any other libevent
functionality. Doing so can produce undefined behavior.
*/
+EVENT2_EXPORT_SYMBOL
void event_set_log_callback(event_log_cb cb);
/**
@@ -704,6 +748,7 @@ typedef void (*event_fatal_cb)(int err);
Libevent will (almost) always log an EVENT_LOG_ERR message before calling
this function; look at the last log message to see why Libevent has died.
*/
+EVENT2_EXPORT_SYMBOL
void event_set_fatal_callback(event_fatal_cb cb);
#define EVENT_DBG_ALL 0xffffffffu
@@ -723,6 +768,7 @@ void event_set_fatal_callback(event_fatal_cb cb);
"EVENT_DBG_ALL" to turn debugging logs on, or "EVENT_DBG_NONE" to turn
debugging logs off.
*/
+EVENT2_EXPORT_SYMBOL
void event_enable_debug_logging(ev_uint32_t which);
/**
@@ -734,6 +780,7 @@ void event_enable_debug_logging(ev_uint32_t which);
@param ev the event
@return 0 on success, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int event_base_set(struct event_base *, struct event *);
/** @name Loop flags
@@ -760,18 +807,19 @@ 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'
+ pending or active events, or until something calls event_base_loopbreak() or
+ event_base_loopexit(). You can override this behavior with the 'flags'
argument.
@param eb the event_base structure returned by event_base_new() or
event_base_new_with_config()
@param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK
- @return 0 if successful, -1 if an error occurred, or 1 if no events were
- registered.
+ @return 0 if successful, -1 if an error occurred, or 1 if we exited because
+ no events were pending or active.
@see event_base_loopexit(), event_base_dispatch(), EVLOOP_ONCE,
EVLOOP_NONBLOCK
*/
+EVENT2_EXPORT_SYMBOL
int event_base_loop(struct event_base *, int);
/**
@@ -789,6 +837,7 @@ int event_base_loop(struct event_base *, int);
@return 0 if successful, or -1 if an error occurred
@see event_base_loopbreak()
*/
+EVENT2_EXPORT_SYMBOL
int event_base_loopexit(struct event_base *, const struct timeval *);
/**
@@ -804,6 +853,7 @@ int event_base_loopexit(struct event_base *, const struct timeval *);
@return 0 if successful, or -1 if an error occurred
@see event_base_loopexit()
*/
+EVENT2_EXPORT_SYMBOL
int event_base_loopbreak(struct event_base *);
/**
@@ -823,6 +873,7 @@ int event_base_loopbreak(struct event_base *);
@return 0 if successful, or -1 if an error occurred
@see event_base_loopbreak()
*/
+EVENT2_EXPORT_SYMBOL
int event_base_loopcontinue(struct event_base *);
/**
@@ -837,6 +888,7 @@ int event_base_loopcontinue(struct event_base *);
@see event_base_loopexit()
@see event_base_got_break()
*/
+EVENT2_EXPORT_SYMBOL
int event_base_got_exit(struct event_base *);
/**
@@ -851,6 +903,7 @@ int event_base_got_exit(struct event_base *);
@see event_base_loopbreak()
@see event_base_got_exit()
*/
+EVENT2_EXPORT_SYMBOL
int event_base_got_break(struct event_base *);
/**
@@ -890,6 +943,15 @@ int event_base_got_break(struct event_base *);
* BECOMES STABLE.
**/
#define EV_FINALIZE 0x40
+/**
+ * Detects connection close events. You can use this to detect when a
+ * connection has been closed, without having to read all the pending data
+ * from a connection.
+ *
+ * Not all backends support EV_CLOSED. To detect or require it, use the
+ * feature flag EV_FEATURE_EARLY_CLOSE.
+ **/
+#define EV_CLOSED 0x80
/**@}*/
/**
@@ -957,6 +1019,7 @@ typedef void (*event_callback_fn)(evutil_socket_t, short, void *);
event_assign().
@see event_new(), event_assign()
*/
+EVENT2_EXPORT_SYMBOL
void *event_self_cbarg(void);
/**
@@ -1007,6 +1070,7 @@ void *event_self_cbarg(void);
event_free().
@see event_free(), event_add(), event_del(), event_assign()
*/
+EVENT2_EXPORT_SYMBOL
struct event *event_new(struct event_base *, evutil_socket_t, short, event_callback_fn, void *);
@@ -1048,6 +1112,7 @@ struct event *event_new(struct event_base *, evutil_socket_t, short, event_callb
@see event_new(), event_add(), event_del(), event_base_once(),
event_get_struct_event_size()
*/
+EVENT2_EXPORT_SYMBOL
int event_assign(struct event *, struct event_base *, evutil_socket_t, short, event_callback_fn, void *);
/**
@@ -1056,6 +1121,7 @@ int event_assign(struct event *, struct event_base *, evutil_socket_t, short, ev
If the event is pending or active, first make it non-pending and
non-active.
*/
+EVENT2_EXPORT_SYMBOL
void event_free(struct event *);
/**
@@ -1100,7 +1166,9 @@ typedef void (*event_finalize_callback_fn)(struct event *, void *);
@return 0 on succes, -1 on failure.
*/
/**@{*/
+EVENT2_EXPORT_SYMBOL
int event_finalize(unsigned, struct event *, event_finalize_callback_fn);
+EVENT2_EXPORT_SYMBOL
int event_free_finalize(unsigned, struct event *, event_finalize_callback_fn);
/**@}*/
@@ -1128,13 +1196,14 @@ int event_free_finalize(unsigned, struct event *, event_finalize_callback_fn);
EV_TIMEOUT event succees immediately.
@return 0 if successful, or -1 if an error occurred
*/
+EVENT2_EXPORT_SYMBOL
int event_base_once(struct event_base *, evutil_socket_t, short, event_callback_fn, void *, const struct timeval *);
/**
Add an event to the set of pending events.
- The function event_add() schedules the execution of the ev event when the
- event specified in event_assign()/event_new() occurs, or when the time
+ The function event_add() schedules the execution of the event 'ev' when the
+ condition specified by event_assign() or event_new() occurs, or when the time
specified in timeout has elapesed. If atimeout is NULL, no timeout
occurs and the function will only be
called if a matching event occurs. The event in the
@@ -1151,6 +1220,7 @@ int event_base_once(struct event_base *, evutil_socket_t, short, event_callback_
@return 0 if successful, or -1 if an error occurred
@see event_del(), event_assign(), event_new()
*/
+EVENT2_EXPORT_SYMBOL
int event_add(struct event *ev, const struct timeval *timeout);
/**
@@ -1162,6 +1232,7 @@ int event_add(struct event *ev, const struct timeval *timeout);
@param ev an event struct initialized via event_assign() or event_new()
@return 0 on success, or -1 if an error occurrect.
*/
+EVENT2_EXPORT_SYMBOL
int event_remove_timer(struct event *ev);
/**
@@ -1175,6 +1246,7 @@ int event_remove_timer(struct event *ev);
@return 0 if successful, or -1 if an error occurred
@see event_add()
*/
+EVENT2_EXPORT_SYMBOL
int event_del(struct event *);
/**
@@ -1185,6 +1257,7 @@ int event_del(struct event *);
THIS IS AN EXPERIMENTAL API. IT MIGHT CHANGE BEFORE THE LIBEVENT 2.1 SERIES
BECOMES STABLE.
*/
+EVENT2_EXPORT_SYMBOL
int event_del_noblock(struct event *ev);
/**
As event_del(), but always blocks while the event's callback is running
@@ -1194,6 +1267,7 @@ int event_del_noblock(struct event *ev);
THIS IS AN EXPERIMENTAL API. IT MIGHT CHANGE BEFORE THE LIBEVENT 2.1 SERIES
BECOMES STABLE.
*/
+EVENT2_EXPORT_SYMBOL
int event_del_block(struct event *ev);
/**
@@ -1210,6 +1284,7 @@ int event_del_block(struct event *ev);
@param res a set of flags to pass to the event's callback.
@param ncalls an obsolete argument: this is ignored.
**/
+EVENT2_EXPORT_SYMBOL
void event_active(struct event *ev, int res, short ncalls);
/**
@@ -1225,6 +1300,7 @@ void event_active(struct event *ev, int res, short ncalls);
@return true if the event is pending on any of the events in 'what', (that
is to say, it has been added), or 0 if the event is not added.
*/
+EVENT2_EXPORT_SYMBOL
int event_pending(const struct event *ev, short events, struct timeval *tv);
/**
@@ -1233,6 +1309,7 @@ int event_pending(const struct event *ev, short events, struct timeval *tv);
The behavior of this function is not defined when called from outside the
callback function for an event.
*/
+EVENT2_EXPORT_SYMBOL
struct event *event_base_get_running_event(struct event_base *base);
/**
@@ -1250,6 +1327,7 @@ struct event *event_base_get_running_event(struct event_base *base);
@return 1 if the structure might be initialized, or 0 if it has not been
initialized
*/
+EVENT2_EXPORT_SYMBOL
int event_initialized(const struct event *ev);
/**
@@ -1261,32 +1339,38 @@ int event_initialized(const struct event *ev);
Get the socket or signal assigned to an event, or -1 if the event has
no socket.
*/
+EVENT2_EXPORT_SYMBOL
evutil_socket_t event_get_fd(const struct event *ev);
/**
Get the event_base associated with an event.
*/
+EVENT2_EXPORT_SYMBOL
struct event_base *event_get_base(const struct event *ev);
/**
Return the events (EV_READ, EV_WRITE, etc) assigned to an event.
*/
+EVENT2_EXPORT_SYMBOL
short event_get_events(const struct event *ev);
/**
Return the callback assigned to an event.
*/
+EVENT2_EXPORT_SYMBOL
event_callback_fn event_get_callback(const struct event *ev);
/**
Return the callback argument assigned to an event.
*/
+EVENT2_EXPORT_SYMBOL
void *event_get_callback_arg(const struct event *ev);
/**
Return the priority of an event.
@see event_priority_init(), event_get_priority()
*/
+EVENT2_EXPORT_SYMBOL
int event_get_priority(const struct event *ev);
/**
@@ -1296,6 +1380,7 @@ int event_get_priority(const struct event *ev);
If any of the "_out" arguments is NULL, it will be ignored.
*/
+EVENT2_EXPORT_SYMBOL
void event_get_assignment(const struct event *event,
struct event_base **base_out, evutil_socket_t *fd_out, short *events_out,
event_callback_fn *callback_out, void **arg_out);
@@ -1313,6 +1398,7 @@ void event_get_assignment(const struct event *event,
We might do this to help ensure ABI-compatibility between different
versions of Libevent.
*/
+EVENT2_EXPORT_SYMBOL
size_t event_get_struct_event_size(void);
/**
@@ -1324,6 +1410,7 @@ size_t event_get_struct_event_size(void);
@return a string containing the version number of Libevent
*/
+EVENT2_EXPORT_SYMBOL
const char *event_get_version(void);
/**
@@ -1337,6 +1424,7 @@ const char *event_get_version(void);
the version number. The low-order byte is unused. For example, version
2.0.1-alpha has a numeric representation of 0x02000100
*/
+EVENT2_EXPORT_SYMBOL
ev_uint32_t event_get_version_number(void);
/** As event_get_version, but gives the version of Libevent's headers. */
@@ -1374,6 +1462,7 @@ ev_uint32_t event_get_version_number(void);
@return 0 if successful, or -1 if an error occurred
@see event_priority_set()
*/
+EVENT2_EXPORT_SYMBOL
int event_base_priority_init(struct event_base *, int);
/**
@@ -1383,6 +1472,7 @@ int event_base_priority_init(struct event_base *, int);
@return Number of different event priorities
@see event_base_priority_init()
*/
+EVENT2_EXPORT_SYMBOL
int event_base_get_npriorities(struct event_base *eb);
/**
@@ -1393,6 +1483,7 @@ int event_base_get_npriorities(struct event_base *eb);
@return 0 if successful, or -1 if an error occurred
@see event_priority_init(), event_get_priority()
*/
+EVENT2_EXPORT_SYMBOL
int event_priority_set(struct event *, int);
/**
@@ -1414,6 +1505,7 @@ int event_priority_set(struct event *, int);
(This optimization probably will not be worthwhile until you have thousands
or tens of thousands of events with the same timeout.)
*/
+EVENT2_EXPORT_SYMBOL
const struct timeval *event_base_init_common_timeout(struct event_base *base,
const struct timeval *duration);
@@ -1440,6 +1532,7 @@ const struct timeval *event_base_init_common_timeout(struct event_base *base,
@param realloc_fn A replacement for realloc
@param free_fn A replacement for free.
**/
+EVENT2_EXPORT_SYMBOL
void event_set_mem_functions(
void *(*malloc_fn)(size_t sz),
void *(*realloc_fn)(void *ptr, size_t sz),
@@ -1459,10 +1552,36 @@ void event_set_mem_functions(
@param base An event_base on which to scan the events.
@param output A stdio file to write on.
*/
+EVENT2_EXPORT_SYMBOL
void event_base_dump_events(struct event_base *, FILE *);
/**
+ Activates all pending events for the given fd and event mask.
+
+ This function activates pending events only. Events which have not been
+ added will not become active.
+
+ @param base the event_base on which to activate the events.
+ @param fd An fd to active events on.
+ @param events One or more of EV_{READ,WRITE}.
+ */
+EVENT2_EXPORT_SYMBOL
+void event_base_active_by_fd(struct event_base *base, evutil_socket_t fd, short events);
+
+/**
+ Activates all pending signals with a given signal number
+
+ This function activates pending events only. Events which have not been
+ added will not become active.
+
+ @param base the event_base on which to activate the events.
+ @param fd The signal to active events on.
+ */
+EVENT2_EXPORT_SYMBOL
+void event_base_active_by_signal(struct event_base *base, int sig);
+
+/**
* Callback for iterating events in an event base via event_base_foreach_event
*/
typedef int (*event_base_foreach_event_cb)(const struct event_base *, const struct event *, void *);
@@ -1492,6 +1611,7 @@ typedef int (*event_base_foreach_event_cb)(const struct event_base *, const stru
@return 0 if we iterated over every event, or the value returned by the
callback function if the loop exited early.
*/
+EVENT2_EXPORT_SYMBOL
int event_base_foreach_event(struct event_base *base, event_base_foreach_event_cb fn, void *arg);
@@ -1506,6 +1626,7 @@ int event_base_foreach_event(struct event_base *base, event_base_foreach_event_c
Returns 0 on success, negative on failure.
*/
+EVENT2_EXPORT_SYMBOL
int event_base_gettimeofday_cached(struct event_base *base,
struct timeval *tv);
@@ -1521,6 +1642,7 @@ int event_base_gettimeofday_cached(struct event_base *base,
*
* @return 0 on success, -1 on failure
*/
+EVENT2_EXPORT_SYMBOL
int event_base_update_cache_time(struct event_base *base);
/** Release up all globally-allocated resources allocated by Libevent.
@@ -1537,6 +1659,7 @@ int event_base_update_cache_time(struct event_base *base);
You should only call this function when no other Libevent functions will
be invoked -- e.g., when cleanly exiting a program.
*/
+EVENT2_EXPORT_SYMBOL
void libevent_global_shutdown(void);
#ifdef __cplusplus
diff --git a/include/event2/event_compat.h b/include/event2/event_compat.h
index 87403a4d..5110175a 100644
--- a/include/event2/event_compat.h
+++ b/include/event2/event_compat.h
@@ -41,6 +41,7 @@
@deprecated All functions in this file are by definition deprecated.
*/
+#include <event2/visibility.h>
#ifdef __cplusplus
extern "C" {
@@ -70,6 +71,7 @@ extern "C" {
@see event_base_set(), event_base_new()
*/
+EVENT2_EXPORT_SYMBOL
struct event_base *event_init(void);
/**
@@ -83,6 +85,7 @@ struct event_base *event_init(void);
@see event_base_dispatch(), event_init()
*/
+EVENT2_EXPORT_SYMBOL
int event_dispatch(void);
/**
@@ -96,6 +99,7 @@ int event_dispatch(void);
@see event_base_loop(), event_init()
*/
+EVENT2_EXPORT_SYMBOL
int event_loop(int);
@@ -111,6 +115,7 @@ int event_loop(int);
@see event_init, event_base_loopexit()
*/
+EVENT2_EXPORT_SYMBOL
int event_loopexit(const struct timeval *);
@@ -126,6 +131,7 @@ int event_loopexit(const struct timeval *);
@see event_base_loopbreak(), event_init()
*/
+EVENT2_EXPORT_SYMBOL
int event_loopbreak(void);
/**
@@ -137,6 +143,7 @@ int event_loopbreak(void);
@see event_base_once()
*/
+EVENT2_EXPORT_SYMBOL
int event_once(evutil_socket_t , short,
void (*)(evutil_socket_t, short, void *), void *, const struct timeval *);
@@ -150,6 +157,7 @@ int event_once(evutil_socket_t , short,
@see event_base_get_method()
*/
+EVENT2_EXPORT_SYMBOL
const char *event_get_method(void);
@@ -162,6 +170,7 @@ const char *event_get_method(void);
@see event_base_priority_init()
*/
+EVENT2_EXPORT_SYMBOL
int event_priority_init(int);
/**
@@ -171,6 +180,7 @@ int event_priority_init(int);
a subsequent call to event_base_set() to be safe under most circumstances.
Use event_assign() or event_new() instead.
*/
+EVENT2_EXPORT_SYMBOL
void event_set(struct event *, evutil_socket_t, short, void (*)(evutil_socket_t, short, void *), void *);
#define evtimer_set(ev, cb, arg) event_set((ev), -1, 0, (cb), (arg))
diff --git a/include/event2/http.h b/include/event2/http.h
index 956d9d6c..81f44b85 100644
--- a/include/event2/http.h
+++ b/include/event2/http.h
@@ -29,6 +29,7 @@
/* For int types. */
#include <event2/util.h>
+#include <event2/visibility.h>
#ifdef __cplusplus
extern "C" {
@@ -38,6 +39,7 @@ extern "C" {
struct evbuffer;
struct event_base;
struct bufferevent;
+struct evhttp_connection;
/** @file event2/http.h
*
@@ -79,6 +81,7 @@ struct evdns_base;
* @return a pointer to a newly initialized evhttp server structure
* @see evhttp_free()
*/
+EVENT2_EXPORT_SYMBOL
struct evhttp *evhttp_new(struct event_base *base);
/**
@@ -93,6 +96,7 @@ struct evhttp *evhttp_new(struct event_base *base);
* @return 0 on success, -1 on failure.
* @see evhttp_accept_socket()
*/
+EVENT2_EXPORT_SYMBOL
int evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port);
/**
@@ -106,6 +110,7 @@ int evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t por
* @return Handle for the socket on success, NULL on failure.
* @see evhttp_bind_socket(), evhttp_del_accept_socket()
*/
+EVENT2_EXPORT_SYMBOL
struct evhttp_bound_socket *evhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint16_t port);
/**
@@ -124,6 +129,7 @@ struct evhttp_bound_socket *evhttp_bind_socket_with_handle(struct evhttp *http,
* @return 0 on success, -1 on failure.
* @see evhttp_bind_socket()
*/
+EVENT2_EXPORT_SYMBOL
int evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd);
/**
@@ -136,6 +142,7 @@ int evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd);
* @return Handle for the socket on success, NULL on failure.
* @see evhttp_accept_socket(), evhttp_del_accept_socket()
*/
+EVENT2_EXPORT_SYMBOL
struct evhttp_bound_socket *evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd);
/**
@@ -143,11 +150,13 @@ struct evhttp_bound_socket *evhttp_accept_socket_with_handle(struct evhttp *http
* returns an evhttp_bound_socket. The listener will be freed when the bound
* socket is freed.
*/
+EVENT2_EXPORT_SYMBOL
struct evhttp_bound_socket *evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener);
/**
* Return the listener used to implement a bound socket.
*/
+EVENT2_EXPORT_SYMBOL
struct evconnlistener *evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound);
typedef void evhttp_bound_socket_foreach_fn(struct evhttp_bound_socket *, void *);
@@ -161,6 +170,7 @@ typedef void evhttp_bound_socket_foreach_fn(struct evhttp_bound_socket *, void *
* @param function function to apply to every bound socket
* @param argument pointer value passed to function for every socket iterated
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_foreach_bound_socket(struct evhttp *http, evhttp_bound_socket_foreach_fn *function, void *argument);
/**
@@ -180,6 +190,7 @@ void evhttp_foreach_bound_socket(struct evhttp *http, evhttp_bound_socket_foreac
* @param bound_socket a handle returned by evhttp_{bind,accept}_socket_with_handle
* @see evhttp_bind_socket_with_handle(), evhttp_accept_socket_with_handle()
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound_socket);
/**
@@ -189,6 +200,7 @@ void evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *b
* @return the file descriptor used by the bound socket
* @see evhttp_bind_socket_with_handle(), evhttp_accept_socket_with_handle()
*/
+EVENT2_EXPORT_SYMBOL
evutil_socket_t evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound_socket);
/**
@@ -199,11 +211,14 @@ evutil_socket_t evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound_soc
* @param http the evhttp server object to be freed
* @see evhttp_start()
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_free(struct evhttp* http);
/** XXX Document. */
+EVENT2_EXPORT_SYMBOL
void evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size);
/** XXX Document. */
+EVENT2_EXPORT_SYMBOL
void evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size);
/**
@@ -214,6 +229,7 @@ void evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size);
@param http the http server on which to set the default content type
@param content_type the value for the Content-Type header
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_set_default_content_type(struct evhttp *http,
const char *content_type);
@@ -228,6 +244,7 @@ void evhttp_set_default_content_type(struct evhttp *http,
@param http the http server on which to set the methods
@param methods bit mask constructed from evhttp_cmd_type values
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_set_allowed_methods(struct evhttp* http, ev_uint16_t methods);
/**
@@ -239,10 +256,12 @@ void evhttp_set_allowed_methods(struct evhttp* http, ev_uint16_t methods);
@param cb_arg an additional context argument for the callback
@return 0 on success, -1 if the callback existed already, -2 on failure
*/
+EVENT2_EXPORT_SYMBOL
int evhttp_set_cb(struct evhttp *http, const char *path,
void (*cb)(struct evhttp_request *, void *), void *cb_arg);
/** Removes the callback for a specified URI */
+EVENT2_EXPORT_SYMBOL
int evhttp_del_cb(struct evhttp *, const char *);
/**
@@ -256,6 +275,7 @@ int evhttp_del_cb(struct evhttp *, const char *);
@param cb the callback to invoke for any unmatched requests
@param arg an context argument for the callback
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_set_gencb(struct evhttp *http,
void (*cb)(struct evhttp_request *, void *), void *arg);
@@ -273,6 +293,7 @@ void evhttp_set_gencb(struct evhttp *http,
@param cb the callback to invoke for incoming connections
@param arg an context argument for the callback
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_set_bevcb(struct evhttp *http,
struct bufferevent *(*cb)(struct event_base *, void *), void *arg);
@@ -298,6 +319,7 @@ void evhttp_set_bevcb(struct evhttp *http,
@return 0 on success, -1 on failure
@see evhttp_remove_virtual_host()
*/
+EVENT2_EXPORT_SYMBOL
int evhttp_add_virtual_host(struct evhttp* http, const char *pattern,
struct evhttp* vhost);
@@ -309,6 +331,7 @@ int evhttp_add_virtual_host(struct evhttp* http, const char *pattern,
@return 0 on success, -1 on failure
@see evhttp_add_virtual_host()
*/
+EVENT2_EXPORT_SYMBOL
int evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost);
/**
@@ -319,6 +342,7 @@ int evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost);
@param alias the alias to add
@see evhttp_add_remove_alias()
*/
+EVENT2_EXPORT_SYMBOL
int evhttp_add_server_alias(struct evhttp *http, const char *alias);
/**
@@ -328,6 +352,7 @@ int evhttp_add_server_alias(struct evhttp *http, const char *alias);
@param alias the alias to remove
@see evhttp_add_server_alias()
*/
+EVENT2_EXPORT_SYMBOL
int evhttp_remove_server_alias(struct evhttp *http, const char *alias);
/**
@@ -336,6 +361,7 @@ int evhttp_remove_server_alias(struct evhttp *http, const char *alias);
* @param http an evhttp object
* @param timeout_in_secs the timeout, in seconds
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_set_timeout(struct evhttp *http, int timeout_in_secs);
/**
@@ -344,6 +370,7 @@ void evhttp_set_timeout(struct evhttp *http, int timeout_in_secs);
* @param http an evhttp object
* @param tv the timeout, or NULL
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_set_timeout_tv(struct evhttp *http, const struct timeval* tv);
/* Request/Response functionality */
@@ -356,6 +383,7 @@ void evhttp_set_timeout_tv(struct evhttp *http, const struct timeval* tv);
* @param reason a brief explanation of the error. If this is NULL, we'll
* just use the standard meaning of the error code.
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_send_error(struct evhttp_request *req, int error,
const char *reason);
@@ -372,6 +400,7 @@ void evhttp_send_error(struct evhttp_request *req, int error,
* @param reason a brief message to send with the response code
* @param databuf the body of the response
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_send_reply(struct evhttp_request *req, int code,
const char *reason, struct evbuffer *databuf);
@@ -391,6 +420,7 @@ void evhttp_send_reply(struct evhttp_request *req, int code,
@param code the HTTP response code to send
@param reason a brief message to send with the response code
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_send_reply_start(struct evhttp_request *req, int code,
const char *reason);
@@ -405,13 +435,33 @@ void evhttp_send_reply_start(struct evhttp_request *req, int code,
@param req a request object
@param databuf the data chunk to send as part of the reply.
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_send_reply_chunk(struct evhttp_request *req,
struct evbuffer *databuf);
+
+/**
+ Send another data chunk as part of an ongoing chunked reply.
+
+ The reply chunk consists of the data in databuf. After calling
+ evhttp_send_reply_chunk() databuf will be empty, but the buffer is
+ still owned by the caller and needs to be deallocated by the caller
+ if necessary.
+
+ @param req a request object
+ @param databuf the data chunk to send as part of the reply.
+ @param cb callback funcion
+ @param call back's argument.
+*/
+EVENT2_EXPORT_SYMBOL
+void evhttp_send_reply_chunk_with_cb(struct evhttp_request *, struct evbuffer *,
+ void (*cb)(struct evhttp_connection *, void *), void *arg);
+
/**
Complete a chunked reply, freeing the request as appropriate.
@param req a request object
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_send_reply_end(struct evhttp_request *req);
/*
@@ -455,17 +505,20 @@ enum evhttp_request_kind { EVHTTP_REQUEST, EVHTTP_RESPONSE };
* @param port the port to connect to
* @return an evhttp_connection object that can be used for making requests
*/
+EVENT2_EXPORT_SYMBOL
struct evhttp_connection *evhttp_connection_base_bufferevent_new(
struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev, const char *address, unsigned short port);
/**
* Return the bufferevent that an evhttp_connection is using.
*/
+EVENT2_EXPORT_SYMBOL
struct bufferevent* evhttp_connection_get_bufferevent(struct evhttp_connection *evcon);
/**
* Return the HTTP server associated with this connection, or NULL.
*/
+EVENT2_EXPORT_SYMBOL
struct evhttp *evhttp_connection_get_server(struct evhttp_connection *evcon);
/**
@@ -473,6 +526,7 @@ struct evhttp *evhttp_connection_get_server(struct evhttp_connection *evcon);
* parameters. The callback is executed when the request completed or an
* error occurred.
*/
+EVENT2_EXPORT_SYMBOL
struct evhttp_request *evhttp_request_new(
void (*cb)(struct evhttp_request *, void *), void *arg);
@@ -483,10 +537,21 @@ struct evhttp_request *evhttp_request_new(
* response. May drain the input buffer; it will be drained
* automatically on return.
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_request_set_chunked_cb(struct evhttp_request *,
void (*cb)(struct evhttp_request *, void *));
/**
+ * Register callback for additional parsing of request headers.
+ * @param cb will be called after receiving and parsing the full header.
+ * It allows analyzing the header and possibly closing the connection
+ * by returning a value < 0.
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_request_set_header_cb(struct evhttp_request *,
+ int (*cb)(struct evhttp_request *, void *));
+
+/**
* The different error types supported by evhttp
*
* @see evhttp_request_set_error_cb()
@@ -524,10 +589,28 @@ enum evhttp_request_error {
* On error, both the error callback and the regular callback will be called,
* error callback is called before the regular callback.
**/
+EVENT2_EXPORT_SYMBOL
void evhttp_request_set_error_cb(struct evhttp_request *,
void (*)(enum evhttp_request_error, void *));
+/**
+ * Set a callback to be called on request completion of evhttp_send_* function.
+ *
+ * The callback function will be called on the completion of the request after
+ * the output data has been written and before the evhttp_request object
+ * is destroyed. This can be useful for tracking resources associated with a
+ * request (ex: timing metrics).
+ *
+ * @param req a request object
+ * @param cb callback function that will be called on request completion
+ * @param cb_arg an additional context argument for the callback
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_request_set_on_complete_cb(struct evhttp_request *req,
+ void (*cb)(struct evhttp_request *, void *), void *cb_arg);
+
/** Frees the request object and removes associated events. */
+EVENT2_EXPORT_SYMBOL
void evhttp_request_free(struct evhttp_request *req);
/**
@@ -542,6 +625,7 @@ void evhttp_request_free(struct evhttp_request *req);
* @param port the port to connect to
* @return an evhttp_connection object that can be used for making requests
*/
+EVENT2_EXPORT_SYMBOL
struct evhttp_connection *evhttp_connection_base_new(
struct event_base *base, struct evdns_base *dnsbase,
const char *address, unsigned short port);
@@ -551,9 +635,11 @@ struct evhttp_connection *evhttp_connection_base_new(
* Can be used in a request callback to keep onto the request until
* evhttp_request_free() is explicitly called by the user.
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_request_own(struct evhttp_request *req);
/** Returns 1 if the request is owned by the user */
+EVENT2_EXPORT_SYMBOL
int evhttp_request_is_owned(struct evhttp_request *req);
/**
@@ -562,36 +648,45 @@ int evhttp_request_is_owned(struct evhttp_request *req);
* The user needs to either free the request explicitly or call
* evhttp_send_reply_end().
*/
+EVENT2_EXPORT_SYMBOL
struct evhttp_connection *evhttp_request_get_connection(struct evhttp_request *req);
/**
* Returns the underlying event_base for this connection
*/
+EVENT2_EXPORT_SYMBOL
struct event_base *evhttp_connection_get_base(struct evhttp_connection *req);
+EVENT2_EXPORT_SYMBOL
void evhttp_connection_set_max_headers_size(struct evhttp_connection *evcon,
ev_ssize_t new_max_headers_size);
+EVENT2_EXPORT_SYMBOL
void evhttp_connection_set_max_body_size(struct evhttp_connection* evcon,
ev_ssize_t new_max_body_size);
/** Frees an http connection */
+EVENT2_EXPORT_SYMBOL
void evhttp_connection_free(struct evhttp_connection *evcon);
/** sets the ip address from which http connections are made */
+EVENT2_EXPORT_SYMBOL
void evhttp_connection_set_local_address(struct evhttp_connection *evcon,
const char *address);
/** sets the local port from which http connections are made */
+EVENT2_EXPORT_SYMBOL
void evhttp_connection_set_local_port(struct evhttp_connection *evcon,
ev_uint16_t port);
/** Sets the timeout in seconds for events related to this connection */
+EVENT2_EXPORT_SYMBOL
void evhttp_connection_set_timeout(struct evhttp_connection *evcon,
int timeout_in_secs);
/** Sets the timeout for events related to this connection. Takes a struct
* timeval. */
+EVENT2_EXPORT_SYMBOL
void evhttp_connection_set_timeout_tv(struct evhttp_connection *evcon,
const struct timeval *tv);
@@ -599,18 +694,22 @@ void evhttp_connection_set_timeout_tv(struct evhttp_connection *evcon,
* used if evhttp_connection_set_retries is used to make the number of retries
* at least one. Each retry after the first is twice as long as the one before
* it. */
+EVENT2_EXPORT_SYMBOL
void evhttp_connection_set_initial_retry_tv(struct evhttp_connection *evcon,
const struct timeval *tv);
/** Sets the retry limit for this connection - -1 repeats indefinitely */
+EVENT2_EXPORT_SYMBOL
void evhttp_connection_set_retries(struct evhttp_connection *evcon,
int retry_max);
/** Set a callback for connection close. */
+EVENT2_EXPORT_SYMBOL
void evhttp_connection_set_closecb(struct evhttp_connection *evcon,
void (*)(struct evhttp_connection *, void *), void *);
/** Get the remote address and port associated with this connection. */
+EVENT2_EXPORT_SYMBOL
void evhttp_connection_get_peer(struct evhttp_connection *evcon,
char **address, ev_uint16_t *port);
@@ -620,6 +719,7 @@ void evhttp_connection_get_peer(struct evhttp_connection *evcon,
* @return NULL if getpeername() return non success,
* or connection is not connected,
* otherwise it return pointer to struct sockaddr_storage */
+EVENT2_EXPORT_SYMBOL
const struct sockaddr*
evhttp_connection_get_addr(struct evhttp_connection *evcon);
@@ -636,6 +736,7 @@ evhttp_connection_get_addr(struct evhttp_connection *evcon);
@return 0 on success, -1 on failure
@see evhttp_cancel_request()
*/
+EVENT2_EXPORT_SYMBOL
int evhttp_make_request(struct evhttp_connection *evcon,
struct evhttp_request *req,
enum evhttp_cmd_type type, const char *uri);
@@ -653,6 +754,7 @@ int evhttp_make_request(struct evhttp_connection *evcon,
@param req the evhttp_request to cancel; req becomes invalid after this call.
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_cancel_request(struct evhttp_request *req);
/**
@@ -661,27 +763,37 @@ void evhttp_cancel_request(struct evhttp_request *req);
struct evhttp_uri;
/** Returns the request URI */
+EVENT2_EXPORT_SYMBOL
const char *evhttp_request_get_uri(const struct evhttp_request *req);
/** Returns the request URI (parsed) */
+EVENT2_EXPORT_SYMBOL
const struct evhttp_uri *evhttp_request_get_evhttp_uri(const struct evhttp_request *req);
/** Returns the request command */
+EVENT2_EXPORT_SYMBOL
enum evhttp_cmd_type evhttp_request_get_command(const struct evhttp_request *req);
+EVENT2_EXPORT_SYMBOL
int evhttp_request_get_response_code(const struct evhttp_request *req);
+EVENT2_EXPORT_SYMBOL
const char * evhttp_request_get_response_code_line(const struct evhttp_request *req);
/** Returns the input headers */
+EVENT2_EXPORT_SYMBOL
struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req);
/** Returns the output headers */
+EVENT2_EXPORT_SYMBOL
struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req);
/** Returns the input buffer */
+EVENT2_EXPORT_SYMBOL
struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req);
/** Returns the output buffer */
+EVENT2_EXPORT_SYMBOL
struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req);
/** Returns the host associated with the request. If a client sends an absolute
URI, the host part of that is preferred. Otherwise, the input headers are
searched for a Host: header. NULL is returned if no absolute URI or Host:
header is provided. */
+EVENT2_EXPORT_SYMBOL
const char *evhttp_request_get_host(struct evhttp_request *req);
/* Interfaces for dealing with HTTP headers */
@@ -695,6 +807,7 @@ const char *evhttp_request_get_host(struct evhttp_request *req);
could not be found.
@see evhttp_add_header(), evhttp_remove_header()
*/
+EVENT2_EXPORT_SYMBOL
const char *evhttp_find_header(const struct evkeyvalq *headers,
const char *key);
@@ -706,6 +819,7 @@ const char *evhttp_find_header(const struct evkeyvalq *headers,
@returns 0 if the header was removed, -1 otherwise.
@see evhttp_find_header(), evhttp_add_header()
*/
+EVENT2_EXPORT_SYMBOL
int evhttp_remove_header(struct evkeyvalq *headers, const char *key);
/**
@@ -717,6 +831,7 @@ int evhttp_remove_header(struct evkeyvalq *headers, const char *key);
@returns 0 on success, -1 otherwise.
@see evhttp_find_header(), evhttp_clear_headers()
*/
+EVENT2_EXPORT_SYMBOL
int evhttp_add_header(struct evkeyvalq *headers, const char *key, const char *value);
/**
@@ -724,6 +839,7 @@ int evhttp_add_header(struct evkeyvalq *headers, const char *key, const char *va
@param headers the evkeyvalq object from which to remove all headers
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_clear_headers(struct evkeyvalq *headers);
/* Miscellaneous utility functions */
@@ -740,6 +856,7 @@ void evhttp_clear_headers(struct evkeyvalq *headers);
@param str an unencoded string
@return a newly allocated URI-encoded string or NULL on failure
*/
+EVENT2_EXPORT_SYMBOL
char *evhttp_encode_uri(const char *str);
/**
@@ -756,6 +873,7 @@ char *evhttp_encode_uri(const char *str);
as +, not %20.
@return a newly allocate URI-encoded string, or NULL on failure.
*/
+EVENT2_EXPORT_SYMBOL
char *evhttp_uriencode(const char *str, ev_ssize_t size, int space_to_plus);
/**
@@ -772,6 +890,7 @@ char *evhttp_uriencode(const char *str, ev_ssize_t size, int space_to_plus);
@param uri an encoded URI
@return a newly allocated unencoded URI or NULL on failure
*/
+EVENT2_EXPORT_SYMBOL
char *evhttp_decode_uri(const char *uri);
/**
@@ -789,6 +908,7 @@ char *evhttp_decode_uri(const char *uri);
returned string
@return a newly allocated unencoded URI or NULL on failure
*/
+EVENT2_EXPORT_SYMBOL
char *evhttp_uridecode(const char *uri, int decode_plus,
size_t *size_out);
@@ -811,6 +931,7 @@ char *evhttp_uridecode(const char *uri, int decode_plus,
@param headers the head of the evkeyval queue
@return 0 on success, -1 on failure
*/
+EVENT2_EXPORT_SYMBOL
int evhttp_parse_query(const char *uri, struct evkeyvalq *headers);
/**
@@ -830,6 +951,7 @@ int evhttp_parse_query(const char *uri, struct evkeyvalq *headers);
@param headers the head of the evkeyval queue
@return 0 on success, -1 on failure
*/
+EVENT2_EXPORT_SYMBOL
int evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers);
/**
@@ -843,26 +965,31 @@ int evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers);
* @param html an unescaped HTML string
* @return an escaped HTML string or NULL on error
*/
+EVENT2_EXPORT_SYMBOL
char *evhttp_htmlescape(const char *html);
/**
* Return a new empty evhttp_uri with no fields set.
*/
+EVENT2_EXPORT_SYMBOL
struct evhttp_uri *evhttp_uri_new(void);
/**
* Changes the flags set on a given URI. See EVHTTP_URI_* for
* a list of flags.
**/
+EVENT2_EXPORT_SYMBOL
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. */
+EVENT2_EXPORT_SYMBOL
const char *evhttp_uri_get_scheme(const struct evhttp_uri *uri);
/**
* Return the userinfo part of an evhttp_uri, or NULL if it has no userinfo
* set.
*/
+EVENT2_EXPORT_SYMBOL
const char *evhttp_uri_get_userinfo(const struct evhttp_uri *uri);
/**
* Return the host part of an evhttp_uri, or NULL if it has no host set.
@@ -876,40 +1003,52 @@ const char *evhttp_uri_get_userinfo(const struct evhttp_uri *uri);
* "mailto:user@example.com" has a host of NULL, but "file:///etc/motd"
* has a host of "".
*/
+EVENT2_EXPORT_SYMBOL
const char *evhttp_uri_get_host(const struct evhttp_uri *uri);
/** Return the port part of an evhttp_uri, or -1 if there is no port set. */
+EVENT2_EXPORT_SYMBOL
int evhttp_uri_get_port(const struct evhttp_uri *uri);
/** Return the path part of an evhttp_uri, or NULL if it has no path set */
+EVENT2_EXPORT_SYMBOL
const char *evhttp_uri_get_path(const struct evhttp_uri *uri);
/** Return the query part of an evhttp_uri (excluding the leading "?"), or
* NULL if it has no query set */
+EVENT2_EXPORT_SYMBOL
const char *evhttp_uri_get_query(const struct evhttp_uri *uri);
/** Return the fragment part of an evhttp_uri (excluding the leading "#"),
* or NULL if it has no fragment set */
+EVENT2_EXPORT_SYMBOL
const char *evhttp_uri_get_fragment(const struct evhttp_uri *uri);
/** Set the scheme of an evhttp_uri, or clear the scheme if scheme==NULL.
* Returns 0 on success, -1 if scheme is not well-formed. */
+EVENT2_EXPORT_SYMBOL
int evhttp_uri_set_scheme(struct evhttp_uri *uri, const char *scheme);
/** Set the userinfo of an evhttp_uri, or clear the userinfo if userinfo==NULL.
* Returns 0 on success, -1 if userinfo is not well-formed. */
+EVENT2_EXPORT_SYMBOL
int evhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo);
/** Set the host of an evhttp_uri, or clear the host if host==NULL.
* Returns 0 on success, -1 if host is not well-formed. */
+EVENT2_EXPORT_SYMBOL
int evhttp_uri_set_host(struct evhttp_uri *uri, const char *host);
/** Set the port of an evhttp_uri, or clear the port if port==-1.
* Returns 0 on success, -1 if port is not well-formed. */
+EVENT2_EXPORT_SYMBOL
int evhttp_uri_set_port(struct evhttp_uri *uri, int port);
/** Set the path of an evhttp_uri, or clear the path if path==NULL.
* Returns 0 on success, -1 if path is not well-formed. */
+EVENT2_EXPORT_SYMBOL
int evhttp_uri_set_path(struct evhttp_uri *uri, const char *path);
/** Set the query of an evhttp_uri, or clear the query if query==NULL.
* The query should not include a leading "?".
* Returns 0 on success, -1 if query is not well-formed. */
+EVENT2_EXPORT_SYMBOL
int evhttp_uri_set_query(struct evhttp_uri *uri, const char *query);
/** Set the fragment of an evhttp_uri, or clear the fragment if fragment==NULL.
* The fragment should not include a leading "#".
* Returns 0 on success, -1 if fragment is not well-formed. */
+EVENT2_EXPORT_SYMBOL
int evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment);
/**
@@ -946,6 +1085,7 @@ int evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment);
* @return uri container to hold parsed data, or NULL if there is error
* @see evhttp_uri_free()
*/
+EVENT2_EXPORT_SYMBOL
struct evhttp_uri *evhttp_uri_parse_with_flags(const char *source_uri,
unsigned flags);
@@ -964,6 +1104,7 @@ struct evhttp_uri *evhttp_uri_parse_with_flags(const char *source_uri,
#define EVHTTP_URI_NONCONFORMANT 0x01
/** Alias for evhttp_uri_parse_with_flags(source_uri, 0) */
+EVENT2_EXPORT_SYMBOL
struct evhttp_uri *evhttp_uri_parse(const char *source_uri);
/**
@@ -973,6 +1114,7 @@ struct evhttp_uri *evhttp_uri_parse(const char *source_uri);
* @param uri container with parsed data
* @see evhttp_uri_parse()
*/
+EVENT2_EXPORT_SYMBOL
void evhttp_uri_free(struct evhttp_uri *uri);
/**
@@ -988,6 +1130,7 @@ void evhttp_uri_free(struct evhttp_uri *uri);
* @return an joined uri as string or NULL on error
* @see evhttp_uri_parse()
*/
+EVENT2_EXPORT_SYMBOL
char *evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit);
#ifdef __cplusplus
diff --git a/include/event2/http_struct.h b/include/event2/http_struct.h
index 25e19bd9..4bf5b1ff 100644
--- a/include/event2/http_struct.h
+++ b/include/event2/http_struct.h
@@ -120,6 +120,14 @@ struct {
* the regular callback.
*/
void (*chunk_cb)(struct evhttp_request *, void *);
+
+ /*
+ * Callback added for forked-daapd so they can collect ICY
+ * (shoutcast) metadata from the http header. If return
+ * int is negative the connection will be closed.
+ */
+ int (*header_cb)(struct evhttp_request *, void *);
+
/*
* Error callback - called when error is occured.
* @see evhttp_request_error for error types.
@@ -127,6 +135,13 @@ struct {
* @see evhttp_request_set_error_cb()
*/
void (*error_cb)(enum evhttp_request_error, void *);
+
+ /*
+ * Send complete callback - called when the request is actually
+ * sent and completed.
+ */
+ void (*on_complete_cb)(struct evhttp_request *, void *);
+ void *on_complete_cb_arg;
};
#ifdef __cplusplus
diff --git a/include/event2/listener.h b/include/event2/listener.h
index 3ad52c52..8c77803d 100644
--- a/include/event2/listener.h
+++ b/include/event2/listener.h
@@ -27,6 +27,8 @@
#ifndef EVENT2_LISTENER_H_INCLUDED_
#define EVENT2_LISTENER_H_INCLUDED_
+#include <event2/visibility.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -104,6 +106,7 @@ typedef void (*evconnlistener_errorcb)(struct evconnlistener *, void *);
file descriptor, and it should already be bound to an appropriate
port and address.
*/
+EVENT2_EXPORT_SYMBOL
struct evconnlistener *evconnlistener_new(struct event_base *base,
evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
evutil_socket_t fd);
@@ -122,34 +125,42 @@ struct evconnlistener *evconnlistener_new(struct event_base *base,
@param addr The address to listen for connections on.
@param socklen The length of the address.
*/
+EVENT2_EXPORT_SYMBOL
struct evconnlistener *evconnlistener_new_bind(struct event_base *base,
evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
const struct sockaddr *sa, int socklen);
/**
Disable and deallocate an evconnlistener.
*/
+EVENT2_EXPORT_SYMBOL
void evconnlistener_free(struct evconnlistener *lev);
/**
Re-enable an evconnlistener that has been disabled.
*/
+EVENT2_EXPORT_SYMBOL
int evconnlistener_enable(struct evconnlistener *lev);
/**
Stop listening for connections on an evconnlistener.
*/
+EVENT2_EXPORT_SYMBOL
int evconnlistener_disable(struct evconnlistener *lev);
/** Return an evconnlistener's associated event_base. */
+EVENT2_EXPORT_SYMBOL
struct event_base *evconnlistener_get_base(struct evconnlistener *lev);
/** Return the socket that an evconnlistner is listening on. */
+EVENT2_EXPORT_SYMBOL
evutil_socket_t evconnlistener_get_fd(struct evconnlistener *lev);
/** Change the callback on the listener to cb and its user_data to arg.
*/
+EVENT2_EXPORT_SYMBOL
void evconnlistener_set_cb(struct evconnlistener *lev,
evconnlistener_cb cb, void *arg);
/** Set an evconnlistener's error callback. */
+EVENT2_EXPORT_SYMBOL
void evconnlistener_set_error_cb(struct evconnlistener *lev,
evconnlistener_errorcb errorcb);
diff --git a/include/event2/tag.h b/include/event2/tag.h
index 7632bd58..2f73bfc0 100644
--- a/include/event2/tag.h
+++ b/include/event2/tag.h
@@ -33,6 +33,8 @@
*/
+#include <event2/visibility.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -56,6 +58,7 @@ struct evbuffer;
* known ones - and we can just ignore the end of an event buffer.
*/
+EVENT2_EXPORT_SYMBOL
void evtag_init(void);
/**
@@ -65,10 +68,13 @@ void evtag_init(void);
@param ptag a pointer in which the tag id is being stored
@returns -1 on failure or the number of bytes in the remaining payload.
*/
+EVENT2_EXPORT_SYMBOL
int evtag_unmarshal_header(struct evbuffer *evbuf, ev_uint32_t *ptag);
+EVENT2_EXPORT_SYMBOL
void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data,
ev_uint32_t len);
+EVENT2_EXPORT_SYMBOL
void evtag_marshal_buffer(struct evbuffer *evbuf, ev_uint32_t tag,
struct evbuffer *data);
@@ -82,38 +88,54 @@ void evtag_marshal_buffer(struct evbuffer *evbuf, ev_uint32_t tag,
@param evbuf evbuffer to store the encoded number
@param number a 32-bit integer
*/
+EVENT2_EXPORT_SYMBOL
void evtag_encode_int(struct evbuffer *evbuf, ev_uint32_t number);
+EVENT2_EXPORT_SYMBOL
void evtag_encode_int64(struct evbuffer *evbuf, ev_uint64_t number);
+EVENT2_EXPORT_SYMBOL
void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag,
ev_uint32_t integer);
+EVENT2_EXPORT_SYMBOL
void evtag_marshal_int64(struct evbuffer *evbuf, ev_uint32_t tag,
ev_uint64_t integer);
+EVENT2_EXPORT_SYMBOL
void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag,
const char *string);
+EVENT2_EXPORT_SYMBOL
void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag,
struct timeval *tv);
+EVENT2_EXPORT_SYMBOL
int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag,
struct evbuffer *dst);
+EVENT2_EXPORT_SYMBOL
int evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag);
+EVENT2_EXPORT_SYMBOL
int evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength);
+EVENT2_EXPORT_SYMBOL
int evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength);
+EVENT2_EXPORT_SYMBOL
int evtag_consume(struct evbuffer *evbuf);
+EVENT2_EXPORT_SYMBOL
int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag,
ev_uint32_t *pinteger);
+EVENT2_EXPORT_SYMBOL
int evtag_unmarshal_int64(struct evbuffer *evbuf, ev_uint32_t need_tag,
ev_uint64_t *pinteger);
+EVENT2_EXPORT_SYMBOL
int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag,
void *data, size_t len);
+EVENT2_EXPORT_SYMBOL
int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
char **pstring);
+EVENT2_EXPORT_SYMBOL
int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag,
struct timeval *ptv);
diff --git a/include/event2/thread.h b/include/event2/thread.h
index f9f51500..b5199863 100644
--- a/include/event2/thread.h
+++ b/include/event2/thread.h
@@ -46,6 +46,8 @@
*/
+#include <event2/visibility.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -124,6 +126,7 @@ struct evthread_lock_callbacks {
* probably shouldn't call this function; instead, use
* evthread_use_windows_threads() or evthread_use_posix_threads() if you can.
*/
+EVENT2_EXPORT_SYMBOL
int evthread_set_lock_callbacks(const struct evthread_lock_callbacks *);
#define EVTHREAD_CONDITION_API_VERSION 1
@@ -174,6 +177,7 @@ struct evthread_condition_callbacks {
* probably shouldn't call this function; instead, use
* evthread_use_windows_threads() or evthread_use_pthreads() if you can.
*/
+EVENT2_EXPORT_SYMBOL
int evthread_set_condition_callbacks(
const struct evthread_condition_callbacks *);
@@ -184,6 +188,7 @@ int evthread_set_condition_callbacks(
@param id_fn the identify function Libevent should invoke to
determine the identity of a thread.
*/
+EVENT2_EXPORT_SYMBOL
void evthread_set_id_callback(
unsigned long (*id_fn)(void));
@@ -192,6 +197,7 @@ void evthread_set_id_callback(
functions. Unavailable if Libevent is not built for Windows.
@return 0 on success, -1 on failure. */
+EVENT2_EXPORT_SYMBOL
int evthread_use_windows_threads(void);
/**
Defined if Libevent was built with support for evthread_use_windows_threads()
@@ -205,6 +211,7 @@ int evthread_use_windows_threads(void);
libraries to link against Libevent_pthreads as well as Libevent.
@return 0 on success, -1 on failure. */
+EVENT2_EXPORT_SYMBOL
int evthread_use_pthreads(void);
/** Defined if Libevent was built with support for evthread_use_pthreads() */
#define EVTHREAD_USE_PTHREADS_IMPLEMENTED 1
@@ -217,10 +224,12 @@ int evthread_use_pthreads(void);
* If you're going to call this function, you must do so before any locks are
* allocated.
**/
+EVENT2_EXPORT_SYMBOL
void evthread_enable_lock_debugging(void);
/* Old (misspelled) version: This is deprecated; use
* evthread_enable_log_debugging instead. */
+EVENT2_EXPORT_SYMBOL
void evthread_enable_lock_debuging(void);
#endif /* EVENT__DISABLE_THREAD_SUPPORT */
@@ -234,6 +243,7 @@ struct event_base;
@return 0 on success, -1 on failure.
*/
+EVENT2_EXPORT_SYMBOL
int evthread_make_base_notifiable(struct event_base *base);
#ifdef __cplusplus
diff --git a/include/event2/util.h b/include/event2/util.h
index 8ffc4a2e..14c6a25d 100644
--- a/include/event2/util.h
+++ b/include/event2/util.h
@@ -32,6 +32,7 @@
related socket manipulations.
*/
+#include <event2/visibility.h>
#ifdef __cplusplus
extern "C" {
@@ -302,12 +303,14 @@ extern "C" {
Parameters and return values are as for socketpair()
*/
+EVENT2_EXPORT_SYMBOL
int evutil_socketpair(int d, int type, int protocol, evutil_socket_t sv[2]);
/** Do platform-specific operations as needed to make a socket nonblocking.
@param sock The socket to make nonblocking
@return 0 on success, -1 on failure
*/
+EVENT2_EXPORT_SYMBOL
int evutil_make_socket_nonblocking(evutil_socket_t sock);
/** Do platform-specific operations to make a listener socket reusable.
@@ -321,6 +324,7 @@ int evutil_make_socket_nonblocking(evutil_socket_t sock);
@param sock The socket to make reusable
@return 0 on success, -1 on failure
*/
+EVENT2_EXPORT_SYMBOL
int evutil_make_listen_socket_reuseable(evutil_socket_t sock);
/** Do platform-specific operations as needed to close a socket upon a
@@ -329,6 +333,7 @@ int evutil_make_listen_socket_reuseable(evutil_socket_t sock);
@param sock The socket to be closed
@return 0 on success, -1 on failure
*/
+EVENT2_EXPORT_SYMBOL
int evutil_make_socket_closeonexec(evutil_socket_t sock);
/** Do the platform-specific call needed to close a socket returned from
@@ -337,6 +342,7 @@ int evutil_make_socket_closeonexec(evutil_socket_t sock);
@param sock The socket to be closed
@return 0 on success, -1 on failure
*/
+EVENT2_EXPORT_SYMBOL
int evutil_closesocket(evutil_socket_t sock);
#define EVUTIL_CLOSESOCKET(s) evutil_closesocket(s)
@@ -351,6 +357,7 @@ int evutil_closesocket(evutil_socket_t sock);
* @return 0 on success (whether the operation is supported or not),
* -1 on failure
*/
+EVENT2_EXPORT_SYMBOL
int evutil_make_tcp_listen_socket_deferred(evutil_socket_t sock);
#ifdef _WIN32
@@ -360,8 +367,10 @@ int evutil_make_tcp_listen_socket_deferred(evutil_socket_t sock);
#define EVUTIL_SET_SOCKET_ERROR(errcode) \
do { WSASetLastError(errcode); } while (0)
/** Return the most recent socket error to occur on sock. */
+EVENT2_EXPORT_SYMBOL
int evutil_socket_geterror(evutil_socket_t sock);
/** Convert a socket error to a string. */
+EVENT2_EXPORT_SYMBOL
const char *evutil_socket_error_to_string(int errcode);
#elif defined(EVENT_IN_DOXYGEN_)
/**
@@ -457,6 +466,7 @@ const char *evutil_socket_error_to_string(int errcode);
/* big-int related functions */
/** Parse a 64-bit value from a string. Arguments are as for strtol. */
+EVENT2_EXPORT_SYMBOL
ev_int64_t evutil_strtoll(const char *s, char **endptr, int base);
/** Replacement for gettimeofday on platforms that lack it. */
@@ -464,12 +474,14 @@ ev_int64_t evutil_strtoll(const char *s, char **endptr, int base);
#define evutil_gettimeofday(tv, tz) gettimeofday((tv), (tz))
#else
struct timezone;
+EVENT2_EXPORT_SYMBOL
int evutil_gettimeofday(struct timeval *tv, struct timezone *tz);
#endif
/** Replacement for snprintf to get consistent behavior on platforms for
which the return value of snprintf does not conform to C99.
*/
+EVENT2_EXPORT_SYMBOL
int evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
#ifdef __GNUC__
__attribute__((format(printf, 3, 4)))
@@ -478,6 +490,7 @@ int evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
/** Replacement for vsnprintf to get consistent behavior on platforms for
which the return value of snprintf does not conform to C99.
*/
+EVENT2_EXPORT_SYMBOL
int evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap)
#ifdef __GNUC__
__attribute__((format(printf, 3, 0)))
@@ -485,8 +498,10 @@ int evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap)
;
/** Replacement for inet_ntop for platforms which lack it. */
+EVENT2_EXPORT_SYMBOL
const char *evutil_inet_ntop(int af, const void *src, char *dst, size_t len);
/** Replacement for inet_pton for platforms which lack it. */
+EVENT2_EXPORT_SYMBOL
int evutil_inet_pton(int af, const char *src, void *dst);
struct sockaddr;
@@ -510,6 +525,7 @@ struct sockaddr;
or if out is not large enough to hold the result. Otherwise returns
0 on success.
*/
+EVENT2_EXPORT_SYMBOL
int evutil_parse_sockaddr_port(const char *str, struct sockaddr *out, int *outlen);
/** Compare two sockaddrs; return 0 if they are equal, or less than 0 if sa1
@@ -517,16 +533,19 @@ int evutil_parse_sockaddr_port(const char *str, struct sockaddr *out, int *outle
* true, consider the port as well as the address. Only implemented for
* AF_INET and AF_INET6 addresses. The ordering is not guaranteed to remain
* the same between Libevent versions. */
+EVENT2_EXPORT_SYMBOL
int evutil_sockaddr_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2,
int include_port);
/** As strcasecmp, but always compares the characters in locale-independent
ASCII. That's useful if you're handling data in ASCII-based protocols.
*/
+EVENT2_EXPORT_SYMBOL
int evutil_ascii_strcasecmp(const char *str1, const char *str2);
/** As strncasecmp, but always compares the characters in locale-independent
ASCII. That's useful if you're handling data in ASCII-based protocols.
*/
+EVENT2_EXPORT_SYMBOL
int evutil_ascii_strncasecmp(const char *str1, const char *str2, size_t n);
/* Here we define evutil_addrinfo to the native addrinfo type, or redefine it
@@ -667,12 +686,15 @@ struct evutil_addrinfo;
*
* For a nonblocking variant, see evdns_getaddrinfo.
*/
+EVENT2_EXPORT_SYMBOL
int evutil_getaddrinfo(const char *nodename, const char *servname,
const struct evutil_addrinfo *hints_in, struct evutil_addrinfo **res);
/** Release storage allocated by evutil_getaddrinfo or evdns_getaddrinfo. */
+EVENT2_EXPORT_SYMBOL
void evutil_freeaddrinfo(struct evutil_addrinfo *ai);
+EVENT2_EXPORT_SYMBOL
const char *evutil_gai_strerror(int err);
/** Generate n bytes of secure pseudorandom data, and store them in buf.
@@ -684,6 +706,7 @@ const char *evutil_gai_strerror(int err);
* provides only rudimentary prediction- and backtracking-resistance. Don't
* use this for serious cryptographic applications.
*/
+EVENT2_EXPORT_SYMBOL
void evutil_secure_rng_get_bytes(void *buf, size_t n);
/**
@@ -702,6 +725,7 @@ void evutil_secure_rng_get_bytes(void *buf, size_t n);
* whatever), and you want to make sure that seeding happens before your
* program loses the ability to do it.
*/
+EVENT2_EXPORT_SYMBOL
int evutil_secure_rng_init(void);
/**
@@ -717,6 +741,7 @@ int evutil_secure_rng_init(void);
*
* This API is unstable, and might change in a future libevent version.
*/
+EVENT2_EXPORT_SYMBOL
int evutil_secure_rng_set_urandom_device_file(char *fname);
/** Seed the random number generator with extra random bytes.
@@ -733,6 +758,7 @@ int evutil_secure_rng_set_urandom_device_file(char *fname);
@param dat a buffer full of a strong source of random numbers
@param datlen the number of bytes to read from datlen
*/
+EVENT2_EXPORT_SYMBOL
void evutil_secure_rng_add_bytes(const char *dat, size_t datlen);
#ifdef __cplusplus
diff --git a/include/event2/visibility.h b/include/event2/visibility.h
new file mode 100644
index 00000000..5e7163a1
--- /dev/null
+++ b/include/event2/visibility.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EVENT2_VISIBILITY_H_INCLUDED_
+#define EVENT2_VISIBILITY_H_INCLUDED_
+
+#include <event2/event-config.h>
+
+#if defined(event_EXPORTS) || defined(event_extra_EXPORTS) || defined(event_core_EXPORTS)
+
+#if defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+#define EVENT2_EXPORT_SYMBOL __global
+#elif defined __GNUC__
+#define EVENT2_EXPORT_SYMBOL __attribute__ ((visibility("default")))
+#elif defined(_MSC_VER)
+#define EVENT2_EXPORT_SYMBOL extern __declspec(dllexport)
+#else
+/* unknown compiler */
+#define EVENT2_EXPORT_SYMBOL
+#endif
+
+#else
+
+#if defined(EVENT__NEED_DLLIMPORT) && defined(_MSC_VER) && !defined(EVENT_BUILDING_REGRESS_TEST)
+#define EVENT2_EXPORT_SYMBOL extern __declspec(dllimport)
+#else
+#define EVENT2_EXPORT_SYMBOL
+#endif
+
+#endif
+
+#endif /* EVENT2_VISIBILITY_H_INCLUDED_ */
diff --git a/include/include.am b/include/include.am
index 5d2012eb..9aad2dba 100644
--- a/include/include.am
+++ b/include/include.am
@@ -30,7 +30,8 @@ EVENT2_EXPORT = \
include/event2/tag.h \
include/event2/tag_compat.h \
include/event2/thread.h \
- include/event2/util.h
+ include/event2/util.h \
+ include/event2/visibility.h
## Without the nobase_ prefixing, Automake would strip "include/event2/" from
## the source header filename to derive the installed header filename.
diff --git a/kqueue.c b/kqueue.c
index 39334674..7780e1f1 100644
--- a/kqueue.c
+++ b/kqueue.c
@@ -332,6 +332,23 @@ kq_dispatch(struct event_base *base, struct timeval *tv)
* on FreeBSD. */
case EINVAL:
continue;
+#if defined(__FreeBSD__)
+ /*
+ * This currently occurs if an FD is closed
+ * before the EV_DELETE makes it out via kevent().
+ * The FreeBSD capabilities code sees the blank
+ * capability set and rejects the request to
+ * modify an event.
+ *
+ * To be strictly correct - when an FD is closed,
+ * all the registered events are also removed.
+ * Queuing EV_DELETE to a closed FD is wrong.
+ * The event(s) should just be deleted from
+ * the pending changelist.
+ */
+ case ENOTCAPABLE:
+ continue;
+#endif
/* Can occur on a delete if the fd is closed. */
case EBADF:
diff --git a/make_epoll_table.py b/make_epoll_table.py
index 37d6df1e..1b15a91a 100755
--- a/make_epoll_table.py
+++ b/make_epoll_table.py
@@ -1,15 +1,17 @@
#!/usr/bin/python2
-def get(old,wc,rc):
- if ('xxx' in (rc, wc)):
- return "0",-1
+def get(old,wc,rc,cc):
+ if ('xxx' in (rc, wc, cc)):
+ return "0",255
- if ('add' in (rc, wc)):
+ if ('add' in (rc, wc, cc)):
events = []
if rc == 'add' or (rc != 'del' and 'r' in old):
events.append("EPOLLIN")
if wc == 'add' or (wc != 'del' and 'w' in old):
events.append("EPOLLOUT")
+ if cc == 'add' or (cc != 'del' and 'c' in old):
+ events.append("EPOLLRDHUP")
if old == "0":
op = "EPOLL_CTL_ADD"
@@ -17,41 +19,45 @@ def get(old,wc,rc):
op = "EPOLL_CTL_MOD"
return "|".join(events), op
- if ('del' in (rc, wc)):
+ if ('del' in (rc, wc, cc)):
+ delevents = []
+ modevents = []
op = "EPOLL_CTL_DEL"
- if rc == 'del':
- if wc == 'del':
- events = "EPOLLIN|EPOLLOUT"
- elif 'w' in old:
- events = "EPOLLOUT"
- op = "EPOLL_CTL_MOD"
- else:
- events = "EPOLLIN"
+
+ if 'r' in old:
+ modevents.append("EPOLLIN")
+ if 'w' in old:
+ modevents.append("EPOLLOUT")
+ if 'c' in old:
+ modevents.append("EPOLLRDHUP")
+
+ for item, event in [(rc,"EPOLLIN"),
+ (wc,"EPOLLOUT"),
+ (cc,"EPOLLRDHUP")]:
+ if item == 'del':
+ delevents.append(event)
+ if event in modevents:
+ modevents.remove(event)
+
+ if modevents:
+ return "|".join(modevents), "EPOLL_CTL_MOD"
else:
- assert wc == 'del'
- if 'r' in old:
- events = "EPOLLIN"
- op = "EPOLL_CTL_MOD"
- else:
- events = "EPOLLOUT"
- return events, op
+ return "|".join(delevents), "EPOLL_CTL_DEL"
return 0, 0
-def fmt(op, ev, old, wc, rc):
+def fmt(op, ev, old, wc, rc, cc):
entry = "{ %s, %s },"%(op, ev)
- assert len(entry)<=36
- sp = " "*(36-len(entry))
- print "\t%s%s/* old=%2s, write:%3s, read:%3s */" % (
- entry, sp, old, wc, rc)
-
+ print "\t/* old=%3s, write:%3s, read:%3s, close:%3s */\n\t%s" % (
+ old, wc, rc, cc, entry)
+ return len(entry)
-for old in ('0','r','w','rw'):
+for old in ('0','r','w','rw','c','cr','cw','crw'):
for wc in ('0', 'add', 'del', 'xxx'):
for rc in ('0', 'add', 'del', 'xxx'):
+ for cc in ('0', 'add', 'del', 'xxx'):
- op,ev = get(old,wc,rc)
-
- fmt(op, ev, old, wc, rc)
+ op,ev = get(old,wc,rc,cc)
+ fmt(op, ev, old, wc, rc, cc)
diff --git a/sample/dns-example.c b/sample/dns-example.c
index c4fb64a5..15e48ce4 100644
--- a/sample/dns-example.c
+++ b/sample/dns-example.c
@@ -171,7 +171,7 @@ main(int c, char **v) {
++idx;
}
-#ifdef WIN32
+#ifdef _WIN32
{
WSADATA WSAData;
WSAStartup(0x101, &WSAData);
diff --git a/sample/http-server.c b/sample/http-server.c
index 1cb89bc9..cbb9c914 100644
--- a/sample/http-server.c
+++ b/sample/http-server.c
@@ -246,7 +246,10 @@ send_document_cb(struct evhttp_request *req, void *arg)
goto err;
#endif
- evbuffer_add_printf(evb, "<html>\n <head>\n"
+ evbuffer_add_printf(evb,
+ "<!DOCTYPE html>\n"
+ "<html>\n <head>\n"
+ " <meta charset='utf-8'>\n"
" <title>%s</title>\n"
" <base href='%s%s'>\n"
" </head>\n"
@@ -274,7 +277,7 @@ send_document_cb(struct evhttp_request *req, void *arg)
#endif
evbuffer_add_printf(evb, "</ul></body></html>\n");
#ifdef _WIN32
- CloseHandle(d);
+ FindClose(d);
#else
closedir(d);
#endif
diff --git a/sample/https-client.c b/sample/https-client.c
index b32e4304..b5f0b1ae 100644
--- a/sample/https-client.c
+++ b/sample/https-client.c
@@ -10,15 +10,23 @@
Loosely based on le-proxy.c.
*/
+// Get rid of OSX 10.7 and greater deprecation warnings.
+#if defined(__APPLE__) && defined(__clang__)
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
+
+#define snprintf _snprintf
+#define strcasecmp _stricmp
#else
#include <sys/socket.h>
#include <netinet/in.h>
@@ -38,6 +46,7 @@
#include "openssl_hostname_validation.h"
static struct event_base *base;
+static int ignore_cert = 0;
static void
http_request_done(struct evhttp_request *req, void *ctx)
@@ -87,9 +96,9 @@ static void
syntax(void)
{
fputs("Syntax:\n", stderr);
- fputs(" https-client <https-url>\n", stderr);
+ fputs(" https-client -url <https-url> [-data data-file.bin] [-ignore-cert]\n", stderr);
fputs("Example:\n", stderr);
- fputs(" https-client https://ip.appspot.com/\n", stderr);
+ fputs(" https-client -url https://ip.appspot.com/\n", stderr);
exit(1);
}
@@ -124,9 +133,17 @@ static int cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg)
/* This is the function that OpenSSL would call if we hadn't called
* SSL_CTX_set_cert_verify_callback(). Therefore, we are "wrapping"
* the default functionality, rather than replacing it. */
- int ok_so_far = X509_verify_cert(x509_ctx);
+ int ok_so_far = 0;
+
+ X509 *server_cert = NULL;
+
+ if (ignore_cert) {
+ return 1;
+ }
- X509 *server_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
+ ok_so_far = X509_verify_cert(x509_ctx);
+
+ server_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
if (ok_so_far) {
res = validate_hostname(host, server_cert);
@@ -174,7 +191,8 @@ main(int argc, char **argv)
int r;
struct evhttp_uri *http_uri;
- const char *url, *scheme, *host, *path, *query;
+ const char *url = NULL, *data_file = NULL;
+ const char *scheme, *host, *path, *query;
char uri[256];
int port;
@@ -184,11 +202,50 @@ main(int argc, char **argv)
struct evhttp_connection *evcon;
struct evhttp_request *req;
struct evkeyvalq *output_headers;
+ struct evbuffer * output_buffer;
+
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp("-url", argv[i])) {
+ if (i < argc - 1) {
+ url = argv[i + 1];
+ } else {
+ syntax();
+ }
+ } else if (!strcmp("-ignore-cert", argv[i])) {
+ ignore_cert = 1;
+ } else if (!strcmp("-data", argv[i])) {
+ if (i < argc - 1) {
+ data_file = argv[i + 1];
+ } else {
+ syntax();
+ }
+ } else if (!strcmp("-help", argv[i])) {
+ syntax();
+ }
+ }
- if (argc != 2)
+ if (!url) {
syntax();
+ }
+
+#ifdef _WIN32
+ {
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+ if (err != 0) {
+ printf("WSAStartup failed with error: %d\n", err);
+ return 1;
+ }
+ }
+#endif // _WIN32
- url = argv[1];
http_uri = evhttp_uri_parse(url);
if (http_uri == NULL) {
die("malformed url");
@@ -241,6 +298,9 @@ main(int argc, char **argv)
if (!ssl_ctx)
die_openssl("SSL_CTX_new");
+ #ifndef _WIN32
+ /* TODO: Add certificate loading on Windows as well */
+
/* Attempt to use the system's trusted root certificates.
* (This path is only valid for Debian-based systems.) */
if (1 != SSL_CTX_load_verify_locations(ssl_ctx,
@@ -271,6 +331,7 @@ main(int argc, char **argv)
* "wrapping" OpenSSL's routine, not replacing it. */
SSL_CTX_set_cert_verify_callback (ssl_ctx, cert_verify_callback,
(void *) host);
+ #endif // not _WIN32
// Create event base
base = event_base_new();
@@ -285,6 +346,9 @@ main(int argc, char **argv)
die_openssl("SSL_new()");
}
+ // Set hostname for SNI extension
+ SSL_set_tlsext_host_name(ssl, host);
+
if (strcasecmp(scheme, "http") == 0) {
bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
} else {
@@ -320,7 +384,30 @@ main(int argc, char **argv)
evhttp_add_header(output_headers, "Host", host);
evhttp_add_header(output_headers, "Connection", "close");
- r = evhttp_make_request(evcon, req, EVHTTP_REQ_GET, uri);
+ if (data_file) {
+ /* NOTE: In production code, you'd probably want to use
+ * evbuffer_add_file() or evbuffer_add_file_segment(), to
+ * avoid needless copying. */
+ FILE * f = fopen(data_file, "rb");
+ char buf[1024];
+ size_t s;
+ size_t bytes = 0;
+
+ if (!f) {
+ syntax();
+ }
+
+ output_buffer = evhttp_request_get_output_buffer(req);
+ while ((s = fread(buf, 1, sizeof(buf), f)) > 0) {
+ evbuffer_add(output_buffer, buf, s);
+ bytes += s;
+ }
+ evutil_snprintf(buf, sizeof(buf)-1, "%lu", (unsigned long)bytes);
+ evhttp_add_header(output_headers, "Content-Length", buf);
+ fclose(f);
+ }
+
+ r = evhttp_make_request(evcon, req, data_file ? EVHTTP_REQ_POST : EVHTTP_REQ_GET, uri);
if (r != 0) {
fprintf(stderr, "evhttp_make_request() failed\n");
return 1;
@@ -331,5 +418,9 @@ main(int argc, char **argv)
evhttp_connection_free(evcon);
event_base_free(base);
+#ifdef _WIN32
+ WSACleanup();
+#endif
+
return 0;
}
diff --git a/sample/include.am b/sample/include.am
index 81980ac5..75f87c70 100644
--- a/sample/include.am
+++ b/sample/include.am
@@ -30,7 +30,9 @@ noinst_HEADERS += \
sample/openssl_hostname_validation.h
endif
+if BUILD_SAMPLES
noinst_PROGRAMS += $(SAMPLES)
+endif
$(SAMPLES) : libevent.la
diff --git a/sample/le-proxy.c b/sample/le-proxy.c
index afacd33f..30e0a5f6 100644
--- a/sample/le-proxy.c
+++ b/sample/le-proxy.c
@@ -5,6 +5,11 @@
XXX It's a little ugly and should probably be cleaned up.
*/
+// Get rid of OSX 10.7 and greater deprecation warnings.
+#if defined(__APPLE__) && defined(__clang__)
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
diff --git a/sample/openssl_hostname_validation.c b/sample/openssl_hostname_validation.c
index f2cd8564..b5adc67b 100644
--- a/sample/openssl_hostname_validation.c
+++ b/sample/openssl_hostname_validation.c
@@ -34,6 +34,10 @@ SOFTWARE.
*
*/
+// Get rid of OSX 10.7 and greater deprecation warnings.
+#if defined(__APPLE__) && defined(__clang__)
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
#include <openssl/x509v3.h>
#include <openssl/ssl.h>
diff --git a/test/Makefile.nmake b/test/Makefile.nmake
index 92244ad7..30c3eb79 100644
--- a/test/Makefile.nmake
+++ b/test/Makefile.nmake
@@ -10,7 +10,7 @@ SSL_OBJS=
SSL_LIBS=
!ENDIF
-CFLAGS=/I.. /I../WIN32-Code /I../include /I../compat /DHAVE_CONFIG_H /DTINYTEST_LOCAL $(SSL_CFLAGS)
+CFLAGS=/I.. /I../WIN32-Code /I../WIN32-Code/nmake /I../include /I../compat /DHAVE_CONFIG_H /DTINYTEST_LOCAL $(SSL_CFLAGS)
CFLAGS=$(CFLAGS) /Ox /W3 /wd4996 /nologo
@@ -22,13 +22,13 @@ REGRESS_OBJS=regress.obj regress_buffer.obj regress_http.obj regress_dns.obj \
regress_main.obj regress_minheap.obj regress_iocp.obj \
regress_thread.obj regress_finalize.obj $(SSL_OBJS)
-OTHER_OBJS=test-init.obj test-eof.obj test-weof.obj test-time.obj \
+OTHER_OBJS=test-init.obj test-eof.obj test-closed.obj test-weof.obj test-time.obj \
bench.obj bench_cascade.obj bench_http.obj bench_httpclient.obj \
test-changelist.obj \
print-winsock-errors.obj
PROGRAMS=regress.exe \
- test-init.exe test-eof.exe test-weof.exe test-time.exe \
+ test-init.exe test-eof.exe test-closed.exe test-weof.exe test-time.exe \
test-changelist.exe \
print-winsock-errors.exe
@@ -47,6 +47,8 @@ test-init.exe: test-init.obj
$(CC) $(CFLAGS) $(LIBS) test-init.obj
test-eof.exe: test-eof.obj
$(CC) $(CFLAGS) $(LIBS) test-eof.obj
+test-closed.exe: test-closed.obj
+ $(CC) $(CFLAGS) $(LIBS) test-closed.obj
test-changelist.exe: test-changelist.obj
$(CC) $(CFLAGS) $(LIBS) test-changelist.obj
test-weof.exe: test-weof.obj
diff --git a/test/bench.c b/test/bench.c
index b3e40a55..922a743a 100644
--- a/test/bench.c
+++ b/test/bench.c
@@ -57,10 +57,14 @@
#endif
#include <errno.h>
+#ifdef _WIN32
+#include <getopt.h>
+#endif
+
#include <event.h>
#include <evutil.h>
-static int count, writes, fired;
+static int count, writes, fired, failures;
static evutil_socket_t *pipes;
static int num_pipes, num_active, num_writes;
static struct event *events;
@@ -71,12 +75,19 @@ read_cb(evutil_socket_t fd, short which, void *arg)
{
ev_intptr_t idx = (ev_intptr_t) arg, widx = idx + 1;
u_char ch;
+ ev_ssize_t n;
- count += recv(fd, (char*)&ch, sizeof(ch), 0);
+ n = recv(fd, (char*)&ch, sizeof(ch), 0);
+ if (n >= 0)
+ count += n;
+ else
+ failures++;
if (writes) {
if (widx >= num_pipes)
widx -= num_pipes;
- (void) send(pipes[2 * widx + 1], "e", 1, 0);
+ n = send(pipes[2 * widx + 1], "e", 1, 0);
+ if (n != 1)
+ failures++;
writes--;
fired++;
}
diff --git a/test/bench_cascade.c b/test/bench_cascade.c
index 831b0bcb..2d85cc1f 100644
--- a/test/bench_cascade.c
+++ b/test/bench_cascade.c
@@ -48,7 +48,7 @@
#include <unistd.h>
#endif
#include <errno.h>
-
+#include <getopt.h>
#include <event.h>
#include <evutil.h>
@@ -84,8 +84,8 @@ run_once(int num_pipes)
evutil_socket_t *cp;
static struct timeval ts, te, tv_timeout;
- events = calloc(num_pipes, sizeof(struct event));
- pipes = calloc(num_pipes * 2, sizeof(evutil_socket_t));
+ events = (struct event *)calloc(num_pipes, sizeof(struct event));
+ pipes = (evutil_socket_t *)calloc(num_pipes * 2, sizeof(evutil_socket_t));
if (events == NULL || pipes == NULL) {
perror("malloc");
@@ -126,8 +126,8 @@ run_once(int num_pipes)
for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
event_del(&events[i]);
- close(cp[0]);
- close(cp[1]);
+ evutil_closesocket(cp[0]);
+ evutil_closesocket(cp[1]);
}
free(pipes);
@@ -146,6 +146,11 @@ main(int argc, char **argv)
struct timeval *tv;
int num_pipes = 100;
+#ifdef _WIN32
+ WSADATA WSAData;
+ WSAStartup(0x101, &WSAData);
+#endif
+
while ((c = getopt(argc, argv, "n:")) != -1) {
switch (c) {
case 'n':
@@ -175,5 +180,9 @@ main(int argc, char **argv)
tv->tv_sec * 1000000L + tv->tv_usec);
}
+#ifdef _WIN32
+ WSACleanup();
+#endif
+
exit(0);
}
diff --git a/test/bench_http.c b/test/bench_http.c
index 09f521b5..6d0d9717 100644
--- a/test/bench_http.c
+++ b/test/bench_http.c
@@ -178,12 +178,18 @@ main(int argc, char **argv)
evhttp_bind_socket(http, "0.0.0.0", port);
+#ifdef _WIN32
if (use_iocp) {
struct timeval tv={99999999,0};
event_base_loopexit(base, &tv);
}
+#endif
event_base_dispatch(base);
+#ifdef _WIN32
+ WSACleanup();
+#endif
+
/* NOTREACHED */
return (0);
}
diff --git a/test/include.am b/test/include.am
index 930d8422..4cd49ef6 100644
--- a/test/include.am
+++ b/test/include.am
@@ -22,6 +22,7 @@ TESTPROGRAMS = \
test/test-changelist \
test/test-dumpevents \
test/test-eof \
+ test/test-closed \
test/test-fdleak \
test/test-init \
test/test-ratelim \
@@ -49,6 +50,7 @@ test/test-script.sh: test/test.sh
cp $(top_srcdir)/test/test.sh $@
DISTCLEANFILES += test/test-script.sh
+DISTCLEANFILES += test/regress.gen.c test/regress.gen.h
if BUILD_REGRESS
BUILT_SOURCES += test/regress.gen.c test/regress.gen.h
@@ -60,6 +62,8 @@ test_test_dumpevents_SOURCES = test/test-dumpevents.c
test_test_dumpevents_LDADD = libevent_core.la
test_test_eof_SOURCES = test/test-eof.c
test_test_eof_LDADD = libevent_core.la
+test_test_closed_SOURCES = test/test-closed.c
+test_test_closed_LDADD = libevent_core.la
test_test_changelist_SOURCES = test/test-changelist.c
test_test_changelist_LDADD = libevent_core.la
test_test_weof_SOURCES = test/test-weof.c
diff --git a/test/regress.c b/test/regress.c
index 0560ef19..a1094abf 100644
--- a/test/regress.c
+++ b/test/regress.c
@@ -944,17 +944,18 @@ signal_cb(evutil_socket_t fd, short event, void *arg)
}
static void
-test_simplesignal(void)
+test_simplesignal_impl(int find_reorder)
{
struct event ev;
struct itimerval itv;
- setup_test("Simple signal: ");
evsignal_set(&ev, SIGALRM, signal_cb, &ev);
evsignal_add(&ev, NULL);
/* find bugs in which operations are re-ordered */
- evsignal_del(&ev);
- evsignal_add(&ev, NULL);
+ if (find_reorder) {
+ evsignal_del(&ev);
+ evsignal_add(&ev, NULL);
+ }
memset(&itv, 0, sizeof(itv));
itv.it_value.tv_sec = 0;
@@ -971,6 +972,20 @@ test_simplesignal(void)
}
static void
+test_simplestsignal(void)
+{
+ setup_test("Simplest one signal: ");
+ test_simplesignal_impl(0);
+}
+
+static void
+test_simplesignal(void)
+{
+ setup_test("Simple signal: ");
+ test_simplesignal_impl(1);
+}
+
+static void
test_multiplesignal(void)
{
struct event ev_one, ev_two;
@@ -1436,6 +1451,150 @@ end:
}
static void
+test_event_base_get_max_events(void *ptr)
+{
+ struct basic_test_data *data = ptr;
+ struct event_base *base = data->base;
+ struct event ev;
+ struct event ev2;
+ int event_count_active;
+ int event_count_virtual;
+ int event_count_added;
+ int event_count_active_virtual;
+ int event_count_active_added;
+ int event_count_virtual_added;
+ int event_count_active_added_virtual;
+
+ struct timeval qsec = {0, 100000};
+
+ event_assign(&ev, base, -1, EV_READ, event_selfarg_cb,
+ event_self_cbarg());
+ event_assign(&ev2, base, -1, EV_READ, event_selfarg_cb,
+ event_self_cbarg());
+
+ event_add(&ev, &qsec);
+ event_add(&ev2, &qsec);
+ event_del(&ev2);
+
+ event_count_active = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE, 0);
+ event_count_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL, 0);
+ event_count_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ADDED, 0);
+ event_count_active_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_VIRTUAL, 0);
+ event_count_active_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED, 0);
+ event_count_virtual_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL | EVENT_BASE_COUNT_ADDED, 0);
+ event_count_active_added_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE |
+ EVENT_BASE_COUNT_ADDED |
+ EVENT_BASE_COUNT_VIRTUAL, 0);
+
+ tt_int_op(event_count_active, ==, 0);
+ tt_int_op(event_count_virtual, ==, 0);
+ /* libevent itself adds a timeout event, so the event_count is 4 here */
+ tt_int_op(event_count_added, ==, 4);
+ tt_int_op(event_count_active_virtual, ==, 0);
+ tt_int_op(event_count_active_added, ==, 4);
+ tt_int_op(event_count_virtual_added, ==, 4);
+ tt_int_op(event_count_active_added_virtual, ==, 4);
+
+ event_active(&ev, EV_READ, 1);
+ event_count_active = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE, 0);
+ event_count_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL, 0);
+ event_count_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ADDED, 0);
+ event_count_active_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_VIRTUAL, 0);
+ event_count_active_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED, 0);
+ event_count_virtual_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL | EVENT_BASE_COUNT_ADDED, 0);
+ event_count_active_added_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE |
+ EVENT_BASE_COUNT_ADDED |
+ EVENT_BASE_COUNT_VIRTUAL, 0);
+
+ tt_int_op(event_count_active, ==, 1);
+ tt_int_op(event_count_virtual, ==, 0);
+ tt_int_op(event_count_added, ==, 4);
+ tt_int_op(event_count_active_virtual, ==, 1);
+ tt_int_op(event_count_active_added, ==, 5);
+ tt_int_op(event_count_virtual_added, ==, 4);
+ tt_int_op(event_count_active_added_virtual, ==, 5);
+
+ event_base_loop(base, 0);
+ event_count_active = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE, 1);
+ event_count_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL, 1);
+ event_count_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ADDED, 1);
+ event_count_active_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_VIRTUAL, 0);
+ event_count_active_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED, 0);
+ event_count_virtual_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL | EVENT_BASE_COUNT_ADDED, 0);
+ event_count_active_added_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE |
+ EVENT_BASE_COUNT_ADDED |
+ EVENT_BASE_COUNT_VIRTUAL, 1);
+
+ tt_int_op(event_count_active, ==, 1);
+ tt_int_op(event_count_virtual, ==, 0);
+ tt_int_op(event_count_added, ==, 4);
+ tt_int_op(event_count_active_virtual, ==, 0);
+ tt_int_op(event_count_active_added, ==, 0);
+ tt_int_op(event_count_virtual_added, ==, 0);
+ tt_int_op(event_count_active_added_virtual, ==, 0);
+
+ event_count_active = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE, 0);
+ event_count_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL, 0);
+ event_count_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ADDED, 0);
+ tt_int_op(event_count_active, ==, 0);
+ tt_int_op(event_count_virtual, ==, 0);
+ tt_int_op(event_count_added, ==, 0);
+
+ event_base_add_virtual_(base);
+ event_count_active = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE, 0);
+ event_count_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL, 0);
+ event_count_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ADDED, 0);
+ event_count_active_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_VIRTUAL, 0);
+ event_count_active_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED, 0);
+ event_count_virtual_added = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_VIRTUAL | EVENT_BASE_COUNT_ADDED, 0);
+ event_count_active_added_virtual = event_base_get_max_events(base,
+ EVENT_BASE_COUNT_ACTIVE |
+ EVENT_BASE_COUNT_ADDED |
+ EVENT_BASE_COUNT_VIRTUAL, 0);
+
+ tt_int_op(event_count_active, ==, 0);
+ tt_int_op(event_count_virtual, ==, 1);
+ tt_int_op(event_count_added, ==, 0);
+ tt_int_op(event_count_active_virtual, ==, 1);
+ tt_int_op(event_count_active_added, ==, 0);
+ tt_int_op(event_count_virtual_added, ==, 1);
+ tt_int_op(event_count_active_added_virtual, ==, 1);
+
+end:
+ ;
+}
+
+static void
test_bad_assign(void *ptr)
{
struct event ev;
@@ -1585,11 +1744,15 @@ static void read_not_timeout_cb(evutil_socket_t fd, short what, void *arg)
{
struct read_not_timeout_param *rntp = arg;
char c;
+ ev_ssize_t n;
(void) fd; (void) what;
- (void) read(fd, &c, 1);
+ n = read(fd, &c, 1);
+ tt_int_op(n, ==, 1);
rntp->events |= what;
++rntp->count;
if(2 == rntp->count) event_del(rntp->ev[0]);
+end:
+ ;
}
static void
@@ -1790,14 +1953,20 @@ re_add_read_cb(evutil_socket_t fd, short event, void *arg)
{
char buf[256];
struct event *ev_other = arg;
+ ev_ssize_t n_read;
+
readd_test_event_last_added = ev_other;
- if (read(fd, buf, sizeof(buf)) < 0) {
+ n_read = read(fd, buf, sizeof(buf));
+
+ if (n_read < 0) {
tt_fail_perror("read");
+ event_base_loopbreak(event_get_base(ev_other));
+ return;
+ } else {
+ event_add(ev_other, NULL);
+ ++test_ok;
}
-
- event_add(ev_other, NULL);
- ++test_ok;
}
static void
@@ -2962,6 +3131,97 @@ end:
event_config_free(cfg);
}
+static void
+tabf_cb(evutil_socket_t fd, short what, void *arg)
+{
+ int *ptr = arg;
+ *ptr = what;
+ *ptr += 0x10000;
+}
+
+static void
+test_active_by_fd(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct event *ev1 = NULL, *ev2 = NULL, *ev3 = NULL, *ev4 = NULL;
+ int e1,e2,e3,e4;
+#ifndef _WIN32
+ struct event *evsig = NULL;
+ int es;
+#endif
+ struct timeval tenmin = { 600, 0 };
+
+ /* Ensure no crash on nonexistent FD. */
+ event_base_active_by_fd(base, 1000, EV_READ);
+
+ /* Ensure no crash on bogus FD. */
+ event_base_active_by_fd(base, -1, EV_READ);
+
+ /* Ensure no crash on nonexistent/bogus signal. */
+ event_base_active_by_signal(base, 1000);
+ event_base_active_by_signal(base, -1);
+
+ event_base_assert_ok_(base);
+
+ e1 = e2 = e3 = e4 = 0;
+ ev1 = event_new(base, data->pair[0], EV_READ, tabf_cb, &e1);
+ ev2 = event_new(base, data->pair[0], EV_WRITE, tabf_cb, &e2);
+ ev3 = event_new(base, data->pair[1], EV_READ, tabf_cb, &e3);
+ ev4 = event_new(base, data->pair[1], EV_READ, tabf_cb, &e4);
+ tt_assert(ev1);
+ tt_assert(ev2);
+ tt_assert(ev3);
+ tt_assert(ev4);
+#ifndef _WIN32
+ evsig = event_new(base, SIGHUP, EV_SIGNAL, tabf_cb, &es);
+ tt_assert(evsig);
+ event_add(evsig, &tenmin);
+#endif
+
+ event_add(ev1, &tenmin);
+ event_add(ev2, NULL);
+ event_add(ev3, NULL);
+ event_add(ev4, &tenmin);
+
+
+ event_base_assert_ok_(base);
+
+ /* Trigger 2, 3, 4 */
+ event_base_active_by_fd(base, data->pair[0], EV_WRITE);
+ event_base_active_by_fd(base, data->pair[1], EV_READ);
+#ifndef _WIN32
+ event_base_active_by_signal(base, SIGHUP);
+#endif
+
+ event_base_assert_ok_(base);
+
+ event_base_loop(base, EVLOOP_ONCE);
+
+ tt_int_op(e1, ==, 0);
+ tt_int_op(e2, ==, EV_WRITE | 0x10000);
+ tt_int_op(e3, ==, EV_READ | 0x10000);
+ /* Mask out EV_WRITE here, since it could be genuinely writeable. */
+ tt_int_op((e4 & ~EV_WRITE), ==, EV_READ | 0x10000);
+#ifndef _WIN32
+ tt_int_op(es, ==, EV_SIGNAL | 0x10000);
+#endif
+
+end:
+ if (ev1)
+ event_free(ev1);
+ if (ev2)
+ event_free(ev2);
+ if (ev3)
+ event_free(ev3);
+ if (ev4)
+ event_free(ev4);
+#ifndef _WIN32
+ if (evsig)
+ event_free(evsig);
+#endif
+}
+
struct testcase_t main_testcases[] = {
/* Some converted-over tests */
{ "methods", test_methods, TT_FORK, NULL, NULL },
@@ -2976,6 +3236,7 @@ struct testcase_t main_testcases[] = {
BASIC(event_new_selfarg, TT_FORK|TT_NEED_BASE),
BASIC(event_assign_selfarg, TT_FORK|TT_NEED_BASE),
BASIC(event_base_get_num_events, TT_FORK|TT_NEED_BASE),
+ BASIC(event_base_get_max_events, TT_FORK|TT_NEED_BASE),
BASIC(bad_assign, TT_FORK|TT_NEED_BASE|TT_NO_LOGS),
BASIC(bad_reentrant, TT_FORK|TT_NEED_BASE|TT_NO_LOGS),
@@ -3029,6 +3290,8 @@ struct testcase_t main_testcases[] = {
{ "gettimeofday_cached_disabled", test_gettimeofday_cached, TT_FORK, &basic_setup, (void*)"sleep disable" },
{ "gettimeofday_cached_disabled_nosleep", test_gettimeofday_cached, TT_FORK, &basic_setup, (void*)"disable" },
+ BASIC(active_by_fd, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR),
+
#ifndef _WIN32
LEGACY(fork, TT_ISOLATED),
#endif
@@ -3046,6 +3309,7 @@ struct testcase_t evtag_testcases[] = {
struct testcase_t signal_testcases[] = {
#ifndef _WIN32
+ LEGACY(simplestsignal, TT_ISOLATED),
LEGACY(simplesignal, TT_ISOLATED),
LEGACY(multiplesignal, TT_ISOLATED),
LEGACY(immediatesignal, TT_ISOLATED),
diff --git a/test/regress_buffer.c b/test/regress_buffer.c
index ab11de94..71e435d3 100644
--- a/test/regress_buffer.c
+++ b/test/regress_buffer.c
@@ -888,7 +888,7 @@ test_evbuffer_file_segment_add_cleanup_cb(void* ptr)
char *tmpfilename = NULL;
int fd = -1;
struct evbuffer *evb = NULL;
- struct evbuffer_file_segment *seg = NULL;
+ struct evbuffer_file_segment *seg = NULL, *segptr;
char const* arg = "token";
fd = regress_make_tmpfile("file_segment_test_file", 22, &tmpfilename);
@@ -897,7 +897,7 @@ test_evbuffer_file_segment_add_cleanup_cb(void* ptr)
evb = evbuffer_new();
tt_assert(evb);
- seg = evbuffer_file_segment_new(fd, 0, -1, 0);
+ segptr = seg = evbuffer_file_segment_new(fd, 0, -1, 0);
tt_assert(seg);
evbuffer_file_segment_add_cleanup_cb(
@@ -906,29 +906,27 @@ test_evbuffer_file_segment_add_cleanup_cb(void* ptr)
tt_assert(fd != -1);
tt_assert(evbuffer_add_file_segment(evb, seg, 0, -1)!=-1);
-
+
evbuffer_validate(evb);
tt_int_op(file_segment_cleanup_cb_called_count, ==, 0);
evbuffer_file_segment_free(seg);
+ seg = NULL; /* Prevent double-free. */
tt_int_op(file_segment_cleanup_cb_called_count, ==, 0);
evbuffer_free(evb);
-
+ evb = NULL; /* pevent double-free */
+
tt_int_op(file_segment_cleanup_cb_called_count, ==, 1);
- tt_assert(file_segment_cleanup_cb_called_with == seg);
+ tt_assert(file_segment_cleanup_cb_called_with == segptr);
tt_assert(file_segment_cleanup_cb_called_with_flags == 0);
tt_assert(file_segment_cleanup_cb_called_with_arg == (void*)arg);
-
- seg = NULL;
- evb = NULL;
end:
-
- if(evb)
- evbuffer_free(evb);
- if(seg)
- evbuffer_file_segment_free(seg);
+ if (evb)
+ evbuffer_free(evb);
+ if (seg)
+ evbuffer_file_segment_free(seg);
if (tmpfilename) {
unlink(tmpfilename);
free(tmpfilename);
@@ -1536,9 +1534,9 @@ test_evbuffer_callbacks(void *ptr)
tt_assert(!evbuffer_remove_cb(buf, log_change_callback, buf_out2));
evbuffer_validate(buf);
- tt_str_op(evbuffer_pullup(buf_out1, -1), ==,
+ tt_str_op((const char *) evbuffer_pullup(buf_out1, -1), ==,
"0->36; 36->26; 26->31; 31->38; ");
- tt_str_op(evbuffer_pullup(buf_out2, -1), ==,
+ tt_str_op((const char *) evbuffer_pullup(buf_out2, -1), ==,
"0->36; 31->38; 38->0; 0->1; ");
evbuffer_drain(buf_out1, evbuffer_get_length(buf_out1));
evbuffer_drain(buf_out2, evbuffer_get_length(buf_out2));
@@ -1554,7 +1552,7 @@ test_evbuffer_callbacks(void *ptr)
tt_uint_op(evbuffer_get_length(buf_out2), ==, 0);
evbuffer_setcb(buf, NULL, NULL);
evbuffer_add_printf(buf, "This will not.");
- tt_str_op(evbuffer_pullup(buf, -1), ==, "This will not.");
+ tt_str_op((const char *) evbuffer_pullup(buf, -1), ==, "This will not.");
evbuffer_validate(buf);
evbuffer_drain(buf, evbuffer_get_length(buf));
evbuffer_validate(buf);
@@ -1662,7 +1660,7 @@ test_evbuffer_add_reference(void *ptr)
evbuffer_add(buf1, "You shake and shake the ", 24);
evbuffer_add_reference(buf1, "ketchup bottle", 14, ref_done_cb,
(void*)3333);
- evbuffer_add(buf1, ". Nothing comes and then a lot'll.", 42);
+ evbuffer_add(buf1, ". Nothing comes and then a lot'll.", 35);
evbuffer_free(buf1);
buf1 = NULL;
tt_int_op(ref_done_cb_called_count, ==, 3);
@@ -1810,6 +1808,7 @@ test_evbuffer_prepend(void *ptr)
evbuffer_prepend(buf1, "It is no longer true to say ", 28);
evbuffer_validate(buf1);
n = evbuffer_remove(buf1, tmp, sizeof(tmp)-1);
+ tt_int_op(n, >=, 0);
tmp[n]='\0';
tt_str_op(tmp,==,"It is no longer true to say it has 29 characters");
@@ -1828,6 +1827,7 @@ test_evbuffer_prepend(void *ptr)
evbuffer_validate(buf2);
evbuffer_validate(buf1);
n = evbuffer_remove(buf2, tmp, sizeof(tmp)-1);
+ tt_int_op(n, >=, 0);
tmp[n]='\0';
tt_str_op(tmp,==,"Here is string 1000. Here is string 999. ");
diff --git a/test/regress_bufferevent.c b/test/regress_bufferevent.c
index 1be16216..4ec2dccf 100644
--- a/test/regress_bufferevent.c
+++ b/test/regress_bufferevent.c
@@ -243,6 +243,7 @@ test_bufferevent_watermarks_impl(int use_pair)
{
struct bufferevent *bev1 = NULL, *bev2 = NULL;
char buffer[65000];
+ size_t low, high;
int i;
test_ok = 0;
@@ -262,16 +263,30 @@ test_bufferevent_watermarks_impl(int use_pair)
bufferevent_disable(bev1, EV_READ);
bufferevent_enable(bev2, EV_READ);
+ /* By default, low watermarks are set to 0 */
+ bufferevent_getwatermark(bev1, EV_READ, &low, NULL);
+ tt_int_op(low, ==, 0);
+ bufferevent_getwatermark(bev2, EV_WRITE, &low, NULL);
+ tt_int_op(low, ==, 0);
+
for (i = 0; i < (int)sizeof(buffer); i++)
buffer[i] = (char)i;
/* limit the reading on the receiving bufferevent */
bufferevent_setwatermark(bev2, EV_READ, 10, 20);
+ bufferevent_getwatermark(bev2, EV_READ, &low, &high);
+ tt_int_op(low, ==, 10);
+ tt_int_op(high, ==, 20);
+
/* Tell the sending bufferevent not to notify us till it's down to
100 bytes. */
bufferevent_setwatermark(bev1, EV_WRITE, 100, 2000);
+ bufferevent_getwatermark(bev1, EV_WRITE, &low, &high);
+ tt_int_op(low, ==, 100);
+ tt_int_op(high, ==, 2000);
+
bufferevent_write(bev1, buffer, sizeof(buffer));
event_dispatch();
@@ -432,6 +447,7 @@ sender_errorcb(struct bufferevent *bev, short what, void *ctx)
}
static int bufferevent_connect_test_flags = 0;
+static int bufferevent_trigger_test_flags = 0;
static int n_strings_read = 0;
static int n_reads_invoked = 0;
@@ -470,6 +486,7 @@ reader_eventcb(struct bufferevent *bev, short what, void *ctx)
char buf[512];
size_t n;
n = bufferevent_read(bev, buf, sizeof(buf)-1);
+ tt_int_op(n, >=, 0);
buf[n] = '\0';
tt_str_op(buf, ==, TEST_STR);
if (++n_strings_read == 2)
@@ -599,7 +616,7 @@ close_socket_cb(evutil_socket_t fd, short what, void *arg)
static void
test_bufferevent_connect_fail(void *arg)
{
- struct basic_test_data *data = arg;
+ struct basic_test_data *data = (struct basic_test_data *)arg;
struct bufferevent *bev=NULL;
struct sockaddr_in localhost;
struct sockaddr *sa = (struct sockaddr*)&localhost;
@@ -797,6 +814,132 @@ end:
bufferevent_free(bev2);
}
+static void
+trigger_failure_cb(evutil_socket_t fd, short what, void *ctx)
+{
+ TT_FAIL(("The triggered callback did not fire or the machine is really slow (try increasing timeout)."));
+}
+
+static void
+trigger_eventcb(struct bufferevent *bev, short what, void *ctx)
+{
+ struct event_base *base = ctx;
+ if (what == ~0) {
+ TT_BLATHER(("Event successfully triggered."));
+ event_base_loopexit(base, NULL);
+ return;
+ }
+ reader_eventcb(bev, what, ctx);
+}
+
+static void
+trigger_readcb_triggered(struct bufferevent *bev, void *ctx)
+{
+ TT_BLATHER(("Read successfully triggered."));
+ n_reads_invoked++;
+ bufferevent_trigger_event(bev, ~0, bufferevent_trigger_test_flags);
+}
+
+static void
+trigger_readcb(struct bufferevent *bev, void *ctx)
+{
+ struct timeval timeout = { 30, 0 };
+ struct event_base *base = ctx;
+ size_t low, high, len;
+ int expected_reads;
+
+ TT_BLATHER(("Read invoked on %d.", (int)bufferevent_getfd(bev)));
+ expected_reads = ++n_reads_invoked;
+
+ bufferevent_setcb(bev, trigger_readcb_triggered, NULL, trigger_eventcb, ctx);
+
+ bufferevent_getwatermark(bev, EV_READ, &low, &high);
+ len = evbuffer_get_length(bufferevent_get_input(bev));
+
+ bufferevent_setwatermark(bev, EV_READ, len + 1, 0);
+ bufferevent_trigger(bev, EV_READ, bufferevent_trigger_test_flags);
+ /* no callback expected */
+ tt_int_op(n_reads_invoked, ==, expected_reads);
+
+ if ((bufferevent_trigger_test_flags & BEV_TRIG_DEFER_CALLBACKS) ||
+ (bufferevent_connect_test_flags & BEV_OPT_DEFER_CALLBACKS)) {
+ /* will be deferred */
+ } else {
+ expected_reads++;
+ }
+
+ event_base_once(base, -1, EV_TIMEOUT, trigger_failure_cb, NULL, &timeout);
+
+ bufferevent_trigger(bev, EV_READ,
+ bufferevent_trigger_test_flags | BEV_TRIG_IGNORE_WATERMARKS);
+ tt_int_op(n_reads_invoked, ==, expected_reads);
+
+ bufferevent_setwatermark(bev, EV_READ, low, high);
+end:
+ ;
+}
+
+static void
+test_bufferevent_trigger(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct evconnlistener *lev=NULL;
+ struct bufferevent *bev=NULL;
+ struct sockaddr_in localhost;
+ struct sockaddr_storage ss;
+ struct sockaddr *sa;
+ ev_socklen_t slen;
+
+ int be_flags=BEV_OPT_CLOSE_ON_FREE;
+ int trig_flags=0;
+
+ if (strstr((char*)data->setup_data, "defer")) {
+ be_flags |= BEV_OPT_DEFER_CALLBACKS;
+ }
+ bufferevent_connect_test_flags = be_flags;
+
+ if (strstr((char*)data->setup_data, "postpone")) {
+ trig_flags |= BEV_TRIG_DEFER_CALLBACKS;
+ }
+ bufferevent_trigger_test_flags = trig_flags;
+
+ memset(&localhost, 0, sizeof(localhost));
+
+ localhost.sin_port = 0; /* pick-a-port */
+ localhost.sin_addr.s_addr = htonl(0x7f000001L);
+ localhost.sin_family = AF_INET;
+ sa = (struct sockaddr *)&localhost;
+ lev = evconnlistener_new_bind(data->base, listen_cb, data->base,
+ LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
+ 16, sa, sizeof(localhost));
+ tt_assert(lev);
+
+ sa = (struct sockaddr *)&ss;
+ slen = sizeof(ss);
+ if (regress_get_listener_addr(lev, sa, &slen) < 0) {
+ tt_abort_perror("getsockname");
+ }
+
+ tt_assert(!evconnlistener_enable(lev));
+ bev = bufferevent_socket_new(data->base, -1, be_flags);
+ tt_assert(bev);
+ bufferevent_setcb(bev, trigger_readcb, NULL, trigger_eventcb, data->base);
+
+ bufferevent_enable(bev, EV_READ);
+
+ tt_want(!bufferevent_socket_connect(bev, sa, sizeof(localhost)));
+
+ event_base_dispatch(data->base);
+
+ tt_int_op(n_reads_invoked, ==, 2);
+end:
+ if (lev)
+ evconnlistener_free(lev);
+
+ if (bev)
+ bufferevent_free(bev);
+}
+
struct testcase_t bufferevent_testcases[] = {
LEGACY(bufferevent, TT_ISOLATED),
@@ -827,6 +970,16 @@ struct testcase_t bufferevent_testcases[] = {
TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter" },
{ "bufferevent_timeout_filter_pair", test_bufferevent_timeouts,
TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter pair" },
+ { "bufferevent_trigger", test_bufferevent_trigger, TT_FORK|TT_NEED_BASE,
+ &basic_setup, (void*)"" },
+ { "bufferevent_trigger_defer", test_bufferevent_trigger,
+ TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"defer" },
+ { "bufferevent_trigger_postpone", test_bufferevent_trigger,
+ TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup,
+ (void*)"postpone" },
+ { "bufferevent_trigger_defer_postpone", test_bufferevent_trigger,
+ TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup,
+ (void*)"defer postpone" },
#ifdef EVENT__HAVE_LIBZ
LEGACY(bufferevent_zlib, TT_ISOLATED),
#else
diff --git a/test/regress_dns.c b/test/regress_dns.c
index e5b9a799..8f20149c 100644
--- a/test/regress_dns.c
+++ b/test/regress_dns.c
@@ -1632,7 +1632,8 @@ test_getaddrinfo_async(void *arg)
end:
if (local_outcome.ai)
evutil_freeaddrinfo(local_outcome.ai);
- for (i=0;i<10;++i) {
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+ for (i=0;i<(int)ARRAY_SIZE(a_out);++i) {
if (a_out[i].ai)
evutil_freeaddrinfo(a_out[i].ai);
}
@@ -1944,6 +1945,8 @@ end:
evdns_base_free(dns_base, 1);
if (server)
evdns_close_server_port(server);
+ if (base)
+ event_base_free(base);
if (fd >= 0)
evutil_closesocket(fd);
}
diff --git a/test/regress_finalize.c b/test/regress_finalize.c
index 61a6313f..552210fe 100644
--- a/test/regress_finalize.c
+++ b/test/regress_finalize.c
@@ -25,6 +25,7 @@
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
#include "tinytest.h"
#include "tinytest_macros.h"
#include <stdlib.h>
diff --git a/test/regress_http.c b/test/regress_http.c
index faebabc4..5658135f 100644
--- a/test/regress_http.c
+++ b/test/regress_http.c
@@ -92,6 +92,7 @@ static void http_delay_cb(struct evhttp_request *req, void *arg);
static void http_large_delay_cb(struct evhttp_request *req, void *arg);
static void http_badreq_cb(struct evhttp_request *req, void *arg);
static void http_dispatcher_cb(struct evhttp_request *req, void *arg);
+static void http_on_complete_cb(struct evhttp_request *req, void *arg);
static int
http_bind(struct evhttp *myhttp, ev_uint16_t *pport, int ipv6)
@@ -104,8 +105,12 @@ http_bind(struct evhttp *myhttp, ev_uint16_t *pport, int ipv6)
else
sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", *pport);
- if (sock == NULL)
- event_errx(1, "Could not start web server");
+ if (sock == NULL) {
+ if (ipv6)
+ return -1;
+ else
+ event_errx(1, "Could not start web server");
+ }
port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock));
if (port < 0)
@@ -136,6 +141,7 @@ http_setup(ev_uint16_t *pport, struct event_base *base, int ipv6)
evhttp_set_cb(myhttp, "/delay", http_delay_cb, base);
evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, base);
evhttp_set_cb(myhttp, "/badrequest", http_badreq_cb, base);
+ evhttp_set_cb(myhttp, "/oncomplete", http_on_complete_cb, base);
evhttp_set_cb(myhttp, "/", http_dispatcher_cb, base);
return (myhttp);
}
@@ -481,6 +487,7 @@ http_basic_test(void *arg)
;
}
+
static void
http_delay_reply(evutil_socket_t fd, short what, void *arg)
{
@@ -581,7 +588,7 @@ http_bad_request_test(void *arg)
struct basic_test_data *data = arg;
struct timeval tv;
struct bufferevent *bev = NULL;
- evutil_socket_t fd;
+ evutil_socket_t fd = -1;
const char *http_request;
ev_uint16_t port=0, port2=0;
@@ -596,6 +603,7 @@ http_bad_request_test(void *arg)
/* NULL request test */
fd = http_connect("127.0.0.1", port);
+ tt_int_op(fd, >=, 0);
/* Stupid thing to send a request */
bev = bufferevent_socket_new(data->base, fd, 0);
@@ -654,6 +662,8 @@ end:
evhttp_free(http);
if (bev)
bufferevent_free(bev);
+ if (fd >= 0)
+ evutil_closesocket(fd);
}
static struct evhttp_connection *delayed_client;
@@ -700,7 +710,7 @@ http_delete_test(void *arg)
{
struct basic_test_data *data = arg;
struct bufferevent *bev;
- evutil_socket_t fd;
+ evutil_socket_t fd = -1;
const char *http_request;
ev_uint16_t port = 0;
@@ -709,6 +719,7 @@ http_delete_test(void *arg)
http = http_setup(&port, data->base, 0);
fd = http_connect("127.0.0.1", port);
+ tt_int_op(fd, >=, 0);
/* Stupid thing to send a request */
bev = bufferevent_socket_new(data->base, fd, 0);
@@ -727,12 +738,95 @@ http_delete_test(void *arg)
bufferevent_free(bev);
evutil_closesocket(fd);
+ fd = -1;
evhttp_free(http);
tt_int_op(test_ok, ==, 2);
end:
- ;
+ if (fd >= 0)
+ evutil_closesocket(fd);
+}
+
+static void
+http_sent_cb(struct evhttp_request *req, void *arg)
+{
+ ev_uintptr_t val = (ev_uintptr_t)arg;
+ struct evbuffer *b;
+
+ if (val != 0xDEADBEEF) {
+ fprintf(stdout, "FAILED on_complete_cb argument\n");
+ exit(1);
+ }
+
+ b = evhttp_request_get_output_buffer(req);
+ if (evbuffer_get_length(b) != 0) {
+ fprintf(stdout, "FAILED on_complete_cb output buffer not written\n");
+ exit(1);
+ }
+
+ event_debug(("%s: called\n", __func__));
+
+ ++test_ok;
+}
+
+static void
+http_on_complete_cb(struct evhttp_request *req, void *arg)
+{
+ struct evbuffer *evb = evbuffer_new();
+
+ evhttp_request_set_on_complete_cb(req, http_sent_cb, (void *)0xDEADBEEF);
+
+ event_debug(("%s: called\n", __func__));
+ evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
+
+ /* allow sending of an empty reply */
+ evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
+
+ evbuffer_free(evb);
+
+ ++test_ok;
+}
+
+static void
+http_on_complete_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct bufferevent *bev;
+ evutil_socket_t fd = -1;
+ const char *http_request;
+ ev_uint16_t port = 0;
+
+ test_ok = 0;
+
+ http = http_setup(&port, data->base, 0);
+
+ fd = http_connect("127.0.0.1", port);
+ tt_int_op(fd, >=, 0);
+
+ /* Stupid thing to send a request */
+ bev = bufferevent_socket_new(data->base, fd, 0);
+ bufferevent_setcb(bev, http_readcb, http_writecb,
+ http_errorcb, data->base);
+
+ http_request =
+ "GET /oncomplete HTTP/1.1\r\n"
+ "Host: somehost\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ bufferevent_write(bev, http_request, strlen(http_request));
+
+ event_base_dispatch(data->base);
+
+ bufferevent_free(bev);
+
+ evhttp_free(http);
+
+ tt_int_op(test_ok, ==, 4);
+ end:
+ if (fd >= 0)
+ evutil_closesocket(fd);
}
static void
@@ -759,7 +853,7 @@ http_allowed_methods_test(void *arg)
{
struct basic_test_data *data = arg;
struct bufferevent *bev1, *bev2, *bev3;
- evutil_socket_t fd1, fd2, fd3;
+ evutil_socket_t fd1=-1, fd2=-1, fd3=-1;
const char *http_request;
char *result1=NULL, *result2=NULL, *result3=NULL;
ev_uint16_t port = 0;
@@ -770,6 +864,7 @@ http_allowed_methods_test(void *arg)
http = http_setup(&port, data->base, 0);
fd1 = http_connect("127.0.0.1", port);
+ tt_int_op(fd1, >=, 0);
/* GET is out; PATCH is in. */
evhttp_set_allowed_methods(http, EVHTTP_REQ_PATCH);
@@ -791,6 +886,7 @@ http_allowed_methods_test(void *arg)
event_base_dispatch(data->base);
fd2 = http_connect("127.0.0.1", port);
+ tt_int_op(fd2, >=, 0);
bev2 = bufferevent_socket_new(data->base, fd2, 0);
bufferevent_enable(bev2, EV_READ|EV_WRITE);
@@ -808,6 +904,7 @@ http_allowed_methods_test(void *arg)
event_base_dispatch(data->base);
fd3 = http_connect("127.0.0.1", port);
+ tt_int_op(fd3, >=, 0);
bev3 = bufferevent_socket_new(data->base, fd3, 0);
bufferevent_enable(bev3, EV_READ|EV_WRITE);
@@ -827,9 +924,6 @@ http_allowed_methods_test(void *arg)
bufferevent_free(bev1);
bufferevent_free(bev2);
bufferevent_free(bev3);
- evutil_closesocket(fd1);
- evutil_closesocket(fd2);
- evutil_closesocket(fd3);
evhttp_free(http);
@@ -852,6 +946,12 @@ http_allowed_methods_test(void *arg)
free(result2);
if (result3)
free(result3);
+ if (fd1 >= 0)
+ evutil_closesocket(fd1);
+ if (fd2 >= 0)
+ evutil_closesocket(fd2);
+ if (fd3 >= 0)
+ evutil_closesocket(fd3);
}
static void http_request_done(struct evhttp_request *, void *);
@@ -867,6 +967,10 @@ http_connection_test_(struct basic_test_data *data, int persistent, const char *
test_ok = 0;
http = http_setup(&port, data->base, ipv6);
+ if (!http && ipv6) {
+ tt_skip();
+ }
+ tt_assert(http);
evcon = evhttp_connection_base_new(data->base, dnsbase, address, port);
tt_assert(evcon);
@@ -1763,7 +1867,7 @@ http_failure_test(void *arg)
{
struct basic_test_data *data = arg;
struct bufferevent *bev;
- evutil_socket_t fd;
+ evutil_socket_t fd = -1;
const char *http_request;
ev_uint16_t port = 0;
@@ -1772,6 +1876,7 @@ http_failure_test(void *arg)
http = http_setup(&port, data->base, 0);
fd = http_connect("127.0.0.1", port);
+ tt_int_op(fd, >=, 0);
/* Stupid thing to send a request */
bev = bufferevent_socket_new(data->base, fd, 0);
@@ -1785,13 +1890,13 @@ http_failure_test(void *arg)
event_base_dispatch(data->base);
bufferevent_free(bev);
- evutil_closesocket(fd);
evhttp_free(http);
tt_int_op(test_ok, ==, 2);
end:
- ;
+ if (fd >= 0)
+ evutil_closesocket(fd);
}
static void
@@ -1865,6 +1970,7 @@ http_close_detection_(struct basic_test_data *data, int with_delay)
evcon = evhttp_connection_base_new(data->base, NULL,
"127.0.0.1", port);
+ tt_assert(evcon);
evhttp_connection_set_timeout_tv(evcon, &sec_tenth);
@@ -2534,9 +2640,11 @@ http_base_test(void *ptr)
test_ok = 0;
base = event_base_new();
+ tt_assert(base);
http = http_setup(&port, base, 0);
fd = http_connect("127.0.0.1", port);
+ tt_int_op(fd, >=, 0);
/* Stupid thing to send a request */
bev = bufferevent_socket_new(base, fd, 0);
@@ -2620,6 +2728,7 @@ http_incomplete_test_(struct basic_test_data *data, int use_timeout)
evhttp_set_timeout(http, 1);
fd = http_connect("127.0.0.1", port);
+ tt_int_op(fd, >=, 0);
/* Stupid thing to send a request */
bev = bufferevent_socket_new(data->base, fd, 0);
@@ -2643,6 +2752,7 @@ http_incomplete_test_(struct basic_test_data *data, int use_timeout)
bufferevent_free(bev);
if (use_timeout) {
evutil_closesocket(fd);
+ fd = -1;
}
evhttp_free(http);
@@ -2656,7 +2766,8 @@ http_incomplete_test_(struct basic_test_data *data, int use_timeout)
tt_int_op(test_ok, ==, 2);
end:
- ;
+ if (fd >= 0)
+ evutil_closesocket(fd);
}
static void
http_incomplete_test(void *arg)
@@ -2682,15 +2793,17 @@ http_chunked_readcb(struct bufferevent *bev, void *arg)
static void
http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
{
+ struct evhttp_request *req = NULL;
+
if (!test_ok)
goto out;
test_ok = -1;
if ((what & BEV_EVENT_EOF) != 0) {
- struct evhttp_request *req = evhttp_request_new(NULL, NULL);
const char *header;
enum message_read_status done;
+ req = evhttp_request_new(NULL, NULL);
/* req->kind = EVHTTP_RESPONSE; */
done = evhttp_parse_firstline_(req, bufferevent_get_input(bev));
@@ -2766,11 +2879,12 @@ http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
free((void *)header);
test_ok = 2;
-
- evhttp_request_free(req);
}
out:
+ if (req)
+ evhttp_request_free(req);
+
event_base_loopexit(arg, NULL);
}
@@ -3317,10 +3431,15 @@ http_multi_line_header_test(void *arg)
http = http_setup(&port, data->base, 0);
+ tt_ptr_op(http, !=, NULL);
+
fd = http_connect("127.0.0.1", port);
+ tt_int_op(fd, !=, -1);
+
/* Stupid thing to send a request */
bev = bufferevent_socket_new(data->base, fd, 0);
+ tt_ptr_op(bev, !=, NULL);
bufferevent_setcb(bev, http_readcb, http_writecb,
http_errorcb, data->base);
@@ -3759,6 +3878,7 @@ struct testcase_t http_testcases[] = {
HTTP(incomplete),
HTTP(incomplete_timeout),
HTTP(terminate_chunked),
+ HTTP(on_complete),
HTTP(highport),
HTTP(dispatcher),
diff --git a/test/regress_rpc.c b/test/regress_rpc.c
index 0a5c7a3f..01a058cb 100644
--- a/test/regress_rpc.c
+++ b/test/regress_rpc.c
@@ -463,12 +463,14 @@ rpc_basic_client(void)
!= NULL);
pool = rpc_pool_with_connection(port);
+ tt_assert(pool);
assert(evrpc_add_hook(pool, EVRPC_OUTPUT, rpc_hook_add_meta, NULL));
assert(evrpc_add_hook(pool, EVRPC_INPUT, rpc_hook_remove_header, (void*)"output"));
/* set up the basic message */
msg = msg_new();
+ tt_assert(msg);
EVTAG_ASSIGN(msg, from_name, "niels");
EVTAG_ASSIGN(msg, to_name, "tester");
@@ -539,9 +541,11 @@ rpc_basic_queued_client(void)
rpc_setup(&http, &port, &base);
pool = rpc_pool_with_connection(port);
+ tt_assert(pool);
/* set up the basic message */
msg = msg_new();
+ tt_assert(msg);
EVTAG_ASSIGN(msg, from_name, "niels");
EVTAG_ASSIGN(msg, to_name, "tester");
@@ -640,12 +644,13 @@ rpc_basic_client_with_pause(void)
assert(evrpc_add_hook(base, EVRPC_OUTPUT, rpc_hook_pause, base));
pool = rpc_pool_with_connection(port);
-
+ tt_assert(pool);
assert(evrpc_add_hook(pool, EVRPC_INPUT, rpc_hook_pause, pool));
assert(evrpc_add_hook(pool, EVRPC_OUTPUT, rpc_hook_pause, pool));
/* set up the basic message */
msg = msg_new();
+ tt_assert(msg);
EVTAG_ASSIGN(msg, from_name, "niels");
EVTAG_ASSIGN(msg, to_name, "tester");
@@ -688,12 +693,14 @@ rpc_client_timeout(void)
rpc_setup(&http, &port, &base);
pool = rpc_pool_with_connection(port);
+ tt_assert(pool);
/* set the timeout to 1 second. */
evrpc_pool_set_timeout(pool, 1);
/* set up the basic message */
msg = msg_new();
+ tt_assert(msg);
EVTAG_ASSIGN(msg, from_name, "niels");
EVTAG_ASSIGN(msg, to_name, "tester");
diff --git a/test/regress_ssl.c b/test/regress_ssl.c
index acf2bd67..c2113414 100644
--- a/test/regress_ssl.c
+++ b/test/regress_ssl.c
@@ -24,6 +24,11 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+// Get rid of OSX 10.7 and greater deprecation warnings.
+#if defined(__APPLE__) && defined(__clang__)
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
diff --git a/test/regress_util.c b/test/regress_util.c
index d64d0024..60f085bf 100644
--- a/test/regress_util.c
+++ b/test/regress_util.c
@@ -179,10 +179,10 @@ regress_ipv6_parse(void *ptr)
for (j = 0; j < 4; ++j) {
/* Can't use s6_addr32 here; some don't have it. */
ev_uint32_t u =
- (in6.s6_addr[j*4 ] << 24) |
- (in6.s6_addr[j*4+1] << 16) |
- (in6.s6_addr[j*4+2] << 8) |
- (in6.s6_addr[j*4+3]);
+ ((ev_uint32_t)in6.s6_addr[j*4 ] << 24) |
+ ((ev_uint32_t)in6.s6_addr[j*4+1] << 16) |
+ ((ev_uint32_t)in6.s6_addr[j*4+2] << 8) |
+ ((ev_uint32_t)in6.s6_addr[j*4+3]);
if (u != ent->res[j]) {
TT_FAIL(("%s did not parse as expected.", ent->addr));
continue;
@@ -726,46 +726,48 @@ test_evutil_integers(void *arg)
tt_assert(u64 > 0);
tt_assert(i64 > 0);
u64++;
- i64++;
+/* i64++; */
tt_assert(u64 == 0);
- tt_assert(i64 == EV_INT64_MIN);
- tt_assert(i64 < 0);
+/* tt_assert(i64 == EV_INT64_MIN); */
+/* tt_assert(i64 < 0); */
u32 = EV_UINT32_MAX;
i32 = EV_INT32_MAX;
tt_assert(u32 > 0);
tt_assert(i32 > 0);
u32++;
- i32++;
+/* i32++; */
tt_assert(u32 == 0);
- tt_assert(i32 == EV_INT32_MIN);
- tt_assert(i32 < 0);
+/* tt_assert(i32 == EV_INT32_MIN); */
+/* tt_assert(i32 < 0); */
u16 = EV_UINT16_MAX;
i16 = EV_INT16_MAX;
tt_assert(u16 > 0);
tt_assert(i16 > 0);
u16++;
- i16++;
+/* i16++; */
tt_assert(u16 == 0);
- tt_assert(i16 == EV_INT16_MIN);
- tt_assert(i16 < 0);
+/* tt_assert(i16 == EV_INT16_MIN); */
+/* tt_assert(i16 < 0); */
u8 = EV_UINT8_MAX;
i8 = EV_INT8_MAX;
tt_assert(u8 > 0);
tt_assert(i8 > 0);
u8++;
- i8++;
+/* i8++;*/
tt_assert(u8 == 0);
- tt_assert(i8 == EV_INT8_MIN);
- tt_assert(i8 < 0);
+/* tt_assert(i8 == EV_INT8_MIN); */
+/* tt_assert(i8 < 0); */
+/*
ssize = EV_SSIZE_MAX;
tt_assert(ssize > 0);
ssize++;
tt_assert(ssize < 0);
tt_assert(ssize == EV_SSIZE_MIN);
+*/
ptr = &ssize;
iptr = (ev_intptr_t)ptr;
@@ -1119,7 +1121,7 @@ end:
static void
test_evutil_loadsyslib(void *arg)
{
- HANDLE h=NULL;
+ HMODULE h=NULL;
h = evutil_load_windows_system_library_(TEXT("kernel32.dll"));
tt_assert(h);
diff --git a/test/regress_zlib.c b/test/regress_zlib.c
index 9339397c..84066769 100644
--- a/test/regress_zlib.c
+++ b/test/regress_zlib.c
@@ -56,6 +56,7 @@
#include "event2/bufferevent.h"
#include "regress.h"
+#include "mm-internal.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
@@ -95,6 +96,7 @@ zlib_deflate_free(void *ctx)
z_streamp p = ctx;
assert(deflateEnd(p) == Z_OK);
+ mm_free(p);
}
static void
@@ -103,6 +105,7 @@ zlib_inflate_free(void *ctx)
z_streamp p = ctx;
assert(inflateEnd(p) == Z_OK);
+ mm_free(p);
}
static int
@@ -275,7 +278,7 @@ test_bufferevent_zlib(void *arg)
{
struct bufferevent *bev1=NULL, *bev2=NULL;
char buffer[8333];
- z_stream z_input, z_output;
+ z_stream *z_input, *z_output;
int i, r;
evutil_socket_t pair[2] = {-1, -1};
(void)arg;
@@ -293,18 +296,18 @@ test_bufferevent_zlib(void *arg)
bev1 = bufferevent_socket_new(NULL, pair[0], 0);
bev2 = bufferevent_socket_new(NULL, pair[1], 0);
- memset(&z_output, 0, sizeof(z_output));
- r = deflateInit(&z_output, Z_DEFAULT_COMPRESSION);
+ z_output = mm_calloc(sizeof(*z_output), 1);
+ r = deflateInit(z_output, Z_DEFAULT_COMPRESSION);
tt_int_op(r, ==, Z_OK);
- memset(&z_input, 0, sizeof(z_input));
- r = inflateInit(&z_input);
+ z_input = mm_calloc(sizeof(*z_input), 1);
+ r = inflateInit(z_input);
tt_int_op(r, ==, Z_OK);
/* initialize filters */
bev1 = bufferevent_filter_new(bev1, NULL, zlib_output_filter,
- BEV_OPT_CLOSE_ON_FREE, zlib_deflate_free, &z_output);
+ BEV_OPT_CLOSE_ON_FREE, zlib_deflate_free, z_output);
bev2 = bufferevent_filter_new(bev2, zlib_input_filter,
- NULL, BEV_OPT_CLOSE_ON_FREE, zlib_inflate_free, &z_input);
+ NULL, BEV_OPT_CLOSE_ON_FREE, zlib_inflate_free, z_input);
bufferevent_setcb(bev1, readcb, writecb, errorcb, NULL);
bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL);
diff --git a/test/test-changelist.c b/test/test-changelist.c
index 206eb601..6e2466d5 100644
--- a/test/test-changelist.c
+++ b/test/test-changelist.c
@@ -183,7 +183,8 @@ main(int argc, char **argv)
return (1);
/* Initalize the event library */
- base = event_base_new();
+ if (!(base = event_base_new()))
+ return (1);
/* Initalize a timeout to terminate the test */
timeout = evtimer_new(base,timeout_cb,&timeout);
diff --git a/test/test-closed.c b/test/test-closed.c
new file mode 100644
index 00000000..5b04f354
--- /dev/null
+++ b/test/test-closed.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2007-2013 Niels Provos and Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "event2/event-config.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef EVENT__HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef EVENT__HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <event.h>
+#include <evutil.h>
+
+#ifdef EVENT____func__
+#define __func__ EVENT____func__
+#endif
+
+struct timeval timeout = {3, 0};
+
+static void
+closed_cb(evutil_socket_t fd, short event, void *arg)
+{
+ if (EV_TIMEOUT & event) {
+ printf("%s: Timeout!\n", __func__);
+ exit(1);
+ }
+
+ if (EV_CLOSED & event) {
+ printf("%s: detected socket close with success\n", __func__);
+ return;
+ }
+
+ printf("%s: unable to detect socket close\n", __func__);
+ exit(1);
+}
+
+#ifndef SHUT_WR
+#define SHUT_WR 1
+#endif
+
+int
+main(int argc, char **argv)
+{
+ struct event_base *base;
+ struct event_config *cfg;
+ struct event *ev;
+ const char *test = "test string";
+ evutil_socket_t pair[2];
+
+ /* Initialize the library and check if the backend
+ supports EV_FEATURE_EARLY_CLOSE
+ */
+ cfg = event_config_new();
+ event_config_require_features(cfg, EV_FEATURE_EARLY_CLOSE);
+ base = event_base_new_with_config(cfg);
+ event_config_free(cfg);
+ if (!base) {
+ /* Backend doesn't support EV_FEATURE_EARLY_CLOSE */
+ return 0;
+ }
+
+ /* Create a pair of sockets */
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
+ return (1);
+
+ /* Send some data on socket 0 and immediately close it */
+ if (send(pair[0], test, (int)strlen(test)+1, 0) < 0)
+ return (1);
+ shutdown(pair[0], SHUT_WR);
+
+ /* Dispatch */
+ ev = event_new(base, pair[1], EV_CLOSED | EV_TIMEOUT, closed_cb, event_self_cbarg());
+ event_add(ev, &timeout);
+ event_base_dispatch(base);
+
+ /* Finalize library */
+ event_base_free(base);
+ return 0;
+}
+
diff --git a/test/test-fdleak.c b/test/test-fdleak.c
index ee2432b7..4c4eba25 100644
--- a/test/test-fdleak.c
+++ b/test/test-fdleak.c
@@ -57,7 +57,7 @@
#endif
/* Provide storage for the address, both for the server & the clients */
-static struct sockaddr_in sin;
+static struct sockaddr_in saddr;
/* Number of sucessful requests so far */
static int num_requests;
@@ -131,7 +131,7 @@ start_loop(void)
listener = evconnlistener_new_bind(base, listener_accept_cb, NULL,
LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
- -1, (struct sockaddr *)&sin, sizeof(sin));
+ -1, (struct sockaddr *)&saddr, sizeof(saddr));
if (listener == NULL) {
my_perror("Could not create listener!");
exit(1);
@@ -145,8 +145,8 @@ start_loop(void)
my_perror("getsockname()");
exit(1);
}
- memcpy(&sin, &ss, sizeof(sin));
- if (sin.sin_family != AF_INET) {
+ memcpy(&saddr, &ss, sizeof(saddr));
+ if (saddr.sin_family != AF_INET) {
puts("AF mismatch from getsockname().");
exit(1);
}
@@ -208,8 +208,8 @@ start_client(struct event_base *base)
BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bev, client_read_cb, NULL, client_event_cb, NULL);
- if (bufferevent_socket_connect(bev, (struct sockaddr *)&sin,
- sizeof(sin)) < 0) {
+ if (bufferevent_socket_connect(bev, (struct sockaddr *)&saddr,
+ sizeof(saddr)) < 0) {
my_perror("Could not connect!");
bufferevent_free(bev);
exit(2);
@@ -236,10 +236,10 @@ main(int argc, char **argv)
#endif
/* Set up an address, used by both client & server. */
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = htonl(0x7f000001);
- sin.sin_port = 0; /* Tell the implementation to pick a port. */
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = htonl(0x7f000001);
+ saddr.sin_port = 0; /* Tell the implementation to pick a port. */
start_loop();
diff --git a/test/test.sh b/test/test.sh
index d16fcde3..2b083ac7 100755
--- a/test/test.sh
+++ b/test/test.sh
@@ -1,7 +1,7 @@
#!/bin/sh
BACKENDS="EVPORT KQUEUE EPOLL DEVPOLL POLL SELECT WIN32"
-TESTS="test-eof test-weof test-time test-changelist test-fdleak"
+TESTS="test-eof test-closed test-weof test-time test-changelist test-fdleak"
FAILED=no
TEST_OUTPUT_FILE=${TEST_OUTPUT_FILE:-/dev/null}
REGRESS_ARGS=${REGRESS_ARGS:-}
diff --git a/test/tinytest.c b/test/tinytest.c
index 36b3a627..3a8e3310 100644
--- a/test/tinytest.c
+++ b/test/tinytest.c
@@ -31,6 +31,8 @@
#include <string.h>
#include <assert.h>
+#ifndef NO_FORKING
+
#ifdef _WIN32
#include <windows.h>
#else
@@ -48,6 +50,8 @@
#endif
#endif
+#endif /* !NO_FORKING */
+
#ifndef __GNUC__
#define __attribute__(x)
#endif
@@ -111,6 +115,8 @@ testcase_run_bare_(const struct testcase_t *testcase)
#define MAGIC_EXITCODE 42
+#ifndef NO_FORKING
+
static enum outcome
testcase_run_forked_(const struct testgroup_t *group,
const struct testcase_t *testcase)
@@ -211,6 +217,8 @@ testcase_run_forked_(const struct testgroup_t *group,
#endif
}
+#endif /* !NO_FORKING */
+
int
testcase_run_one(const struct testgroup_t *group,
const struct testcase_t *testcase)
@@ -234,9 +242,13 @@ testcase_run_one(const struct testgroup_t *group,
cur_test_name = testcase->name;
}
+#ifndef NO_FORKING
if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
outcome = testcase_run_forked_(group, testcase);
} else {
+#else
+ {
+#endif
outcome = testcase_run_bare_(testcase);
}
@@ -411,7 +423,9 @@ tinytest_main(int c, const char **v, struct testgroup_t *groups)
if (!n)
tinytest_set_flag_(groups, "..", 1, TT_ENABLED_);
+#ifdef _IONBF
setvbuf(stdout, NULL, _IONBF, 0);
+#endif
++in_tinytest_main;
for (i=0; groups[i].prefix; ++i)
@@ -458,3 +472,22 @@ tinytest_set_test_skipped_(void)
cur_test_outcome = SKIP;
}
+char *
+tinytest_format_hex_(const void *val_, unsigned long len)
+{
+ const unsigned char *val = val_;
+ char *result, *cp;
+ size_t i;
+
+ if (!val)
+ return strdup("null");
+ if (!(result = malloc(len*2+1)))
+ return strdup("<allocation failure>");
+ cp = result;
+ for (i=0;i<len;++i) {
+ *cp++ = "0123456789ABCDEF"[val[i] >> 4];
+ *cp++ = "0123456789ABCDEF"[val[i] & 0x0f];
+ }
+ *cp = 0;
+ return result;
+}
diff --git a/test/tinytest.h b/test/tinytest.h
index dff440e3..ed07b26b 100644
--- a/test/tinytest.h
+++ b/test/tinytest.h
@@ -81,6 +81,8 @@ int tinytest_get_verbosity_(void);
/** Implementation: Set a flag on tests matching a name; returns number
* of tests that matched. */
int tinytest_set_flag_(struct testgroup_t *, const char *, int set, unsigned long);
+/** Implementation: Put a chunk of memory into hex. */
+char *tinytest_format_hex_(const void *, unsigned long);
/** Set all tests in 'groups' matching the name 'named' to be skipped. */
#define tinytest_skip(groups, named) \
diff --git a/test/tinytest_demo.c b/test/tinytest_demo.c
index 10a80b2f..bdd0e600 100644
--- a/test/tinytest_demo.c
+++ b/test/tinytest_demo.c
@@ -152,6 +152,9 @@ test_memcpy(void *ptr)
memcpy(db->buffer2, db->buffer1, sizeof(db->buffer1));
tt_str_op(db->buffer1, ==, db->buffer2);
+ /* This one works if there's an internal NUL. */
+ tt_mem_op(db->buffer1, <, db->buffer2, sizeof(db->buffer1));
+
/* Now we've allocated memory that's referenced by a local variable.
The end block of the function will clean it up. */
mem = strdup("Hello world.");
diff --git a/test/tinytest_macros.h b/test/tinytest_macros.h
index 9ff69b1d..c3728d1f 100644
--- a/test/tinytest_macros.h
+++ b/test/tinytest_macros.h
@@ -113,8 +113,8 @@
#define tt_assert_test_fmt_type(a,b,str_test,type,test,printf_type,printf_fmt, \
setup_block,cleanup_block,die_on_fail) \
TT_STMT_BEGIN \
- type val1_ = (type)(a); \
- type val2_ = (type)(b); \
+ type val1_ = (a); \
+ type val2_ = (b); \
int tt_status_ = (test); \
if (!tt_status_ || tinytest_get_verbosity_()>1) { \
printf_type print_; \
@@ -144,6 +144,10 @@
tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt, \
{print_=value_;},{},die_on_fail)
+#define tt_assert_test_type_opt(a,b,str_test,type,test,fmt,die_on_fail) \
+ tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt, \
+ {print_=value_?value_:"<NULL>";},{},die_on_fail)
+
/* Helper: assert that a op b, when cast to type. Format the values with
* printf format fmt on failure. */
#define tt_assert_op_type(a,op,b,type,fmt) \
@@ -159,12 +163,23 @@
(val1_ op val2_),"%lu",TT_EXIT_TEST_FUNCTION)
#define tt_ptr_op(a,op,b) \
- tt_assert_test_type(a,b,#a" "#op" "#b,void*, \
+ tt_assert_test_type(a,b,#a" "#op" "#b,const void*, \
(val1_ op val2_),"%p",TT_EXIT_TEST_FUNCTION)
#define tt_str_op(a,op,b) \
- tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \
- (strcmp(val1_,val2_) op 0),"<%s>",TT_EXIT_TEST_FUNCTION)
+ tt_assert_test_type_opt(a,b,#a" "#op" "#b,const char *, \
+ (val1_ && val2_ && strcmp(val1_,val2_) op 0),"<%s>", \
+ TT_EXIT_TEST_FUNCTION)
+
+#define tt_mem_op(expr1, op, expr2, len) \
+ tt_assert_test_fmt_type(expr1,expr2,#expr1" "#op" "#expr2, \
+ const void *, \
+ (val1_ && val2_ && memcmp(val1_, val2_, len) op 0), \
+ char *, "%s", \
+ { print_ = tinytest_format_hex_(value_, (len)); }, \
+ { if (print_) free(print_); }, \
+ TT_EXIT_TEST_FUNCTION \
+ );
#define tt_want_int_op(a,op,b) \
tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_),"%ld",(void)0)
@@ -174,7 +189,7 @@
(val1_ op val2_),"%lu",(void)0)
#define tt_want_ptr_op(a,op,b) \
- tt_assert_test_type(a,b,#a" "#op" "#b,void*, \
+ tt_assert_test_type(a,b,#a" "#op" "#b,const void*, \
(val1_ op val2_),"%p",(void)0)
#define tt_want_str_op(a,op,b) \
diff --git a/util-internal.h b/util-internal.h
index 0ab8a257..4fdedeaf 100644
--- a/util-internal.h
+++ b/util-internal.h
@@ -392,7 +392,7 @@ void evutil_free_secure_rng_globals_(void);
void evutil_free_globals_(void);
#ifdef _WIN32
-HANDLE evutil_load_windows_system_library_(const TCHAR *library_name);
+HMODULE evutil_load_windows_system_library_(const TCHAR *library_name);
#endif
#ifndef EV_SIZE_FMT
@@ -443,6 +443,9 @@ HANDLE evutil_load_windows_system_library_(const TCHAR *library_name);
evutil_socket_t evutil_socket_(int domain, int type, int protocol);
evutil_socket_t evutil_accept4_(evutil_socket_t sockfd, struct sockaddr *addr,
ev_socklen_t *addrlen, int flags);
+
+ /* used by one of the test programs.. */
+EVENT2_EXPORT_SYMBOL
int evutil_make_internal_pipe_(evutil_socket_t fd[2]);
evutil_socket_t evutil_eventfd_(unsigned initval, int flags);
diff --git a/whatsnew-2.1.txt b/whatsnew-2.1.txt
index c0ee7cf7..0be54ae1 100644
--- a/whatsnew-2.1.txt
+++ b/whatsnew-2.1.txt
@@ -41,7 +41,7 @@
We don't try to do binary compatibility except within stable release
series, so binaries linked against any version of Libevent 2.0 will
- probably need to be recompiled against Libevent 2.1.3-alpha if you
+ probably need to be recompiled against Libevent 2.1.4-alpha if you
want to use it. It is probable that we'll break binary compatibility
again before Libevent 2.1 is stable.
@@ -63,6 +63,9 @@
surrounded with appropriate #ifdef lines to keep your IDE from getting
upset.
+ There is now an alternative cmake-based build process; cmake users
+ should see the relevant sections in the README.
+
1.2. New functions for events and the event loop
@@ -146,6 +149,19 @@
that's a no-op in past versions of Libevent, and we don't want to
break compatibility.)
+ You can use the new event_base_get_num_events() function to find the
+ number of events active or pending on an event_base. To find the
+ largest number of events that there have been since the last call, use
+ event_base_get_max_events().
+
+ You can now activate all the events waiting for a given fd or signal
+ using the event_base_active_by_fd() and event_base_active_by_signal()
+ APIs.
+
+ On backends that support it (currently epoll), there is now an
+ EV_CLOSED flag that programs can use to detect when a socket has
+ closed without having to read all the bytes until receiving an EOF.
+
1.3. Event finalization
[NOTE: This is an experimental feature in Libevent 2.1.3-alpha. Though
@@ -325,6 +341,13 @@
You can find the priority at which a bufferevent runs with
bufferevent_get_priority().
+ The function bufferevent_get_token_bucket_cfg() can retrieve the
+ rate-limit settings for a bufferevent; bufferevent_getwatermark() can
+ return a bufferevent's current watermark settings.
+
+ You can manually trigger a bufferevent's callbacks via
+ bufferevent_trigger() and bufferevent_trigger_event().
+
1.7. New functions and features: evdns
The previous evdns interface used an "open a test UDP socket" trick in
@@ -340,6 +363,9 @@
flag, which tells the evdns_base that it should not prevent Libevent from
exiting while it has no DNS requests in progress.
+ There is a new evdns_base_clear_host_addresses() function to remove
+ all the /etc/hosts addresses registered with an evdns instance.
+
1.8. New functions and features: evconnlistener
Libevent 2.1 adds the following evconnlistener flags:
@@ -392,6 +418,31 @@
and actually reports the error code and lets you figure out which request
failed.
+ You can navigate from an evhttp_connection back to its evhttp with the
+ new evhttp_connection_get_server() function.
+
+ You can override the default HTTP Content-Type with the new
+ evhttp_set_default_content_type() function
+
+ There's a new evhttp_connection_get_addr() API to return the peer
+ address of an evhttp_connection.
+
+ The new evhttp_send_reply_chunk_with_cb() is a variant of
+ evhttp_send_reply_chunk() with a callback to be invoked when the
+ chunk is sent.
+
+ The evhttp_request_set_header_cb() facility adds a callback to be
+ invoked while parsing headers.
+
+ The evhttp_request_set_on_complete_cb() facility adds a callback to be
+ invoked on request completion.
+
+1.10. New functions and features: evutil
+
+ There's a function "evutil_secure_rng_set_urandom_device_file()" that
+ you can use to override the default file that Libevent uses to seed
+ its (sort-of) secure RNG.
+
2. Cross-platform performance improvements
2.1. Better data structures