]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
libevent-2.1.12-stable
authorHarlan Stenn <stenn@ntp.org>
Thu, 1 Sep 2022 07:56:37 +0000 (02:56 -0500)
committerHarlan Stenn <stenn@ntp.org>
Thu, 1 Sep 2022 07:56:37 +0000 (02:56 -0500)
bk: 631065b5yabnqA2tb3jdOp7zV8PtMw

162 files changed:
ChangeLog
sntp/libevent/CMakeLists.txt [new file with mode: 0644]
sntp/libevent/ChangeLog
sntp/libevent/ChangeLog-1.4
sntp/libevent/ChangeLog-2.0
sntp/libevent/Doxyfile
sntp/libevent/Makefile.am
sntp/libevent/README.md
sntp/libevent/WIN32-Code/getopt_long.c
sntp/libevent/WIN32-Code/nmake/event2/event-config.h
sntp/libevent/arc4random.c
sntp/libevent/autogen.sh
sntp/libevent/buffer.c
sntp/libevent/buffer_iocp.c
sntp/libevent/bufferevent-internal.h
sntp/libevent/bufferevent.c
sntp/libevent/bufferevent_async.c
sntp/libevent/bufferevent_filter.c
sntp/libevent/bufferevent_openssl.c
sntp/libevent/bufferevent_pair.c
sntp/libevent/bufferevent_ratelim.c
sntp/libevent/bufferevent_sock.c
sntp/libevent/build-aux/test-driver [new file with mode: 0755]
sntp/libevent/checkpatch.sh [new file with mode: 0755]
sntp/libevent/cmake/AddCompilerFlags.cmake [new file with mode: 0644]
sntp/libevent/cmake/AddEventLibrary.cmake [new file with mode: 0644]
sntp/libevent/cmake/COPYING-CMAKE-SCRIPTS [new file with mode: 0644]
sntp/libevent/cmake/CheckConstExists.cmake [new file with mode: 0644]
sntp/libevent/cmake/CheckFileOffsetBits.c [new file with mode: 0644]
sntp/libevent/cmake/CheckFileOffsetBits.cmake [new file with mode: 0644]
sntp/libevent/cmake/CheckFunctionKeywords.cmake [new file with mode: 0644]
sntp/libevent/cmake/CheckPrototypeDefinition.c.in [new file with mode: 0644]
sntp/libevent/cmake/CheckPrototypeDefinition.cmake [new file with mode: 0644]
sntp/libevent/cmake/CheckWorkingKqueue.cmake [new file with mode: 0644]
sntp/libevent/cmake/CodeCoverage.cmake [new file with mode: 0644]
sntp/libevent/cmake/Copyright.txt [new file with mode: 0644]
sntp/libevent/cmake/LibeventConfig.cmake.in [new file with mode: 0644]
sntp/libevent/cmake/LibeventConfigVersion.cmake.in [new file with mode: 0644]
sntp/libevent/cmake/Macros.cmake [new file with mode: 0644]
sntp/libevent/cmake/Uninstall.cmake.in [new file with mode: 0644]
sntp/libevent/cmake/UseDoxygen.cmake [new file with mode: 0644]
sntp/libevent/cmake/VersionViaGit.cmake [new file with mode: 0644]
sntp/libevent/compile [new file with mode: 0755]
sntp/libevent/config.guess [new file with mode: 0755]
sntp/libevent/config.sub [new file with mode: 0755]
sntp/libevent/configure.ac
sntp/libevent/defer-internal.h
sntp/libevent/depcomp [new file with mode: 0755]
sntp/libevent/doxygen.am [new file with mode: 0644]
sntp/libevent/epoll.c
sntp/libevent/epolltable-internal.h
sntp/libevent/evbuffer-internal.h
sntp/libevent/evconfig-private.h.cmake [new file with mode: 0644]
sntp/libevent/evconfig-private.h.in
sntp/libevent/evdns.c
sntp/libevent/event-config.h.cmake [new file with mode: 0644]
sntp/libevent/event-internal.h
sntp/libevent/event.c
sntp/libevent/event_iocp.c
sntp/libevent/event_rpcgen.py
sntp/libevent/event_tagging.c
sntp/libevent/evmap.c
sntp/libevent/evrpc.c
sntp/libevent/evthread-internal.h
sntp/libevent/evthread.c
sntp/libevent/evutil.c
sntp/libevent/evutil_rand.c
sntp/libevent/evutil_time.c
sntp/libevent/http-internal.h
sntp/libevent/http.c
sntp/libevent/include/event.h
sntp/libevent/include/event2/buffer.h
sntp/libevent/include/event2/buffer_compat.h
sntp/libevent/include/event2/bufferevent.h
sntp/libevent/include/event2/bufferevent_compat.h
sntp/libevent/include/event2/dns.h
sntp/libevent/include/event2/dns_compat.h
sntp/libevent/include/event2/event.h
sntp/libevent/include/event2/http.h
sntp/libevent/include/event2/http_compat.h
sntp/libevent/include/event2/listener.h
sntp/libevent/include/event2/rpc.h
sntp/libevent/include/event2/rpc_struct.h
sntp/libevent/include/event2/util.h
sntp/libevent/include/event2/visibility.h
sntp/libevent/include/include.am
sntp/libevent/iocp-internal.h
sntp/libevent/kqueue.c
sntp/libevent/libevent_core.pc.in [new file with mode: 0644]
sntp/libevent/libevent_extra.pc.in [new file with mode: 0644]
sntp/libevent/listener.c
sntp/libevent/log-internal.h
sntp/libevent/log.c
sntp/libevent/ltmain.sh [new file with mode: 0644]
sntp/libevent/m4/ax_check_funcs_ex.m4 [new file with mode: 0644]
sntp/libevent/m4/ax_prog_doxygen.m4 [new file with mode: 0644]
sntp/libevent/m4/libevent_openssl.m4
sntp/libevent/make-event-config.sed
sntp/libevent/minheap-internal.h
sntp/libevent/missing [new file with mode: 0755]
sntp/libevent/mm-internal.h
sntp/libevent/openssl-compat.h [new file with mode: 0644]
sntp/libevent/poll.c
sntp/libevent/sample/dns-example.c
sntp/libevent/sample/event-read-fifo.c
sntp/libevent/sample/hello-world.c
sntp/libevent/sample/http-connect.c [new file with mode: 0644]
sntp/libevent/sample/http-server.c
sntp/libevent/sample/https-client.c
sntp/libevent/sample/include.am
sntp/libevent/sample/le-proxy.c
sntp/libevent/sample/openssl_hostname_validation.c
sntp/libevent/sample/signal-test.c
sntp/libevent/sample/time-test.c
sntp/libevent/select.c
sntp/libevent/signal.c
sntp/libevent/strlcpy-internal.h
sntp/libevent/test-driver [new file with mode: 0755]
sntp/libevent/test/bench.c
sntp/libevent/test/bench_cascade.c
sntp/libevent/test/bench_http.c
sntp/libevent/test/bench_httpclient.c
sntp/libevent/test/check-dumpevents.py
sntp/libevent/test/include.am
sntp/libevent/test/print-winsock-errors.c
sntp/libevent/test/regress.c
sntp/libevent/test/regress.h
sntp/libevent/test/regress_buffer.c
sntp/libevent/test/regress_bufferevent.c
sntp/libevent/test/regress_dns.c
sntp/libevent/test/regress_et.c
sntp/libevent/test/regress_finalize.c
sntp/libevent/test/regress_http.c
sntp/libevent/test/regress_listener.c
sntp/libevent/test/regress_main.c
sntp/libevent/test/regress_minheap.c
sntp/libevent/test/regress_rpc.c
sntp/libevent/test/regress_ssl.c
sntp/libevent/test/regress_testutils.c
sntp/libevent/test/regress_testutils.h
sntp/libevent/test/regress_thread.c
sntp/libevent/test/regress_thread.h
sntp/libevent/test/regress_util.c
sntp/libevent/test/regress_zlib.c
sntp/libevent/test/rpcgen_wrapper.sh
sntp/libevent/test/test-changelist.c
sntp/libevent/test/test-closed.c
sntp/libevent/test/test-eof.c
sntp/libevent/test/test-fdleak.c
sntp/libevent/test/test-init.c
sntp/libevent/test/test-ratelim.c
sntp/libevent/test/test-time.c
sntp/libevent/test/test-weof.c
sntp/libevent/test/test.sh
sntp/libevent/test/tinytest.c
sntp/libevent/test/tinytest.h
sntp/libevent/test/tinytest_demo.c
sntp/libevent/test/tinytest_macros.h
sntp/libevent/time-internal.h
sntp/libevent/util-internal.h
sntp/libevent/whatsnew-2.1.txt
sntp/libevent/win32select.c

index 3addb7b81eaef60a58c74b960291d16ae7370602..2c1e611aad95dbf7f8cf44983d60ea64c9f9b6e9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -43,6 +43,7 @@
   - backport from -dev, plus some more work on warnings for unchecked results
 * Implement NTP_FUNC_REALPATH.  <stenn@ntp.org>
 * Lose a gmake construct in ntpd/Makefile.am.  <stenn@ntp.org>
+* Upgrade to libevent-2.1.12-stable <stenn@ntp.org>
 
 ---
 (4.2.8p15) 2020/06/23 Released by Harlan Stenn <stenn@ntp.org>
diff --git a/sntp/libevent/CMakeLists.txt b/sntp/libevent/CMakeLists.txt
new file mode 100644 (file)
index 0000000..676727f
--- /dev/null
@@ -0,0 +1,1575 @@
+#
+# 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 3.1 FATAL_ERROR)
+
+if (POLICY CMP0054)
+    cmake_policy(SET CMP0054 NEW)
+endif()
+if (POLICY CMP0074)
+    cmake_policy(SET CMP0074 NEW)
+endif()
+if (POLICY CMP0075)
+    cmake_policy(SET CMP0075 NEW)
+endif()
+
+if(NOT CMAKE_BUILD_TYPE)
+    set(CMAKE_BUILD_TYPE Release
+        CACHE STRING "Set build type to Debug o Release (default Release)" FORCE)
+endif()
+string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER)
+
+# get rid of the extra default configurations
+# what? why would you get id of other useful build types? - Ellzey
+set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Limited configurations" FORCE)
+
+set(EVENT__LIBRARY_TYPE DEFAULT CACHE STRING
+    "Set library type to SHARED/STATIC/BOTH (default SHARED for MSVC, otherwise BOTH)")
+
+project(libevent C)
+
+list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/")
+string(REGEX MATCH "SunOS" SOLARIS "${CMAKE_SYSTEM_NAME}")
+
+
+include(CheckTypeSize)
+include(CheckFileOffsetBits)
+include(Macros)
+include(CheckVariableExists)
+include(CheckSymbolExists)
+include(CheckStructHasMember)
+include(CheckCSourceCompiles)
+include(CheckPrototypeDefinition)
+include(CheckFunctionKeywords)
+include(CheckConstExists)
+include(AddCompilerFlags)
+include(VersionViaGit)
+
+event_fuzzy_version_from_git()
+
+set(EVENT_VERSION_MAJOR ${EVENT_GIT___VERSION_MAJOR})
+set(EVENT_VERSION_MINOR ${EVENT_GIT___VERSION_MINOR})
+set(EVENT_VERSION_PATCH ${EVENT_GIT___VERSION_PATCH})
+set(EVENT_VERSION_STAGE ${EVENT_GIT___VERSION_STAGE})
+
+
+set(EVENT_ABI_MAJOR ${EVENT_VERSION_MAJOR})
+set(EVENT_ABI_MINOR ${EVENT_VERSION_MINOR})
+set(EVENT_ABI_PATCH ${EVENT_VERSION_PATCH})
+
+set(EVENT_ABI_LIBVERSION
+    "${EVENT_ABI_MAJOR}.${EVENT_ABI_MINOR}.${EVENT_ABI_PATCH}")
+
+set(EVENT_PACKAGE_VERSION
+    "${EVENT_VERSION_MAJOR}.${EVENT_VERSION_MINOR}.${EVENT_VERSION_PATCH}")
+
+set(EVENT_NUMERIC_VERSION 0x02010c00)
+# equals to VERSION_INFO in Makefile.am
+set(EVENT_ABI_LIBVERSION_CURRENT   7)
+set(EVENT_ABI_LIBVERSION_REVISION  1)
+set(EVENT_ABI_LIBVERSION_AGE       0)
+
+# equals to RELEASE in Makefile.am
+set(EVENT_PACKAGE_RELEASE 2.1)
+
+# only a subset of names can be used, defaults to "beta"
+set(EVENT_STAGE_NAME ${EVENT_VERSION_STAGE})
+
+# a list that defines what can set for EVENT_STAGE_VERSION
+set(EVENT__ALLOWED_STAGE_NAMES
+       rc
+       beta
+       alpha
+       alpha-dev
+       release
+       stable
+)
+list(
+       FIND EVENT__ALLOWED_STAGE_NAMES
+       "${EVENT_STAGE_NAME}"
+       EVENT__STAGE_RET
+)
+if (EVENT__STAGE_RET EQUAL -1)
+       message(WARNING
+               "stage ${EVENT_STAGE_NAME} is not allowed, reset to beta")
+       set(EVENT_STAGE_NAME beta)
+endif()
+
+set(EVENT_VERSION
+       "${EVENT_VERSION_MAJOR}.${EVENT_VERSION_MINOR}.${EVENT_VERSION_PATCH}-${EVENT_STAGE_NAME}")
+
+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 encryption" OFF)
+
+option(EVENT__DISABLE_BENCHMARK
+    "Defines if libevent should build without the benchmark executables" OFF)
+
+option(EVENT__DISABLE_TESTS
+    "If tests should be compiled or not" OFF)
+
+option(EVENT__DISABLE_REGRESS
+    "Disable the regress tests" OFF)
+
+option(EVENT__DISABLE_SAMPLES
+    "Disable sample files" OFF)
+
+option(EVENT__DISABLE_CLOCK_GETTIME
+    "Do not use clock_gettime even if it is available" 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 cross compilation target to verify that it works. See cmake documentation for try_run for more details" OFF)
+
+# TODO: Add --disable-largefile     omit support for large files
+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)
+
+# 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.
+#
+# But only if this variables are not defined yet
+# (i.e. libevent is used via add_subdirectory())
+if (NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY)
+    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
+endif()
+if (NOT DEFINED CMAKE_LIBRARY_OUTPUT_DIRECTORY)
+    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
+endif()
+if (NOT DEFINED CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
+    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
+endif()
+
+if (EVENT__ENABLE_VERBOSE_DEBUG)
+    add_definitions(-DUSE_DEBUG=1)
+endif()
+
+# make it colorful under ninja-build
+if ("${CMAKE_GENERATOR}" STREQUAL "Ninja")
+    add_compiler_flags(-fdiagnostics-color=always)
+endif()
+
+# Setup compiler flags for coverage.
+if (EVENT__COVERAGE)
+    if (NOT "${CMAKE_BUILD_TYPE_LOWER}" STREQUAL "debug")
+        message(FATAL_ERROR "Coverage requires -DCMAKE_BUILD_TYPE=Debug")
+    endif()
+
+    message(STATUS "Setting coverage compiler flags")
+
+    set(CMAKE_REQUIRED_LIBRARIES "--coverage")
+    add_compiler_flags(-g -O0 --coverage)
+    set(CMAKE_REQUIRED_LIBRARIES "")
+endif()
+
+set(GNUC 0)
+set(CLANG 0)
+set(MSVC 0)
+if (("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") OR
+    ("${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang"))
+    set(CLANG 1)
+endif()
+if (("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") OR (${CLANG}))
+    set(GNUC 1)
+endif()
+if (("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") OR (${CLANG}))
+    set(MSVC 1)
+endif()
+
+# Detect library type
+set(EVENT_LIBRARY_TYPE)
+if ("${EVENT__LIBRARY_TYPE}" STREQUAL "DEFAULT")
+    if (${MSVC})
+        set(EVENT_LIBRARY_TYPE SHARED)
+    else()
+        set(EVENT_LIBRARY_TYPE BOTH)
+    endif()
+else()
+    string(TOUPPER "${EVENT__LIBRARY_TYPE}" EVENT_LIBRARY_TYPE)
+endif()
+if ((${MSVC}) AND ("${EVENT_LIBRARY_TYPE}" STREQUAL "BOTH"))
+    message(WARNING
+      "Building SHARED and STATIC is not supported for MSVC "
+      "(due to conflicts in library name"
+      " between STATIC library and IMPORTED library for SHARED libraries)")
+endif()
+set(EVENT_LIBRARY_STATIC OFF)
+set(EVENT_LIBRARY_SHARED OFF)
+if ("${EVENT_LIBRARY_TYPE}" STREQUAL "BOTH")
+    set(EVENT_LIBRARY_STATIC ON)
+    set(EVENT_LIBRARY_SHARED ON)
+elseif ("${EVENT_LIBRARY_TYPE}" STREQUAL "STATIC")
+    set(EVENT_LIBRARY_STATIC ON)
+elseif ("${EVENT_LIBRARY_TYPE}" STREQUAL "SHARED")
+    set(EVENT_LIBRARY_SHARED ON)
+else()
+    message(FATAL_ERROR "${EVENT_LIBRARY_TYPE} is not supported")
+endif()
+
+if (${MSVC})
+    set(msvc_static_runtime OFF)
+    if ("${EVENT_LIBRARY_TYPE}" STREQUAL "STATIC")
+        set(msvc_static_runtime ON)
+    endif()
+
+    # For more info:
+    # - https://docs.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library?view=vs-2017
+    # - https://gitlab.kitware.com/cmake/community/wikis/FAQ#how-can-i-build-my-msvc-application-with-a-static-runtime
+    option(EVENT__MSVC_STATIC_RUNTIME
+           "Link static runtime libraries"
+           ${msvc_static_runtime})
+
+    if (EVENT__MSVC_STATIC_RUNTIME)
+        foreach (flag_var
+                 CMAKE_C_FLAGS_DEBUG
+                 CMAKE_C_FLAGS_RELEASE
+                 CMAKE_C_FLAGS_MINSIZEREL
+                 CMAKE_C_FLAGS_RELWITHDEBINFO
+        )
+            if (${flag_var} MATCHES "/MD")
+                string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+            endif()
+        endforeach()
+    endif()
+endif()
+
+# GNUC specific options.
+if (${GNUC})
+    option(EVENT__DISABLE_GCC_WARNINGS "Disable verbose warnings with GCC" OFF)
+    option(EVENT__ENABLE_GCC_HARDENING "Enable compiler security checks" OFF)
+    option(EVENT__ENABLE_GCC_FUNCTION_SECTIONS "Enable gcc function sections" OFF)
+    option(EVENT__ENABLE_GCC_WARNINGS "Make all GCC warnings into errors" OFF)
+
+    set(GCC_V ${CMAKE_C_COMPILER_VERSION})
+
+    list(APPEND __FLAGS
+         -Wall -Wextra -Wno-unused-parameter -Wstrict-aliasing -Wstrict-prototypes
+
+         -fno-strict-aliasing # gcc 2.9.5+
+         -Wmissing-prototypes
+
+         # gcc 4
+         -Winit-self
+         -Wmissing-field-initializers
+         -Wdeclaration-after-statement
+
+         # gcc 4.2
+         -Waddress
+         -Wnormalized=id
+         -Woverride-init
+
+         # gcc 4.5
+         -Wlogical-op
+
+         -Wwrite-strings
+    )
+
+    if (${CLANG})
+        list(APPEND __FLAGS -Wno-unused-function)
+    endif()
+
+    if (EVENT__DISABLE_GCC_WARNINGS)
+        list(APPEND __FLAGS -w)
+    endif()
+
+    if (EVENT__ENABLE_GCC_HARDENING)
+        list(APPEND __FLAGS
+             -fstack-protector-all
+             -fwrapv
+             -fPIE
+             -Wstack-protector
+             "--param ssp-buffer-size=1")
+
+        add_definitions(-D_FORTIFY_SOURCE=2)
+    endif()
+
+    if (EVENT__ENABLE_GCC_FUNCTION_SECTIONS)
+        list(APPEND __FLAGS -ffunction-sections)
+        # TODO: Add --gc-sections support. We need some checks for NetBSD to ensure this works.
+    endif()
+
+    if (EVENT__ENABLE_GCC_WARNINGS)
+        list(APPEND __FLAGS -Werror)
+    endif()
+
+    add_compiler_flags(${__FLAGS})
+endif()
+
+if (APPLE)
+    # Get rid of deprecated warnings for OpenSSL on OSX 10.7 and greater.
+    add_compiler_flags(
+        -Wno-error=deprecated-declarations
+        -Qunused-arguments
+    )
+endif()
+
+if (MINGW OR CYGWIN)
+    set(WIN32 TRUE)
+endif()
+
+# Winsock.
+if(WIN32)
+    set(CMAKE_REQUIRED_LIBRARIES  ws2_32 shell32 advapi32)
+    set(CMAKE_REQUIRED_DEFINITIONS -FIwinsock2.h -FIws2tcpip.h -D_WIN32_WINNT=0x0600)
+endif()
+if (SOLARIS)
+    set(CMAKE_REQUIRED_LIBRARIES socket nsl)
+endif()
+
+# Check if _GNU_SOURCE is available.
+if (NOT DEFINED _GNU_SOURCE)
+  CHECK_SYMBOL_EXISTS(__GNU_LIBRARY__ "features.h" _GNU_SOURCE)
+
+  if (NOT _GNU_SOURCE)
+    unset(_GNU_SOURCE CACHE)
+    CHECK_SYMBOL_EXISTS(_GNU_SOURCE "features.h" _GNU_SOURCE)
+  endif()
+
+  if (ANDROID)
+    set(_GNU_SOURCE TRUE)
+  endif()
+endif()
+
+if (_GNU_SOURCE)
+    add_definitions(-D_GNU_SOURCE=1)
+    set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
+endif()
+
+# Check if header files exist
+list(APPEND FILES_TO_CHECK
+    fcntl.h
+    inttypes.h
+    memory.h
+    signal.h
+    stdarg.h
+    stddef.h
+    stdint.h
+    stdlib.h
+    string.h
+    errno.h
+    unistd.h
+    time.h
+    sys/types.h
+    sys/stat.h
+    sys/time.h
+    sys/param.h
+)
+if (WIN32)
+    list(APPEND FILES_TO_CHECK
+        io.h
+        winsock2.h
+        ws2tcpip.h
+        afunix.h
+    )
+else()
+    list(APPEND FILES_TO_CHECK
+        netdb.h
+        dlfcn.h
+        arpa/inet.h
+        poll.h
+        port.h
+        sys/socket.h
+        sys/random.h
+        sys/un.h
+        sys/devpoll.h
+        sys/epoll.h
+        sys/eventfd.h
+        sys/event.h
+        sys/ioctl.h
+        sys/mman.h
+        sys/queue.h
+        sys/select.h
+        sys/sendfile.h
+        sys/uio.h
+        sys/wait.h
+        sys/resource.h
+        sys/timerfd.h
+        netinet/in.h
+        netinet/in6.h
+        netinet/tcp.h
+        ifaddrs.h
+    )
+endif()
+
+if (NOT "${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Linux")
+    list(APPEND FILES_TO_CHECK sys/sysctl.h)
+endif()
+
+if (APPLE)
+    list(APPEND FILES_TO_CHECK
+        mach/mach_time.h
+        mach/mach.h
+    )
+endif()
+
+foreach(FILE ${FILES_TO_CHECK})
+    CHECK_INCLUDE_FILE_CONCAT(${FILE} "EVENT")
+endforeach()
+unset(FILES_TO_CHECK)
+
+# Check if functions exist
+list(APPEND SYMBOLS_TO_CHECK
+    getaddrinfo
+    getnameinfo
+    getprotobynumber
+    getservbyname
+    gethostbyname
+    inet_ntop
+    inet_pton
+    gettimeofday
+    signal
+    strtoll
+    splice
+    strlcpy
+    strsep
+    strtok_r
+    vasprintf
+    timerclear
+    timercmp
+    timerisset
+    timeradd
+    nanosleep
+    putenv
+    umask
+)
+if (NOT EVENT__DISABLE_CLOCK_GETTIME)
+    list(APPEND SYMBOLS_TO_CHECK clock_gettime)
+endif()
+
+if (WIN32)
+    list(APPEND SYMBOLS_TO_CHECK
+        _gmtime64_s
+        _gmtime64
+    )
+else()
+    list(APPEND SYMBOLS_TO_CHECK
+        getifaddrs
+        select
+        epoll_create
+        epoll_create1
+        epoll_ctl
+        eventfd
+        poll
+        port_create
+        kqueue
+        fcntl
+        mmap
+        pipe
+        pipe2
+        sendfile
+        sigaction
+        strsignal
+        sysctl
+        accept4
+        arc4random
+        arc4random_buf
+        arc4random_addrandom
+        getrandom
+        getegid
+        geteuid
+        issetugid
+        usleep
+        timerfd_create
+        setenv
+        unsetenv
+        setrlimit
+        gethostbyname_r
+    )
+    if (APPLE)
+        list(APPEND SYMBOLS_TO_CHECK mach_absolute_time)
+    endif()
+endif()
+
+# Add stdio.h for vasprintf
+set(EVENT_INCLUDES ${EVENT_INCLUDES} stdio.h)
+CHECK_SYMBOLS_EXIST("${SYMBOLS_TO_CHECK}" "${EVENT_INCLUDES}" "EVENT")
+unset(SYMBOLS_TO_CHECK)
+set(EVENT__HAVE_EPOLL ${EVENT__HAVE_EPOLL_CREATE})
+
+# Get the gethostbyname_r prototype.
+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()
+
+# Only `CHECK_TYPE_SIZE()' will use `CMAKE_EXTRA_INCLUDE_FILES'
+set(CMAKE_EXTRA_INCLUDE_FILES ${EVENT_INCLUDES})
+
+CHECK_TYPE_SIZE("struct sockaddr_un" EVENT__HAVE_STRUCT_SOCKADDR_UN)
+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.
+check_function_keywords("inline" "__inline" "__inline__")
+
+if (HAVE_INLINE)
+    set(EVENT__inline inline)
+elseif (HAVE___INLINE)
+    set(EVENT__inline __inline)
+elseif(HAVE___INLINE__)
+    set(EVENT__inline __inline__)
+else()
+    set(EVENT__inline)
+endif()
+
+# __func__/__FUNCTION__ is not a macros in general
+CHECK_SYMBOL_EXISTS("__func__"     "" EVENT__HAVE___func__)
+CHECK_SYMBOL_EXISTS("__FUNCTION__" "" EVENT__HAVE___FUNCTION__)
+
+CHECK_SYMBOL_EXISTS(TAILQ_FOREACH sys/queue.h EVENT__HAVE_TAILQFOREACH)
+CHECK_CONST_EXISTS(CTL_KERN sys/sysctl.h EVENT__HAVE_DECL_CTL_KERN)
+CHECK_CONST_EXISTS(KERN_ARND sys/sysctl.h EVENT__HAVE_DECL_KERN_ARND)
+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})
+else()
+    set(EVENT__size_t size_t)
+endif()
+
+CHECK_TYPE_SIZE("off_t" EVENT__SIZEOF_OFF_T LANGUAGE C)
+
+
+# XXX we should functionalize these size and type sets. --elley
+
+# Winssck.
+if (_MSC_VER)
+    list(APPEND CMAKE_EXTRA_INCLUDE_FILES BaseTsd.h)
+endif()
+CHECK_TYPE_SIZE("ssize_t" EVENT__SIZEOF_SSIZE_T_LOWER LANGUAGE C)
+CHECK_TYPE_SIZE("SSIZE_T" EVENT__SIZEOF_SSIZE_T_UPPER LANGUAGE C)
+
+if (EVENT__SIZEOF_SSIZE_T_LOWER)
+    set(EVENT__ssize_t "ssize_t")
+    set(EVENT__SIZEOF_SSIZE_T ${EVENT__SIZEOF_SSIZE_T_LOWER})
+elseif (EVENT__SIZEOF_SSIZE_T_UPPER)
+    set(EVENT__ssize_t "SSIZE_T")
+    set(EVENT__SIZEOF_SSIZE_T ${EVENT__SIZEOF_SSIZE_T_UPPER})
+else()
+    set(EVENT__ssize_t "int")
+    set(EVENT__SIZEOF_SSIZE_T ${EVENT__SIZEOF_INT})
+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})
+else()
+    set(EVENT__socklen_t "socklen_t")
+endif()
+
+CHECK_TYPE_SIZE(pid_t EVENT__SIZEOF_PID_T)
+if(NOT EVENT__SIZEOF_PID_T)
+  set(EVENT__SIZEOF_PID_T ${EVENT__SIZEOF_INT})
+else()
+       set(EVENT__SIZEOF_PID_T EVENT__SIZEOF_PID_T)
+endif()
+
+if (NOT EVENT__DISABLE_THREAD_SUPPORT)
+    if (NOT WIN32)
+        list(APPEND CMAKE_EXTRA_INCLUDE_FILES pthread.h)
+    endif()
+    CHECK_TYPE_SIZE(pthread_t EVENT__SIZEOF_PTHREAD_T)
+endif()
+
+if(EVENT__HAVE_CLOCK_GETTIME)
+  set(EVENT__DNS_USE_CPU_CLOCK_FOR_ID 1)
+endif()
+
+# we're just getting lazy now.
+CHECK_TYPE_SIZE("uintptr_t" EVENT__HAVE_UINTPTR_T)
+CHECK_TYPE_SIZE("void *" EVENT__SIZEOF_VOID_P)
+CHECK_TYPE_SIZE("time_t" EVENT__SIZEOF_TIME_T)
+
+# Tests file offset bits.
+# TODO: Add AIX test for if -D_LARGE_FILES is needed.
+
+# XXX: Why is this here? we don't even use it. Well, we don't even use it
+#      on top of that, why is it set in the config.h?! IT_MAKES_NO_SENSE
+#      I'm commenting it out for now.
+#      - ellzey
+
+#CHECK_FILE_OFFSET_BITS()
+
+# Verify kqueue works with pipes.
+if (EVENT__HAVE_KQUEUE)
+    if ((CMAKE_CROSSCOMPILING OR APPLE) 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(STATUS "Checking if kqueue works with pipes...")
+        include(CheckWorkingKqueue)
+    endif()
+endif()
+
+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()
+
+CHECK_TYPE_SIZE("struct linger" EVENT__HAVE_STRUCT_LINGER)
+
+# 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.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(STATUS "OpenSSL include: ${OPENSSL_INCLUDE_DIR}")
+    message(STATUS "OpenSSL lib: ${OPENSSL_LIBRARIES}")
+
+    include_directories(${OPENSSL_INCLUDE_DIR})
+
+    list(APPEND SRC_OPENSSL 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 disable")
+        endif()
+
+        set(EVENT__HAVE_PTHREADS 1)
+        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 AND ZLIB_INCLUDE_DIR)
+        include_directories(${ZLIB_INCLUDE_DIRS})
+
+        set(EVENT__HAVE_LIBZ 1)
+        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
+        win32select.c)
+
+    list(APPEND HDR_PRIVATE WIN32-Code/getopt.h)
+
+    set(EVENT__DNS_USE_FTIME_FOR_ID 1)
+    set(LIB_PLATFORM ws2_32 shell32 advapi32)
+    add_definitions(
+            -D_CRT_SECURE_NO_WARNINGS
+            -D_CRT_NONSTDC_NO_DEPRECATE)
+
+    include_directories(./WIN32-Code)
+endif()
+
+if (SOLARIS)
+    list(APPEND LIB_PLATFORM socket nsl)
+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 (${GNUC})
+    set(EVENT_SHARED_FLAGS -fvisibility=hidden)
+elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "SunPro")
+    set(EVENT_SHARED_FLAGS -xldscope=hidden)
+endif()
+
+configure_file(
+    ${CMAKE_CURRENT_SOURCE_DIR}/event-config.h.cmake
+    ${CMAKE_CURRENT_BINARY_DIR}/include/event2/event-config.h
+        NEWLINE_STYLE UNIX)
+
+configure_file(
+    ${CMAKE_CURRENT_SOURCE_DIR}/evconfig-private.h.cmake
+    ${CMAKE_CURRENT_BINARY_DIR}/include/evconfig-private.h)
+
+#
+# Create the libraries.
+#
+include(AddEventLibrary)
+add_event_library(event_core SOURCES ${SRC_CORE})
+add_event_library(event_extra
+    INNER_LIBRARIES event_core
+    SOURCES ${SRC_EXTRA})
+
+if (NOT EVENT__DISABLE_OPENSSL)
+    add_event_library(event_openssl
+        INNER_LIBRARIES event_core
+        OUTER_INCLUDES ${OPENSSL_INCLUDE_DIR}
+        LIBRARIES ${OPENSSL_LIBRARIES}
+        SOURCES ${SRC_OPENSSL})
+endif()
+
+if (EVENT__HAVE_PTHREADS)
+    set(SRC_PTHREADS evthread_pthread.c)
+    add_event_library(event_pthreads
+        INNER_LIBRARIES event_core
+        SOURCES ${SRC_PTHREADS})
+endif()
+
+# 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_event_library(event SOURCES ${SRC_CORE} ${SRC_EXTRA})
+
+set(WIN32_GETOPT)
+if (WIN32)
+    set(_TMPLIBS)
+    if (${EVENT_LIBRARY_STATIC})
+        list(APPEND _TMPLIBS event_core_static event_static)
+    endif()
+    if (${EVENT_LIBRARY_SHARED})
+        list(APPEND _TMPLIBS event_core_shared event_shared)
+    endif()
+    foreach(lib ${_TMPLIBS})
+        target_link_libraries(${lib} iphlpapi)
+    endforeach()
+    unset(_TMPLIBS)
+
+    list(APPEND WIN32_GETOPT
+         WIN32-Code/getopt.c
+         WIN32-Code/getopt_long.c)
+endif()
+
+#
+# Samples.
+#
+macro(add_sample_prog ssl name)
+    add_executable(${name} ${ARGN})
+
+    target_link_libraries(${name}
+                          event_extra
+                          event_core
+                          ${LIB_APPS}
+                          ${LIB_PLATFORM})
+
+    if (${ssl})
+        target_link_libraries(${name} event_openssl)
+        if(WIN32)
+            target_link_libraries(${name} crypt32)
+        endif()
+    endif()
+endmacro()
+if (NOT EVENT__DISABLE_SAMPLES)
+    set(SAMPLES
+        event-read-fifo
+        hello-world
+        signal-test
+        http-connect
+        time-test)
+
+    foreach(SAMPLE ${SAMPLES})
+        add_sample_prog(OFF ${SAMPLE} sample/${SAMPLE}.c)
+    endforeach()
+
+    if (NOT EVENT__DISABLE_OPENSSL)
+        add_sample_prog(ON https-client
+                        sample/https-client.c
+                        sample/openssl_hostname_validation.c
+                        sample/hostcheck.c)
+        add_sample_prog(ON le-proxy
+                        sample/le-proxy.c)
+    endif()
+
+    set(SAMPLES_WOPT
+        dns-example
+        http-server
+    )
+    foreach (SAMPLE ${SAMPLES_WOPT})
+        add_sample_prog(OFF ${SAMPLE} sample/${SAMPLE}.c ${WIN32_GETOPT})
+    endforeach()
+endif()
+
+#
+# Benchmarks
+#
+macro(add_bench_prog prog)
+    add_executable(${prog} ${ARGN})
+    target_link_libraries(${prog}
+                          event_extra
+                          event_core
+                          ${LIB_APPS}
+                          ${LIB_PLATFORM})
+endmacro()
+if (NOT EVENT__DISABLE_BENCHMARK)
+    foreach (BENCHMARK bench_http bench_httpclient)
+        add_bench_prog(${BENCHMARK} test/${BENCHMARK}.c)
+    endforeach()
+
+    add_bench_prog(bench test/bench.c ${WIN32_GETOPT})
+    add_bench_prog(bench_cascade test/bench_cascade.c ${WIN32_GETOPT})
+endif()
+
+#
+# Tests
+#
+macro(add_test_prog prog)
+    add_executable(${prog} test/${prog}.c)
+    target_link_libraries(${prog}
+                          ${LIB_APPS}
+                          ${LIB_PLATFORM}
+                          event_core
+                          event_extra
+                          ${ARGN})
+endmacro()
+if (NOT EVENT__DISABLE_TESTS)
+    #
+    # Generate Regress tests.
+    #
+    if (NOT EVENT__DISABLE_REGRESS)
+        # (We require python to generate the regress tests)
+        find_package(PythonInterp 3)
+
+        if (PYTHONINTERP_FOUND)
+            set(__FOUND_USABLE_PYTHON 1)
+        else()
+            find_package(PythonInterp 2)
+            if (PYTHONINTERP_FOUND)
+                set(__FOUND_USABLE_PYTHON 1)
+            else()
+                message(ERROR "No suitable Python version found, bailing...")
+            endif()
+        endif()
+
+        if (__FOUND_USABLE_PYTHON)
+            message(STATUS "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 --quiet 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)
+
+            if (WIN32)
+                list(APPEND SRC_REGRESS test/regress_iocp.c)
+                if (NOT EVENT__DISABLE_THREAD_SUPPORT)
+                    list(APPEND SRC_REGRESS test/regress_thread.c)
+                endif()
+            elseif (EVENT__HAVE_PTHREADS)
+                list(APPEND SRC_REGRESS test/regress_thread.c)
+            endif()
+
+            if (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
+                list(APPEND SRC_REGRESS test/regress_zlib.c)
+            endif()
+
+            if (NOT EVENT__DISABLE_OPENSSL)
+                list(APPEND SRC_REGRESS test/regress_ssl.c)
+            endif()
+
+            add_executable(regress ${SRC_REGRESS})
+
+            target_link_libraries(regress
+                                  ${LIB_APPS}
+                                  ${LIB_PLATFORM}
+                                  event_core
+                                  event_extra)
+            if (NOT EVENT__DISABLE_OPENSSL)
+                target_link_libraries(regress event_openssl)
+            endif()
+            if (CMAKE_USE_PTHREADS_INIT)
+                target_link_libraries(regress event_pthreads)
+            endif()
+        else()
+            message(WARNING "No suitable Python interpreter found, cannot generate regress tests!")
+        endif()
+    endif()
+
+    #
+    # Test programs.
+    #
+    # all of these, including the cmakelists.txt should be moved
+    # into the dirctory 'tests' first.
+    #
+    # doing this, we can remove all the DISABLE_TESTS stuff, and simply
+    # do something like:
+    #
+    # add_custom_targets(tests)
+    # add_executable(... EXCLUDE_FROM_ALL ...c)
+    # add_dependencis(tests testa testb testc)
+    # add_test(....)
+    #
+    # then you can just run 'make tests' instead of them all
+    # auto-compile|running
+    # - ellzey
+    set(TESTPROGS test-changelist
+                  test-eof
+                  test-closed
+                  test-fdleak
+                  test-init
+                  test-time
+                  test-weof)
+
+    foreach (TESTPROG ${TESTPROGS} test-dumpevents)
+        add_test_prog(${TESTPROG})
+    endforeach()
+    if (UNIX)
+        add_test_prog(test-ratelim m)
+    else()
+        add_test_prog(test-ratelim)
+    endif()
+
+    set(ALL_TESTPROGS
+        ${TESTPROGS}
+        test-dumpevents
+        test-ratelim
+    )
+
+    #
+    # 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()
+
+
+    # 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)
+    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 --quiet)
+
+            set_tests_properties(${TEST_NAME}
+                                 PROPERTIES ENVIRONMENT "${ENV_VARS}")
+
+            add_test(${TEST_NAME}_debug
+                     ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/regress --quiet)
+
+            set_tests_properties(${TEST_NAME}_debug
+                                 PROPERTIES ENVIRONMENT "${ENV_VARS};EVENT_DEBUG_MODE=1")
+        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.
+    set(RL_BIN ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-ratelim)
+
+    add_test(test-ratelim__group_lim
+             ${RL_BIN}
+             -g 30000
+             -n 30
+             -t 100
+             --check-grouplimit 1000
+             --check-stddev 100)
+
+    # Connection limit, no group limit.
+    add_test(test-ratelim__con_lim
+             ${RL_BIN}
+             -c 1000
+             -n 30
+             -t 100
+             --check-connlimit 50
+             --check-stddev 50)
+
+    # Connection limit and group limit.
+    add_test(test-ratelim__group_con_lim
+             ${RL_BIN}
+             -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
+             ${RL_BIN}
+             -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(STATUS "${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.
+#
+
+set(EVENT_INSTALL_CMAKE_DIR
+    "${CMAKE_INSTALL_PREFIX}/lib/cmake/libevent")
+
+export(PACKAGE libevent)
+
+function(gen_package_config forinstall)
+    if(${forinstall})
+        set(CONFIG_FOR_INSTALL_TREE 1)
+        set(dir "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}")
+    else()
+        set(CONFIG_FOR_INSTALL_TREE 0)
+        set(dir "${PROJECT_BINARY_DIR}")
+    endif()
+    configure_file(${PROJECT_SOURCE_DIR}/cmake/LibeventConfig.cmake.in
+                "${dir}/LibeventConfig.cmake"
+                @ONLY)
+endfunction()
+
+# 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")
+
+gen_package_config(0)
+
+# Generate the config file for the installation tree.
+gen_package_config(1)
+
+# 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)
+
+# Install compat headers
+install(FILES ${HDR_COMPAT}
+        DESTINATION "include"
+        COMPONENT dev)
+
+# Install public headers
+install(FILES ${HDR_PUBLIC}
+        DESTINATION "include/event2"
+        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.
+macro(install_export type)
+    install(EXPORT LibeventTargets-${type}
+        NAMESPACE ${PROJECT_NAME}::
+        DESTINATION "${EVENT_INSTALL_CMAKE_DIR}"
+        COMPONENT dev)
+endmacro()
+
+if (${EVENT_LIBRARY_STATIC})
+    install_export(static)
+endif()
+if (${EVENT_LIBRARY_SHARED})
+    install_export(shared)
+endif()
+
+# Install the scripts.
+install(PROGRAMS
+       ${CMAKE_CURRENT_SOURCE_DIR}/event_rpcgen.py
+       DESTINATION "bin"
+       COMPONENT runtime)
+
+# Create documents with doxygen.
+option(EVENT__DOXYGEN
+    "Enables doxygen documentation" OFF)
+if (EVENT__DOXYGEN)
+    include(UseDoxygen)
+    UseDoxygen()
+endif()
+
+
+if (NOT TARGET uninstall)
+       # Create the uninstall target.
+       # https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake
+       configure_file(${PROJECT_SOURCE_DIR}/cmake/Uninstall.cmake.in
+                                  ${PROJECT_BINARY_DIR}/Uninstall.cmake
+                                  @ONLY)
+
+       add_custom_target(uninstall
+                                         COMMAND ${CMAKE_COMMAND} -P ${PROJECT_BINARY_DIR}/Uninstall.cmake)
+endif()
+
+message(STATUS "")
+message(STATUS "        ---( Libevent " ${EVENT_VERSION} " )---")
+message(STATUS "")
+message(STATUS "Available event backends: ${BACKENDS}")
+message(STATUS "CMAKE_BINARY_DIR:         ${CMAKE_BINARY_DIR}")
+message(STATUS "CMAKE_CURRENT_BINARY_DIR: ${CMAKE_CURRENT_BINARY_DIR}")
+message(STATUS "CMAKE_SOURCE_DIR:         ${CMAKE_SOURCE_DIR}")
+message(STATUS "CMAKE_CURRENT_SOURCE_DIR: ${CMAKE_CURRENT_SOURCE_DIR}")
+message(STATUS "PROJECT_BINARY_DIR:       ${PROJECT_BINARY_DIR}")
+message(STATUS "PROJECT_SOURCE_DIR:       ${PROJECT_SOURCE_DIR}")
+message(STATUS "CMAKE_MODULE_PATH:        ${CMAKE_MODULE_PATH}")
+message(STATUS "CMAKE_COMMAND:            ${CMAKE_COMMAND}")
+message(STATUS "CMAKE_ROOT:               ${CMAKE_ROOT}")
+message(STATUS "CMAKE_SYSTEM:             ${CMAKE_SYSTEM}")
+message(STATUS "CMAKE_SYSTEM_NAME:        ${CMAKE_SYSTEM_NAME}")
+message(STATUS "CMAKE_SYSTEM_VERSION:     ${CMAKE_SYSTEM_VERSION}")
+message(STATUS "CMAKE_SYSTEM_PROCESSOR:   ${CMAKE_SYSTEM_PROCESSOR}")
+message(STATUS "CMAKE_SKIP_RPATH:         ${CMAKE_SKIP_RPATH}")
+message(STATUS "CMAKE_VERBOSE_MAKEFILE:   ${CMAKE_VERBOSE_MAKEFILE}")
+message(STATUS "CMAKE_C_FLAGS:            ${CMAKE_C_FLAGS}")
+message(STATUS "CMAKE_BUILD_TYPE:         ${CMAKE_BUILD_TYPE}")
+message(STATUS "CMAKE_C_COMPILER:         ${CMAKE_C_COMPILER} (id ${CMAKE_C_COMPILER_ID}, clang ${CLANG}, GNUC ${GNUC})")
+message(STATUS "CMAKE_AR:                 ${CMAKE_AR}")
+message(STATUS "CMAKE_RANLIB:             ${CMAKE_RANLIB}")
+message(STATUS "")
+
index 1499637504963a99a76fb9e2130c59dcaab2f349..17874b14b92ba3094a4673c5ac09a0e390286dcb 100644 (file)
@@ -1,3 +1,763 @@
+Changes in version 2.1.12-stable (05 Jul 2020)
+
+ This release contains mostly bug fixes (I decided not to port some features
+ that can be ported even without ABI breakage, if you cannot find feature that
+ you are interested in, please give us a note!)
+
+ Since 2.1.12 libevent will use github actions as main CI, since
+ it recommends itself better then travis/appveyor (and had been removed from
+ upstream).
+
+ Look carefully at "slightly touches the behaviour" section.
+
+ Below you will find some of changes (this list has been cleaned up from the
+ patches that touches only tests and similar):
+
+ CI:
+  o Backport github actions to 2.1 (be3acd7c Azat Khuzhin)
+  o Merge branch 'event_rpcgen.py-cleanup' (f0ded5f3, 48e04887 Enji Cooper)
+  o Add API/ABI checker (using LVC) (709210d4, 2af1f6cc yuangongji)
+
+ test:
+  o tinytest: support timeout on Windows (794e8f75 yuangongji)
+  o Merge branch 'osx-clock' (e85afbe3 Azat Khuzhin)
+  o test-ratelim: calculate timers bias (for slow CPUs) to avoid false-positive (8ad26d0b Azat Khuzhin)
+
+ fixes:
+  o buffer: do not pass NULL to memcpy() from evbuffer_pullup() (5b063049 Azat Khuzhin)
+  o http: fix undefined-shift in EVUTIL_IS*_ helpers (6b8d02a7 Azat Khuzhin)
+  o Check error code of evhttp_add_header_internal() in evhttp_parse_query_impl() (97e28f09 Azat Khuzhin)
+  o http: fix EVHTTP_CON_AUTOFREE in case of timeout (and some else) (1be25938 Azat Khuzhin)
+  o evdns: Add additional validation for values of dns options (c2972453 ayuseleznev)
+  o There is typo in GetAdaptersAddresses windows library. It should be iphlpapi.dll (891adda9 Aleksandr-Melnikov)
+  o Merge branch 'EV_CLOSED-and-EV_ET-fixes' (db2efdf5 Azat Khuzhin)
+  o Fix memory corruption in EV_CLOSURE_EVENT_FINALIZE with debug enabled (8ccd8f56 Jan Kasiak)
+  o increase segment refcnt only if evbuffer_add_file_segment() succeeds (30662a3c yuangongji)
+  o evdns: fix a crash when evdns_base with waiting requests is freed (6f8e0e97 ayuseleznev)
+  o event_base_once: fix potential null pointer threat (2e9ceb16 chenguolong)
+  o http: do not assume body for CONNECT (1b42270b Azat Khuzhin)
+  o evbuffer_add_file: fix freeing of segment in the error path (5f017bde Azat Khuzhin)
+  o Fix checking return value of the evdns_base_resolv_conf_parse() (fc51bf2c Azat Khuzhin)
+  o Merge branch 'fix-signal-leak' (poll/select now needs reinit) (1c9cc07b Azat Khuzhin)
+
+ improvements:
+  o evutil_time: improve evutil_gettimeofday on Windows (a8219143 Nick Grifka)
+  o Support EV_CLOSED on linux for poll(2) (2530e7c6 Azat Khuzhin)
+  o Parse IPv6 scope IDs. (f602211f Philip Homburg)
+  o evutil_time: Implements usleep() using wait funtion on Windows (d42240d1 yuangongji)
+  o evutil_time: detect and use _gmtime64_s()/_gmtime64() (f4a6152c yuangongji)
+
+ slightly touches the behaviour:
+  o bufferevent: allow setting priority on socket and openssl type (4dd3acdd Nicolas J. Bouliane)
+  o Fix EV_CLOSED detection/reporting (epoll only) (1df324d4 Azat Khuzhin) (XXX)
+  o Revert "Warn if forked from the event loop during event_reinit()" (71f5c0d3 Azat Khuzhin)
+
+ samples:
+  o https-client: load certificates from the system cert store on Windows (e9478640 yuangongji)
+
+ build fixes:
+  o Do not use sysctl.h on linux (it had been deprecated) (d2871a37 Azat Khuzhin)
+  o cmake: avoid problems from use of CMAKE_USE_PTHREADS_INIT (a62ec765 Paul Osborne)
+  o Update list of cmake files for autotools dist archive (2016f017 Azat Khuzhin)
+  o LibeventConfig.cmake: restore CMAKE_FIND_LIBRARY_SUFFIXES and LIBEVENT_STATIC_LINK default (640f9cf6 Mario Emmenlauer)
+  o cmake: fix getaddrinfo checking error (dea51c2e yuangongji)
+  o autoconf: fix getaddrinfo checking errors on mingw (b9bf7fa7 yuangongji)
+  o Do not use shared global structures on CYGWIN (8a9b5655 Azat Khuzhin)
+  o Added uninstall target check to cmakelists (3f1fb1f9 Dimo Markov)
+  o Fix compilation without OPENSSL_API_COMPAT (921bdcdd Azat Khuzhin)
+  o cmake: improve package config file (1c047618, baec84f2 yuangongji)
+  o Link with iphlpapi only on windows (976f7d34 Azat Khuzhin)
+  o autotools: fails build when need but can not find openssl (93174bb5 yuangongji)
+  o Merge branch 'http-connect' (e2424229 Azat Khuzhin)
+  o Fix compat with NetBSD >= 10 (5febb4e1 Kamil Rytarowski)
+  o cmake: fix getrandom() detection (e0e5f3bd Azat Khuzhin)
+  o arc4random: replace sysctl() with getrandom (on linux) (66ec78fd Azat Khuzhin)
+  o Upgrade autoconf (after upgrading minimum required to 2.67) (45da7d9d yuangongji)
+  o eliminate some C4267 warnings in Windows (9e468c77 yuangongji)
+  o autotools: attach doxygen target into all target (5d1e8570 yuangongji)
+  o cmake: attach doxygen target into all target (7a85300a yuangongji)
+  o Change the minimum version of automake to 1.13 and autoconf to 2.67 (fdb8fb66 ygj6)
+  o Add Uninstall.cmake.in into dist archive (877f2355 Azat Khuzhin)
+
+Changes in version 2.1.11-stable (01 Aug 2019)
+
+ This release contains one ABI breakage fix (that had been introduced in
+ 2.1.10, and strictly speaking this release breaks ABI again to make it
+ compatible with 2.1.9 and less, please take a look at 18104973 for more
+ details). Apart from that it contains some bug fixes, that grouped below.
+
+ And even though the return value for evbuffer_setcb() had been changed it
+ should ABI compatible (anyway that function is in -compat.h header).
+
+ There is also one patch that introduce new functionality, this is 546a366c,
+ to tune SO_RCVBUF/SO_SNDBUF in evdns, but one can count it as a bug-fix on
+ the application level, since before you cannot tune this settings and hence
+ you could stumble on problems.
+
+ ABI breakage:
+  o Protect min_heap_push_ against integer overflow. (8c899768 Tobias Stoeckmann)
+  o Revert "Protect min_heap_push_ against integer overflow." (18104973 Azat Khuzhin)
+
+ functionality:
+  o evdns: add new options -- so-rcvbuf/so-sndbuf (546a366c Azat Khuzhin)
+
+ build:
+  o Change autoconf version to 2.62 and automake version to 1.11.2 (2a333008 yuangongji)
+  o cmake: install shared library only if it was requested (596855f7 Azat Khuzhin)
+  o Missing <winerror.h> on win7/MinGW(MINGW32_NT-6.1)/MSYS (9559349c yuangongji)
+  o cmake: set library names to be the same as with autotools (305251b9 yuangongji)
+  o Enable _GNU_SOURCE for Android (f013fc7d Keith Smiley)
+  o Enable kqueue for APPLE targets (3aa68a82 Keith Smiley)
+  o autotools: do not install bufferevent_ssl.h under --disable-openssl (5349a07e Azat Khuzhin)
+  o cmake: link against shell32.lib/advapi32.lib (c9ce638c Azat Khuzhin)
+  o Add README.md into dist archive (3660a4cc Azat Khuzhin)
+  o cmake: add missing autotools targets (doxygen, uninstall, event_rpcgen.py) (2d65071c yuangongji)
+  o m4/libevent_openssl.m4: fix detection of openssl (d4056e59 Fabrice Fontaine)
+  o Fix detection of the __has_attribute() for apple clang [ci skip] (7fd7c5ef Azat Khuzhin)
+
+ lib:
+  o buffer: fix possible NULL dereference in evbuffer_setcb() on ENOMEM (598f247d Azat Khuzhin)
+  o Warn if forked from the event loop during event_reinit() (b75922ae Azat Khuzhin)
+  o evutil: set the have_checked_interfaces in evutil_check_interfaces()
+    (ef498aa2, a09265ac jeremyerb)
+
+ samples:
+  o https-client: correction error checking (a8a04565 wenyg)
+
+
+Changes in version 2.1.10-stable (26 May 2019)
+
+ This release contains mostly fixes (some evbuffer oddity, AF_UNIX handling in
+ http server, some UB fixes and others) but also some new functionality
+ (without ABI breakage as usual) and now dist archive can be used for building
+ on windows (getopt had been added into it).
+
+ Above you will find changelog for this particular release (but with some
+ trivial fixes pruned out from it - to make it a little bit more informative).
+
+ To view full changelog please use git:
+   git log --format='  o %s (%h %aN)' release-2.1.9-beta...release-2.1.10-stable
+
+ dist:
+  o Add getopt into dist archive (7042ff24 Azat Khuzhin)
+
+ functionality:
+  o evdns: add DNS_OPTION_NAMESERVERS_NO_DEFAULT/EVDNS_BASE_NAMESERVERS_NO_DEFAULT
+  (58e81106 Azat Khuzhin)
+  o Add support for EV_TIMEOUT to event_base_active_by_fd (3f893f0a John Ohl)
+
+ fixes:
+  o Merge branch 'evbuffer-fixes-806-v2' (2fea04b3 Azat Khuzhin)
+  o Merge branch 'issue-807-accept4-getnameinfo-AF_UNIX' (7c4da937, e2790a7f
+    Azat Khuzhin)
+  o kqueue: Avoid undefined behaviour. (e70e18e9 Tobias Stoeckmann)
+  o Prevent integer overflow in kq_build_changes_list. (43a55a23 Tobias Stoeckmann)
+  o evdns: fix lock/unlock mismatch in evdns_close_server_port() (54103883 zhuizhuhaomeng)
+  o Merge remote-tracking branch 'official/pr/804' -- Enforce limit of NSIG
+    signals (87fa93a8 Tobias Stoeckmann)
+  o Protect min_heap_push_ against integer overflow. (0b46bb8c Tobias Stoeckmann)
+  o le-proxy: initiate use of the Winsock DLL (2a1e1530 linxiaohui)
+  o Fix leaks in error path of the bufferevent_init_common_() (bb0f8fe7 Azat Khuzhin)
+  o buffer: make evbuffer_prepend() of zero-length array no-op (61fa7b7d Azat Khuzhin)
+  o Merge branch 'evbuffer-empty-chain-handling' (6a3dd717 Azat Khuzhin)
+  o Don't loose top error in SSL (3d1a7a1d Yury Korzhetsky)
+  o Remove needless check for arc4_seeded_ok (6602a97d Seong-Joong Kim)
+  o Merge pull request #769 from sungjungk/fix-return-handling (91084140 Nathan French)
+
+ build:
+  o Define `_GNU_SOURCE` properly/consistently per autoconf (00ba9fa2 Enji Cooper)
+  o signal: guard __cdecl definition with #ifdef (d89045a6 Azat Khuzhin)
+  o Link test/regress with event_core/event_extra over event (22380996 Azat Khuzhin)
+
+ tests:
+  o Use kill() over raise() for raising the signal (fixes osx 10.14 with
+    kqueue) (3db5296b, a45f6733 Azat Khuzhin)
+  o tinytest: implement per-test timeout (via alarm() under !win32 only)
+    (b64dbfb6, 75d7e1ff Azat Khuzhin)
+
+Changes in version 2.1.9-beta (10 February 2019)
+
+ This changelog will differs from other releases in the next few clauses:
+ - contains only highlighted changes (so now it will not contains a lot of
+   patches that fixes some stuff in regression tests, typos, leaks fixes in
+   samples and so forth)
+ - no authors (since merge commits breaks them anyway, but AUTHORS sections in
+   README will be kept up to date)
+ - group name trimmed from commit subjects trimmed
+ - it's been 2 years since the previoius release, so it is pretty huge
+
+ And I think that this is more useful, so from now on it will always has the
+ same look (until there will too many objections of course).
+
+ To view full changelog please use git:
+   git log --format='  o %s (%h %aN)' release-2.1.8-stable...release-2.1.9-beta
+
+
+ dist archive:
+  o Add cmake rules into dist archive (bf3a67cf)
+  o Add missing print-winsock-errors.c into dist archive (822d6462)
+  o Include openssl-compat.h into dist archive (08658136)
+
+ core:
+  o Merge branch 'check-O_NONBLOCK-in-debug' (a39898f3, a8155c62)
+  o Merge branch 'event-ET-#636-v2' (ca4b6404)
+  o Fix visibility issues under (mostly on win32)
+    (349081e1g, 802be13ag, a1f28e2f)
+  o Define __EXT_POSIX2 for QNX (a2176f2c)
+  o Cleanup __func__ detection (b3af7bdd)
+  o Add convenience macros for user-triggered events (06ec5de6)
+  o Notify event base if there are no more events, so it can exit without delay (d9d1c09e)
+  o Fix base unlocking in event_del() if event_base_set() runned in another thread (4f0f40e3)
+  o If precise_time is false, we should not set EVENT_BASE_FLAG_PRECISE_TIMER (27dee54d)
+  o Fix race in access to ev_res from event loop with event_active() (43d92a6d)
+  o Return from event_del() after the last event callback termination (876c7ac7)
+
+ http:
+  o Merge branch 'http-EVHTTP_CON_READ_ON_WRITE_ERROR-fixes-v2' (eb7b472b)
+  o Preserve socket error from listen across closesocket cleanup (2ccd00a6)
+  o fix connection retries when there more then one request for connection (d30e7bba)
+  o improve error path for bufferevent_{setfd,enable,disable}() (a8cc449e)
+  o Fix conceivable UAF of the bufferevent in evhttp_connection_free() (6ac2ec25)
+  o Merge branch 'http-request-line-parsing' (cdcfbafe)
+  o Fix evhttp_connection_get_addr() fox incomming http connections (4215c003)
+  o fix leaks in evhttp_uriencode() (123362e9)
+  o CONNECT method only takes an authority (7d1ffe64)
+  o Allow bodies for GET/DELETE/OPTIONS/CONNECT (23eb38b9)
+  o Do not crash when evhttp_send_reply_start() is called after a timeout. (826f1134)
+  o Fix crashing http server when callback do not reply in place (5b40744d, b2581380)
+  o fix handling of close_notify (ssl) in http with openssl bufferevents (7e91622b)
+
+ evrpc:
+  o use *_new_with_arg() to match function prototype (a95cc9e3)
+  o avoid NULL dereference on request is not EVHTTP_REQ_POST (e05136c7)
+
+ regression tests:
+  o Merge branch 'TT_RETRIABLE' (6ea1ec68, f9b592aa)
+
+ bufferevent:
+  o Merge branch 'iocp-fixes' (6bfac964)
+  o Merge branch 'be-wm-overrun-v2' (3f692fff)
+  o bufferevent_socket_connect{,_hostname}() missing event callback and use ret code (1dde74ef)
+  o don't fail be_null_filter if bytes are copied (b92b0792)
+  o Call underlying bev ctrl GET_FD on filtered bufferevents (ebfac517)
+
+ bufferevent_openssl/openssl:
+  o Merge branch 'ssl_bufferevent_wm_filter-fix' (30020a35)
+  o be_openssl: avoid leaking of SSL structure (e86ccfe5)
+  o Fix build with LibreSSL 2.7 (894ca48a)
+  o Add missing includes into openssl-compat.h (01bc36c1)
+  o Explicitly call SSL_clear when reseting the fd. (29b7a516)
+  o Unbreak build with LibreSSL after openssl 1.1 support added (230af9f0)
+
+ samples:
+  o Merge branch 'sample-http-server' (b6309bcc)
+  o sample/https-client: use host SSL certificate store by default (5c0132f3)
+
+ listener:
+  o ipv6only socket bind support (ba148796)
+  o Merge branch 'listener-immediate-close' (df2ed13f)
+  o Merge branch 'evconnlistener-do-not-close-client-fd' (42e851bb)
+
+ evdns:
+  o evdns: handle NULL filename explicitly (0033f5cc)
+  o Merge branch 'evdns_getaddrinfo-race-fix' (3237d697)
+  o Generating evdns_base_config_windows_nameservers docs on all platforms (3bd2ce43)
+
+ utils:
+  o Merge branch 'evutil_found_ifaddr-dev' (b07e43e6)
+  o Avoid possible SEGVs in select() (in unit tests) (8818c86c)
+  o Port `event_rpcgen.py` and `test/check-dumpevents.py` to Python 3. (532a8cc3)
+
+ buffer:
+  o Fix assert() condition in evbuffer_drain() for IOCP (d6326104)
+  o fix incorrect unlock of the buffer mutex (for deferred callbacks) (2b4d127d)
+  o Fix wrong assert in evbuffer_drain() (9f4d0dce)
+
+ cmake:
+  o fix checking of devpoll backend (like in autotools, by devpoll.h existence) (7f161902)
+  o support static runtime (MSVC) (c8b3ec17, 61fb055a)
+  o do not build both (SHARED and STATIC) for MSVC/win32 (bc7f2fd9)
+  o introduce EVENT__LIBRARY_TYPE option (eb10a738)
+  o ensure windows dll's are installed as well as lib files (29590718)
+  o Fix generation of LibeventConfig.cmake for the installation tree (7fa08c4b)
+  o fix pkgconfig generation (copy-paste typo) (cc554d87)
+  o Merge branch 'cmake-missing-bits' (9806b126)
+  o Fix detection of timerfd_create() in CMake. (e50af331)
+  o Merge branch 'cmake-configure-fixes-v2' (a0bfe2c4)
+  o Do not add epoll_sub (syscall wrappers) for epoll in cmake (cea61de6)
+  o Fix RPATH for APPLE (45b1f379)
+
+ autotools:
+  o include win32 specific headers for socklen_t detection on win32/mingw (d7579fb9)
+  o Ignore evconfig-private.h for autotools (37423849)
+  o config.h can't be prefixed unconditionally (63a054f8)
+  o Merge branch 'pull-628' (7e56c8b2)
+  o Provide Makefile variables LIBEVENT_{CFLAGS,CPPFLAGS,LDFLAGS} (2f060c5f)
+  o confirm openssl is working before using (b39ccf8e)
+  o pass $(OPENSSL_INCS) for samples (FTBFS macOS) (c2495265)
+  o Add configure check for midipix (d433201e)
+  o Fix tests with detached builds (c46ff439)
+
+ build:
+  o Fix arc4random_addrandom() detecting and fallback (regression) (303d6d77)
+  o Merge branch 'win32-fixes' (ebd12e6d)
+  o Merge branch 'fix-openssl-linking' (e7bd9e03)
+  o Merge branch 'fix-struct-linger' (8567f2f5)
+
+ CI:
+  o travis-ci/appveyor now uses fast_finish+allow_failures
+    (5e97b6e6, dd472e7d, dfb5fc167)
+  o Merge branch 'travis-ci-osx-fixes' (9f02b39c)
+  o Merge branch 'win64-fixes' (aee0fcd5)
+
+
+Changes in version 2.1.8-stable (22 January 2017)
+
+ Libevent 2.1.8-stable, it contains openssl fixes for resetting fd and using
+ bufferevent_openssl_filter_new(). vagrant fixes, some build fixes, increased
+ timeout for some tests (to reduce number of failures due to timing issues),
+ date in RFC1123 format and running tests in parallel.
+
+ There are highlighted changes above.
+
+ Build fixes:
+  o Fix _FILE_OFFSET_BITS redinition (solaris/autotools) (336f3b11 Azat Khuzhin)
+  o util-internal: fix __func__ redefinition (netbsd) (253e7fa9 Azat Khuzhin)
+  o Fix signedness differ for iov_base (solaris) (2c62062e Azat Khuzhin)
+  o evutil_time: include <unistd.h> when there is only sleep()/usleep() (3e75194c Azat Khuzhin)
+  o http: fix formatter for pritnf for req->ntoread (osx) (1cbf26f6 Azat Khuzhin)
+ Testing environment:
+  o Merge branch 'automake-tests-parallel-v4' (*includes ci bits also*) (59e217df Azat Khuzhin)
+ Vagrant env fixes:
+  o vagrant/netbsd: missing libtool (9c9be399 Azat Khuzhin)
+  o vagrant/netbsd: more reliable way of installing packages (36da6877 Azat Khuzhin)
+  o vagrant/osx: use make instead of gmake (there is no gmake) (f7c70aef Azat Khuzhin)
+  o vagrant: add centos box (ca591c5b Azat Khuzhin)
+ Tests:
+  o test/dns: replace servname since solaris does not have "http" (d6bafbbe Azat Khuzhin)
+  o test/thread: netbsd is too slow, increase timeout for conditions_simple (3c7422fc Azat Khuzhin)
+  o test/dns: run async resolving after sync one (to avoid timeouts) (07862531 Azat Khuzhin)
+  o test/http: turn off some tests that based on backlog filling (falky) (26f416c1 Azat Khuzhin)
+ Bugfixes:
+  o Merge branch 'openssl-filter-fixes-v4' (83e0f43b Azat Khuzhin)
+  o Merge branch 'date-rfc1123' (68def435,4798de6c,4545807d Azat Khuzhin)
+  o Merge branch 'be-openssl-fd-reset-fix-v2' (86fa0070,32adf434 Azat Khuzhin)
+  o Merge branch 'openssl-1.1-init-fixes-v2' (18a161f0 Azat Khuzhin)
+  o Fix incorrect MIME type (23f9a20e johnsonlee)
+ Trivial fixes:
+ Documentation updates:
+  o Update README.md (3821cca1 Breaker)
+
+
+Changes in version 2.1.7-rc (2 Novemer 2016)
+
+ Libevent 2.1.7-rc contains openssl 1.1 support, build fixes, CI improvements
+ and plus Vagrantfile for testing under multiple OS'es.
+
+
+ Continious Integration:
+  o Use coveralls.io via travis (9ac000c Azat Khuzhin)
+  o travis-ci: use container-based infrastructure (7e12e96 Azat Khuzhin)
+  o travis-ci/osx: fix compiling/linking openssl libraries (9d2f8d4 Azat Khuzhin)
+  o travis-ci: use gcc-5 (fixes osx|gcc failures) (d7ceae5 Azat Khuzhin)
+  o Testing with vagrant for 6 OS and cmake+autoconf (9585338 Azat Khuzhin)
+  o travis-ci/osx: install lcov (e4e099b Azat Khuzhin)
+
+ Build Improvements/Fixes:
+  o Fix cmake -DEVENT__COVERAGE=ON (40fbffc Azat Khuzhin)
+  o autogen.sh: learn about gmake (9376ac4 Azat Khuzhin)
+  o autogen.sh: remove all autoconf/automake caches, if any (69cce25 Azat Khuzhin)
+  o cmake: fix finding python2, and check that it is really 2 (3453c08 Azat Khuzhin)
+  o cmake: fix CheckFunctionExistsEx/CheckPrototypeDefinition (CMP0054) (43b69b2 Azat Khuzhin)
+  o cmake: cleanup (dc624ad Zonr Chang)
+  o cmake/win32: fix running regress, but fixing finding python2 interpreter (bcb990a Azat Khuzhin)
+  o cmake: use PYTHON_EXECUTABLE to find python2 (a4d044c Azat Khuzhin)
+  o Merge branch 'force-disable-clockgettime' (83c7cdf Azat Khuzhin)
+
+ Code Improvements (core)
+  o use ev_uint16_t instead of unsigned short for port (e983712 Thomas Bernard)
+  o Merge branch 'contrib-guide-v2' (b9c5077 Azat Khuzhin)
+  o poll: Prevent libevent from spinning if POLLNVAL occurs (675974c Tim Hentenaar)
+
+ Testing:
+  o test/regress: cover a polling of invalid fd (cb0df5c Tim Hentenaar)
+
+ Code Improvements (bufferevent_openssl)
+  o Make it build using OpenSSL 1.1.0 (3e9e0a0 Kurt Roeckx)
+  o Don't call BIO_number_{read|written} on NULL BIOs. (6702da1 Adam Langley)
+  o Switch from a 512 to 2048-bit RSA key. (f9803a6 Adam Langley)
+
+ Trivial fixes:
+  o Ignore temporary configure files (8fb08ae Azat Khuzhin)
+  o README.md: fix typo: ar -> are (2361616 Simone Basso)
+  o be: just a simple mistake, reinclude the <errno.h> (7521664 Seven)
+
+Changes in version 2.1.6-beta (4 July 2016)
+
+ Libevent 2.1.6-beta contains mostly bug fixes (evbuffers, evthread, evdns,
+ bufferevents, core, http, samples), improvements but mostly to fix some
+ possible issues (EVHTTP_CON_LINGERING_CLOSE), a lot of new unit tests and new
+ appveyor integration.
+
+ Security Fixes (utils)
+   o evutil_parse_sockaddr_port(): fix buffer overflow (329acc1 Azat Khuzhin)
+
+ Security Fixes (evdns)
+   o evdns: name_parse(): fix remote stack overread (96f64a0 Azat Khuzhin)
+   o evdns: fix searching empty hostnames (ec65c42 Azat Khuzhin)
+
+ New APIs (evdns)
+   o New function to get address for nameserver. (537177d Nick Mathewson)
+
+ New APIs (bufferevents)
+   o expose bufferevent_incref/decref (with fewer modifications) (1ed6718 Mark Ellzey)
+
+ New APIs (internal)
+   o evdns: export cancel via callbacks in util (like async lib core/extra issues) (8cbe65d Azat Khuzhin)
+
+ New APIs/Improvements (http)
+   o http: take EVHTTP_CON_LINGERING_CLOSE into account for "Expect: 100-Continue" (ac448a7 Azat Khuzhin)
+   o http: lingering close (like nginx have) for entity-too-large (9fde518 Azat Khuzhin)
+   o http: read server response even after server closed the connection (680742e Azat Khuzhin)
+   o http: export evhttp_connection_set_family() (714fc70 Azat Khuzhin)
+   o http: reuse connected address only with EVHTTP_CON_REUSE_CONNECTED_ADDR (a50f5f0 Azat Khuzhin)
+   o http: use IP address that we got before (if any) during retrying (54c887d Azat Khuzhin)
+
+ Bugfixes (core)
+   o Fix getaddrinfo under solaris (for multiprotocol case) (40730ae Azat Khuzhin)
+   o Check for Mac OS X 10.4 kqueue bug properly (df6f99e Mark Mentovai)
+   o event_reinit: make signals works after fork() without evsig_add() (88640aa Nicholas Marriott)
+   o event_reinit: always re-init signal's socketpair (ad0c237 Nicholas Marriott)
+   o Free event queues even for recursive finalizers (7c8d015 Azat Khuzhin)
+   o Fix checking for make_base_notifiable() (f337296 Azat Khuzhin)
+   o Set correct socklen for PF_INET6 sockaddr len (3499ad9 Mark Ellzey)
+   o Fix garbage value in socketpair util function, stdint? (043ae74 Mark Ellzey)
+   o fix the return value of event_deferred_cb_schedule_ (38cef64 Greg Hazel)
+   o event_free_debug_globals_locks(): disable lock debugging (e5c87d1 Azat Khuzhin)
+   o event: call event_disable_debug_mode() in libevent_global_shutdown() (941faae Azat Khuzhin)
+   o ht-internal: don't reset hth_table_length explicitly in name_##HT_CLEAR (597c7b2 Azat Khuzhin)
+
+ Bugfixes (evthread)
+   o evthread: fix evthread_setup_global_lock_() for debug-lock with a real-lock case (e4556fc Azat Khuzhin)
+   o evthread: evthreadimpl_disable_lock_debugging_() for libevent_global_shutdown() (ccc5593 Azat Khuzhin)
+
+ Bugfixes (evdns)
+   o evdns: avoid double-free in evdns_base_free() for probing requests (4db15e0 Azat Khuzhin)
+   o evdns: evdns_base_free(): fix UAF of evdns_base with @fail_requests (00313c5 Azat Khuzhin)
+   o evdns: evdns_base_free(): free requests before namservers (14f84bb Azat Khuzhin)
+   o evdns: fix randomize-case by make case-insensitive as required (9c238de Azat Khuzhin)
+
+ Bugfixes (bufferevents)
+   o be_sock: handle readv() returns ECONNREFUSED (freebsd 9.2) (3189eb0 Azat Khuzhin)
+   o be_filter: avoid data stuck under active watermarks (b627ad8 Eduardo Panisset)
+   o Fix bufferevent_pair to properly set BEV_EVENT_{READING,WRITING} on flush. (2851889 David Paschich)
+   o be_openssl: clear all pending errors before SSL_*() calls (38e0f4a Azat Khuzhin)
+   o be_sock: cancel in-progress dns requests (86dfd2c Azat Khuzhin)
+   o be_sock: unfreeze buffers on fd changing (255525d Azat Khuzhin)
+   o be_sock: bufferevent_socket_connect_hostname(): make it thread-safe (809bb39 Azat Khuzhin)
+   o be_openssl: don't call do_write() directly from outbuf_cb (da52933 Azat Khuzhin)
+   o be_openssl: use bufferevent_enable() instead of bufferevent_add_event_() (0c66d32 Azat Khuzhin)
+   o be_openssl: don't add events during bev creation (like be_sock) (f4b6284 Azat Khuzhin)
+   o Fix lock leak in be_pair_flush() if flush type is BEV_NORMAL (f45d39d Bill Vaughan)
+   o be_openssl: don't use *_auto() in do_handshake() we can't have fd == -1 there (877280d Azat Khuzhin)
+   o be_openssl: don't call set_open_callbacks() if fd == -1 (e8a2da9 Azat Khuzhin)
+   o be_openssl: get rid off hackish "fd_is_set", to fix some corner cases (40b0379 Azat Khuzhin)
+   o be: we don't need to use getpeername() we we have conn_address (2c271e2 Azat Khuzhin)
+   o Call underlying bev ctrl SET_FD on filtered bufferevents (c2aa7dc Mark Ellzey)
+   o be_pair: release shared lock with the latest of bufferevent_pair (92a359e Azat Khuzhin)
+
+ Bugfixes (http)
+   o [Issue #313] set method to ASCII "NULL" if evhttp_method() returns NULL (17cc636 Mark Ellzey)
+   o evhttp_have_expect(): fix -Wlogical-not-parentheses (24b5214 Azat Khuzhin)
+   o http: set fd to -1 unconditioally, to avoid leaking of DNS requests (7a4b472 Azat Khuzhin)
+   o http: avoid leaking of fd in evhttp_connection_free() (f0e1341 Azat Khuzhin)
+   o http: get fd from be layer during connection reset (4a53c54 Azat Khuzhin)
+   o http: fix EVHTTP_CON_READ_ON_WRITE_ERROR when it doesn't supported by OS (2ff164a Azat Khuzhin)
+   o http: do not do function calls under EVUTIL_ASSERT() to fix NDEBUG builds (7c89999 Azat Khuzhin)
+   o http: fix leaking of response_code_line (8f18a62 Azat Khuzhin)
+   o http: fix "Expect: 100-continue" client side (0b46b39 Azat Khuzhin)
+   o http: fix conflicts EVHTTP_CON_AUTOFREE and EVHTTP_CON_REUSE_CONNECTED_ADDR (4dc0979 Azat Khuzhin)
+   o http: avoid epoll_ctl() on already closed fd (triggers by http/chunk_out) (ab3bc69 Azat Khuzhin)
+   o http: install timeout for read too during connect for ssl (040000d Azat Khuzhin)
+   o http: fix evhttp_request_own() by checking EVHTTP_USER_OWNED in more cases (b0d3964 Azat Khuzhin)
+   o http: fix detecting EOF without write (7ed02ac Azat Khuzhin)
+   o evhttp: Fix failure to send all output data for POST/PUT requests (24eea0d John Ohl)
+   o Fix evhttp_uriencode() regression. (c6b1ec1 Mark Ellzey)
+   o removed unused vars (e94250c Mark Ellzey)
+   o pointer overflow checks for evhttp_uriencode (72afe4c Zonr Chang)
+
+ Bugfixes (evbuffers)
+   o buffer: fix overflow check in evbuffer_expand_singlechain() (a3f4ccd Azat Khuzhin)
+   o buffer: evbuffer_add_buffer(): clean empty chains from destination buffer (26fd932 Azat Khuzhin)
+   o Fix n_add_for_cb in evbuffer_prepend() in case of new buffer required (0abd039 Azat Khuzhin)
+   o be_filter: actually disable output_filter during processing output (c031215 Simon Perreault)
+   o evbuffer_add: Use last_with_datap if set, not last. (a8769ef Marcus Sundberg)
+   o EVBUFFER_PTR_SET -> EVBUFFER_PTR_ADD (8674e4f jer-gentoo)
+
+ Bugfixes (evconnlistener)
+   o listener: unlock lev on error in listener_read_cb() (2a71b33 Azat Khuzhin)
+   o Fix potential fd leak in listener_read_cb() (a695a72 Mark Ellzey)
+
+ Testing
+   o tests: use waitpid(..., WNOWAIT) to fix failing of main/fork under solaris (43eb56c Azat Khuzhin)
+   o test: replace sleeping with syncing pair in main/fork (16d220c Azat Khuzhin)
+   o test/http: do not run tests that based on backlog filling (freebsd) (500b6b7 Azat Khuzhin)
+   o test/bufferevent/iocp: fix test name for "bufferevent_connect_fail_eventcb" (4410e9d Azat Khuzhin)
+   o test/ssl: use send()/recv()/EVUTIL_ERR_RW_RETRIABLE()/EVUTIL_SOCKET_ERROR() to fix win32 (a9e8cd6 Azat Khuzhin)
+   o test/https_basic: increase timeout for complete write (fixes win32) (d5a2f2f Azat Khuzhin)
+   o test: fix building with --disable-thread-support under win32 (a487706 Azat Khuzhin)
+   o test/buffer: evbuffer_add_buffer() with empty chains (a272bc4 Azat Khuzhin)
+   o test/buffer: evbuffer_remove_buffer() with empty chains (prepend) (f0cfa14 Azat Khuzhin)
+   o test/buffer: evbuffer_remove_buffer() with empty chains (evbuffer_add_buffer()) (2880ce6 Azat Khuzhin)
+   o test/buffer: cover evbuffer_expand() for overflow (48dab7a Azat Khuzhin)
+   o test/be_filter: creating test case for data stuck with active watermarks (766194b Eduardo Panisset)
+   o test/http: avoid using conditionals with omitted operands (fixes VS2015) (2a4bf29 Azat Khuzhin)
+   o test/http: don't mix declarations and code (fixes -Wdeclaration-after-statement) (aabf1c2 Azat Khuzhin)
+   o test/buffer: fix leak in test_evbuffer_prepend() (c08d90b Azat Khuzhin)
+   o test/buffer: avoid errors with --no-fork (reinitialize static vars) (e7d1e39 Azat Khuzhin)
+   o test/buffer: cover n_add_for_cb when evbuffer_prepend() need to allocate buffer (e77ff41 Azat Khuzhin)
+   o test/tinytest_macros: add new one tt_nstr_op() (bd19a28 Azat Khuzhin)
+   o test/bufferevent: check that output_filter disabled during processing output (ae28812 Azat Khuzhin)
+   o test/listener: regression for missing unlock in listener_read_cb() (7d85651 Azat Khuzhin)
+   o test/regress: add tests for evbuffer_add() breakage on empty last chain (d5ee739 Marcus Sundberg)
+   o test/http: fix running some tests sequential (with --no-fork) (bddad71 Azat Khuzhin)
+   o test/http: localize evhttp server structure (cbc3209 Azat Khuzhin)
+   o test/dns: regression for empty hostname (d7348ba Azat Khuzhin)
+   o test/http: fix SERVER_TIMEOUT tests under win32 (d49a658 Azat Khuzhin)
+   o test/http: add a helper for creating timedout/failed request (376f107 Azat Khuzhin)
+   o test/http: adopt for C90 (mixed code and declarations) (d02a285 Azat Khuzhin)
+   o test/http: cover NS timed out during request cancellations separatelly (0c343af Azat Khuzhin)
+   o test/http: request cancellation with resolving/{conn,write}-timeouts in progress (334340d Azat Khuzhin)
+   o test/http: exit from the loop in the errorcb to wait cancellation (927ab33 Azat Khuzhin)
+   o regress_clean_dnsserver(): reset global port vars (351207f Azat Khuzhin)
+   o test/http: read_on_write_error: fix it for win32 (3b58169 Azat Khuzhin)
+   o test/http: separate coverage for EVHTTP_CON_READ_ON_WRITE_ERROR (5c2b4c1 Azat Khuzhin)
+   o test/http: cover "Expect: 100-continue" client-server interaction (31d8116 Azat Khuzhin)
+   o test/http: *lingering tests shouldn't have "Expect: 100-continue" (ed469ab Azat Khuzhin)
+   o test: use EVUTIL_SHUT_WR (04fc82f Azat Khuzhin)
+   o test/http: avoid huge stack allocations to fix win32 builds (3166765 Azat Khuzhin)
+   o test: http/lingering_close: cover EVHTTP_SERVER_LINGERING_CLOSE (e122ca1 Azat Khuzhin)
+   o test: http/non_lingering_close: cover ~EVHTTP_SERVER_LINGERING_CLOSE (f41e1b0 Azat Khuzhin)
+   o test: http/*: update expected HTTP codes for body exceeds `max_body_size` (addf2b9 Azat Khuzhin)
+   o test: http/data_length_constrains: set EVHTTP_CON_READ_ON_WRITE_ERROR (d38a723 Azat Khuzhin)
+   o test: increase buffer size for http/data_length_constraints to trigger EPIPE (0792e1e Azat Khuzhin)
+   o test/tinytest_demo: include <windows.h> for win32 to fix tdm-gcc (f062bbe Azat Khuzhin)
+   o test/regress: cover event_del() waiting mechanism (5b58b70 Azat Khuzhin)
+   o test/regress: cover existing signal callbacks and fork() + event_reinit() (ceddc60 Azat Khuzhin)
+   o test/regress: cover signals after fork() + event_reinit() (b075b81 Azat Khuzhin)
+   o test/regress: main/fork: rewrite assertions by just removing event in callback (088d8b3 Azat Khuzhin)
+   o test/dns: check exit code of evdns_getaddrinfo() (0b9d432 Azat Khuzhin)
+   o test/dns: cover evdns_getaddrinfo() and evdns_base_free() with @fail_requests (4ad3483 Azat Khuzhin)
+   o test/dns: cover @fail_requests for evdns_base_free() (d6c6fb4 Azat Khuzhin)
+   o test/dns: more graceful coverage of @fail_requests (123d372 Azat Khuzhin)
+   o test/ssl: cover busy-loop (i.e. {read,write}-blocked-on-{write,read} stuff) (da0ea7a Azat Khuzhin)
+   o test/http: write_during_read for https (23c77b6 Azat Khuzhin)
+   o test/http: connection_fail for https (7ea26f7 Azat Khuzhin)
+   o test/http: stream_out for https (ac04968 Azat Khuzhin)
+   o test/http: chunk_out for https (a71ffb9 Azat Khuzhin)
+   o test/regress: fix ssl-less builds (need to make this prettier) (3160716 Azat Khuzhin)
+   o test/http: allow dirty shutdown for ssl to fix https_incomplete (1ede326 Azat Khuzhin)
+   o test/http: https basic (59714b4 Azat Khuzhin)
+   o test/http: incomplete{,_timeout} for https (615490d Azat Khuzhin)
+   o test/http: add simplest test for http/https/https_dirty_shutdown (93b19dc Azat Khuzhin)
+   o test/http: https: retry coverage (7c2d24a Azat Khuzhin)
+   o test/http: https server support (plus some helpers) (a7088ad Azat Khuzhin)
+   o test/http: more sanity checks (a27c53c Azat Khuzhin)
+   o test/ssl: export getkey()/getcert()/get_ssl_ctx()/init_ssl() for https (0c4c387 Azat Khuzhin)
+   o test/regress_be: basic coverage bufferevent_flush() for pair/sock layers (ad52602 Azat Khuzhin)
+   o test/regress_be: socket_filter_inactive: check bufferevent after creation (f8081af Azat Khuzhin)
+   o test/regress_be: cover finalizers from inactive to active queue (337684b Azat Khuzhin)
+   o test/regress_buffer: fix clang compilation warnings (d8fd4c0 Azat Khuzhin)
+   o test/regress_http: fix compilation warnings (-Wmissing-field-initializers) (cd422e0 Azat Khuzhin)
+   o test/regress_dns: fix compilation warnings (-Wmissing-field-initializers/for) (f55db98 Azat Khuzhin)
+   o tests/regress_dns: cover that randomize-case works case-insensitive (1e8bfbc Azat Khuzhin)
+   o test: fix bufferevent/bufferevent_pair_release_lock in debug mode (3f749e9 Azat Khuzhin)
+   o test: fix bufferevent/bufferevent_pair_release_lock for freebsd (79f9ace Azat Khuzhin)
+   o test/regress_be: bufferevent_enable() shouldn't call eventcb by it's own (a0f308d Azat Khuzhin)
+   o test/regress_be: introduce fake_listener_create() (37dc9e0 Azat Khuzhin)
+   o test/regress_http: cover evhttp_request_own() (6f6fa0d Azat Khuzhin)
+   o test/regress_http: cover write during read (3d15aeb Azat Khuzhin)
+   o test/regress_http: verify that closecb will be called without multiple write (4be6c70 Azat Khuzhin)
+   o test/regress: fix bufferevent_pair_release_lock with EVENT_DEBUG_MODE (6ea6655 Azat Khuzhin)
+   o test/regress_ssl: check events fd/pending after timeout triggered (cdafdf0 Azat Khuzhin)
+   o test/regress_ssl: cover case when server didn't up (failed with timeout) (74845f1 Azat Khuzhin)
+   o test/regress_ssl: covert that we can't change fd with underlying (df507af Azat Khuzhin)
+   o test/regress_ssl: cover that events (read/write) at finish not pending (762edb4 Azat Khuzhin)
+   o test/regress_ssl: cover fd manipulations (b78a829 Azat Khuzhin)
+   o test/regress_ssl: convert open_ssl_bufevs() to mask (46bba73 Azat Khuzhin)
+   o test/regress_ssl: convert client/server to mask too (3455991 Azat Khuzhin)
+   o test/regress_ssl: cover "allow_dirty_shutdown" (0430327 Azat Khuzhin)
+   o test/regress_ssl: convert regress_bufferevent_openssl() to bitmask (342e116 Azat Khuzhin)
+   o tests/regress_ssl: drop duplicated assert (25e56fd Azat Khuzhin)
+   o test/regress_http: initialize "dns_base" to avoid reading trash (9f0bff3 Azat Khuzhin)
+   o test/http: cover retrying with saved conn_address by shutting down dns server (f4874d8 Azat Khuzhin)
+   o be_pair/regress: cover use of shared lock (lock/unlock/free) (a558fcd Azat Khuzhin)
+   o regress_dns: drop hack for event_debug_map_HT_GROW in leak tests (3540a19 Azat Khuzhin)
+
+ Sample code
+   o Fix memory leak in signal-test.c (666db91 basavesh.as)
+   o sample/hello-world: exAmple, not eXMple (2d3cd35 kirillDanshin)
+   o dns-example: allow to set ns from args (df19a97 Azat Khuzhin)
+   o dns-example: convert to getopt() (32f8592 Azat Khuzhin)
+   o http-connect: make it win32 compilable (1bf7595 Azat Khuzhin)
+   o sample/https-client: allow to change path to ca-certificates (fdf713a Azat Khuzhin)
+   o sample/https-client: check for ERR_remove_thread_state() existence (c4e9d9b Azat Khuzhin)
+   o sample/https-client: replace ERR_remove_state() by ERR_remove_thread_state() (77ad68a Azat Khuzhin)
+   o sample/https-client: add -timeout option (4637aa8 Azat Khuzhin)
+   o sample/https-client: don't try to free uninitialized SSL (f3d7ff5 Azat Khuzhin)
+   o sample/https-client: graceful exit with freeing memory (to make valgrind happy) (24a1f25 Azat Khuzhin)
+   o https-client: correctly handle URLs with no path (like "https://host:port") (29a0482 Andrey Skriabin)
+   o sample/http-connect: don't use assert() to make it work with NDEBUG (6dc71e7 Azat Khuzhin)
+   o sample/http-connect: made it compatible with C90 (f976d43 Azat Khuzhin)
+   o sample: add HTTP CONNECT tunnelling example using libevent http layer (1d34498 Azat Khuzhin)
+   o Update dns-example. (620ff24 Mark Ellzey)
+
+ Documentation
+   o Update README.md (b8ec70c Mark Ellzey)
+   o Update README.md (80faee9 Mark Ellzey)
+   o Update README.md (ad4a897 Mark Ellzey)
+   o Update README.md (a2b2e1e Mark Ellzey)
+   o Update README.md (0dfa5dc Mark Ellzey)
+
+ Code Improvements (evthread)
+   o evthread: add evthread_get_{lock,condition}_callbacks() helpers (c0b34f6 Azat Khuzhin)
+
+ Code Improvements (core)
+   o util: make @sa const for evutil_socket_connect_() (a8d32c2 Azat Khuzhin)
+
+ Code Improvements (http)
+   o http: assert's that evbuffer_drain() success on connection reset (2185e63 Azat Khuzhin)
+   o http: introduce evhttp_request_free_() helper (22061ac Azat Khuzhin)
+   o http: introduce evhttp_is_request_connection_close() helper (6540da3 Azat Khuzhin)
+
+ Code Improvements (bufferevents)
+   o be_sock: bufferevent_socket_set_conn_address(): assert instead of silent no-op (0ab88c2 Azat Khuzhin)
+   o be_sock: sanity check in bufferevent_socket_set_conn_address() (eedbeff Azat Khuzhin)
+   o be: replace sockaddr_storage with sockaddr_in6 for conn_address (3889612 Azat Khuzhin)
+   o be: replace conn_address by full struct instead of pointer (e5615aa Azat Khuzhin)
+   o bufferevent: move conn_address out from http into bufferevent (8bb3842 Azat Khuzhin)
+   o be: make @sa const for bufferevent_socket_connect() (dc33c78 Azat Khuzhin)
+
+ Cleanups (core)
+   o Refactoring conditional directives that break parts of statements. (4b41eeb lzmths)
+   o epoll: introduce PRINT_CHANGES() macro to avoid copy-pasting (a1b142b Azat Khuzhin)
+   o tab (6e7a580 Greg Hazel)
+
+ Cleanups (evbuffers)
+   o buffer_compat: fix comment -- we have EVBUFFER_EOL_ANY not EOL_STYLE_ANY (575ff67 Azat Khuzhin)
+
+ Cleanups (bufferevents)
+   o be_sock: evutil_getaddrinfo_async_() always return 0 (dbff101 Azat Khuzhin)
+   o be_sock: drop be_sock_add() macro (useless and debug unfriendly) (fad5fe2 Azat Khuzhin)
+   o be: introduce bufferevent_generic_adj_existing_timeouts_() (3c1f58f Azat Khuzhin)
+   o be: add_event: use evutil_timerisset() (a96b73b Azat Khuzhin)
+   o be_openssl: introduce be_openssl_auto_fd() helper (2a8a711 Azat Khuzhin)
+   o be_openssl: introduce set_open_callbacks_auto() (510da71 Azat Khuzhin)
+
+ Cleanups (http)
+   o http: make fallback for EVHTTP_CON_READ_ON_WRITE_ERROR more cleaner (d405492 Azat Khuzhin)
+   o http: coding style issue (365f181 Azat Khuzhin)
+
+ Cleanups (evdns)
+   o evnds: inline TEST_NAME macro to make debuggin easier (0c615f4 Azat Khuzhin)
+
+ Portability Fixes
+   o [#372] check for errno.h (3031617 Mark Ellzey)
+   o Fixed Unicode issue in error messages. (e8b7895 Mattes D)
+   o Assume that ke_udata is an integer type on CloudABI. (5602e45 Ed Schouten)
+   o Add missing include of <netinet/in.h>. (b2c68bc Ed Schouten)
+   o Include <sys/ioctl.h>, <sys/resource.h> and <sys/wait.h> optionally. (c1404b5 Ed Schouten)
+   o Test against SO_REUSEADDR (along with _WIN32). (ce1776c Ed Schouten)
+   o Always define missing TAILQ functions from sys/queue.h (2828bdb Christopher Wiley)
+   o Don't use BSD u_* types. (fd36647 Ed Schouten)
+   o Remove BSD-ism: TIMEVAL_TO_TIMESPEC(). (193c7de Ed Schouten)
+   o be: include all variations of headers for sockaddr_in6 struct (c212291 Azat Khuzhin)
+   o be: fix sockaddr_in6 type definition for win32 (c42bc6b Azat Khuzhin)
+
+ Continious Integration:
+   o travis: split long lines, and make it cleaner (685a6a1 Azat Khuzhin)
+   o travis: fix autotools on osx by reinstalling libtool (088ea5e Azat Khuzhin)
+   o appveyor/autotools: link with openssl by passing LDFLAGS/CFLAGS (6fcfa25 Azat Khuzhin)
+   o appveyor: image already had openssl installed (4634b85 Azat Khuzhin)
+   o appveyor: check -DUNICODE -D_UNICODE according to ReleaseChecklist (cmake only) (e9acc44 Azat Khuzhin)
+   o appveyor: ignore failure of mingw-get (1810857 Azat Khuzhin)
+   o appveyor: drop shallow_clone, since we use tags for detecting version in cmake (ac90133 Azat Khuzhin)
+   o appveyor: support cmake & autotools using build matrix (like travis-ci has) (8f95015 Azat Khuzhin)
+   o travis-ci/osx: relink gcc/g++ instead of clang (481481d Azat Khuzhin)
+   o travis-ci: enable multi-os mode (osx, linux) (79917e4 Azat Khuzhin)
+   o travis-ci: increase matrix (--disable-foo) (59649f7 Azat Khuzhin)
+   o travis-ci: adjust alignment (c8be339 Azat Khuzhin)
+   o travis: add builds without debug mode into matrix (3e56da2 Azat Khuzhin)
+   o test: run regress with EVENT_DEBUG_MODE=1 and without (cf2cf2a Azat Khuzhin)
+   o Update travis config for status updates (37453ab Mark Ellzey)
+   o Use autotools for appveyor until cmake is fixed. (1cc2e29 Mark Ellzey)
+   o Fix the link for appveyor OpenSSL installer (WIN32) (107d565 Mark Ellzey)
+   o Forgot to install OpenSSL for appveyor (26164a5 Joakim Söderberg)
+   o Add support for appveyor.com windows CI (5f89c37 Joakim Söderberg)
+
+ Build Improvements/Fixes:
+   o evutil: mark ai_find_protocol() static (prototype-less) (5a157c8 Azat Khuzhin)
+   o cmake/solaris: set CMAKE_REQUIRED_LIBRARIES to fix functions detections (dc95823 Azat Khuzhin)
+   o cmake/solaris: fix building (link with socket,nsl) (050bfc7 Azat Khuzhin)
+   o cmake: check for ZLIB_INCLUDE_DIR, since we can have only library without headers (c4dfb93 Azat Khuzhin)
+   o autotools/win32: fix searching ssl library (671a24f Azat Khuzhin)
+   o cmake/win32: do not compile regress_thread on -DEVENT__DISABLE_THREAD_SUPPORT=ON (de0c196 Azat Khuzhin)
+   o cmake/win32: do not compile evthread_win32 on -DEVENT__DISABLE_THREAD_SUPPORT=ON (ecb0ec8 Azat Khuzhin)
+   o cmake: fix -DEVENT__ENABLE_VERBOSE_DEBUG (typo on -DUSE_DEBUG) (e35f224 Azat Khuzhin)
+   o cmake: do not use stderr for notifications/version-info (38716c6 Azat Khuzhin)
+   o autoconf: fix --disable-thread-support build under win32 (bb09535 Azat Khuzhin)
+   o buffer: don't mix code and declarations (8892f4c Azat Khuzhin)
+   o Update gitignore file to ignore cscope gen'ed files (0aaa4fb Neeraj Badlani)
+   o For non GCC/clang on OSX the -Wno-deprecated-declarations may not be valid (b5ca365 Rainer Keller)
+   o automake: define serial-tests only if automake have this option (61179de Azat Khuzhin)
+   o test/automake: don't use paralell test harness (since automake 1.12) (44d755e Azat Khuzhin)
+   o Ignore all pkgconfig generated stuff (ce38993 Azat Khuzhin)
+   o libevent_core and libevent_extra also deserve a pkgconfig file (b8d7c62 Jan Heylen)
+   o Ignore verify_tests.bat (win32 version) (0f2de10 Azat Khuzhin)
+   o cmake: require 3.1 only for win32 to make it work under ubunty precise (87f7238 Azat Khuzhin)
+   o cmake: require at least 3.1 for target_sources() (c46ead5 Azat Khuzhin)
+   o cmake: fix adding of compiler flags, and now it will (36588e1 Azat Khuzhin)
+   o Replace -Wswitch-enum with -Wswitch, and add it into cmake rules too (f29f59e Azat Khuzhin)
+   o test/regress_ssl: Fix compile problems for win32 (73d0360 Trond Norbye)
+   o util: fix "%zu" format on TDM-gcc/MinGW-w64 (79b69d8 Azat Khuzhin)
+   o cmake: don't define EVENT__NEED_DLLIMPORT always (fixes VS2013 static build) (49bd790 Azat Khuzhin)
+   o Add missing return statement to del_wait_thread so libevent can build. (4f778ab Nick Mathewson)
+   o cmake: fix building dns-example under win32 (missing getopt) (a1609a8 Azat Khuzhin)
+   o visibility: align it to make it more readable (bb6b53d Azat Khuzhin)
+   o cmake: Fix detection of ssize_t/SSIZE_T (7707f6b Azat Khuzhin)
+   o Ignore more configure stuff (configure.lineno) (8d34302 Azat Khuzhin)
+   o Fixed issue with cmake version generation (d56efd9 Mark Ellzey)
+   o Cmake is now officially working. (7f9646d Mark Ellzey)
+   o More cmake updates, lot's of missing definitions (49a5381 Mark Ellzey)
+   o CMake syntax fixes fo .in files (6aad23d Mark Ellzey)
+   o Revert "The Windows socket type is defined as SOCKET." (a264da8 Mark Ellzey)
+   o CMAKE CMAKE CMAKE CLEANUPS (a9db46a Mark Ellzey)
+   o Lot's of cmake updates (8b228e2 Mark Ellzey)
+   o Provide a mechanism for building the library on Windows with different compiler flags. Add a batch file that builds it for the M[DT][d] options and performs a hunt and gather of the different output libraries. (ded8086 billsegall)
+   o The Windows socket type is defined as SOCKET. (c9e6c3d billsegall)
+   o autotools: fix getservbyname() detection (959a4c2 Azat Khuzhin)
+   o Add missing <string.h> for openssl_hostname_validation module (3316a21 Azat Khuzhin)
+   o make test/regress_ssl.c compile without warnings (9f02a44 Thomas Bernard)
+   o test/regress_be: drop debug __asm__(int3) to fix arm build (8240379 Azat Khuzhin)
+   o event_debug_created_threadable_ctx_: fix compilation without debug mode (a068f2e Azat Khuzhin)
+   o Add a prototype for event_disable_debug_mode() (bfcedee Sebastian Hahn)
+   o http: eliminate warning about "socklen" in evhttp_connection_connect_() (dfad1a4 Azat Khuzhin)
+   o Updated gitignore (1dbb55d Mark Ellzey)
+   o Update bench_httpclient.c (cb96931 Seungmo Koo)
+   o *fix: bench_httpclient to support win32 (4e9325e zeliard)
+   o Commented out a WIN32 threading / timing test for now (e84e269 Mark Ellzey)
+   o Fix mixed declarations and code (forbidden by ISO C90) (0c7f217 Thomas Bernard)
+   o Fix "function declaration isn’t a prototype" (746d2c5 Thomas Bernard)
+   o This fixes a bug introduced in 27bd9faf498b91923296cc91643e03ec4055c230 (19ba454 Joakim Söderberg)
+   o changed strtotimeval signature as per #211 (bdbc823 Xiao Bao Clark)
+   o Added cmake-generated files to ignore list. (6c12bfe Matyas Dolak)
+   o Ignore `make dist` generated files (8a2c6c7 Azat Khuzhin)
+
+  Debugging
+   o Debug mode option to error on evthread init AFTER other event calls. (dcfb19a Mark Ellzey)
+
+
+
 Changes in version 2.1.5-beta (5 January 2015)
 
  Security Fixes (evbuffers)
index 166d30872f81ec373b17acc6a7a0c54b2229ba6f..d7f6517b2b92d2bfcbea09bd0230676b7a85f4bb 100644 (file)
@@ -175,7 +175,7 @@ Changes in 1.4.1-beta:
  o support for 32-bit tag numbers in rpc structures; this is wire compatible, but changes the API slightly.
  o prefix {encode,decode}_tag functions with evtag to avoid collisions
  o Correctly handle DNS replies with no answers set (Fixes bug 1846282)
- o The configure script now takes an --enable-gcc-warnigns option that turns on many optional gcc warnings.  (Nick has been building with these for a while, but they might be useful to other developers.)
+ o The configure script now takes an --enable-gcc-warnings option that turns on many optional gcc warnings.  (Nick has been building with these for a while, but they might be useful to other developers.)
  o When building with GCC, use the "format" attribute to verify type correctness of calls to printf-like functions.
  o removed linger from http server socket; reported by Ilya Martynov
  o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr.
index a925d33b180a3a0cfe77774b7f84d3564a7f999b..16f36008cdec3d2b3c492b0d2d3c1c48ba6ae1b9 100644 (file)
@@ -1143,7 +1143,7 @@ Changes in 2.0.1-alpha (17 Apr 2009):
  o Check return value of event_add in signal.c
  o Add a more powerful evbuffer_readln as a replacement for evbuffer_readline.  The new function handles more newline styles, and is more useful with buffers that may contain a nul characters.
  o Do not mangle socket handles on 64-bit windows.
- o The configure script now takes an --enable-gcc-warnigns option that turns on many optional gcc warnings.  (Nick has been building with these for a while, but they might be useful to other developers.)
+ o The configure script now takes an --enable-gcc-warnings option that turns on many optional gcc warnings.  (Nick has been building with these for a while, but they might be useful to other developers.)
  o move EV_PERSIST handling out of the event backends
  o small improvements to evhttp documentation
  o always generate Date and Content-Length headers for HTTP/1.1 replies
index d9d6603459c323e7ee82413d42aa14bbc8326ee0..3f094f72134e2ddd5882ce7ffc8cbb3f702f5f79 100644 (file)
 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
 # by quotes) that should identify the project.
 
-PROJECT_NAME           = libevent
+PROJECT_NAME           = $(PROJECT)-$(VERSION)
 
 # Place all output under 'doxygen/'
 
-OUTPUT_DIRECTORY        = doxygen/
+OUTPUT_DIRECTORY        = $(DOCDIR)
 
 # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
 # will interpret the first line (until the first dot) of a JavaDoc-style 
@@ -64,24 +64,24 @@ STRIP_FROM_PATH        = include/
 # with spaces.
 
 INPUT                  = \
-        include/event2/buffer.h \
-        include/event2/buffer_compat.h \
-        include/event2/bufferevent.h \
-        include/event2/bufferevent_compat.h \
-        include/event2/bufferevent_ssl.h \
-        include/event2/dns.h \
-        include/event2/dns_compat.h \
-        include/event2/event.h \
-        include/event2/event_compat.h \
-        include/event2/http.h \
-        include/event2/http_compat.h \
-        include/event2/listener.h \
-        include/event2/rpc.h \
-        include/event2/rpc_compat.h \
-        include/event2/tag.h \
-        include/event2/tag_compat.h \
-        include/event2/thread.h \
-        include/event2/util.h
+        $(SRCDIR)/include/event2/buffer.h \
+        $(SRCDIR)/include/event2/buffer_compat.h \
+        $(SRCDIR)/include/event2/bufferevent.h \
+        $(SRCDIR)/include/event2/bufferevent_compat.h \
+        $(SRCDIR)/include/event2/bufferevent_ssl.h \
+        $(SRCDIR)/include/event2/dns.h \
+        $(SRCDIR)/include/event2/dns_compat.h \
+        $(SRCDIR)/include/event2/event.h \
+        $(SRCDIR)/include/event2/event_compat.h \
+        $(SRCDIR)/include/event2/http.h \
+        $(SRCDIR)/include/event2/http_compat.h \
+        $(SRCDIR)/include/event2/listener.h \
+        $(SRCDIR)/include/event2/rpc.h \
+        $(SRCDIR)/include/event2/rpc_compat.h \
+        $(SRCDIR)/include/event2/tag.h \
+        $(SRCDIR)/include/event2/tag_compat.h \
+        $(SRCDIR)/include/event2/thread.h \
+        $(SRCDIR)/include/event2/util.h
 
 #---------------------------------------------------------------------------
 # configuration options related to the HTML output
@@ -90,7 +90,7 @@ INPUT                  = \
 # If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
 # generate HTML output.
 
-GENERATE_HTML          = YES
+GENERATE_HTML          = $(GENERATE_HTML)
 
 #---------------------------------------------------------------------------
 # configuration options related to the LaTeX output
@@ -99,7 +99,7 @@ GENERATE_HTML          = YES
 # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
 # generate Latex output.
 
-GENERATE_LATEX         = YES
+GENERATE_LATEX         = $(GENERATE_LATEX)
 
 # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
 # If a relative path is entered the value of OUTPUT_DIRECTORY will be 
@@ -175,7 +175,7 @@ LATEX_HIDE_INDICES     = NO
 # If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
 # generate man pages
 
-GENERATE_MAN           = NO
+GENERATE_MAN           = $(GENERATE_MAN)
 
 # The MAN_EXTENSION tag determines the extension that is added to 
 # the generated man pages (default is the subroutine's section .3)
index 0da682b5d10303ed6e81ed55d1c741b9f6afe008..21815008a43c9f4e653940134464ae1f66a9b2fc 100644 (file)
@@ -5,8 +5,8 @@
 # See LICENSE for copying information.
 
 # 'foreign' means that we're not enforcing GNU package rules strictly.
-# '1.9' means that we need automake 1.9 or later (and we do).
-AUTOMAKE_OPTIONS = foreign 1.9 subdir-objects
+# '1.13' means that we need automake 1.13 or later (and we do).
+AUTOMAKE_OPTIONS = foreign 1.13 subdir-objects
 
 ACLOCAL_AMFLAGS = -I m4
 
@@ -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 = 5:0:0
+VERSION_INFO = 7:1:0
 
 # History:          RELEASE    VERSION_INFO
 #  2.0.1-alpha --     2.0        1:0:0
@@ -69,6 +69,13 @@ VERSION_INFO = 5:0:0
 #  2.1.3-alpha --     2.1        3:0:0 (ABI changed slightly)
 #  2.1.4-alpha --     2.1        4:0:0 (ABI changed slightly)
 #  2.1.5-beta  --     2.1        5:0:0 (ABI changed slightly)
+#  2.1.6-beta  --     2.1        6:0:0 (ABI changed slightly)
+#  2.1.7-beta  --     2.1        6:1:0 (ABI changed slightly)
+#  2.1.8-stable--     2.1        6:2:0 (No ABI change)
+#  2.1.9-beta--       2.1        6:3:0 (No ABI change)
+#  2.1.10-stable--    2.1        6:4:0 (No ABI change, WRONG)
+#  2.1.11-stable--    2.1        7:0:0 (ABI changed)
+#  2.1.12-stable--    2.1        7:1:0 (No ABI change)
 
 # ABI version history for this package effectively restarts every time
 # we change RELEASE.  Version 1.4.x had RELEASE of 1.4.
@@ -93,7 +100,7 @@ dist_bin_SCRIPTS = event_rpcgen.py
 endif
 
 pkgconfigdir=$(libdir)/pkgconfig
-LIBEVENT_PKGCONFIG=libevent.pc
+LIBEVENT_PKGCONFIG=libevent.pc libevent_core.pc libevent_extra.pc
 
 # These sources are conditionally added by configure.ac or conditionally
 # included from other files.
@@ -101,6 +108,29 @@ PLATFORM_DEPENDENT_SRC = \
        arc4random.c \
        epoll_sub.c
 
+CMAKE_FILES = \
+       cmake/AddCompilerFlags.cmake \
+       cmake/AddEventLibrary.cmake \
+       cmake/CheckConstExists.cmake \
+       cmake/CheckFileOffsetBits.c \
+       cmake/CheckFileOffsetBits.cmake \
+       cmake/CheckFunctionKeywords.cmake \
+       cmake/CheckPrototypeDefinition.c.in \
+       cmake/CheckPrototypeDefinition.cmake \
+       cmake/CheckWorkingKqueue.cmake \
+       cmake/CodeCoverage.cmake \
+       cmake/COPYING-CMAKE-SCRIPTS \
+       cmake/Copyright.txt \
+       cmake/LibeventConfig.cmake.in \
+       cmake/LibeventConfigVersion.cmake.in \
+       cmake/Macros.cmake \
+       cmake/Uninstall.cmake.in \
+       cmake/UseDoxygen.cmake \
+       cmake/VersionViaGit.cmake \
+       event-config.h.cmake \
+       evconfig-private.h.cmake \
+       CMakeLists.txt
+
 EXTRA_DIST = \
        ChangeLog-1.4 \
        ChangeLog-2.0 \
@@ -113,6 +143,8 @@ EXTRA_DIST = \
        make-event-config.sed \
        whatsnew-2.0.txt \
        whatsnew-2.1.txt \
+       README.md \
+       $(CMAKE_FILES) \
        $(PLATFORM_DEPENDENT_SRC)
 
 LIBEVENT_LIBS_LA = libevent.la libevent_core.la libevent_extra.la
@@ -140,18 +172,24 @@ CLEANFILES=
 DISTCLEANFILES=
 BUILT_SOURCES =
 include include/include.am
-#include sample/include.am
+include sample/include.am
 include test/include.am
 
 if BUILD_WIN32
 
+SYS_CORE_LIBS = -liphlpapi
 SYS_LIBS = -lws2_32 -lshell32 -ladvapi32
-SYS_SRC = win32select.c evthread_win32.c buffer_iocp.c event_iocp.c \
+SYS_SRC = win32select.c buffer_iocp.c event_iocp.c \
        bufferevent_async.c
 SYS_INCLUDES = -IWIN32-Code -IWIN32-Code/nmake
 
+if THREADS
+SYS_SRC += evthread_win32.c
+endif
+
 else
 
+SYS_CORE_LIBS =
 SYS_LIBS =
 SYS_SRC =
 SYS_INCLUDES =
@@ -221,18 +259,18 @@ NO_UNDEFINED =
 MAYBE_CORE =
 endif
 
-AM_CFLAGS = $(LEP_CFLAGS)
-AM_CPPFLAGS = -I$(srcdir)/compat -I$(srcdir)/include -I./include $(SYS_INCLUDES) $(LEP_CPPFLAGS)
-AM_LDFLAGS = $(LEP_CFLAGS)
+AM_CFLAGS = $(LIBEVENT_CFLAGS)
+AM_CPPFLAGS = -I$(srcdir)/compat -I./include -I$(srcdir)/include $(SYS_INCLUDES) $(LIBEVENT_CPPFLAGS)
+AM_LDFLAGS = $(LIBEVENT_LDFLAGS)
 
 GENERIC_LDFLAGS = -version-info $(VERSION_INFO) $(RELEASE) $(NO_UNDEFINED) $(AM_LDFLAGS)
 
 libevent_la_SOURCES = $(CORE_SRC) $(EXTRAS_SRC)
-libevent_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
+libevent_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS) $(SYS_CORE_LIBS)
 libevent_la_LDFLAGS = $(GENERIC_LDFLAGS)
 
 libevent_core_la_SOURCES = $(CORE_SRC)
-libevent_core_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
+libevent_core_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS) $(SYS_CORE_LIBS)
 libevent_core_la_LDFLAGS = $(GENERIC_LDFLAGS)
 
 if PTHREADS
@@ -255,14 +293,16 @@ endif
 noinst_HEADERS +=                              \
        WIN32-Code/nmake/evconfig-private.h     \
        WIN32-Code/nmake/event2/event-config.h  \
+       WIN32-Code/getopt.h                     \
+       WIN32-Code/getopt.c                     \
+       WIN32-Code/getopt_long.c        \
        WIN32-Code/tree.h                       \
-       bufferevent-internal.h                  \
-       changelist-internal.h                   \
+       bufferevent-internal.h          \
+       changelist-internal.h           \
        compat/sys/queue.h                      \
        defer-internal.h                        \
-       epolltable-internal.h                   \
+       epolltable-internal.h           \
        evbuffer-internal.h                     \
-       evconfig-private.h                      \
        event-internal.h                        \
        evmap-internal.h                        \
        evrpc-internal.h                        \
@@ -280,7 +320,8 @@ noinst_HEADERS +=                           \
        ratelim-internal.h                      \
        strlcpy-internal.h                      \
        time-internal.h                         \
-       util-internal.h
+       util-internal.h                         \
+       openssl-compat.h
 
 EVENT1_HDRS = \
        include/evdns.h \
@@ -297,9 +338,7 @@ endif
 
 verify: check
 
-doxygen: FORCE
-       doxygen $(srcdir)/Doxyfile
-FORCE:
+include doxygen.am
 
-DISTCLEANFILES += *~ libevent.pc ./include/event2/event-config.h
+DISTCLEANFILES += *~ libevent.pc libevent_core.pc libevent_extra.pc ./include/event2/event-config.h
 
index a7c82b016f0919ee41f6fd706fdc737a932ce859..1247e220f50e73f8ebdb3b6545b869c1f20244be 100644 (file)
@@ -1,3 +1,16 @@
+<p align="center">
+  <img src="https://strcpy.net/libevent3.png" alt="libevent logo"/>
+</p>
+
+
+
+[![Appveyor Win32 Build Status](https://ci.appveyor.com/api/projects/status/ng3jg0uhy44mp7ik?svg=true)](https://ci.appveyor.com/project/libevent/libevent)
+[![Travis Build Status](https://travis-ci.org/libevent/libevent.svg?branch=master)](https://travis-ci.org/libevent/libevent)
+[![Coverage Status](https://coveralls.io/repos/github/libevent/libevent/badge.svg)](https://coveralls.io/github/libevent/libevent)
+[![Join the chat at https://gitter.im/libevent/libevent](https://badges.gitter.im/libevent/libevent.svg)](https://gitter.im/libevent/libevent?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+
+
 # 0. BUILDING AND INSTALLATION (Briefly)
 
 ## Autoconf
@@ -7,9 +20,64 @@
      $ make verify   # (optional)
      $ sudo make install
 
+## CMake (General)
+
+
+The following Libevent specific CMake variables are as follows (the values being
+the default).
+
+```
+# Type of the library to build (SHARED or STATIC)
+# Default is: SHARED for MSVC, otherwise BOTH
+EVENT__LIBRARY_TYPE:STRING=DEFAULT
+
+# Installation directory for CMake files
+EVENT_INSTALL_CMAKE_DIR:PATH=lib/cmake/libevent
+
+# Enable running gcov to get a test coverage report (only works with
+# GCC/CLang). Make sure to enable -DCMAKE_BUILD_TYPE=Debug as well.
+EVENT__COVERAGE:BOOL=OFF
+
+# Defines if Libevent should build without the benchmark executables
+EVENT__DISABLE_BENCHMARK:BOOL=OFF
+
+# Define if Libevent should build without support for a debug mode
+EVENT__DISABLE_DEBUG_MODE:BOOL=OFF
+
+# Define if Libevent should not allow replacing the mm functions
+EVENT__DISABLE_MM_REPLACEMENT:BOOL=OFF
+
+# Define if Libevent should build without support for OpenSSL encryption
+EVENT__DISABLE_OPENSSL:BOOL=OFF
+
+# Disable the regress tests
+EVENT__DISABLE_REGRESS:BOOL=OFF
+
+# Disable sample files
+EVENT__DISABLE_SAMPLES:BOOL=OFF
+
+# If tests should be compiled or not
+EVENT__DISABLE_TESTS:BOOL=OFF
+
+# Define if Libevent should not be compiled with thread support
+EVENT__DISABLE_THREAD_SUPPORT:BOOL=OFF
+
+# Enables verbose debugging
+EVENT__ENABLE_VERBOSE_DEBUG:BOOL=OFF
+
+# When cross compiling, 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
+EVENT__FORCE_KQUEUE_CHECK:BOOL=OFF
+```
+
+__More variables can be found by running `cmake -LAH <sourcedir_path>`__
+
+
 ## CMake (Windows)
 
-Install CMake: <http://www.cmake.org>
+Install CMake: <https://www.cmake.org>
 
 
      $ md build && cd build
@@ -28,12 +96,12 @@ Install CMake: <http://www.cmake.org>
 
 ## Autoconf
 
-To build libevent, type
+To build Libevent, type
 
      $ ./configure && make
 
 
- (If you got libevent from the git repository, you will
+ (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.)
 
@@ -47,36 +115,36 @@ Install as root via
 
 Before reporting any problems, please run the regression tests.
 
-To enable the low-level tracing build the library as:
+To enable 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.
+     --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.
+     --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
+environment 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>.
+First of all install <https://www.cmake.org>.
 
-To build libevent using Microsoft Visual studio open the "Visual Studio Command prompt" and type:
+To build Libevent using Microsoft Visual studio open the "Visual Studio Command prompt" and type:
 
 ```
 $ cd <libevent source dir>
@@ -105,11 +173,6 @@ $ cmake -LH ..
 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
@@ -122,19 +185,21 @@ For the latest development versions of Libevent, access our Git repository
 via
 
 ```
-$ git clone git://levent.git.sourceforge.net/gitroot/levent/libevent
+$ git clone https://github.com/libevent/libevent.git
 ```
 
 You can browse the git repository online at:
 
-<http://levent.git.sourceforge.net/git/gitweb-index.cgi> 
+<https://github.com/libevent/libevent>
 
-<https://github.com/libevent/Libevent>
+To report bugs, issues, or ask for new features:
 
-To report bugs, request features, or submit patches to Libevent,
-use the Sourceforge trackers at
+__Patches__: https://github.com/libevent/libevent/pulls
+> OK, those are not really _patches_. You fork, modify, and hit the "Create Pull Request" button.
+> You can still submit normal git patches via the mailing list.
 
-<https://sourceforge.net/tracker/?group_id=50884> 
+__Bugs, Features [RFC], and Issues__: https://github.com/libevent/libevent/issues
+> Or you can do it via the mailing list.
 
 There's also a libevent-users mailing list for talking about Libevent
 use and development: 
@@ -198,7 +263,6 @@ fixing bugs:
  * Greg Hazel
  * Nicholas Heath
  * Michael Herf
- * Sebastian Hahn
  * Savg He
  * Mark Heily
  * Maxime Henrion
@@ -314,5 +378,110 @@ fixing bugs:
  * masksqwe
  * mmadia
  * yangacer
+ * Andrey Skriabin
+ * basavesh.as
+ * billsegall
+ * Bill Vaughan
+ * Christopher Wiley
+ * David Paschich
+ * Ed Schouten
+ * Eduardo Panisset
+ * Jan Heylen
+ * jer-gentoo
+ * Joakim Söderberg
+ * kirillDanshin
+ * lzmths
+ * Marcus Sundberg
+ * Mark Mentovai
+ * Mattes D
+ * Matyas Dolak
+ * Neeraj Badlani
+ * Nick Mathewson
+ * Rainer Keller
+ * Seungmo Koo
+ * Thomas Bernard
+ * Xiao Bao Clark
+ * zeliard
+ * Zonr Chang
+ * Kurt Roeckx
+ * Seven
+ * Simone Basso
+ * Vlad Shcherban
+ * Tim Hentenaar
+ * Breaker
+ * johnsonlee
+ * Philip Prindeville
+ * Vis Virial
+ * Andreas Gustafsson
+ * Andrey Okoshkin
+ * an-tao
+ * baixiangcpp
+ * Bernard Spil
+ * Bogdan Harjoc
+ * Carlo Marcelo Arenas Belón
+ * David Benjamin
+ * David Disseldorp
+ * Dmitry Alimov
+ * Dominic Chen
+ * dpayne
+ * ejurgensen
+ * Fredrik Strupe
+ * Gonçalo Ribeiro
+ * James Synge
+ * Jan Beich
+ * Jesse Fang
+ * Jiri Luznicky
+ * José Luis Millán
+ * Kiyoshi Aman
+ * Leo Zhang
+ * lightningkay
+ * Luke Dashjr
+ * Marcin Szewczyk
+ * Maximilian Brunner
+ * Maya Rashish
+ * Murat Demirten
+ * Nathan French
+ * Nikolay Edigaryev
+ * Philip Herron
+ * Redfoxmoon
+ * stenn
+ * SuckShit
+ * The Gitter Badger
+ * tim-le
+ * Vincent JARDIN
+ * Xiang Zhang
+ * Xiaozhou Liu
+ * yongqing.jiao
+ * Enji Cooper
+ * linxiaohui
+ * Seong-Joong Kim
+ * Tobias Stoeckmann
+ * Yury Korzhetsky
+ * zhuizhuhaomeng
+ * Pierce Lopez
+ * yuangongji
+ * Keith Smiley
+ * jeremyerb
+ * Fabrice Fontaine
+ * wenyg
+ * Aleksandr-Melnikov
+ * ayuseleznev
+ * chenguolong
+ * Dimo Markov
+ * dota17
+ * fanquake
+ * Jan Kasiak
+ * Kamil Rytarowski
+ * Mario Emmenlauer
+ * Michael Davidsaver
+ * mohuang
+ * Nick Grifka
+ * Nicolas J. Bouliane
+ * Paul Osborne
+ * Philip Homburg
+ * Wataru Ashihara
+ * William A Rowe Jr
+ * yangyongsheng
+
 
 If we have forgotten your name, please contact us.
index 03f0c01a15eccce5dad323ce25c8d58b736a99b3..092defbc4bedcdd2bdf3ed6833a0c3520f494631 100644 (file)
@@ -173,7 +173,8 @@ getopt_long(nargc, nargv, options, long_options, index)
 
        if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
                char *current_argv = nargv[optind++] + 2, *has_equal;
-               int i, current_argv_len, match = -1;
+               int i, match = -1;
+               size_t current_argv_len;
 
                if (*current_argv == '\0') {
                        return(-1);
@@ -184,11 +185,11 @@ getopt_long(nargc, nargv, options, long_options, index)
                } else
                        current_argv_len = strlen(current_argv);
 
-               for (i = 0; long_options[i].name; i++) { 
+               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) { 
+                       if (strlen(long_options[i].name) == current_argv_len) {
                                match = i;
                                break;
                        }
index 8cbf1902891f4d8c18e4fa0078a7b436a3dda093..3f3a0d2968dcb372f3d92b7cdbd18419a7ed4a3f 100644 (file)
 /* Define to 1 if the system has the type `struct sockaddr_storage'. */
 #define EVENT__HAVE_STRUCT_SOCKADDR_STORAGE 1
 
-/* Define to 1 if you have the <sys/devpoll.h> header file. */
-/* #undef EVENT__HAVE_SYS_DEVPOLL_H */
-
 /* Define to 1 if you have the <sys/epoll.h> header file. */
 /* #undef EVENT__HAVE_SYS_EPOLL_H */
 
 /* #undef EVENT__HAVE_WORKING_KQUEUE */
 
 /* Numeric representation of the version */
-#define EVENT__NUMERIC_VERSION 0x02010500
+#define EVENT__NUMERIC_VERSION 0x02010c00
 
 /* Name of package */
 #define EVENT__PACKAGE "libevent"
 #define EVENT__SIZEOF_VOID_P 4
 #endif
 
-/* Define to 1 if you have the ANSI C header files. */
-#define EVENT__STDC_HEADERS 1
+/* The size of `time_t`, as computed by sizeof. */
+#ifdef _WIN64
+#define EVENT__SIZEOF_TIME_T 8
+#else
+#define EVENT__SIZEOF_TIME_T 4
+#endif
 
 /* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
 #define EVENT__TIME_WITH_SYS_TIME 1
 
 /* Version number of package */
-#define EVENT__VERSION "2.1.5-beta"
-
-/* Define to appropriate substitue if compiler doesnt have __func__ */
-#define EVENT____func__ __FUNCTION__
-
-/* Define to empty if `const' does not conform to ANSI C. */
-/* #undef EVENT__const */
+#define EVENT__VERSION "2.1.12-stable"
 
 /* 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 _EVENT___cplusplus
 #define EVENT__inline __inline
-#endif
-
-/* Define to `int' if <sys/types.h> does not define. */
-/* #undef EVENT__pid_t */
 
 /* Define to `unsigned' if <sys/types.h> does not define. */
 /* #undef EVENT__size_t */
index a2338e692a1077dd903104a4b4dc620ec291b4a7..8729f6b92fe7584c4870900210e13c15ef72a623 100644 (file)
@@ -54,6 +54,7 @@
 #ifdef _WIN32
 #include <wincrypt.h>
 #include <process.h>
+#include <winerror.h>
 #else
 #include <fcntl.h>
 #include <unistd.h>
@@ -62,6 +63,9 @@
 #ifdef EVENT__HAVE_SYS_SYSCTL_H
 #include <sys/sysctl.h>
 #endif
+#ifdef EVENT__HAVE_SYS_RANDOM_H
+#include <sys/random.h>
+#endif
 #endif
 #include <limits.h>
 #include <stdlib.h>
@@ -89,7 +93,6 @@ static int rs_initialized;
 static struct arc4_stream rs;
 static pid_t arc4_stir_pid;
 static int arc4_count;
-static int arc4_seeded_ok;
 
 static inline unsigned char arc4_getbyte(void);
 
@@ -163,22 +166,15 @@ arc4_seed_win32(void)
                return -1;
        arc4_addrandom(buf, sizeof(buf));
        evutil_memclear_(buf, sizeof(buf));
-       arc4_seeded_ok = 1;
        return 0;
 }
 #endif
 
-#if defined(EVENT__HAVE_SYS_SYSCTL_H) && defined(EVENT__HAVE_SYSCTL)
-#if EVENT__HAVE_DECL_CTL_KERN && EVENT__HAVE_DECL_KERN_RANDOM && EVENT__HAVE_DECL_RANDOM_UUID
-#define TRY_SEED_SYSCTL_LINUX
+#if defined(EVENT__HAVE_GETRANDOM)
+#define TRY_SEED_GETRANDOM
 static int
-arc4_seed_sysctl_linux(void)
+arc4_seed_getrandom(void)
 {
-       /* Based on code by William Ahern, this function tries to use the
-        * RANDOM_UUID sysctl to get entropy from the kernel.  This can work
-        * even if /dev/urandom is inaccessible for some reason (e.g., we're
-        * running in a chroot). */
-       int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID };
        unsigned char buf[ADD_ENTROPY];
        size_t len, n;
        unsigned i;
@@ -189,7 +185,7 @@ arc4_seed_sysctl_linux(void)
        for (len = 0; len < sizeof(buf); len += n) {
                n = sizeof(buf) - len;
 
-               if (0 != sysctl(mib, 3, &buf[len], &n, NULL, 0))
+               if (0 == getrandom(&buf[len], n, 0))
                        return -1;
        }
        /* make sure that the buffer actually got set. */
@@ -201,11 +197,11 @@ arc4_seed_sysctl_linux(void)
 
        arc4_addrandom(buf, sizeof(buf));
        evutil_memclear_(buf, sizeof(buf));
-       arc4_seeded_ok = 1;
        return 0;
 }
-#endif
+#endif /* EVENT__HAVE_GETRANDOM */
 
+#if defined(EVENT__HAVE_SYS_SYSCTL_H) && defined(EVENT__HAVE_SYSCTL)
 #if EVENT__HAVE_DECL_CTL_KERN && EVENT__HAVE_DECL_KERN_ARND
 #define TRY_SEED_SYSCTL_BSD
 static int
@@ -241,7 +237,6 @@ arc4_seed_sysctl_bsd(void)
 
        arc4_addrandom(buf, sizeof(buf));
        evutil_memclear_(buf, sizeof(buf));
-       arc4_seeded_ok = 1;
        return 0;
 }
 #endif
@@ -287,7 +282,6 @@ arc4_seed_proc_sys_kernel_random_uuid(void)
        }
        evutil_memclear_(entropy, sizeof(entropy));
        evutil_memclear_(buf, sizeof(buf));
-       arc4_seeded_ok = 1;
        return 0;
 }
 #endif
@@ -311,7 +305,6 @@ static int arc4_seed_urandom_helper_(const char *fname)
                return -1;
        arc4_addrandom(buf, sizeof(buf));
        evutil_memclear_(buf, sizeof(buf));
-       arc4_seeded_ok = 1;
        return 0;
 }
 
@@ -347,6 +340,10 @@ arc4_seed(void)
        if (0 == arc4_seed_win32())
                ok = 1;
 #endif
+#ifdef TRY_SEED_GETRANDOM
+       if (0 == arc4_seed_getrandom())
+               ok = 1;
+#endif
 #ifdef TRY_SEED_URANDOM
        if (0 == arc4_seed_urandom())
                ok = 1;
@@ -356,12 +353,6 @@ arc4_seed(void)
            0 == arc4_seed_proc_sys_kernel_random_uuid())
                ok = 1;
 #endif
-#ifdef TRY_SEED_SYSCTL_LINUX
-       /* Apparently Linux is deprecating sysctl, and spewing warning
-        * messages when you try to use it. */
-       if (!ok && 0 == arc4_seed_sysctl_linux())
-               ok = 1;
-#endif
 #ifdef TRY_SEED_SYSCTL_BSD
        if (0 == arc4_seed_sysctl_bsd())
                ok = 1;
@@ -379,8 +370,7 @@ arc4_stir(void)
                rs_initialized = 1;
        }
 
-       arc4_seed();
-       if (!arc4_seeded_ok)
+       if (0 != arc4_seed())
                return -1;
 
        /*
index 57eeb940b91174203488c9c6ce96e377b640e200..bcfe937a60ce2c8d306803f060a2629bede2d5a6 100755 (executable)
@@ -1,4 +1,11 @@
 #!/bin/sh
+
+MAKE=make
+if command -v gmake >/dev/null 2>/dev/null; then
+  MAKE=gmake
+fi
+$MAKE maintainer-clean >/dev/null 2>/dev/null
+
 if [ -x "`which autoreconf 2>/dev/null`" ] ; then
    exec autoreconf -ivf
 fi
index a1a2b988c13a38346cbc80333af9dd097fa2bdd9..3524b3504d431941b0e84a1ea5db48d5db651180 100644 (file)
@@ -95,6 +95,7 @@
 #include "evthread-internal.h"
 #include "evbuffer-internal.h"
 #include "bufferevent-internal.h"
+#include "event-internal.h"
 
 /* some systems do not have MAP_FAILED */
 #ifndef MAP_FAILED
@@ -184,7 +185,7 @@ evbuffer_chain_new(size_t size)
        /* this way we can manipulate the buffer to different addresses,
         * which is required for mmap for example.
         */
-       chain->buffer = EVBUFFER_CHAIN_EXTRA(u_char, chain);
+       chain->buffer = EVBUFFER_CHAIN_EXTRA(unsigned char, chain);
 
        chain->refcnt = 1;
 
@@ -522,8 +523,8 @@ evbuffer_invoke_callbacks_(struct evbuffer *buffer)
                        evbuffer_incref_and_lock_(buffer);
                        if (buffer->parent)
                                bufferevent_incref_(buffer->parent);
+                       EVBUFFER_UNLOCK(buffer);
                }
-               EVBUFFER_UNLOCK(buffer);
        }
 
        evbuffer_run_callbacks(buffer, 0);
@@ -682,8 +683,8 @@ evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size,
                if ((chain = evbuffer_expand_singlechain(buf, size)) == NULL)
                        goto done;
 
-               vec[0].iov_base = CHAIN_SPACE_PTR(chain);
-               vec[0].iov_len = (size_t) CHAIN_SPACE_LEN(chain);
+               vec[0].iov_base = (void *)CHAIN_SPACE_PTR(chain);
+               vec[0].iov_len = (size_t)CHAIN_SPACE_LEN(chain);
                EVUTIL_ASSERT(size<0 || (size_t)vec[0].iov_len >= (size_t)size);
                n = 1;
        } else {
@@ -703,13 +704,17 @@ static int
 advance_last_with_data(struct evbuffer *buf)
 {
        int n = 0;
+       struct evbuffer_chain **chainp = buf->last_with_datap;
+
        ASSERT_EVBUFFER_LOCKED(buf);
 
-       if (!*buf->last_with_datap)
+       if (!*chainp)
                return 0;
 
-       while ((*buf->last_with_datap)->next && (*buf->last_with_datap)->next->off) {
-               buf->last_with_datap = &(*buf->last_with_datap)->next;
+       while ((*chainp)->next) {
+               chainp = &(*chainp)->next;
+               if ((*chainp)->off)
+                       buf->last_with_datap = chainp;
                ++n;
        }
        return n;
@@ -732,7 +737,7 @@ evbuffer_commit_space(struct evbuffer *buf,
                result = 0;
                goto done;
        } else if (n_vecs == 1 &&
-           (buf->last && vec[0].iov_base == (void*)CHAIN_SPACE_PTR(buf->last))) {
+           (buf->last && vec[0].iov_base == (void *)CHAIN_SPACE_PTR(buf->last))) {
                /* The user only got or used one chain; it might not
                 * be the first one with space in it. */
                if ((size_t)vec[0].iov_len > (size_t)CHAIN_SPACE_LEN(buf->last))
@@ -758,7 +763,7 @@ evbuffer_commit_space(struct evbuffer *buf,
        for (i=0; i<n_vecs; ++i) {
                if (!chain)
                        goto done;
-               if (vec[i].iov_base != (void*)CHAIN_SPACE_PTR(chain) ||
+               if (vec[i].iov_base != (void *)CHAIN_SPACE_PTR(chain) ||
                    (size_t)vec[i].iov_len > CHAIN_SPACE_LEN(chain))
                        goto done;
                chain = chain->next;
@@ -883,11 +888,16 @@ COPY_CHAIN(struct evbuffer *dst, struct evbuffer *src)
 static void
 APPEND_CHAIN(struct evbuffer *dst, struct evbuffer *src)
 {
+       struct evbuffer_chain **chp;
+
        ASSERT_EVBUFFER_LOCKED(dst);
        ASSERT_EVBUFFER_LOCKED(src);
-       dst->last->next = src->first;
+
+       chp = evbuffer_free_trailing_empty_chains(dst);
+       *chp = src->first;
+
        if (src->last_with_datap == &src->first)
-               dst->last_with_datap = &dst->last->next;
+               dst->last_with_datap = chp;
        else
                dst->last_with_datap = src->last_with_datap;
        dst->last = src->last;
@@ -1141,7 +1151,7 @@ evbuffer_drain(struct evbuffer *buf, size_t len)
                }
 
                buf->first = chain;
-               EVUTIL_ASSERT(chain && remaining <= chain->off);
+               EVUTIL_ASSERT(remaining <= chain->off);
                chain->misalign += remaining;
                chain->off -= remaining;
        }
@@ -1293,7 +1303,7 @@ evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst,
                chain = chain->next;
        }
 
-       if (nread) {
+       if (chain != src->first) {
                /* we can remove the chain */
                struct evbuffer_chain **chp;
                chp = evbuffer_free_trailing_empty_chains(dst);
@@ -1411,9 +1421,11 @@ evbuffer_pullup(struct evbuffer *buf, ev_ssize_t size)
        for (; chain != NULL && (size_t)size >= chain->off; chain = next) {
                next = chain->next;
 
-               memcpy(buffer, chain->buffer + chain->misalign, chain->off);
-               size -= chain->off;
-               buffer += chain->off;
+               if (chain->buffer) {
+                       memcpy(buffer, chain->buffer + chain->misalign, chain->off);
+                       size -= chain->off;
+                       buffer += chain->off;
+               }
                if (chain == last_with_data)
                        removed_last_with_data = 1;
                if (&chain->next == buf->last_with_datap)
@@ -1529,11 +1541,11 @@ evbuffer_find_eol_char(struct evbuffer_ptr *it)
        return (-1);
 }
 
-static inline int
+static inline size_t
 evbuffer_strspn(
        struct evbuffer_ptr *ptr, const char *chrset)
 {
-       int count = 0;
+       size_t count = 0;
        struct evbuffer_chain *chain = ptr->internal_.chain;
        size_t i = ptr->internal_.pos_in_chain;
 
@@ -1732,7 +1744,11 @@ evbuffer_add(struct evbuffer *buf, const void *data_in, size_t datlen)
                goto done;
        }
 
-       chain = buf->last;
+       if (*buf->last_with_datap == NULL) {
+               chain = buf->last;
+       } else {
+               chain = *buf->last_with_datap;
+       }
 
        /* If there are no chains allocated for this buffer, allocate one
         * big enough to hold all the data. */
@@ -1815,6 +1831,10 @@ evbuffer_prepend(struct evbuffer *buf, const void *data, size_t datlen)
 
        EVBUFFER_LOCK(buf);
 
+       if (datlen == 0) {
+               result = 0;
+               goto done;
+       }
        if (buf->freeze_start) {
                goto done;
        }
@@ -1868,7 +1888,7 @@ evbuffer_prepend(struct evbuffer *buf, const void *data, size_t datlen)
        if ((tmp = evbuffer_chain_new(datlen)) == NULL)
                goto done;
        buf->first = tmp;
-       if (buf->last_with_datap == &buf->first)
+       if (buf->last_with_datap == &buf->first && chain->off)
                buf->last_with_datap = &tmp->next;
 
        tmp->next = chain;
@@ -1879,7 +1899,7 @@ evbuffer_prepend(struct evbuffer *buf, const void *data, size_t datlen)
 
        memcpy(tmp->buffer + tmp->misalign, data, datlen);
        buf->total_len += datlen;
-       buf->n_add_for_cb += (size_t)chain->misalign;
+       buf->n_add_for_cb += datlen;
 
 out:
        evbuffer_invoke_callbacks_(buf);
@@ -1974,8 +1994,7 @@ evbuffer_expand_singlechain(struct evbuffer *buf, size_t datlen)
        /* Would expanding this chunk be affordable and worthwhile? */
        if (CHAIN_SPACE_LEN(chain) < chain->buffer_len / 8 ||
            chain->off > MAX_TO_COPY_IN_EXPAND ||
-           (datlen < EVBUFFER_CHAIN_MAX &&
-               EVBUFFER_CHAIN_MAX - datlen >= chain->off)) {
+               datlen >= (EVBUFFER_CHAIN_MAX - chain->off)) {
                /* It's not worth resizing this chain. Can the next one be
                 * used? */
                if (chain->next && CHAIN_SPACE_LEN(chain->next) >= datlen) {
@@ -2219,16 +2238,18 @@ evbuffer_read_setup_vecs_(struct evbuffer *buf, ev_ssize_t howmuch,
        so_far = 0;
        /* Let firstchain be the first chain with any space on it */
        firstchainp = buf->last_with_datap;
+       EVUTIL_ASSERT(*firstchainp);
        if (CHAIN_SPACE_LEN(*firstchainp) == 0) {
                firstchainp = &(*firstchainp)->next;
        }
 
        chain = *firstchainp;
+       EVUTIL_ASSERT(chain);
        for (i = 0; i < n_vecs_avail && so_far < (size_t)howmuch; ++i) {
                size_t avail = (size_t) CHAIN_SPACE_LEN(chain);
                if (avail > (howmuch - so_far) && exact)
                        avail = howmuch - so_far;
-               vecs[i].iov_base = CHAIN_SPACE_PTR(chain);
+               vecs[i].iov_base = (void *)CHAIN_SPACE_PTR(chain);
                vecs[i].iov_len = avail;
                so_far += avail;
                chain = chain->next;
@@ -2457,7 +2478,7 @@ evbuffer_write_sendfile(struct evbuffer *buffer, evutil_socket_t dest_fd,
        ev_off_t len = chain->off;
 #elif defined(SENDFILE_IS_LINUX) || defined(SENDFILE_IS_SOLARIS)
        ev_ssize_t res;
-       ev_off_t offset = chain->misalign;
+       off_t offset = chain->misalign;
 #endif
 
        ASSERT_EVBUFFER_LOCKED(buffer);
@@ -2781,8 +2802,8 @@ evbuffer_peek(struct evbuffer *buffer, ev_ssize_t len,
                    - start_at->internal_.pos_in_chain;
                idx = 1;
                if (n_vec > 0) {
-                       vec[0].iov_base = chain->buffer + chain->misalign
-                           + start_at->internal_.pos_in_chain;
+                       vec[0].iov_base = (void *)(chain->buffer + chain->misalign
+                           + start_at->internal_.pos_in_chain);
                        vec[0].iov_len = len_so_far;
                }
                chain = chain->next;
@@ -2803,7 +2824,7 @@ evbuffer_peek(struct evbuffer *buffer, ev_ssize_t len,
                if (len >= 0 && len_so_far >= len)
                        break;
                if (idx<n_vec) {
-                       vec[idx].iov_base = chain->buffer + chain->misalign;
+                       vec[idx].iov_base = (void *)(chain->buffer + chain->misalign);
                        vec[idx].iov_len = chain->off;
                } else if (len<0) {
                        break;
@@ -2909,7 +2930,7 @@ evbuffer_add_reference(struct evbuffer *outbuf,
        if (!chain)
                return (-1);
        chain->flags |= EVBUFFER_REFERENCE | EVBUFFER_IMMUTABLE;
-       chain->buffer = (u_char *)data;
+       chain->buffer = (unsigned char *)data;
        chain->buffer_len = datlen;
        chain->off = datlen;
 
@@ -3190,7 +3211,6 @@ evbuffer_add_file_segment(struct evbuffer *buf,
                        }
                }
        }
-       ++seg->refcnt;
        EVLOCK_UNLOCK(seg->lock, 0);
 
        if (buf->freeze_end)
@@ -3254,6 +3274,9 @@ evbuffer_add_file_segment(struct evbuffer *buf,
                chain->off = length;
        }
 
+       EVLOCK_LOCK(seg->lock, 0);
+       ++seg->refcnt;
+       EVLOCK_UNLOCK(seg->lock, 0);
        extra->segment = seg;
        buf->n_add_for_cb += length;
        evbuffer_chain_insert(buf, chain);
@@ -3285,7 +3308,7 @@ evbuffer_add_file(struct evbuffer *buf, int fd, ev_off_t offset, ev_off_t length
        return r;
 }
 
-void
+int
 evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg)
 {
        EVBUFFER_LOCK(buffer);
@@ -3296,10 +3319,15 @@ evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg)
        if (cb) {
                struct evbuffer_cb_entry *ent =
                    evbuffer_add_cb(buffer, NULL, cbarg);
+               if (!ent) {
+                       EVBUFFER_UNLOCK(buffer);
+                       return -1;
+               }
                ent->cb.cb_obsolete = cb;
                ent->flags |= EVBUFFER_CB_OBSOLETE;
        }
        EVBUFFER_UNLOCK(buffer);
+       return 0;
 }
 
 struct evbuffer_cb_entry *
index 2d76a90e7702c5ba69ab8e631ba4eb9c25e77b7d..2af0c49cc64b3a8ca547c8354bab2452f6c6a2e9 100644 (file)
@@ -44,6 +44,7 @@
 #include "mm-internal.h"
 
 #include <winsock2.h>
+#include <winerror.h>
 #include <windows.h>
 #include <stdio.h>
 
index 134bb337521c128a7d2aa08561736e49cc5a7ac6..87ab9ad9c0f731b49e37c05c28b705fcaf73c76a 100644 (file)
@@ -40,6 +40,17 @@ extern "C" {
 #include "ratelim-internal.h"
 #include "event2/bufferevent_struct.h"
 
+#include "ipv6-internal.h"
+#ifdef _WIN32
+#include <ws2tcpip.h>
+#endif
+#ifdef EVENT__HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef EVENT__HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+
 /* These flags are reasons that we might be declining to actually enable
    reading or writing on a bufferevent.
  */
@@ -205,6 +216,20 @@ struct bufferevent_private {
 
        /** Rate-limiting information for this bufferevent */
        struct bufferevent_rate_limit *rate_limiting;
+
+       /* Saved conn_addr, to extract IP address from it.
+        *
+        * Because some servers may reset/close connection without waiting clients,
+        * in that case we can't extract IP address even in close_cb.
+        * So we need to save it, just after we connected to remote server, or
+        * after resolving (to avoid extra dns requests during retrying, since UDP
+        * is slow) */
+       union {
+               struct sockaddr_in6 in6;
+               struct sockaddr_in in;
+       } conn_address;
+
+       struct evdns_getaddrinfo_request *dns_request;
 };
 
 /** Possible operations for a control callback. */
@@ -281,6 +306,13 @@ extern const struct bufferevent_ops bufferevent_ops_pair;
 #define BEV_IS_FILTER(bevp) ((bevp)->be_ops == &bufferevent_ops_filter)
 #define BEV_IS_PAIR(bevp) ((bevp)->be_ops == &bufferevent_ops_pair)
 
+#if defined(EVENT__HAVE_OPENSSL)
+extern const struct bufferevent_ops bufferevent_ops_openssl;
+#define BEV_IS_OPENSSL(bevp) ((bevp)->be_ops == &bufferevent_ops_openssl)
+#else
+#define BEV_IS_OPENSSL(bevp) 0
+#endif
+
 #ifdef _WIN32
 extern const struct bufferevent_ops bufferevent_ops_async;
 #define BEV_IS_ASYNC(bevp) ((bevp)->be_ops == &bufferevent_ops_async)
@@ -289,13 +321,16 @@ extern const struct bufferevent_ops bufferevent_ops_async;
 #endif
 
 /** Initialize the shared parts of a bufferevent. */
+EVENT2_EXPORT_SYMBOL
 int bufferevent_init_common_(struct bufferevent_private *, struct event_base *, const struct bufferevent_ops *, enum bufferevent_options options);
 
 /** For internal use: temporarily stop all reads on bufev, until the conditions
  * in 'what' are over. */
+EVENT2_EXPORT_SYMBOL
 void bufferevent_suspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what);
 /** For internal use: clear the conditions 'what' on bufev, and re-enable
  * reading if there are no conditions left. */
+EVENT2_EXPORT_SYMBOL
 void bufferevent_unsuspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what);
 
 /** For internal use: temporarily stop all writes on bufev, until the conditions
@@ -322,32 +357,42 @@ void bufferevent_unsuspend_write_(struct bufferevent *bufev, bufferevent_suspend
   @return 0 if successful, or -1 if an error occurred
   @see bufferevent_disable()
  */
+EVENT2_EXPORT_SYMBOL
 int bufferevent_disable_hard_(struct bufferevent *bufev, short event);
 
 /** Internal: Set up locking on a bufferevent.  If lock is set, use it.
  * Otherwise, use a new lock. */
+EVENT2_EXPORT_SYMBOL
 int bufferevent_enable_locking_(struct bufferevent *bufev, void *lock);
-/** Internal: Increment the reference count on bufev. */
-void bufferevent_incref_(struct bufferevent *bufev);
+/** Internal: backwards compat macro for the now public function
+ * Increment the reference count on bufev. */
+#define bufferevent_incref_(bufev) bufferevent_incref(bufev)
 /** Internal: Lock bufev and increase its reference count.
  * unlocking it otherwise. */
+EVENT2_EXPORT_SYMBOL
 void bufferevent_incref_and_lock_(struct bufferevent *bufev);
-/** Internal: Decrement the reference count on bufev.  Returns 1 if it freed
+/** Internal: backwards compat macro for the now public function
+ * Decrement the reference count on bufev.  Returns 1 if it freed
  * the bufferevent.*/
-int bufferevent_decref_(struct bufferevent *bufev);
+#define bufferevent_decref_(bufev) bufferevent_decref(bufev)
+
 /** Internal: Drop the reference count on bufev, freeing as necessary, and
  * unlocking it otherwise.  Returns 1 if it freed the bufferevent. */
+EVENT2_EXPORT_SYMBOL
 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. Ignores watermarks. */
+EVENT2_EXPORT_SYMBOL
 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. Ignores watermarks. */
+EVENT2_EXPORT_SYMBOL
 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.
  * See bufferevent_trigger_event for meaning of "options". */
+EVENT2_EXPORT_SYMBOL
 void bufferevent_run_eventcb_(struct bufferevent *bufev, short what, int options);
 
 /** Internal: Run or schedule (if deferred or options contain
@@ -371,6 +416,7 @@ bufferevent_trigger_nolock_(struct bufferevent *bufev, short iotype, int options
 
 /** Internal: Add the event 'ev' with timeout tv, unless tv is set to 0, in
  * which case add ev with no timeout. */
+EVENT2_EXPORT_SYMBOL
 int bufferevent_add_event_(struct event *ev, const struct timeval *tv);
 
 /* =========
@@ -380,15 +426,33 @@ int bufferevent_add_event_(struct event *ev, const struct timeval *tv);
 /** Internal use: Set up the ev_read and ev_write callbacks so that
  * the other "generic_timeout" functions will work on it.  Call this from
  * the constructor function. */
+EVENT2_EXPORT_SYMBOL
 void bufferevent_init_generic_timeout_cbs_(struct bufferevent *bev);
 /** Internal use: Add or delete the generic timeout events as appropriate.
  * (If an event is enabled and a timeout is set, we add the event.  Otherwise
  * we delete it.)  Call this from anything that changes the timeout values,
  * that enabled EV_READ or EV_WRITE, or that disables EV_READ or EV_WRITE. */
+EVENT2_EXPORT_SYMBOL
 int bufferevent_generic_adj_timeouts_(struct bufferevent *bev);
+EVENT2_EXPORT_SYMBOL
+int bufferevent_generic_adj_existing_timeouts_(struct bufferevent *bev);
 
+EVENT2_EXPORT_SYMBOL
 enum bufferevent_options bufferevent_get_options_(struct bufferevent *bev);
 
+EVENT2_EXPORT_SYMBOL
+const struct sockaddr*
+bufferevent_socket_get_conn_address_(struct bufferevent *bev);
+
+EVENT2_EXPORT_SYMBOL
+void
+bufferevent_socket_set_conn_address_fd_(struct bufferevent *bev, evutil_socket_t fd);
+
+EVENT2_EXPORT_SYMBOL
+void
+bufferevent_socket_set_conn_address_(struct bufferevent *bev, struct sockaddr *addr, size_t addrlen);
+
+
 /** Internal use: We have just successfully read data into an inbuf, so
  * reset the read timeout (if any). */
 #define BEV_RESET_GENERIC_READ_TIMEOUT(bev)                            \
@@ -433,11 +497,15 @@ enum bufferevent_options bufferevent_get_options_(struct bufferevent *bev);
 
 /* ==== For rate-limiting. */
 
+EVENT2_EXPORT_SYMBOL
 int bufferevent_decrement_write_buckets_(struct bufferevent_private *bev,
     ev_ssize_t bytes);
+EVENT2_EXPORT_SYMBOL
 int bufferevent_decrement_read_buckets_(struct bufferevent_private *bev,
     ev_ssize_t bytes);
+EVENT2_EXPORT_SYMBOL
 ev_ssize_t bufferevent_get_read_max_(struct bufferevent_private *bev);
+EVENT2_EXPORT_SYMBOL
 ev_ssize_t bufferevent_get_write_max_(struct bufferevent_private *bev);
 
 int bufferevent_ratelim_init_(struct bufferevent_private *bev);
index d298d0b3f01387aae7a453ecff9b9193e2b94d76..08c0486c087d5cf7b5859d34965cff855b2436d5 100644 (file)
@@ -45,7 +45,6 @@
 #ifdef _WIN32
 #include <winsock2.h>
 #endif
-#include <errno.h>
 
 #include "event2/util.h"
 #include "event2/buffer.h"
@@ -67,8 +66,7 @@ static void bufferevent_finalize_cb_(struct event_callback *evcb, void *arg_);
 void
 bufferevent_suspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what)
 {
-       struct bufferevent_private *bufev_private =
-           EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+       struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
        BEV_LOCK(bufev);
        if (!bufev_private->read_suspended)
                bufev->be_ops->disable(bufev, EV_READ);
@@ -79,8 +77,7 @@ bufferevent_suspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags w
 void
 bufferevent_unsuspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what)
 {
-       struct bufferevent_private *bufev_private =
-           EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+       struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
        BEV_LOCK(bufev);
        bufev_private->read_suspended &= ~what;
        if (!bufev_private->read_suspended && (bufev->enabled & EV_READ))
@@ -91,8 +88,7 @@ bufferevent_unsuspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags
 void
 bufferevent_suspend_write_(struct bufferevent *bufev, bufferevent_suspend_flags what)
 {
-       struct bufferevent_private *bufev_private =
-           EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+       struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
        BEV_LOCK(bufev);
        if (!bufev_private->write_suspended)
                bufev->be_ops->disable(bufev, EV_WRITE);
@@ -103,8 +99,7 @@ bufferevent_suspend_write_(struct bufferevent *bufev, bufferevent_suspend_flags
 void
 bufferevent_unsuspend_write_(struct bufferevent *bufev, bufferevent_suspend_flags what)
 {
-       struct bufferevent_private *bufev_private =
-           EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+       struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
        BEV_LOCK(bufev);
        bufev_private->write_suspended &= ~what;
        if (!bufev_private->write_suspended && (bufev->enabled & EV_WRITE))
@@ -112,6 +107,28 @@ bufferevent_unsuspend_write_(struct bufferevent *bufev, bufferevent_suspend_flag
        BEV_UNLOCK(bufev);
 }
 
+/**
+ * Sometimes bufferevent's implementation can overrun high watermarks
+ * (one of examples is openssl) and in this case if the read callback
+ * will not handle enough data do over condition above the read
+ * callback will never be called again (due to suspend above).
+ *
+ * To avoid this we are scheduling read callback again here, but only
+ * from the user callback to avoid multiple scheduling:
+ * - when the data had been added to it
+ * - when the data had been drained from it (user specified read callback)
+ */
+static void bufferevent_inbuf_wm_check(struct bufferevent *bev)
+{
+       if (!bev->wm_read.high)
+               return;
+       if (!(bev->enabled & EV_READ))
+               return;
+       if (evbuffer_get_length(bev->input) < bev->wm_read.high)
+               return;
+
+       bufferevent_trigger(bev, EV_READ, BEV_OPT_DEFER_CALLBACKS);
+}
 
 /* Callback to implement watermarks on the input buffer.  Only enabled
  * if the watermark is set. */
@@ -148,6 +165,7 @@ bufferevent_run_deferred_callbacks_locked(struct event_callback *cb, void *arg)
        if (bufev_private->readcb_pending && bufev->readcb) {
                bufev_private->readcb_pending = 0;
                bufev->readcb(bufev, bufev->cbarg);
+               bufferevent_inbuf_wm_check(bufev);
        }
        if (bufev_private->writecb_pending && bufev->writecb) {
                bufev_private->writecb_pending = 0;
@@ -188,6 +206,7 @@ bufferevent_run_deferred_callbacks_unlocked(struct event_callback *cb, void *arg
                void *cbarg = bufev->cbarg;
                bufev_private->readcb_pending = 0;
                UNLOCKED(readcb(bufev, cbarg));
+               bufferevent_inbuf_wm_check(bufev);
        }
        if (bufev_private->writecb_pending && bufev->writecb) {
                bufferevent_data_cb writecb = bufev->writecb;
@@ -222,8 +241,7 @@ void
 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);
+       struct bufferevent_private *p = BEV_UPCAST(bufev);
        if (bufev->readcb == NULL)
                return;
        if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) {
@@ -231,6 +249,7 @@ bufferevent_run_readcb_(struct bufferevent *bufev, int options)
                SCHEDULE_DEFERRED(p);
        } else {
                bufev->readcb(bufev, bufev->cbarg);
+               bufferevent_inbuf_wm_check(bufev);
        }
 }
 
@@ -238,8 +257,7 @@ void
 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);
+       struct bufferevent_private *p = BEV_UPCAST(bufev);
        if (bufev->writecb == NULL)
                return;
        if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) {
@@ -267,8 +285,7 @@ void
 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);
+       struct bufferevent_private *p = BEV_UPCAST(bufev);
        if (bufev->errorcb == NULL)
                return;
        if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) {
@@ -298,14 +315,12 @@ bufferevent_init_common_(struct bufferevent_private *bufev_private,
 
        if (!bufev->input) {
                if ((bufev->input = evbuffer_new()) == NULL)
-                       return -1;
+                       goto err;
        }
 
        if (!bufev->output) {
-               if ((bufev->output = evbuffer_new()) == NULL) {
-                       evbuffer_free(bufev->input);
-                       return -1;
-               }
+               if ((bufev->output = evbuffer_new()) == NULL)
+                       goto err;
        }
 
        bufev_private->refcnt = 1;
@@ -317,7 +332,8 @@ bufferevent_init_common_(struct bufferevent_private *bufev_private,
 
        bufev->be_ops = ops;
 
-       bufferevent_ratelim_init_(bufev_private);
+       if (bufferevent_ratelim_init_(bufev_private))
+               goto err;
 
        /*
         * Set to EV_WRITE so that using bufferevent_write is going to
@@ -328,20 +344,14 @@ bufferevent_init_common_(struct bufferevent_private *bufev_private,
 
 #ifndef EVENT__DISABLE_THREAD_SUPPORT
        if (options & BEV_OPT_THREADSAFE) {
-               if (bufferevent_enable_locking_(bufev, NULL) < 0) {
-                       /* cleanup */
-                       evbuffer_free(bufev->input);
-                       evbuffer_free(bufev->output);
-                       bufev->input = NULL;
-                       bufev->output = NULL;
-                       return -1;
-               }
+               if (bufferevent_enable_locking_(bufev, NULL) < 0)
+                       goto err;
        }
 #endif
        if ((options & (BEV_OPT_DEFER_CALLBACKS|BEV_OPT_UNLOCK_CALLBACKS))
            == BEV_OPT_UNLOCK_CALLBACKS) {
                event_warnx("UNLOCK_CALLBACKS requires DEFER_CALLBACKS");
-               return -1;
+               goto err;
        }
        if (options & BEV_OPT_UNLOCK_CALLBACKS)
                event_deferred_cb_init_(
@@ -362,6 +372,17 @@ bufferevent_init_common_(struct bufferevent_private *bufev_private,
        evbuffer_set_parent_(bufev->output, bufev);
 
        return 0;
+
+err:
+       if (bufev->input) {
+               evbuffer_free(bufev->input);
+               bufev->input = NULL;
+       }
+       if (bufev->output) {
+               evbuffer_free(bufev->output);
+               bufev->output = NULL;
+       }
+       return -1;
 }
 
 void
@@ -460,8 +481,7 @@ bufferevent_read_buffer(struct bufferevent *bufev, struct evbuffer *buf)
 int
 bufferevent_enable(struct bufferevent *bufev, short event)
 {
-       struct bufferevent_private *bufev_private =
-           EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+       struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
        short impl_events = event;
        int r = 0;
 
@@ -475,6 +495,8 @@ bufferevent_enable(struct bufferevent *bufev, short event)
 
        if (impl_events && bufev->be_ops->enable(bufev, impl_events) < 0)
                r = -1;
+       if (r)
+               event_debug(("%s: cannot enable 0x%hx on %p", __func__, event, bufev));
 
        bufferevent_decref_and_unlock_(bufev);
        return r;
@@ -534,8 +556,7 @@ int
 bufferevent_disable_hard_(struct bufferevent *bufev, short event)
 {
        int r = 0;
-       struct bufferevent_private *bufev_private =
-           EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+       struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
 
        BEV_LOCK(bufev);
        bufev->enabled &= ~event;
@@ -558,6 +579,8 @@ bufferevent_disable(struct bufferevent *bufev, short event)
 
        if (bufev->be_ops->disable(bufev, event) < 0)
                r = -1;
+       if (r)
+               event_debug(("%s: cannot disable 0x%hx on %p", __func__, event, bufev));
 
        BEV_UNLOCK(bufev);
        return r;
@@ -571,8 +594,7 @@ void
 bufferevent_setwatermark(struct bufferevent *bufev, short events,
     size_t lowmark, size_t highmark)
 {
-       struct bufferevent_private *bufev_private =
-           EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+       struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
 
        BEV_LOCK(bufev);
        if (events & EV_WRITE) {
@@ -657,8 +679,7 @@ bufferevent_flush(struct bufferevent *bufev,
 void
 bufferevent_incref_and_lock_(struct bufferevent *bufev)
 {
-       struct bufferevent_private *bufev_private =
-           BEV_UPCAST(bufev);
+       struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
        BEV_LOCK(bufev);
        ++bufev_private->refcnt;
 }
@@ -684,8 +705,7 @@ bufferevent_transfer_lock_ownership_(struct bufferevent *donor,
 int
 bufferevent_decref_and_unlock_(struct bufferevent *bufev)
 {
-       struct bufferevent_private *bufev_private =
-           EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+       struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
        int n_cbs = 0;
 #define MAX_CBS 16
        struct event_callback *cbs[MAX_CBS];
@@ -728,8 +748,7 @@ bufferevent_finalize_cb_(struct event_callback *evcb, void *arg_)
 {
        struct bufferevent *bufev = arg_;
        struct bufferevent *underlying;
-       struct bufferevent_private *bufev_private =
-           EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+       struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
 
        BEV_LOCK(bufev);
        underlying = bufferevent_get_underlying(bufev);
@@ -777,7 +796,7 @@ bufferevent_finalize_cb_(struct event_callback *evcb, void *arg_)
 }
 
 int
-bufferevent_decref_(struct bufferevent *bufev)
+bufferevent_decref(struct bufferevent *bufev)
 {
        BEV_LOCK(bufev);
        return bufferevent_decref_and_unlock_(bufev);
@@ -793,11 +812,14 @@ bufferevent_free(struct bufferevent *bufev)
 }
 
 void
-bufferevent_incref_(struct bufferevent *bufev)
+bufferevent_incref(struct bufferevent *bufev)
 {
-       struct bufferevent_private *bufev_private =
-           EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+       struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
 
+       /* XXX: now that this function is public, we might want to
+        * - return the count from this function
+        * - create a new function to atomically grab the current refcount
+        */
        BEV_LOCK(bufev);
        ++bufev_private->refcnt;
        BEV_UNLOCK(bufev);
@@ -848,6 +870,8 @@ bufferevent_setfd(struct bufferevent *bev, evutil_socket_t fd)
        BEV_LOCK(bev);
        if (bev->be_ops->ctrl)
                res = bev->be_ops->ctrl(bev, BEV_CTRL_SET_FD, &d);
+       if (res)
+               event_debug(("%s: cannot set fd for %p to "EV_SOCK_FMT, __func__, bev, fd));
        BEV_UNLOCK(bev);
        return res;
 }
@@ -861,6 +885,8 @@ bufferevent_getfd(struct bufferevent *bev)
        BEV_LOCK(bev);
        if (bev->be_ops->ctrl)
                res = bev->be_ops->ctrl(bev, BEV_CTRL_GET_FD, &d);
+       if (res)
+               event_debug(("%s: cannot get fd for %p", __func__, bev));
        BEV_UNLOCK(bev);
        return (res<0) ? -1 : d.fd;
 }
@@ -868,8 +894,7 @@ bufferevent_getfd(struct bufferevent *bev)
 enum bufferevent_options
 bufferevent_get_options_(struct bufferevent *bev)
 {
-       struct bufferevent_private *bev_p =
-           EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+       struct bufferevent_private *bev_p = BEV_UPCAST(bev);
        enum bufferevent_options options;
 
        BEV_LOCK(bev);
@@ -945,8 +970,7 @@ int
 bufferevent_generic_adj_timeouts_(struct bufferevent *bev)
 {
        const short enabled = bev->enabled;
-       struct bufferevent_private *bev_p =
-           EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+       struct bufferevent_private *bev_p = BEV_UPCAST(bev);
        int r1=0, r2=0;
        if ((enabled & EV_READ) && !bev_p->read_suspended &&
            evutil_timerisset(&bev->timeout_read))
@@ -965,10 +989,33 @@ bufferevent_generic_adj_timeouts_(struct bufferevent *bev)
        return 0;
 }
 
+int
+bufferevent_generic_adj_existing_timeouts_(struct bufferevent *bev)
+{
+       int r = 0;
+       if (event_pending(&bev->ev_read, EV_READ, NULL)) {
+               if (evutil_timerisset(&bev->timeout_read)) {
+                           if (bufferevent_add_event_(&bev->ev_read, &bev->timeout_read) < 0)
+                                   r = -1;
+               } else {
+                       event_remove_timer(&bev->ev_read);
+               }
+       }
+       if (event_pending(&bev->ev_write, EV_WRITE, NULL)) {
+               if (evutil_timerisset(&bev->timeout_write)) {
+                       if (bufferevent_add_event_(&bev->ev_write, &bev->timeout_write) < 0)
+                               r = -1;
+               } else {
+                       event_remove_timer(&bev->ev_write);
+               }
+       }
+       return r;
+}
+
 int
 bufferevent_add_event_(struct event *ev, const struct timeval *tv)
 {
-       if (tv->tv_sec == 0 && tv->tv_usec == 0)
+       if (!evutil_timerisset(tv))
                return event_add(ev, NULL);
        else
                return event_add(ev, tv);
index 6395e57a9f0c67faac04cc619dbafc7379b9aad5..40c7c5e8d0d34fac08ca5a7beb4df76ae5474afc 100644 (file)
@@ -46,6 +46,7 @@
 
 #ifdef _WIN32
 #include <winsock2.h>
+#include <winerror.h>
 #include <ws2tcpip.h>
 #endif
 
@@ -100,11 +101,32 @@ const struct bufferevent_ops bufferevent_ops_async = {
        be_async_ctrl,
 };
 
+static inline void
+be_async_run_eventcb(struct bufferevent *bev, short what, int options)
+{ bufferevent_run_eventcb_(bev, what, options|BEV_TRIG_DEFER_CALLBACKS); }
+
+static inline void
+be_async_trigger_nolock(struct bufferevent *bev, short what, int options)
+{ bufferevent_trigger_nolock_(bev, what, options|BEV_TRIG_DEFER_CALLBACKS); }
+
+static inline int
+fatal_error(int err)
+{
+       switch (err) {
+               /* We may have already associated this fd with a port.
+                * Let's hope it's this port, and that the error code
+                * for doing this neer changes. */
+               case ERROR_INVALID_PARAMETER:
+                       return 0;
+       }
+       return 1;
+}
+
 static inline struct bufferevent_async *
 upcast(struct bufferevent *bev)
 {
        struct bufferevent_async *bev_a;
-       if (bev->be_ops != &bufferevent_ops_async)
+       if (!BEV_IS_ASYNC(bev))
                return NULL;
        bev_a = EVUTIL_UPCAST(bev, struct bufferevent_async, bev.bev);
        return bev_a;
@@ -217,7 +239,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, 0);
+               be_async_run_eventcb(bev, BEV_EVENT_ERROR, 0);
        } else {
                beva->write_in_progress = at_most;
                bufferevent_decrement_write_buckets_(&beva->bev, at_most);
@@ -270,7 +292,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, 0);
+               be_async_run_eventcb(bev, BEV_EVENT_ERROR, 0);
                bufferevent_decref_(bev);
        } else {
                beva->read_in_progress = at_most;
@@ -381,10 +403,10 @@ be_async_destruct(struct bufferevent *bev)
        bev_async_del_write(bev_async);
 
        fd = evbuffer_overlapped_get_fd_(bev->input);
-       if (fd != (evutil_socket_t)INVALID_SOCKET &&
+       if (fd != (evutil_socket_t)EVUTIL_INVALID_SOCKET &&
                (bev_p->options & BEV_OPT_CLOSE_ON_FREE)) {
                evutil_closesocket(fd);
-               evbuffer_overlapped_set_fd_(bev->input, INVALID_SOCKET);
+               evbuffer_overlapped_set_fd_(bev->input, EVUTIL_INVALID_SOCKET);
        }
 }
 
@@ -428,8 +450,7 @@ connect_complete(struct event_overlapped *eo, ev_uintptr_t key,
        else
                bev_async_set_wsa_error(bev, eo);
 
-       bufferevent_run_eventcb_(bev,
-                       ok? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR, 0);
+       be_async_run_eventcb(bev, ok ? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR, 0);
 
        event_base_del_virtual_(bev->ev_base);
 
@@ -459,16 +480,16 @@ read_complete(struct event_overlapped *eo, ev_uintptr_t key,
        if (bev_a->ok) {
                if (ok && nbytes) {
                        BEV_RESET_GENERIC_READ_TIMEOUT(bev);
-                       bufferevent_trigger_nolock_(bev, EV_READ, 0);
+                       be_async_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, 0);
+                       be_async_run_eventcb(bev, what, 0);
                } else if (!nbytes) {
                        what |= BEV_EVENT_EOF;
                        bev_a->ok = 0;
-                       bufferevent_run_eventcb_(bev, what, 0);
+                       be_async_run_eventcb(bev, what, 0);
                }
        }
 
@@ -502,16 +523,16 @@ write_complete(struct event_overlapped *eo, ev_uintptr_t key,
        if (bev_a->ok) {
                if (ok && nbytes) {
                        BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
-                       bufferevent_trigger_nolock_(bev, EV_WRITE, 0);
+                       be_async_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, 0);
+                       be_async_run_eventcb(bev, what, 0);
                } else if (!nbytes) {
                        what |= BEV_EVENT_EOF;
                        bev_a->ok = 0;
-                       bufferevent_run_eventcb_(bev, what, 0);
+                       be_async_run_eventcb(bev, what, 0);
                }
        }
 
@@ -532,11 +553,7 @@ bufferevent_async_new_(struct event_base *base,
                return NULL;
 
        if (fd >= 0 && event_iocp_port_associate_(iocp, fd, 1)<0) {
-               int err = GetLastError();
-               /* We may have alrady associated this fd with a port.
-                * Let's hope it's this port, and that the error code
-                * for doing this neer changes. */
-               if (err != ERROR_INVALID_PARAMETER)
+               if (fatal_error(GetLastError()))
                        return NULL;
        }
 
@@ -580,7 +597,6 @@ bufferevent_async_set_connected_(struct bufferevent *bev)
 {
        struct bufferevent_async *bev_async = upcast(bev);
        bev_async->ok = 1;
-       bufferevent_init_generic_timeout_cbs_(bev);
        /* Now's a good time to consider reading/writing */
        be_async_enable(bev, bev->enabled);
 }
@@ -654,25 +670,29 @@ be_async_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op,
                data->fd = evbuffer_overlapped_get_fd_(bev->input);
                return 0;
        case BEV_CTRL_SET_FD: {
+               struct bufferevent_async *bev_a = upcast(bev);
                struct event_iocp_port *iocp;
 
                if (data->fd == evbuffer_overlapped_get_fd_(bev->input))
                        return 0;
                if (!(iocp = event_base_get_iocp_(bev->ev_base)))
                        return -1;
-               if (event_iocp_port_associate_(iocp, data->fd, 1) < 0)
-                       return -1;
+               if (event_iocp_port_associate_(iocp, data->fd, 1) < 0) {
+                       if (fatal_error(GetLastError()))
+                               return -1;
+               }
                evbuffer_overlapped_set_fd_(bev->input, data->fd);
                evbuffer_overlapped_set_fd_(bev->output, data->fd);
+               bev_a->ok = data->fd >= 0;
                return 0;
        }
        case BEV_CTRL_CANCEL_ALL: {
                struct bufferevent_async *bev_a = upcast(bev);
                evutil_socket_t fd = evbuffer_overlapped_get_fd_(bev->input);
-               if (fd != (evutil_socket_t)INVALID_SOCKET &&
+               if (fd != (evutil_socket_t)EVUTIL_INVALID_SOCKET &&
                    (bev_a->bev.options & BEV_OPT_CLOSE_ON_FREE)) {
                        closesocket(fd);
-                       evbuffer_overlapped_set_fd_(bev->input, INVALID_SOCKET);
+                       evbuffer_overlapped_set_fd_(bev->input, EVUTIL_INVALID_SOCKET);
                }
                bev_a->ok = 0;
                return 0;
index 4d9be43e25db8c69743f712b5cbdc6afcec48e5b..a7bdedddfe1d114bf199c45774640619365d29f0 100644 (file)
@@ -71,6 +71,9 @@ static int be_filter_flush(struct bufferevent *bufev,
     short iotype, enum bufferevent_flush_mode mode);
 static int be_filter_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
 
+static void bufferevent_filtered_inbuf_cb(struct evbuffer *buf,
+    const struct evbuffer_cb_info *cbinfo, void *arg);
+
 static void bufferevent_filtered_outbuf_cb(struct evbuffer *buf,
     const struct evbuffer_cb_info *info, void *arg);
 
@@ -79,6 +82,8 @@ struct bufferevent_filtered {
 
        /** The bufferevent that we read/write filtered data from/to. */
        struct bufferevent *underlying;
+       /** A callback on our inbuf to notice somebory removes data */
+       struct evbuffer_cb_entry *inbuf_cb;
        /** A callback on our outbuf to notice when somebody adds data */
        struct evbuffer_cb_entry *outbuf_cb;
        /** True iff we have received an EOF callback from the underlying
@@ -113,11 +118,11 @@ static inline struct bufferevent_filtered *
 upcast(struct bufferevent *bev)
 {
        struct bufferevent_filtered *bev_f;
-       if (bev->be_ops != &bufferevent_ops_filter)
+       if (!BEV_IS_FILTER(bev))
                return NULL;
        bev_f = (void*)( ((char*)bev) -
                         evutil_offsetof(struct bufferevent_filtered, bev.bev));
-       EVUTIL_ASSERT(bev_f->bev.bev.be_ops == &bufferevent_ops_filter);
+       EVUTIL_ASSERT(BEV_IS_FILTER(&bev_f->bev.bev));
        return bev_f;
 }
 
@@ -155,7 +160,7 @@ be_null_filter(struct evbuffer *src, struct evbuffer *dst, ev_ssize_t lim,
               enum bufferevent_flush_mode state, void *ctx)
 {
        (void)state;
-       if (evbuffer_remove_buffer(src, dst, lim) == 0)
+       if (evbuffer_remove_buffer(src, dst, lim) >= 0)
                return BEV_OK;
        else
                return BEV_ERROR;
@@ -203,6 +208,11 @@ bufferevent_filter_new(struct bufferevent *underlying,
        bufferevent_setcb(bufev_f->underlying,
            be_filter_readcb, be_filter_writecb, be_filter_eventcb, bufev_f);
 
+       bufev_f->inbuf_cb = evbuffer_add_cb(downcast(bufev_f)->input,
+               bufferevent_filtered_inbuf_cb, bufev_f);
+       evbuffer_cb_clear_flags(downcast(bufev_f)->input, bufev_f->inbuf_cb,
+               EVBUFFER_CB_ENABLED);
+
        bufev_f->outbuf_cb = evbuffer_add_cb(downcast(bufev_f)->output,
           bufferevent_filtered_outbuf_cb, bufev_f);
 
@@ -251,6 +261,12 @@ be_filter_destruct(struct bufferevent *bev)
        EVUTIL_ASSERT(bevf);
        if (bevf->free_context)
                bevf->free_context(bevf->context);
+
+       if (bevf->inbuf_cb)
+               evbuffer_remove_cb_entry(bev->input, bevf->inbuf_cb);
+
+       if (bevf->outbuf_cb)
+               evbuffer_remove_cb_entry(bev->output, bevf->outbuf_cb);
 }
 
 static int
@@ -345,7 +361,8 @@ be_filter_process_output(struct bufferevent_filtered *bevf,
 
        /* disable the callback that calls this function
           when the user adds to the output buffer. */
-       evbuffer_cb_set_flags(bufev->output, bevf->outbuf_cb, 0);
+       evbuffer_cb_clear_flags(bufev->output, bevf->outbuf_cb,
+           EVBUFFER_CB_ENABLED);
 
        do {
                int processed = 0;
@@ -417,9 +434,8 @@ bufferevent_filtered_outbuf_cb(struct evbuffer *buf,
        }
 }
 
-/* Called when the underlying socket has read. */
 static void
-be_filter_readcb(struct bufferevent *underlying, void *me_)
+be_filter_read_nolock_(struct bufferevent *underlying, void *me_)
 {
        struct bufferevent_filtered *bevf = me_;
        enum bufferevent_filter_result res;
@@ -428,8 +444,6 @@ be_filter_readcb(struct bufferevent *underlying, void *me_)
        struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
        int processed_any = 0;
 
-       BEV_LOCK(bufev);
-
        // It's possible our refcount is 0 at this point if another thread free'd our filterevent
        EVUTIL_ASSERT(bufev_private->refcnt >= 0);
 
@@ -448,11 +462,65 @@ be_filter_readcb(struct bufferevent *underlying, void *me_)
                /* 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)
+               if (processed_any) {
                        bufferevent_trigger_nolock_(bufev, EV_READ, 0);
+                       if (evbuffer_get_length(underlying->input) > 0 &&
+                               be_readbuf_full(bevf, state)) {
+                               /* data left in underlying buffer and filter input buffer
+                                * hit its read high watermark.
+                                * Schedule callback to avoid data gets stuck in underlying
+                                * input buffer.
+                                */
+                               evbuffer_cb_set_flags(bufev->input, bevf->inbuf_cb,
+                                       EVBUFFER_CB_ENABLED);
+                       }
+               }
        }
+}
+
+/* Called when the size of our inbuf changes. */
+static void
+bufferevent_filtered_inbuf_cb(struct evbuffer *buf,
+    const struct evbuffer_cb_info *cbinfo, void *arg)
+{
+       struct bufferevent_filtered *bevf = arg;
+       enum bufferevent_flush_mode state;
+       struct bufferevent *bev = downcast(bevf);
 
-       BEV_UNLOCK(bufev);
+       BEV_LOCK(bev);
+
+       if (bevf->got_eof)
+               state = BEV_FINISHED;
+       else
+               state = BEV_NORMAL;
+
+
+       if (!be_readbuf_full(bevf, state)) {
+               /* opportunity to read data which was left in underlying
+                * input buffer because filter input buffer hit read
+                * high watermark.
+                */
+               evbuffer_cb_clear_flags(bev->input, bevf->inbuf_cb,
+                       EVBUFFER_CB_ENABLED);
+               if (evbuffer_get_length(bevf->underlying->input) > 0)
+                       be_filter_read_nolock_(bevf->underlying, bevf);
+       }
+
+       BEV_UNLOCK(bev);
+}
+
+/* Called when the underlying socket has read. */
+static void
+be_filter_readcb(struct bufferevent *underlying, void *me_)
+{
+       struct bufferevent_filtered *bevf = me_;
+       struct bufferevent *bev = downcast(bevf);
+
+       BEV_LOCK(bev);
+
+       be_filter_read_nolock_(underlying, me_);
+
+       BEV_UNLOCK(bev);
 }
 
 /* Called when the underlying socket has drained enough that we can write to
@@ -536,10 +604,22 @@ be_filter_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op,
                bevf = upcast(bev);
                data->ptr = bevf->underlying;
                return 0;
-       case BEV_CTRL_GET_FD:
        case BEV_CTRL_SET_FD:
+       case BEV_CTRL_GET_FD:
+               bevf = upcast(bev);
+
+               if (bevf->underlying &&
+                       bevf->underlying->be_ops &&
+                       bevf->underlying->be_ops->ctrl) {
+                   return (bevf->underlying->be_ops->ctrl)(bevf->underlying, op, data);
+               }
+               EVUTIL_FALLTHROUGH;
+
        case BEV_CTRL_CANCEL_ALL:
+               EVUTIL_FALLTHROUGH;
        default:
                return -1;
        }
+
+       return -1;
 }
index b30f90ff2e946ff71dd7d1e89068ab731e294b83..b51b834bca7f815993ce4e5ba1c7596b67ce9f44 100644 (file)
@@ -63,9 +63,9 @@
 #include "bufferevent-internal.h"
 #include "log-internal.h"
 
-#include <openssl/bio.h>
 #include <openssl/ssl.h>
 #include <openssl/err.h>
+#include "openssl-compat.h"
 
 /*
  * Define an OpenSSL bio that targets a bufferevent.
@@ -109,10 +109,8 @@ print_err(int val)
 static int
 bio_bufferevent_new(BIO *b)
 {
-       b->init = 0;
-       b->num = -1;
-       b->ptr = NULL; /* We'll be putting the bufferevent in this field.*/
-       b->flags = 0;
+       BIO_set_init(b, 0);
+       BIO_set_data(b, NULL); /* We'll be putting the bufferevent in this field.*/
        return 1;
 }
 
@@ -122,12 +120,10 @@ bio_bufferevent_free(BIO *b)
 {
        if (!b)
                return 0;
-       if (b->shutdown) {
-               if (b->init && b->ptr)
-                       bufferevent_free(b->ptr);
-               b->init = 0;
-               b->flags = 0;
-               b->ptr = NULL;
+       if (BIO_get_shutdown(b)) {
+               if (BIO_get_init(b) && BIO_get_data(b))
+                       bufferevent_free(BIO_get_data(b));
+               BIO_free(b);
        }
        return 1;
 }
@@ -143,10 +139,10 @@ bio_bufferevent_read(BIO *b, char *out, int outlen)
 
        if (!out)
                return 0;
-       if (!b->ptr)
+       if (!BIO_get_data(b))
                return -1;
 
-       input = bufferevent_get_input(b->ptr);
+       input = bufferevent_get_input(BIO_get_data(b));
        if (evbuffer_get_length(input) == 0) {
                /* If there's no data to read, say so. */
                BIO_set_retry_read(b);
@@ -158,17 +154,17 @@ bio_bufferevent_read(BIO *b, char *out, int outlen)
        return r;
 }
 
-/* Called to write data info the BIO */
+/* Called to write data into the BIO */
 static int
 bio_bufferevent_write(BIO *b, const char *in, int inlen)
 {
-       struct bufferevent *bufev = b->ptr;
+       struct bufferevent *bufev = BIO_get_data(b);
        struct evbuffer *output;
        size_t outlen;
 
        BIO_clear_retry_flags(b);
 
-       if (!b->ptr)
+       if (!BIO_get_data(b))
                return -1;
 
        output = bufferevent_get_output(bufev);
@@ -194,15 +190,15 @@ bio_bufferevent_write(BIO *b, const char *in, int inlen)
 static long
 bio_bufferevent_ctrl(BIO *b, int cmd, long num, void *ptr)
 {
-       struct bufferevent *bufev = b->ptr;
+       struct bufferevent *bufev = BIO_get_data(b);
        long ret = 1;
 
        switch (cmd) {
        case BIO_CTRL_GET_CLOSE:
-               ret = b->shutdown;
+               ret = BIO_get_shutdown(b);
                break;
        case BIO_CTRL_SET_CLOSE:
-               b->shutdown = (int)num;
+               BIO_set_shutdown(b, (int)num);
                break;
        case BIO_CTRL_PENDING:
                ret = evbuffer_get_length(bufferevent_get_input(bufev)) != 0;
@@ -231,38 +227,41 @@ bio_bufferevent_puts(BIO *b, const char *s)
 }
 
 /* Method table for the bufferevent BIO */
-static BIO_METHOD methods_bufferevent = {
-       BIO_TYPE_LIBEVENT, "bufferevent",
-       bio_bufferevent_write,
-       bio_bufferevent_read,
-       bio_bufferevent_puts,
-       NULL /* bio_bufferevent_gets */,
-       bio_bufferevent_ctrl,
-       bio_bufferevent_new,
-       bio_bufferevent_free,
-       NULL /* callback_ctrl */,
-};
+static BIO_METHOD *methods_bufferevent;
 
 /* Return the method table for the bufferevents BIO */
 static BIO_METHOD *
 BIO_s_bufferevent(void)
 {
-       return &methods_bufferevent;
+       if (methods_bufferevent == NULL) {
+               methods_bufferevent = BIO_meth_new(BIO_TYPE_LIBEVENT, "bufferevent");
+               if (methods_bufferevent == NULL)
+                       return NULL;
+               BIO_meth_set_write(methods_bufferevent, bio_bufferevent_write);
+               BIO_meth_set_read(methods_bufferevent, bio_bufferevent_read);
+               BIO_meth_set_puts(methods_bufferevent, bio_bufferevent_puts);
+               BIO_meth_set_ctrl(methods_bufferevent, bio_bufferevent_ctrl);
+               BIO_meth_set_create(methods_bufferevent, bio_bufferevent_new);
+               BIO_meth_set_destroy(methods_bufferevent, bio_bufferevent_free);
+       }
+       return methods_bufferevent;
 }
 
 /* Create a new BIO to wrap communication around a bufferevent.  If close_flag
  * is true, the bufferevent will be freed when the BIO is closed. */
 static BIO *
-BIO_new_bufferevent(struct bufferevent *bufferevent, int close_flag)
+BIO_new_bufferevent(struct bufferevent *bufferevent)
 {
        BIO *result;
        if (!bufferevent)
                return NULL;
        if (!(result = BIO_new(BIO_s_bufferevent())))
                return NULL;
-       result->init = 1;
-       result->ptr = bufferevent;
-       result->shutdown = close_flag ? 1 : 0;
+       BIO_set_init(result, 1);
+       BIO_set_data(result, bufferevent);
+       /* We don't tell the BIO to close the bufferevent; we do it ourselves on
+        * be_openssl_destruct() */
+       BIO_set_shutdown(result, 0);
        return result;
 }
 
@@ -320,13 +319,13 @@ struct bufferevent_openssl {
        unsigned write_blocked_on_read : 1;
        /* Treat TCP close before SSL close on SSL >= v3 as clean EOF. */
        unsigned allow_dirty_shutdown : 1;
-       /* XXXX */
-       unsigned fd_is_set : 1;
        /* XXX */
        unsigned n_errors : 2;
 
        /* Are we currently connecting, accepting, or doing IO? */
        unsigned state : 2;
+       /* If we reset fd, we sould reset state too */
+       unsigned old_state : 2;
 };
 
 static int be_openssl_enable(struct bufferevent *, short);
@@ -356,11 +355,11 @@ static inline struct bufferevent_openssl *
 upcast(struct bufferevent *bev)
 {
        struct bufferevent_openssl *bev_o;
-       if (bev->be_ops != &bufferevent_ops_openssl)
+       if (!BEV_IS_OPENSSL(bev))
                return NULL;
        bev_o = (void*)( ((char*)bev) -
                         evutil_offsetof(struct bufferevent_openssl, bev.bev));
-       EVUTIL_ASSERT(bev_o->bev.bev.be_ops == &bufferevent_ops_openssl);
+       EVUTIL_ASSERT(BEV_IS_OPENSSL(&bev_o->bev.bev));
        return bev_o;
 }
 
@@ -406,7 +405,10 @@ start_writing(struct bufferevent_openssl *bev_ssl)
 {
        int r = 0;
        if (bev_ssl->underlying) {
-               ;
+               if (bev_ssl->write_blocked_on_read) {
+                       bufferevent_unsuspend_read_(bev_ssl->underlying,
+                           BEV_SUSPEND_FILT_READ);
+               }
        } else {
                struct bufferevent *bev = &bev_ssl->bev.bev;
                r = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write);
@@ -437,7 +439,8 @@ stop_writing(struct bufferevent_openssl *bev_ssl)
        if (bev_ssl->read_blocked_on_write)
                return;
        if (bev_ssl->underlying) {
-               ;
+               bufferevent_unsuspend_read_(bev_ssl->underlying,
+                   BEV_SUSPEND_FILT_READ);
        } else {
                struct bufferevent *bev = &bev_ssl->bev.bev;
                event_del(&bev->ev_write);
@@ -506,14 +509,17 @@ conn_closed(struct bufferevent_openssl *bev_ssl, int when, int errcode, int ret)
                break;
        case SSL_ERROR_SYSCALL:
                /* IO error; possibly a dirty shutdown. */
-               if (ret == 0 && ERR_peek_error() == 0)
+               if ((ret == 0 || ret == -1) && ERR_peek_error() == 0)
                        dirty_shutdown = 1;
+               put_error(bev_ssl, errcode);
                break;
        case SSL_ERROR_SSL:
                /* Protocol error. */
+               put_error(bev_ssl, errcode);
                break;
        case SSL_ERROR_WANT_X509_LOOKUP:
                /* XXXX handle this. */
+               put_error(bev_ssl, errcode);
                break;
        case SSL_ERROR_NONE:
        case SSL_ERROR_WANT_READ:
@@ -544,10 +550,12 @@ conn_closed(struct bufferevent_openssl *bev_ssl, int when, int errcode, int ret)
 static void
 init_bio_counts(struct bufferevent_openssl *bev_ssl)
 {
-       bev_ssl->counts.n_written =
-           BIO_number_written(SSL_get_wbio(bev_ssl->ssl));
-       bev_ssl->counts.n_read =
-           BIO_number_read(SSL_get_rbio(bev_ssl->ssl));
+       BIO *rbio, *wbio;
+
+       wbio = SSL_get_wbio(bev_ssl->ssl);
+       bev_ssl->counts.n_written = wbio ? BIO_number_written(wbio) : 0;
+       rbio = SSL_get_rbio(bev_ssl->ssl);
+       bev_ssl->counts.n_read = rbio ? BIO_number_read(rbio) : 0;
 }
 
 static inline void
@@ -595,6 +603,7 @@ do_read(struct bufferevent_openssl *bev_ssl, int n_to_read) {
        for (i=0; i<n; ++i) {
                if (bev_ssl->bev.read_suspended)
                        break;
+               ERR_clear_error();
                r = SSL_read(bev_ssl->ssl, space[i].iov_base, space[i].iov_len);
                if (r>0) {
                        result |= OP_MADE_PROGRESS;
@@ -671,6 +680,7 @@ do_write(struct bufferevent_openssl *bev_ssl, int atmost)
                if (space[i].iov_len == 0)
                        continue;
 
+               ERR_clear_error();
                r = SSL_write(bev_ssl->ssl, space[i].iov_base,
                    space[i].iov_len);
                if (r > 0) {
@@ -714,7 +724,7 @@ do_write(struct bufferevent_openssl *bev_ssl, int atmost)
                if (bev_ssl->underlying)
                        BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
 
-               bufferevent_trigger_nolock_(bev, EV_WRITE, 0);
+               bufferevent_trigger_nolock_(bev, EV_WRITE, BEV_OPT_DEFER_CALLBACKS);
        }
        return result;
 }
@@ -797,7 +807,7 @@ consider_reading(struct bufferevent_openssl *bev_ssl)
 
                if (bev_ssl->bev.read_suspended)
                        break;
-        
+
                /* Read all pending data.  This won't hit the network
                 * again, and will (most importantly) put us in a state
                 * where we don't need to read anything else until the
@@ -957,6 +967,18 @@ be_openssl_writeeventcb(evutil_socket_t fd, short what, void *ptr)
        bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
 }
 
+static evutil_socket_t
+be_openssl_auto_fd(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
+{
+       if (!bev_ssl->underlying) {
+               struct bufferevent *bev = &bev_ssl->bev.bev;
+               if (event_initialized(&bev->ev_read) && fd < 0) {
+                       fd = event_get_fd(&bev->ev_read);
+               }
+       }
+       return fd;
+}
+
 static int
 set_open_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
 {
@@ -968,27 +990,27 @@ set_open_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
        } else {
                struct bufferevent *bev = &bev_ssl->bev.bev;
                int rpending=0, wpending=0, r1=0, r2=0;
-               if (fd < 0 && bev_ssl->fd_is_set)
-                       fd = event_get_fd(&bev->ev_read);
-               if (bev_ssl->fd_is_set) {
+
+               if (event_initialized(&bev->ev_read)) {
                        rpending = event_pending(&bev->ev_read, EV_READ, NULL);
                        wpending = event_pending(&bev->ev_write, EV_WRITE, NULL);
+
                        event_del(&bev->ev_read);
                        event_del(&bev->ev_write);
                }
+
                event_assign(&bev->ev_read, bev->ev_base, fd,
                    EV_READ|EV_PERSIST|EV_FINALIZE,
                    be_openssl_readeventcb, bev_ssl);
                event_assign(&bev->ev_write, bev->ev_base, fd,
                    EV_WRITE|EV_PERSIST|EV_FINALIZE,
                    be_openssl_writeeventcb, bev_ssl);
+
                if (rpending)
                        r1 = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read);
                if (wpending)
                        r2 = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write);
-               if (fd >= 0) {
-                       bev_ssl->fd_is_set = 1;
-               }
+
                return (r1<0 || r2<0) ? -1 : 0;
        }
 }
@@ -1005,15 +1027,17 @@ do_handshake(struct bufferevent_openssl *bev_ssl)
                return -1;
        case BUFFEREVENT_SSL_CONNECTING:
        case BUFFEREVENT_SSL_ACCEPTING:
+               ERR_clear_error();
                r = SSL_do_handshake(bev_ssl->ssl);
                break;
        }
        decrement_buckets(bev_ssl);
 
        if (r==1) {
+               evutil_socket_t fd = event_get_fd(&bev_ssl->bev.bev.ev_read);
                /* We're done! */
                bev_ssl->state = BUFFEREVENT_SSL_OPEN;
-               set_open_callbacks(bev_ssl, -1); /* XXXX handle failure */
+               set_open_callbacks(bev_ssl, fd); /* XXXX handle failure */
                /* 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,
@@ -1024,17 +1048,11 @@ do_handshake(struct bufferevent_openssl *bev_ssl)
                print_err(err);
                switch (err) {
                case SSL_ERROR_WANT_WRITE:
-                       if (!bev_ssl->underlying) {
-                               stop_reading(bev_ssl);
-                               return start_writing(bev_ssl);
-                       }
-                       return 0;
+                       stop_reading(bev_ssl);
+                       return start_writing(bev_ssl);
                case SSL_ERROR_WANT_READ:
-                       if (!bev_ssl->underlying) {
-                               stop_writing(bev_ssl);
-                               return start_reading(bev_ssl);
-                       }
-                       return 0;
+                       stop_writing(bev_ssl);
+                       return start_reading(bev_ssl);
                default:
                        conn_closed(bev_ssl, BEV_EVENT_READING, err, r);
                        return -1;
@@ -1070,28 +1088,31 @@ set_handshake_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
                    be_openssl_handshakecb, be_openssl_handshakecb,
                    be_openssl_eventcb,
                    bev_ssl);
+
+               if (fd < 0)
+                       return 0;
+
+               if (bufferevent_setfd(bev_ssl->underlying, fd))
+                       return 1;
+
                return do_handshake(bev_ssl);
        } else {
                struct bufferevent *bev = &bev_ssl->bev.bev;
-               int r1=0, r2=0;
-               if (fd < 0 && bev_ssl->fd_is_set)
-                       fd = event_get_fd(&bev->ev_read);
-               if (bev_ssl->fd_is_set) {
+
+               if (event_initialized(&bev->ev_read)) {
                        event_del(&bev->ev_read);
                        event_del(&bev->ev_write);
                }
+
                event_assign(&bev->ev_read, bev->ev_base, fd,
                    EV_READ|EV_PERSIST|EV_FINALIZE,
                    be_openssl_handshakeeventcb, bev_ssl);
                event_assign(&bev->ev_write, bev->ev_base, fd,
                    EV_WRITE|EV_PERSIST|EV_FINALIZE,
                    be_openssl_handshakeeventcb, bev_ssl);
-               if (fd >= 0) {
-                       r1 = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read);
-                       r2 = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write);
-                       bev_ssl->fd_is_set = 1;
-               }
-               return (r1<0 || r2<0) ? -1 : 0;
+               if (fd >= 0)
+                       bufferevent_enable(bev, bev->enabled);
+               return 0;
        }
 }
 
@@ -1104,7 +1125,7 @@ bufferevent_ssl_renegotiate(struct bufferevent *bev)
        if (SSL_renegotiate(bev_ssl->ssl) < 0)
                return -1;
        bev_ssl->state = BUFFEREVENT_SSL_CONNECTING;
-       if (set_handshake_callbacks(bev_ssl, -1) < 0)
+       if (set_handshake_callbacks(bev_ssl, be_openssl_auto_fd(bev_ssl, -1)) < 0)
                return -1;
        if (!bev_ssl->underlying)
                return do_handshake(bev_ssl);
@@ -1123,10 +1144,12 @@ be_openssl_outbuf_cb(struct evbuffer *buf,
                if (cbinfo->orig_size == 0)
                        r = bufferevent_add_event_(&bev_ssl->bev.bev.ev_write,
                            &bev_ssl->bev.bev.timeout_write);
-               consider_writing(bev_ssl);
+
+               if (bev_ssl->underlying)
+                       consider_writing(bev_ssl);
        }
        /* XXX Handle r < 0 */
-        (void)r;
+       (void)r;
 }
 
 
@@ -1136,9 +1159,6 @@ be_openssl_enable(struct bufferevent *bev, short events)
        struct bufferevent_openssl *bev_ssl = upcast(bev);
        int r1 = 0, r2 = 0;
 
-       if (bev_ssl->state != BUFFEREVENT_SSL_OPEN)
-               return 0;
-
        if (events & EV_READ)
                r1 = start_reading(bev_ssl);
        if (events & EV_WRITE)
@@ -1162,8 +1182,6 @@ static int
 be_openssl_disable(struct bufferevent *bev, short events)
 {
        struct bufferevent_openssl *bev_ssl = upcast(bev);
-       if (bev_ssl->state != BUFFEREVENT_SSL_OPEN)
-               return 0;
 
        if (events & EV_READ)
                stop_reading(bev_ssl);
@@ -1214,7 +1232,7 @@ be_openssl_destruct(struct bufferevent *bev)
 
        if (bev_ssl->bev.options & BEV_OPT_CLOSE_ON_FREE) {
                if (! bev_ssl->underlying) {
-                       evutil_socket_t fd = -1;
+                       evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
                        BIO *bio = SSL_get_wbio(bev_ssl->ssl);
                        if (bio)
                                fd = BIO_get_fd(bio, NULL);
@@ -1233,23 +1251,7 @@ be_openssl_adj_timeouts(struct bufferevent *bev)
        if (bev_ssl->underlying) {
                return bufferevent_generic_adj_timeouts_(bev);
        } else {
-               int r1=0, r2=0;
-               if (event_pending(&bev->ev_read, EV_READ, NULL)) {
-                       if (evutil_timerisset(&bev->timeout_read)) {
-                               r1 = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read);
-                       } else {
-                               event_remove_timer(&bev->ev_read);
-                       }
-               }
-               if (event_pending(&bev->ev_write, EV_WRITE, NULL)) {
-                       if (evutil_timerisset(&bev->timeout_write)) {
-                               r2 = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write);
-                       } else {
-                               event_remove_timer(&bev->ev_write);
-                       }
-               }
-
-               return (r1<0 || r2<0) ? -1 : 0;
+               return bufferevent_generic_adj_existing_timeouts_(bev);
        }
 }
 
@@ -1261,6 +1263,38 @@ be_openssl_flush(struct bufferevent *bufev,
        return 0;
 }
 
+static int
+be_openssl_set_fd(struct bufferevent_openssl *bev_ssl,
+    enum bufferevent_ssl_state state, evutil_socket_t fd)
+{
+       bev_ssl->state = state;
+
+       switch (state) {
+       case BUFFEREVENT_SSL_ACCEPTING:
+               if (!SSL_clear(bev_ssl->ssl))
+                       return -1;
+               SSL_set_accept_state(bev_ssl->ssl);
+               if (set_handshake_callbacks(bev_ssl, fd) < 0)
+                       return -1;
+               break;
+       case BUFFEREVENT_SSL_CONNECTING:
+               if (!SSL_clear(bev_ssl->ssl))
+                       return -1;
+               SSL_set_connect_state(bev_ssl->ssl);
+               if (set_handshake_callbacks(bev_ssl, fd) < 0)
+                       return -1;
+               break;
+       case BUFFEREVENT_SSL_OPEN:
+               if (set_open_callbacks(bev_ssl, fd) < 0)
+                       return -1;
+               break;
+       default:
+               return -1;
+       }
+
+       return 0;
+}
+
 static int
 be_openssl_ctrl(struct bufferevent *bev,
     enum bufferevent_ctrl_op op, union bufferevent_ctrl_data *data)
@@ -1268,31 +1302,26 @@ be_openssl_ctrl(struct bufferevent *bev,
        struct bufferevent_openssl *bev_ssl = upcast(bev);
        switch (op) {
        case BEV_CTRL_SET_FD:
-               if (bev_ssl->underlying)
-                       return -1;
-               {
+               if (!bev_ssl->underlying) {
                        BIO *bio;
-                       bio = BIO_new_socket(data->fd, 0);
+                       bio = BIO_new_socket((int)data->fd, 0);
+                       SSL_set_bio(bev_ssl->ssl, bio, bio);
+               } else {
+                       BIO *bio;
+                       if (!(bio = BIO_new_bufferevent(bev_ssl->underlying)))
+                               return -1;
                        SSL_set_bio(bev_ssl->ssl, bio, bio);
-                       bev_ssl->fd_is_set = 1;
-               }
-               if (data->fd == -1)
-                       bev_ssl->fd_is_set = 0;
-               if (bev_ssl->state == BUFFEREVENT_SSL_OPEN)
-                       return set_open_callbacks(bev_ssl, data->fd);
-               else {
-                       return set_handshake_callbacks(bev_ssl, data->fd);
                }
+
+               return be_openssl_set_fd(bev_ssl, bev_ssl->old_state, data->fd);
        case BEV_CTRL_GET_FD:
-               if (bev_ssl->underlying)
-                       return -1;
-               if (!bev_ssl->fd_is_set)
-                       return -1;
-               data->fd = event_get_fd(&bev->ev_read);
+               if (bev_ssl->underlying) {
+                       data->fd = event_get_fd(&bev_ssl->underlying->ev_read);
+               } else {
+                       data->fd = event_get_fd(&bev->ev_read);
+               }
                return 0;
        case BEV_CTRL_GET_UNDERLYING:
-               if (!bev_ssl->underlying)
-                       return -1;
                data->ptr = bev_ssl->underlying;
                return 0;
        case BEV_CTRL_CANCEL_ALL:
@@ -1322,8 +1351,9 @@ bufferevent_openssl_new_impl(struct event_base *base,
        struct bufferevent_private *bev_p = NULL;
        int tmp_options = options & ~BEV_OPT_THREADSAFE;
 
+       /* Only one can be set. */
        if (underlying != NULL && fd >= 0)
-               return NULL; /* Only one can be set. */
+               goto err;
 
        if (!(bev_ssl = mm_calloc(1, sizeof(struct bufferevent_openssl))))
                goto err;
@@ -1352,29 +1382,14 @@ bufferevent_openssl_new_impl(struct event_base *base,
                bufferevent_incref_(underlying);
        }
 
-       bev_ssl->state = state;
+       bev_ssl->old_state = state;
        bev_ssl->last_write = -1;
 
        init_bio_counts(bev_ssl);
 
-       switch (state) {
-       case BUFFEREVENT_SSL_ACCEPTING:
-               SSL_set_accept_state(bev_ssl->ssl);
-               if (set_handshake_callbacks(bev_ssl, fd) < 0)
-                       goto err;
-               break;
-       case BUFFEREVENT_SSL_CONNECTING:
-               SSL_set_connect_state(bev_ssl->ssl);
-               if (set_handshake_callbacks(bev_ssl, fd) < 0)
-                       goto err;
-               break;
-       case BUFFEREVENT_SSL_OPEN:
-               if (set_open_callbacks(bev_ssl, fd) < 0)
-                       goto err;
-               break;
-       default:
+       fd = be_openssl_auto_fd(bev_ssl, fd);
+       if (be_openssl_set_fd(bev_ssl, state, fd))
                goto err;
-       }
 
        if (underlying) {
                bufferevent_setwatermark(underlying, EV_READ, 0, 0);
@@ -1382,21 +1397,16 @@ bufferevent_openssl_new_impl(struct event_base *base,
                if (state == BUFFEREVENT_SSL_OPEN)
                        bufferevent_suspend_read_(underlying,
                            BEV_SUSPEND_FILT_READ);
-       } else {
-               bev_ssl->bev.bev.enabled = EV_READ|EV_WRITE;
-               if (bev_ssl->fd_is_set) {
-                       if (state != BUFFEREVENT_SSL_OPEN)
-                               if (event_add(&bev_ssl->bev.bev.ev_read, NULL) < 0)
-                                       goto err;
-                       if (event_add(&bev_ssl->bev.bev.ev_write, NULL) < 0)
-                               goto err;
-               }
        }
 
        return &bev_ssl->bev.bev;
 err:
-       if (bev_ssl)
+       if (options & BEV_OPT_CLOSE_ON_FREE)
+               SSL_free(ssl);
+       if (bev_ssl) {
+               bev_ssl->ssl = NULL;
                bufferevent_free(&bev_ssl->bev.bev);
+       }
        return NULL;
 }
 
@@ -1407,19 +1417,24 @@ bufferevent_openssl_filter_new(struct event_base *base,
     enum bufferevent_ssl_state state,
     int options)
 {
-       /* We don't tell the BIO to close the bufferevent; we do it ourselves
-        * on be_openssl_destruct */
-       int close_flag = 0; /* options & BEV_OPT_CLOSE_ON_FREE; */
        BIO *bio;
+       struct bufferevent *bev;
+
        if (!underlying)
-               return NULL;
-       if (!(bio = BIO_new_bufferevent(underlying, close_flag)))
-               return NULL;
+               goto err;
+       if (!(bio = BIO_new_bufferevent(underlying)))
+               goto err;
 
        SSL_set_bio(ssl, bio, bio);
 
-       return bufferevent_openssl_new_impl(
+       bev = bufferevent_openssl_new_impl(
                base, underlying, -1, ssl, state, options);
+       return bev;
+
+err:
+       if (options & BEV_OPT_CLOSE_ON_FREE)
+               SSL_free(ssl);
+       return NULL;
 }
 
 struct bufferevent *
@@ -1446,14 +1461,14 @@ bufferevent_openssl_socket_new(struct event_base *base,
                } else {
                        /* We specified an fd different from that of the SSL.
                           This is probably an error on our part.  Fail. */
-                       return NULL;
+                       goto err;
                }
-               (void) BIO_set_close(bio, 0);
+               BIO_set_close(bio, 0);
        } else {
                /* The SSL isn't configured with a BIO with an fd. */
                if (fd >= 0) {
                        /* ... and we have an fd we want to use. */
-                       bio = BIO_new_socket(fd, 0);
+                       bio = BIO_new_socket((int)fd, 0);
                        SSL_set_bio(ssl, bio, bio);
                } else {
                        /* Leave the fd unset. */
@@ -1462,6 +1477,11 @@ bufferevent_openssl_socket_new(struct event_base *base,
 
        return bufferevent_openssl_new_impl(
                base, NULL, fd, ssl, state, options);
+
+err:
+       if (options & BEV_OPT_CLOSE_ON_FREE)
+               SSL_free(ssl);
+       return NULL;
 }
 
 int
index 8154e17be732dcb7a67f8efa3e51a2ac4d1e4440..f88cd751de1b9113dfb0206defd1add3c48f9254 100644 (file)
@@ -56,10 +56,10 @@ static inline struct bufferevent_pair *
 upcast(struct bufferevent *bev)
 {
        struct bufferevent_pair *bev_p;
-       if (bev->be_ops != &bufferevent_ops_pair)
+       if (!BEV_IS_PAIR(bev))
                return NULL;
        bev_p = EVUTIL_UPCAST(bev, struct bufferevent_pair, bev.bev);
-       EVUTIL_ASSERT(bev_p->bev.bev.be_ops == &bufferevent_ops_pair);
+       EVUTIL_ASSERT(BEV_IS_PAIR(&bev_p->bev.bev));
        return bev_p;
 }
 
@@ -307,15 +307,17 @@ be_pair_flush(struct bufferevent *bev, short iotype,
 {
        struct bufferevent_pair *bev_p = upcast(bev);
        struct bufferevent *partner;
-       incref_and_lock(bev);
+
        if (!bev_p->partner)
                return -1;
 
-       partner = downcast(bev_p->partner);
-
        if (mode == BEV_NORMAL)
                return 0;
 
+       incref_and_lock(bev);
+
+       partner = downcast(bev_p->partner);
+
        if ((iotype & EV_READ) != 0)
                be_pair_transfer(partner, bev, 1);
 
@@ -323,7 +325,12 @@ 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, 0);
+               short what = BEV_EVENT_EOF;
+               if (iotype & EV_READ)
+                       what |= BEV_EVENT_WRITING;
+               if (iotype & EV_WRITE)
+                       what |= BEV_EVENT_READING;
+               bufferevent_run_eventcb_(partner, what, 0);
        }
        decref_and_unlock(bev);
        return 0;
index bde192021be14ad102011c0912ed0be8a695d04b..258749685353bd98da540ec6b2b970b67a26e645 100644 (file)
@@ -560,8 +560,7 @@ int
 bufferevent_set_rate_limit(struct bufferevent *bev,
     struct ev_token_bucket_cfg *cfg)
 {
-       struct bufferevent_private *bevp =
-           EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+       struct bufferevent_private *bevp = BEV_UPCAST(bev);
        int r = -1;
        struct bufferevent_rate_limit *rlim;
        struct timeval now;
@@ -737,8 +736,7 @@ bufferevent_add_to_rate_limit_group(struct bufferevent *bev,
     struct bufferevent_rate_limit_group *g)
 {
        int wsuspend, rsuspend;
-       struct bufferevent_private *bevp =
-           EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+       struct bufferevent_private *bevp = BEV_UPCAST(bev);
        BEV_LOCK(bev);
 
        if (!bevp->rate_limiting) {
@@ -789,8 +787,7 @@ int
 bufferevent_remove_from_rate_limit_group_internal_(struct bufferevent *bev,
     int unsuspend)
 {
-       struct bufferevent_private *bevp =
-           EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+       struct bufferevent_private *bevp = BEV_UPCAST(bev);
        BEV_LOCK(bev);
        if (bevp->rate_limiting && bevp->rate_limiting->group) {
                struct bufferevent_rate_limit_group *g =
index 49ebc0bef8ff9ff4411f7ec92444339350c37f2b..f40a8d9c57d88dc9dee2630e37064cdc12e7f5c5 100644 (file)
@@ -79,7 +79,6 @@
 static int be_socket_enable(struct bufferevent *, short);
 static int be_socket_disable(struct bufferevent *, short);
 static void be_socket_destruct(struct bufferevent *);
-static int be_socket_adj_timeouts(struct bufferevent *);
 static int be_socket_flush(struct bufferevent *, short, enum bufferevent_flush_mode);
 static int be_socket_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
 
@@ -92,13 +91,39 @@ const struct bufferevent_ops bufferevent_ops_socket = {
        be_socket_disable,
        NULL, /* unlink */
        be_socket_destruct,
-       be_socket_adj_timeouts,
+       bufferevent_generic_adj_existing_timeouts_,
        be_socket_flush,
        be_socket_ctrl,
 };
 
-#define be_socket_add(ev, t)                   \
-       bufferevent_add_event_((ev), (t))
+const struct sockaddr*
+bufferevent_socket_get_conn_address_(struct bufferevent *bev)
+{
+       struct bufferevent_private *bev_p = BEV_UPCAST(bev);
+       return (struct sockaddr *)&bev_p->conn_address;
+}
+
+void
+bufferevent_socket_set_conn_address_fd_(struct bufferevent *bev,
+       evutil_socket_t fd)
+{
+       struct bufferevent_private *bev_p = BEV_UPCAST(bev);
+
+       socklen_t len = sizeof(bev_p->conn_address);
+
+       struct sockaddr *addr = (struct sockaddr *)&bev_p->conn_address;
+       if (addr->sa_family != AF_UNSPEC)
+               getpeername(fd, addr, &len);
+}
+
+void
+bufferevent_socket_set_conn_address_(struct bufferevent *bev,
+       struct sockaddr *addr, size_t addrlen)
+{
+       struct bufferevent_private *bev_p = BEV_UPCAST(bev);
+       EVUTIL_ASSERT(addrlen <= sizeof(bev_p->conn_address));
+       memcpy(&bev_p->conn_address, addr, addrlen);
+}
 
 static void
 bufferevent_socket_outbuf_cb(struct evbuffer *buf,
@@ -106,8 +131,7 @@ bufferevent_socket_outbuf_cb(struct evbuffer *buf,
     void *arg)
 {
        struct bufferevent *bufev = arg;
-       struct bufferevent_private *bufev_p =
-           EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+       struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
 
        if (cbinfo->n_added &&
            (bufev->enabled & EV_WRITE) &&
@@ -115,7 +139,7 @@ bufferevent_socket_outbuf_cb(struct evbuffer *buf,
            !bufev_p->write_suspended) {
                /* Somebody added data to the buffer, and we would like to
                 * write, and we were not writing.  So, start writing. */
-               if (be_socket_add(&bufev->ev_write, &bufev->timeout_write) == -1) {
+               if (bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1) {
                    /* Should we log this? */
                }
        }
@@ -125,8 +149,7 @@ static void
 bufferevent_readcb(evutil_socket_t fd, short event, void *arg)
 {
        struct bufferevent *bufev = arg;
-       struct bufferevent_private *bufev_p =
-           EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+       struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
        struct evbuffer *input;
        int res = 0;
        short what = BEV_EVENT_READING;
@@ -171,6 +194,10 @@ bufferevent_readcb(evutil_socket_t fd, short event, void *arg)
                int err = evutil_socket_geterror(fd);
                if (EVUTIL_ERR_RW_RETRIABLE(err))
                        goto reschedule;
+               if (EVUTIL_ERR_CONNECT_REFUSED(err)) {
+                       bufev_p->connection_refused = 1;
+                       goto done;
+               }
                /* error case */
                what |= BEV_EVENT_ERROR;
        } else if (res == 0) {
@@ -203,8 +230,7 @@ static void
 bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
 {
        struct bufferevent *bufev = arg;
-       struct bufferevent_private *bufev_p =
-           EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+       struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
        int res = 0;
        short what = BEV_EVENT_WRITING;
        int connected = 0;
@@ -224,8 +250,8 @@ bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
                /* we need to fake the error if the connection was refused
                 * immediately - usually connection to localhost on BSD */
                if (bufev_p->connection_refused) {
-                 bufev_p->connection_refused = 0;
-                 c = -1;
+                       bufev_p->connection_refused = 0;
+                       c = -1;
                }
 
                if (c == 0)
@@ -239,6 +265,7 @@ bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
                        goto done;
                } else {
                        connected = 1;
+                       bufferevent_socket_set_conn_address_fd_(bufev, fd);
 #ifdef _WIN32
                        if (BEV_IS_ASYNC(bufev)) {
                                event_del(&bufev->ev_write);
@@ -351,10 +378,9 @@ bufferevent_socket_new(struct event_base *base, evutil_socket_t fd,
 
 int
 bufferevent_socket_connect(struct bufferevent *bev,
-    struct sockaddr *sa, int socklen)
+    const struct sockaddr *sa, int socklen)
 {
-       struct bufferevent_private *bufev_p =
-           EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+       struct bufferevent_private *bufev_p = BEV_UPCAST(bev);
 
        evutil_socket_t fd;
        int r = 0;
@@ -363,9 +389,6 @@ bufferevent_socket_connect(struct bufferevent *bev,
 
        bufferevent_incref_and_lock_(bev);
 
-       if (!bufev_p)
-               goto done;
-
        fd = bufferevent_getfd(bev);
        if (fd < 0) {
                if (!sa)
@@ -373,7 +396,7 @@ bufferevent_socket_connect(struct bufferevent *bev,
                fd = evutil_socket_(sa->sa_family,
                    SOCK_STREAM|EVUTIL_SOCK_NONBLOCK, 0);
                if (fd < 0)
-                       goto done;
+                       goto freesock;
                ownfd = 1;
        }
        if (sa) {
@@ -412,22 +435,19 @@ bufferevent_socket_connect(struct bufferevent *bev,
                /* The connect succeeded already. How very BSD of it. */
                result = 0;
                bufev_p->connecting = 1;
-               event_active(&bev->ev_write, EV_WRITE, 1);
+               bufferevent_trigger_nolock_(bev, EV_WRITE, BEV_OPT_DEFER_CALLBACKS);
        } else {
                /* The connect failed already.  How very BSD of it. */
-               bufev_p->connection_refused = 1;
-               bufev_p->connecting = 1;
                result = 0;
-               event_active(&bev->ev_write, EV_WRITE, 1);
+               bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, BEV_OPT_DEFER_CALLBACKS);
+               bufferevent_disable(bev, EV_WRITE|EV_READ);
        }
 
        goto done;
 
 freesock:
-       bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
        if (ownfd)
                evutil_closesocket(fd);
-       /* do something about the error? */
 done:
        bufferevent_decref_and_unlock_(bev);
        return result;
@@ -438,14 +458,20 @@ bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai,
     void *arg)
 {
        struct bufferevent *bev = arg;
-       struct bufferevent_private *bev_p =
-           EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+       struct bufferevent_private *bev_p = BEV_UPCAST(bev);
        int r;
        BEV_LOCK(bev);
 
        bufferevent_unsuspend_write_(bev, BEV_SUSPEND_LOOKUP);
        bufferevent_unsuspend_read_(bev, BEV_SUSPEND_LOOKUP);
 
+       bev_p->dns_request = NULL;
+
+       if (result == EVUTIL_EAI_CANCEL) {
+               bev_p->dns_error = result;
+               bufferevent_decref_and_unlock_(bev);
+               return;
+       }
        if (result != 0) {
                bev_p->dns_error = result;
                bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
@@ -456,9 +482,10 @@ bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai,
        }
 
        /* XXX use the other addrinfos? */
-       /* XXX use this return value */
+       bufferevent_socket_set_conn_address_(bev, ai->ai_addr, (int)ai->ai_addrlen);
        r = bufferevent_socket_connect(bev, ai->ai_addr, (int)ai->ai_addrlen);
-       (void)r;
+       if (r < 0)
+               bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
        bufferevent_decref_and_unlock_(bev);
        evutil_freeaddrinfo(ai);
 }
@@ -469,49 +496,39 @@ bufferevent_socket_connect_hostname(struct bufferevent *bev,
 {
        char portbuf[10];
        struct evutil_addrinfo hint;
-       int err;
-       struct bufferevent_private *bev_p =
-           EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+       struct bufferevent_private *bev_p = BEV_UPCAST(bev);
 
        if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC)
                return -1;
        if (port < 1 || port > 65535)
                return -1;
 
-       BEV_LOCK(bev);
-       bev_p->dns_error = 0;
-       BEV_UNLOCK(bev);
-
-       evutil_snprintf(portbuf, sizeof(portbuf), "%d", port);
-
        memset(&hint, 0, sizeof(hint));
        hint.ai_family = family;
        hint.ai_protocol = IPPROTO_TCP;
        hint.ai_socktype = SOCK_STREAM;
 
+       evutil_snprintf(portbuf, sizeof(portbuf), "%d", port);
+
+       BEV_LOCK(bev);
+       bev_p->dns_error = 0;
+
        bufferevent_suspend_write_(bev, BEV_SUSPEND_LOOKUP);
        bufferevent_suspend_read_(bev, BEV_SUSPEND_LOOKUP);
 
        bufferevent_incref_(bev);
-       err = evutil_getaddrinfo_async_(evdns_base, hostname, portbuf,
-           &hint, bufferevent_connect_getaddrinfo_cb, bev);
+       bev_p->dns_request = evutil_getaddrinfo_async_(evdns_base, hostname,
+           portbuf, &hint, bufferevent_connect_getaddrinfo_cb, bev);
+       BEV_UNLOCK(bev);
 
-       if (err == 0) {
-               return 0;
-       } else {
-               bufferevent_unsuspend_write_(bev, BEV_SUSPEND_LOOKUP);
-               bufferevent_unsuspend_read_(bev, BEV_SUSPEND_LOOKUP);
-               bufferevent_decref_(bev);
-               return -1;
-       }
+       return 0;
 }
 
 int
 bufferevent_socket_get_dns_error(struct bufferevent *bev)
 {
        int rv;
-       struct bufferevent_private *bev_p =
-           EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+       struct bufferevent_private *bev_p = BEV_UPCAST(bev);
 
        BEV_LOCK(bev);
        rv = bev_p->dns_error;
@@ -550,22 +567,19 @@ bufferevent_new(evutil_socket_t fd,
 static int
 be_socket_enable(struct bufferevent *bufev, short event)
 {
-       if (event & EV_READ) {
-               if (be_socket_add(&bufev->ev_read,&bufev->timeout_read) == -1)
+       if (event & EV_READ &&
+           bufferevent_add_event_(&bufev->ev_read, &bufev->timeout_read) == -1)
                        return -1;
-       }
-       if (event & EV_WRITE) {
-               if (be_socket_add(&bufev->ev_write,&bufev->timeout_write) == -1)
+       if (event & EV_WRITE &&
+           bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1)
                        return -1;
-       }
        return 0;
 }
 
 static int
 be_socket_disable(struct bufferevent *bufev, short event)
 {
-       struct bufferevent_private *bufev_p =
-           EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+       struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
        if (event & EV_READ) {
                if (event_del(&bufev->ev_read) == -1)
                        return -1;
@@ -581,38 +595,16 @@ be_socket_disable(struct bufferevent *bufev, short event)
 static void
 be_socket_destruct(struct bufferevent *bufev)
 {
-       struct bufferevent_private *bufev_p =
-           EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+       struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
        evutil_socket_t fd;
-       EVUTIL_ASSERT(bufev->be_ops == &bufferevent_ops_socket);
+       EVUTIL_ASSERT(BEV_IS_SOCKET(bufev));
 
        fd = event_get_fd(&bufev->ev_read);
 
        if ((bufev_p->options & BEV_OPT_CLOSE_ON_FREE) && fd >= 0)
                EVUTIL_CLOSESOCKET(fd);
-}
 
-static int
-be_socket_adj_timeouts(struct bufferevent *bufev)
-{
-       int r = 0;
-       if (event_pending(&bufev->ev_read, EV_READ, NULL)) {
-               if (evutil_timerisset(&bufev->timeout_read)) {
-                           if (be_socket_add(&bufev->ev_read, &bufev->timeout_read) < 0)
-                                   r = -1;
-               } else {
-                       event_remove_timer(&bufev->ev_read);
-               }
-       }
-       if (event_pending(&bufev->ev_write, EV_WRITE, NULL)) {
-               if (evutil_timerisset(&bufev->timeout_write)) {
-                       if (be_socket_add(&bufev->ev_write, &bufev->timeout_write) < 0)
-                               r = -1;
-               } else {
-                       event_remove_timer(&bufev->ev_write);
-               }
-       }
-       return r;
+       evutil_getaddrinfo_cancel_async_(bufev_p->dns_request);
 }
 
 static int
@@ -626,12 +618,17 @@ be_socket_flush(struct bufferevent *bev, short iotype,
 static void
 be_socket_setfd(struct bufferevent *bufev, evutil_socket_t fd)
 {
+       struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
+
        BEV_LOCK(bufev);
-       EVUTIL_ASSERT(bufev->be_ops == &bufferevent_ops_socket);
+       EVUTIL_ASSERT(BEV_IS_SOCKET(bufev));
 
        event_del(&bufev->ev_read);
        event_del(&bufev->ev_write);
 
+       evbuffer_unfreeze(bufev->input, 0);
+       evbuffer_unfreeze(bufev->output, 1);
+
        event_assign(&bufev->ev_read, bufev->ev_base, fd,
            EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev);
        event_assign(&bufev->ev_write, bufev->ev_base, fd,
@@ -640,6 +637,8 @@ be_socket_setfd(struct bufferevent *bufev, evutil_socket_t fd)
        if (fd >= 0)
                bufferevent_enable(bufev, bufev->enabled);
 
+       evutil_getaddrinfo_cancel_async_(bufev_p->dns_request);
+
        BEV_UNLOCK(bufev);
 }
 
@@ -648,11 +647,10 @@ int
 bufferevent_priority_set(struct bufferevent *bufev, int priority)
 {
        int r = -1;
-       struct bufferevent_private *bufev_p =
-           EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
+       struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
 
        BEV_LOCK(bufev);
-       if (bufev->be_ops != &bufferevent_ops_socket)
+       if (BEV_IS_ASYNC(bufev) || BEV_IS_FILTER(bufev) || BEV_IS_PAIR(bufev))
                goto done;
 
        if (event_priority_set(&bufev->ev_read, priority) == -1)
@@ -675,7 +673,7 @@ bufferevent_base_set(struct event_base *base, struct bufferevent *bufev)
        int res = -1;
 
        BEV_LOCK(bufev);
-       if (bufev->be_ops != &bufferevent_ops_socket)
+       if (!BEV_IS_SOCKET(bufev))
                goto done;
 
        bufev->ev_base = base;
diff --git a/sntp/libevent/build-aux/test-driver b/sntp/libevent/build-aux/test-driver
new file mode 100755 (executable)
index 0000000..0218a01
--- /dev/null
@@ -0,0 +1,148 @@
+#! /bin/sh
+# test-driver - basic testsuite driver script.
+
+scriptversion=2016-01-11.22; # UTC
+
+# Copyright (C) 2011-2017 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+# Make unconditional expansion of undefined variables an error.  This
+# helps a lot in preventing typo-related bugs.
+set -u
+
+usage_error ()
+{
+  echo "$0: $*" >&2
+  print_usage >&2
+  exit 2
+}
+
+print_usage ()
+{
+  cat <<END
+Usage:
+  test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
+              [--expect-failure={yes|no}] [--color-tests={yes|no}]
+              [--enable-hard-errors={yes|no}] [--]
+              TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
+The '--test-name', '--log-file' and '--trs-file' options are mandatory.
+END
+}
+
+test_name= # Used for reporting.
+log_file=  # Where to save the output of the test script.
+trs_file=  # Where to save the metadata of the test run.
+expect_failure=no
+color_tests=no
+enable_hard_errors=yes
+while test $# -gt 0; do
+  case $1 in
+  --help) print_usage; exit $?;;
+  --version) echo "test-driver $scriptversion"; exit $?;;
+  --test-name) test_name=$2; shift;;
+  --log-file) log_file=$2; shift;;
+  --trs-file) trs_file=$2; shift;;
+  --color-tests) color_tests=$2; shift;;
+  --expect-failure) expect_failure=$2; shift;;
+  --enable-hard-errors) enable_hard_errors=$2; shift;;
+  --) shift; break;;
+  -*) usage_error "invalid option: '$1'";;
+   *) break;;
+  esac
+  shift
+done
+
+missing_opts=
+test x"$test_name" = x && missing_opts="$missing_opts --test-name"
+test x"$log_file"  = x && missing_opts="$missing_opts --log-file"
+test x"$trs_file"  = x && missing_opts="$missing_opts --trs-file"
+if test x"$missing_opts" != x; then
+  usage_error "the following mandatory options are missing:$missing_opts"
+fi
+
+if test $# -eq 0; then
+  usage_error "missing argument"
+fi
+
+if test $color_tests = yes; then
+  # Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
+  red='\e[0;31m' # Red.
+  grn='\e[0;32m' # Green.
+  lgn='\e[1;32m' # Light green.
+  blu='\e[1;34m' # Blue.
+  mgn='\e[0;35m' # Magenta.
+  std='\e[m'     # No color.
+else
+  red= grn= lgn= blu= mgn= std=
+fi
+
+do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
+trap "st=129; $do_exit" 1
+trap "st=130; $do_exit" 2
+trap "st=141; $do_exit" 13
+trap "st=143; $do_exit" 15
+
+# Test script is run here.
+"$@" >$log_file 2>&1
+estatus=$?
+
+if test $enable_hard_errors = no && test $estatus -eq 99; then
+  tweaked_estatus=1
+else
+  tweaked_estatus=$estatus
+fi
+
+case $tweaked_estatus:$expect_failure in
+  0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
+  0:*)   col=$grn res=PASS  recheck=no  gcopy=no;;
+  77:*)  col=$blu res=SKIP  recheck=no  gcopy=yes;;
+  99:*)  col=$mgn res=ERROR recheck=yes gcopy=yes;;
+  *:yes) col=$lgn res=XFAIL recheck=no  gcopy=yes;;
+  *:*)   col=$red res=FAIL  recheck=yes gcopy=yes;;
+esac
+
+# Report the test outcome and exit status in the logs, so that one can
+# know whether the test passed or failed simply by looking at the '.log'
+# file, without the need of also peaking into the corresponding '.trs'
+# file (automake bug#11814).
+echo "$res $test_name (exit status: $estatus)" >>$log_file
+
+# Report outcome to console.
+echo "${col}${res}${std}: $test_name"
+
+# Register the test result, and other relevant metadata.
+echo ":test-result: $res" > $trs_file
+echo ":global-test-result: $res" >> $trs_file
+echo ":recheck: $recheck" >> $trs_file
+echo ":copy-in-global-log: $gcopy" >> $trs_file
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/sntp/libevent/checkpatch.sh b/sntp/libevent/checkpatch.sh
new file mode 100755 (executable)
index 0000000..6eaa19c
--- /dev/null
@@ -0,0 +1,299 @@
+#!/usr/bin/env bash
+
+# TODO:
+# - inline replace
+# - clang-format-diff replacement
+# - uncrustify for patches (not git refs)
+# - maybe integrate into travis-ci?
+
+function usage()
+{
+    cat <<EOL
+$0 [ OPTS ] [ file-or-gitref [ ... ] ]
+
+Example:
+  # Chech HEAD git ref
+  $ $0 -r
+  $ $0 -r HEAD
+
+  # Check patch
+  $ git format-patch --stdout -1 | $0 -p
+  $ git show -1 | $0 -p
+
+  # Or via regular files
+  $ git format-patch --stdout -2
+  $ $0 *.patch
+
+  # Over a file
+  $ $0 -d event.c
+  $ $0 -d < event.c
+
+  # And print the whole file not only summary
+  $ $0 -f event.c
+  $ $0 -f < event.c
+
+OPTS:
+  -p   - treat as patch
+  -f   - treat as regular file
+  -f   - treat as regular file and print diff
+  -r   - treat as git revision (default)
+  -C   - check using clang-format (default)
+  -U   - check with uncrustify
+  -c   - config for clang-format/uncrustify
+  -h   - print this message
+EOL
+}
+function cfg()
+{
+    [ -z "${options[cfg]}" ] || {
+        echo "${options[cfg]}"
+        return
+    }
+
+    local dir="$(dirname "${BASH_SOURCE[0]}")"
+    [ "${options[clang]}" -eq 0 ] || {
+        echo "$dir/.clang-format"
+        return
+    }
+    [ "${options[uncrustify]}" -eq 0 ] || {
+        echo "$dir/.uncrustify"
+        return
+    }
+}
+function abort()
+{
+    local msg="$1"
+    shift
+
+    printf "$msg\n" "$@" >&2
+    exit 1
+}
+function default_arg()
+{
+    if [ "${options[ref]}" -eq 1 ]; then
+        echo "HEAD"
+    else
+        [ ! -t 0 ] || abort "<stdin> is a tty"
+        echo "/dev/stdin"
+    fi
+}
+function parse_options()
+{
+    options[patch]=0
+    options[file]=0
+    options[file_diff]=0
+    options[ref]=1
+    options[clang]=1
+    options[uncrustify]=0
+    options[cfg]=
+
+    local OPTARG OPTIND c
+    while getopts "pfrdCUc:h?" c; do
+        case "$c" in
+            p)
+                options[patch]=1
+                options[ref]=0
+                options[file]=0
+                options[file_diff]=0
+                ;;
+            f)
+                options[file]=1
+                options[ref]=0
+                options[patch]=0
+                options[file_diff]=0
+                ;;
+            r)
+                options[ref]=1
+                options[file]=0
+                options[patch]=0
+                options[file_diff]=0
+                ;;
+            d)
+                options[file_diff]=1
+                options[file]=0
+                options[patch]=0
+                options[ref]=0
+                ;;
+            C)
+                options[clang]=1
+                options[uncrustify]=0
+                ;;
+            U)
+                options[uncrustify]=1
+                options[clang]=0
+                ;;
+            c) options[cfg]="$OPTIND" ;;
+            ?|h)
+                usage
+                exit 0
+                ;;
+            *)
+                usage
+                exit 1
+                ;;
+        esac
+    done
+
+    options[cfg]="$(cfg)"
+
+    [ -f "${options[cfg]}" ] || \
+        abort "Config '%s' does not exist" "${options[cfg]}"
+
+    shift $((OPTIND - 1))
+    args=( "$@" )
+
+    if [ ${#args[@]} -eq 0 ]; then
+        # exit on error globally, not only in subshell
+        default_arg > /dev/null
+        args=( "$(default_arg)" )
+    fi
+
+    if [ "${args[0]}" = "/dev/stdin" ]; then
+        TMP_FILE="/tmp/libevent.checkpatch.$RANDOM"
+        cat > "$TMP_FILE"
+        trap "rm '$TMP_FILE'" EXIT
+
+        args[0]="$TMP_FILE"
+    fi
+}
+
+function diff() { command diff --color=always "$@"; }
+
+function clang_style()
+{
+    local c="${options[cfg]}"
+    echo "{ $(sed -e 's/#.*//' -e '/---/d' -e '/\.\.\./d' "$c" | tr $'\n' ,) }"
+}
+function clang_format() { clang-format --style="$(clang_style)" "$@"; }
+function clang_format_diff() { clang-format-diff --style="$(clang_style)" "$@"; }
+# for non-bare repo will work
+function clang_format_git()
+{ git format-patch --stdout "$@" -1 | clang_format_diff; }
+
+function uncrustify() { command uncrustify -c "${options[cfg]}" "$@"; }
+function uncrustify_frag() { uncrustify -l C --frag "$@"; }
+function uncrustify_indent_off() { echo '/* *INDENT-OFF* */'; }
+function uncrustify_indent_on() { echo '/* *INDENT-ON* */'; }
+function git_hunk()
+{
+    local ref=$1 f=$2
+    shift 2
+    git cat-file -p $ref:$f
+}
+function uncrustify_git_indent_hunk()
+{
+    local start=$1 end=$2
+    shift 2
+
+    # Will be beatier with tee(1), but doh bash async substitution
+    { uncrustify_indent_off; git_hunk "$@" | head -n$((start - 1)); }
+    { uncrustify_indent_on;  git_hunk "$@" | head -n$((end - 1)) | tail -n+$start; }
+    { uncrustify_indent_off; git_hunk "$@" | tail -n+$((end + 1)); }
+}
+function strip()
+{
+    local start=$1 end=$2
+    shift 2
+
+    # seek indent_{on,off}()
+    let start+=2
+    head -n$end | tail -n+$start
+}
+function patch_ranges()
+{
+    egrep -o '^@@ -[0-9]+(,[0-9]+|) \+[0-9]+(,[0-9]+|) @@' | \
+        cut -d' ' -f3
+}
+function git_ranges()
+{
+    local ref=$1 f=$2
+    shift 2
+
+    git diff -W $ref^..$ref -- $f | patch_ranges
+}
+function diff_substitute()
+{
+    local f="$1"
+    shift
+
+    sed \
+        -e "s#^--- /dev/fd.*\$#--- a/$f#" \
+        -e "s#^+++ /dev/fd.*\$#+++ b/$f#"
+}
+function uncrustify_git()
+{
+    local ref=$1 r f start end length
+    shift
+
+    local files=( $(git diff --name-only $ref^..$ref | egrep "\.(c|h)$") )
+    for f in "${files[@]}"; do
+        local ranges=( $(git_ranges $ref "$f") )
+        for r in "${ranges[@]}"; do
+            [[ ! "$r" =~ ^\+([0-9]+)(,([0-9]+)|)$ ]] && continue
+            start=${BASH_REMATCH[1]}
+            [ -n "${BASH_REMATCH[3]}" ] && \
+                length=${BASH_REMATCH[3]} || \
+                length=1
+            end=$((start + length))
+            echo "Range: $start:$end ($length)" >&2
+
+            diff -u \
+                <(uncrustify_git_indent_hunk $start $end $ref "$f" | strip $start $end) \
+                <(uncrustify_git_indent_hunk $start $end $ref "$f" | uncrustify_frag | strip $start $end) \
+            | diff_substitute "$f"
+        done
+    done
+}
+function uncrustify_diff() { abort "Not implemented"; }
+function uncrustify_file() { uncrustify -f "$@"; }
+
+function checker()
+{
+    local c=$1 u=$2
+    shift 2
+
+    [ "${options[clang]}" -eq 0 ] || {
+        $c "$@"
+        return
+    }
+    [ "${options[uncrustify]}" -eq 0 ] || {
+        $u "$@"
+        return
+    }
+}
+function check_patch() { checker clang_format_diff uncrustify_diff "$@"; }
+function check_file() { checker clang_format uncrustify_file "$@"; }
+function check_ref() { checker clang_format_git uncrustify_git "$@"; }
+
+function check_arg()
+{
+    [ "${options[patch]}" -eq 0 ] || {
+        check_patch "$@"
+        return
+    }
+    [ "${options[file]}" -eq 0 ] || {
+        check_file "$@"
+        return
+    }
+    [ "${options[file_diff]}" -eq 0 ] || {
+        diff -u "$@" <(check_file "$@") | diff_substitute "$@"
+        return
+    }
+    [ "${options[ref]}" -eq 0 ] || {
+        check_ref "$@"
+        return
+    }
+}
+
+function main()
+{
+    local a
+    for a in "${args}"; do
+        check_arg "$a"
+    done
+}
+
+declare -A options
+parse_options "$@"
+
+main "$@" | less -FRSX
diff --git a/sntp/libevent/cmake/AddCompilerFlags.cmake b/sntp/libevent/cmake/AddCompilerFlags.cmake
new file mode 100644 (file)
index 0000000..9dc21d0
--- /dev/null
@@ -0,0 +1,13 @@
+include(CheckCCompilerFlag)
+
+macro(add_compiler_flags)
+       foreach(flag ${ARGN})
+               string(REGEX REPLACE "[-.+/:= ]" "_" _flag_esc "${flag}")
+
+               check_c_compiler_flag("${flag}" check_c_compiler_flag_${_flag_esc})
+
+               if (check_c_compiler_flag_${_flag_esc})
+                       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${flag}")
+               endif()
+       endforeach()
+endmacro()
diff --git a/sntp/libevent/cmake/AddEventLibrary.cmake b/sntp/libevent/cmake/AddEventLibrary.cmake
new file mode 100644 (file)
index 0000000..04f5837
--- /dev/null
@@ -0,0 +1,193 @@
+include(CMakeParseArguments)
+
+set(LIBEVENT_SHARED_LIBRARIES "")
+set(LIBEVENT_STATIC_LIBRARIES "")
+
+macro(set_event_shared_lib_flags LIB_NAME)
+    set_target_properties("${LIB_NAME}_shared" PROPERTIES
+        COMPILE_FLAGS ${ARGN})
+    set_target_properties("${LIB_NAME}_shared" PROPERTIES
+        LINK_FLAGS ${ARGN})
+endmacro()
+
+macro(generate_pkgconfig LIB_NAME)
+    set(prefix      ${CMAKE_INSTALL_PREFIX})
+    set(exec_prefix ${CMAKE_INSTALL_PREFIX})
+    set(libdir      ${CMAKE_INSTALL_PREFIX}/lib)
+    set(includedir  ${CMAKE_INSTALL_PREFIX}/include)
+
+    set(VERSION ${EVENT_ABI_LIBVERSION})
+
+    set(LIBS         "")
+    foreach (LIB ${LIB_PLATFORM})
+        set(LIBS "${LIBS} -L${LIB}")
+    endforeach()
+
+    set(OPENSSL_LIBS "")
+    foreach(LIB ${OPENSSL_LIBRARIES})
+        set(OPENSSL_LIBS "${OPENSSL_LIBS} -L${LIB}")
+    endforeach()
+
+    configure_file("lib${LIB_NAME}.pc.in" "lib${LIB_NAME}.pc" @ONLY)
+    install(
+        FILES "${CMAKE_CURRENT_BINARY_DIR}/lib${LIB_NAME}.pc"
+        DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig"
+    )
+endmacro()
+
+# LIB_NAME maybe event_core, event_extra, event_openssl, event_pthreads or event.
+# Targets whose LIB_NAME is not 'event' should be exported and installed.
+macro(export_install_target TYPE LIB_NAME OUTER_INCLUDES)
+    if("${LIB_NAME}" STREQUAL "event")
+        install(TARGETS "${LIB_NAME}_${TYPE}"
+            LIBRARY DESTINATION "lib" COMPONENT lib
+            ARCHIVE DESTINATION "lib" COMPONENT lib
+            RUNTIME DESTINATION "lib" COMPONENT lib
+            COMPONENT dev
+        )
+    else()
+        string(REPLACE "event_" "" PURE_NAME ${LIB_NAME})
+        string(TOUPPER ${TYPE} UPPER_TYPE)
+        list(APPEND LIBEVENT_${UPPER_TYPE}_LIBRARIES "${PURE_NAME}")
+        set(OUTER_INCS)
+        if (NOT "${OUTER_INCLUDES}" STREQUAL "NONE")
+            set(OUTER_INCS ${OUTER_INCLUDES})
+        endif()
+        target_include_directories("${LIB_NAME}_${TYPE}"
+            PUBLIC  "$<INSTALL_INTERFACE:include>"
+                    "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
+                    "$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>"
+                    ${OUTER_INCS}
+        )
+        set_target_properties("${LIB_NAME}_${TYPE}" PROPERTIES EXPORT_NAME ${PURE_NAME})
+        export(TARGETS "${LIB_NAME}_${TYPE}"
+            NAMESPACE ${PROJECT_NAME}::
+            FILE "${PROJECT_BINARY_DIR}/LibeventTargets-${TYPE}.cmake"
+            APPEND
+        )
+        install(TARGETS "${LIB_NAME}_${TYPE}"
+            EXPORT LibeventTargets-${TYPE}
+            LIBRARY DESTINATION "lib" COMPONENT lib
+            ARCHIVE DESTINATION "lib" COMPONENT lib
+            RUNTIME DESTINATION "lib" COMPONENT lib
+            COMPONENT dev
+        )
+    endif()
+endmacro()
+
+# Global variables that it uses:
+# - EVENT_ABI_LIBVERSION
+# - EVENT_ABI_LIBVERSION_CURRENT
+# - EVENT_ABI_LIBVERSION_REVISION
+# - EVENT_ABI_LIBVERSION_AGE
+# - EVENT_PACKAGE_RELEASE
+# - CMAKE_THREAD_LIBS_INIT LIB_PLATFORM
+# - OPENSSL_LIBRARIES
+# - EVENT_SHARED_FLAGS
+# - EVENT_LIBRARY_STATIC
+# - EVENT_LIBRARY_SHARED
+#
+# Exported variables:
+# - LIBEVENT_SHARED_LIBRARIES
+# - LIBEVENT_STATIC_LIBRARIES
+macro(add_event_library LIB_NAME)
+    cmake_parse_arguments(LIB
+        "" # Options
+        "VERSION" # One val
+        "SOURCES;LIBRARIES;INNER_LIBRARIES;OUTER_INCLUDES" # Multi val
+        ${ARGN}
+    )
+
+    if ("${LIB_OUTER_INCLUDES}" STREQUAL "")
+        set(LIB_OUTER_INCLUDES NONE)
+    endif()
+    set(ADD_EVENT_LIBRARY_INTERFACE)
+
+    if (${EVENT_LIBRARY_STATIC})
+        add_library("${LIB_NAME}_static" STATIC ${LIB_SOURCES})
+        set_target_properties("${LIB_NAME}_static" PROPERTIES
+            OUTPUT_NAME "${LIB_NAME}"
+            CLEAN_DIRECT_OUTPUT 1)
+
+        if(LIB_INNER_LIBRARIES)
+            set(INNER_LIBRARIES "${LIB_INNER_LIBRARIES}_static")
+        endif()
+        target_link_libraries("${LIB_NAME}_static"
+            ${CMAKE_THREAD_LIBS_INIT}
+            ${LIB_PLATFORM}
+            ${INNER_LIBRARIES}
+            ${LIB_LIBRARIES})
+
+        export_install_target(static "${LIB_NAME}" "${LIB_OUTER_INCLUDES}")
+
+        set(ADD_EVENT_LIBRARY_INTERFACE "${LIB_NAME}_static")
+    endif()
+
+    if (${EVENT_LIBRARY_SHARED})
+        add_library("${LIB_NAME}_shared" SHARED ${LIB_SOURCES})
+
+        if(LIB_INNER_LIBRARIES)
+            set(INNER_LIBRARIES "${LIB_INNER_LIBRARIES}_shared")
+        endif()
+        target_link_libraries("${LIB_NAME}_shared"
+            ${CMAKE_THREAD_LIBS_INIT}
+            ${LIB_PLATFORM}
+            ${INNER_LIBRARIES}
+            ${LIB_LIBRARIES})
+
+        if (EVENT_SHARED_FLAGS)
+            set_event_shared_lib_flags("${LIB_NAME}" "${EVENT_SHARED_FLAGS}")
+        endif()
+
+        if (WIN32)
+            set_target_properties(
+                "${LIB_NAME}_shared" PROPERTIES
+                OUTPUT_NAME "${LIB_NAME}"
+                SOVERSION ${EVENT_ABI_LIBVERSION})
+        elseif (APPLE)
+            math(EXPR COMPATIBILITY_VERSION "${EVENT_ABI_LIBVERSION_CURRENT}+1")
+            math(EXPR CURRENT_MINUS_AGE "${EVENT_ABI_LIBVERSION_CURRENT}-${EVENT_ABI_LIBVERSION_AGE}")
+            set_target_properties(
+                "${LIB_NAME}_shared" PROPERTIES
+                OUTPUT_NAME "${LIB_NAME}-${EVENT_PACKAGE_RELEASE}.${CURRENT_MINUS_AGE}"
+                INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib"
+                LINK_FLAGS "-compatibility_version ${COMPATIBILITY_VERSION} -current_version ${COMPATIBILITY_VERSION}.${EVENT_ABI_LIBVERSION_REVISION}")
+        else()
+            math(EXPR CURRENT_MINUS_AGE "${EVENT_ABI_LIBVERSION_CURRENT}-${EVENT_ABI_LIBVERSION_AGE}")
+            set_target_properties(
+                "${LIB_NAME}_shared" PROPERTIES
+                OUTPUT_NAME "${LIB_NAME}-${EVENT_PACKAGE_RELEASE}"
+                VERSION "${CURRENT_MINUS_AGE}.${EVENT_ABI_LIBVERSION_AGE}.${EVENT_ABI_LIBVERSION_REVISION}"
+                SOVERSION "${CURRENT_MINUS_AGE}"
+                INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
+        endif()
+
+        if (NOT WIN32)
+            set(LIB_LINK_NAME
+                "${CMAKE_SHARED_LIBRARY_PREFIX}${LIB_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}")
+
+            add_custom_command(TARGET ${LIB_NAME}_shared
+                POST_BUILD
+                COMMAND ${CMAKE_COMMAND} -E create_symlink
+                    "$<TARGET_FILE_NAME:${LIB_NAME}_shared>"
+                    "${LIB_LINK_NAME}"
+                WORKING_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
+        endif()
+
+        export_install_target(shared "${LIB_NAME}" "${LIB_OUTER_INCLUDES}")
+
+        set(ADD_EVENT_LIBRARY_INTERFACE "${LIB_NAME}_shared")
+
+        if (NOT WIN32)
+            install(FILES
+                "$<TARGET_FILE_DIR:${LIB_NAME}_shared>/${LIB_LINK_NAME}"
+                DESTINATION "lib"
+                COMPONENT lib)
+        endif()
+    endif()
+
+    add_library(${LIB_NAME} INTERFACE)
+    target_link_libraries(${LIB_NAME} INTERFACE ${ADD_EVENT_LIBRARY_INTERFACE})
+
+    generate_pkgconfig("${LIB_NAME}")
+endmacro()
diff --git a/sntp/libevent/cmake/COPYING-CMAKE-SCRIPTS b/sntp/libevent/cmake/COPYING-CMAKE-SCRIPTS
new file mode 100644 (file)
index 0000000..ab3c4d2
--- /dev/null
@@ -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/sntp/libevent/cmake/CheckConstExists.cmake b/sntp/libevent/cmake/CheckConstExists.cmake
new file mode 100644 (file)
index 0000000..de07458
--- /dev/null
@@ -0,0 +1,25 @@
+include(CheckCSourceCompiles)
+
+macro(check_const_exists CONST FILES VARIABLE)
+  if (NOT DEFINED ${VARIABLE})
+    set(check_const_exists_source "")
+    foreach(file ${FILES})
+      set(check_const_exists_source
+          "${check_const_exists_source}
+          #include <${file}>")
+    endforeach()
+    set(check_const_exists_source
+        "${check_const_exists_source}
+        int main() { (void)${CONST}; return 0; }")
+
+    check_c_source_compiles("${check_const_exists_source}" ${VARIABLE})
+
+    if (${${VARIABLE}})
+      set(${VARIABLE} 1 CACHE INTERNAL "Have const ${CONST}")
+      message(STATUS "Looking for ${CONST} - found")
+    else()
+      set(${VARIABLE} 0 CACHE INTERNAL "Have const ${CONST}")
+      message(STATUS "Looking for ${CONST} - not found")
+    endif()
+  endif()
+endmacro(check_const_exists)
diff --git a/sntp/libevent/cmake/CheckFileOffsetBits.c b/sntp/libevent/cmake/CheckFileOffsetBits.c
new file mode 100644 (file)
index 0000000..d948fec
--- /dev/null
@@ -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/sntp/libevent/cmake/CheckFileOffsetBits.cmake b/sntp/libevent/cmake/CheckFileOffsetBits.cmake
new file mode 100644 (file)
index 0000000..1253440
--- /dev/null
@@ -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/sntp/libevent/cmake/CheckFunctionKeywords.cmake b/sntp/libevent/cmake/CheckFunctionKeywords.cmake
new file mode 100644 (file)
index 0000000..3d968b8
--- /dev/null
@@ -0,0 +1,14 @@
+include(CheckCSourceCompiles)
+
+macro(check_function_keywords _wordlist)
+  set(${_result} "")
+  foreach(flag ${_wordlist})
+    string(REGEX REPLACE "[-+/ ()]" "_" flagname "${flag}")
+    string(TOUPPER "${flagname}" flagname)
+    set(have_flag "HAVE_${flagname}")
+    check_c_source_compiles("${flag} void func(); void func() { } int main() { func(); return 0; }" ${have_flag})
+    if(${have_flag} AND NOT ${_result})
+      set(${_result} "${flag}")
+    endif(${have_flag} AND NOT ${_result})
+  endforeach(flag)
+endmacro(check_function_keywords)
diff --git a/sntp/libevent/cmake/CheckPrototypeDefinition.c.in b/sntp/libevent/cmake/CheckPrototypeDefinition.c.in
new file mode 100644 (file)
index 0000000..a97344a
--- /dev/null
@@ -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/sntp/libevent/cmake/CheckPrototypeDefinition.cmake b/sntp/libevent/cmake/CheckPrototypeDefinition.cmake
new file mode 100644 (file)
index 0000000..940d1ff
--- /dev/null
@@ -0,0 +1,82 @@
+# - 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})
+
+        configure_file("${PROJECT_SOURCE_DIR}/cmake/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()
+endfunction(CHECK_PROTOTYPE_DEFINITION)
diff --git a/sntp/libevent/cmake/CheckWorkingKqueue.cmake b/sntp/libevent/cmake/CheckWorkingKqueue.cmake
new file mode 100644 (file)
index 0000000..f22f011
--- /dev/null
@@ -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[80000];
+
+    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)
diff --git a/sntp/libevent/cmake/CodeCoverage.cmake b/sntp/libevent/cmake/CodeCoverage.cmake
new file mode 100644 (file)
index 0000000..eba85b3
--- /dev/null
@@ -0,0 +1,165 @@
+#
+# 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.
+#
+# 2016-11-02, Azat Khuzhin
+# - Adopt for C compiler only (libevent)
+#
+# 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)
+       # 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_C_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/sntp/libevent/cmake/Copyright.txt b/sntp/libevent/cmake/Copyright.txt
new file mode 100644 (file)
index 0000000..813124f
--- /dev/null
@@ -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/sntp/libevent/cmake/LibeventConfig.cmake.in b/sntp/libevent/cmake/LibeventConfig.cmake.in
new file mode 100644 (file)
index 0000000..7b808c3
--- /dev/null
@@ -0,0 +1,183 @@
+# - Config file for the Libevent package
+# It defines the following variables
+#  LIBEVENT_FOUND            - true if libevent and all required components found on the system
+#  LIBEVENT_xxx_FOUND        - true if component xxx(see available components) found on the system
+#  LIBEVENT_VERSION          - libevent version in format Major.Minor.Patch
+#  LIBEVENT_INCLUDE_DIRS     - directories where libevent header is located.
+#  LIBEVENT_INCLUDE_DIR      - same as DIRS
+#  LIBEVENT_LIBRARIES        - libevent library to link against.
+#  LIBEVENT_LIBRARY          - same as LIBRARIES
+#
+# These variables are deprecated, don't use them.
+#  LIBEVENT_STATIC_LIBRARIES - libraries to link against (archive/static)
+#  LIBEVENT_SHARED_LIBRARIES - libraries to link against (shared)
+#
+# When you try to locate the libevent libraries, you should specify which components you want to use.
+# The following table lists all available components. If none is given, all imported targets will used.
+#  core        - the core functons of libevent
+#  extra       - extra functions, contains http, dns and rpc
+#  pthreads    - multiple threads for libevent, not exists on Windows
+#  openssl     - openssl support for libevent
+#
+# By default, the shared libraries of libevent will be found. To find the static ones instead,
+# you must set the LIBEVENT_STATIC_LINK variable to TRUE before calling find_package(Libevent ...).
+# If no component provided, all components will be used.
+# example:
+#  set(LIBEVENT_STATIC_LINK TRUE)
+#  find_package(Libevent 2.2 REQUIRED COMPONENTS core)
+#  include_directories(${LIBEVENT_INCLUDE_DIRS})  # Can be omitted
+#  target_link_libraries(myapp ${LIBEVENT_LIBRARIES})
+#    or target_link_libraries(myapp libevent::core)
+#
+# find_package() can handle dependencies automatically. For example, given the 'openssl' component,
+# all dependencies (libevent_core, libssl, libcrypto and openssl include directories) will be found.
+
+set(CONFIG_FOR_INSTALL_TREE @CONFIG_FOR_INSTALL_TREE@)
+
+set(LIBEVENT_VERSION @EVENT_PACKAGE_VERSION@)
+
+# IMPORTED targets from LibeventTargets.cmake
+set(LIBEVENT_STATIC_LIBRARIES "@LIBEVENT_STATIC_LIBRARIES@")
+set(LIBEVENT_SHARED_LIBRARIES "@LIBEVENT_SHARED_LIBRARIES@")
+
+# Default to the same type as libevent was built:
+if(NOT DEFINED LIBEVENT_STATIC_LINK)
+    set(LIBEVENT_STATIC_LINK NOT @EVENT_LIBRARY_SHARED@)
+endif()
+
+set(CMAKE_FIND_LIBRARY_SUFFIXES_SAVE "${CMAKE_FIND_LIBRARY_SUFFIXES}")
+if(${LIBEVENT_STATIC_LINK})
+    set(_LIB_TYPE static)
+    set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX})
+    set(_AVAILABLE_LIBS "${LIBEVENT_STATIC_LIBRARIES}")
+else()
+    set(_LIB_TYPE shared)
+    set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX})
+    set(_AVAILABLE_LIBS "${LIBEVENT_SHARED_LIBRARIES}")
+endif()
+
+# Get the path of the current file.
+get_filename_component(LIBEVENT_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+get_filename_component(_INSTALL_PREFIX "${LIBEVENT_CMAKE_DIR}/../../.." ABSOLUTE)
+
+macro(message_if_needed _flag _msg)
+    if (NOT ${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
+        message(${_flag} "${_msg}")
+    endif()
+endmacro()
+
+macro(no_component_msg _comp)
+    if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED_${_comp})
+        set(pthreadlib)
+        if(NOT WIN32)
+            set(pthreadlib ", pthreads")
+        endif()
+        message(FATAL_ERROR "Your libevent library does not contain a ${_comp} component!\n"
+                "The valid components are core, extra${pthreadlib} and openssl.")
+    else()
+        message_if_needed(WARNING "Your libevent library does not contain a ${_comp} component!")
+    endif()
+endmacro()
+
+set(_EVENT_COMPONENTS)
+if(${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS)
+    list(REMOVE_DUPLICATES ${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS)
+    foreach(_comp ${${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS})
+        list(FIND _AVAILABLE_LIBS ${_comp} _INDEX)
+        if(_INDEX GREATER -1)
+            list(APPEND _EVENT_COMPONENTS ${_comp})
+        else()
+            no_component_msg(${_comp})
+        endif()
+    endforeach()
+else()
+    set(_EVENT_COMPONENTS ${_AVAILABLE_LIBS})
+endif()
+
+set(_POSSIBLE_PKG_NAMES)
+list(APPEND _POSSIBLE_PKG_NAMES ${CMAKE_FIND_PACKAGE_NAME} LIBEVENT Libevent libevent)
+list(REMOVE_DUPLICATES _POSSIBLE_PKG_NAMES)
+
+macro(set_case_insensitive_found _comp)
+    foreach(name ${_POSSIBLE_PKG_NAMES})
+        if("${_comp}" STREQUAL "")
+            set(${name}_FOUND TRUE)
+            set(${name}_NOTFOUND FALSE)
+        else()
+            set(${name}_${_comp}_FOUND TRUE)
+            set(${name}_${_comp}_NOTFOUND FALSE)
+        endif()
+    endforeach()
+endmacro()
+
+if(CONFIG_FOR_INSTALL_TREE)
+    ## Config for install tree ----------------------------------------
+    # Find includes
+    unset(_event_h CACHE)
+    find_path(_event_h
+              NAMES event2/event.h
+              PATHS "${_INSTALL_PREFIX}/include"
+              NO_DEFAULT_PATH)
+    if(_event_h)
+        set(LIBEVENT_INCLUDE_DIRS "${_event_h}")
+        message_if_needed(STATUS "Found libevent include directory: ${_event_h}")
+    else()
+        message_if_needed(WARNING "Your libevent library does not contain header files!")
+    endif()
+
+    # Find libraries
+    macro(find_event_lib _comp)
+        unset(_event_lib CACHE)
+        find_library(_event_lib
+                    NAMES "event_${_comp}"
+                    PATHS "${_INSTALL_PREFIX}/lib"
+                    NO_DEFAULT_PATH)
+        if(_event_lib)
+            list(APPEND LIBEVENT_LIBRARIES "libevent::${_comp}")
+            set_case_insensitive_found(${_comp})
+            message_if_needed(STATUS "Found libevent component: ${_event_lib}")
+        else()
+            no_component_msg(${_comp})
+        endif()
+    endmacro()
+
+    foreach(comp ${_EVENT_COMPONENTS})
+        find_event_lib(${comp})
+    endforeach()
+else()
+    ## Config for build tree ----------------------------------------
+    set(LIBEVENT_INCLUDE_DIRS "@EVENT__INCLUDE_DIRS@")
+    foreach(_comp ${_EVENT_COMPONENTS})
+        list(APPEND LIBEVENT_LIBRARIES "libevent::${_comp}")
+        set_case_insensitive_found(${_comp})
+    endforeach()
+endif()
+
+set(LIBEVENT_INCLUDE_DIR ${LIBEVENT_INCLUDE_DIRS})
+if(LIBEVENT_LIBRARIES)
+    set(LIBEVENT_LIBRARY ${LIBEVENT_LIBRARIES})
+    if(CONFIG_FOR_INSTALL_TREE)
+        message_if_needed(STATUS "Found libevent ${LIBEVENT_VERSION} in ${_INSTALL_PREFIX}")
+    else()
+        message_if_needed(STATUS "Found libevent ${LIBEVENT_VERSION} in ${LIBEVENT_CMAKE_DIR}")
+    endif()
+
+    # Avoid including targets more than one times
+    if(NOT TARGET event_core_${_LIB_TYPE})
+        # Include the project Targets file, this contains definitions for IMPORTED targets.
+        include(${LIBEVENT_CMAKE_DIR}/LibeventTargets-${_LIB_TYPE}.cmake)
+    endif()
+else()
+    if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED)
+        message(FATAL_ERROR "Can not find any libraries for libevent.")
+    else()
+        message_if_needed(WARNING "Can not find any libraries for libevent.")
+    endif()
+endif()
+
+set(CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES_SAVE}")
+unset(_LIB_TYPE)
+unset(_AVAILABLE_LIBS)
+unset(_EVENT_COMPONENTS)
+unset(_POSSIBLE_PKG_NAMES)
+unset(_INSTALL_PREFIX)
diff --git a/sntp/libevent/cmake/LibeventConfigVersion.cmake.in b/sntp/libevent/cmake/LibeventConfigVersion.cmake.in
new file mode 100644 (file)
index 0000000..56371a8
--- /dev/null
@@ -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/sntp/libevent/cmake/Macros.cmake b/sntp/libevent/cmake/Macros.cmake
new file mode 100644 (file)
index 0000000..e480bbf
--- /dev/null
@@ -0,0 +1,36 @@
+include(CheckSymbolExists)
+include(CheckIncludeFiles)
+
+# Check if each symbol in the symbol list exists,
+# and define PREFIX__HAVE_SYMNAME to 1 if yes.
+#
+# SYMLIST: list of symbols to check
+# HEADERS: header files to be included in check code
+# PREFIX: the prefix of definition
+macro(CHECK_SYMBOLS_EXIST SYMLIST HEADERS PREFIX)
+  foreach(SYMNAME ${SYMLIST})
+    string(TOUPPER "${SYMNAME}" SYMNAME_UPPER)
+    if ("${PREFIX}" STREQUAL "")
+      set(HAVE_SYM_DEF "HAVE_${SYMNAME_UPPER}")
+    else()
+      set(HAVE_SYM_DEF "${PREFIX}__HAVE_${SYMNAME_UPPER}")
+    endif()
+    CHECK_SYMBOL_EXISTS(${SYMNAME} "${HEADERS}" ${HAVE_SYM_DEF})
+  endforeach()
+endmacro()
+
+# Check if file exists, define PREFIX__HAVE_FILE to 1 if yes,
+# and collect file to EVENT_INCLUDES
+macro(CHECK_INCLUDE_FILE_CONCAT FILE PREFIX)
+  string(REGEX REPLACE "[./]" "_" FILE_UL ${FILE})
+  string(TOUPPER "${FILE_UL}" FILE_UL_UPPER)
+  if ("${PREFIX}" STREQUAL "")
+    set(HAVE_FILE_DEF "HAVE_${FILE_UL_UPPER}")
+  else()
+    set(HAVE_FILE_DEF "${PREFIX}__HAVE_${FILE_UL_UPPER}")
+  endif()
+  CHECK_INCLUDE_FILES("${EVENT_INCLUDES};${FILE}" ${HAVE_FILE_DEF})
+  if(${HAVE_FILE_DEF})
+    set(EVENT_INCLUDES ${EVENT_INCLUDES} ${FILE})
+  endif()
+endmacro()
diff --git a/sntp/libevent/cmake/Uninstall.cmake.in b/sntp/libevent/cmake/Uninstall.cmake.in
new file mode 100644 (file)
index 0000000..c6dc09e
--- /dev/null
@@ -0,0 +1,23 @@
+# https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake
+
+if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
+  message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
+endif(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
+
+file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
+string(REGEX REPLACE "\n" ";" files "${files}")
+foreach(file ${files})
+  message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
+  if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+    exec_program(
+      "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+      OUTPUT_VARIABLE rm_out
+      RETURN_VALUE rm_retval
+      )
+    if(NOT "${rm_retval}" STREQUAL 0)
+      message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
+    endif(NOT "${rm_retval}" STREQUAL 0)
+  else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+    message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
+  endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+endforeach(file)
diff --git a/sntp/libevent/cmake/UseDoxygen.cmake b/sntp/libevent/cmake/UseDoxygen.cmake
new file mode 100644 (file)
index 0000000..3b60d5a
--- /dev/null
@@ -0,0 +1,111 @@
+# Use FindDoxygen.cmake to generate documentation.
+
+option(DOXYGEN_GENERATE_HTML  "Generate HTML"      ON)
+option(DOXYGEN_GENERATE_MAN   "Generate man pages" OFF)
+option(DOXYGEN_MAN_LINKS      "Generate man links" ON)
+option(DOXYGEN_GENERATE_LATEX "Generate LaTeX"     OFF)
+
+# If the case-insensitive value of the cmake option is one of
+# "off, no, false" or 0, it is equal to false, otherwise true.
+# And the values of the doxygen config does not exactly match it.
+# So we need to convert the cmake option to a doxygen config.
+macro(_convert_to_dx_cfg CMK_OPTION)
+  if (${CMK_OPTION})
+    set(${CMK_OPTION} YES)
+  else()
+    set(${CMK_OPTION} NO)
+  endif()
+endmacro()
+
+macro(UseDoxygen)
+  if (${CMAKE_VERSION} VERSION_LESS "3.9")
+    # Old versions of cmake have poor support for Doxygen generation.
+    message(FATAL_ERROR "Doxygen generation only enabled for cmake 3.9 and higher")
+  else()
+    find_package(Doxygen)
+    if (DOXYGEN_FOUND)
+      set(DOXYGEN_PROJECT_NAME ${PROJECT_NAME})
+      set(DOXYGEN_PROJECT_NUMBER ${EVENT_PACKAGE_VERSION})
+      set(DOXYGEN_PROJECT_BRIEF "Event notification library")
+      set(DOXYGEN_OUTPUT_DIRECTORY doxygen)
+      set(DOXYGEN_STRIP_FROM_PATH include)
+      set(DOXYGEN_JAVADOC_AUTOBRIEF YES)
+      set(DOXYGEN_OPTIMIZE_OUTPUT_FOR_C YES)
+      set(DOXYGEN_SORT_BRIEF_DOCS YES)
+      set(DOXYGEN_RECURSIVE NO)
+
+      _convert_to_dx_cfg(DOXYGEN_GENERATE_HTML)
+      _convert_to_dx_cfg(DOXYGEN_GENERATE_MAN)
+      _convert_to_dx_cfg(DOXYGEN_MAN_LINKS)
+      _convert_to_dx_cfg(DOXYGEN_GENERATE_LATEX)
+
+      set(DOXYGEN_LATEX_CMD_NAME latex)
+      set(DOXYGEN_PAPER_TYPE a4wide)
+      set(DOXYGEN_PDF_HYPERLINKS NO)
+
+      set(DOXYGEN_GENERATE_RTF NO)
+      set(DOXYGEN_GENERATE_XML NO)
+      set(DOXYGEN_GENERATE_CHI NO)
+
+      set(DOXYGEN_PREDEFINED TAILQ_ENTRY
+        RB_ENTRY
+        EVENT_DEFINED_TQENTRY_
+        EVENT_IN_DOXYGEN_
+      )
+
+      set(DOX_INPUT include/event2/buffer.h
+        include/event2/buffer_compat.h
+        include/event2/bufferevent.h
+        include/event2/bufferevent_compat.h
+        include/event2/bufferevent_ssl.h
+        include/event2/dns.h
+        include/event2/dns_compat.h
+        include/event2/event.h
+        include/event2/event_compat.h
+        include/event2/http.h
+        include/event2/http_compat.h
+        include/event2/listener.h
+        include/event2/rpc.h
+        include/event2/rpc_compat.h
+        include/event2/tag.h
+        include/event2/tag_compat.h
+        include/event2/thread.h
+        include/event2/util.h
+      )
+      # Add 'doxygen' target
+      doxygen_add_docs(doxygen
+        ${DOX_INPUT}
+        ALL
+        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+        COMMENT "Generating doxygen documentation for ${PROJECT_NAME}..."
+      )
+
+      # Use 'make clean' to remove the generated directory
+      set_property(DIRECTORY
+        PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
+        "${PROJECT_BINARY_DIR}/${DOXYGEN_OUTPUT_DIRECTORY}"
+      )
+
+      # Install html into <prefix>/share/doc/<project>
+      if ("${DOXYGEN_GENERATE_HTML}" STREQUAL "YES")
+        install(DIRECTORY
+          ${PROJECT_BINARY_DIR}/${DOXYGEN_OUTPUT_DIRECTORY}/html
+          DESTINATION ${CMAKE_INSTALL_PREFIX}/share/doc/${PROJECT_NAME}
+          COMPONENT doc
+        )
+      endif()
+
+      # Install manual into <prefix>/share/man/man3
+      if ("${DOXYGEN_GENERATE_MAN}" STREQUAL "YES")
+        install(DIRECTORY
+          ${PROJECT_BINARY_DIR}/${DOXYGEN_OUTPUT_DIRECTORY}/man/man3
+          DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man
+          COMPONENT doc
+        )
+      endif()
+
+    else(DOXYGEN_FOUND)
+      message(FATAL_ERROR "Doxygen command not found, set EVENT__DOXYGEN to disable")
+    endif (DOXYGEN_FOUND)
+  endif()
+endmacro()
diff --git a/sntp/libevent/cmake/VersionViaGit.cmake b/sntp/libevent/cmake/VersionViaGit.cmake
new file mode 100644 (file)
index 0000000..24eb6af
--- /dev/null
@@ -0,0 +1,66 @@
+# This module defines the following variables utilizing
+# git to determine the parent tag. And if found the macro
+# will attempt to parse them in the github tag fomat
+#
+# Useful for auto-versioning in our CMakeLists
+#
+#  EVENT_GIT___VERSION_MAJOR - Major version.
+#  EVENT_GIT___VERSION_MINOR - Minor version
+#  EVENT_GIT___VERSION_STAGE - Stage version
+#
+# Example usage:
+#
+# event_fuzzy_version_from_git()
+#    message("Libvent major=${EVENT_GIT___VERSION_MAJOR}")
+#    message("        minor=${EVENT_GIT___VERSION_MINOR}")
+#    message("        patch=${EVENT_GIT___VERSION_PATCH}")
+#    message("        stage=${EVENT_GIT___VERSION_STAGE}")
+# endif()
+
+include(FindGit)
+
+macro(event_fuzzy_version_from_git)
+       # set our defaults.
+       set(EVENT_GIT___VERSION_MAJOR 2)
+       set(EVENT_GIT___VERSION_MINOR 1)
+       set(EVENT_GIT___VERSION_PATCH 12)
+       set(EVENT_GIT___VERSION_STAGE "stable")
+
+       find_package(Git)
+
+       if (GIT_FOUND)
+               execute_process(
+                       COMMAND
+                               ${GIT_EXECUTABLE} describe --abbrev=0 --always
+                       WORKING_DIRECTORY
+                               ${PROJECT_SOURCE_DIR}
+                       RESULT_VARIABLE
+                               GITRET
+                       OUTPUT_VARIABLE
+                               GITVERSION
+                       OUTPUT_STRIP_TRAILING_WHITESPACE
+               )
+
+               string(REGEX REPLACE "[\\._-]" ";" VERSION_LIST "${GITVERSION}")
+               if(VERSION_LIST)
+                       list(LENGTH VERSION_LIST VERSION_LIST_LENGTH)
+               endif()
+
+               if ((GITRET EQUAL 0) AND (VERSION_LIST_LENGTH EQUAL 5))
+                       list(GET VERSION_LIST 1 _MAJOR)
+                       list(GET VERSION_LIST 2 _MINOR)
+                       list(GET VERSION_LIST 3 _PATCH)
+                       list(GET VERSION_LIST 4 _STAGE)
+
+                       set(_DEFAULT_VERSION "${EVENT_GIT___VERSION_MAJOR}.${EVENT_GIT___VERSION_MINOR}.${EVENT_GIT___VERSION_PATCH}-${EVENT_GIT___VERSION_STAGE}")
+                       set(_GIT_VERSION     "${_MAJOR}.${_MINOR}.${_PATCH}-${_STAGE}")
+
+                       if (${_DEFAULT_VERSION} VERSION_LESS ${_GIT_VERSION})
+                               set(EVENT_GIT___VERSION_MAJOR ${_MAJOR})
+                               set(EVENT_GIT___VERSION_MINOR ${_MINOR})
+                               set(EVENT_GIT___VERSION_PATCH ${_PATCH})
+                               set(EVENT_GIT___VERSION_STAGE ${_STAGE})
+                       endif()
+               endif()
+       endif()
+endmacro()
diff --git a/sntp/libevent/compile b/sntp/libevent/compile
new file mode 100755 (executable)
index 0000000..a85b723
--- /dev/null
@@ -0,0 +1,347 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2012-10-14.11; # UTC
+
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" ""       $nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+  file=$1
+  case $file in
+    / | /[!/]*) # absolute file, and not a UNC file
+      if test -z "$file_conv"; then
+       # lazily determine how to convert abs files
+       case `uname -s` in
+         MINGW*)
+           file_conv=mingw
+           ;;
+         CYGWIN*)
+           file_conv=cygwin
+           ;;
+         *)
+           file_conv=wine
+           ;;
+       esac
+      fi
+      case $file_conv/,$2, in
+       *,$file_conv,*)
+         ;;
+       mingw/*)
+         file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+         ;;
+       cygwin/*)
+         file=`cygpath -m "$file" || echo "$file"`
+         ;;
+       wine/*)
+         file=`winepath -w "$file" || echo "$file"`
+         ;;
+      esac
+      ;;
+  esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+  func_file_conv "$1"
+  if test -z "$lib_path"; then
+    lib_path=$file
+  else
+    lib_path="$lib_path;$file"
+  fi
+  linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+  lib=$1
+  found=no
+  save_IFS=$IFS
+  IFS=';'
+  for dir in $lib_path $LIB
+  do
+    IFS=$save_IFS
+    if $shared && test -f "$dir/$lib.dll.lib"; then
+      found=yes
+      lib=$dir/$lib.dll.lib
+      break
+    fi
+    if test -f "$dir/$lib.lib"; then
+      found=yes
+      lib=$dir/$lib.lib
+      break
+    fi
+    if test -f "$dir/lib$lib.a"; then
+      found=yes
+      lib=$dir/lib$lib.a
+      break
+    fi
+  done
+  IFS=$save_IFS
+
+  if test "$found" != yes; then
+    lib=$lib.lib
+  fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+  # Assume a capable shell
+  lib_path=
+  shared=:
+  linker_opts=
+  for arg
+  do
+    if test -n "$eat"; then
+      eat=
+    else
+      case $1 in
+       -o)
+         # configure might choose to run compile as 'compile cc -o foo foo.c'.
+         eat=1
+         case $2 in
+           *.o | *.[oO][bB][jJ])
+             func_file_conv "$2"
+             set x "$@" -Fo"$file"
+             shift
+             ;;
+           *)
+             func_file_conv "$2"
+             set x "$@" -Fe"$file"
+             shift
+             ;;
+         esac
+         ;;
+       -I)
+         eat=1
+         func_file_conv "$2" mingw
+         set x "$@" -I"$file"
+         shift
+         ;;
+       -I*)
+         func_file_conv "${1#-I}" mingw
+         set x "$@" -I"$file"
+         shift
+         ;;
+       -l)
+         eat=1
+         func_cl_dashl "$2"
+         set x "$@" "$lib"
+         shift
+         ;;
+       -l*)
+         func_cl_dashl "${1#-l}"
+         set x "$@" "$lib"
+         shift
+         ;;
+       -L)
+         eat=1
+         func_cl_dashL "$2"
+         ;;
+       -L*)
+         func_cl_dashL "${1#-L}"
+         ;;
+       -static)
+         shared=false
+         ;;
+       -Wl,*)
+         arg=${1#-Wl,}
+         save_ifs="$IFS"; IFS=','
+         for flag in $arg; do
+           IFS="$save_ifs"
+           linker_opts="$linker_opts $flag"
+         done
+         IFS="$save_ifs"
+         ;;
+       -Xlinker)
+         eat=1
+         linker_opts="$linker_opts $2"
+         ;;
+       -*)
+         set x "$@" "$1"
+         shift
+         ;;
+       *.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+         func_file_conv "$1"
+         set x "$@" -Tp"$file"
+         shift
+         ;;
+       *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+         func_file_conv "$1" mingw
+         set x "$@" "$file"
+         shift
+         ;;
+       *)
+         set x "$@" "$1"
+         shift
+         ;;
+      esac
+    fi
+    shift
+  done
+  if test -n "$linker_opts"; then
+    linker_opts="-link$linker_opts"
+  fi
+  exec "$@" $linker_opts
+  exit 1
+}
+
+eat=
+
+case $1 in
+  '')
+     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "compile $scriptversion"
+    exit $?
+    ;;
+  cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
+    func_cl_wrapper "$@"      # Doesn't return...
+    ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+  if test -n "$eat"; then
+    eat=
+  else
+    case $1 in
+      -o)
+       # configure might choose to run compile as 'compile cc -o foo foo.c'.
+       # So we strip '-o arg' only if arg is an object.
+       eat=1
+       case $2 in
+         *.o | *.obj)
+           ofile=$2
+           ;;
+         *)
+           set x "$@" -o "$2"
+           shift
+           ;;
+       esac
+       ;;
+      *.c)
+       cfile=$1
+       set x "$@" "$1"
+       shift
+       ;;
+      *)
+       set x "$@" "$1"
+       shift
+       ;;
+    esac
+  fi
+  shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+  # If no '-o' option was seen then we might have been invoked from a
+  # pattern rule where we don't need one.  That is ok -- this is a
+  # normal compilation that the losing compiler can handle.  If no
+  # '.c' file was seen then we are probably linking.  That is also
+  # ok.
+  exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file.  Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+  if mkdir "$lockdir" >/dev/null 2>&1; then
+    break
+  fi
+  sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+  test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+  test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/sntp/libevent/config.guess b/sntp/libevent/config.guess
new file mode 100755 (executable)
index 0000000..0bb53ae
--- /dev/null
@@ -0,0 +1,1433 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright 1992-2015 Free Software Foundation, Inc.
+
+timestamp='2015-03-04'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+#
+# Please send patches to <config-patches@gnu.org>.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2015 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+       for c in cc gcc c89 c99 ; do
+         if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+            CC_FOR_BUILD="$c"; break ;
+         fi ;
+       done ;
+       if test x"$CC_FOR_BUILD" = x ; then
+         CC_FOR_BUILD=no_compiler_found ;
+       fi
+       ;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+       PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "${UNAME_SYSTEM}" in
+Linux|GNU|GNU/*)
+       # If the system lacks a compiler, then just pick glibc.
+       # We could probably try harder.
+       LIBC=gnu
+
+       eval $set_cc_for_build
+       cat <<-EOF > $dummy.c
+       #include <features.h>
+       #if defined(__UCLIBC__)
+       LIBC=uclibc
+       #elif defined(__dietlibc__)
+       LIBC=dietlibc
+       #else
+       LIBC=gnu
+       #endif
+       EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+       ;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+       # NetBSD (nbsd) targets should (where applicable) match one or
+       # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+       # *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+       # switched to ELF, *-*-netbsd* would select the old
+       # object file format.  This provides both forward
+       # compatibility and a consistent mechanism for selecting the
+       # object file format.
+       #
+       # Note: NetBSD doesn't particularly care about the vendor
+       # portion of the name.  We always set it to "unknown".
+       sysctl="sysctl -n hw.machine_arch"
+       UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+           /sbin/$sysctl 2>/dev/null || \
+           /usr/sbin/$sysctl 2>/dev/null || \
+           echo unknown)`
+       case "${UNAME_MACHINE_ARCH}" in
+           armeb) machine=armeb-unknown ;;
+           arm*) machine=arm-unknown ;;
+           sh3el) machine=shl-unknown ;;
+           sh3eb) machine=sh-unknown ;;
+           sh5el) machine=sh5le-unknown ;;
+           earmv*)
+               arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+               endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
+               machine=${arch}${endian}-unknown
+               ;;
+           *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+       esac
+       # The Operating System including object format, if it has switched
+       # to ELF recently, or will in the future.
+       case "${UNAME_MACHINE_ARCH}" in
+           arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax)
+               eval $set_cc_for_build
+               if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+                       | grep -q __ELF__
+               then
+                   # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+                   # Return netbsd for either.  FIX?
+                   os=netbsd
+               else
+                   os=netbsdelf
+               fi
+               ;;
+           *)
+               os=netbsd
+               ;;
+       esac
+       # Determine ABI tags.
+       case "${UNAME_MACHINE_ARCH}" in
+           earm*)
+               expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+               abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
+               ;;
+       esac
+       # The OS release
+       # Debian GNU/NetBSD machines have a different userland, and
+       # thus, need a distinct triplet. However, they do not need
+       # kernel version information, so it can be replaced with a
+       # suitable tag, in the style of linux-gnu.
+       case "${UNAME_VERSION}" in
+           Debian*)
+               release='-gnu'
+               ;;
+           *)
+               release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+               ;;
+       esac
+       # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+       # contains redundant information, the shorter form:
+       # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+       echo "${machine}-${os}${release}${abi}"
+       exit ;;
+    *:Bitrig:*:*)
+       UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+       echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+       exit ;;
+    *:OpenBSD:*:*)
+       UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+       echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+       exit ;;
+    *:ekkoBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+       exit ;;
+    *:SolidBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+       exit ;;
+    macppc:MirBSD:*:*)
+       echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+       exit ;;
+    *:MirBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+       exit ;;
+    alpha:OSF1:*:*)
+       case $UNAME_RELEASE in
+       *4.0)
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+               ;;
+       *5.*)
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+               ;;
+       esac
+       # According to Compaq, /usr/sbin/psrinfo has been available on
+       # OSF/1 and Tru64 systems produced since 1995.  I hope that
+       # covers most systems running today.  This code pipes the CPU
+       # types through head -n 1, so we only detect the type of CPU 0.
+       ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+       case "$ALPHA_CPU_TYPE" in
+           "EV4 (21064)")
+               UNAME_MACHINE="alpha" ;;
+           "EV4.5 (21064)")
+               UNAME_MACHINE="alpha" ;;
+           "LCA4 (21066/21068)")
+               UNAME_MACHINE="alpha" ;;
+           "EV5 (21164)")
+               UNAME_MACHINE="alphaev5" ;;
+           "EV5.6 (21164A)")
+               UNAME_MACHINE="alphaev56" ;;
+           "EV5.6 (21164PC)")
+               UNAME_MACHINE="alphapca56" ;;
+           "EV5.7 (21164PC)")
+               UNAME_MACHINE="alphapca57" ;;
+           "EV6 (21264)")
+               UNAME_MACHINE="alphaev6" ;;
+           "EV6.7 (21264A)")
+               UNAME_MACHINE="alphaev67" ;;
+           "EV6.8CB (21264C)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.8AL (21264B)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.8CX (21264D)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.9A (21264/EV69A)")
+               UNAME_MACHINE="alphaev69" ;;
+           "EV7 (21364)")
+               UNAME_MACHINE="alphaev7" ;;
+           "EV7.9 (21364A)")
+               UNAME_MACHINE="alphaev79" ;;
+       esac
+       # A Pn.n version is a patched version.
+       # A Vn.n version is a released version.
+       # A Tn.n version is a released field test version.
+       # A Xn.n version is an unreleased experimental baselevel.
+       # 1.2 uses "1.2" for uname -r.
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+       exitcode=$?
+       trap '' 0
+       exit $exitcode ;;
+    Alpha\ *:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # Should we change UNAME_MACHINE based on the output of uname instead
+       # of the specific Alpha model?
+       echo alpha-pc-interix
+       exit ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-unknown-sysv4
+       exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-amigaos
+       exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-morphos
+       exit ;;
+    *:OS/390:*:*)
+       echo i370-ibm-openedition
+       exit ;;
+    *:z/VM:*:*)
+       echo s390-ibm-zvmoe
+       exit ;;
+    *:OS400:*:*)
+       echo powerpc-ibm-os400
+       exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit ;;
+    arm*:riscos:*:*|arm*:RISCOS:*:*)
+       echo arm-unknown-riscos
+       exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+       echo hppa1.1-hitachi-hiuxmpp
+       exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+       if test "`(/bin/universe) 2>/dev/null`" = att ; then
+               echo pyramid-pyramid-sysv3
+       else
+               echo pyramid-pyramid-bsd
+       fi
+       exit ;;
+    NILE*:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit ;;
+    DRS?6000:unix:4.0:6*)
+       echo sparc-icl-nx6
+       exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+       case `/usr/bin/uname -p` in
+           sparc) echo sparc-icl-nx7; exit ;;
+       esac ;;
+    s390x:SunOS:*:*)
+       echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4H:SunOS:5.*:*)
+       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+       echo i386-pc-auroraux${UNAME_RELEASE}
+       exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+       eval $set_cc_for_build
+       SUN_ARCH="i386"
+       # If there is a compiler, see if it is configured for 64-bit objects.
+       # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+       # This test works for both compilers.
+       if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+           if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+               (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+               grep IS_64BIT_ARCH >/dev/null
+           then
+               SUN_ARCH="x86_64"
+           fi
+       fi
+       echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:6*:*)
+       # According to config.sub, this is the proper way to canonicalize
+       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+       # it's likely to be more like Solaris than SunOS4.
+       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:*:*)
+       case "`/usr/bin/arch -k`" in
+           Series*|S4*)
+               UNAME_RELEASE=`uname -v`
+               ;;
+       esac
+       # Japanese Language versions have a version number like `4.1.3-JL'.
+       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+       exit ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit ;;
+    sun*:*:4.2BSD:*)
+       UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+       case "`/bin/arch`" in
+           sun3)
+               echo m68k-sun-sunos${UNAME_RELEASE}
+               ;;
+           sun4)
+               echo sparc-sun-sunos${UNAME_RELEASE}
+               ;;
+       esac
+       exit ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+       exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+       exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+       exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+       echo m68k-milan-mint${UNAME_RELEASE}
+       exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+       echo m68k-hades-mint${UNAME_RELEASE}
+       exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+       echo m68k-unknown-mint${UNAME_RELEASE}
+       exit ;;
+    m68k:machten:*:*)
+       echo m68k-apple-machten${UNAME_RELEASE}
+       exit ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+       echo clipper-intergraph-clix${UNAME_RELEASE}
+       exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+       #if defined (host_mips) && defined (MIPSEB)
+       #if defined (SYSTYPE_SYSV)
+         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_SVR4)
+         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+       #endif
+       #endif
+         exit (-1);
+       }
+EOF
+       $CC_FOR_BUILD -o $dummy $dummy.c &&
+         dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+         SYSTEM_NAME=`$dummy $dummyarg` &&
+           { echo "$SYSTEM_NAME"; exit; }
+       echo mips-mips-riscos${UNAME_RELEASE}
+       exit ;;
+    Motorola:PowerMAX_OS:*:*)
+       echo powerpc-motorola-powermax
+       exit ;;
+    Motorola:*:4.3:PL8-*)
+       echo powerpc-harris-powermax
+       exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+       echo powerpc-harris-powermax
+       exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+       echo powerpc-harris-powerunix
+       exit ;;
+    m88k:CX/UX:7*:*)
+       echo m88k-harris-cxux7
+       exit ;;
+    m88k:*:4*:R4*)
+       echo m88k-motorola-sysv4
+       exit ;;
+    m88k:*:3*:R3*)
+       echo m88k-motorola-sysv3
+       exit ;;
+    AViiON:dgux:*:*)
+       # DG/UX returns AViiON for all architectures
+       UNAME_PROCESSOR=`/usr/bin/uname -p`
+       if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+       then
+           if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+              [ ${TARGET_BINARY_INTERFACE}x = x ]
+           then
+               echo m88k-dg-dgux${UNAME_RELEASE}
+           else
+               echo m88k-dg-dguxbcs${UNAME_RELEASE}
+           fi
+       else
+           echo i586-dg-dgux${UNAME_RELEASE}
+       fi
+       exit ;;
+    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
+       echo m88k-dolphin-sysv3
+       exit ;;
+    M88*:*:R3*:*)
+       # Delta 88k system running SVR3
+       echo m88k-motorola-sysv3
+       exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+       echo m88k-tektronix-sysv3
+       exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+       echo m68k-tektronix-bsd
+       exit ;;
+    *:IRIX*:*:*)
+       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+       exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+       echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+       exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+       echo i386-ibm-aix
+       exit ;;
+    ia64:AIX:*:*)
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+       exit ;;
+    *:AIX:2:3)
+       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               eval $set_cc_for_build
+               sed 's/^                //' << EOF >$dummy.c
+               #include <sys/systemcfg.h>
+
+               main()
+                       {
+                       if (!__power_pc())
+                               exit(1);
+                       puts("powerpc-ibm-aix3.2.5");
+                       exit(0);
+                       }
+EOF
+               if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+               then
+                       echo "$SYSTEM_NAME"
+               else
+                       echo rs6000-ibm-aix3.2.5
+               fi
+       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+               echo rs6000-ibm-aix3.2.4
+       else
+               echo rs6000-ibm-aix3.2
+       fi
+       exit ;;
+    *:AIX:*:[4567])
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+       if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+               IBM_ARCH=rs6000
+       else
+               IBM_ARCH=powerpc
+       fi
+       if [ -x /usr/bin/lslpp ] ; then
+               IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+                          awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+       exit ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit ;;
+    9000/[34678]??:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       case "${UNAME_MACHINE}" in
+           9000/31? )            HP_ARCH=m68000 ;;
+           9000/[34]?? )         HP_ARCH=m68k ;;
+           9000/[678][0-9][0-9])
+               if [ -x /usr/bin/getconf ]; then
+                   sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                   sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                   case "${sc_cpu_version}" in
+                     523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                     528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                     532)                      # CPU_PA_RISC2_0
+                       case "${sc_kernel_bits}" in
+                         32) HP_ARCH="hppa2.0n" ;;
+                         64) HP_ARCH="hppa2.0w" ;;
+                         '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                       esac ;;
+                   esac
+               fi
+               if [ "${HP_ARCH}" = "" ]; then
+                   eval $set_cc_for_build
+                   sed 's/^            //' << EOF >$dummy.c
+
+               #define _HPUX_SOURCE
+               #include <stdlib.h>
+               #include <unistd.h>
+
+               int main ()
+               {
+               #if defined(_SC_KERNEL_BITS)
+                   long bits = sysconf(_SC_KERNEL_BITS);
+               #endif
+                   long cpu  = sysconf (_SC_CPU_VERSION);
+
+                   switch (cpu)
+                       {
+                       case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+                       case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+                       case CPU_PA_RISC2_0:
+               #if defined(_SC_KERNEL_BITS)
+                           switch (bits)
+                               {
+                               case 64: puts ("hppa2.0w"); break;
+                               case 32: puts ("hppa2.0n"); break;
+                               default: puts ("hppa2.0"); break;
+                               } break;
+               #else  /* !defined(_SC_KERNEL_BITS) */
+                           puts ("hppa2.0"); break;
+               #endif
+                       default: puts ("hppa1.0"); break;
+                       }
+                   exit (0);
+               }
+EOF
+                   (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+                   test -z "$HP_ARCH" && HP_ARCH=hppa
+               fi ;;
+       esac
+       if [ ${HP_ARCH} = "hppa2.0w" ]
+       then
+           eval $set_cc_for_build
+
+           # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+           # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+           # generating 64-bit code.  GNU and HP use different nomenclature:
+           #
+           # $ CC_FOR_BUILD=cc ./config.guess
+           # => hppa2.0w-hp-hpux11.23
+           # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+           # => hppa64-hp-hpux11.23
+
+           if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+               grep -q __LP64__
+           then
+               HP_ARCH="hppa2.0w"
+           else
+               HP_ARCH="hppa64"
+           fi
+       fi
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit ;;
+    ia64:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ia64-hp-hpux${HPUX_REV}
+       exit ;;
+    3050*:HI-UX:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <unistd.h>
+       int
+       main ()
+       {
+         long cpu = sysconf (_SC_CPU_VERSION);
+         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+            results, however.  */
+         if (CPU_IS_PA_RISC (cpu))
+           {
+             switch (cpu)
+               {
+                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+                 default: puts ("hppa-hitachi-hiuxwe2"); break;
+               }
+           }
+         else if (CPU_IS_HP_MC68K (cpu))
+           puts ("m68k-hitachi-hiuxwe2");
+         else puts ("unknown-hitachi-hiuxwe2");
+         exit (0);
+       }
+EOF
+       $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+               { echo "$SYSTEM_NAME"; exit; }
+       echo unknown-hitachi-hiuxwe2
+       exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+       echo hppa1.1-hp-bsd
+       exit ;;
+    9000/8??:4.3bsd:*:*)
+       echo hppa1.0-hp-bsd
+       exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+       echo hppa1.0-hp-mpeix
+       exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+       echo hppa1.1-hp-osf
+       exit ;;
+    hp8??:OSF1:*:*)
+       echo hppa1.0-hp-osf
+       exit ;;
+    i*86:OSF1:*:*)
+       if [ -x /usr/sbin/sysversion ] ; then
+           echo ${UNAME_MACHINE}-unknown-osf1mk
+       else
+           echo ${UNAME_MACHINE}-unknown-osf1
+       fi
+       exit ;;
+    parisc*:Lites*:*:*)
+       echo hppa1.1-hp-lites
+       exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+       echo c1-convex-bsd
+       exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+       echo c34-convex-bsd
+       exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+       echo c38-convex-bsd
+       exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+       echo c4-convex-bsd
+       exit ;;
+    CRAY*Y-MP:*:*:*)
+       echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*[A-Z]90:*:*:*)
+       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+             -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*TS:*:*:*)
+       echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*T3E:*:*:*)
+       echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*SV1:*:*:*)
+       echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    *:UNICOS/mp:*:*)
+       echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+       FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+       FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+       echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+       exit ;;
+    5000:UNIX_System_V:4.*:*)
+       FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+       FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+       echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+       exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+       exit ;;
+    sparc*:BSD/OS:*:*)
+       echo sparc-unknown-bsdi${UNAME_RELEASE}
+       exit ;;
+    *:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+       exit ;;
+    *:FreeBSD:*:*)
+       UNAME_PROCESSOR=`/usr/bin/uname -p`
+       echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+       exit ;;
+    i*:CYGWIN*:*)
+       echo ${UNAME_MACHINE}-pc-cygwin
+       exit ;;
+    *:MINGW64*:*)
+       echo ${UNAME_MACHINE}-pc-mingw64
+       exit ;;
+    *:MINGW*:*)
+       echo ${UNAME_MACHINE}-pc-mingw32
+       exit ;;
+    *:MSYS*:*)
+       echo ${UNAME_MACHINE}-pc-msys
+       exit ;;
+    i*:windows32*:*)
+       # uname -m includes "-pc" on this system.
+       echo ${UNAME_MACHINE}-mingw32
+       exit ;;
+    i*:PW*:*)
+       echo ${UNAME_MACHINE}-pc-pw32
+       exit ;;
+    *:Interix*:*)
+       case ${UNAME_MACHINE} in
+           x86)
+               echo i586-pc-interix${UNAME_RELEASE}
+               exit ;;
+           authenticamd | genuineintel | EM64T)
+               echo x86_64-unknown-interix${UNAME_RELEASE}
+               exit ;;
+           IA64)
+               echo ia64-unknown-interix${UNAME_RELEASE}
+               exit ;;
+       esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+       echo i${UNAME_MACHINE}-pc-mks
+       exit ;;
+    8664:Windows_NT:*)
+       echo x86_64-pc-mks
+       exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+       # UNAME_MACHINE based on the output of uname instead of i386?
+       echo i586-pc-interix
+       exit ;;
+    i*:UWIN*:*)
+       echo ${UNAME_MACHINE}-pc-uwin
+       exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+       echo x86_64-unknown-cygwin
+       exit ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin
+       exit ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    *:GNU:*:*)
+       # the GNU system
+       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit ;;
+    *:GNU/*:*:*)
+       # other systems with GNU libc and userland
+       echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+       exit ;;
+    i*86:Minix:*:*)
+       echo ${UNAME_MACHINE}-pc-minix
+       exit ;;
+    aarch64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    aarch64_be:Linux:*:*)
+       UNAME_MACHINE=aarch64_be
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    alpha:Linux:*:*)
+       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+         EV5)   UNAME_MACHINE=alphaev5 ;;
+         EV56)  UNAME_MACHINE=alphaev56 ;;
+         PCA56) UNAME_MACHINE=alphapca56 ;;
+         PCA57) UNAME_MACHINE=alphapca56 ;;
+         EV6)   UNAME_MACHINE=alphaev6 ;;
+         EV67)  UNAME_MACHINE=alphaev67 ;;
+         EV68*) UNAME_MACHINE=alphaev68 ;;
+       esac
+       objdump --private-headers /bin/sh | grep -q ld.so.1
+       if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    arc:Linux:*:* | arceb:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    arm*:Linux:*:*)
+       eval $set_cc_for_build
+       if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+           | grep -q __ARM_EABI__
+       then
+           echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       else
+           if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+               | grep -q __ARM_PCS_VFP
+           then
+               echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+           else
+               echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+           fi
+       fi
+       exit ;;
+    avr32*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    cris:Linux:*:*)
+       echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+       exit ;;
+    crisv32:Linux:*:*)
+       echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+       exit ;;
+    e2k:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    frv:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    hexagon:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    i*86:Linux:*:*)
+       echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+       exit ;;
+    ia64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    m32r*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    m68*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #undef CPU
+       #undef ${UNAME_MACHINE}
+       #undef ${UNAME_MACHINE}el
+       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+       CPU=${UNAME_MACHINE}el
+       #else
+       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+       CPU=${UNAME_MACHINE}
+       #else
+       CPU=
+       #endif
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+       test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+       ;;
+    openrisc*:Linux:*:*)
+       echo or1k-unknown-linux-${LIBC}
+       exit ;;
+    or32:Linux:*:* | or1k*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    padre:Linux:*:*)
+       echo sparc-unknown-linux-${LIBC}
+       exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+       echo hppa64-unknown-linux-${LIBC}
+       exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+       # Look for CPU level
+       case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+         PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
+         PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+         *)    echo hppa-unknown-linux-${LIBC} ;;
+       esac
+       exit ;;
+    ppc64:Linux:*:*)
+       echo powerpc64-unknown-linux-${LIBC}
+       exit ;;
+    ppc:Linux:*:*)
+       echo powerpc-unknown-linux-${LIBC}
+       exit ;;
+    ppc64le:Linux:*:*)
+       echo powerpc64le-unknown-linux-${LIBC}
+       exit ;;
+    ppcle:Linux:*:*)
+       echo powerpcle-unknown-linux-${LIBC}
+       exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+       echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+       exit ;;
+    sh64*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    sh*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    tile*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    vax:Linux:*:*)
+       echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+       exit ;;
+    x86_64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    xtensa*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    i*86:DYNIX/ptx:4*:*)
+       # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+       # earlier versions are messed up and put the nodename in both
+       # sysname and nodename.
+       echo i386-sequent-sysv4
+       exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+       # Unixware is an offshoot of SVR4, but it has its own version
+       # number series starting with 2...
+       # I am not positive that other SVR4 systems won't match this,
+       # I just have to hope.  -- rms.
+       # Use sysv4.2uw... so that sysv4* matches it.
+       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+       exit ;;
+    i*86:OS/2:*:*)
+       # If we were able to find `uname', then EMX Unix compatibility
+       # is probably installed.
+       echo ${UNAME_MACHINE}-pc-os2-emx
+       exit ;;
+    i*86:XTS-300:*:STOP)
+       echo ${UNAME_MACHINE}-unknown-stop
+       exit ;;
+    i*86:atheos:*:*)
+       echo ${UNAME_MACHINE}-unknown-atheos
+       exit ;;
+    i*86:syllable:*:*)
+       echo ${UNAME_MACHINE}-pc-syllable
+       exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    i*86:*DOS:*:*)
+       echo ${UNAME_MACHINE}-pc-msdosdjgpp
+       exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+       fi
+       exit ;;
+    i*86:*:5:[678]*)
+       # UnixWare 7.x, OpenUNIX and OpenServer 6.
+       case `/bin/uname -X | grep "^Machine"` in
+           *486*)           UNAME_MACHINE=i486 ;;
+           *Pentium)        UNAME_MACHINE=i586 ;;
+           *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+       esac
+       echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+       exit ;;
+    i*86:*:3.2:*)
+       if test -f /usr/options/cb.name; then
+               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/dev/null >/dev/null ; then
+               UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+                       && UNAME_MACHINE=i586
+               (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+       else
+               echo ${UNAME_MACHINE}-pc-sysv32
+       fi
+       exit ;;
+    pc:*:*:*)
+       # Left here for compatibility:
+       # uname -m prints for DJGPP always 'pc', but it prints nothing about
+       # the processor, so we play safe by assuming i586.
+       # Note: whatever this is, it MUST be the same as what config.sub
+       # prints for the "djgpp" host, or else GDB configury will decide that
+       # this is a cross-build.
+       echo i586-pc-msdosdjgpp
+       exit ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit ;;
+    i860:*:4.*:*) # i860-SVR4
+       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+       else # Add other i860-SVR4 vendors below as they are discovered.
+         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+       fi
+       exit ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+       echo m68k-convergent-sysv
+       exit ;;
+    M680?0:D-NIX:5.3:*)
+       echo m68k-diab-dnix
+       exit ;;
+    M68*:*:R3V[5678]*:*)
+       test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+       OS_REL=''
+       test -r /etc/.relid \
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+       OS_REL='.3'
+       test -r /etc/.relid \
+           && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+           && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+           && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+       /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+           && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    rs6000:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+       echo powerpc-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit ;;
+    RM*:ReliantUNIX-*:*:*)
+       echo mips-sni-sysv4
+       exit ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit ;;
+    *:SINIX-*:*:*)
+       if uname -p 2>/dev/null >/dev/null ; then
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               echo ${UNAME_MACHINE}-sni-sysv4
+       else
+               echo ns32k-sni-sysv
+       fi
+       exit ;;
+    PENTIUM:*:4.0*:*)  # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                       # says <Richard.M.Bartel@ccMail.Census.GOV>
+       echo i586-unisys-sysv4
+       exit ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # How about differentiating between stratus architectures? -djm
+       echo hppa1.1-stratus-sysv4
+       exit ;;
+    *:*:*:FTX*)
+       # From seanf@swdc.stratus.com.
+       echo i860-stratus-sysv4
+       exit ;;
+    i*86:VOS:*:*)
+       # From Paul.Green@stratus.com.
+       echo ${UNAME_MACHINE}-stratus-vos
+       exit ;;
+    *:VOS:*:*)
+       # From Paul.Green@stratus.com.
+       echo hppa1.1-stratus-vos
+       exit ;;
+    mc68*:A/UX:*:*)
+       echo m68k-apple-aux${UNAME_RELEASE}
+       exit ;;
+    news*:NEWS-OS:6*:*)
+       echo mips-sony-newsos6
+       exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+       if [ -d /usr/nec ]; then
+               echo mips-nec-sysv${UNAME_RELEASE}
+       else
+               echo mips-unknown-sysv${UNAME_RELEASE}
+       fi
+       exit ;;
+    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
+       echo powerpc-be-beos
+       exit ;;
+    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
+       echo powerpc-apple-beos
+       exit ;;
+    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
+       echo i586-pc-beos
+       exit ;;
+    BePC:Haiku:*:*)    # Haiku running on Intel PC compatible.
+       echo i586-pc-haiku
+       exit ;;
+    x86_64:Haiku:*:*)
+       echo x86_64-unknown-haiku
+       exit ;;
+    SX-4:SUPER-UX:*:*)
+       echo sx4-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-5:SUPER-UX:*:*)
+       echo sx5-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-6:SUPER-UX:*:*)
+       echo sx6-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-7:SUPER-UX:*:*)
+       echo sx7-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-8:SUPER-UX:*:*)
+       echo sx8-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-8R:SUPER-UX:*:*)
+       echo sx8r-nec-superux${UNAME_RELEASE}
+       exit ;;
+    Power*:Rhapsody:*:*)
+       echo powerpc-apple-rhapsody${UNAME_RELEASE}
+       exit ;;
+    *:Rhapsody:*:*)
+       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+       exit ;;
+    *:Darwin:*:*)
+       UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+       eval $set_cc_for_build
+       if test "$UNAME_PROCESSOR" = unknown ; then
+           UNAME_PROCESSOR=powerpc
+       fi
+       if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
+           if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+               if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+                   (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+                   grep IS_64BIT_ARCH >/dev/null
+               then
+                   case $UNAME_PROCESSOR in
+                       i386) UNAME_PROCESSOR=x86_64 ;;
+                       powerpc) UNAME_PROCESSOR=powerpc64 ;;
+                   esac
+               fi
+           fi
+       elif test "$UNAME_PROCESSOR" = i386 ; then
+           # Avoid executing cc on OS X 10.9, as it ships with a stub
+           # that puts up a graphical alert prompting to install
+           # developer tools.  Any system running Mac OS X 10.7 or
+           # later (Darwin 11 and later) is required to have a 64-bit
+           # processor. This is not true of the ARM version of Darwin
+           # that Apple uses in portable devices.
+           UNAME_PROCESSOR=x86_64
+       fi
+       echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+       exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+       UNAME_PROCESSOR=`uname -p`
+       if test "$UNAME_PROCESSOR" = "x86"; then
+               UNAME_PROCESSOR=i386
+               UNAME_MACHINE=pc
+       fi
+       echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+       exit ;;
+    *:QNX:*:4*)
+       echo i386-pc-qnx
+       exit ;;
+    NEO-?:NONSTOP_KERNEL:*:*)
+       echo neo-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    NSE-*:NONSTOP_KERNEL:*:*)
+       echo nse-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+       echo nsr-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    *:NonStop-UX:*:*)
+       echo mips-compaq-nonstopux
+       exit ;;
+    BS2000:POSIX*:*:*)
+       echo bs2000-siemens-sysv
+       exit ;;
+    DS/*:UNIX_System_V:*:*)
+       echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+       exit ;;
+    *:Plan9:*:*)
+       # "uname -m" is not consistent, so use $cputype instead. 386
+       # is converted to i386 for consistency with other x86
+       # operating systems.
+       if test "$cputype" = "386"; then
+           UNAME_MACHINE=i386
+       else
+           UNAME_MACHINE="$cputype"
+       fi
+       echo ${UNAME_MACHINE}-unknown-plan9
+       exit ;;
+    *:TOPS-10:*:*)
+       echo pdp10-unknown-tops10
+       exit ;;
+    *:TENEX:*:*)
+       echo pdp10-unknown-tenex
+       exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+       echo pdp10-dec-tops20
+       exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+       echo pdp10-xkl-tops20
+       exit ;;
+    *:TOPS-20:*:*)
+       echo pdp10-unknown-tops20
+       exit ;;
+    *:ITS:*:*)
+       echo pdp10-unknown-its
+       exit ;;
+    SEI:*:*:SEIUX)
+       echo mips-sei-seiux${UNAME_RELEASE}
+       exit ;;
+    *:DragonFly:*:*)
+       echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+       exit ;;
+    *:*VMS:*:*)
+       UNAME_MACHINE=`(uname -p) 2>/dev/null`
+       case "${UNAME_MACHINE}" in
+           A*) echo alpha-dec-vms ; exit ;;
+           I*) echo ia64-dec-vms ; exit ;;
+           V*) echo vax-dec-vms ; exit ;;
+       esac ;;
+    *:XENIX:*:SysV)
+       echo i386-pc-xenix
+       exit ;;
+    i*86:skyos:*:*)
+       echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+       exit ;;
+    i*86:rdos:*:*)
+       echo ${UNAME_MACHINE}-pc-rdos
+       exit ;;
+    i*86:AROS:*:*)
+       echo ${UNAME_MACHINE}-pc-aros
+       exit ;;
+    x86_64:VMkernel:*:*)
+       echo ${UNAME_MACHINE}-unknown-esx
+       exit ;;
+esac
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/sntp/libevent/config.sub b/sntp/libevent/config.sub
new file mode 100755 (executable)
index 0000000..a5eae25
--- /dev/null
@@ -0,0 +1,1804 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright 1992-2015 Free Software Foundation, Inc.
+
+timestamp='2015-03-08'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2015 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+  linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+  knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  android-linux)
+    os=-linux-android
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+       -sun*os*)
+               # Prevent following clause from handling this invalid input.
+               ;;
+       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+       -apple | -axis | -knuth | -cray | -microblaze*)
+               os=
+               basic_machine=$1
+               ;;
+       -bluegene*)
+               os=-cnk
+               ;;
+       -sim | -cisco | -oki | -wec | -winbond)
+               os=
+               basic_machine=$1
+               ;;
+       -scout)
+               ;;
+       -wrs)
+               os=-vxworks
+               basic_machine=$1
+               ;;
+       -chorusos*)
+               os=-chorusos
+               basic_machine=$1
+               ;;
+       -chorusrdb)
+               os=-chorusrdb
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco6)
+               os=-sco5v6
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco5)
+               os=-sco3.2v5
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco4)
+               os=-sco3.2v4
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2.[4-9]*)
+               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2v[4-9]*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco5v6*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco*)
+               os=-sco3.2v2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -udk*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -isc)
+               os=-isc2.2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -clix*)
+               basic_machine=clipper-intergraph
+               ;;
+       -isc*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -lynx*178)
+               os=-lynxos178
+               ;;
+       -lynx*5)
+               os=-lynxos5
+               ;;
+       -lynx*)
+               os=-lynxos
+               ;;
+       -ptx*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+               ;;
+       -windowsnt*)
+               os=`echo $os | sed -e 's/windowsnt/winnt/'`
+               ;;
+       -psos*)
+               os=-psos
+               ;;
+       -mint | -mint[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+       # Recognize the basic CPU types without company name.
+       # Some are omitted here because they have special meanings below.
+       1750a | 580 \
+       | a29k \
+       | aarch64 | aarch64_be \
+       | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+       | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+       | am33_2.0 \
+       | arc | arceb \
+       | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+       | avr | avr32 \
+       | be32 | be64 \
+       | bfin \
+       | c4x | c8051 | clipper \
+       | d10v | d30v | dlx | dsp16xx \
+       | e2k | epiphany \
+       | fido | fr30 | frv | ft32 \
+       | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+       | hexagon \
+       | i370 | i860 | i960 | ia64 \
+       | ip2k | iq2000 \
+       | k1om \
+       | le32 | le64 \
+       | lm32 \
+       | m32c | m32r | m32rle | m68000 | m68k | m88k \
+       | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+       | mips | mipsbe | mipseb | mipsel | mipsle \
+       | mips16 \
+       | mips64 | mips64el \
+       | mips64octeon | mips64octeonel \
+       | mips64orion | mips64orionel \
+       | mips64r5900 | mips64r5900el \
+       | mips64vr | mips64vrel \
+       | mips64vr4100 | mips64vr4100el \
+       | mips64vr4300 | mips64vr4300el \
+       | mips64vr5000 | mips64vr5000el \
+       | mips64vr5900 | mips64vr5900el \
+       | mipsisa32 | mipsisa32el \
+       | mipsisa32r2 | mipsisa32r2el \
+       | mipsisa32r6 | mipsisa32r6el \
+       | mipsisa64 | mipsisa64el \
+       | mipsisa64r2 | mipsisa64r2el \
+       | mipsisa64r6 | mipsisa64r6el \
+       | mipsisa64sb1 | mipsisa64sb1el \
+       | mipsisa64sr71k | mipsisa64sr71kel \
+       | mipsr5900 | mipsr5900el \
+       | mipstx39 | mipstx39el \
+       | mn10200 | mn10300 \
+       | moxie \
+       | mt \
+       | msp430 \
+       | nds32 | nds32le | nds32be \
+       | nios | nios2 | nios2eb | nios2el \
+       | ns16k | ns32k \
+       | open8 | or1k | or1knd | or32 \
+       | pdp10 | pdp11 | pj | pjl \
+       | powerpc | powerpc64 | powerpc64le | powerpcle \
+       | pyramid \
+       | riscv32 | riscv64 \
+       | rl78 | rx \
+       | score \
+       | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+       | sh64 | sh64le \
+       | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+       | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+       | spu \
+       | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+       | ubicom32 \
+       | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+       | visium \
+       | we32k \
+       | x86 | xc16x | xstormy16 | xtensa \
+       | z8k | z80)
+               basic_machine=$basic_machine-unknown
+               ;;
+       c54x)
+               basic_machine=tic54x-unknown
+               ;;
+       c55x)
+               basic_machine=tic55x-unknown
+               ;;
+       c6x)
+               basic_machine=tic6x-unknown
+               ;;
+       leon|leon[3-9])
+               basic_machine=sparc-$basic_machine
+               ;;
+       m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+               ;;
+       ms1)
+               basic_machine=mt-unknown
+               ;;
+
+       strongarm | thumb | xscale)
+               basic_machine=arm-unknown
+               ;;
+       xgate)
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       xscaleeb)
+               basic_machine=armeb-unknown
+               ;;
+
+       xscaleel)
+               basic_machine=armel-unknown
+               ;;
+
+       # We use `pc' rather than `unknown'
+       # because (1) that's what they normally are, and
+       # (2) the word "unknown" tends to confuse beginning users.
+       i*86 | x86_64)
+         basic_machine=$basic_machine-pc
+         ;;
+       # Object if more than one company name word.
+       *-*-*)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+       # Recognize the basic CPU types with company name.
+       580-* \
+       | a29k-* \
+       | aarch64-* | aarch64_be-* \
+       | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+       | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+       | alphapca5[67]-* | alpha64pca5[67]-* | amd64-* | arc-* | arceb-* \
+       | arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+       | avr-* | avr32-* \
+       | be32-* | be64-* \
+       | bfin-* | bs2000-* \
+       | c[123]* | c30-* | [cjt]90-* | c4x-* \
+       | c8051-* | clipper-* | craynv-* | cydra-* \
+       | d10v-* | d30v-* | dlx-* \
+       | e2k-* | elxsi-* \
+       | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+       | h8300-* | h8500-* \
+       | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+       | hexagon-* \
+       | i*86-* | i860-* | i960-* | ia64-* \
+       | ip2k-* | iq2000-* \
+       | k1om-* \
+       | le32-* | le64-* \
+       | lm32-* \
+       | m32c-* | m32r-* | m32rle-* \
+       | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+       | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+       | microblaze-* | microblazeel-* \
+       | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+       | mips16-* \
+       | mips64-* | mips64el-* \
+       | mips64octeon-* | mips64octeonel-* \
+       | mips64orion-* | mips64orionel-* \
+       | mips64r5900-* | mips64r5900el-* \
+       | mips64vr-* | mips64vrel-* \
+       | mips64vr4100-* | mips64vr4100el-* \
+       | mips64vr4300-* | mips64vr4300el-* \
+       | mips64vr5000-* | mips64vr5000el-* \
+       | mips64vr5900-* | mips64vr5900el-* \
+       | mipsisa32-* | mipsisa32el-* \
+       | mipsisa32r2-* | mipsisa32r2el-* \
+       | mipsisa32r6-* | mipsisa32r6el-* \
+       | mipsisa64-* | mipsisa64el-* \
+       | mipsisa64r2-* | mipsisa64r2el-* \
+       | mipsisa64r6-* | mipsisa64r6el-* \
+       | mipsisa64sb1-* | mipsisa64sb1el-* \
+       | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+       | mipsr5900-* | mipsr5900el-* \
+       | mipstx39-* | mipstx39el-* \
+       | mmix-* \
+       | mt-* \
+       | msp430-* \
+       | nds32-* | nds32le-* | nds32be-* \
+       | nios-* | nios2-* | nios2eb-* | nios2el-* \
+       | none-* | np1-* | ns16k-* | ns32k-* \
+       | open8-* \
+       | or1k*-* \
+       | orion-* \
+       | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+       | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+       | pyramid-* \
+       | rl78-* | romp-* | rs6000-* | rx-* \
+       | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+       | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+       | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+       | sparclite-* \
+       | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+       | tahoe-* \
+       | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+       | tile*-* \
+       | tron-* \
+       | ubicom32-* \
+       | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+       | vax-* \
+       | visium-* \
+       | we32k-* \
+       | x86-* | x86_64-* | xc16x-* | xps100-* \
+       | xstormy16-* | xtensa*-* \
+       | ymp-* \
+       | z8k-* | z80-*)
+               ;;
+       # Recognize the basic CPU types without company name, with glob match.
+       xtensa*)
+               basic_machine=$basic_machine-unknown
+               ;;
+       # Recognize the various machine names and aliases which stand
+       # for a CPU type and a company and sometimes even an OS.
+       386bsd)
+               basic_machine=i386-unknown
+               os=-bsd
+               ;;
+       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+               basic_machine=m68000-att
+               ;;
+       3b*)
+               basic_machine=we32k-att
+               ;;
+       a29khif)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       abacus)
+               basic_machine=abacus-unknown
+               ;;
+       adobe68k)
+               basic_machine=m68010-adobe
+               os=-scout
+               ;;
+       alliant | fx80)
+               basic_machine=fx80-alliant
+               ;;
+       altos | altos3068)
+               basic_machine=m68k-altos
+               ;;
+       am29k)
+               basic_machine=a29k-none
+               os=-bsd
+               ;;
+       amdahl)
+               basic_machine=580-amdahl
+               os=-sysv
+               ;;
+       amiga | amiga-*)
+               basic_machine=m68k-unknown
+               ;;
+       amigaos | amigados)
+               basic_machine=m68k-unknown
+               os=-amigaos
+               ;;
+       amigaunix | amix)
+               basic_machine=m68k-unknown
+               os=-sysv4
+               ;;
+       apollo68)
+               basic_machine=m68k-apollo
+               os=-sysv
+               ;;
+       apollo68bsd)
+               basic_machine=m68k-apollo
+               os=-bsd
+               ;;
+       aros)
+               basic_machine=i386-pc
+               os=-aros
+               ;;
+        asmjs)
+               basic_machine=asmjs-unknown
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       blackfin)
+               basic_machine=bfin-unknown
+               os=-linux
+               ;;
+       blackfin-*)
+               basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       bluegene*)
+               basic_machine=powerpc-ibm
+               os=-cnk
+               ;;
+       c54x-*)
+               basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       c55x-*)
+               basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       c6x-*)
+               basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       c90)
+               basic_machine=c90-cray
+               os=-unicos
+               ;;
+       cegcc)
+               basic_machine=arm-unknown
+               os=-cegcc
+               ;;
+       convex-c1)
+               basic_machine=c1-convex
+               os=-bsd
+               ;;
+       convex-c2)
+               basic_machine=c2-convex
+               os=-bsd
+               ;;
+       convex-c32)
+               basic_machine=c32-convex
+               os=-bsd
+               ;;
+       convex-c34)
+               basic_machine=c34-convex
+               os=-bsd
+               ;;
+       convex-c38)
+               basic_machine=c38-convex
+               os=-bsd
+               ;;
+       cray | j90)
+               basic_machine=j90-cray
+               os=-unicos
+               ;;
+       craynv)
+               basic_machine=craynv-cray
+               os=-unicosmp
+               ;;
+       cr16 | cr16-*)
+               basic_machine=cr16-unknown
+               os=-elf
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       crisv32 | crisv32-* | etraxfs*)
+               basic_machine=crisv32-axis
+               ;;
+       cris | cris-* | etrax*)
+               basic_machine=cris-axis
+               ;;
+       crx)
+               basic_machine=crx-unknown
+               os=-elf
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       decsystem10* | dec10*)
+               basic_machine=pdp10-dec
+               os=-tops10
+               ;;
+       decsystem20* | dec20*)
+               basic_machine=pdp10-dec
+               os=-tops20
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       dicos)
+               basic_machine=i686-pc
+               os=-dicos
+               ;;
+       djgpp)
+               basic_machine=i586-pc
+               os=-msdosdjgpp
+               ;;
+       dpx20 | dpx20-*)
+               basic_machine=rs6000-bull
+               os=-bosx
+               ;;
+       dpx2* | dpx2*-bull)
+               basic_machine=m68k-bull
+               os=-sysv3
+               ;;
+       ebmon29k)
+               basic_machine=a29k-amd
+               os=-ebmon
+               ;;
+       elxsi)
+               basic_machine=elxsi-elxsi
+               os=-bsd
+               ;;
+       encore | umax | mmax)
+               basic_machine=ns32k-encore
+               ;;
+       es1800 | OSE68k | ose68k | ose | OSE)
+               basic_machine=m68k-ericsson
+               os=-ose
+               ;;
+       fx2800)
+               basic_machine=i860-alliant
+               ;;
+       genix)
+               basic_machine=ns32k-ns
+               ;;
+       gmicro)
+               basic_machine=tron-gmicro
+               os=-sysv
+               ;;
+       go32)
+               basic_machine=i386-pc
+               os=-go32
+               ;;
+       h3050r* | hiux*)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       h8300hms)
+               basic_machine=h8300-hitachi
+               os=-hms
+               ;;
+       h8300xray)
+               basic_machine=h8300-hitachi
+               os=-xray
+               ;;
+       h8500hms)
+               basic_machine=h8500-hitachi
+               os=-hms
+               ;;
+       harris)
+               basic_machine=m88k-harris
+               os=-sysv3
+               ;;
+       hp300-*)
+               basic_machine=m68k-hp
+               ;;
+       hp300bsd)
+               basic_machine=m68k-hp
+               os=-bsd
+               ;;
+       hp300hpux)
+               basic_machine=m68k-hp
+               os=-hpux
+               ;;
+       hp3k9[0-9][0-9] | hp9[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k2[0-9][0-9] | hp9k31[0-9])
+               basic_machine=m68000-hp
+               ;;
+       hp9k3[2-9][0-9])
+               basic_machine=m68k-hp
+               ;;
+       hp9k6[0-9][0-9] | hp6[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k7[0-79][0-9] | hp7[0-79][0-9])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k78[0-9] | hp78[0-9])
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][13679] | hp8[0-9][13679])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][0-9] | hp8[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hppa-next)
+               os=-nextstep3
+               ;;
+       hppaosf)
+               basic_machine=hppa1.1-hp
+               os=-osf
+               ;;
+       hppro)
+               basic_machine=hppa1.1-hp
+               os=-proelf
+               ;;
+       i370-ibm* | ibm*)
+               basic_machine=i370-ibm
+               ;;
+       i*86v32)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv32
+               ;;
+       i*86v4*)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv4
+               ;;
+       i*86v)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv
+               ;;
+       i*86sol2)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-solaris2
+               ;;
+       i386mach)
+               basic_machine=i386-mach
+               os=-mach
+               ;;
+       i386-vsta | vsta)
+               basic_machine=i386-unknown
+               os=-vsta
+               ;;
+       iris | iris4d)
+               basic_machine=mips-sgi
+               case $os in
+                   -irix*)
+                       ;;
+                   *)
+                       os=-irix4
+                       ;;
+               esac
+               ;;
+       isi68 | isi)
+               basic_machine=m68k-isi
+               os=-sysv
+               ;;
+       leon-*|leon[3-9]-*)
+               basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
+               ;;
+       m68knommu)
+               basic_machine=m68k-unknown
+               os=-linux
+               ;;
+       m68knommu-*)
+               basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+       microblaze*)
+               basic_machine=microblaze-xilinx
+               ;;
+       mingw64)
+               basic_machine=x86_64-pc
+               os=-mingw64
+               ;;
+       mingw32)
+               basic_machine=i686-pc
+               os=-mingw32
+               ;;
+       mingw32ce)
+               basic_machine=arm-unknown
+               os=-mingw32ce
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       monitor)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       morphos)
+               basic_machine=powerpc-unknown
+               os=-morphos
+               ;;
+       moxiebox)
+               basic_machine=moxie-unknown
+               os=-moxiebox
+               ;;
+       msdos)
+               basic_machine=i386-pc
+               os=-msdos
+               ;;
+       ms1-*)
+               basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+               ;;
+       msys)
+               basic_machine=i686-pc
+               os=-msys
+               ;;
+       mvs)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
+       nacl)
+               basic_machine=le32-unknown
+               os=-nacl
+               ;;
+       ncr3000)
+               basic_machine=i486-ncr
+               os=-sysv4
+               ;;
+       netbsd386)
+               basic_machine=i386-unknown
+               os=-netbsd
+               ;;
+       netwinder)
+               basic_machine=armv4l-rebel
+               os=-linux
+               ;;
+       news | news700 | news800 | news900)
+               basic_machine=m68k-sony
+               os=-newsos
+               ;;
+       news1000)
+               basic_machine=m68030-sony
+               os=-newsos
+               ;;
+       news-3600 | risc-news)
+               basic_machine=mips-sony
+               os=-newsos
+               ;;
+       necv70)
+               basic_machine=v70-nec
+               os=-sysv
+               ;;
+       next | m*-next )
+               basic_machine=m68k-next
+               case $os in
+                   -nextstep* )
+                       ;;
+                   -ns2*)
+                     os=-nextstep2
+                       ;;
+                   *)
+                     os=-nextstep3
+                       ;;
+               esac
+               ;;
+       nh3000)
+               basic_machine=m68k-harris
+               os=-cxux
+               ;;
+       nh[45]000)
+               basic_machine=m88k-harris
+               os=-cxux
+               ;;
+       nindy960)
+               basic_machine=i960-intel
+               os=-nindy
+               ;;
+       mon960)
+               basic_machine=i960-intel
+               os=-mon960
+               ;;
+       nonstopux)
+               basic_machine=mips-compaq
+               os=-nonstopux
+               ;;
+       np1)
+               basic_machine=np1-gould
+               ;;
+       neo-tandem)
+               basic_machine=neo-tandem
+               ;;
+       nse-tandem)
+               basic_machine=nse-tandem
+               ;;
+       nsr-tandem)
+               basic_machine=nsr-tandem
+               ;;
+       op50n-* | op60c-*)
+               basic_machine=hppa1.1-oki
+               os=-proelf
+               ;;
+       openrisc | openrisc-*)
+               basic_machine=or32-unknown
+               ;;
+       os400)
+               basic_machine=powerpc-ibm
+               os=-os400
+               ;;
+       OSE68000 | ose68000)
+               basic_machine=m68000-ericsson
+               os=-ose
+               ;;
+       os68k)
+               basic_machine=m68k-none
+               os=-os68k
+               ;;
+       pa-hitachi)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       paragon)
+               basic_machine=i860-intel
+               os=-osf
+               ;;
+       parisc)
+               basic_machine=hppa-unknown
+               os=-linux
+               ;;
+       parisc-*)
+               basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+       pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pc98)
+               basic_machine=i386-pc
+               ;;
+       pc98-*)
+               basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentium | p5 | k5 | k6 | nexgen | viac3)
+               basic_machine=i586-pc
+               ;;
+       pentiumpro | p6 | 6x86 | athlon | athlon_*)
+               basic_machine=i686-pc
+               ;;
+       pentiumii | pentium2 | pentiumiii | pentium3)
+               basic_machine=i686-pc
+               ;;
+       pentium4)
+               basic_machine=i786-pc
+               ;;
+       pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-* | 6x86-* | athlon-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentium4-*)
+               basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pn)
+               basic_machine=pn-gould
+               ;;
+       power)  basic_machine=power-ibm
+               ;;
+       ppc | ppcbe)    basic_machine=powerpc-unknown
+               ;;
+       ppc-* | ppcbe-*)
+               basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppcle | powerpclittle | ppc-le | powerpc-little)
+               basic_machine=powerpcle-unknown
+               ;;
+       ppcle-* | powerpclittle-*)
+               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64)  basic_machine=powerpc64-unknown
+               ;;
+       ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+               basic_machine=powerpc64le-unknown
+               ;;
+       ppc64le-* | powerpc64little-*)
+               basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       pw32)
+               basic_machine=i586-unknown
+               os=-pw32
+               ;;
+       rdos | rdos64)
+               basic_machine=x86_64-pc
+               os=-rdos
+               ;;
+       rdos32)
+               basic_machine=i386-pc
+               os=-rdos
+               ;;
+       rom68k)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       s390 | s390-*)
+               basic_machine=s390-ibm
+               ;;
+       s390x | s390x-*)
+               basic_machine=s390x-ibm
+               ;;
+       sa29200)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       sb1)
+               basic_machine=mipsisa64sb1-unknown
+               ;;
+       sb1el)
+               basic_machine=mipsisa64sb1el-unknown
+               ;;
+       sde)
+               basic_machine=mipsisa32-sde
+               os=-elf
+               ;;
+       sei)
+               basic_machine=mips-sei
+               os=-seiux
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sh5el)
+               basic_machine=sh5le-unknown
+               ;;
+       sh64)
+               basic_machine=sh64-unknown
+               ;;
+       sparclite-wrs | simso-wrs)
+               basic_machine=sparclite-wrs
+               os=-vxworks
+               ;;
+       sps7)
+               basic_machine=m68k-bull
+               os=-sysv2
+               ;;
+       spur)
+               basic_machine=spur-unknown
+               ;;
+       st2000)
+               basic_machine=m68k-tandem
+               ;;
+       stratus)
+               basic_machine=i860-stratus
+               os=-sysv4
+               ;;
+       strongarm-* | thumb-*)
+               basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       sun2)
+               basic_machine=m68000-sun
+               ;;
+       sun2os3)
+               basic_machine=m68000-sun
+               os=-sunos3
+               ;;
+       sun2os4)
+               basic_machine=m68000-sun
+               os=-sunos4
+               ;;
+       sun3os3)
+               basic_machine=m68k-sun
+               os=-sunos3
+               ;;
+       sun3os4)
+               basic_machine=m68k-sun
+               os=-sunos4
+               ;;
+       sun4os3)
+               basic_machine=sparc-sun
+               os=-sunos3
+               ;;
+       sun4os4)
+               basic_machine=sparc-sun
+               os=-sunos4
+               ;;
+       sun4sol2)
+               basic_machine=sparc-sun
+               os=-solaris2
+               ;;
+       sun3 | sun3-*)
+               basic_machine=m68k-sun
+               ;;
+       sun4)
+               basic_machine=sparc-sun
+               ;;
+       sun386 | sun386i | roadrunner)
+               basic_machine=i386-sun
+               ;;
+       sv1)
+               basic_machine=sv1-cray
+               os=-unicos
+               ;;
+       symmetry)
+               basic_machine=i386-sequent
+               os=-dynix
+               ;;
+       t3e)
+               basic_machine=alphaev5-cray
+               os=-unicos
+               ;;
+       t90)
+               basic_machine=t90-cray
+               os=-unicos
+               ;;
+       tile*)
+               basic_machine=$basic_machine-unknown
+               os=-linux-gnu
+               ;;
+       tx39)
+               basic_machine=mipstx39-unknown
+               ;;
+       tx39el)
+               basic_machine=mipstx39el-unknown
+               ;;
+       toad1)
+               basic_machine=pdp10-xkl
+               os=-tops20
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       tpf)
+               basic_machine=s390x-ibm
+               os=-tpf
+               ;;
+       udi29k)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       ultra3)
+               basic_machine=a29k-nyu
+               os=-sym1
+               ;;
+       v810 | necv810)
+               basic_machine=v810-nec
+               os=-none
+               ;;
+       vaxv)
+               basic_machine=vax-dec
+               os=-sysv
+               ;;
+       vms)
+               basic_machine=vax-dec
+               os=-vms
+               ;;
+       vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+       vxworks960)
+               basic_machine=i960-wrs
+               os=-vxworks
+               ;;
+       vxworks68)
+               basic_machine=m68k-wrs
+               os=-vxworks
+               ;;
+       vxworks29k)
+               basic_machine=a29k-wrs
+               os=-vxworks
+               ;;
+       w65*)
+               basic_machine=w65-wdc
+               os=-none
+               ;;
+       w89k-*)
+               basic_machine=hppa1.1-winbond
+               os=-proelf
+               ;;
+       xbox)
+               basic_machine=i686-pc
+               os=-mingw32
+               ;;
+       xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       xscale-* | xscalee[bl]-*)
+               basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+               ;;
+       ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       z8k-*-coff)
+               basic_machine=z8k-unknown
+               os=-sim
+               ;;
+       z80-*-coff)
+               basic_machine=z80-unknown
+               os=-sim
+               ;;
+       none)
+               basic_machine=none-none
+               os=-none
+               ;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+       w89k)
+               basic_machine=hppa1.1-winbond
+               ;;
+       op50n)
+               basic_machine=hppa1.1-oki
+               ;;
+       op60c)
+               basic_machine=hppa1.1-oki
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       mmix)
+               basic_machine=mmix-knuth
+               ;;
+       rs6000)
+               basic_machine=rs6000-ibm
+               ;;
+       vax)
+               basic_machine=vax-dec
+               ;;
+       pdp10)
+               # there are many clones, so DEC is not a safe bet
+               basic_machine=pdp10-unknown
+               ;;
+       pdp11)
+               basic_machine=pdp11-dec
+               ;;
+       we32k)
+               basic_machine=we32k-att
+               ;;
+       sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+               basic_machine=sh-unknown
+               ;;
+       sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+               basic_machine=sparc-sun
+               ;;
+       cydra)
+               basic_machine=cydra-cydrome
+               ;;
+       orion)
+               basic_machine=orion-highlevel
+               ;;
+       orion105)
+               basic_machine=clipper-highlevel
+               ;;
+       mac | mpw | mac-mpw)
+               basic_machine=m68k-apple
+               ;;
+       pmac | pmac-mpw)
+               basic_machine=powerpc-apple
+               ;;
+       *-unknown)
+               # Make sure to match an already-canonicalized machine name.
+               ;;
+       *)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+       *-digital*)
+               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+               ;;
+       *-commodore*)
+               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+               ;;
+       *)
+               ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+       # First match some system type aliases
+       # that might get confused with valid system types.
+       # -solaris* is a basic system type, with this one exception.
+       -auroraux)
+               os=-auroraux
+               ;;
+       -solaris1 | -solaris1.*)
+               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               ;;
+       -solaris)
+               os=-solaris2
+               ;;
+       -svr4*)
+               os=-sysv4
+               ;;
+       -unixware*)
+               os=-sysv4.2uw
+               ;;
+       -gnu/linux*)
+               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+               ;;
+       # First accept the basic system types.
+       # The portable systems comes first.
+       # Each alternative MUST END IN A *, to match a version number.
+       # -sysv* is not here because it comes later, after sysvr4.
+       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+             | -sym* | -kopensolaris* | -plan9* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+             | -aos* | -aros* | -cloudabi* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+             | -bitrig* | -openbsd* | -solidbsd* \
+             | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+             | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -chorusos* | -chorusrdb* | -cegcc* \
+             | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+             | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+             | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
+             | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+             | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+             | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+             | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+             | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+             | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+             | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -qnx*)
+               case $basic_machine in
+                   x86-* | i*86-*)
+                       ;;
+                   *)
+                       os=-nto$os
+                       ;;
+               esac
+               ;;
+       -nto-qnx*)
+               ;;
+       -nto*)
+               os=`echo $os | sed -e 's|nto|nto-qnx|'`
+               ;;
+       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+             | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+             | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+               ;;
+       -mac*)
+               os=`echo $os | sed -e 's|mac|macos|'`
+               ;;
+       -linux-dietlibc)
+               os=-linux-dietlibc
+               ;;
+       -linux*)
+               os=`echo $os | sed -e 's|linux|linux-gnu|'`
+               ;;
+       -sunos5*)
+               os=`echo $os | sed -e 's|sunos5|solaris2|'`
+               ;;
+       -sunos6*)
+               os=`echo $os | sed -e 's|sunos6|solaris3|'`
+               ;;
+       -opened*)
+               os=-openedition
+               ;;
+       -os400*)
+               os=-os400
+               ;;
+       -wince*)
+               os=-wince
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -atheos*)
+               os=-atheos
+               ;;
+       -syllable*)
+               os=-syllable
+               ;;
+       -386bsd)
+               os=-bsd
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -nova*)
+               os=-rtmk-nova
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       -nsk*)
+               os=-nsk
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+       -tpf*)
+               os=-tpf
+               ;;
+       -triton*)
+               os=-sysv3
+               ;;
+       -oss*)
+               os=-sysv3
+               ;;
+       -svr4)
+               os=-sysv4
+               ;;
+       -svr3)
+               os=-sysv3
+               ;;
+       -sysvr4)
+               os=-sysv4
+               ;;
+       # This must come after -sysvr4.
+       -sysv*)
+               ;;
+       -ose*)
+               os=-ose
+               ;;
+       -es1800*)
+               os=-ose
+               ;;
+       -xenix)
+               os=-xenix
+               ;;
+       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+               os=-mint
+               ;;
+       -aros*)
+               os=-aros
+               ;;
+       -zvmoe)
+               os=-zvmoe
+               ;;
+       -dicos*)
+               os=-dicos
+               ;;
+       -nacl*)
+               ;;
+       -none)
+               ;;
+       *)
+               # Get rid of the `-' at the beginning of $os.
+               os=`echo $os | sed 's/[^-]*-//'`
+               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+       score-*)
+               os=-elf
+               ;;
+       spu-*)
+               os=-elf
+               ;;
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-rebel)
+               os=-linux
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+       c4x-* | tic4x-*)
+               os=-coff
+               ;;
+       c8051-*)
+               os=-elf
+               ;;
+       hexagon-*)
+               os=-elf
+               ;;
+       tic54x-*)
+               os=-coff
+               ;;
+       tic55x-*)
+               os=-coff
+               ;;
+       tic6x-*)
+               os=-coff
+               ;;
+       # This must come before the *-dec entry.
+       pdp10-*)
+               os=-tops20
+               ;;
+       pdp11-*)
+               os=-none
+               ;;
+       *-dec | vax-*)
+               os=-ultrix4.2
+               ;;
+       m68*-apollo)
+               os=-domain
+               ;;
+       i386-sun)
+               os=-sunos4.0.2
+               ;;
+       m68000-sun)
+               os=-sunos3
+               ;;
+       m68*-cisco)
+               os=-aout
+               ;;
+       mep-*)
+               os=-elf
+               ;;
+       mips*-cisco)
+               os=-elf
+               ;;
+       mips*-*)
+               os=-elf
+               ;;
+       or32-*)
+               os=-coff
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-be)
+               os=-beos
+               ;;
+       *-haiku)
+               os=-haiku
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-knuth)
+               os=-mmixware
+               ;;
+       *-wec)
+               os=-proelf
+               ;;
+       *-winbond)
+               os=-proelf
+               ;;
+       *-oki)
+               os=-proelf
+               ;;
+       *-hp)
+               os=-hpux
+               ;;
+       *-hitachi)
+               os=-hiux
+               ;;
+       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+               os=-sysv
+               ;;
+       *-cbm)
+               os=-amigaos
+               ;;
+       *-dg)
+               os=-dgux
+               ;;
+       *-dolphin)
+               os=-sysv3
+               ;;
+       m68k-ccur)
+               os=-rtu
+               ;;
+       m88k-omron*)
+               os=-luna
+               ;;
+       *-next )
+               os=-nextstep
+               ;;
+       *-sequent)
+               os=-ptx
+               ;;
+       *-crds)
+               os=-unos
+               ;;
+       *-ns)
+               os=-genix
+               ;;
+       i370-*)
+               os=-mvs
+               ;;
+       *-next)
+               os=-nextstep3
+               ;;
+       *-gould)
+               os=-sysv
+               ;;
+       *-highlevel)
+               os=-bsd
+               ;;
+       *-encore)
+               os=-bsd
+               ;;
+       *-sgi)
+               os=-irix
+               ;;
+       *-siemens)
+               os=-sysv4
+               ;;
+       *-masscomp)
+               os=-rtu
+               ;;
+       f30[01]-fujitsu | f700-fujitsu)
+               os=-uxpv
+               ;;
+       *-rom68k)
+               os=-coff
+               ;;
+       *-*bug)
+               os=-coff
+               ;;
+       *-apple)
+               os=-macos
+               ;;
+       *-atari*)
+               os=-mint
+               ;;
+       *)
+               os=-none
+               ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+       *-unknown)
+               case $os in
+                       -riscix*)
+                               vendor=acorn
+                               ;;
+                       -sunos*)
+                               vendor=sun
+                               ;;
+                       -cnk*|-aix*)
+                               vendor=ibm
+                               ;;
+                       -beos*)
+                               vendor=be
+                               ;;
+                       -hpux*)
+                               vendor=hp
+                               ;;
+                       -mpeix*)
+                               vendor=hp
+                               ;;
+                       -hiux*)
+                               vendor=hitachi
+                               ;;
+                       -unos*)
+                               vendor=crds
+                               ;;
+                       -dgux*)
+                               vendor=dg
+                               ;;
+                       -luna*)
+                               vendor=omron
+                               ;;
+                       -genix*)
+                               vendor=ns
+                               ;;
+                       -mvs* | -opened*)
+                               vendor=ibm
+                               ;;
+                       -os400*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -tpf*)
+                               vendor=ibm
+                               ;;
+                       -vxsim* | -vxworks* | -windiss*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+                       -hms*)
+                               vendor=hitachi
+                               ;;
+                       -mpw* | -macos*)
+                               vendor=apple
+                               ;;
+                       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+                               vendor=atari
+                               ;;
+                       -vos*)
+                               vendor=stratus
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
index 5cb7f678be00aeea7a1e8b7de602ba1862a591a3..d00e063a1474dd2343af413acce532c78a7e602f 100644 (file)
@@ -5,31 +5,23 @@ dnl See LICENSE for copying information.
 dnl
 dnl Original version Dug Song <dugsong@monkey.org>
 
-AC_INIT(libevent,2.1.5-beta)
-AC_PREREQ(2.59)
+AC_INIT(libevent,2.1.12-stable)
+AC_PREREQ(2.67)
 AC_CONFIG_SRCDIR(event.c)
 
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_AUX_DIR([build-aux])
 AM_INIT_AUTOMAKE
 dnl AM_SILENT_RULES req. automake 1.11.  [no] defaults V=1
-m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+AM_SILENT_RULES([yes])
 AC_CONFIG_HEADERS(config.h  evconfig-private.h:evconfig-private.h.in)
-AC_DEFINE(NUMERIC_VERSION, 0x02010500, [Numeric representation of the version])
+AC_DEFINE(NUMERIC_VERSION, 0x02010c00, [Numeric representation of the version])
 
 dnl Initialize prefix.
-if test "$prefix" = "NONE"; then
-   prefix="/usr/local"
-fi
+AC_PREFIX_DEFAULT([/usr/local])
 
 dnl Try and get a full POSIX environment on obscure systems
-ifdef([AC_USE_SYSTEM_EXTENSIONS], [
 AC_USE_SYSTEM_EXTENSIONS
-], [
-AC_AIX
-AC_GNU_SOURCE
-AC_MINIX
-])
 
 AC_CANONICAL_BUILD
 AC_CANONICAL_HOST
@@ -49,11 +41,7 @@ AC_PROG_INSTALL
 AC_PROG_LN_S
 # AC_PROG_MKDIR_P - $(MKDIR_P) should be defined by AM_INIT_AUTOMAKE
 
-# AC_PROG_SED is only available in Autoconf >= 2.59b; workaround for older
-# versions
-ifdef([AC_PROG_SED], [AC_PROG_SED], [
-AC_CHECK_PROGS(SED, [gsed sed])
-])
+AC_PROG_SED
 
 AC_PROG_GCC_TRADITIONAL
 
@@ -75,13 +63,14 @@ if test "$GCC" = "yes" ; then
 fi
 
 # OS X Lion started deprecating the system openssl. Let's just disable
-# all deprecation warnings on OS X.
-case "$host_os" in
-
- darwin*)
-    CFLAGS="$CFLAGS -Wno-deprecated-declarations"
-    ;;
-esac
+# all deprecation warnings on OS X; but do so only for gcc...
+if test "$GCC" = "yes" ; then
+       case "$host_os" in
+        darwin*)
+           CFLAGS="$CFLAGS -Wno-deprecated-declarations"
+           ;;
+       esac
+fi
 
 AC_ARG_ENABLE(gcc-warnings,
      AS_HELP_STRING(--disable-gcc-warnings, disable verbose warnings with GCC))
@@ -121,9 +110,13 @@ AC_ARG_ENABLE([function-sections],
 AC_ARG_ENABLE([verbose-debug],
                AS_HELP_STRING([--enable-verbose-debug, verbose debug logging]),
        [], [enable_verbose_debug=no])
+AC_ARG_ENABLE([clock-gettime],
+     AS_HELP_STRING(--disable-clock-gettime, do not use clock_gettime even if it is available),
+  [], [enable_clock_gettime=yes])
 
 
-AC_PROG_LIBTOOL
+LT_PREREQ([2.4.2])
+LT_INIT
 
 dnl   Uncomment "AC_DISABLE_SHARED" to make shared libraries not get
 dnl   built by default.  You can also turn shared libs on and off from
@@ -138,33 +131,55 @@ dnl Checks for libraries.
 AC_SEARCH_LIBS([inet_ntoa], [nsl])
 AC_SEARCH_LIBS([socket], [socket])
 AC_SEARCH_LIBS([inet_aton], [resolv])
-AC_SEARCH_LIBS([clock_gettime], [rt])
+if test "x$enable_clock_gettime" = "xyes"; then
+  AC_SEARCH_LIBS([clock_gettime], [rt])
+  AC_CHECK_FUNCS([clock_gettime])
+fi
 AC_SEARCH_LIBS([sendfile], [sendfile])
 
 dnl - check if the macro _WIN32 is defined on this compiler.
 dnl - (this is how we check for a windows compiler)
 AC_MSG_CHECKING(for WIN32)
-AC_TRY_COMPILE(,
-       [
+AC_COMPILE_IFELSE(
+  [AC_LANG_PROGRAM([],
+    [
 #ifndef _WIN32
 die horribly
 #endif
-       ],
-       bwin32=true; AC_MSG_RESULT(yes),
-       bwin32=false; AC_MSG_RESULT(no),
+    ]
+  )],
+       [bwin32=true; AC_MSG_RESULT(yes)],
+       [bwin32=false; AC_MSG_RESULT(no)]
+)
+
+dnl - check if the macro __midipix__ is defined on this compiler.
+dnl - (this is how we check for a midipix version of GCC)
+AC_MSG_CHECKING(for MIDIPIX)
+AC_COMPILE_IFELSE(
+  [AC_LANG_PROGRAM([],
+    [
+#ifndef __midipix__
+die horribly
+#endif
+    ]
+  )],
+       [midipix=true; AC_MSG_RESULT(yes)],
+       [midipix=false; AC_MSG_RESULT(no)]
 )
 
 dnl - check if the macro __CYGWIN__ is defined on this compiler.
 dnl - (this is how we check for a cygwin version of GCC)
 AC_MSG_CHECKING(for CYGWIN)
-AC_TRY_COMPILE(,
-       [
+AC_COMPILE_IFELSE(
+  [AC_LANG_PROGRAM([],
+    [
 #ifndef __CYGWIN__
 die horribly
 #endif
-       ],
-       cygwin=true; AC_MSG_RESULT(yes),
-       cygwin=false; AC_MSG_RESULT(no),
+    ]
+  )],
+       [cygwin=true; AC_MSG_RESULT(yes)],
+       [cygwin=false; AC_MSG_RESULT(no)]
 )
 
 AC_CHECK_HEADERS([zlib.h])
@@ -207,10 +222,12 @@ AC_CHECK_HEADERS([ \
   fcntl.h \
   ifaddrs.h \
   mach/mach_time.h \
+  mach/mach.h \
   netdb.h \
   netinet/in.h \
   netinet/in6.h \
   netinet/tcp.h \
+  sys/un.h \
   poll.h \
   port.h \
   stdarg.h \
@@ -232,13 +249,21 @@ AC_CHECK_HEADERS([ \
   sys/timerfd.h \
   sys/uio.h \
   sys/wait.h \
+  sys/random.h \
+  errno.h \
+  afunix.h \
 ])
 
-AC_CHECK_HEADERS(sys/sysctl.h, [], [], [
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-])
+case "${host_os}" in
+    linux*) ;;
+    *)
+        AC_CHECK_HEADERS(sys/sysctl.h, [], [], [
+        #ifdef HAVE_SYS_PARAM_H
+        #include <sys/param.h>
+        #endif
+        ])
+esac
+
 if test "x$ac_cv_header_sys_queue_h" = "xyes"; then
        AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h)
        AC_EGREP_CPP(yes,
@@ -311,7 +336,7 @@ if test "x$ac_cv_header_sys_time_h" = "xyes"; then
 fi
 
 if test "x$ac_cv_header_sys_sysctl_h" = "xyes"; then
-       AC_CHECK_DECLS([CTL_KERN, KERN_RANDOM, RANDOM_UUID, KERN_ARND], [], [],
+       AC_CHECK_DECLS([CTL_KERN, KERN_ARND], [], [],
           [[#include <sys/types.h>
             #include <sys/sysctl.h>]]
        )
@@ -319,10 +344,11 @@ fi
 
 AM_CONDITIONAL(BUILD_WIN32, test x$bwin32 = xtrue)
 AM_CONDITIONAL(BUILD_CYGWIN, test x$cygwin = xtrue)
-AM_CONDITIONAL(BUILD_WITH_NO_UNDEFINED, test x$bwin32 = xtrue || test x$cygwin = xtrue)
+AM_CONDITIONAL(BUILD_MIDIPIX, test x$midipix = xtrue)
+AM_CONDITIONAL(BUILD_WITH_NO_UNDEFINED, test x$bwin32 = xtrue || test x$cygwin = xtrue || test x$midipix = xtrue)
 
 if test x$bwin32 = xtrue; then
-   AC_SEARCH_LIBS([getservbyname],[ws2_32])
+  AC_HAVE_LIBRARY([ws2_32])
 fi
 
 dnl Checks for typedefs, structures, and compiler characteristics.
@@ -335,18 +361,14 @@ AC_CHECK_FUNCS([ \
   accept4 \
   arc4random \
   arc4random_buf \
-  clock_gettime \
+  arc4random_addrandom \
   eventfd \
   epoll_create1 \
   fcntl \
   getegid \
   geteuid \
   getifaddrs \
-  getnameinfo \
-  getprotobynumber \
   gettimeofday \
-  inet_ntop \
-  inet_pton \
   issetugid \
   mach_absolute_time \
   mmap \
@@ -370,9 +392,36 @@ AC_CHECK_FUNCS([ \
   unsetenv \
   usleep \
   vasprintf \
+  getrandom \
 ])
+
+AS_IF([test x$bwin32 = xtrue],
+  AC_CHECK_FUNCS(_gmtime64_s, , [AC_CHECK_FUNCS(_gmtime64)])
+)
+
 AM_CONDITIONAL(STRLCPY_IMPL, [test x"$ac_cv_func_strlcpy" = xno])
 
+m4_define([funcstochk],
+  [getnameinfo
+  getprotobynumber
+  getservbyname
+  inet_ntop
+  inet_pton]
+)
+
+AS_IF([test x$bwin32 = xtrue],
+  [AX_CHECK_DECLS_EX([funcstochk getaddrinfo],
+    [#ifdef _WIN32
+    #include <winsock2.h>
+    #include <ws2tcpip.h>
+    #endif])],
+  [AC_CHECK_FUNCS(m4_normalize(funcstochk))]
+)
+
+m4_undefine([funcstochk])
+
+dnl check getaddrinfo and gethostbyname_r for non-windows
+AS_IF([test x$bwin32 = xfalse], [
 AC_CACHE_CHECK(
     [for getaddrinfo],
     [libevent_cv_getaddrinfo],
@@ -395,7 +444,6 @@ if test "$libevent_cv_getaddrinfo" = "yes" ; then
     AC_DEFINE([HAVE_GETADDRINFO], [1], [Do we have getaddrinfo()?])
 else
 
-AC_CHECK_FUNCS([getservbyname])
 # Check for gethostbyname_r in all its glorious incompatible versions.
 #   (This is cut-and-pasted from Tor, which based its logic on
 #   Python's configure.in.)
@@ -419,27 +467,27 @@ AC_CHECK_FUNC(gethostbyname_r, [
      [Define this if gethostbyname_r takes 6 arguments])
     AC_MSG_RESULT(6)
   ], [
-    AC_TRY_COMPILE([
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
 #include <netdb.h>
     ], [
       char *cp1, *cp2;
       struct hostent *h1;
       int i1, i2;
       (void)gethostbyname_r(cp1,h1,cp2,i1,&i2);
-    ], [
+    ])], [
       AC_DEFINE(HAVE_GETHOSTBYNAME_R)
       AC_DEFINE(HAVE_GETHOSTBYNAME_R_5_ARG, 1,
         [Define this if gethostbyname_r takes 5 arguments])
       AC_MSG_RESULT(5)
-   ], [
-      AC_TRY_COMPILE([
+    ], [
+      AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
 #include <netdb.h>
      ], [
        char *cp1;
        struct hostent *h1;
        struct hostent_data hd;
        (void) gethostbyname_r(cp1,h1,&hd);
-     ], [
+     ])], [
        AC_DEFINE(HAVE_GETHOSTBYNAME_R)
        AC_DEFINE(HAVE_GETHOSTBYNAME_R_3_ARG, 1,
          [Define this if gethostbyname_r takes 3 arguments])
@@ -453,11 +501,12 @@ AC_CHECK_FUNC(gethostbyname_r, [
 ])
 
 fi
+]) dnl end of checking getaddrinfo and gethostbyname_r
 
 AC_MSG_CHECKING(for F_SETFD in fcntl.h)
 AC_EGREP_CPP(yes,
 [
-#define _GNU_SOURCE
+#define _GNU_SOURCE 1
 #include <fcntl.h>
 #ifdef F_SETFD
 yes
@@ -495,57 +544,64 @@ if test "x$ac_cv_header_sys_event_h" = "xyes"; then
        AC_CHECK_FUNCS(kqueue, [havekqueue=yes], )
        if test "x$havekqueue" = "xyes" ; then
                AC_MSG_CHECKING(for working kqueue)
-               AC_TRY_RUN(
+               AC_RUN_IFELSE(
+      [AC_LANG_PROGRAM([
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
 #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]];
+       int fd[2];
        struct kevent ev;
        struct timespec ts;
-       char buf[[8000]];
+       char buf[80000];
 
        if (pipe(fd) == -1)
-               exit(1);
-       if (fcntl(fd[[1]], F_SETFL, O_NONBLOCK) == -1)
-               exit(1);
+               return 1;
+       if (fcntl(fd[1], F_SETFL, O_NONBLOCK) == -1)
+               return 1;
 
-       while ((n = write(fd[[1]], buf, sizeof(buf))) == sizeof(buf))
+       while ((n = write(fd[1], buf, sizeof(buf))) == sizeof(buf))
                ;
 
-        if ((kq = kqueue()) == -1)
-               exit(1);
+       if ((kq = kqueue()) == -1)
+               return 1;
 
        memset(&ev, 0, sizeof(ev));
-       ev.ident = fd[[1]];
+       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);
+               return 1;
 
-       read(fd[[0]], buf, sizeof(buf));
+       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);
-}, [AC_MSG_RESULT(yes)
-    AC_DEFINE(HAVE_WORKING_KQUEUE, 1,
-               [Define if kqueue works correctly with pipes])
-    havekqueue=yes
-    ], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
+               return 1;
+
+       return 0;
+        ]]
+      )],
+      [AC_MSG_RESULT(yes)
+      AC_DEFINE(HAVE_WORKING_KQUEUE, 1,
+        [Define if kqueue works correctly with pipes])
+      havekqueue=yes
+      ], [AC_MSG_RESULT(no)], [AC_MSG_RESULT(no)]
+    )
        fi
 fi
 AM_CONDITIONAL(KQUEUE_BACKEND, [test "x$havekqueue" = "xyes"])
@@ -561,7 +617,8 @@ fi
 if test "x$ac_cv_header_sys_epoll_h" = "xyes"; then
        if test "x$haveepoll" = "xno" ; then
                AC_MSG_CHECKING(for epoll system call)
-               AC_TRY_RUN(
+               AC_RUN_IFELSE(
+      [AC_LANG_PROGRAM([[
 #include <stdint.h>
 #include <sys/param.h>
 #include <sys/types.h>
@@ -574,21 +631,21 @@ epoll_create(int size)
 {
        return (syscall(__NR_epoll_create, size));
 }
-
-int
-main(int argc, char **argv)
-{
+        ]],[[
        int epfd;
 
        epfd = epoll_create(256);
-       exit (epfd == -1 ? 1 : 0);
-}, [AC_MSG_RESULT(yes)
-    AC_DEFINE(HAVE_EPOLL, 1,
-       [Define if your system supports the epoll system calls])
-    needsignal=yes
-    have_epoll=yes
-    AC_LIBOBJ(epoll_sub)
-    ], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
+       return (epfd == -1 ? 1 : 0);
+        ]]
+      )], 
+      [AC_MSG_RESULT(yes)
+      AC_DEFINE(HAVE_EPOLL, 1,
+             [Define if your system supports the epoll system calls])
+      needsignal=yes
+      have_epoll=yes
+      AC_LIBOBJ(epoll_sub)
+      ], [AC_MSG_RESULT(no)], [AC_MSG_RESULT(no)]
+    )
        fi
 fi
 AM_CONDITIONAL(EPOLL_BACKEND, [test "x$haveepoll" = "xyes"])
@@ -637,9 +694,10 @@ AC_CHECK_SIZEOF(short)
 AC_CHECK_SIZEOF(size_t)
 AC_CHECK_SIZEOF(void *)
 AC_CHECK_SIZEOF(off_t)
+AC_CHECK_SIZEOF(time_t)
 
-AC_CHECK_TYPES([struct in6_addr, struct sockaddr_in6, sa_family_t, struct addrinfo, struct sockaddr_storage], , ,
-[#define _GNU_SOURCE
+AC_CHECK_TYPES([struct in6_addr, struct sockaddr_in6, struct sockaddr_un, sa_family_t, struct addrinfo, struct sockaddr_storage], , ,
+[#define _GNU_SOURCE 1
 #include <sys/types.h>
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
@@ -647,6 +705,9 @@ AC_CHECK_TYPES([struct in6_addr, struct sockaddr_in6, sa_family_t, struct addrin
 #ifdef HAVE_NETINET_IN6_H
 #include <netinet/in6.h>
 #endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif
@@ -689,40 +750,54 @@ AC_CHECK_MEMBERS([struct in6_addr.s6_addr32, struct in6_addr.s6_addr16, struct s
 #endif
 ])
 
-AC_CHECK_TYPES([struct so_linger],
-[#define HAVE_SO_LINGER], ,
+AC_CHECK_TYPES([struct linger],,,
 [
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
 ])
 
 AC_MSG_CHECKING([for socklen_t])
-AC_TRY_COMPILE([
+AC_COMPILE_IFELSE(
+  [AC_LANG_PROGRAM([
  #include <sys/types.h>
- #include <sys/socket.h>],
-  [socklen_t x;],
-  AC_MSG_RESULT([yes]),
+ #ifdef _WIN32
+ #include <ws2tcpip.h>
+ #else
+ #include <sys/socket.h>
+ #endif
+    ],[socklen_t x;]
+  )],
+       [AC_MSG_RESULT([yes])],
   [AC_MSG_RESULT([no])
   AC_DEFINE(socklen_t, unsigned int,
-       [Define to unsigned int if you dont have it])]
+         [Define to unsigned int if you dont have it])]
 )
 
+# __func__/__FUNCTION__ is not a macros in general
 AC_MSG_CHECKING([whether our compiler supports __func__])
-AC_TRY_COMPILE([],
- [ const char *cp = __func__; ],
- AC_MSG_RESULT([yes]),
- AC_MSG_RESULT([no])
- AC_MSG_CHECKING([whether our compiler supports __FUNCTION__])
- AC_TRY_COMPILE([],
-   [ const char *cp = __FUNCTION__; ],
-   AC_MSG_RESULT([yes])
-   AC_DEFINE(__func__, __FUNCTION__,
-         [Define to appropriate substitue if compiler doesnt have __func__]),
-   AC_MSG_RESULT([no])
-   AC_DEFINE(__func__, __FILE__,
-         [Define to appropriate substitue if compiler doesnt have __func__])))
-
+AC_COMPILE_IFELSE(
+  [AC_LANG_PROGRAM([],
+    [ const char *cp = __func__; ]
+  )],
+       [ AC_DEFINE(HAVE___func__, 1, [Define to 1 if compiler have __func__])
+    AC_MSG_RESULT([yes])
+  ],
+  [AC_MSG_RESULT([no])]
+)
+AC_MSG_CHECKING([whether our compiler supports __FUNCTION__])
+AC_COMPILE_IFELSE(
+  [AC_LANG_PROGRAM([],
+    [ const char *cp = __FUNCTION__; ]
+  )],
+       [ AC_DEFINE(HAVE___FUNCTION__, 1, [Define to 1 if compiler have __FUNCTION__])
+    AC_MSG_RESULT([yes])
+  ],
+  [AC_MSG_RESULT([no])]
+)
 
 # check if we can compile with pthreads
 have_pthreads=no
@@ -737,7 +812,8 @@ if test x$bwin32 != xtrue && test "$enable_thread_support" != "no"; then
       #include <pthread.h> ]
   )
 fi
-AM_CONDITIONAL([PTHREADS], [test "$have_pthreads" != "no" && test "$enable_thread_support" != "no"])
+AM_CONDITIONAL(THREADS, [test "$enable_thread_support" != "no"])
+AM_CONDITIONAL(PTHREADS, [test "$have_pthreads" != "no" && test "$enable_thread_support" != "no"])
 
 # check if we should compile locking into the library
 if test x$enable_thread_support = xno; then
@@ -789,7 +865,8 @@ if test x$enable_gcc_warnings != xno && test "$GCC" = "yes"; then
 #error
 #endif])], have_clang=yes, have_clang=no)
 
-  CFLAGS="$CFLAGS -W -Wfloat-equal -Wundef -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings -Wredundant-decls -Wchar-subscripts -Wcomment -Wformat -Wwrite-strings -Wmissing-declarations -Wredundant-decls -Wnested-externs -Wbad-function-cast -Wswitch-enum"
+  # -W is the same as -Wextra
+  CFLAGS="$CFLAGS -W -Wfloat-equal -Wundef -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings -Wredundant-decls -Wmissing-declarations -Wnested-externs -Wbad-function-cast"
   if test x$enable_gcc_warnings = xyes; then
     CFLAGS="$CFLAGS -Werror"
   fi
@@ -822,7 +899,7 @@ if test x$enable_gcc_warnings != xno && test "$GCC" = "yes"; then
     # for minheap-internal.h related code.
     CFLAGS="$CFLAGS -Wno-unused-function"
 
-    # clang on macosx emits warnigns for each directory specified which
+    # clang on macosx emits warnings for each directory specified which
     # isn't "used" generating a lot of build noise (typically 3 warnings
     # per file
     case "$host_os" in
@@ -912,9 +989,19 @@ AC_SUBST([LIBEVENT_GC_SECTIONS])
 
 AM_CONDITIONAL([INSTALL_LIBEVENT], [test "$enable_libevent_install" = "yes"])
 
-AC_SUBST([LEP_CFLAGS])
-AC_SUBST([LEP_CPPFLAGS])
-AC_SUBST([LEP_LDFLAGS])
-
-AC_CONFIG_FILES( [libevent.pc libevent_openssl.pc libevent_pthreads.pc] )
+# Doxygen support
+DX_HTML_FEATURE(ON)
+DX_MAN_FEATURE(OFF)
+DX_RTF_FEATURE(OFF)
+DX_XML_FEATURE(OFF)
+DX_PDF_FEATURE(OFF)
+DX_PS_FEATURE(OFF)
+DX_CHM_FEATURE(OFF)
+DX_CHI_FEATURE(OFF)
+DX_INIT_DOXYGEN([libevent], [${top_srcdir}/Doxyfile], [doxygen])
+
+AM_CONDITIONAL([ENABLE_DOXYGEN], [test "$DX_FLAG_doc" = "1"])
+AM_CONDITIONAL([ENABLE_DOXYGEN_MAN], [test "$DX_FLAG_man" = "1"])
+
+AC_CONFIG_FILES( [libevent.pc libevent_openssl.pc libevent_pthreads.pc libevent_core.pc libevent_extra.pc] )
 AC_OUTPUT(Makefile)
index d8cf32f443a1aee87147e62e19ba9e9e42f67d94..d6f80a1180aae62a0539621d08e77e982dc920b4 100644 (file)
@@ -46,6 +46,7 @@ typedef void (*deferred_cb_fn)(struct event_callback *, void *);
    @param cb The function to run when the struct event_callback executes.
    @param arg The function's second argument.
  */
+EVENT2_EXPORT_SYMBOL
 void event_deferred_cb_init_(struct event_callback *, ev_uint8_t, deferred_cb_fn, void *);
 /**
    Change the priority of a non-pending event_callback.
@@ -54,12 +55,14 @@ void event_deferred_cb_set_priority_(struct event_callback *, ev_uint8_t);
 /**
    Cancel a struct event_callback if it is currently scheduled in an event_base.
  */
+EVENT2_EXPORT_SYMBOL
 void event_deferred_cb_cancel_(struct event_base *, struct event_callback *);
 /**
    Activate a struct event_callback if it is not currently scheduled in an event_base.
 
-   Return true iff it was not previously scheduled.
+   Return true if it was not previously scheduled.
  */
+EVENT2_EXPORT_SYMBOL
 int event_deferred_cb_schedule_(struct event_base *, struct event_callback *);
 
 #ifdef __cplusplus
diff --git a/sntp/libevent/depcomp b/sntp/libevent/depcomp
new file mode 100755 (executable)
index 0000000..fc98710
--- /dev/null
@@ -0,0 +1,791 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2013-05-30.07; # UTC
+
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+  '')
+    echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+    exit 1;
+    ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+  depmode     Dependency tracking mode.
+  source      Source file read by 'PROGRAMS ARGS'.
+  object      Object file output by 'PROGRAMS ARGS'.
+  DEPDIR      directory where to store dependencies.
+  depfile     Dependency file to output.
+  tmpdepfile  Temporary file to use when outputting dependencies.
+  libtool     Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "depcomp $scriptversion"
+    exit $?
+    ;;
+esac
+
+# Get the directory component of the given path, and save it in the
+# global variables '$dir'.  Note that this directory component will
+# be either empty or ending with a '/' character.  This is deliberate.
+set_dir_from ()
+{
+  case $1 in
+    */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
+      *) dir=;;
+  esac
+}
+
+# Get the suffix-stripped basename of the given path, and save it the
+# global variable '$base'.
+set_base_from ()
+{
+  base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
+}
+
+# If no dependency file was actually created by the compiler invocation,
+# we still have to create a dummy depfile, to avoid errors with the
+# Makefile "include basename.Plo" scheme.
+make_dummy_depfile ()
+{
+  echo "#dummy" > "$depfile"
+}
+
+# Factor out some common post-processing of the generated depfile.
+# Requires the auxiliary global variable '$tmpdepfile' to be set.
+aix_post_process_depfile ()
+{
+  # If the compiler actually managed to produce a dependency file,
+  # post-process it.
+  if test -f "$tmpdepfile"; then
+    # Each line is of the form 'foo.o: dependency.h'.
+    # Do two passes, one to just change these to
+    #   $object: dependency.h
+    # and one to simply output
+    #   dependency.h:
+    # which is needed to avoid the deleted-header problem.
+    { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
+      sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
+    } > "$depfile"
+    rm -f "$tmpdepfile"
+  else
+    make_dummy_depfile
+  fi
+}
+
+# A tabulation character.
+tab='  '
+# A newline character.
+nl='
+'
+# Character ranges might be problematic outside the C locale.
+# These definitions help.
+upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
+lower=abcdefghijklmnopqrstuvwxyz
+digits=0123456789
+alpha=${upper}${lower}
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+  echo "depcomp: Variables source, object and depmode must be set" 1>&2
+  exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+  sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Avoid interferences from the environment.
+gccflag= dashmflag=
+
+# Some modes work just like other modes, but use different flags.  We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write.  Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+  # HP compiler uses -M and no extra arg.
+  gccflag=-M
+  depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+  # This is just like dashmstdout with a different argument.
+  dashmflag=-xM
+  depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+  # This is just like msvisualcpp but w/o cygpath translation.
+  # Just convert the backslash-escaped backslashes to single forward
+  # slashes to satisfy depend.m4
+  cygpath_u='sed s,\\\\,/,g'
+  depmode=msvisualcpp
+fi
+
+if test "$depmode" = msvc7msys; then
+  # This is just like msvc7 but w/o cygpath translation.
+  # Just convert the backslash-escaped backslashes to single forward
+  # slashes to satisfy depend.m4
+  cygpath_u='sed s,\\\\,/,g'
+  depmode=msvc7
+fi
+
+if test "$depmode" = xlc; then
+  # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
+  gccflag=-qmakedep=gcc,-MF
+  depmode=gcc
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want.  Yay!  Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff.  Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am.  Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+  for arg
+  do
+    case $arg in
+    -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+    *)  set fnord "$@" "$arg" ;;
+    esac
+    shift # fnord
+    shift # $arg
+  done
+  "$@"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  mv "$tmpdepfile" "$depfile"
+  ;;
+
+gcc)
+## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
+## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
+## (see the conditional assignment to $gccflag above).
+## There are various ways to get dependency output from gcc.  Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+##   up in a subdir.  Having to rename by hand is ugly.
+##   (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+##   -MM, not -M (despite what the docs say).  Also, it might not be
+##   supported by the other compilers which use the 'gcc' depmode.
+## - Using -M directly means running the compiler twice (even worse
+##   than renaming).
+  if test -z "$gccflag"; then
+    gccflag=-MD,
+  fi
+  "$@" -Wp,"$gccflag$tmpdepfile"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  # The second -e expression handles DOS-style file names with drive
+  # letters.
+  sed -e 's/^[^:]*: / /' \
+      -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the "deleted header file" problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header).  We avoid this by adding
+## dummy dependencies for each header file.  Too bad gcc doesn't do
+## this for us directly.
+## Some versions of gcc put a space before the ':'.  On the theory
+## that the space means something, we add a space to the output as
+## well.  hp depmode also adds that space, but also prefixes the VPATH
+## to the object.  Take care to not repeat it in the output.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+  tr ' ' "$nl" < "$tmpdepfile" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+sgi)
+  if test "$libtool" = yes; then
+    "$@" "-Wp,-MDupdate,$tmpdepfile"
+  else
+    "$@" -MDupdate "$tmpdepfile"
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+
+  if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files
+    echo "$object : \\" > "$depfile"
+    # Clip off the initial element (the dependent).  Don't try to be
+    # clever and replace this with sed code, as IRIX sed won't handle
+    # lines with more than a fixed number of characters (4096 in
+    # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
+    # the IRIX cc adds comments like '#:fec' to the end of the
+    # dependency line.
+    tr ' ' "$nl" < "$tmpdepfile" \
+      | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
+      | tr "$nl" ' ' >> "$depfile"
+    echo >> "$depfile"
+    # The second pass generates a dummy entry for each header file.
+    tr ' ' "$nl" < "$tmpdepfile" \
+      | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+      >> "$depfile"
+  else
+    make_dummy_depfile
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+xlc)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+aix)
+  # The C for AIX Compiler uses -M and outputs the dependencies
+  # in a .u file.  In older versions, this file always lives in the
+  # current directory.  Also, the AIX compiler puts '$object:' at the
+  # start of each line; $object doesn't have directory information.
+  # Version 6 uses the directory in both cases.
+  set_dir_from "$object"
+  set_base_from "$object"
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$base.u
+    tmpdepfile3=$dir.libs/$base.u
+    "$@" -Wc,-M
+  else
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$dir$base.u
+    tmpdepfile3=$dir$base.u
+    "$@" -M
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+    exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  aix_post_process_depfile
+  ;;
+
+tcc)
+  # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
+  # FIXME: That version still under development at the moment of writing.
+  #        Make that this statement remains true also for stable, released
+  #        versions.
+  # It will wrap lines (doesn't matter whether long or short) with a
+  # trailing '\', as in:
+  #
+  #   foo.o : \
+  #    foo.c \
+  #    foo.h \
+  #
+  # It will put a trailing '\' even on the last line, and will use leading
+  # spaces rather than leading tabs (at least since its commit 0394caf7
+  # "Emit spaces for -MD").
+  "$@" -MD -MF "$tmpdepfile"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
+  # We have to change lines of the first kind to '$object: \'.
+  sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
+  # And for each line of the second kind, we have to emit a 'dep.h:'
+  # dummy dependency, to avoid the deleted-header problem.
+  sed -n -e 's|^  *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+## The order of this option in the case statement is important, since the
+## shell code in configure will try each of these formats in the order
+## listed in this file.  A plain '-MD' option would be understood by many
+## compilers, so we must ensure this comes after the gcc and icc options.
+pgcc)
+  # Portland's C compiler understands '-MD'.
+  # Will always output deps to 'file.d' where file is the root name of the
+  # source file under compilation, even if file resides in a subdirectory.
+  # The object file name does not affect the name of the '.d' file.
+  # pgcc 10.2 will output
+  #    foo.o: sub/foo.c sub/foo.h
+  # and will wrap long lines using '\' :
+  #    foo.o: sub/foo.c ... \
+  #     sub/foo.h ... \
+  #     ...
+  set_dir_from "$object"
+  # Use the source, not the object, to determine the base name, since
+  # that's sadly what pgcc will do too.
+  set_base_from "$source"
+  tmpdepfile=$base.d
+
+  # For projects that build the same source file twice into different object
+  # files, the pgcc approach of using the *source* file root name can cause
+  # problems in parallel builds.  Use a locking strategy to avoid stomping on
+  # the same $tmpdepfile.
+  lockdir=$base.d-lock
+  trap "
+    echo '$0: caught signal, cleaning up...' >&2
+    rmdir '$lockdir'
+    exit 1
+  " 1 2 13 15
+  numtries=100
+  i=$numtries
+  while test $i -gt 0; do
+    # mkdir is a portable test-and-set.
+    if mkdir "$lockdir" 2>/dev/null; then
+      # This process acquired the lock.
+      "$@" -MD
+      stat=$?
+      # Release the lock.
+      rmdir "$lockdir"
+      break
+    else
+      # If the lock is being held by a different process, wait
+      # until the winning process is done or we timeout.
+      while test -d "$lockdir" && test $i -gt 0; do
+        sleep 1
+        i=`expr $i - 1`
+      done
+    fi
+    i=`expr $i - 1`
+  done
+  trap - 1 2 13 15
+  if test $i -le 0; then
+    echo "$0: failed to acquire lock after $numtries attempts" >&2
+    echo "$0: check lockdir '$lockdir'" >&2
+    exit 1
+  fi
+
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each line is of the form `foo.o: dependent.h',
+  # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+  # Do two passes, one to just change these to
+  # `$object: dependent.h' and one to simply `dependent.h:'.
+  sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process this invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp2)
+  # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+  # compilers, which have integrated preprocessors.  The correct option
+  # to use with these is +Maked; it writes dependencies to a file named
+  # 'foo.d', which lands next to the object file, wherever that
+  # happens to be.
+  # Much of this is similar to the tru64 case; see comments there.
+  set_dir_from  "$object"
+  set_base_from "$object"
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir.libs/$base.d
+    "$@" -Wc,+Maked
+  else
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir$base.d
+    "$@" +Maked
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+     rm -f "$tmpdepfile1" "$tmpdepfile2"
+     exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  if test -f "$tmpdepfile"; then
+    sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
+    # Add 'dependent.h:' lines.
+    sed -ne '2,${
+               s/^ *//
+               s/ \\*$//
+               s/$/:/
+               p
+             }' "$tmpdepfile" >> "$depfile"
+  else
+    make_dummy_depfile
+  fi
+  rm -f "$tmpdepfile" "$tmpdepfile2"
+  ;;
+
+tru64)
+  # The Tru64 compiler uses -MD to generate dependencies as a side
+  # effect.  'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
+  # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+  # dependencies in 'foo.d' instead, so we check for that too.
+  # Subdirectories are respected.
+  set_dir_from  "$object"
+  set_base_from "$object"
+
+  if test "$libtool" = yes; then
+    # Libtool generates 2 separate objects for the 2 libraries.  These
+    # two compilations output dependencies in $dir.libs/$base.o.d and
+    # in $dir$base.o.d.  We have to check for both files, because
+    # one of the two compilations can be disabled.  We should prefer
+    # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+    # automatically cleaned when .libs/ is deleted, while ignoring
+    # the former would cause a distcleancheck panic.
+    tmpdepfile1=$dir$base.o.d          # libtool 1.5
+    tmpdepfile2=$dir.libs/$base.o.d    # Likewise.
+    tmpdepfile3=$dir.libs/$base.d      # Compaq CCC V6.2-504
+    "$@" -Wc,-MD
+  else
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir$base.d
+    tmpdepfile3=$dir$base.d
+    "$@" -MD
+  fi
+
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+    exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  # Same post-processing that is required for AIX mode.
+  aix_post_process_depfile
+  ;;
+
+msvc7)
+  if test "$libtool" = yes; then
+    showIncludes=-Wc,-showIncludes
+  else
+    showIncludes=-showIncludes
+  fi
+  "$@" $showIncludes > "$tmpdepfile"
+  stat=$?
+  grep -v '^Note: including file: ' "$tmpdepfile"
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  # The first sed program below extracts the file names and escapes
+  # backslashes for cygpath.  The second sed program outputs the file
+  # name when reading, but also accumulates all include files in the
+  # hold buffer in order to output them again at the end.  This only
+  # works with sed implementations that can handle large buffers.
+  sed < "$tmpdepfile" -n '
+/^Note: including file:  *\(.*\)/ {
+  s//\1/
+  s/\\/\\\\/g
+  p
+}' | $cygpath_u | sort -u | sed -n '
+s/ /\\ /g
+s/\(.*\)/'"$tab"'\1 \\/p
+s/.\(.*\) \\/\1:/
+H
+$ {
+  s/.*/'"$tab"'/
+  G
+  p
+}' >> "$depfile"
+  echo >> "$depfile" # make sure the fragment doesn't end with a backslash
+  rm -f "$tmpdepfile"
+  ;;
+
+msvc7msys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+#nosideeffect)
+  # This comment above is used by automake to tell side-effect
+  # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout, regardless of -o.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove '-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  test -z "$dashmflag" && dashmflag=-M
+  # Require at least two characters before searching for ':'
+  # in the target name.  This is to cope with DOS-style filenames:
+  # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
+  "$@" $dashmflag |
+    sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process this sed invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  tr ' ' "$nl" < "$tmpdepfile" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+dashXmstdout)
+  # This case only exists to satisfy depend.m4.  It is never actually
+  # run, as this mode is specially recognized in the preamble.
+  exit 1
+  ;;
+
+makedepend)
+  "$@" || exit $?
+  # Remove any Libtool call
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+  # X makedepend
+  shift
+  cleared=no eat=no
+  for arg
+  do
+    case $cleared in
+    no)
+      set ""; shift
+      cleared=yes ;;
+    esac
+    if test $eat = yes; then
+      eat=no
+      continue
+    fi
+    case "$arg" in
+    -D*|-I*)
+      set fnord "$@" "$arg"; shift ;;
+    # Strip any option that makedepend may not understand.  Remove
+    # the object too, otherwise makedepend will parse it as a source file.
+    -arch)
+      eat=yes ;;
+    -*|$object)
+      ;;
+    *)
+      set fnord "$@" "$arg"; shift ;;
+    esac
+  done
+  obj_suffix=`echo "$object" | sed 's/^.*\././'`
+  touch "$tmpdepfile"
+  ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+  rm -f "$depfile"
+  # makedepend may prepend the VPATH from the source file name to the object.
+  # No need to regex-escape $object, excess matching of '.' is harmless.
+  sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process the last invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  sed '1,2d' "$tmpdepfile" \
+    | tr ' ' "$nl" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile" "$tmpdepfile".bak
+  ;;
+
+cpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove '-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  "$@" -E \
+    | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+             -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+    | sed '$ s: \\$::' > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  cat < "$tmpdepfile" >> "$depfile"
+  sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvisualcpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  IFS=" "
+  for arg
+  do
+    case "$arg" in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+        set fnord "$@"
+        shift
+        shift
+        ;;
+    *)
+        set fnord "$@" "$arg"
+        shift
+        shift
+        ;;
+    esac
+  done
+  "$@" -E 2>/dev/null |
+  sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+  echo "$tab" >> "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvcmsys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+none)
+  exec "$@"
+  ;;
+
+*)
+  echo "Unknown depmode $depmode" 1>&2
+  exit 1
+  ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/sntp/libevent/doxygen.am b/sntp/libevent/doxygen.am
new file mode 100644 (file)
index 0000000..916d7c4
--- /dev/null
@@ -0,0 +1,55 @@
+# Doxygen documentation will not be generated with default configuration,
+# unless '--enable-doxygen-doc' is configured.
+# The following targets are all about doxygen:
+# make                # 'make doxygen' would be auto executed
+# make doxygen        # generating doxygen documentation
+# make doxygen-doc    # same as 'make doxygen'
+# make clean          # clean docs generated by doxygen
+# make install        # install doxygen documentation
+# make uninstall      # uninstall doxygen documentation
+
+if ENABLE_DOXYGEN
+
+# Add all needed rules defined in ax_prog_doxygen.m4
+@DX_RULES@
+
+# Use 'make clean' to clean docs generated by doxygen.
+clean-local:
+       -rm -rf $(DX_CLEANFILES)
+
+# integrate doxygen with automake targets
+man3_MANS = @DX_DOCDIR@/man/man3/*
+$(man3_MANS): doxygen-doc
+
+# Docs will be installed. It may be one or more docs supported
+# by doxygen, but does not include 'man'.
+docdirs = $(DX_INSTALL_DOCS)
+
+# Rules for installing docs generated by doxygen into $(htmldir),
+# The typical value of $(htmldir) is '/usr/local/share/doc/$(PACKAGE)'
+install-data-local:
+       @if ! test -d "$(DESTDIR)$(htmldir)"; then \
+         echo "$(mkinstalldirs) '$(DESTDIR)$(htmldir)'"; \
+         $(mkinstalldirs) '$(DESTDIR)$(htmldir)'; \
+       fi
+       @for d in $(docdirs); do \
+         echo "cp -pR $$d '$(DESTDIR)$(htmldir)/'"; \
+         cp -pR $$d '$(DESTDIR)$(htmldir)/'; \
+       done
+
+# Rules for uninstalling docs generated by doxygen from $(htmldir)
+uninstall-local:
+       @for d in $(docdirs); do \
+         d=`basename $$d`; \
+         echo "test ! -d '$(DESTDIR)$(htmldir)/'$$d || \
+         { find '$(DESTDIR)$(htmldir)/'$$d -type d ! -perm -200 -exec chmod u+w '{}' ';' && \
+         rm -rf '$(DESTDIR)$(htmldir)/'$$d; }"; \
+         test ! -d '$(DESTDIR)$(htmldir)/'$$d || \
+         { find '$(DESTDIR)$(htmldir)/'$$d -type d ! -perm -200 -exec chmod u+w '{}' ';' && \
+         rm -rf '$(DESTDIR)$(htmldir)/'$$d; }; \
+       done
+       rmdir "$(DESTDIR)$(htmldir)/" || true
+
+doxygen: doxygen-doc
+
+endif ENABLE_DOXYGEN
index aa41f84e027e30876dd282ea7e733c38a093d171..bdec2e45695da22a5b85a9e3d481f28e87648724 100644 (file)
@@ -246,6 +246,23 @@ epoll_op_to_string(int op)
            "???";
 }
 
+#define PRINT_CHANGES(op, events, ch, status)  \
+       "Epoll %s(%d) on fd %d " status ". "       \
+       "Old events were %d; "                     \
+       "read change was %d (%s); "                \
+       "write change was %d (%s); "               \
+       "close change was %d (%s)",                \
+       epoll_op_to_string(op),                    \
+       events,                                    \
+       ch->fd,                                    \
+       ch->old_events,                            \
+       ch->read_change,                           \
+       change_to_string(ch->read_change),         \
+       ch->write_change,                          \
+       change_to_string(ch->write_change),        \
+       ch->close_change,                          \
+       change_to_string(ch->close_change)
+
 static int
 epoll_apply_one_change(struct event_base *base,
     struct epollop *epollop,
@@ -264,21 +281,14 @@ epoll_apply_one_change(struct event_base *base,
                return 0;
        }
 
-       if ((ch->read_change|ch->write_change) & EV_CHANGE_ET)
+       if ((ch->read_change|ch->write_change|ch->close_change) & EV_CHANGE_ET)
                events |= EPOLLET;
 
        memset(&epev, 0, sizeof(epev));
        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; 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->close_change));
+               event_debug((PRINT_CHANGES(op, epev.events, ch, "okay")));
                return 0;
        }
 
@@ -338,18 +348,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); close change was %d (%s)",
-           epoll_op_to_string(op),
-           (int)epev.events,
-           ch->fd,
-           ch->old_events,
-           ch->read_change,
-           change_to_string(ch->read_change),
-           ch->write_change,
-           change_to_string(ch->write_change),
-           ch->close_change,
-           change_to_string(ch->close_change));
-
+       event_warn(PRINT_CHANGES(op, epev.events, ch, "failed"));
        return -1;
 }
 
@@ -402,11 +401,14 @@ epoll_nochangelist_del(struct event_base *base, evutil_socket_t fd,
        ch.old_events = old;
        ch.read_change = ch.write_change = ch.close_change = 0;
        if (events & EV_WRITE)
-               ch.write_change = EV_CHANGE_DEL;
+               ch.write_change = EV_CHANGE_DEL |
+                   (events & EV_ET);
        if (events & EV_READ)
-               ch.read_change = EV_CHANGE_DEL;
+               ch.read_change = EV_CHANGE_DEL |
+                   (events & EV_ET);
        if (events & EV_CLOSED)
-               ch.close_change = EV_CHANGE_DEL;
+               ch.close_change = EV_CHANGE_DEL |
+                   (events & EV_ET);
 
        return epoll_apply_one_change(base, base->evbase, &ch);
 }
@@ -484,7 +486,9 @@ epoll_dispatch(struct event_base *base, struct timeval *tv)
                        continue;
 #endif
 
-               if (what & (EPOLLHUP|EPOLLERR)) {
+               if (what & EPOLLERR) {
+                       ev = EV_READ | EV_WRITE;
+               } else if ((what & EPOLLHUP) && !(what & EPOLLRDHUP)) {
                        ev = EV_READ | EV_WRITE;
                } else {
                        if (what & EPOLLIN)
index da30e0973a27e08490d2393ceebb0b4723625d17..73c2e3647e297e3770083b9ebad116373df1c742 100644 (file)
@@ -34,7 +34,7 @@
   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
+  Note 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
index cf4bddc80ea86c0ebbe42e98c82ae78cf1934b25..d09b4f1ddd58af85c946ac4a1bfa178996930a77 100644 (file)
@@ -92,7 +92,7 @@ struct evbuffer {
         * If the buffer has no chains, it is NULL.
         *
         * The last_with_datap pointer points at _whatever 'next' pointer_
-        * points at the last_with_datap chain.  If the last_with_data chain
+        * pointing at the last_with_data chain. If the last_with_data chain
         * is the first chain, or it is NULL, then the last_with_datap pointer
         * is &buf->first.
         */
diff --git a/sntp/libevent/evconfig-private.h.cmake b/sntp/libevent/evconfig-private.h.cmake
new file mode 100644 (file)
index 0000000..1adf9c0
--- /dev/null
@@ -0,0 +1,40 @@
+
+#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
+
+/* Enable POSIX.2 extensions on QNX for getopt */
+#ifdef __QNX__
+#cmakedefine __EXT_POSIX2 1
+#endif
+
+#endif
index 7b3dfdb10e90ae5fbd166d51036929fb3ca06626..8cd64787433225b74d9562aebceea24e8f2c515b 100644 (file)
 #undef _POSIX_SOURCE
 #endif
 
+/* Enable POSIX.2 extensions on QNX for getopt */
+#ifdef __QNX__
+# ifndef __EXT_POSIX2
+#  define __EXT_POSIX2
+# endif
+#endif
+
 #endif
index 52a2b6bce60415ea30aa1076a9d7327f88c8f71a..a5b31a3c0017ae381a019e13b05e9f7eed2b6590 100644 (file)
@@ -77,6 +77,7 @@
 #include <stdarg.h>
 #ifdef _WIN32
 #include <winsock2.h>
+#include <winerror.h>
 #include <ws2tcpip.h>
 #ifndef _WIN32_IE
 #define _WIN32_IE 0x400
@@ -346,6 +347,9 @@ struct evdns_base {
 
        struct timeval global_getaddrinfo_allow_skew;
 
+       int so_rcvbuf;
+       int so_sndbuf;
+
        int getaddrinfo_ipv4_timeouts;
        int getaddrinfo_ipv6_timeouts;
        int getaddrinfo_ipv4_answered;
@@ -863,6 +867,19 @@ reply_schedule_callback(struct request *const req, u32 ttl, u32 err, struct repl
                &d->deferred);
 }
 
+
+#define _QR_MASK    0x8000U
+#define _OP_MASK    0x7800U
+#define _AA_MASK    0x0400U
+#define _TC_MASK    0x0200U
+#define _RD_MASK    0x0100U
+#define _RA_MASK    0x0080U
+#define _Z_MASK     0x0040U
+#define _AD_MASK    0x0020U
+#define _CD_MASK    0x0010U
+#define _RCODE_MASK 0x000fU
+#define _Z_MASK_DEPRECATED 0x0070U
+
 /* this processes a parsed reply packet */
 static void
 reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) {
@@ -876,12 +893,12 @@ reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply)
        ASSERT_LOCKED(req->base);
        ASSERT_VALID_REQUEST(req);
 
-       if (flags & 0x020f || !reply || !reply->have_answer) {
+       if (flags & (_RCODE_MASK | _TC_MASK) || !reply || !reply->have_answer) {
                /* there was an error */
-               if (flags & 0x0200) {
+               if (flags & _TC_MASK) {
                        error = DNS_ERR_TRUNCATED;
-               } else if (flags & 0x000f) {
-                       u16 error_code = (flags & 0x000f) - 1;
+               } else if (flags & _RCODE_MASK) {
+                       u16 error_code = (flags & _RCODE_MASK) - 1;
                        if (error_code > 4) {
                                error = DNS_ERR_UNKNOWN;
                        } else {
@@ -976,7 +993,6 @@ name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) {
 
        for (;;) {
                u8 label_len;
-               if (j >= length) return -1;
                GET8(label_len);
                if (!label_len) break;
                if (label_len & 0xc0) {
@@ -997,6 +1013,7 @@ name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) {
                        *cp++ = '.';
                }
                if (cp + label_len >= end) return -1;
+               if (j + label_len > length) return -1;
                memcpy(cp, packet + j, label_len);
                cp += label_len;
                j += label_len;
@@ -1046,8 +1063,8 @@ reply_parse(struct evdns_base *base, u8 *packet, int length) {
        memset(&reply, 0, sizeof(reply));
 
        /* If it's not an answer, it doesn't correspond to any request. */
-       if (!(flags & 0x8000)) return -1;  /* must be an answer */
-       if ((flags & 0x020f) && (flags & 0x020f) != DNS_ERR_NOTEXIST) {
+       if (!(flags & _QR_MASK)) return -1;  /* must be an answer */
+       if ((flags & (_RCODE_MASK|_TC_MASK)) && (flags & (_RCODE_MASK|_TC_MASK)) != DNS_ERR_NOTEXIST) {
                /* there was an error and it's not NXDOMAIN */
                goto err;
        }
@@ -1060,24 +1077,6 @@ reply_parse(struct evdns_base *base, u8 *packet, int length) {
                        sizeof(tmp_name))<0)                    \
                        goto err;                               \
        } while (0)
-#define TEST_NAME                                                      \
-       do { tmp_name[0] = '\0';                                        \
-               cmp_name[0] = '\0';                                     \
-               k = j;                                                  \
-               if (name_parse(packet, length, &j, tmp_name,            \
-                       sizeof(tmp_name))<0)                            \
-                       goto err;                                       \
-               if (name_parse(req->request, req->request_len, &k,      \
-                       cmp_name, sizeof(cmp_name))<0)                  \
-                       goto err;                                       \
-               if (base->global_randomize_case) {                      \
-                       if (strcmp(tmp_name, cmp_name) == 0)            \
-                               name_matches = 1;                       \
-               } else {                                                \
-                       if (evutil_ascii_strcasecmp(tmp_name, cmp_name) == 0) \
-                               name_matches = 1;                       \
-               }                                                       \
-       } while (0)
 
        reply.type = req->request_type;
 
@@ -1086,9 +1085,25 @@ reply_parse(struct evdns_base *base, u8 *packet, int length) {
                /* the question looks like
                 *   <label:name><u16:type><u16:class>
                 */
-               TEST_NAME;
+               tmp_name[0] = '\0';
+               cmp_name[0] = '\0';
+               k = j;
+               if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name)) < 0)
+                       goto err;
+               if (name_parse(req->request, req->request_len, &k,
+                       cmp_name, sizeof(cmp_name))<0)
+                       goto err;
+               if (!base->global_randomize_case) {
+                       if (strcmp(tmp_name, cmp_name) == 0)
+                               name_matches = 1;
+               } else {
+                       if (evutil_ascii_strcasecmp(tmp_name, cmp_name) == 0)
+                               name_matches = 1;
+               }
+
                j += 4;
-               if (j > length) goto err;
+               if (j > length)
+                       goto err;
        }
 
        if (!name_matches)
@@ -1238,8 +1253,8 @@ request_parse(u8 *packet, int length, struct evdns_server_port *port, struct soc
        (void)additional;
        (void)authority;
 
-       if (flags & 0x8000) return -1; /* Must not be an answer. */
-       flags &= 0x0110; /* Only RD and CD get preserved. */
+       if (flags & _QR_MASK) return -1; /* Must not be an answer. */
+       flags &= (_RD_MASK|_CD_MASK); /* Only RD and CD get preserved. */
 
        server_req = mm_malloc(sizeof(struct server_request));
        if (server_req == NULL) return -1;
@@ -1279,7 +1294,7 @@ request_parse(u8 *packet, int length, struct evdns_server_port *port, struct soc
        port->refcnt++;
 
        /* Only standard queries are supported. */
-       if (flags & 0x7800) {
+       if (flags & _OP_MASK) {
                evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL);
                return -1;
        }
@@ -1288,14 +1303,12 @@ request_parse(u8 *packet, int length, struct evdns_server_port *port, struct soc
 
        return 0;
 err:
-       if (server_req) {
-               if (server_req->base.questions) {
-                       for (i = 0; i < server_req->base.nquestions; ++i)
-                               mm_free(server_req->base.questions[i]);
-                       mm_free(server_req->base.questions);
-               }
-               mm_free(server_req);
+       if (server_req->base.questions) {
+               for (i = 0; i < server_req->base.nquestions; ++i)
+                       mm_free(server_req->base.questions[i]);
+               mm_free(server_req->base.questions);
        }
+       mm_free(server_req);
        return -1;
 
 #undef SKIP_NAME
@@ -1753,6 +1766,7 @@ evdns_close_server_port(struct evdns_server_port *port)
                server_port_free(port);
        } else {
                port->closing = 1;
+               EVDNS_UNLOCK(port);
        }
 }
 
@@ -1906,7 +1920,7 @@ evdns_server_request_format_response(struct server_request *req, int err)
        /* Set response bit and error code; copy OPCODE and RD fields from
         * question; copy RA and AA if set by caller. */
        flags = req->base.flags;
-       flags |= (0x8000 | err);
+       flags |= (_QR_MASK | err);
 
        dnslabel_table_init(&table);
        APPEND16(req->trans_id);
@@ -2267,11 +2281,11 @@ evdns_request_transmit(struct request *req) {
                nameserver_write_waiting(req->ns, 1);
                return 1;
        case 2:
-               /* failed to transmit the request entirely. */
+               /* failed to transmit the request entirely. we can fallthrough since
+                * we'll set a timeout, which will time out, and make us retransmit the
+                * request anyway. */
                retcode = 1;
-               /* fall through: we'll set a timeout, which will time out,
-                * and make us retransmit the request anyway. */
-               /* FALLTHROUGH */
+               EVUTIL_FALLTHROUGH;
        default:
                /* all ok */
                log(EVDNS_LOG_DEBUG,
@@ -2528,6 +2542,23 @@ evdns_nameserver_add_impl_(struct evdns_base *base, const struct sockaddr *addre
                }
        }
 
+       if (base->so_rcvbuf) {
+               if (setsockopt(ns->socket, SOL_SOCKET, SO_RCVBUF,
+                   (void *)&base->so_rcvbuf, sizeof(base->so_rcvbuf))) {
+                       log(EVDNS_LOG_WARN, "Couldn't set SO_RCVBUF to %i", base->so_rcvbuf);
+                       err = -SO_RCVBUF;
+                       goto out2;
+               }
+       }
+       if (base->so_sndbuf) {
+               if (setsockopt(ns->socket, SOL_SOCKET, SO_SNDBUF,
+                   (void *)&base->so_sndbuf, sizeof(base->so_sndbuf))) {
+                       log(EVDNS_LOG_WARN, "Couldn't set SO_SNDBUF to %i", base->so_sndbuf);
+                       err = -SO_SNDBUF;
+                       goto out2;
+               }
+       }
+
        memcpy(&ns->address, address, addrlen);
        ns->addrlen = addrlen;
        ns->state = 1;
@@ -3178,9 +3209,12 @@ search_set_from_hostname(struct evdns_base *base) {
 static char *
 search_make_new(const struct search_state *const state, int n, const char *const base_name) {
        const size_t base_len = strlen(base_name);
-       const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
+       char need_to_append_dot;
        struct search_domain *dom;
 
+       if (!base_len) return NULL;
+       need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
+
        for (dom = state->head; dom; dom = dom->next) {
                if (!n--) {
                        /* this is the postfix we want */
@@ -3313,10 +3347,16 @@ search_request_finished(struct evdns_request *const handle) {
 
 static void
 evdns_resolv_set_defaults(struct evdns_base *base, int flags) {
+       int add_default = flags & DNS_OPTION_NAMESERVERS;
+       if (flags & DNS_OPTION_NAMESERVERS_NO_DEFAULT)
+               add_default = 0;
+
        /* if the file isn't found then we assume a local resolver */
        ASSERT_LOCKED(base);
-       if (flags & DNS_OPTION_SEARCH) search_set_from_hostname(base);
-       if (flags & DNS_OPTION_NAMESERVERS) evdns_base_nameserver_ip_add(base,"127.0.0.1");
+       if (flags & DNS_OPTION_SEARCH)
+               search_set_from_hostname(base);
+       if (add_default)
+               evdns_base_nameserver_ip_add(base, "127.0.0.1");
 }
 
 #ifndef EVENT__HAVE_STRTOK_R
@@ -3491,6 +3531,7 @@ evdns_base_set_option_impl(struct evdns_base *base,
                base->global_max_retransmits = retries;
        } else if (str_matches_option(option, "randomize-case:")) {
                int randcase = strtoint(val);
+               if (randcase == -1) return -1;
                if (!(flags & DNS_OPTION_MISC)) return 0;
                base->global_randomize_case = randcase;
        } else if (str_matches_option(option, "bind-to:")) {
@@ -3512,6 +3553,18 @@ evdns_base_set_option_impl(struct evdns_base *base,
                    val);
                memcpy(&base->global_nameserver_probe_initial_timeout, &tv,
                    sizeof(tv));
+       } else if (str_matches_option(option, "so-rcvbuf:")) {
+               int buf = strtoint(val);
+               if (buf == -1) return -1;
+               if (!(flags & DNS_OPTION_MISC)) return 0;
+               log(EVDNS_LOG_DEBUG, "Setting SO_RCVBUF to %s", val);
+               base->so_rcvbuf = buf;
+       } else if (str_matches_option(option, "so-sndbuf:")) {
+               int buf = strtoint(val);
+               if (buf == -1) return -1;
+               if (!(flags & DNS_OPTION_MISC)) return 0;
+               log(EVDNS_LOG_DEBUG, "Setting SO_SNDBUF to %s", val);
+               base->so_sndbuf = buf;
        }
        return 0;
 }
@@ -3612,9 +3665,14 @@ evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char
        char *resolv;
        char *start;
        int err = 0;
+       int add_default;
 
        log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename);
 
+       add_default = flags & DNS_OPTION_NAMESERVERS;
+       if (flags & DNS_OPTION_NAMESERVERS_NO_DEFAULT)
+               add_default = 0;
+
        if (flags & DNS_OPTION_HOSTSFILE) {
                char *fname = evdns_get_default_hosts_filename();
                evdns_base_load_hosts(base, fname);
@@ -3622,6 +3680,11 @@ evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char
                        mm_free(fname);
        }
 
+       if (!filename) {
+               evdns_resolv_set_defaults(base, flags);
+               return 1;
+       }
+
        if ((err = evutil_read_file_(filename, &resolv, &n, 0)) < 0) {
                if (err == -1) {
                        /* No file. */
@@ -3645,7 +3708,7 @@ evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char
                }
        }
 
-       if (!base->server_head && (flags & DNS_OPTION_NAMESERVERS)) {
+       if (!base->server_head && add_default) {
                /* no nameservers were configured. */
                evdns_base_nameserver_ip_add(base, "127.0.0.1");
                err = 6;
@@ -3911,6 +3974,7 @@ evdns_base_new(struct event_base *event_base, int flags)
         * functionality.  We can't just call evdns_getaddrinfo directly or
         * else libevent-core will depend on libevent-extras. */
        evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo);
+       evutil_set_evdns_getaddrinfo_cancel_fn_(evdns_getaddrinfo_cancel);
 
        base = mm_malloc(sizeof(struct evdns_base));
        if (base == NULL)
@@ -3945,7 +4009,12 @@ evdns_base_new(struct event_base *event_base, int flags)
 
        TAILQ_INIT(&base->hostsdb);
 
-#define EVDNS_BASE_ALL_FLAGS (0x8001)
+#define EVDNS_BASE_ALL_FLAGS ( \
+       EVDNS_BASE_INITIALIZE_NAMESERVERS | \
+       EVDNS_BASE_DISABLE_WHEN_INACTIVE  | \
+       EVDNS_BASE_NAMESERVERS_NO_DEFAULT | \
+       0)
+
        if (flags & ~EVDNS_BASE_ALL_FLAGS) {
                flags = EVDNS_BASE_INITIALIZE_NAMESERVERS;
                log(EVDNS_LOG_WARN,
@@ -3956,12 +4025,17 @@ evdns_base_new(struct event_base *event_base, int flags)
 
        if (flags & EVDNS_BASE_INITIALIZE_NAMESERVERS) {
                int r;
+               int opts = DNS_OPTIONS_ALL;
+               if (flags & EVDNS_BASE_NAMESERVERS_NO_DEFAULT) {
+                       opts |= DNS_OPTION_NAMESERVERS_NO_DEFAULT;
+               }
+
 #ifdef _WIN32
                r = evdns_base_config_windows_nameservers(base);
 #else
-               r = evdns_base_resolv_conf_parse(base, DNS_OPTIONS_ALL, "/etc/resolv.conf");
+               r = evdns_base_resolv_conf_parse(base, opts, "/etc/resolv.conf");
 #endif
-               if (r == -1) {
+               if (r) {
                        evdns_base_free_and_unlock(base, 0);
                        return NULL;
                }
@@ -4011,7 +4085,7 @@ static void
 evdns_nameserver_free(struct nameserver *server)
 {
        if (server->socket >= 0)
-       evutil_closesocket(server->socket);
+               evutil_closesocket(server->socket);
        (void) event_del(&server->event);
        event_debug_unassign(&server->event);
        if (server->state == 0)
@@ -4035,15 +4109,11 @@ 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;
+       while (base->req_waiting_head) {
+               if (fail_requests)
+                       reply_schedule_callback(base->req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL);
+               request_finished(base->req_waiting_head, &base->req_waiting_head, 1);
        }
-       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)
@@ -4051,13 +4121,18 @@ evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests)
                        request_finished(base->req_heads[i], &REQ_HEAD(base, base->req_heads[i]->trans_id), 1);
                }
        }
-       while (base->req_waiting_head) {
-               if (fail_requests)
-                       reply_schedule_callback(base->req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL);
-               request_finished(base->req_waiting_head, &base->req_waiting_head, 1);
-       }
        base->global_requests_inflight = base->global_requests_waiting = 0;
 
+       for (server = base->server_head; server; server = server_next) {
+               server_next = server->next;
+               /** already done something before */
+               server->probe_request = NULL;
+               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) {
@@ -4407,17 +4482,23 @@ evdns_getaddrinfo_gotresolve(int result, char type, int count,
                other_req = &data->ipv4_request;
        }
 
-       EVDNS_LOCK(data->evdns_base);
-       if (evdns_result_is_answer(result)) {
-               if (req->type == DNS_IPv4_A)
-                       ++data->evdns_base->getaddrinfo_ipv4_answered;
-               else
-                       ++data->evdns_base->getaddrinfo_ipv6_answered;
+       /** Called from evdns_base_free() with @fail_requests == 1 */
+       if (result != DNS_ERR_SHUTDOWN) {
+               EVDNS_LOCK(data->evdns_base);
+               if (evdns_result_is_answer(result)) {
+                       if (req->type == DNS_IPv4_A)
+                               ++data->evdns_base->getaddrinfo_ipv4_answered;
+                       else
+                               ++data->evdns_base->getaddrinfo_ipv6_answered;
+               }
+               user_canceled = data->user_canceled;
+               if (other_req->r == NULL)
+                       data->request_done = 1;
+               EVDNS_UNLOCK(data->evdns_base);
+       } else {
+               data->evdns_base = NULL;
+               user_canceled = data->user_canceled;
        }
-       user_canceled = data->user_canceled;
-       if (other_req->r == NULL)
-               data->request_done = 1;
-       EVDNS_UNLOCK(data->evdns_base);
 
        req->r = NULL;
 
@@ -4451,7 +4532,9 @@ evdns_getaddrinfo_gotresolve(int result, char type, int count,
                        /* The other request is still working; maybe it will
                         * succeed. */
                        /* XXXX handle failure from set_timeout */
-                       evdns_getaddrinfo_set_timeout(data->evdns_base, data);
+                       if (result != DNS_ERR_SHUTDOWN) {
+                               evdns_getaddrinfo_set_timeout(data->evdns_base, data);
+                       }
                        data->pending_error = err;
                        return;
                }
@@ -4626,6 +4709,7 @@ evdns_getaddrinfo(struct evdns_base *dns_base,
        int err;
        int port = 0;
        int want_cname = 0;
+       int started = 0;
 
        if (!dns_base) {
                dns_base = current_base;
@@ -4704,6 +4788,8 @@ evdns_getaddrinfo(struct evdns_base *dns_base,
         * launching those requests. (XXX we don't do that yet.)
         */
 
+       EVDNS_LOCK(dns_base);
+
        if (hints.ai_family != PF_INET6) {
                log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv4 as %p",
                    nodename, &data->ipv4_request);
@@ -4730,7 +4816,11 @@ evdns_getaddrinfo(struct evdns_base *dns_base,
        evtimer_assign(&data->timeout, dns_base->event_base,
            evdns_getaddrinfo_timeout_cb, data);
 
-       if (data->ipv4_request.r || data->ipv6_request.r) {
+       started = (data->ipv4_request.r || data->ipv6_request.r);
+
+       EVDNS_UNLOCK(dns_base);
+
+       if (started) {
                return data;
        } else {
                mm_free(data);
diff --git a/sntp/libevent/event-config.h.cmake b/sntp/libevent/event-config.h.cmake
new file mode 100644 (file)
index 0000000..fccf0cf
--- /dev/null
@@ -0,0 +1,513 @@
+/* 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@"
+
+#define EVENT__VERSION_MAJOR @EVENT_VERSION_MAJOR@
+#define EVENT__VERSION_MINOR @EVENT_VERSION_MINOR@
+#define EVENT__VERSION_PATCH @EVENT_VERSION_PATCH@
+
+/* 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 1
+
+/* Define if libevent should not allow replacing the mm functions */
+#cmakedefine EVENT__DISABLE_MM_REPLACEMENT 1
+
+/* Define if libevent should not be compiled with thread support */
+#cmakedefine EVENT__DISABLE_THREAD_SUPPORT 1
+
+/* 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 to 1 if you have the `arc4random_addrandom' function. */
+#cmakedefine EVENT__HAVE_ARC4RANDOM_ADDRANDOM 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'. */
+#define EVENT__HAVE_DECL_CTL_KERN @EVENT__HAVE_DECL_CTL_KERN@
+
+/* Define to 1 if you have the declaration of `KERN_ARND'. */
+#define EVENT__HAVE_DECL_KERN_ARND @EVENT__HAVE_DECL_KERN_ARND@
+
+/* Define to 1 if you have `getrandom' function. */
+#cmakedefine EVENT__HAVE_GETRANDOM 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 <mach/mach.h> header file. */
+#cmakedefine EVENT__HAVE_MACH_MACH_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 <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 to 1 if you have the <sys/un.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <afunix.h> header file. */
+#cmakedefine EVENT__HAVE_AFUNIX_H 1
+
+/* Define if the system has openssl */
+#cmakedefine EVENT__HAVE_OPENSSL 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 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 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 <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 you have the `_gmtime64_s' function. */
+#cmakedefine EVENT__HAVE__GMTIME64_S 1
+
+/* Define to 1 if you have the `_gmtime64' function. */
+#cmakedefine EVENT__HAVE__GMTIME64 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_un'. */
+#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_UN 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 the system has the type `struct linger'. */
+#cmakedefine EVENT__HAVE_STRUCT_LINGER 1
+
+/* Define to 1 if you have the `sysctl' function. */
+#cmakedefine EVENT__HAVE_SYSCTL 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/random.h> header file. */
+#cmakedefine EVENT__HAVE_SYS_RANDOM_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 1
+
+/* 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 to 1 if you have the <errno.h> header file. */
+#cmakedefine EVENT__HAVE_ERRNO_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
+
+#ifdef __USE_UNUSED_DEFINITIONS__
+/* Define to necessary symbol if this constant uses a non-standard name on your system. */
+/* XXX: Hello, this isn't even used, nor is it defined anywhere... - Ellzey */
+#define EVENT__PTHREAD_CREATE_JOINABLE ${EVENT__PTHREAD_CREATE_JOINABLE}
+#endif
+
+/* The size of `pthread_t', as computed by sizeof. */
+#define EVENT__SIZEOF_PTHREAD_T @EVENT__SIZEOF_PTHREAD_T@
+
+/* The size of a `int', as computed by sizeof. */
+#define EVENT__SIZEOF_INT @EVENT__SIZEOF_INT@
+
+/* The size of a `long', as computed by sizeof. */
+#define EVENT__SIZEOF_LONG @EVENT__SIZEOF_LONG@
+
+/* The size of a `long long', as computed by sizeof. */
+#define EVENT__SIZEOF_LONG_LONG @EVENT__SIZEOF_LONG_LONG@
+
+/* The size of `off_t', as computed by sizeof. */
+#define EVENT__SIZEOF_OFF_T @EVENT__SIZEOF_OFF_T@
+
+#define EVENT__SIZEOF_SSIZE_T @EVENT__SIZEOF_SSIZE_T@
+
+
+/* The size of a `short', as computed by sizeof. */
+#define EVENT__SIZEOF_SHORT @EVENT__SIZEOF_SHORT@
+
+/* The size of `size_t', as computed by sizeof. */
+#define EVENT__SIZEOF_SIZE_T @EVENT__SIZEOF_SIZE_T@
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#cmakedefine EVENT__TIME_WITH_SYS_TIME 1
+
+/* The size of `socklen_t', as computed by sizeof. */
+#define EVENT__SIZEOF_SOCKLEN_T @EVENT__SIZEOF_SOCKLEN_T@
+
+/* The size of 'void *', as computer by sizeof */
+#define EVENT__SIZEOF_VOID_P @EVENT__SIZEOF_VOID_P@
+
+/* 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
+/* why not c++?
+ *
+ *  and are we really expected to use EVENT__inline everywhere,
+ *  shouldn't we just do:
+ *     ifdef EVENT__inline
+ *     define inline EVENT__inline
+ *
+ * - Ellzey
+ */
+
+#define EVENT__inline @EVENT__inline@
+#endif
+
+#cmakedefine EVENT__HAVE___func__ 1
+#cmakedefine EVENT__HAVE___FUNCTION__ 1
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#define EVENT__size_t @EVENT__size_t@
+
+/* Define to unsigned int if you dont have it */
+#define EVENT__socklen_t @EVENT__socklen_t@
+
+/* Define to `int' if <sys/types.h> does not define. */
+#define EVENT__ssize_t @EVENT__ssize_t@
+
+#endif /* \EVENT2_EVENT_CONFIG_H_INCLUDED_ */
index 5208fbe0874e1dd7a599336d92daf06ffc7a7921..9e5ff42447374ae191fa264d1d253f187b6eaa18 100644 (file)
@@ -219,7 +219,7 @@ struct event_base {
        /** Function pointers used to describe the backend that this event_base
         * uses for signals */
        const struct eventop *evsigsel;
-       /** Data to implement the common signal handelr code. */
+       /** Data to implement the common signal handler code. */
        struct evsig_info sig;
 
        /** Number of virtual events */
@@ -368,7 +368,10 @@ struct event_config {
 };
 
 /* Internal use only: Functions that might be missing from <sys/queue.h> */
-#if defined(EVENT__HAVE_SYS_QUEUE_H) && !defined(EVENT__HAVE_TAILQFOREACH)
+#ifndef LIST_END
+#define LIST_END(head)                 NULL
+#endif
+
 #ifndef TAILQ_FIRST
 #define        TAILQ_FIRST(head)               ((head)->tqh_first)
 #endif
@@ -394,7 +397,6 @@ struct event_config {
        (listelm)->field.tqe_prev = &(elm)->field.tqe_next;             \
 } while (0)
 #endif
-#endif /* TAILQ_FOREACH */
 
 #define N_ACTIVE_CALLBACKS(base)                                       \
        ((base)->event_count_active)
@@ -416,26 +418,29 @@ int event_add_nolock_(struct event *ev,
  * if it is running in another thread and it doesn't have EV_FINALIZE set.
  */
 #define EVENT_DEL_AUTOBLOCK 2
-/** Argument for event_del_nolock_. Tells event_del to procede even if the
+/** Argument for event_del_nolock_. Tells event_del to proceed even if the
  * event is set up for finalization rather for regular use.*/
 #define EVENT_DEL_EVEN_IF_FINALIZING 3
 int event_del_nolock_(struct event *ev, int blocking);
 int event_remove_timer_nolock_(struct event *ev);
 
 void event_active_nolock_(struct event *ev, int res, short count);
+EVENT2_EXPORT_SYMBOL
 int event_callback_activate_(struct event_base *, struct event_callback *);
 int event_callback_activate_nolock_(struct event_base *, struct event_callback *);
 int event_callback_cancel_(struct event_base *base,
     struct event_callback *evcb);
 
 void event_callback_finalize_nolock_(struct event_base *base, unsigned flags, struct event_callback *evcb, void (*cb)(struct event_callback *, void *));
+EVENT2_EXPORT_SYMBOL
 void event_callback_finalize_(struct event_base *base, unsigned flags, struct event_callback *evcb, void (*cb)(struct event_callback *, void *));
 int event_callback_finalize_many_(struct event_base *base, int n_cbs, struct event_callback **evcb, void (*cb)(struct event_callback *, void *));
 
 
+EVENT2_EXPORT_SYMBOL
 void event_active_later_(struct event *ev, int res);
 void event_active_later_nolock_(struct event *ev, int res);
-void event_callback_activate_later_nolock_(struct event_base *base,
+int event_callback_activate_later_nolock_(struct event_base *base,
     struct event_callback *evcb);
 int event_callback_cancel_nolock_(struct event_base *base,
     struct event_callback *evcb, int even_if_finalizing);
@@ -443,6 +448,7 @@ void event_callback_init_(struct event_base *base,
     struct event_callback *cb);
 
 /* FIXME document. */
+EVENT2_EXPORT_SYMBOL
 void event_base_add_virtual_(struct event_base *base);
 void event_base_del_virtual_(struct event_base *base);
 
@@ -452,6 +458,7 @@ void event_base_del_virtual_(struct event_base *base);
 
     Returns on success; aborts on failure.
 */
+EVENT2_EXPORT_SYMBOL
 void event_base_assert_ok_(struct event_base *base);
 void event_base_assert_ok_nolock_(struct event_base *base);
 
@@ -467,6 +474,13 @@ void event_base_assert_ok_nolock_(struct event_base *base);
 int event_base_foreach_event_nolock_(struct event_base *base,
     event_base_foreach_event_cb cb, void *arg);
 
+/* Cleanup function to reset debug mode during shutdown.
+ *
+ * Calling this function doesn't mean it'll be possible to re-enable
+ * debug mode if any events were added.
+ */
+void event_disable_debug_mode(void);
+
 #ifdef __cplusplus
 }
 #endif
index af4a6e05e677491bbb0421f4a19b766562d36b5d..7a42b73191477bfee4d55ee9114b9dd0a7a51650 100644 (file)
@@ -52,6 +52,9 @@
 #include <string.h>
 #include <time.h>
 #include <limits.h>
+#ifdef EVENT__HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
 
 #include "event2/event.h"
 #include "event2/event_struct.h"
@@ -123,6 +126,7 @@ static const struct eventop *eventops[] = {
 };
 
 /* Global state; deprecated */
+EVENT2_EXPORT_SYMBOL
 struct event_base *event_global_current_base_ = NULL;
 #define current_base event_global_current_base_
 
@@ -199,6 +203,22 @@ eq_debug_entry(const struct event_debug_entry *a,
 }
 
 int event_debug_mode_on_ = 0;
+
+
+#if !defined(EVENT__DISABLE_THREAD_SUPPORT) && !defined(EVENT__DISABLE_DEBUG_MODE)
+/**
+ * @brief debug mode variable which is set for any function/structure that needs
+ *        to be shared across threads (if thread support is enabled).
+ *
+ *        When and if evthreads are initialized, this variable will be evaluated,
+ *        and if set to something other than zero, this means the evthread setup 
+ *        functions were called out of order.
+ *
+ *        See: "Locks and threading" in the documentation.
+ */
+int event_debug_created_threadable_ctx_ = 0;
+#endif
+
 /* Set if it's too late to enable event_debug_mode. */
 static int event_debug_mode_too_late = 0;
 #ifndef EVENT__DISABLE_THREAD_SUPPORT
@@ -212,133 +232,169 @@ HT_PROTOTYPE(event_debug_map, event_debug_entry, node, hash_debug_entry,
 HT_GENERATE(event_debug_map, event_debug_entry, node, hash_debug_entry,
     eq_debug_entry, 0.5, mm_malloc, mm_realloc, mm_free)
 
-/* Macro: record that ev is now setup (that is, ready for an add) */
-#define event_debug_note_setup_(ev) do {                               \
-       if (event_debug_mode_on_) {                                     \
-               struct event_debug_entry *dent,find;                    \
-               find.ptr = (ev);                                        \
-               EVLOCK_LOCK(event_debug_map_lock_, 0);                  \
-               dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
-               if (dent) {                                             \
-                       dent->added = 0;                                \
-               } else {                                                \
-                       dent = mm_malloc(sizeof(*dent));                \
-                       if (!dent)                                      \
-                               event_err(1,                            \
-                                   "Out of memory in debugging code"); \
-                       dent->ptr = (ev);                               \
-                       dent->added = 0;                                \
-                       HT_INSERT(event_debug_map, &global_debug_map, dent); \
-               }                                                       \
-               EVLOCK_UNLOCK(event_debug_map_lock_, 0);                \
-       }                                                               \
-       event_debug_mode_too_late = 1;                                  \
-       } while (0)
-/* Macro: record that ev is no longer setup */
-#define event_debug_note_teardown_(ev) do {                            \
-       if (event_debug_mode_on_) {                                     \
-               struct event_debug_entry *dent,find;                    \
-               find.ptr = (ev);                                        \
-               EVLOCK_LOCK(event_debug_map_lock_, 0);                  \
-               dent = HT_REMOVE(event_debug_map, &global_debug_map, &find); \
-               if (dent)                                               \
-                       mm_free(dent);                                  \
-               EVLOCK_UNLOCK(event_debug_map_lock_, 0);                \
-       }                                                               \
-       event_debug_mode_too_late = 1;                                  \
-       } while (0)
+/* record that ev is now setup (that is, ready for an add) */
+static void event_debug_note_setup_(const struct event *ev)
+{
+       struct event_debug_entry *dent, find;
+
+       if (!event_debug_mode_on_)
+               goto out;
+
+       find.ptr = ev;
+       EVLOCK_LOCK(event_debug_map_lock_, 0);
+       dent = HT_FIND(event_debug_map, &global_debug_map, &find);
+       if (dent) {
+               dent->added = 0;
+       } else {
+               dent = mm_malloc(sizeof(*dent));
+               if (!dent)
+                       event_err(1,
+                           "Out of memory in debugging code");
+               dent->ptr = ev;
+               dent->added = 0;
+               HT_INSERT(event_debug_map, &global_debug_map, dent);
+       }
+       EVLOCK_UNLOCK(event_debug_map_lock_, 0);
+
+out:
+       event_debug_mode_too_late = 1;
+}
+/* record that ev is no longer setup */
+static void event_debug_note_teardown_(const struct event *ev)
+{
+       struct event_debug_entry *dent, find;
+
+       if (!event_debug_mode_on_)
+               goto out;
+
+       find.ptr = ev;
+       EVLOCK_LOCK(event_debug_map_lock_, 0);
+       dent = HT_REMOVE(event_debug_map, &global_debug_map, &find);
+       if (dent)
+               mm_free(dent);
+       EVLOCK_UNLOCK(event_debug_map_lock_, 0);
+
+out:
+       event_debug_mode_too_late = 1;
+}
 /* Macro: record that ev is now added */
-#define event_debug_note_add_(ev)      do {                            \
-       if (event_debug_mode_on_) {                                     \
-               struct event_debug_entry *dent,find;                    \
-               find.ptr = (ev);                                        \
-               EVLOCK_LOCK(event_debug_map_lock_, 0);                  \
-               dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
-               if (dent) {                                             \
-                       dent->added = 1;                                \
-               } else {                                                \
-                       event_errx(EVENT_ERR_ABORT_,                    \
-                           "%s: noting an add on a non-setup event %p" \
-                           " (events: 0x%x, fd: "EV_SOCK_FMT           \
-                           ", flags: 0x%x)",                           \
-                           __func__, (ev), (ev)->ev_events,            \
-                           EV_SOCK_ARG((ev)->ev_fd), (ev)->ev_flags);  \
-               }                                                       \
-               EVLOCK_UNLOCK(event_debug_map_lock_, 0);                \
-       }                                                               \
-       event_debug_mode_too_late = 1;                                  \
-       } while (0)
-/* Macro: record that ev is no longer added */
-#define event_debug_note_del_(ev) do {                                 \
-       if (event_debug_mode_on_) {                                     \
-               struct event_debug_entry *dent,find;                    \
-               find.ptr = (ev);                                        \
-               EVLOCK_LOCK(event_debug_map_lock_, 0);                  \
-               dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
-               if (dent) {                                             \
-                       dent->added = 0;                                \
-               } else {                                                \
-                       event_errx(EVENT_ERR_ABORT_,                    \
-                           "%s: noting a del on a non-setup event %p"  \
-                           " (events: 0x%x, fd: "EV_SOCK_FMT           \
-                           ", flags: 0x%x)",                           \
-                           __func__, (ev), (ev)->ev_events,            \
-                           EV_SOCK_ARG((ev)->ev_fd), (ev)->ev_flags);  \
-               }                                                       \
-               EVLOCK_UNLOCK(event_debug_map_lock_, 0);                \
-       }                                                               \
-       event_debug_mode_too_late = 1;                                  \
-       } while (0)
-/* Macro: assert that ev is setup (i.e., okay to add or inspect) */
-#define event_debug_assert_is_setup_(ev) do {                          \
-       if (event_debug_mode_on_) {                                     \
-               struct event_debug_entry *dent,find;                    \
-               find.ptr = (ev);                                        \
-               EVLOCK_LOCK(event_debug_map_lock_, 0);                  \
-               dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
-               if (!dent) {                                            \
-                       event_errx(EVENT_ERR_ABORT_,                    \
-                           "%s called on a non-initialized event %p"   \
-                           " (events: 0x%x, fd: "EV_SOCK_FMT\
-                           ", flags: 0x%x)",                           \
-                           __func__, (ev), (ev)->ev_events,            \
-                           EV_SOCK_ARG((ev)->ev_fd), (ev)->ev_flags);  \
-               }                                                       \
-               EVLOCK_UNLOCK(event_debug_map_lock_, 0);                \
-       }                                                               \
-       } while (0)
-/* Macro: assert that ev is not added (i.e., okay to tear down or set
- * up again) */
-#define event_debug_assert_not_added_(ev) do {                         \
-       if (event_debug_mode_on_) {                                     \
-               struct event_debug_entry *dent,find;                    \
-               find.ptr = (ev);                                        \
-               EVLOCK_LOCK(event_debug_map_lock_, 0);                  \
-               dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
-               if (dent && dent->added) {                              \
-                       event_errx(EVENT_ERR_ABORT_,                    \
-                           "%s called on an already added event %p"    \
-                           " (events: 0x%x, fd: "EV_SOCK_FMT", "       \
-                           "flags: 0x%x)",                             \
-                           __func__, (ev), (ev)->ev_events,            \
-                           EV_SOCK_ARG((ev)->ev_fd), (ev)->ev_flags);  \
-               }                                                       \
-               EVLOCK_UNLOCK(event_debug_map_lock_, 0);                \
-       }                                                               \
-       } while (0)
+static void event_debug_note_add_(const struct event *ev)
+{
+       struct event_debug_entry *dent,find;
+
+       if (!event_debug_mode_on_)
+               goto out;
+
+       find.ptr = ev;
+       EVLOCK_LOCK(event_debug_map_lock_, 0);
+       dent = HT_FIND(event_debug_map, &global_debug_map, &find);
+       if (dent) {
+               dent->added = 1;
+       } else {
+               event_errx(EVENT_ERR_ABORT_,
+                   "%s: noting an add on a non-setup event %p"
+                   " (events: 0x%x, fd: "EV_SOCK_FMT
+                   ", flags: 0x%x)",
+                   __func__, ev, ev->ev_events,
+                   EV_SOCK_ARG(ev->ev_fd), ev->ev_flags);
+       }
+       EVLOCK_UNLOCK(event_debug_map_lock_, 0);
+
+out:
+       event_debug_mode_too_late = 1;
+}
+/* record that ev is no longer added */
+static void event_debug_note_del_(const struct event *ev)
+{
+       struct event_debug_entry *dent, find;
+
+       if (!event_debug_mode_on_)
+               goto out;
+
+       find.ptr = ev;
+       EVLOCK_LOCK(event_debug_map_lock_, 0);
+       dent = HT_FIND(event_debug_map, &global_debug_map, &find);
+       if (dent) {
+               dent->added = 0;
+       } else {
+               event_errx(EVENT_ERR_ABORT_,
+                   "%s: noting a del on a non-setup event %p"
+                   " (events: 0x%x, fd: "EV_SOCK_FMT
+                   ", flags: 0x%x)",
+                   __func__, ev, ev->ev_events,
+                   EV_SOCK_ARG(ev->ev_fd), ev->ev_flags);
+       }
+       EVLOCK_UNLOCK(event_debug_map_lock_, 0);
+
+out:
+       event_debug_mode_too_late = 1;
+}
+/* assert that ev is setup (i.e., okay to add or inspect) */
+static void event_debug_assert_is_setup_(const struct event *ev)
+{
+       struct event_debug_entry *dent, find;
+
+       if (!event_debug_mode_on_)
+               return;
+
+       find.ptr = ev;
+       EVLOCK_LOCK(event_debug_map_lock_, 0);
+       dent = HT_FIND(event_debug_map, &global_debug_map, &find);
+       if (!dent) {
+               event_errx(EVENT_ERR_ABORT_,
+                   "%s called on a non-initialized event %p"
+                   " (events: 0x%x, fd: "EV_SOCK_FMT
+                   ", flags: 0x%x)",
+                   __func__, ev, ev->ev_events,
+                   EV_SOCK_ARG(ev->ev_fd), ev->ev_flags);
+       }
+       EVLOCK_UNLOCK(event_debug_map_lock_, 0);
+}
+/* assert that ev is not added (i.e., okay to tear down or set up again) */
+static void event_debug_assert_not_added_(const struct event *ev)
+{
+       struct event_debug_entry *dent, find;
+
+       if (!event_debug_mode_on_)
+               return;
+
+       find.ptr = ev;
+       EVLOCK_LOCK(event_debug_map_lock_, 0);
+       dent = HT_FIND(event_debug_map, &global_debug_map, &find);
+       if (dent && dent->added) {
+               event_errx(EVENT_ERR_ABORT_,
+                   "%s called on an already added event %p"
+                   " (events: 0x%x, fd: "EV_SOCK_FMT", "
+                   "flags: 0x%x)",
+                   __func__, ev, ev->ev_events,
+                   EV_SOCK_ARG(ev->ev_fd), ev->ev_flags);
+       }
+       EVLOCK_UNLOCK(event_debug_map_lock_, 0);
+}
+static void event_debug_assert_socket_nonblocking_(evutil_socket_t fd)
+{
+       if (!event_debug_mode_on_)
+               return;
+       if (fd < 0)
+               return;
+
+#ifndef _WIN32
+       {
+               int flags;
+               if ((flags = fcntl(fd, F_GETFL, NULL)) >= 0) {
+                       EVUTIL_ASSERT(flags & O_NONBLOCK);
+               }
+       }
+#endif
+}
 #else
-#define event_debug_note_setup_(ev) \
-       ((void)0)
-#define event_debug_note_teardown_(ev) \
-       ((void)0)
-#define event_debug_note_add_(ev) \
-       ((void)0)
-#define event_debug_note_del_(ev) \
-       ((void)0)
-#define event_debug_assert_is_setup_(ev) \
-       ((void)0)
-#define event_debug_assert_not_added_(ev) \
-       ((void)0)
+static void event_debug_note_setup_(const struct event *ev) { (void)ev; }
+static void event_debug_note_teardown_(const struct event *ev) { (void)ev; }
+static void event_debug_note_add_(const struct event *ev) { (void)ev; }
+static void event_debug_note_del_(const struct event *ev) { (void)ev; }
+static void event_debug_assert_is_setup_(const struct event *ev) { (void)ev; }
+static void event_debug_assert_not_added_(const struct event *ev) { (void)ev; }
+static void event_debug_assert_socket_nonblocking_(evutil_socket_t fd) { (void)fd; }
 #endif
 
 #define EVENT_BASE_ASSERT_LOCKED(base)         \
@@ -574,7 +630,9 @@ event_base_new_with_config(const struct event_config *cfg)
                int flags;
                if (should_check_environment && !precise_time) {
                        precise_time = evutil_getenv_("EVENT_PRECISE_TIMER") != NULL;
-                       base->flags |= EVENT_BASE_FLAG_PRECISE_TIMER;
+                       if (precise_time) {
+                               base->flags |= EVENT_BASE_FLAG_PRECISE_TIMER;
+                       }
                }
                flags = precise_time ? EV_MONOT_PRECISE : 0;
                evutil_configure_monotonic_time_(&base->monotonic_timer, flags);
@@ -655,6 +713,10 @@ event_base_new_with_config(const struct event_config *cfg)
 
        /* prepare for threading */
 
+#if !defined(EVENT__DISABLE_THREAD_SUPPORT) && !defined(EVENT__DISABLE_DEBUG_MODE)
+       event_debug_created_threadable_ctx_ = 1;
+#endif
+
 #ifndef EVENT__DISABLE_THREAD_SUPPORT
        if (EVTHREAD_LOCKING_ENABLED() &&
            (!cfg || !(cfg->flags & EVENT_BASE_FLAG_NOLOCK))) {
@@ -749,6 +811,29 @@ event_base_cancel_single_callback_(struct event_base *base,
        return result;
 }
 
+static int event_base_free_queues_(struct event_base *base, int run_finalizers)
+{
+       int deleted = 0, i;
+
+       for (i = 0; i < base->nactivequeues; ++i) {
+               struct event_callback *evcb, *next;
+               for (evcb = TAILQ_FIRST(&base->activequeues[i]); evcb; ) {
+                       next = TAILQ_NEXT(evcb, evcb_active_next);
+                       deleted += event_base_cancel_single_callback_(base, evcb, run_finalizers);
+                       evcb = next;
+               }
+       }
+
+       {
+               struct event_callback *evcb;
+               while ((evcb = TAILQ_FIRST(&base->active_later_queue))) {
+                       deleted += event_base_cancel_single_callback_(base, evcb, run_finalizers);
+               }
+       }
+
+       return deleted;
+}
+
 static void
 event_base_free_(struct event_base *base, int run_finalizers)
 {
@@ -809,22 +894,23 @@ event_base_free_(struct event_base *base, int run_finalizers)
        if (base->common_timeout_queues)
                mm_free(base->common_timeout_queues);
 
-       for (i = 0; i < base->nactivequeues; ++i) {
-               struct event_callback *evcb, *next;
-               for (evcb = TAILQ_FIRST(&base->activequeues[i]); evcb; ) {
-                       next = TAILQ_NEXT(evcb, evcb_active_next);
-                       n_deleted += event_base_cancel_single_callback_(base, evcb, run_finalizers);
-                       evcb = next;
-               }
-       }
-       {
-               struct event_callback *evcb;
-               while ((evcb = TAILQ_FIRST(&base->active_later_queue))) {
-                       n_deleted += event_base_cancel_single_callback_(base, evcb, run_finalizers);
+       for (;;) {
+               /* For finalizers we can register yet another finalizer out from
+                * finalizer, and iff finalizer will be in active_later_queue we can
+                * add finalizer to activequeues, and we will have events in
+                * activequeues after this function returns, which is not what we want
+                * (we even have an assertion for this).
+                *
+                * A simple case is bufferevent with underlying (i.e. filters).
+                */
+               int i = event_base_free_queues_(base, run_finalizers);
+               event_debug(("%s: %d events freed", __func__, i));
+               if (!i) {
+                       break;
                }
+               n_deleted += i;
        }
 
-
        if (n_deleted)
                event_debug(("%s: %d events were still set in base",
                        __func__, n_deleted));
@@ -926,13 +1012,13 @@ event_reinit(struct event_base *base)
                event_del_nolock_(&base->sig.ev_signal, EVENT_DEL_AUTOBLOCK);
                event_debug_unassign(&base->sig.ev_signal);
                memset(&base->sig.ev_signal, 0, sizeof(base->sig.ev_signal));
-               if (base->sig.ev_signal_pair[0] != -1)
-                       EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]);
-               if (base->sig.ev_signal_pair[1] != -1)
-                       EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[1]);
                had_signal_added = 1;
                base->sig.ev_signal_added = 0;
        }
+       if (base->sig.ev_signal_pair[0] != -1)
+               EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]);
+       if (base->sig.ev_signal_pair[1] != -1)
+               EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[1]);
        if (base->th_notify_fn != NULL) {
                was_notifiable = 1;
                base->th_notify_fn = NULL;
@@ -981,8 +1067,12 @@ event_reinit(struct event_base *base)
                if (evmap_reinit_(base) < 0)
                        res = -1;
        } else {
-               if (had_signal_added)
-                       res = evsig_init_(base);
+               res = evsig_init_(base);
+               if (res == 0 && had_signal_added) {
+                       res = event_add_nolock_(&base->sig.ev_signal, NULL, 0);
+                       if (res == 0)
+                               base->sig.ev_signal_added = 1;
+               }
        }
 
        /* If we were notifiable before, and nothing just exploded, become
@@ -1593,10 +1683,12 @@ event_process_active_single_queue(struct event_base *base,
                        break;
                case EV_CLOSURE_EVENT: {
                        void (*evcb_callback)(evutil_socket_t, short, void *);
+                       short res;
                        EVUTIL_ASSERT(ev != NULL);
                        evcb_callback = *ev->ev_callback;
+                       res = ev->ev_res;
                        EVBASE_RELEASE_LOCK(base, th_base_lock);
-                       evcb_callback(ev->ev_fd, ev->ev_res, ev->ev_arg);
+                       evcb_callback(ev->ev_fd, res, ev->ev_arg);
                }
                break;
                case EV_CLOSURE_CB_SELF: {
@@ -1614,8 +1706,8 @@ event_process_active_single_queue(struct event_base *base,
                        evcb_evfinalize = ev->ev_evcallback.evcb_cb_union.evcb_evfinalize;
                        EVUTIL_ASSERT((evcb->evcb_flags & EVLIST_FINALIZING));
                        EVBASE_RELEASE_LOCK(base, th_base_lock);
-                       evcb_evfinalize(ev, ev->ev_arg);
                        event_debug_note_teardown_(ev);
+                       evcb_evfinalize(ev, ev->ev_arg);
                        if (evcb_closure == EV_CLOSURE_EVENT_FINALIZE_FREE)
                                mm_free(ev);
                }
@@ -1964,6 +2056,9 @@ event_base_once(struct event_base *base, evutil_socket_t fd, short events,
        int res = 0;
        int activate = 0;
 
+       if (!base)
+               return (-1);
+
        /* We cannot support signals that just fire once, or persistent
         * events. */
        if (events & (EV_SIGNAL|EV_PERSIST))
@@ -2022,6 +2117,8 @@ event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, shor
        if (arg == &event_self_cbarg_ptr_)
                arg = ev;
 
+       if (!(events & EV_SIGNAL))
+               event_debug_assert_socket_nonblocking_(fd);
        event_debug_assert_not_added_(ev);
 
        ev->ev_base = base;
@@ -2672,17 +2769,16 @@ static int
 event_del_(struct event *ev, int blocking)
 {
        int res;
+       struct event_base *base = ev->ev_base;
 
-       if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
+       if (EVUTIL_FAILURE_CHECK(!base)) {
                event_warnx("%s: event has no event_base set.", __func__);
                return -1;
        }
 
-       EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
-
+       EVBASE_ACQUIRE_LOCK(base, th_base_lock);
        res = event_del_nolock_(ev, blocking);
-
-       EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
+       EVBASE_RELEASE_LOCK(base, th_base_lock);
 
        return (res);
 }
@@ -2732,21 +2828,7 @@ event_del_nolock_(struct event *ev, int blocking)
                }
        }
 
-       /* If the main thread is currently executing this event's callback,
-        * and we are not the main thread, then we want to wait until the
-        * callback is done before we start removing the event.  That way,
-        * when this function returns, it will be safe to free the
-        * user-supplied argument. */
        base = ev->ev_base;
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
-       if (blocking != EVENT_DEL_NOBLOCK &&
-           base->current_event == event_to_event_callback(ev) &&
-           !EVBASE_IN_THREAD(base) &&
-           (blocking == EVENT_DEL_BLOCK || !(ev->ev_events & EV_FINALIZE))) {
-               ++base->current_event_waiters;
-               EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
-       }
-#endif
 
        EVUTIL_ASSERT(!(ev->ev_flags & ~EVLIST_ALL));
 
@@ -2785,6 +2867,10 @@ event_del_nolock_(struct event *ev, int blocking)
                        notify = 1;
                        res = 0;
                }
+               /* If we do not have events, let's notify event base so it can
+                * exit without waiting */
+               if (!event_haveevents(base) && !N_ACTIVE_CALLBACKS(base))
+                       notify = 1;
        }
 
        /* if we are not in the right thread, we need to wake up the loop */
@@ -2793,6 +2879,21 @@ event_del_nolock_(struct event *ev, int blocking)
 
        event_debug_note_del_(ev);
 
+       /* If the main thread is currently executing this event's callback,
+        * and we are not the main thread, then we want to wait until the
+        * callback is done before returning. That way, when this function
+        * returns, it will be safe to free the user-supplied argument.
+        */
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+       if (blocking != EVENT_DEL_NOBLOCK &&
+           base->current_event == event_to_event_callback(ev) &&
+           !EVBASE_IN_THREAD(base) &&
+           (blocking == EVENT_DEL_BLOCK || !(ev->ev_events & EV_FINALIZE))) {
+               ++base->current_event_waiters;
+               EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
+       }
+#endif
+
        return (res);
 }
 
@@ -2913,6 +3014,7 @@ event_callback_activate_nolock_(struct event_base *base,
        switch (evcb->evcb_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER)) {
        default:
                EVUTIL_ASSERT(0);
+               EVUTIL_FALLTHROUGH;
        case EVLIST_ACTIVE_LATER:
                event_queue_remove_active_later(base, evcb);
                r = 0;
@@ -2931,16 +3033,17 @@ event_callback_activate_nolock_(struct event_base *base,
        return r;
 }
 
-void
+int
 event_callback_activate_later_nolock_(struct event_base *base,
     struct event_callback *evcb)
 {
        if (evcb->evcb_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))
-               return;
+               return 0;
 
        event_queue_insert_active_later(base, evcb);
        if (EVBASE_NEED_NOTIFY(base))
                evthread_notify_base(base);
+       return 1;
 }
 
 void
@@ -3025,10 +3128,12 @@ event_deferred_cb_schedule_(struct event_base *base, struct event_callback *cb)
                base = current_base;
        EVBASE_ACQUIRE_LOCK(base, th_base_lock);
        if (base->n_deferreds_queued > MAX_DEFERREDS_QUEUED) {
-               event_callback_activate_later_nolock_(base, cb);
+               r = event_callback_activate_later_nolock_(base, cb);
        } else {
-               ++base->n_deferreds_queued;
                r = event_callback_activate_nolock_(base, cb);
+               if (r) {
+                       ++base->n_deferreds_queued;
+               }
        }
        EVBASE_RELEASE_LOCK(base, th_base_lock);
        return r;
@@ -3098,10 +3203,6 @@ 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
@@ -3109,13 +3210,13 @@ timeout_process(struct event_base *base)
 #define MAX_EVENT_COUNT(var, v) var = MAX(var, v)
 
 /* These are a fancy way to spell
-     if (flags & EVLIST_INTERNAL)
+     if (~flags & EVLIST_INTERNAL)
          base->event_count--/++;
 */
 #define DECR_EVENT_COUNT(base,flags) \
-       ((base)->event_count -= (~((flags) >> 4) & 1))
+       ((base)->event_count -= !((flags) & EVLIST_INTERNAL))
 #define INCR_EVENT_COUNT(base,flags) do {                                      \
-       ((base)->event_count += (~((flags) >> 4) & 1));                         \
+       ((base)->event_count += !((flags) & EVLIST_INTERNAL));                  \
        MAX_EVENT_COUNT((base)->event_count_max, (base)->event_count);          \
 } while (0)
 
@@ -3647,13 +3748,14 @@ 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%s",
+       fprintf(output, "  %p [%s "EV_SOCK_FMT"]%s%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_events&EV_ET)?" ET":"",
            (e->ev_flags&EVLIST_INTERNAL)?" Internal":"");
        if (e->ev_flags & EVLIST_TIMEOUT) {
                struct timeval tv;
@@ -3724,7 +3826,35 @@ 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));
+
+       /* Activate any non timer events */
+       if (!(events & EV_TIMEOUT)) {
+               evmap_io_active_(base, fd, events & (EV_READ|EV_WRITE|EV_CLOSED));
+       } else {
+               /* If we want to activate timer events, loop and activate each event with
+                * the same fd in both the timeheap and common timeouts list */
+               int i;
+               unsigned u;
+               struct event *ev;
+
+               for (u = 0; u < base->timeheap.n; ++u) {
+                       ev = base->timeheap.p[u];
+                       if (ev->ev_fd == fd) {
+                               event_active_nolock_(ev, EV_TIMEOUT, 1);
+                       }
+               }
+
+               for (i = 0; i < base->n_common_timeouts; ++i) {
+                       struct common_timeout_list *ctl = base->common_timeout_queues[i];
+                       TAILQ_FOREACH(ev, &ctl->events,
+                               ev_timeout_pos.ev_next_with_common_timeout) {
+                               if (ev->ev_fd == fd) {
+                                       event_active_nolock_(ev, EV_TIMEOUT, 1);
+                               }
+                       }
+               }
+       }
+
        EVBASE_RELEASE_LOCK(base, th_base_lock);
 }
 
index a9902fbc426ee59853506d5513671edafe70c18e..6b2a2e15ef864fd75f50f29d4020e70ab7377de5 100644 (file)
@@ -151,7 +151,7 @@ init_extension_functions(struct win32_extension_fns *ext)
        const GUID connectex = WSAID_CONNECTEX;
        const GUID getacceptexsockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
        SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
-       if (s == INVALID_SOCKET)
+       if (s == EVUTIL_INVALID_SOCKET)
                return;
        ext->AcceptEx = get_extension_function(s, &acceptex);
        ext->ConnectEx = get_extension_function(s, &connectex);
index c5375656969e38f2fab5e884bc4e85132c6dafc6..0bae3b0fe662ad934a8c968c78c52e6cffd0eafc 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python
 #
 # Copyright (c) 2005-2007 Niels Provos <provos@citi.umich.edu>
 # Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
@@ -6,65 +6,79 @@
 #
 # Generates marshaling code based on libevent.
 
+# pylint: disable=too-many-lines
+# pylint: disable=too-many-branches
+# pylint: disable=too-many-public-methods
+# pylint: disable=too-many-statements
+# pylint: disable=global-statement
+
 # TODO:
-# 1) use optparse to allow the strategy shell to parse options, and
-#    to allow the instantiated factory (for the specific output language)
-#    to parse remaining options
-# 2) move the globals into a class that manages execution (including the
-#    progress outputs that space stderr at the moment)
-# 3) emit other languages
+# 1) propagate the arguments/options parsed by argparse down to the
+#    instantiated factory objects.
+# 2) move the globals into a class that manages execution, including the
+#    progress outputs that go to stderr at the moment.
+# 3) emit other languages.
 
-import sys
+import argparse
 import re
+import sys
 
 _NAME = "event_rpcgen.py"
 _VERSION = "0.1"
 
 # Globals
-line_count = 0
+LINE_COUNT = 0
 
-white = re.compile(r'\s+')
-cppcomment = re.compile(r'\/\/.*$')
-nonident = re.compile(r'[^a-zA-Z0-9_]')
-structref = re.compile(r'^struct\[([a-zA-Z_][a-zA-Z0-9_]*)\]$')
-structdef = re.compile(r'^struct +[a-zA-Z_][a-zA-Z0-9_]* *{$')
+CPPCOMMENT_RE = re.compile(r"\/\/.*$")
+NONIDENT_RE = re.compile(r"\W")
+PREPROCESSOR_DEF_RE = re.compile(r"^#define")
+STRUCT_REF_RE = re.compile(r"^struct\[(?P<name>[a-zA-Z_][a-zA-Z0-9_]*)\]$")
+STRUCT_DEF_RE = re.compile(r"^struct +[a-zA-Z_][a-zA-Z0-9_]* *{$")
+WHITESPACE_RE = re.compile(r"\s+")
 
-headerdirect = []
-cppdirect = []
+HEADER_DIRECT = []
+CPP_DIRECT = []
+
+QUIETLY = False
 
-QUIETLY = 0
 
 def declare(s):
     if not QUIETLY:
-        print s
+        print(s)
+
 
 def TranslateList(mylist, mydict):
-    return map(lambda x: x % mydict, mylist)
+    return [x % mydict for x in mylist]
+
 
-# Exception class for parse errors
 class RpcGenError(Exception):
-        def __init__(self, why):
-                self.why = why
-        def __str__(self):
-                return str(self.why)
+    """An Exception class for parse errors."""
+
+    def __init__(self, why): # pylint: disable=super-init-not-called
+        self.why = why
+
+    def __str__(self):
+        return str(self.why)
+
 
 # Holds everything that makes a struct
-class Struct:
+class Struct(object):
     def __init__(self, name):
         self._name = name
         self._entries = []
         self._tags = {}
-        declare('  Created struct: %s' % name)
+        declare("  Created struct: %s" % name)
 
     def AddEntry(self, entry):
-        if self._tags.has_key(entry.Tag()):
+        if entry.Tag() in self._tags:
             raise RpcGenError(
                 'Entry "%s" duplicates tag number %d from "%s" '
-                'around line %d' % (entry.Name(), entry.Tag(),
-                                    self._tags[entry.Tag()], line_count))
+                "around line %d"
+                % (entry.Name(), entry.Tag(), self._tags[entry.Tag()], LINE_COUNT)
+            )
         self._entries.append(entry)
         self._tags[entry.Tag()] = entry.Name()
-        declare('    Added entry: %s' % entry.Name())
+        declare("    Added entry: %s" % entry.Name())
 
     def Name(self):
         return self._name
@@ -75,10 +89,12 @@ class Struct:
         name = "%s_%s" % (self._name, entry.Name())
         return name.upper()
 
-    def PrintIndented(self, file, ident, code):
+    @staticmethod
+    def PrintIndented(filep, ident, code):
         """Takes an array, add indentation to each entry and prints it."""
         for entry in code:
-            print >>file, '%s%s' % (ident, entry)
+            filep.write("%s%s\n" % (ident, entry))
+
 
 class StructCCode(Struct):
     """ Knows how to generate C code for a struct """
@@ -86,44 +102,41 @@ class StructCCode(Struct):
     def __init__(self, name):
         Struct.__init__(self, name)
 
-    def PrintTags(self, file):
+    def PrintTags(self, filep):
         """Prints the tag definitions for a structure."""
-        print >>file, '/* Tag definition for %s */' % self._name
-        print >>file, 'enum %s_ {' % self._name.lower()
+        filep.write("/* Tag definition for %s */\n" % self._name)
+        filep.write("enum %s_ {\n" % self._name.lower())
         for entry in self._entries:
-            print >>file, '  %s=%d,' % (self.EntryTagName(entry),
-                                        entry.Tag())
-        print >>file, '  %s_MAX_TAGS' % (self._name.upper())
-        print >>file, '};\n'
+            filep.write("  %s=%d,\n" % (self.EntryTagName(entry), entry.Tag()))
+        filep.write("  %s_MAX_TAGS\n" % (self._name.upper()))
+        filep.write("};\n\n")
 
-    def PrintForwardDeclaration(self, file):
-        print >>file, 'struct %s;' % self._name
+    def PrintForwardDeclaration(self, filep):
+        filep.write("struct %s;\n" % self._name)
 
-    def PrintDeclaration(self, file):
-        print >>file, '/* Structure declaration for %s */' % self._name
-        print >>file, 'struct %s_access_ {' % self._name
+    def PrintDeclaration(self, filep):
+        filep.write("/* Structure declaration for %s */\n" % self._name)
+        filep.write("struct %s_access_ {\n" % self._name)
         for entry in self._entries:
-            dcl = entry.AssignDeclaration('(*%s_assign)' % entry.Name())
-            dcl.extend(
-                entry.GetDeclaration('(*%s_get)' % entry.Name()))
+            dcl = entry.AssignDeclaration("(*%s_assign)" % entry.Name())
+            dcl.extend(entry.GetDeclaration("(*%s_get)" % entry.Name()))
             if entry.Array():
-                dcl.extend(
-                    entry.AddDeclaration('(*%s_add)' % entry.Name()))
-            self.PrintIndented(file, '  ', dcl)
-        print >>file, '};\n'
+                dcl.extend(entry.AddDeclaration("(*%s_add)" % entry.Name()))
+            self.PrintIndented(filep, "  ", dcl)
+        filep.write("};\n\n")
 
-        print >>file, 'struct %s {' % self._name
-        print >>file, '  struct %s_access_ *base;\n' % self._name
+        filep.write("struct %s {\n" % self._name)
+        filep.write("  struct %s_access_ *base;\n\n" % self._name)
         for entry in self._entries:
             dcl = entry.Declaration()
-            self.PrintIndented(file, '  ', dcl)
-        print >>file, ''
+            self.PrintIndented(filep, "  ", dcl)
+        filep.write("\n")
         for entry in self._entries:
-            print >>file, '  ev_uint8_t %s_set;' % entry.Name()
-        print >>file, '};\n'
+            filep.write("  ev_uint8_t %s_set;\n" % entry.Name())
+        filep.write("};\n\n")
 
-        print >>file, \
-"""struct %(name)s *%(name)s_new(void);
+        filep.write(
+            """struct %(name)s *%(name)s_new(void);
 struct %(name)s *%(name)s_new_with_arg(void *);
 void %(name)s_free(struct %(name)s *);
 void %(name)s_clear(struct %(name)s *);
@@ -133,227 +146,291 @@ int %(name)s_complete(struct %(name)s *);
 void evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t,
     const struct %(name)s *);
 int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
-    struct %(name)s *);""" % { 'name' : self._name }
-
+    struct %(name)s *);\n"""
+            % {"name": self._name}
+        )
 
         # Write a setting function of every variable
         for entry in self._entries:
-            self.PrintIndented(file, '', entry.AssignDeclaration(
-                entry.AssignFuncName()))
-            self.PrintIndented(file, '', entry.GetDeclaration(
-                entry.GetFuncName()))
+            self.PrintIndented(
+                filep, "", entry.AssignDeclaration(entry.AssignFuncName())
+            )
+            self.PrintIndented(filep, "", entry.GetDeclaration(entry.GetFuncName()))
             if entry.Array():
-                self.PrintIndented(file, '', entry.AddDeclaration(
-                    entry.AddFuncName()))
+                self.PrintIndented(filep, "", entry.AddDeclaration(entry.AddFuncName()))
 
-        print >>file, '/* --- %s done --- */\n' % self._name
+        filep.write("/* --- %s done --- */\n\n" % self._name)
 
-    def PrintCode(self, file):
-        print >>file, ('/*\n'
-                       ' * Implementation of %s\n'
-                       ' */\n') % self._name
+    def PrintCode(self, filep):
+        filep.write(
+            """/*
+ * Implementation of %s
+ */
+"""
+            % (self._name)
+        )
 
-        print >>file, \
-              'static struct %(name)s_access_ %(name)s_base__ = {' % \
-              { 'name' : self._name }
+        filep.write(
+            """
+static struct %(name)s_access_ %(name)s_base__ = {
+"""
+            % {"name": self._name}
+        )
         for entry in self._entries:
-            self.PrintIndented(file, '  ', entry.CodeBase())
-        print >>file, '};\n'
+            self.PrintIndented(filep, "  ", entry.CodeBase())
+        filep.write("};\n\n")
 
         # Creation
-        print >>file, (
-            'struct %(name)s *\n'
-            '%(name)s_new(void)\n'
-            '{\n'
-            '  return %(name)s_new_with_arg(NULL);\n'
-            '}\n'
-            '\n'
-            'struct %(name)s *\n'
-            '%(name)s_new_with_arg(void *unused)\n'
-            '{\n'
-            '  struct %(name)s *tmp;\n'
-            '  if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) {\n'
-            '    event_warn("%%s: malloc", __func__);\n'
-            '    return (NULL);\n'
-            '  }\n'
-            '  tmp->base = &%(name)s_base__;\n') % { 'name' : self._name }
+        filep.write(
+            """struct %(name)s *
+%(name)s_new(void)
+{
+  return %(name)s_new_with_arg(NULL);
+}
+
+struct %(name)s *
+%(name)s_new_with_arg(void *unused)
+{
+  struct %(name)s *tmp;
+  if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) {
+    event_warn("%%s: malloc", __func__);
+    return (NULL);
+  }
+  tmp->base = &%(name)s_base__;
+
+"""
+            % {"name": self._name}
+        )
 
         for entry in self._entries:
-            self.PrintIndented(file, '  ', entry.CodeInitialize('tmp'))
-            print >>file, '  tmp->%s_set = 0;\n' % entry.Name()
+            self.PrintIndented(filep, "  ", entry.CodeInitialize("tmp"))
+            filep.write("  tmp->%s_set = 0;\n\n" % entry.Name())
+
+        filep.write(
+            """  return (tmp);
+}
 
-        print >>file, (
-            '  return (tmp);\n'
-            '}\n')
+"""
+        )
 
         # Adding
         for entry in self._entries:
             if entry.Array():
-                self.PrintIndented(file, '', entry.CodeAdd())
-            print >>file, ''
+                self.PrintIndented(filep, "", entry.CodeAdd())
+            filep.write("\n")
 
         # Assigning
         for entry in self._entries:
-            self.PrintIndented(file, '', entry.CodeAssign())
-            print >>file, ''
+            self.PrintIndented(filep, "", entry.CodeAssign())
+            filep.write("\n")
 
         # Getting
         for entry in self._entries:
-            self.PrintIndented(file, '', entry.CodeGet())
-            print >>file, ''
+            self.PrintIndented(filep, "", entry.CodeGet())
+            filep.write("\n")
 
         # Clearing
-        print >>file, ( 'void\n'
-                        '%(name)s_clear(struct %(name)s *tmp)\n'
-                        '{'
-                        ) % { 'name' : self._name }
+        filep.write(
+            """void
+%(name)s_clear(struct %(name)s *tmp)
+{
+"""
+            % {"name": self._name}
+        )
         for entry in self._entries:
-            self.PrintIndented(file, '  ', entry.CodeClear('tmp'))
+            self.PrintIndented(filep, "  ", entry.CodeClear("tmp"))
 
-        print >>file, '}\n'
+        filep.write("}\n\n")
 
         # Freeing
-        print >>file, ( 'void\n'
-                        '%(name)s_free(struct %(name)s *tmp)\n'
-                        '{'
-                        ) % { 'name' : self._name }
+        filep.write(
+            """void
+%(name)s_free(struct %(name)s *tmp)
+{
+"""
+            % {"name": self._name}
+        )
 
         for entry in self._entries:
-            self.PrintIndented(file, '  ', entry.CodeFree('tmp'))
+            self.PrintIndented(filep, "  ", entry.CodeFree("tmp"))
+
+        filep.write(
+            """  free(tmp);
+}
 
-        print >>file, ('  free(tmp);\n'
-                       '}\n')
+"""
+        )
 
         # Marshaling
-        print >>file, ('void\n'
-                       '%(name)s_marshal(struct evbuffer *evbuf, '
-                       'const struct %(name)s *tmp)'
-                       '{') % { 'name' : self._name }
+        filep.write(
+            """void
+%(name)s_marshal(struct evbuffer *evbuf, const struct %(name)s *tmp) {
+"""
+            % {"name": self._name}
+        )
         for entry in self._entries:
-            indent = '  '
+            indent = "  "
             # Optional entries do not have to be set
             if entry.Optional():
-                indent += '  '
-                print >>file, '  if (tmp->%s_set) {' % entry.Name()
+                indent += "  "
+                filep.write("  if (tmp->%s_set) {\n" % entry.Name())
             self.PrintIndented(
-                file, indent,
-                entry.CodeMarshal('evbuf', self.EntryTagName(entry),
-                                  entry.GetVarName('tmp'),
-                                  entry.GetVarLen('tmp')))
+                filep,
+                indent,
+                entry.CodeMarshal(
+                    "evbuf",
+                    self.EntryTagName(entry),
+                    entry.GetVarName("tmp"),
+                    entry.GetVarLen("tmp"),
+                ),
+            )
             if entry.Optional():
-                print >>file, '  }'
+                filep.write("  }\n")
 
-        print >>file, '}\n'
+        filep.write("}\n\n")
 
         # Unmarshaling
-        print >>file, ('int\n'
-                       '%(name)s_unmarshal(struct %(name)s *tmp, '
-                       ' struct evbuffer *evbuf)\n'
-                       '{\n'
-                       '  ev_uint32_t tag;\n'
-                       '  while (evbuffer_get_length(evbuf) > 0) {\n'
-                       '    if (evtag_peek(evbuf, &tag) == -1)\n'
-                       '      return (-1);\n'
-                       '    switch (tag) {\n'
-                       ) % { 'name' : self._name }
+        filep.write(
+            """int
+%(name)s_unmarshal(struct %(name)s *tmp, struct evbuffer *evbuf)
+{
+  ev_uint32_t tag;
+  while (evbuffer_get_length(evbuf) > 0) {
+    if (evtag_peek(evbuf, &tag) == -1)
+      return (-1);
+    switch (tag) {
+
+"""
+            % {"name": self._name}
+        )
         for entry in self._entries:
-            print >>file, '      case %s:\n' % self.EntryTagName(entry)
+            filep.write("      case %s:\n" % (self.EntryTagName(entry)))
             if not entry.Array():
-                print >>file, (
-                    '        if (tmp->%s_set)\n'
-                    '          return (-1);'
-                    ) % (entry.Name())
+                filep.write(
+                    """        if (tmp->%s_set)
+          return (-1);
+"""
+                    % (entry.Name())
+                )
 
             self.PrintIndented(
-                file, '        ',
-                entry.CodeUnmarshal('evbuf',
-                                    self.EntryTagName(entry),
-                                    entry.GetVarName('tmp'),
-                                    entry.GetVarLen('tmp')))
-
-            print >>file, ( '        tmp->%s_set = 1;\n' % entry.Name() +
-                            '        break;\n' )
-        print >>file, ( '      default:\n'
-                        '        return -1;\n'
-                        '    }\n'
-                        '  }\n' )
+                filep,
+                "        ",
+                entry.CodeUnmarshal(
+                    "evbuf",
+                    self.EntryTagName(entry),
+                    entry.GetVarName("tmp"),
+                    entry.GetVarLen("tmp"),
+                ),
+            )
+
+            filep.write(
+                """        tmp->%s_set = 1;
+        break;
+"""
+                % (entry.Name())
+            )
+        filep.write(
+            """      default:
+        return -1;
+    }
+  }
+
+"""
+        )
         # Check if it was decoded completely
-        print >>file, ( '  if (%(name)s_complete(tmp) == -1)\n'
-                        '    return (-1);'
-                        ) % { 'name' : self._name }
-
-        # Successfully decoded
-        print >>file, ( '  return (0);\n'
-                        '}\n')
+        filep.write(
+            """  if (%(name)s_complete(tmp) == -1)
+    return (-1);
+  return (0);
+}
+"""
+            % {"name": self._name}
+        )
 
         # Checking if a structure has all the required data
-        print >>file, (
-            'int\n'
-            '%(name)s_complete(struct %(name)s *msg)\n'
-            '{' ) % { 'name' : self._name }
+        filep.write(
+            """
+int
+%(name)s_complete(struct %(name)s *msg)
+{
+"""
+            % {"name": self._name}
+        )
         for entry in self._entries:
             if not entry.Optional():
                 code = [
-                    'if (!msg->%(name)s_set)',
-                    '  return (-1);' ]
+                    """if (!msg->%(name)s_set)
+    return (-1);"""
+                ]
                 code = TranslateList(code, entry.GetTranslation())
-                self.PrintIndented(
-                    file, '  ', code)
+                self.PrintIndented(filep, "  ", code)
 
             self.PrintIndented(
-                file, '  ',
-                entry.CodeComplete('msg', entry.GetVarName('msg')))
-        print >>file, (
-            '  return (0);\n'
-            '}\n' )
+                filep, "  ", entry.CodeComplete("msg", entry.GetVarName("msg"))
+            )
+        filep.write(
+            """  return (0);
+}
+"""
+        )
 
         # Complete message unmarshaling
-        print >>file, (
-            'int\n'
-            'evtag_unmarshal_%(name)s(struct evbuffer *evbuf, '
-            'ev_uint32_t need_tag, struct %(name)s *msg)\n'
-            '{\n'
-            '  ev_uint32_t tag;\n'
-            '  int res = -1;\n'
-            '\n'
-            '  struct evbuffer *tmp = evbuffer_new();\n'
-            '\n'
-            '  if (evtag_unmarshal(evbuf, &tag, tmp) == -1'
-            ' || tag != need_tag)\n'
-            '    goto error;\n'
-            '\n'
-            '  if (%(name)s_unmarshal(msg, tmp) == -1)\n'
-            '    goto error;\n'
-            '\n'
-            '  res = 0;\n'
-            '\n'
-            ' error:\n'
-            '  evbuffer_free(tmp);\n'
-            '  return (res);\n'
-            '}\n' ) % { 'name' : self._name }
+        filep.write(
+            """
+int
+evtag_unmarshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t need_tag,
+  struct %(name)s *msg)
+{
+  ev_uint32_t tag;
+  int res = -1;
+
+  struct evbuffer *tmp = evbuffer_new();
+
+  if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag)
+    goto error;
+
+  if (%(name)s_unmarshal(msg, tmp) == -1)
+    goto error;
+
+  res = 0;
+
+ error:
+  evbuffer_free(tmp);
+  return (res);
+}
+"""
+            % {"name": self._name}
+        )
 
         # Complete message marshaling
-        print >>file, (
-            'void\n'
-            'evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag, '
-            'const struct %(name)s *msg)\n'
-            '{\n'
-            '  struct evbuffer *buf_ = evbuffer_new();\n'
-            '  assert(buf_ != NULL);\n'
-            '  %(name)s_marshal(buf_, msg);\n'
-            '  evtag_marshal_buffer(evbuf, tag, buf_);\n '
-            '  evbuffer_free(buf_);\n'
-            '}\n' ) % { 'name' : self._name }
-
-class Entry:
-    def __init__(self, type, name, tag):
-        self._type = type
+        filep.write(
+            """
+void
+evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag,
+    const struct %(name)s *msg)
+{
+  struct evbuffer *buf_ = evbuffer_new();
+  assert(buf_ != NULL);
+  %(name)s_marshal(buf_, msg);
+  evtag_marshal_buffer(evbuf, tag, buf_);
+  evbuffer_free(buf_);
+}
+
+"""
+            % {"name": self._name}
+        )
+
+
+class Entry(object):
+    def __init__(self, ent_type, name, tag):
+        self._type = ent_type
         self._name = name
         self._tag = int(tag)
-        self._ctype = type
-        self._optional = 0
-        self._can_be_array = 0
-        self._array = 0
+        self._ctype = ent_type
+        self._optional = False
+        self._can_be_array = False
+        self._array = False
         self._line_count = -1
         self._struct = None
         self._refname = None
@@ -361,8 +438,9 @@ class Entry:
         self._optpointer = True
         self._optaddarg = True
 
-    def GetInitializer(self):
-        assert 0, "Entry does not provide initializer"
+    @staticmethod
+    def GetInitializer():
+        raise NotImplementedError("Entry does not provide an initializer")
 
     def SetStruct(self, struct):
         self._struct = struct
@@ -389,326 +467,351 @@ class Entry:
     def Type(self):
         return self._type
 
-    def MakeArray(self, yes=1):
-        self._array = yes
+    def MakeArray(self):
+        self._array = True
 
     def MakeOptional(self):
-        self._optional = 1
+        self._optional = True
 
     def Verify(self):
         if self.Array() and not self._can_be_array:
             raise RpcGenError(
                 'Entry "%s" cannot be created as an array '
-                'around line %d' % (self._name, self.LineCount()))
+                "around line %d" % (self._name, self.LineCount())
+            )
         if not self._struct:
             raise RpcGenError(
                 'Entry "%s" does not know which struct it belongs to '
-                'around line %d' % (self._name, self.LineCount()))
+                "around line %d" % (self._name, self.LineCount())
+            )
         if self._optional and self._array:
             raise RpcGenError(
                 'Entry "%s" has illegal combination of optional and array '
-                'around line %d' % (self._name, self.LineCount()))
+                "around line %d" % (self._name, self.LineCount())
+            )
 
-    def GetTranslation(self, extradict = {}):
+    def GetTranslation(self, extradict=None):
+        if extradict is None:
+            extradict = {}
         mapping = {
-            "parent_name" : self._struct.Name(),
-            "name" : self._name,
-            "ctype" : self._ctype,
-            "refname" : self._refname,
-            "optpointer" : self._optpointer and "*" or "",
-            "optreference" : self._optpointer and "&" or "",
-            "optaddarg" :
-            self._optaddarg and ", const %s value" % self._ctype or ""
-            }
-        for (k, v) in extradict.items():
+            "parent_name": self._struct.Name(),
+            "name": self._name,
+            "ctype": self._ctype,
+            "refname": self._refname,
+            "optpointer": self._optpointer and "*" or "",
+            "optreference": self._optpointer and "&" or "",
+            "optaddarg": self._optaddarg and ", const %s value" % self._ctype or "",
+        }
+        for (k, v) in list(extradict.items()):
             mapping[k] = v
 
         return mapping
 
     def GetVarName(self, var):
-        return '%(var)s->%(name)s_data' % self.GetTranslation({ 'var' : var })
+        return "%(var)s->%(name)s_data" % self.GetTranslation({"var": var})
 
-    def GetVarLen(self, var):
-        return 'sizeof(%s)' % self._ctype
+    def GetVarLen(self, _var):
+        return "sizeof(%s)" % self._ctype
 
     def GetFuncName(self):
-        return '%s_%s_get' % (self._struct.Name(), self._name)
+        return "%s_%s_get" % (self._struct.Name(), self._name)
 
     def GetDeclaration(self, funcname):
-        code = [ 'int %s(struct %s *, %s *);' % (
-            funcname, self._struct.Name(), self._ctype ) ]
+        code = [
+            "int %s(struct %s *, %s *);" % (funcname, self._struct.Name(), self._ctype)
+        ]
         return code
 
     def CodeGet(self):
-        code = (
-            'int',
-            '%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, '
-            '%(ctype)s *value)',
-            '{',
-            '  if (msg->%(name)s_set != 1)',
-            '    return (-1);',
-            '  *value = msg->%(name)s_data;',
-            '  return (0);',
-            '}' )
-        code = '\n'.join(code)
+        code = """int
+%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, %(ctype)s *value)
+{
+  if (msg->%(name)s_set != 1)
+    return (-1);
+  *value = msg->%(name)s_data;
+  return (0);
+}"""
         code = code % self.GetTranslation()
-        return code.split('\n')
+        return code.split("\n")
 
     def AssignFuncName(self):
-        return '%s_%s_assign' % (self._struct.Name(), self._name)
+        return "%s_%s_assign" % (self._struct.Name(), self._name)
 
     def AddFuncName(self):
-        return '%s_%s_add' % (self._struct.Name(), self._name)
+        return "%s_%s_add" % (self._struct.Name(), self._name)
 
     def AssignDeclaration(self, funcname):
-        code = [ 'int %s(struct %s *, const %s);' % (
-            funcname, self._struct.Name(), self._ctype ) ]
+        code = [
+            "int %s(struct %s *, const %s);"
+            % (funcname, self._struct.Name(), self._ctype)
+        ]
         return code
 
     def CodeAssign(self):
-        code = [ 'int',
-                 '%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,'
-                 ' const %(ctype)s value)',
-                 '{',
-                 '  msg->%(name)s_set = 1;',
-                 '  msg->%(name)s_data = value;',
-                 '  return (0);',
-                 '}' ]
-        code = '\n'.join(code)
+        code = [
+            "int",
+            "%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,"
+            " const %(ctype)s value)",
+            "{",
+            "  msg->%(name)s_set = 1;",
+            "  msg->%(name)s_data = value;",
+            "  return (0);",
+            "}",
+        ]
+        code = "\n".join(code)
         code = code % self.GetTranslation()
-        return code.split('\n')
+        return code.split("\n")
 
     def CodeClear(self, structname):
-        code = [ '%s->%s_set = 0;' % (structname, self.Name()) ]
+        code = ["%s->%s_set = 0;" % (structname, self.Name())]
 
         return code
 
-    def CodeComplete(self, structname, var_name):
+    @staticmethod
+    def CodeComplete(_structname, _var_name):
         return []
 
-    def CodeFree(self, name):
+    @staticmethod
+    def CodeFree(_name):
         return []
 
     def CodeBase(self):
-        code = [
-            '%(parent_name)s_%(name)s_assign,',
-            '%(parent_name)s_%(name)s_get,'
-            ]
+        code = ["%(parent_name)s_%(name)s_assign,", "%(parent_name)s_%(name)s_get,"]
         if self.Array():
-            code.append('%(parent_name)s_%(name)s_add,')
+            code.append("%(parent_name)s_%(name)s_add,")
 
-        code = '\n'.join(code)
+        code = "\n".join(code)
         code = code % self.GetTranslation()
-        return code.split('\n')
+        return code.split("\n")
+
 
 class EntryBytes(Entry):
-    def __init__(self, type, name, tag, length):
+    def __init__(self, ent_type, name, tag, length):
         # Init base class
-        Entry.__init__(self, type, name, tag)
+        super(EntryBytes, self).__init__(ent_type, name, tag)
 
         self._length = length
-        self._ctype = 'ev_uint8_t'
+        self._ctype = "ev_uint8_t"
 
-    def GetInitializer(self):
+    @staticmethod
+    def GetInitializer():
         return "NULL"
 
-    def GetVarLen(self, var):
-        return '(%s)' % self._length
+    def GetVarLen(self, _var):
+        return "(%s)" % self._length
 
-    def CodeArrayAdd(self, varname, value):
+    @staticmethod
+    def CodeArrayAdd(varname, _value):
         # XXX: copy here
-        return [ '%(varname)s = NULL;' % { 'varname' : varname } ]
+        return ["%(varname)s = NULL;" % {"varname": varname}]
 
     def GetDeclaration(self, funcname):
-        code = [ 'int %s(struct %s *, %s **);' % (
-            funcname, self._struct.Name(), self._ctype ) ]
+        code = [
+            "int %s(struct %s *, %s **);" % (funcname, self._struct.Name(), self._ctype)
+        ]
         return code
 
     def AssignDeclaration(self, funcname):
-        code = [ 'int %s(struct %s *, const %s *);' % (
-            funcname, self._struct.Name(), self._ctype ) ]
+        code = [
+            "int %s(struct %s *, const %s *);"
+            % (funcname, self._struct.Name(), self._ctype)
+        ]
         return code
 
     def Declaration(self):
-        dcl  = ['ev_uint8_t %s_data[%s];' % (self._name, self._length)]
+        dcl = ["ev_uint8_t %s_data[%s];" % (self._name, self._length)]
 
         return dcl
 
     def CodeGet(self):
         name = self._name
-        code = [ 'int',
-                 '%s_%s_get(struct %s *msg, %s **value)' % (
-            self._struct.Name(), name,
-            self._struct.Name(), self._ctype),
-                 '{',
-                 '  if (msg->%s_set != 1)' % name,
-                 '    return (-1);',
-                 '  *value = msg->%s_data;' % name,
-                 '  return (0);',
-                 '}' ]
+        code = [
+            "int",
+            "%s_%s_get(struct %s *msg, %s **value)"
+            % (self._struct.Name(), name, self._struct.Name(), self._ctype),
+            "{",
+            "  if (msg->%s_set != 1)" % name,
+            "    return (-1);",
+            "  *value = msg->%s_data;" % name,
+            "  return (0);",
+            "}",
+        ]
         return code
 
     def CodeAssign(self):
         name = self._name
-        code = [ 'int',
-                 '%s_%s_assign(struct %s *msg, const %s *value)' % (
-            self._struct.Name(), name,
-            self._struct.Name(), self._ctype),
-                 '{',
-                 '  msg->%s_set = 1;' % name,
-                 '  memcpy(msg->%s_data, value, %s);' % (
-            name, self._length),
-                 '  return (0);',
-                 '}' ]
+        code = [
+            "int",
+            "%s_%s_assign(struct %s *msg, const %s *value)"
+            % (self._struct.Name(), name, self._struct.Name(), self._ctype),
+            "{",
+            "  msg->%s_set = 1;" % name,
+            "  memcpy(msg->%s_data, value, %s);" % (name, self._length),
+            "  return (0);",
+            "}",
+        ]
         return code
 
     def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
-        code = [  'if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, '
-                  '%(var)s, %(varlen)s) == -1) {',
-                  '  event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
-                  '  return (-1);',
-                  '}'
-                  ]
-        return TranslateList(code,
-                             self.GetTranslation({
-            'var' : var_name,
-            'varlen' : var_len,
-            'buf' : buf,
-            'tag' : tag_name }))
-
-    def CodeMarshal(self, buf, tag_name, var_name, var_len):
-        code = ['evtag_marshal(%s, %s, %s, %s);' % (
-            buf, tag_name, var_name, var_len)]
+        code = [
+            "if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, "
+            "%(var)s, %(varlen)s) == -1) {",
+            '  event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
+            "  return (-1);",
+            "}",
+        ]
+        return TranslateList(
+            code,
+            self.GetTranslation(
+                {"var": var_name, "varlen": var_len, "buf": buf, "tag": tag_name}
+            ),
+        )
+
+    @staticmethod
+    def CodeMarshal(buf, tag_name, var_name, var_len):
+        code = ["evtag_marshal(%s, %s, %s, %s);" % (buf, tag_name, var_name, var_len)]
         return code
 
     def CodeClear(self, structname):
-        code = [ '%s->%s_set = 0;' % (structname, self.Name()),
-                 'memset(%s->%s_data, 0, sizeof(%s->%s_data));' % (
-            structname, self._name, structname, self._name)]
+        code = [
+            "%s->%s_set = 0;" % (structname, self.Name()),
+            "memset(%s->%s_data, 0, sizeof(%s->%s_data));"
+            % (structname, self._name, structname, self._name),
+        ]
 
         return code
 
     def CodeInitialize(self, name):
-        code  = ['memset(%s->%s_data, 0, sizeof(%s->%s_data));' % (
-            name, self._name, name, self._name)]
+        code = [
+            "memset(%s->%s_data, 0, sizeof(%s->%s_data));"
+            % (name, self._name, name, self._name)
+        ]
         return code
 
     def Verify(self):
         if not self._length:
             raise RpcGenError(
                 'Entry "%s" needs a length '
-                'around line %d' % (self._name, self.LineCount()))
+                "around line %d" % (self._name, self.LineCount())
+            )
+
+        super(EntryBytes, self).Verify()
 
-        Entry.Verify(self)
 
 class EntryInt(Entry):
-    def __init__(self, type, name, tag, bits=32):
+    def __init__(self, ent_type, name, tag, bits=32):
         # Init base class
-        Entry.__init__(self, type, name, tag)
+        super(EntryInt, self).__init__(ent_type, name, tag)
 
-        self._can_be_array = 1
+        self._can_be_array = True
         if bits == 32:
-            self._ctype = 'ev_uint32_t'
-            self._marshal_type = 'int'
+            self._ctype = "ev_uint32_t"
+            self._marshal_type = "int"
         if bits == 64:
-            self._ctype = 'ev_uint64_t'
-            self._marshal_type = 'int64'
+            self._ctype = "ev_uint64_t"
+            self._marshal_type = "int64"
 
-    def GetInitializer(self):
+    @staticmethod
+    def GetInitializer():
         return "0"
 
-    def CodeArrayFree(self, var):
+    @staticmethod
+    def CodeArrayFree(_var):
         return []
 
-    def CodeArrayAssign(self, varname, srcvar):
-        return [ '%(varname)s = %(srcvar)s;' % { 'varname' : varname,
-                                                'srcvar' : srcvar } ]
+    @staticmethod
+    def CodeArrayAssign(varname, srcvar):
+        return ["%(varname)s = %(srcvar)s;" % {"varname": varname, "srcvar": srcvar}]
 
-    def CodeArrayAdd(self, varname, value):
+    @staticmethod
+    def CodeArrayAdd(varname, value):
         """Returns a new entry of this type."""
-        return [ '%(varname)s = %(value)s;' % { 'varname' : varname,
-                                              'value' : value } ]
+        return ["%(varname)s = %(value)s;" % {"varname": varname, "value": value}]
 
-    def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
+    def CodeUnmarshal(self, buf, tag_name, var_name, _var_len):
         code = [
-            'if (evtag_unmarshal_%(ma)s(%(buf)s, %(tag)s, &%(var)s) == -1) {',
+            "if (evtag_unmarshal_%(ma)s(%(buf)s, %(tag)s, &%(var)s) == -1) {",
             '  event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
-            '  return (-1);',
-            '}' ]
-        code = '\n'.join(code) % self.GetTranslation({
-            'ma'  : self._marshal_type,
-            'buf' : buf,
-            'tag' : tag_name,
-            'var' : var_name })
-        return code.split('\n')
-
-    def CodeMarshal(self, buf, tag_name, var_name, var_len):
+            "  return (-1);",
+            "}",
+        ]
+        code = "\n".join(code) % self.GetTranslation(
+            {"ma": self._marshal_type, "buf": buf, "tag": tag_name, "var": var_name}
+        )
+        return code.split("\n")
+
+    def CodeMarshal(self, buf, tag_name, var_name, _var_len):
         code = [
-            'evtag_marshal_%s(%s, %s, %s);' % (
-            self._marshal_type, buf, tag_name, var_name)]
+            "evtag_marshal_%s(%s, %s, %s);"
+            % (self._marshal_type, buf, tag_name, var_name)
+        ]
         return code
 
     def Declaration(self):
-        dcl  = ['%s %s_data;' % (self._ctype, self._name)]
+        dcl = ["%s %s_data;" % (self._ctype, self._name)]
 
         return dcl
 
     def CodeInitialize(self, name):
-        code = ['%s->%s_data = 0;' % (name, self._name)]
+        code = ["%s->%s_data = 0;" % (name, self._name)]
         return code
 
+
 class EntryString(Entry):
-    def __init__(self, type, name, tag):
+    def __init__(self, ent_type, name, tag):
         # Init base class
-        Entry.__init__(self, type, name, tag)
+        super(EntryString, self).__init__(ent_type, name, tag)
 
-        self._can_be_array = 1
-        self._ctype = 'char *'
+        self._can_be_array = True
+        self._ctype = "char *"
 
-    def GetInitializer(self):
+    @staticmethod
+    def GetInitializer():
         return "NULL"
 
-    def CodeArrayFree(self, varname):
-        code = [
-            'if (%(var)s != NULL) free(%(var)s);' ]
+    @staticmethod
+    def CodeArrayFree(varname):
+        code = ["if (%(var)s != NULL) free(%(var)s);"]
 
-        return TranslateList(code, { 'var' : varname })
+        return TranslateList(code, {"var": varname})
 
-    def CodeArrayAssign(self, varname, srcvar):
+    @staticmethod
+    def CodeArrayAssign(varname, srcvar):
         code = [
-            'if (%(var)s != NULL)',
-            '  free(%(var)s);',
-            '%(var)s = strdup(%(srcvar)s);',
-            'if (%(var)s == NULL) {',
+            "if (%(var)s != NULL)",
+            "  free(%(var)s);",
+            "%(var)s = strdup(%(srcvar)s);",
+            "if (%(var)s == NULL) {",
             '  event_warnx("%%s: strdup", __func__);',
-            '  return (-1);',
-            '}' ]
+            "  return (-1);",
+            "}",
+        ]
 
-        return TranslateList(code, { 'var' : varname,
-                                     'srcvar' : srcvar })
+        return TranslateList(code, {"var": varname, "srcvar": srcvar})
 
-    def CodeArrayAdd(self, varname, value):
+    @staticmethod
+    def CodeArrayAdd(varname, value):
         code = [
-            'if (%(value)s != NULL) {',
-            '  %(var)s = strdup(%(value)s);',
-            '  if (%(var)s == NULL) {',
-            '    goto error;',
-            '  }',
-            '} else {',
-            '  %(var)s = NULL;',
-            '}' ]
-
-        return TranslateList(code, { 'var' : varname,
-                                     'value' : value })
+            "if (%(value)s != NULL) {",
+            "  %(var)s = strdup(%(value)s);",
+            "  if (%(var)s == NULL) {",
+            "    goto error;",
+            "  }",
+            "} else {",
+            "  %(var)s = NULL;",
+            "}",
+        ]
+
+        return TranslateList(code, {"var": varname, "value": value})
 
     def GetVarLen(self, var):
-        return 'strlen(%s)' % self.GetVarName(var)
+        return "strlen(%s)" % self.GetVarName(var)
 
-    def CodeMakeInitalize(self, varname):
-        return '%(varname)s = NULL;' % { 'varname' : varname }
+    @staticmethod
+    def CodeMakeInitalize(varname):
+        return "%(varname)s = NULL;" % {"varname": varname}
 
     def CodeAssign(self):
-        name = self._name
         code = """int
 %(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
     const %(ctype)s value)
@@ -719,131 +822,137 @@ class EntryString(Entry):
     return (-1);
   msg->%(name)s_set = 1;
   return (0);
-}""" % self.GetTranslation()
+}""" % (
+            self.GetTranslation()
+        )
 
-        return code.split('\n')
+        return code.split("\n")
 
-    def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
-        code = ['if (evtag_unmarshal_string(%(buf)s, %(tag)s, &%(var)s) == -1) {',
-                '  event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
-                '  return (-1);',
-                '}'
-                ]
-        code = '\n'.join(code) % self.GetTranslation({
-            'buf' : buf,
-            'tag' : tag_name,
-            'var' : var_name })
-        return code.split('\n')
-
-    def CodeMarshal(self, buf, tag_name, var_name, var_len):
-        code = ['evtag_marshal_string(%s, %s, %s);' % (
-            buf, tag_name, var_name)]
+    def CodeUnmarshal(self, buf, tag_name, var_name, _var_len):
+        code = [
+            "if (evtag_unmarshal_string(%(buf)s, %(tag)s, &%(var)s) == -1) {",
+            '  event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
+            "  return (-1);",
+            "}",
+        ]
+        code = "\n".join(code) % self.GetTranslation(
+            {"buf": buf, "tag": tag_name, "var": var_name}
+        )
+        return code.split("\n")
+
+    @staticmethod
+    def CodeMarshal(buf, tag_name, var_name, _var_len):
+        code = ["evtag_marshal_string(%s, %s, %s);" % (buf, tag_name, var_name)]
         return code
 
     def CodeClear(self, structname):
-        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
-                 '  free(%s->%s_data);' % (structname, self.Name()),
-                 '  %s->%s_data = NULL;' % (structname, self.Name()),
-                 '  %s->%s_set = 0;' % (structname, self.Name()),
-                 '}'
-                 ]
+        code = [
+            "if (%s->%s_set == 1) {" % (structname, self.Name()),
+            "  free(%s->%s_data);" % (structname, self.Name()),
+            "  %s->%s_data = NULL;" % (structname, self.Name()),
+            "  %s->%s_set = 0;" % (structname, self.Name()),
+            "}",
+        ]
 
         return code
 
     def CodeInitialize(self, name):
-        code  = ['%s->%s_data = NULL;' % (name, self._name)]
+        code = ["%s->%s_data = NULL;" % (name, self._name)]
         return code
 
     def CodeFree(self, name):
-        code  = ['if (%s->%s_data != NULL)' % (name, self._name),
-                 '    free (%s->%s_data);' % (name, self._name)]
+        code = [
+            "if (%s->%s_data != NULL)" % (name, self._name),
+            "    free (%s->%s_data);" % (name, self._name),
+        ]
 
         return code
 
     def Declaration(self):
-        dcl  = ['char *%s_data;' % self._name]
+        dcl = ["char *%s_data;" % self._name]
 
         return dcl
 
+
 class EntryStruct(Entry):
-    def __init__(self, type, name, tag, refname):
+    def __init__(self, ent_type, name, tag, refname):
         # Init base class
-        Entry.__init__(self, type, name, tag)
+        super(EntryStruct, self).__init__(ent_type, name, tag)
 
         self._optpointer = False
-        self._can_be_array = 1
+        self._can_be_array = True
         self._refname = refname
-        self._ctype = 'struct %s*' % refname
+        self._ctype = "struct %s*" % refname
         self._optaddarg = False
 
     def GetInitializer(self):
         return "NULL"
 
-    def GetVarLen(self, var):
-        return '-1'
+    def GetVarLen(self, _var):
+        return "-1"
 
-    def CodeArrayAdd(self, varname, value):
+    def CodeArrayAdd(self, varname, _value):
         code = [
-            '%(varname)s = %(refname)s_new();',
-            'if (%(varname)s == NULL)',
-            '  goto error;' ]
+            "%(varname)s = %(refname)s_new();",
+            "if (%(varname)s == NULL)",
+            "  goto error;",
+        ]
 
-        return TranslateList(code, self.GetTranslation({ 'varname' : varname }))
+        return TranslateList(code, self.GetTranslation({"varname": varname}))
 
     def CodeArrayFree(self, var):
-        code = [ '%(refname)s_free(%(var)s);' % self.GetTranslation(
-            { 'var' : var }) ]
+        code = ["%(refname)s_free(%(var)s);" % self.GetTranslation({"var": var})]
         return code
 
     def CodeArrayAssign(self, var, srcvar):
         code = [
-            'int had_error = 0;',
-            'struct evbuffer *tmp = NULL;',
-            '%(refname)s_clear(%(var)s);',
-            'if ((tmp = evbuffer_new()) == NULL) {',
+            "int had_error = 0;",
+            "struct evbuffer *tmp = NULL;",
+            "%(refname)s_clear(%(var)s);",
+            "if ((tmp = evbuffer_new()) == NULL) {",
             '  event_warn("%%s: evbuffer_new()", __func__);',
-            '  had_error = 1;',
-            '  goto done;',
-            '}',
-            '%(refname)s_marshal(tmp, %(srcvar)s);',
-            'if (%(refname)s_unmarshal(%(var)s, tmp) == -1) {',
+            "  had_error = 1;",
+            "  goto done;",
+            "}",
+            "%(refname)s_marshal(tmp, %(srcvar)s);",
+            "if (%(refname)s_unmarshal(%(var)s, tmp) == -1) {",
             '  event_warnx("%%s: %(refname)s_unmarshal", __func__);',
-            '  had_error = 1;',
-            '  goto done;',
-            '}',
-            'done:'
-            'if (tmp != NULL)',
-            '  evbuffer_free(tmp);',
-            'if (had_error) {',
-            '  %(refname)s_clear(%(var)s);',
-            '  return (-1);',
-            '}' ]
-
-        return TranslateList(code, self.GetTranslation({
-            'var' : var,
-            'srcvar' : srcvar}))
+            "  had_error = 1;",
+            "  goto done;",
+            "}",
+            "done:",
+            "if (tmp != NULL)",
+            "  evbuffer_free(tmp);",
+            "if (had_error) {",
+            "  %(refname)s_clear(%(var)s);",
+            "  return (-1);",
+            "}",
+        ]
+
+        return TranslateList(code, self.GetTranslation({"var": var, "srcvar": srcvar}))
 
     def CodeGet(self):
         name = self._name
-        code = [ 'int',
-                 '%s_%s_get(struct %s *msg, %s *value)' % (
-            self._struct.Name(), name,
-            self._struct.Name(), self._ctype),
-                 '{',
-                 '  if (msg->%s_set != 1) {' % name,
-                 '    msg->%s_data = %s_new();' % (name, self._refname),
-                 '    if (msg->%s_data == NULL)' % name,
-                 '      return (-1);',
-                 '    msg->%s_set = 1;' % name,
-                 '  }',
-                 '  *value = msg->%s_data;' % name,
-                 '  return (0);',
-                 '}' ]
+        code = [
+            "int",
+            "%s_%s_get(struct %s *msg, %s *value)"
+            % (self._struct.Name(), name, self._struct.Name(), self._ctype),
+            "{",
+            "  if (msg->%s_set != 1) {" % name,
+            "    msg->%s_data = %s_new();" % (name, self._refname),
+            "    if (msg->%s_data == NULL)" % name,
+            "      return (-1);",
+            "    msg->%s_set = 1;" % name,
+            "  }",
+            "  *value = msg->%s_data;" % name,
+            "  return (0);",
+            "}",
+        ]
         return code
 
     def CodeAssign(self):
-        name = self._name
-        code = """int
+        code = (
+            """int
 %(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
     const %(ctype)s value)
 {
@@ -878,186 +987,210 @@ class EntryStruct(Entry):
      msg->%(name)s_data = NULL;
    }
    return (-1);
-}""" % self.GetTranslation()
-        return code.split('\n')
+}"""
+            % self.GetTranslation()
+        )
+        return code.split("\n")
 
     def CodeComplete(self, structname, var_name):
-        code = [ 'if (%(structname)s->%(name)s_set && '
-                 '%(refname)s_complete(%(var)s) == -1)',
-                 '  return (-1);' ]
+        code = [
+            "if (%(structname)s->%(name)s_set && "
+            "%(refname)s_complete(%(var)s) == -1)",
+            "  return (-1);",
+        ]
 
-        return TranslateList(code, self.GetTranslation({
-            'structname' : structname,
-            'var' : var_name }))
+        return TranslateList(
+            code, self.GetTranslation({"structname": structname, "var": var_name})
+        )
 
-    def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
-        code = ['%(var)s = %(refname)s_new();',
-                'if (%(var)s == NULL)',
-                '  return (-1);',
-                'if (evtag_unmarshal_%(refname)s(%(buf)s, %(tag)s, '
-                '%(var)s) == -1) {',
-                  '  event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
-                '  return (-1);',
-                '}'
-                ]
-        code = '\n'.join(code) % self.GetTranslation({
-            'buf' : buf,
-            'tag' : tag_name,
-            'var' : var_name })
-        return code.split('\n')
-
-    def CodeMarshal(self, buf, tag_name, var_name, var_len):
-        code = ['evtag_marshal_%s(%s, %s, %s);' % (
-            self._refname, buf, tag_name, var_name)]
+    def CodeUnmarshal(self, buf, tag_name, var_name, _var_len):
+        code = [
+            "%(var)s = %(refname)s_new();",
+            "if (%(var)s == NULL)",
+            "  return (-1);",
+            "if (evtag_unmarshal_%(refname)s(%(buf)s, %(tag)s, ",
+            "    %(var)s) == -1) {",
+            '  event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
+            "  return (-1);",
+            "}",
+        ]
+        code = "\n".join(code) % self.GetTranslation(
+            {"buf": buf, "tag": tag_name, "var": var_name}
+        )
+        return code.split("\n")
+
+    def CodeMarshal(self, buf, tag_name, var_name, _var_len):
+        code = [
+            "evtag_marshal_%s(%s, %s, %s);" % (self._refname, buf, tag_name, var_name)
+        ]
         return code
 
     def CodeClear(self, structname):
-        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
-                 '  %s_free(%s->%s_data);' % (
-            self._refname, structname, self.Name()),
-                 '  %s->%s_data = NULL;' % (structname, self.Name()),
-                 '  %s->%s_set = 0;' % (structname, self.Name()),
-                 '}'
-                 ]
+        code = [
+            "if (%s->%s_set == 1) {" % (structname, self.Name()),
+            "  %s_free(%s->%s_data);" % (self._refname, structname, self.Name()),
+            "  %s->%s_data = NULL;" % (structname, self.Name()),
+            "  %s->%s_set = 0;" % (structname, self.Name()),
+            "}",
+        ]
 
         return code
 
     def CodeInitialize(self, name):
-        code  = ['%s->%s_data = NULL;' % (name, self._name)]
+        code = ["%s->%s_data = NULL;" % (name, self._name)]
         return code
 
     def CodeFree(self, name):
-        code  = ['if (%s->%s_data != NULL)' % (name, self._name),
-                 '    %s_free(%s->%s_data);' % (
-            self._refname, name, self._name)]
+        code = [
+            "if (%s->%s_data != NULL)" % (name, self._name),
+            "    %s_free(%s->%s_data);" % (self._refname, name, self._name),
+        ]
 
         return code
 
     def Declaration(self):
-        dcl  = ['%s %s_data;' % (self._ctype, self._name)]
+        dcl = ["%s %s_data;" % (self._ctype, self._name)]
 
         return dcl
 
+
 class EntryVarBytes(Entry):
-    def __init__(self, type, name, tag):
+    def __init__(self, ent_type, name, tag):
         # Init base class
-        Entry.__init__(self, type, name, tag)
+        super(EntryVarBytes, self).__init__(ent_type, name, tag)
 
-        self._ctype = 'ev_uint8_t *'
+        self._ctype = "ev_uint8_t *"
 
-    def GetInitializer(self):
+    @staticmethod
+    def GetInitializer():
         return "NULL"
 
     def GetVarLen(self, var):
-        return '%(var)s->%(name)s_length' % self.GetTranslation({ 'var' : var })
+        return "%(var)s->%(name)s_length" % self.GetTranslation({"var": var})
 
-    def CodeArrayAdd(self, varname, value):
+    @staticmethod
+    def CodeArrayAdd(varname, _value):
         # xxx: copy
-        return [ '%(varname)s = NULL;' % { 'varname' : varname } ]
+        return ["%(varname)s = NULL;" % {"varname": varname}]
 
     def GetDeclaration(self, funcname):
-        code = [ 'int %s(struct %s *, %s *, ev_uint32_t *);' % (
-            funcname, self._struct.Name(), self._ctype ) ]
+        code = [
+            "int %s(struct %s *, %s *, ev_uint32_t *);"
+            % (funcname, self._struct.Name(), self._ctype)
+        ]
         return code
 
     def AssignDeclaration(self, funcname):
-        code = [ 'int %s(struct %s *, const %s, ev_uint32_t);' % (
-            funcname, self._struct.Name(), self._ctype ) ]
+        code = [
+            "int %s(struct %s *, const %s, ev_uint32_t);"
+            % (funcname, self._struct.Name(), self._ctype)
+        ]
         return code
 
     def CodeAssign(self):
         name = self._name
-        code = [ 'int',
-                 '%s_%s_assign(struct %s *msg, '
-                 'const %s value, ev_uint32_t len)' % (
-            self._struct.Name(), name,
-            self._struct.Name(), self._ctype),
-                 '{',
-                 '  if (msg->%s_data != NULL)' % name,
-                 '    free (msg->%s_data);' % name,
-                 '  msg->%s_data = malloc(len);' % name,
-                 '  if (msg->%s_data == NULL)' % name,
-                 '    return (-1);',
-                 '  msg->%s_set = 1;' % name,
-                 '  msg->%s_length = len;' % name,
-                 '  memcpy(msg->%s_data, value, len);' % name,
-                 '  return (0);',
-                 '}' ]
+        code = [
+            "int",
+            "%s_%s_assign(struct %s *msg, "
+            "const %s value, ev_uint32_t len)"
+            % (self._struct.Name(), name, self._struct.Name(), self._ctype),
+            "{",
+            "  if (msg->%s_data != NULL)" % name,
+            "    free (msg->%s_data);" % name,
+            "  msg->%s_data = malloc(len);" % name,
+            "  if (msg->%s_data == NULL)" % name,
+            "    return (-1);",
+            "  msg->%s_set = 1;" % name,
+            "  msg->%s_length = len;" % name,
+            "  memcpy(msg->%s_data, value, len);" % name,
+            "  return (0);",
+            "}",
+        ]
         return code
 
     def CodeGet(self):
         name = self._name
-        code = [ 'int',
-                 '%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)' % (
-            self._struct.Name(), name,
-            self._struct.Name(), self._ctype),
-                 '{',
-                 '  if (msg->%s_set != 1)' % name,
-                 '    return (-1);',
-                 '  *value = msg->%s_data;' % name,
-                 '  *plen = msg->%s_length;' % name,
-                 '  return (0);',
-                 '}' ]
+        code = [
+            "int",
+            "%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)"
+            % (self._struct.Name(), name, self._struct.Name(), self._ctype),
+            "{",
+            "  if (msg->%s_set != 1)" % name,
+            "    return (-1);",
+            "  *value = msg->%s_data;" % name,
+            "  *plen = msg->%s_length;" % name,
+            "  return (0);",
+            "}",
+        ]
         return code
 
     def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
-        code = ['if (evtag_payload_length(%(buf)s, &%(varlen)s) == -1)',
-                '  return (-1);',
-                # We do not want DoS opportunities
-                'if (%(varlen)s > evbuffer_get_length(%(buf)s))',
-                '  return (-1);',
-                'if ((%(var)s = malloc(%(varlen)s)) == NULL)',
-                '  return (-1);',
-                'if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, %(var)s, '
-                '%(varlen)s) == -1) {',
-                '  event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
-                '  return (-1);',
-                '}'
-                ]
-        code = '\n'.join(code) % self.GetTranslation({
-            'buf' : buf,
-            'tag' : tag_name,
-            'var' : var_name,
-            'varlen' : var_len })
-        return code.split('\n')
-
-    def CodeMarshal(self, buf, tag_name, var_name, var_len):
-        code = ['evtag_marshal(%s, %s, %s, %s);' % (
-            buf, tag_name, var_name, var_len)]
+        code = [
+            "if (evtag_payload_length(%(buf)s, &%(varlen)s) == -1)",
+            "  return (-1);",
+            # We do not want DoS opportunities
+            "if (%(varlen)s > evbuffer_get_length(%(buf)s))",
+            "  return (-1);",
+            "if ((%(var)s = malloc(%(varlen)s)) == NULL)",
+            "  return (-1);",
+            "if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, %(var)s, "
+            "%(varlen)s) == -1) {",
+            '  event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
+            "  return (-1);",
+            "}",
+        ]
+        code = "\n".join(code) % self.GetTranslation(
+            {"buf": buf, "tag": tag_name, "var": var_name, "varlen": var_len}
+        )
+        return code.split("\n")
+
+    @staticmethod
+    def CodeMarshal(buf, tag_name, var_name, var_len):
+        code = ["evtag_marshal(%s, %s, %s, %s);" % (buf, tag_name, var_name, var_len)]
         return code
 
     def CodeClear(self, structname):
-        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
-                 '  free (%s->%s_data);' % (structname, self.Name()),
-                 '  %s->%s_data = NULL;' % (structname, self.Name()),
-                 '  %s->%s_length = 0;' % (structname, self.Name()),
-                 '  %s->%s_set = 0;' % (structname, self.Name()),
-                 '}'
-                 ]
+        code = [
+            "if (%s->%s_set == 1) {" % (structname, self.Name()),
+            "  free (%s->%s_data);" % (structname, self.Name()),
+            "  %s->%s_data = NULL;" % (structname, self.Name()),
+            "  %s->%s_length = 0;" % (structname, self.Name()),
+            "  %s->%s_set = 0;" % (structname, self.Name()),
+            "}",
+        ]
 
         return code
 
     def CodeInitialize(self, name):
-        code  = ['%s->%s_data = NULL;' % (name, self._name),
-                 '%s->%s_length = 0;' % (name, self._name) ]
+        code = [
+            "%s->%s_data = NULL;" % (name, self._name),
+            "%s->%s_length = 0;" % (name, self._name),
+        ]
         return code
 
     def CodeFree(self, name):
-        code  = ['if (%s->%s_data != NULL)' % (name, self._name),
-                 '    free(%s->%s_data);' % (name, self._name)]
+        code = [
+            "if (%s->%s_data != NULL)" % (name, self._name),
+            "    free(%s->%s_data);" % (name, self._name),
+        ]
 
         return code
 
     def Declaration(self):
-        dcl  = ['ev_uint8_t *%s_data;' % self._name,
-                'ev_uint32_t %s_length;' % self._name]
+        dcl = [
+            "ev_uint8_t *%s_data;" % self._name,
+            "ev_uint32_t %s_length;" % self._name,
+        ]
 
         return dcl
 
+
 class EntryArray(Entry):
+    _index = None
+
     def __init__(self, entry):
         # Init base class
-        Entry.__init__(self, entry._type, entry._name, entry._tag)
+        super(EntryArray, self).__init__(entry._type, entry._name, entry._tag)
 
         self._entry = entry
         self._refname = entry._refname
@@ -1068,37 +1201,42 @@ class EntryArray(Entry):
 
         # provide a new function for accessing the variable name
         def GetVarName(var_name):
-            return '%(var)s->%(name)s_data[%(index)s]' % \
-                   self._entry.GetTranslation({'var' : var_name,
-                                               'index' : self._index})
+            return "%(var)s->%(name)s_data[%(index)s]" % self._entry.GetTranslation(
+                {"var": var_name, "index": self._index}
+            )
+
         self._entry.GetVarName = GetVarName
 
     def GetInitializer(self):
         return "NULL"
 
-    def GetVarName(self, var_name):
-        return var_name
+    def GetVarName(self, var):
+        return var
 
-    def GetVarLen(self, var_name):
-        return '-1'
+    def GetVarLen(self, _var_name):
+        return "-1"
 
     def GetDeclaration(self, funcname):
         """Allows direct access to elements of the array."""
         code = [
-            'int %(funcname)s(struct %(parent_name)s *, int, %(ctype)s *);' %
-            self.GetTranslation({ 'funcname' : funcname }) ]
+            "int %(funcname)s(struct %(parent_name)s *, int, %(ctype)s *);"
+            % self.GetTranslation({"funcname": funcname})
+        ]
         return code
 
     def AssignDeclaration(self, funcname):
-        code = [ 'int %s(struct %s *, int, const %s);' % (
-            funcname, self._struct.Name(), self._ctype ) ]
+        code = [
+            "int %s(struct %s *, int, const %s);"
+            % (funcname, self._struct.Name(), self._ctype)
+        ]
         return code
 
     def AddDeclaration(self, funcname):
         code = [
-            '%(ctype)s %(optpointer)s '
-            '%(funcname)s(struct %(parent_name)s *msg%(optaddarg)s);' % \
-            self.GetTranslation({ 'funcname' : funcname }) ]
+            "%(ctype)s %(optpointer)s "
+            "%(funcname)s(struct %(parent_name)s *msg%(optaddarg)s);"
+            % self.GetTranslation({"funcname": funcname})
+        ]
         return code
 
     def CodeGet(self):
@@ -1110,226 +1248,249 @@ class EntryArray(Entry):
     return (-1);
   *value = msg->%(name)s_data[offset];
   return (0);
-}""" % self.GetTranslation()
+}
+""" % (
+            self.GetTranslation()
+        )
 
-        return code.split('\n')
+        return code.splitlines()
 
     def CodeAssign(self):
         code = [
-            'int',
-            '%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, int off,',
-            '    const %(ctype)s value)',
-            '{',
-            '  if (!msg->%(name)s_set || off < 0 || off >= msg->%(name)s_length)',
-            '    return (-1);\n',
-            '  {' ]
+            "int",
+            "%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, int off,",
+            "  const %(ctype)s value)",
+            "{",
+            "  if (!msg->%(name)s_set || off < 0 || off >= msg->%(name)s_length)",
+            "    return (-1);",
+            "",
+            "  {",
+        ]
         code = TranslateList(code, self.GetTranslation())
 
         codearrayassign = self._entry.CodeArrayAssign(
-            'msg->%(name)s_data[off]' % self.GetTranslation(), 'value')
-        code += map(lambda x: '    ' + x, codearrayassign)
+            "msg->%(name)s_data[off]" % self.GetTranslation(), "value"
+        )
+        code += ["    " + x for x in codearrayassign]
 
-        code += TranslateList([
-            '  }',
-            '  return (0);',
-            '}' ], self.GetTranslation())
+        code += TranslateList(["  }", "  return (0);", "}"], self.GetTranslation())
 
         return code
 
     def CodeAdd(self):
         codearrayadd = self._entry.CodeArrayAdd(
-            'msg->%(name)s_data[msg->%(name)s_length - 1]' % self.GetTranslation(),
-            'value')
+            "msg->%(name)s_data[msg->%(name)s_length - 1]" % self.GetTranslation(),
+            "value",
+        )
         code = [
-            'static int',
-            '%(parent_name)s_%(name)s_expand_to_hold_more('
-            'struct %(parent_name)s *msg)',
-            '{',
-            '  int tobe_allocated = msg->%(name)s_num_allocated;',
-            '  %(ctype)s* new_data = NULL;',
-            '  tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;',
-            '  new_data = (%(ctype)s*) realloc(msg->%(name)s_data,',
-            '      tobe_allocated * sizeof(%(ctype)s));',
-            '  if (new_data == NULL)',
-            '    return -1;',
-            '  msg->%(name)s_data = new_data;',
-            '  msg->%(name)s_num_allocated = tobe_allocated;',
-            '  return 0;'
-            '}',
-            '',
-            '%(ctype)s %(optpointer)s',
-            '%(parent_name)s_%(name)s_add('
-            'struct %(parent_name)s *msg%(optaddarg)s)',
-            '{',
-            '  if (++msg->%(name)s_length >= msg->%(name)s_num_allocated) {',
-            '    if (%(parent_name)s_%(name)s_expand_to_hold_more(msg)<0)',
-            '      goto error;',
-            '  }' ]
+            "static int",
+            "%(parent_name)s_%(name)s_expand_to_hold_more("
+            "struct %(parent_name)s *msg)",
+            "{",
+            "  int tobe_allocated = msg->%(name)s_num_allocated;",
+            "  %(ctype)s* new_data = NULL;",
+            "  tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;",
+            "  new_data = (%(ctype)s*) realloc(msg->%(name)s_data,",
+            "      tobe_allocated * sizeof(%(ctype)s));",
+            "  if (new_data == NULL)",
+            "    return -1;",
+            "  msg->%(name)s_data = new_data;",
+            "  msg->%(name)s_num_allocated = tobe_allocated;",
+            "  return 0;",
+            "}",
+            "",
+            "%(ctype)s %(optpointer)s",
+            "%(parent_name)s_%(name)s_add(struct %(parent_name)s *msg%(optaddarg)s)",
+            "{",
+            "  if (++msg->%(name)s_length >= msg->%(name)s_num_allocated) {",
+            "    if (%(parent_name)s_%(name)s_expand_to_hold_more(msg)<0)",
+            "      goto error;",
+            "  }",
+        ]
 
         code = TranslateList(code, self.GetTranslation())
 
-        code += map(lambda x: '  ' + x, codearrayadd)
-
-        code += TranslateList([
-            '  msg->%(name)s_set = 1;',
-            '  return %(optreference)s(msg->%(name)s_data['
-            'msg->%(name)s_length - 1]);',
-            'error:',
-            '  --msg->%(name)s_length;',
-            '  return (NULL);',
-            '}' ], self.GetTranslation())
+        code += ["  " + x for x in codearrayadd]
+
+        code += TranslateList(
+            [
+                "  msg->%(name)s_set = 1;",
+                "  return %(optreference)s(msg->%(name)s_data["
+                "msg->%(name)s_length - 1]);",
+                "error:",
+                "  --msg->%(name)s_length;",
+                "  return (NULL);",
+                "}",
+            ],
+            self.GetTranslation(),
+        )
 
         return code
 
     def CodeComplete(self, structname, var_name):
-        self._index = 'i'
+        self._index = "i"
         tmp = self._entry.CodeComplete(structname, self._entry.GetVarName(var_name))
         # skip the whole loop if there is nothing to check
         if not tmp:
             return []
 
-        translate = self.GetTranslation({ 'structname' : structname })
+        translate = self.GetTranslation({"structname": structname})
         code = [
-            '{',
-            '  int i;',
-            '  for (i = 0; i < %(structname)s->%(name)s_length; ++i) {' ]
+            "{",
+            "  int i;",
+            "  for (i = 0; i < %(structname)s->%(name)s_length; ++i) {",
+        ]
 
         code = TranslateList(code, translate)
 
-        code += map(lambda x: '    ' + x, tmp)
+        code += ["    " + x for x in tmp]
 
-        code += [
-            '  }',
-            '}' ]
+        code += ["  }", "}"]
 
         return code
 
-    def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
-        translate = self.GetTranslation({ 'var' : var_name,
-                                          'buf' : buf,
-                                          'tag' : tag_name,
-                                          'init' : self._entry.GetInitializer()})
+    def CodeUnmarshal(self, buf, tag_name, var_name, _var_len):
+        translate = self.GetTranslation(
+            {
+                "var": var_name,
+                "buf": buf,
+                "tag": tag_name,
+                "init": self._entry.GetInitializer(),
+            }
+        )
         code = [
-            'if (%(var)s->%(name)s_length >= %(var)s->%(name)s_num_allocated &&',
-            '    %(parent_name)s_%(name)s_expand_to_hold_more(%(var)s) < 0) {',
+            "if (%(var)s->%(name)s_length >= %(var)s->%(name)s_num_allocated &&",
+            "    %(parent_name)s_%(name)s_expand_to_hold_more(%(var)s) < 0) {",
             '  puts("HEY NOW");',
-            '  return (-1);',
-            '}']
+            "  return (-1);",
+            "}",
+        ]
 
         # the unmarshal code directly returns
         code = TranslateList(code, translate)
 
-        self._index = '%(var)s->%(name)s_length' % translate
-        code += self._entry.CodeUnmarshal(buf, tag_name,
-                                        self._entry.GetVarName(var_name),
-                                        self._entry.GetVarLen(var_name))
+        self._index = "%(var)s->%(name)s_length" % translate
+        code += self._entry.CodeUnmarshal(
+            buf,
+            tag_name,
+            self._entry.GetVarName(var_name),
+            self._entry.GetVarLen(var_name),
+        )
 
-        code += [ '++%(var)s->%(name)s_length;' % translate ]
+        code += ["++%(var)s->%(name)s_length;" % translate]
 
         return code
 
-    def CodeMarshal(self, buf, tag_name, var_name, var_len):
-        code = ['{',
-                '  int i;',
-                '  for (i = 0; i < %(var)s->%(name)s_length; ++i) {' ]
+    def CodeMarshal(self, buf, tag_name, var_name, _var_len):
+        code = ["{", "  int i;", "  for (i = 0; i < %(var)s->%(name)s_length; ++i) {"]
 
-        self._index = 'i'
-        code += self._entry.CodeMarshal(buf, tag_name,
-                                        self._entry.GetVarName(var_name),
-                                        self._entry.GetVarLen(var_name))
-        code += ['  }',
-                 '}'
-                 ]
+        self._index = "i"
+        code += self._entry.CodeMarshal(
+            buf,
+            tag_name,
+            self._entry.GetVarName(var_name),
+            self._entry.GetVarLen(var_name),
+        )
+        code += ["  }", "}"]
 
-        code = "\n".join(code) % self.GetTranslation({ 'var' : var_name })
+        code = "\n".join(code) % self.GetTranslation({"var": var_name})
 
-        return code.split('\n')
+        return code.split("\n")
 
     def CodeClear(self, structname):
-        translate = self.GetTranslation({ 'structname' : structname })
+        translate = self.GetTranslation({"structname": structname})
         codearrayfree = self._entry.CodeArrayFree(
-            '%(structname)s->%(name)s_data[i]' % self.GetTranslation(
-            { 'structname' : structname } ))
+            "%(structname)s->%(name)s_data[i]"
+            % self.GetTranslation({"structname": structname})
+        )
 
-        code = [ 'if (%(structname)s->%(name)s_set == 1) {' ]
+        code = ["if (%(structname)s->%(name)s_set == 1) {"]
 
         if codearrayfree:
             code += [
-                '  int i;',
-                '  for (i = 0; i < %(structname)s->%(name)s_length; ++i) {' ]
+                "  int i;",
+                "  for (i = 0; i < %(structname)s->%(name)s_length; ++i) {",
+            ]
 
         code = TranslateList(code, translate)
 
         if codearrayfree:
-            code += map(lambda x: '    ' + x, codearrayfree)
-            code += [
-                '  }' ]
-
-        code += TranslateList([
-                 '  free(%(structname)s->%(name)s_data);',
-                 '  %(structname)s->%(name)s_data = NULL;',
-                 '  %(structname)s->%(name)s_set = 0;',
-                 '  %(structname)s->%(name)s_length = 0;',
-                 '  %(structname)s->%(name)s_num_allocated = 0;',
-                 '}'
-                 ], translate)
+            code += ["    " + x for x in codearrayfree]
+            code += ["  }"]
+
+        code += TranslateList(
+            [
+                "  free(%(structname)s->%(name)s_data);",
+                "  %(structname)s->%(name)s_data = NULL;",
+                "  %(structname)s->%(name)s_set = 0;",
+                "  %(structname)s->%(name)s_length = 0;",
+                "  %(structname)s->%(name)s_num_allocated = 0;",
+                "}",
+            ],
+            translate,
+        )
 
         return code
 
     def CodeInitialize(self, name):
-        code  = ['%s->%s_data = NULL;' % (name, self._name),
-                 '%s->%s_length = 0;' % (name, self._name),
-                 '%s->%s_num_allocated = 0;' % (name, self._name)]
+        code = [
+            "%s->%s_data = NULL;" % (name, self._name),
+            "%s->%s_length = 0;" % (name, self._name),
+            "%s->%s_num_allocated = 0;" % (name, self._name),
+        ]
         return code
 
     def CodeFree(self, structname):
-        code = self.CodeClear(structname);
+        code = self.CodeClear(structname)
 
-        code += TranslateList([
-            'free(%(structname)s->%(name)s_data);' ],
-                              self.GetTranslation({'structname' : structname }))
+        code += TranslateList(
+            ["free(%(structname)s->%(name)s_data);"],
+            self.GetTranslation({"structname": structname}),
+        )
 
         return code
 
     def Declaration(self):
-        dcl  = ['%s *%s_data;' % (self._ctype, self._name),
-                'int %s_length;' % self._name,
-                'int %s_num_allocated;' % self._name ]
+        dcl = [
+            "%s *%s_data;" % (self._ctype, self._name),
+            "int %s_length;" % self._name,
+            "int %s_num_allocated;" % self._name,
+        ]
 
         return dcl
 
+
 def NormalizeLine(line):
-    global white
-    global cppcomment
 
-    line = cppcomment.sub('', line)
+    line = CPPCOMMENT_RE.sub("", line)
     line = line.strip()
-    line = white.sub(' ', line)
+    line = WHITESPACE_RE.sub(" ", line)
 
     return line
 
+
+ENTRY_NAME_RE = re.compile(r"(?P<name>[^\[\]]+)(\[(?P<fixed_length>.*)\])?")
+ENTRY_TAG_NUMBER_RE = re.compile(r"(0x)?\d+", re.I)
+
+
 def ProcessOneEntry(factory, newstruct, entry):
-    optional = 0
-    array = 0
-    entry_type = ''
-    name = ''
-    tag = ''
+    optional = False
+    array = False
+    entry_type = ""
+    name = ""
+    tag = ""
     tag_set = None
-    separator = ''
-    fixed_length = ''
-
-    tokens = entry.split(' ')
-    while tokens:
-        token = tokens[0]
-        tokens = tokens[1:]
+    separator = ""
+    fixed_length = ""
 
+    for token in entry.split(" "):
         if not entry_type:
-            if not optional and token == 'optional':
-                optional = 1
+            if not optional and token == "optional":
+                optional = True
                 continue
 
-            if not array and token == 'array':
-                array = 1
+            if not array and token == "array":
+                array = True
                 continue
 
         if not entry_type:
@@ -1337,53 +1498,52 @@ def ProcessOneEntry(factory, newstruct, entry):
             continue
 
         if not name:
-            res = re.match(r'^([^\[\]]+)(\[.*\])?$', token)
+            res = ENTRY_NAME_RE.match(token)
             if not res:
-                 raise RpcGenError(
-                     'Cannot parse name: \"%s\" '
-                     'around line %d' % (entry, line_count))
-            name = res.group(1)
-            fixed_length = res.group(2)
-            if fixed_length:
-                fixed_length = fixed_length[1:-1]
+                raise RpcGenError(
+                    r"""Cannot parse name: "%s" around line %d""" % (entry, LINE_COUNT)
+                )
+            name = res.group("name")
+            fixed_length = res.group("fixed_length")
             continue
 
         if not separator:
             separator = token
-            if separator != '=':
-                 raise RpcGenError('Expected "=" after name \"%s\" got %s'
-                                   % (name, token))
+            if separator != "=":
+                raise RpcGenError(
+                    r'''Expected "=" after name "%s" got "%s"''' % (name, token)
+                )
             continue
 
         if not tag_set:
             tag_set = 1
-            if not re.match(r'^(0x)?[0-9]+$', token):
-                raise RpcGenError('Expected tag number: \"%s\"' % entry)
+            if not ENTRY_TAG_NUMBER_RE.match(token):
+                raise RpcGenError(r'''Expected tag number: "%s"''' % (entry))
             tag = int(token, 0)
             continue
 
-        raise RpcGenError('Cannot parse \"%s\"' % entry)
+        raise RpcGenError(r'''Cannot parse "%s"''' % (entry))
 
     if not tag_set:
-        raise RpcGenError('Need tag number: \"%s\"' % entry)
+        raise RpcGenError(r'''Need tag number: "%s"''' % (entry))
 
     # Create the right entry
-    if entry_type == 'bytes':
+    if entry_type == "bytes":
         if fixed_length:
             newentry = factory.EntryBytes(entry_type, name, tag, fixed_length)
         else:
             newentry = factory.EntryVarBytes(entry_type, name, tag)
-    elif entry_type == 'int' and not fixed_length:
+    elif entry_type == "int" and not fixed_length:
         newentry = factory.EntryInt(entry_type, name, tag)
-    elif entry_type == 'int64' and not fixed_length:
+    elif entry_type == "int64" and not fixed_length:
         newentry = factory.EntryInt(entry_type, name, tag, bits=64)
-    elif entry_type == 'string' and not fixed_length:
+    elif entry_type == "string" and not fixed_length:
         newentry = factory.EntryString(entry_type, name, tag)
     else:
-        res = structref.match(entry_type)
+        res = STRUCT_REF_RE.match(entry_type)
         if res:
             # References another struct defined in our file
-            newentry = factory.EntryStruct(entry_type, name, tag, res.group(1))
+            newentry = factory.EntryStruct(entry_type, name, tag, res.group("name"))
         else:
             raise RpcGenError('Bad type: "%s" in "%s"' % (entry_type, entry))
 
@@ -1395,32 +1555,30 @@ def ProcessOneEntry(factory, newstruct, entry):
         newentry.MakeArray()
 
     newentry.SetStruct(newstruct)
-    newentry.SetLineCount(line_count)
+    newentry.SetLineCount(LINE_COUNT)
     newentry.Verify()
 
     if array:
         # We need to encapsulate this entry into a struct
-        newname = newentry.Name()+ '_array'
-
-        # Now borgify the new entry.
         newentry = factory.EntryArray(newentry)
         newentry.SetStruct(newstruct)
-        newentry.SetLineCount(line_count)
+        newentry.SetLineCount(LINE_COUNT)
         newentry.MakeArray()
 
     newstruct.AddEntry(newentry)
 
     return structs
 
+
 def ProcessStruct(factory, data):
-    tokens = data.split(' ')
+    tokens = data.split(" ")
 
     # First three tokens are: 'struct' 'name' '{'
     newstruct = factory.Struct(tokens[1])
 
-    inside = ' '.join(tokens[3:-1])
+    inside = " ".join(tokens[3:-1])
 
-    tokens = inside.split(';')
+    tokens = inside.split(";")
 
     structs = []
 
@@ -1435,36 +1593,52 @@ def ProcessStruct(factory, data):
     structs.append(newstruct)
     return structs
 
-def GetNextStruct(file):
-    global line_count
-    global cppdirect
 
-    got_struct = 0
+C_COMMENT_START = "/*"
+C_COMMENT_END = "*/"
 
-    processed_lines = []
+C_COMMENT_START_RE = re.compile(re.escape(C_COMMENT_START))
+C_COMMENT_END_RE = re.compile(re.escape(C_COMMENT_END))
 
-    have_c_comment = 0
-    data = ''
-    while 1:
-        line = file.readline()
+C_COMMENT_START_SUB_RE = re.compile(r"%s.*$" % (re.escape(C_COMMENT_START)))
+C_COMMENT_END_SUB_RE = re.compile(r"%s.*$" % (re.escape(C_COMMENT_END)))
+
+C_MULTILINE_COMMENT_SUB_RE = re.compile(
+    r"%s.*?%s" % (re.escape(C_COMMENT_START), re.escape(C_COMMENT_END))
+)
+CPP_CONDITIONAL_BLOCK_RE = re.compile(r"#(if( |def)|endif)")
+INCLUDE_RE = re.compile(r'#include (".+"|<.+>)')
+
+
+def GetNextStruct(filep):
+    global CPP_DIRECT
+    global LINE_COUNT
+
+    got_struct = False
+    have_c_comment = False
+
+    data = ""
+
+    while True:
+        line = filep.readline()
         if not line:
             break
 
-        line_count += 1
+        LINE_COUNT += 1
         line = line[:-1]
 
-        if not have_c_comment and re.search(r'/\*', line):
-            if re.search(r'/\*.*?\*/', line):
-                line = re.sub(r'/\*.*?\*/', '', line)
+        if not have_c_comment and C_COMMENT_START_RE.search(line):
+            if C_MULTILINE_COMMENT_SUB_RE.search(line):
+                line = C_MULTILINE_COMMENT_SUB_RE.sub("", line)
             else:
-                line = re.sub(r'/\*.*$', '', line)
-                have_c_comment = 1
+                line = C_COMMENT_START_SUB_RE.sub("", line)
+                have_c_comment = True
 
         if have_c_comment:
-            if not re.search(r'\*/', line):
+            if not C_COMMENT_END_RE.search(line):
                 continue
-            have_c_comment = 0
-            line = re.sub(r'^.*\*/', '', line)
+            have_c_comment = False
+            line = C_COMMENT_END_SUB_RE.sub("", line)
 
         line = NormalizeLine(line)
 
@@ -1472,47 +1646,39 @@ def GetNextStruct(file):
             continue
 
         if not got_struct:
-            if re.match(r'#include ["<].*[>"]', line):
-                cppdirect.append(line)
-                continue
-
-            if re.match(r'^#(if( |def)|endif)', line):
-                cppdirect.append(line)
-                continue
-
-            if re.match(r'^#define', line):
-                headerdirect.append(line)
-                continue
-
-            if not structdef.match(line):
-                raise RpcGenError('Missing struct on line %d: %s'
-                                  % (line_count, line))
+            if INCLUDE_RE.match(line):
+                CPP_DIRECT.append(line)
+            elif CPP_CONDITIONAL_BLOCK_RE.match(line):
+                CPP_DIRECT.append(line)
+            elif PREPROCESSOR_DEF_RE.match(line):
+                HEADER_DIRECT.append(line)
+            elif not STRUCT_DEF_RE.match(line):
+                raise RpcGenError("Missing struct on line %d: %s" % (LINE_COUNT, line))
             else:
-                got_struct = 1
+                got_struct = True
                 data += line
             continue
 
         # We are inside the struct
-        tokens = line.split('}')
+        tokens = line.split("}")
         if len(tokens) == 1:
-            data += ' ' + line
+            data += " " + line
             continue
 
-        if len(tokens[1]):
-            raise RpcGenError('Trailing garbage after struct on line %d'
-                              % line_count)
+        if tokens[1]:
+            raise RpcGenError("Trailing garbage after struct on line %d" % LINE_COUNT)
 
         # We found the end of the struct
-        data += ' %s}' % tokens[0]
+        data += " %s}" % tokens[0]
         break
 
     # Remove any comments, that might be in there
-    data = re.sub(r'/\*.*\*/', '', data)
+    data = re.sub(r"/\*.*\*/", "", data)
 
     return data
 
 
-def Parse(factory, file):
+def Parse(factory, filep):
     """
     Parses the input file and returns C code and corresponding header file.
     """
@@ -1521,7 +1687,7 @@ def Parse(factory, file):
 
     while 1:
         # Just gets the whole struct nicely formatted
-        data = GetNextStruct(file)
+        data = GetNextStruct(filep)
 
         if not data:
             break
@@ -1530,199 +1696,230 @@ def Parse(factory, file):
 
     return entities
 
-class CCodeGenerator:
+
+class CCodeGenerator(object):
     def __init__(self):
         pass
 
-    def GuardName(self, name):
+    @staticmethod
+    def GuardName(name):
         # Use the complete provided path to the input file, with all
         # non-identifier characters replaced with underscores, to
         # reduce the chance of a collision between guard macros.
-        return 'EVENT_RPCOUT_' + nonident.sub('_', name).upper() + '_'
+        return "EVENT_RPCOUT_%s_" % (NONIDENT_RE.sub("_", name).upper())
 
     def HeaderPreamble(self, name):
         guard = self.GuardName(name)
-        pre = (
-            '/*\n'
-            ' * Automatically generated from %s\n'
-            ' */\n\n'
-            '#ifndef %s\n'
-            '#define %s\n\n' ) % (
-            name, guard, guard)
-
-        for statement in headerdirect:
-            pre += '%s\n' % statement
-        if headerdirect:
-            pre += '\n'
-
-        pre += (
-            '#include <event2/util.h> /* for ev_uint*_t */\n'
-            '#include <event2/rpc.h>\n'
+        pre = """
+/*
+ * Automatically generated from %s
+ */
+
+#ifndef %s
+#define %s
+
+""" % (
+            name,
+            guard,
+            guard,
         )
 
+        if HEADER_DIRECT:
+            for statement in HEADER_DIRECT:
+                pre += "%s\n" % statement
+            pre += "\n"
+
+        pre += """
+#include <event2/util.h> /* for ev_uint*_t */
+#include <event2/rpc.h>
+"""
+
         return pre
 
     def HeaderPostamble(self, name):
         guard = self.GuardName(name)
-        return '#endif  /* %s */' % guard
+        return "#endif  /* %s */" % (guard)
 
-    def BodyPreamble(self, name, header_file):
+    @staticmethod
+    def BodyPreamble(name, header_file):
         global _NAME
         global _VERSION
 
-        slash = header_file.rfind('/')
+        slash = header_file.rfind("/")
         if slash != -1:
-            header_file = header_file[slash+1:]
-
-        pre = ( '/*\n'
-                ' * Automatically generated from %s\n'
-                ' * by %s/%s.  DO NOT EDIT THIS FILE.\n'
-                ' */\n\n' ) % (name, _NAME, _VERSION)
-        pre += ( '#include <stdlib.h>\n'
-                 '#include <string.h>\n'
-                 '#include <assert.h>\n'
-                 '#include <event2/event-config.h>\n'
-                 '#include <event2/event.h>\n'
-                 '#include <event2/buffer.h>\n'
-                 '#include <event2/tag.h>\n\n'
-                 '#ifdef EVENT____func__\n'
-                 '#define __func__ EVENT____func__\n'
-                 '#endif\n\n'
-                 )
-
-        for statement in cppdirect:
-            pre += '%s\n' % statement
+            header_file = header_file[slash + 1 :]
+
+        pre = """
+/*
+ * Automatically generated from %(name)s
+ * by %(script_name)s/%(script_version)s.  DO NOT EDIT THIS FILE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <event2/event-config.h>
+#include <event2/event.h>
+#include <event2/buffer.h>
+#include <event2/tag.h>
+
+#if defined(EVENT__HAVE___func__)
+# ifndef __func__
+#  define __func__ __func__
+# endif
+#elif defined(EVENT__HAVE___FUNCTION__)
+# define __func__ __FUNCTION__
+#else
+# define __func__ __FILE__
+#endif
+
+""" % {
+            "name": name,
+            "script_name": _NAME,
+            "script_version": _VERSION,
+        }
+
+        for statement in CPP_DIRECT:
+            pre += "%s\n" % statement
 
         pre += '\n#include "%s"\n\n' % header_file
 
-        pre += 'void event_warn(const char *fmt, ...);\n'
-        pre += 'void event_warnx(const char *fmt, ...);\n\n'
+        pre += "void event_warn(const char *fmt, ...);\n"
+        pre += "void event_warnx(const char *fmt, ...);\n\n"
 
         return pre
 
-    def HeaderFilename(self, filename):
-        return '.'.join(filename.split('.')[:-1]) + '.h'
+    @staticmethod
+    def HeaderFilename(filename):
+        return ".".join(filename.split(".")[:-1]) + ".h"
 
-    def CodeFilename(self, filename):
-        return '.'.join(filename.split('.')[:-1]) + '.gen.c'
+    @staticmethod
+    def CodeFilename(filename):
+        return ".".join(filename.split(".")[:-1]) + ".gen.c"
 
-    def Struct(self, name):
+    @staticmethod
+    def Struct(name):
         return StructCCode(name)
 
-    def EntryBytes(self, entry_type, name, tag, fixed_length):
+    @staticmethod
+    def EntryBytes(entry_type, name, tag, fixed_length):
         return EntryBytes(entry_type, name, tag, fixed_length)
 
-    def EntryVarBytes(self, entry_type, name, tag):
+    @staticmethod
+    def EntryVarBytes(entry_type, name, tag):
         return EntryVarBytes(entry_type, name, tag)
 
-    def EntryInt(self, entry_type, name, tag, bits=32):
+    @staticmethod
+    def EntryInt(entry_type, name, tag, bits=32):
         return EntryInt(entry_type, name, tag, bits)
 
-    def EntryString(self, entry_type, name, tag):
+    @staticmethod
+    def EntryString(entry_type, name, tag):
         return EntryString(entry_type, name, tag)
 
-    def EntryStruct(self, entry_type, name, tag, struct_name):
+    @staticmethod
+    def EntryStruct(entry_type, name, tag, struct_name):
         return EntryStruct(entry_type, name, tag, struct_name)
 
-    def EntryArray(self, entry):
+    @staticmethod
+    def EntryArray(entry):
         return EntryArray(entry)
 
-class Usage(RpcGenError):
-    def __init__(self, argv0):
-        RpcGenError.__init__("usage: %s input.rpc [[output.h] output.c]"
-                             % argv0)
 
-class CommandLine:
-    def __init__(self, argv):
+class CommandLine(object):
+    def __init__(self, argv=None):
         """Initialize a command-line to launch event_rpcgen, as if
            from a command-line with CommandLine(sys.argv).  If you're
            calling this directly, remember to provide a dummy value
            for sys.argv[0]
         """
+        global QUIETLY
+
         self.filename = None
         self.header_file = None
         self.impl_file = None
         self.factory = CCodeGenerator()
 
-        if len(argv) >= 2 and argv[1] == '--quiet':
-            global QUIETLY
-            QUIETLY = 1
-            del argv[1]
+        parser = argparse.ArgumentParser(
+            usage="%(prog)s [options] rpc-file [[h-file] c-file]"
+        )
+        parser.add_argument("--quiet", action="store_true", default=False)
+        parser.add_argument("rpc_file", type=argparse.FileType("r"))
+
+        args, extra_args = parser.parse_known_args(args=argv)
 
-        if len(argv) < 2 or len(argv) > 4:
-            raise Usage(argv[0])
+        QUIETLY = args.quiet
 
-        self.filename = argv[1].replace('\\', '/')
-        if len(argv) == 3:
-            self.impl_file = argv[2].replace('\\', '/')
-        if len(argv) == 4:
-            self.header_file = argv[2].replace('\\', '/')
-            self.impl_file = argv[3].replace('\\', '/')
+        if extra_args:
+            if len(extra_args) == 1:
+                self.impl_file = extra_args[0].replace("\\", "/")
+            elif len(extra_args) == 2:
+                self.header_file = extra_args[0].replace("\\", "/")
+                self.impl_file = extra_args[1].replace("\\", "/")
+            else:
+                parser.error("Spurious arguments provided")
 
-        if not self.filename:
-            raise Usage(argv[0])
+        self.rpc_file = args.rpc_file
 
         if not self.impl_file:
-            self.impl_file = self.factory.CodeFilename(self.filename)
+            self.impl_file = self.factory.CodeFilename(self.rpc_file.name)
 
         if not self.header_file:
             self.header_file = self.factory.HeaderFilename(self.impl_file)
 
-        if not self.impl_file.endswith('.c'):
-            raise RpcGenError("can only generate C implementation files")
-        if not self.header_file.endswith('.h'):
-            raise RpcGenError("can only generate C header files")
+        if not self.impl_file.endswith(".c"):
+            parser.error("can only generate C implementation files")
+        if not self.header_file.endswith(".h"):
+            parser.error("can only generate C header files")
 
     def run(self):
-        filename = self.filename
+        filename = self.rpc_file.name
         header_file = self.header_file
         impl_file = self.impl_file
         factory = self.factory
 
-        declare('Reading \"%s\"' % filename)
+        declare('Reading "%s"' % filename)
 
-        fp = open(filename, 'r')
-        entities = Parse(factory, fp)
-        fp.close()
+        with self.rpc_file:
+            entities = Parse(factory, self.rpc_file)
 
         declare('... creating "%s"' % header_file)
-        header_fp = open(header_file, 'w')
-        print >>header_fp, factory.HeaderPreamble(filename)
+        with open(header_file, "w") as header_fp:
+            header_fp.write(factory.HeaderPreamble(filename))
 
-        # Create forward declarations: allows other structs to reference
-        # each other
-        for entry in entities:
-            entry.PrintForwardDeclaration(header_fp)
-        print >>header_fp, ''
+            # Create forward declarations: allows other structs to reference
+            # each other
+            for entry in entities:
+                entry.PrintForwardDeclaration(header_fp)
+            header_fp.write("\n")
 
-        for entry in entities:
-            entry.PrintTags(header_fp)
-            entry.PrintDeclaration(header_fp)
-        print >>header_fp, factory.HeaderPostamble(filename)
-        header_fp.close()
+            for entry in entities:
+                entry.PrintTags(header_fp)
+                entry.PrintDeclaration(header_fp)
+            header_fp.write(factory.HeaderPostamble(filename))
 
         declare('... creating "%s"' % impl_file)
-        impl_fp = open(impl_file, 'w')
-        print >>impl_fp, factory.BodyPreamble(filename, header_file)
-        for entry in entities:
-            entry.PrintCode(impl_fp)
-        impl_fp.close()
+        with open(impl_file, "w") as impl_fp:
+            impl_fp.write(factory.BodyPreamble(filename, header_file))
+            for entry in entities:
+                entry.PrintCode(impl_fp)
 
-if __name__ == '__main__':
-    try:
-        CommandLine(sys.argv).run()
-        sys.exit(0)
-
-    except RpcGenError, e:
-        print >>sys.stderr, e
-        sys.exit(1)
 
-    except EnvironmentError, e:
+def main(argv=None):
+    try:
+        CommandLine(argv=argv).run()
+        return 0
+    except RpcGenError as e:
+        sys.stderr.write(e)
+    except EnvironmentError as e:
         if e.filename and e.strerror:
-            print >>sys.stderr, "%s: %s" % (e.filename, e.strerror)
-            sys.exit(1)
+            sys.stderr.write("%s: %s" % (e.filename, e.strerror))
         elif e.strerror:
-            print >> sys.stderr, e.strerror
-            sys.exit(1)
+            sys.stderr.write(e.strerror)
         else:
             raise
+    return 1
+
+
+if __name__ == "__main__":
+    sys.exit(main(argv=sys.argv[1:]))
index 64b100b82510aca72901afae7b78e6f0a61f239f..b021e8c8dea22073fb67caec6af7768397160e20 100644 (file)
 #include <winsock2.h>
 #include <windows.h>
 #undef WIN32_LEAN_AND_MEAN
-#else
-#include <sys/ioctl.h>
 #endif
 
+#ifdef EVENT__HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
 #include <sys/queue.h>
 #ifdef EVENT__HAVE_SYS_TIME_H
 #include <sys/time.h>
        a final padding nibble with value 0 is appended.
 */
 
+EVENT2_EXPORT_SYMBOL
 int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf);
+EVENT2_EXPORT_SYMBOL
 int evtag_decode_int64(ev_uint64_t *pnumber, struct evbuffer *evbuf);
+EVENT2_EXPORT_SYMBOL
 int evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag);
+EVENT2_EXPORT_SYMBOL
 int evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf);
 
 void
index 3f76dd0ae1f7024613be86fc91c8c6e3d7af087f..e4e35c6877f8b992ec6b377d15abab45abc13af1 100644 (file)
@@ -43,6 +43,7 @@
 #include <unistd.h>
 #endif
 #include <errno.h>
+#include <limits.h>
 #include <signal.h>
 #include <string.h>
 #include <time.h>
@@ -207,9 +208,15 @@ evmap_make_space(struct event_signal_map *map, int slot, int msize)
                int nentries = map->nentries ? map->nentries : 32;
                void **tmp;
 
+               if (slot > INT_MAX / 2)
+                       return (-1);
+
                while (nentries <= slot)
                        nentries <<= 1;
 
+               if (nentries > INT_MAX / msize)
+                       return (-1);
+
                tmp = (void **)mm_realloc(map->entries, nentries * msize);
                if (tmp == NULL)
                        return (-1);
@@ -393,7 +400,8 @@ evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev)
 
        if (res) {
                void *extra = ((char*)ctx) + sizeof(struct evmap_io);
-               if (evsel->del(base, ev->ev_fd, old, res, extra) == -1) {
+               if (evsel->del(base, ev->ev_fd,
+                       old, (ev->ev_events & EV_ET) | res, extra) == -1) {
                        retval = -1;
                } else {
                        retval = 1;
@@ -424,7 +432,7 @@ evmap_io_active_(struct event_base *base, evutil_socket_t fd, short events)
        if (NULL == ctx)
                return;
        LIST_FOREACH(ev, &ctx->events, ev_io_next) {
-               if (ev->ev_events & events)
+               if (ev->ev_events & (events & ~EV_ET))
                        event_active_nolock_(ev, ev->ev_events & events, 1);
        }
 }
@@ -445,6 +453,9 @@ evmap_signal_add_(struct event_base *base, int sig, struct event *ev)
        struct event_signal_map *map = &base->sigmap;
        struct evmap_signal *ctx = NULL;
 
+       if (sig < 0 || sig >= NSIG)
+               return (-1);
+
        if (sig >= map->nentries) {
                if (evmap_make_space(
                        map, sig, sizeof(struct evmap_signal *)) == -1)
@@ -471,7 +482,7 @@ evmap_signal_del_(struct event_base *base, int sig, struct event *ev)
        struct event_signal_map *map = &base->sigmap;
        struct evmap_signal *ctx;
 
-       if (sig >= map->nentries)
+       if (sig < 0 || sig >= map->nentries)
                return (-1);
 
        GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
@@ -858,6 +869,7 @@ event_changelist_add_(struct event_base *base, evutil_socket_t fd, short old, sh
        struct event_changelist *changelist = &base->changelist;
        struct event_changelist_fdinfo *fdinfo = p;
        struct event_change *change;
+       ev_uint8_t evchange = EV_CHANGE_ADD | (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
 
        event_changelist_check(base);
 
@@ -869,18 +881,12 @@ event_changelist_add_(struct event_base *base, evutil_socket_t fd, short old, sh
         * since the delete might fail (because the fd had been closed since
         * the last add, for instance. */
 
-       if (events & (EV_READ|EV_SIGNAL)) {
-               change->read_change = EV_CHANGE_ADD |
-                   (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
-       }
-       if (events & EV_WRITE) {
-               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));
-       }
+       if (events & (EV_READ|EV_SIGNAL))
+               change->read_change = evchange;
+       if (events & EV_WRITE)
+               change->write_change = evchange;
+       if (events & EV_CLOSED)
+               change->close_change = evchange;
 
        event_changelist_check(base);
        return (0);
@@ -893,6 +899,7 @@ event_changelist_del_(struct event_base *base, evutil_socket_t fd, short old, sh
        struct event_changelist *changelist = &base->changelist;
        struct event_changelist_fdinfo *fdinfo = p;
        struct event_change *change;
+       ev_uint8_t del = EV_CHANGE_DEL | (events & EV_ET);
 
        event_changelist_check(base);
        change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
@@ -919,19 +926,19 @@ event_changelist_del_(struct event_base *base, evutil_socket_t fd, short old, sh
                if (!(change->old_events & (EV_READ | EV_SIGNAL)))
                        change->read_change = 0;
                else
-                       change->read_change = EV_CHANGE_DEL;
+                       change->read_change = del;
        }
        if (events & EV_WRITE) {
                if (!(change->old_events & EV_WRITE))
                        change->write_change = 0;
                else
-                       change->write_change = EV_CHANGE_DEL;
+                       change->write_change = del;
        }
        if (events & EV_CLOSED) {
                if (!(change->old_events & EV_CLOSED))
                        change->close_change = 0;
                else
-                       change->close_change = EV_CHANGE_DEL;
+                       change->close_change = del;
        }
 
        event_changelist_check(base);
index 2443ab27937adfbeb8b750cdf960b56d4db7dba8..4a60ca5f0703fe551c4d1b6a8122370dea3d1b5a 100644 (file)
@@ -329,7 +329,8 @@ evrpc_request_cb(struct evhttp_request *req, void *arg)
        return;
 
 error:
-       evrpc_reqstate_free_(rpc_state);
+       if (rpc_state)
+               evrpc_reqstate_free_(rpc_state);
        evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
        return;
 }
@@ -891,8 +892,7 @@ evrpc_reply_done(struct evhttp_request *req, void *arg)
                         * layer is going to free it.  we need to
                         * request ownership explicitly
                         */
-                       if (req != NULL)
-                               evhttp_request_own(req);
+                       evhttp_request_own(req);
 
                        evrpc_pause_request(pool, ctx,
                            evrpc_reply_done_closure);
index efdecf81e7cd5a29cd57ad7c085188816e3c4ea6..83e409f09b4c83c0e22f3834161f3de6a4b095db 100644 (file)
@@ -38,7 +38,7 @@ extern "C" {
 
 struct event_base;
 
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(__CYGWIN__)
 /* On Windows, the way we currently make DLLs, it's not allowed for us to
  * have shared global structures.  Thus, we only do the direct-call-to-function
  * code path if we know that the local shared library system supports it.
@@ -49,9 +49,12 @@ struct event_base;
 #if ! defined(EVENT__DISABLE_THREAD_SUPPORT) && defined(EVTHREAD_EXPOSE_STRUCTS)
 /* Global function pointers to lock-related functions. NULL if locking isn't
    enabled. */
+EVENT2_EXPORT_SYMBOL
 extern struct evthread_lock_callbacks evthread_lock_fns_;
+EVENT2_EXPORT_SYMBOL
 extern struct evthread_condition_callbacks evthread_cond_fns_;
 extern unsigned long (*evthread_id_fn_)(void);
+EVENT2_EXPORT_SYMBOL
 extern int evthread_lock_debugging_enabled_;
 
 /** Return the ID of the current thread, or 1 if threading isn't enabled. */
@@ -182,14 +185,23 @@ EVLOCK_TRY_LOCK_(void *lock)
 #elif ! defined(EVENT__DISABLE_THREAD_SUPPORT)
 
 unsigned long evthreadimpl_get_id_(void);
+EVENT2_EXPORT_SYMBOL
 int evthreadimpl_is_lock_debugging_enabled_(void);
+EVENT2_EXPORT_SYMBOL
 void *evthreadimpl_lock_alloc_(unsigned locktype);
+EVENT2_EXPORT_SYMBOL
 void evthreadimpl_lock_free_(void *lock, unsigned locktype);
+EVENT2_EXPORT_SYMBOL
 int evthreadimpl_lock_lock_(unsigned mode, void *lock);
+EVENT2_EXPORT_SYMBOL
 int evthreadimpl_lock_unlock_(unsigned mode, void *lock);
+EVENT2_EXPORT_SYMBOL
 void *evthreadimpl_cond_alloc_(unsigned condtype);
+EVENT2_EXPORT_SYMBOL
 void evthreadimpl_cond_free_(void *cond);
+EVENT2_EXPORT_SYMBOL
 int evthreadimpl_cond_signal_(void *cond, int broadcast);
+EVENT2_EXPORT_SYMBOL
 int evthreadimpl_cond_wait_(void *cond, void *lock, const struct timeval *tv);
 int evthreadimpl_locking_enabled_(void);
 
@@ -355,6 +367,7 @@ EVLOCK_TRY_LOCK_(void *lock)
                EVLOCK_UNLOCK(lock1_tmplock_,mode1);                    \
        } while (0)
 
+EVENT2_EXPORT_SYMBOL
 int evthread_is_debug_lock_held_(void *lock);
 void *evthread_debug_get_real_lock_(void *lock);
 
@@ -377,6 +390,7 @@ int evutil_global_setup_locks_(const int enable_locks);
 int evutil_secure_rng_global_setup_locks_(const int enable_locks);
 
 /** Return current evthread_lock_callbacks */
+EVENT2_EXPORT_SYMBOL
 struct evthread_lock_callbacks *evthread_get_lock_callbacks(void);
 /** Return current evthread_condition_callbacks */
 struct evthread_condition_callbacks *evthread_get_condition_callbacks(void);
index 02dab7a8057e58f0fe64b0175ed016635d442eec..3eac594d64dc8967f599f872568c1b425d9cde67 100644 (file)
 #define GLOBAL static
 #endif
 
+#ifndef EVENT__DISABLE_DEBUG_MODE
+extern int event_debug_created_threadable_ctx_;
+extern int event_debug_mode_on_;
+#endif
+
 /* globals */
 GLOBAL int evthread_lock_debugging_enabled_ = 0;
 GLOBAL struct evthread_lock_callbacks evthread_lock_fns_ = {
@@ -89,6 +94,14 @@ evthread_set_lock_callbacks(const struct evthread_lock_callbacks *cbs)
 {
        struct evthread_lock_callbacks *target = evthread_get_lock_callbacks();
 
+#ifndef EVENT__DISABLE_DEBUG_MODE
+       if (event_debug_mode_on_) {
+               if (event_debug_created_threadable_ctx_) {
+                   event_errx(1, "evthread initialization must be called BEFORE anything else!");
+               }
+       }
+#endif
+
        if (!cbs) {
                if (target->alloc)
                        event_warnx("Trying to disable lock functions after "
@@ -124,6 +137,14 @@ evthread_set_condition_callbacks(const struct evthread_condition_callbacks *cbs)
 {
        struct evthread_condition_callbacks *target = evthread_get_condition_callbacks();
 
+#ifndef EVENT__DISABLE_DEBUG_MODE
+       if (event_debug_mode_on_) {
+               if (event_debug_created_threadable_ctx_) {
+                   event_errx(1, "evthread initialization must be called BEFORE anything else!");
+               }
+       }
+#endif
+
        if (!cbs) {
                if (target->alloc_condition)
                        event_warnx("Trying to disable condition functions "
@@ -380,17 +401,18 @@ evthread_setup_global_lock_(void *lock_, unsigned locktype, int enable_locks)
                return evthread_lock_fns_.alloc(locktype);
        } else {
                /* Case 4: Fill in a debug lock with a real lock */
-               struct debug_lock *lock = lock_;
+               struct debug_lock *lock = lock_ ? lock_ : debug_lock_alloc(locktype);
                EVUTIL_ASSERT(enable_locks &&
                              evthread_lock_debugging_enabled_);
                EVUTIL_ASSERT(lock->locktype == locktype);
-               EVUTIL_ASSERT(lock->lock == NULL);
-               lock->lock = original_lock_fns_.alloc(
-                       locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
                if (!lock->lock) {
-                       lock->count = -200;
-                       mm_free(lock);
-                       return NULL;
+                       lock->lock = original_lock_fns_.alloc(
+                               locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
+                       if (!lock->lock) {
+                               lock->count = -200;
+                               mm_free(lock);
+                               return NULL;
+                       }
                }
                return lock;
        }
@@ -406,6 +428,12 @@ evthreadimpl_get_id_()
 void *
 evthreadimpl_lock_alloc_(unsigned locktype)
 {
+#ifndef EVENT__DISABLE_DEBUG_MODE
+       if (event_debug_mode_on_) {
+               event_debug_created_threadable_ctx_ = 1;
+       }
+#endif
+
        return evthread_lock_fns_.alloc ?
            evthread_lock_fns_.alloc(locktype) : NULL;
 }
@@ -434,6 +462,12 @@ evthreadimpl_lock_unlock_(unsigned mode, void *lock)
 void *
 evthreadimpl_cond_alloc_(unsigned condtype)
 {
+#ifndef EVENT__DISABLE_DEBUG_MODE
+       if (event_debug_mode_on_) {
+               event_debug_created_threadable_ctx_ = 1;
+       }
+#endif
+
        return evthread_cond_fns_.alloc_condition ?
            evthread_cond_fns_.alloc_condition(condtype) : NULL;
 }
index 3d72e4032450d89498ad84467aaa8df4ec848abc..9817f086433d5e070fd88bd9d2fe40f416a6790d 100644 (file)
@@ -29,6 +29,7 @@
 
 #ifdef _WIN32
 #include <winsock2.h>
+#include <winerror.h>
 #include <ws2tcpip.h>
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
@@ -40,6 +41,7 @@
 /* For structs needed by GetAdaptersAddresses */
 #define _WIN32_WINNT 0x0501
 #include <iphlpapi.h>
+#include <netioapi.h>
 #endif
 
 #include <sys/types.h>
@@ -73,6 +75,9 @@
 #endif
 #include <time.h>
 #include <sys/stat.h>
+#ifndef _WIN32
+#include <net/if.h>
+#endif
 #ifdef EVENT__HAVE_IFADDRS_H
 #include <ifaddrs.h>
 #endif
@@ -226,16 +231,17 @@ evutil_ersatz_socketpair_(int family, int type, int protocol,
        struct sockaddr_in connect_addr;
        ev_socklen_t size;
        int saved_errno = -1;
-
-       if (protocol
-               || (family != AF_INET
+       int family_test;
+       
+       family_test = family != AF_INET;
 #ifdef AF_UNIX
-                   && family != AF_UNIX
+       family_test = family_test && (family != AF_UNIX);
 #endif
-               )) {
+       if (protocol || family_test) {
                EVUTIL_SET_SOCKET_ERROR(ERR(EAFNOSUPPORT));
                return -1;
        }
+       
        if (!fd) {
                EVUTIL_SET_SOCKET_ERROR(ERR(EINVAL));
                return -1;
@@ -257,6 +263,9 @@ evutil_ersatz_socketpair_(int family, int type, int protocol,
        connector = socket(AF_INET, type, 0);
        if (connector < 0)
                goto tidy_up_and_fail;
+
+       memset(&connect_addr, 0, sizeof(connect_addr));
+
        /* We want to find out the port number to connect to.  */
        size = sizeof(connect_addr);
        if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1)
@@ -310,7 +319,7 @@ evutil_make_socket_nonblocking(evutil_socket_t fd)
 {
 #ifdef _WIN32
        {
-               u_long nonblocking = 1;
+               unsigned long nonblocking = 1;
                if (ioctlsocket(fd, FIONBIO, &nonblocking) == SOCKET_ERROR) {
                        event_sock_warn(fd, "fcntl(%d, F_GETFL)", (int)fd);
                        return -1;
@@ -355,7 +364,7 @@ evutil_fast_socket_nonblocking(evutil_socket_t fd)
 int
 evutil_make_listen_socket_reuseable(evutil_socket_t sock)
 {
-#ifndef _WIN32
+#if defined(SO_REUSEADDR) && !defined(_WIN32)
        int one = 1;
        /* REUSEADDR on Unix means, "don't hang on to this address after the
         * listener is closed."  On Windows, though, it means "don't keep other
@@ -381,6 +390,17 @@ evutil_make_listen_socket_reuseable_port(evutil_socket_t sock)
 #endif
 }
 
+int
+evutil_make_listen_socket_ipv6only(evutil_socket_t sock)
+{
+#if defined(IPV6_V6ONLY)
+       int one = 1;
+       return setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void*) &one,
+           (ev_socklen_t)sizeof(one));
+#endif
+       return 0;
+}
+
 int
 evutil_make_tcp_listen_socket_deferred(evutil_socket_t sock)
 {
@@ -520,7 +540,7 @@ evutil_socket_geterror(evutil_socket_t sock)
 /* XXX we should use an enum here. */
 /* 2 for connection refused, 1 for connected, 0 for not yet, -1 for error. */
 int
-evutil_socket_connect_(evutil_socket_t *fd_ptr, struct sockaddr *sa, int socklen)
+evutil_socket_connect_(evutil_socket_t *fd_ptr, const struct sockaddr *sa, int socklen)
 {
        int made_fd = 0;
 
@@ -591,44 +611,56 @@ evutil_socket_finished_connecting_(evutil_socket_t fd)
    set by evutil_check_interfaces. */
 static int have_checked_interfaces, had_ipv4_address, had_ipv6_address;
 
-/* Macro: True iff the IPv4 address 'addr', in host order, is in 127.0.0.0/8
- */
-#define EVUTIL_V4ADDR_IS_LOCALHOST(addr) (((addr)>>24) == 127)
+/* True iff the IPv4 address 'addr', in host order, is in 127.0.0.0/8 */
+static inline int evutil_v4addr_is_localhost(ev_uint32_t addr)
+{ return addr>>24 == 127; }
 
-/* Macro: True iff the IPv4 address 'addr', in host order, is a class D
- * (multiclass) address.
- */
-#define EVUTIL_V4ADDR_IS_CLASSD(addr) ((((addr)>>24) & 0xf0) == 0xe0)
+/* True iff the IPv4 address 'addr', in host order, is link-local
+ * 169.254.0.0/16 (RFC3927) */
+static inline int evutil_v4addr_is_linklocal(ev_uint32_t addr)
+{ return ((addr & 0xffff0000U) == 0xa9fe0000U); }
+
+/* True iff the IPv4 address 'addr', in host order, is a class D
+ * (multiclass) address.  */
+static inline int evutil_v4addr_is_classd(ev_uint32_t addr)
+{ return ((addr>>24) & 0xf0) == 0xe0; }
+
+int
+evutil_v4addr_is_local_(const struct in_addr *in)
+{
+       const ev_uint32_t addr = ntohl(in->s_addr);
+       return addr == INADDR_ANY ||
+               evutil_v4addr_is_localhost(addr) ||
+               evutil_v4addr_is_linklocal(addr) ||
+               evutil_v4addr_is_classd(addr);
+}
+int
+evutil_v6addr_is_local_(const struct in6_addr *in)
+{
+       static const char ZEROES[] =
+               "\x00\x00\x00\x00\x00\x00\x00\x00"
+               "\x00\x00\x00\x00\x00\x00\x00\x00";
+
+       const unsigned char *addr = (const unsigned char *)in->s6_addr;
+       return !memcmp(addr, ZEROES, 8) ||
+               ((addr[0] & 0xfe) == 0xfc) ||
+               (addr[0] == 0xfe && (addr[1] & 0xc0) == 0x80) ||
+               (addr[0] == 0xfe && (addr[1] & 0xc0) == 0xc0) ||
+               (addr[0] == 0xff);
+}
 
 static void
 evutil_found_ifaddr(const struct sockaddr *sa)
 {
-       const char ZEROES[] = "\x00\x00\x00\x00\x00\x00\x00\x00"
-           "\x00\x00\x00\x00\x00\x00\x00\x00";
-
        if (sa->sa_family == AF_INET) {
                const struct sockaddr_in *sin = (struct sockaddr_in *)sa;
-               ev_uint32_t addr = ntohl(sin->sin_addr.s_addr);
-               if (addr == 0 ||
-                   EVUTIL_V4ADDR_IS_LOCALHOST(addr) ||
-                   EVUTIL_V4ADDR_IS_CLASSD(addr)) {
-                       /* Not actually a usable external address. */
-               } else {
+               if (!evutil_v4addr_is_local_(&sin->sin_addr)) {
                        event_debug(("Detected an IPv4 interface"));
                        had_ipv4_address = 1;
                }
        } else if (sa->sa_family == AF_INET6) {
                const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
-               const unsigned char *addr =
-                   (unsigned char*)sin6->sin6_addr.s6_addr;
-               if (!memcmp(addr, ZEROES, 8) ||
-                   ((addr[0] & 0xfe) == 0xfc) ||
-                   (addr[0] == 0xfe && (addr[1] & 0xc0) == 0x80) ||
-                   (addr[0] == 0xfe && (addr[1] & 0xc0) == 0xc0) ||
-                   (addr[0] == 0xff)) {
-                       /* This is a reserved, ipv4compat, ipv4map, loopback,
-                        * link-local, multicast, or unspecified address. */
-               } else {
+               if (!evutil_v6addr_is_local_(&sin6->sin6_addr)) {
                        event_debug(("Detected an IPv6 interface"));
                        had_ipv6_address = 1;
                }
@@ -666,7 +698,7 @@ evutil_check_ifaddrs(void)
           "GetAdaptersInfo", but that's deprecated; let's just try
           GetAdaptersAddresses and fall back to connect+getsockname.
        */
-       HMODULE lib = evutil_load_windows_system_library_(TEXT("ihplapi.dll"));
+       HMODULE lib = evutil_load_windows_system_library_(TEXT("iphlpapi.dll"));
        GetAdaptersAddresses_fn_t fn;
        ULONG size, res;
        IP_ADAPTER_ADDRESSES *addresses = NULL, *address;
@@ -723,7 +755,7 @@ done:
 /* Test whether we have an ipv4 interface and an ipv6 interface.  Return 0 if
  * the test seemed successful. */
 static int
-evutil_check_interfaces(int force_recheck)
+evutil_check_interfaces(void)
 {
        evutil_socket_t fd = -1;
        struct sockaddr_in sin, sin_out;
@@ -731,9 +763,12 @@ evutil_check_interfaces(int force_recheck)
        ev_socklen_t sin_out_len = sizeof(sin_out);
        ev_socklen_t sin6_out_len = sizeof(sin6_out);
        int r;
-       if (have_checked_interfaces && !force_recheck)
+       if (have_checked_interfaces)
                return 0;
 
+       /* From this point on we have done the ipv4/ipv6 interface check */
+       have_checked_interfaces = 1;
+
        if (evutil_check_ifaddrs() == 0) {
                /* Use a nice sane interface, if this system has one. */
                return 0;
@@ -959,6 +994,7 @@ evutil_getaddrinfo_common_(const char *nodename, const char *servname,
     struct evutil_addrinfo *hints, struct evutil_addrinfo **res, int *portnum)
 {
        int port = 0;
+       unsigned int if_index;
        const char *pname;
 
        if (nodename == NULL && servname == NULL)
@@ -1032,10 +1068,12 @@ evutil_getaddrinfo_common_(const char *nodename, const char *servname,
        if (hints->ai_family == PF_INET6 || hints->ai_family == PF_UNSPEC) {
                struct sockaddr_in6 sin6;
                memset(&sin6, 0, sizeof(sin6));
-               if (1==evutil_inet_pton(AF_INET6, nodename, &sin6.sin6_addr)) {
+               if (1 == evutil_inet_pton_scope(
+                       AF_INET6, nodename, &sin6.sin6_addr, &if_index)) {
                        /* Got an ipv6 address. */
                        sin6.sin6_family = AF_INET6;
                        sin6.sin6_port = htons(port);
+                       sin6.sin6_scope_id = if_index;
                        *res = evutil_new_addrinfo_((struct sockaddr*)&sin6,
                            sizeof(sin6), hints);
                        if (!*res)
@@ -1049,7 +1087,7 @@ evutil_getaddrinfo_common_(const char *nodename, const char *servname,
                struct sockaddr_in sin;
                memset(&sin, 0, sizeof(sin));
                if (1==evutil_inet_pton(AF_INET, nodename, &sin.sin_addr)) {
-                       /* Got an ipv6 address. */
+                       /* Got an ipv4 address. */
                        sin.sin_family = AF_INET;
                        sin.sin_port = htons(port);
                        *res = evutil_new_addrinfo_((struct sockaddr*)&sin,
@@ -1159,7 +1197,7 @@ addrinfo_from_hostent(const struct hostent *ent,
                sin6.sin6_family = AF_INET6;
                sin6.sin6_port = htons(port);
                sa = (struct sockaddr *)&sin6;
-               socklen = sizeof(struct sockaddr_in);
+               socklen = sizeof(struct sockaddr_in6);
                addrp = &sin6.sin6_addr;
                if (ent->h_length != sizeof(sin6.sin6_addr)) {
                        event_warnx("Weird h_length from gethostbyname");
@@ -1201,8 +1239,7 @@ evutil_adjust_hints_for_addrconfig_(struct evutil_addrinfo *hints)
                return;
        if (hints->ai_family != PF_UNSPEC)
                return;
-       if (!have_checked_interfaces)
-               evutil_check_interfaces(0);
+       evutil_check_interfaces();
        if (had_ipv4_address && !had_ipv6_address) {
                hints->ai_family = PF_INET;
        } else if (!had_ipv4_address && had_ipv6_address) {
@@ -1234,11 +1271,20 @@ static int tested_for_getaddrinfo_hacks=0;
      field set to 0.  We test for this so we can apply an appropriate
      workaround.
 */
+static struct evutil_addrinfo *ai_find_protocol(struct evutil_addrinfo *ai)
+{
+       while (ai) {
+               if (ai->ai_protocol)
+                       return ai;
+               ai = ai->ai_next;
+       }
+       return NULL;
+}
 static void
 test_for_getaddrinfo_hacks(void)
 {
        int r, r2;
-       struct evutil_addrinfo *ai=NULL, *ai2=NULL;
+       struct evutil_addrinfo *ai=NULL, *ai2=NULL, *ai3=NULL;
        struct evutil_addrinfo hints;
 
        memset(&hints,0,sizeof(hints));
@@ -1252,12 +1298,13 @@ test_for_getaddrinfo_hacks(void)
 #endif
            0;
        r = getaddrinfo("1.2.3.4", "80", &hints, &ai);
+       getaddrinfo("1.2.3.4", NULL, &hints, &ai3);
        hints.ai_socktype = SOCK_STREAM;
        r2 = getaddrinfo("1.2.3.4", "80", &hints, &ai2);
        if (r2 == 0 && r != 0) {
                need_numeric_port_hack_=1;
        }
-       if (ai2 && ai2->ai_protocol == 0) {
+       if (!ai_find_protocol(ai2) || !ai_find_protocol(ai3)) {
                need_socktype_protocol_hack_=1;
        }
 
@@ -1265,6 +1312,8 @@ test_for_getaddrinfo_hacks(void)
                freeaddrinfo(ai);
        if (ai2)
                freeaddrinfo(ai2);
+       if (ai3)
+               freeaddrinfo(ai3);
        tested_for_getaddrinfo_hacks=1;
 }
 
@@ -1542,6 +1591,7 @@ evutil_freeaddrinfo(struct evutil_addrinfo *ai)
 }
 
 static evdns_getaddrinfo_fn evdns_getaddrinfo_impl = NULL;
+static evdns_getaddrinfo_cancel_fn evdns_getaddrinfo_cancel_impl = NULL;
 
 void
 evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo_fn fn)
@@ -1549,27 +1599,40 @@ evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo_fn fn)
        if (!evdns_getaddrinfo_impl)
                evdns_getaddrinfo_impl = fn;
 }
+void
+evutil_set_evdns_getaddrinfo_cancel_fn_(evdns_getaddrinfo_cancel_fn fn)
+{
+       if (!evdns_getaddrinfo_cancel_impl)
+               evdns_getaddrinfo_cancel_impl = fn;
+}
 
 /* Internal helper function: act like evdns_getaddrinfo if dns_base is set;
  * otherwise do a blocking resolve and pass the result to the callback in the
  * way that evdns_getaddrinfo would.
  */
-int
-evutil_getaddrinfo_async_(struct evdns_base *dns_base,
+struct evdns_getaddrinfo_request *evutil_getaddrinfo_async_(
+    struct evdns_base *dns_base,
     const char *nodename, const char *servname,
     const struct evutil_addrinfo *hints_in,
     void (*cb)(int, struct evutil_addrinfo *, void *), void *arg)
 {
        if (dns_base && evdns_getaddrinfo_impl) {
-               evdns_getaddrinfo_impl(
+               return evdns_getaddrinfo_impl(
                        dns_base, nodename, servname, hints_in, cb, arg);
        } else {
                struct evutil_addrinfo *ai=NULL;
                int err;
                err = evutil_getaddrinfo(nodename, servname, hints_in, &ai);
                cb(err, ai, arg);
+               return NULL;
+       }
+}
+
+void evutil_getaddrinfo_cancel_async_(struct evdns_getaddrinfo_request *data)
+{
+       if (evdns_getaddrinfo_cancel_impl && data) {
+               evdns_getaddrinfo_cancel_impl(data);
        }
-       return 0;
 }
 
 const char *
@@ -1705,10 +1768,10 @@ evutil_socket_error_to_string(int errcode)
                goto done;
        }
 
-       if (0 != FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+       if (0 != FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
                               FORMAT_MESSAGE_IGNORE_INSERTS |
                               FORMAT_MESSAGE_ALLOCATE_BUFFER,
-                              NULL, errcode, 0, (LPTSTR)&msg, 0, NULL))
+                              NULL, errcode, 0, (char *)&msg, 0, NULL))
                chomp (msg);    /* because message has trailing newline */
        else {
                size_t len = 50;
@@ -1925,6 +1988,41 @@ evutil_inet_ntop(int af, const void *src, char *dst, size_t len)
 #endif
 }
 
+int
+evutil_inet_pton_scope(int af, const char *src, void *dst, unsigned *indexp)
+{
+       int r;
+       unsigned if_index;
+       char *check, *cp, *tmp_src;
+
+       *indexp = 0; /* Reasonable default */
+
+       /* Bail out if not IPv6 */
+       if (af != AF_INET6)
+               return evutil_inet_pton(af, src, dst);
+
+       cp = strchr(src, '%');
+
+       /* Bail out if no zone ID */
+       if (cp == NULL)
+               return evutil_inet_pton(af, src, dst);
+
+       if_index = if_nametoindex(cp + 1);
+       if (if_index == 0) {
+               /* Could be numeric */
+               if_index = strtoul(cp + 1, &check, 10);
+               if (check[0] != '\0')
+                       return 0;
+       }
+       *indexp = if_index;
+       tmp_src = mm_strdup(src);
+       cp = strchr(tmp_src, '%');
+       *cp = '\0';
+       r = evutil_inet_pton(af, tmp_src, dst);
+       free(tmp_src);
+       return r;
+}
+
 int
 evutil_inet_pton(int af, const char *src, void *dst)
 {
@@ -2041,6 +2139,7 @@ int
 evutil_parse_sockaddr_port(const char *ip_as_string, struct sockaddr *out, int *outlen)
 {
        int port;
+       unsigned int if_index;
        char buf[128];
        const char *cp, *addr_part, *port_part;
        int is_ipv6;
@@ -2054,12 +2153,12 @@ evutil_parse_sockaddr_port(const char *ip_as_string, struct sockaddr *out, int *
 
        cp = strchr(ip_as_string, ':');
        if (*ip_as_string == '[') {
-               int len;
+               size_t len;
                if (!(cp = strchr(ip_as_string, ']'))) {
                        return -1;
                }
-               len = (int) ( cp-(ip_as_string + 1) );
-               if (len > (int)sizeof(buf)-1) {
+               len = ( cp-(ip_as_string + 1) );
+               if (len > sizeof(buf)-1) {
                        return -1;
                }
                memcpy(buf, ip_as_string+1, len);
@@ -2110,10 +2209,13 @@ evutil_parse_sockaddr_port(const char *ip_as_string, struct sockaddr *out, int *
 #endif
                sin6.sin6_family = AF_INET6;
                sin6.sin6_port = htons(port);
-               if (1 != evutil_inet_pton(AF_INET6, addr_part, &sin6.sin6_addr))
+               if (1 != evutil_inet_pton_scope(
+                       AF_INET6, addr_part, &sin6.sin6_addr, &if_index)) {
                        return -1;
+               }
                if ((int)sizeof(sin6) > *outlen)
                        return -1;
+               sin6.sin6_scope_id = if_index;
                memset(out, 0, *outlen);
                memcpy(out, &sin6, sizeof(sin6));
                *outlen = sizeof(sin6);
@@ -2267,7 +2369,7 @@ static const unsigned char EVUTIL_TOLOWER_TABLE[256] = {
 #define IMPL_CTYPE_FN(name)                                            \
        int EVUTIL_##name##_(char c) {                                  \
                ev_uint8_t u = c;                                       \
-               return !!(EVUTIL_##name##_TABLE[(u >> 5) & 7] & (1 << (u & 31))); \
+               return !!(EVUTIL_##name##_TABLE[(u >> 5) & 7] & (1U << (u & 31))); \
        }
 IMPL_CTYPE_FN(ISALPHA)
 IMPL_CTYPE_FN(ISALNUM)
@@ -2563,7 +2665,7 @@ evutil_accept4_(evutil_socket_t sockfd, struct sockaddr *addr,
 }
 
 /* Internal function: Set fd[0] and fd[1] to a pair of fds such that writes on
- * fd[0] get read from fd[1].  Make both fds nonblocking and close-on-exec.
+ * fd[1] get read from fd[0].  Make both fds nonblocking and close-on-exec.
  * Return 0 on success, -1 on failure.
  */
 int
index 046a14b07a9a637b2096cd95f129e38dd1196685..8e9afdaa67535748697ff93d5a4dc1c05fc9ea7c 100644 (file)
@@ -171,9 +171,7 @@ evutil_secure_rng_init(void)
        int val;
 
        ARC4_LOCK_();
-       if (!arc4_seeded_ok)
-               arc4_stir();
-       val = arc4_seeded_ok ? 0 : -1;
+       val = (!arc4_stir()) ? 0 : -1;
        ARC4_UNLOCK_();
        return val;
 }
@@ -192,12 +190,14 @@ evutil_secure_rng_get_bytes(void *buf, size_t n)
        ev_arc4random_buf(buf, n);
 }
 
+#if !defined(EVENT__HAVE_ARC4RANDOM) || defined(EVENT__HAVE_ARC4RANDOM_ADDRANDOM)
 void
 evutil_secure_rng_add_bytes(const char *buf, size_t n)
 {
        arc4random_addrandom((unsigned char*)buf,
            n>(size_t)INT_MAX ? INT_MAX : (int)n);
 }
+#endif
 
 void
 evutil_free_secure_rng_globals_(void)
index 8f53c66b68c0e403fd8f4d53cb73117dd75d03bb..c327218227a45c97d057c3efc50209302ed9eab1 100644 (file)
@@ -43,7 +43,7 @@
 #ifndef EVENT__HAVE_GETTIMEOFDAY
 #include <sys/timeb.h>
 #endif
-#if !defined(EVENT__HAVE_NANOSLEEP) && !defined(EVENT_HAVE_USLEEP) && \
+#if !defined(EVENT__HAVE_NANOSLEEP) && !defined(EVENT__HAVE_USLEEP) && \
        !defined(_WIN32)
 #include <sys/select.h>
 #endif
 #include <sys/stat.h>
 #include <string.h>
 
+/** evutil_usleep_() */
+#if defined(_WIN32)
+#elif defined(EVENT__HAVE_NANOSLEEP)
+#elif defined(EVENT__HAVE_USLEEP)
+#include <unistd.h>
+#endif
+
 #include "event2/util.h"
 #include "util-internal.h"
 #include "log-internal.h"
@@ -58,6 +65,9 @@
 
 #ifndef EVENT__HAVE_GETTIMEOFDAY
 /* No gettimeofday; this must be windows. */
+
+typedef void (WINAPI *GetSystemTimePreciseAsFileTime_fn_t) (LPFILETIME);
+
 int
 evutil_gettimeofday(struct timeval *tv, struct timezone *tz)
 {
@@ -83,7 +93,22 @@ evutil_gettimeofday(struct timeval *tv, struct timezone *tz)
        if (tv == NULL)
                return -1;
 
-       GetSystemTimeAsFileTime(&ft.ft_ft);
+       static GetSystemTimePreciseAsFileTime_fn_t GetSystemTimePreciseAsFileTime_fn = NULL;
+       static int check_precise = 1;
+
+       if (EVUTIL_UNLIKELY(check_precise)) {
+               HMODULE h = evutil_load_windows_system_library_(TEXT("kernel32.dll"));
+               if (h != NULL)
+                       GetSystemTimePreciseAsFileTime_fn =
+                               (GetSystemTimePreciseAsFileTime_fn_t)
+                                       GetProcAddress(h, "GetSystemTimePreciseAsFileTime");
+               check_precise = 0;
+       }
+
+       if (GetSystemTimePreciseAsFileTime_fn != NULL)
+               GetSystemTimePreciseAsFileTime_fn(&ft.ft_ft);
+       else
+               GetSystemTimeAsFileTime(&ft.ft_ft);
 
        if (EVUTIL_UNLIKELY(ft.ft_64 < EPOCH_BIAS)) {
                /* Time before the unix epoch. */
@@ -119,8 +144,22 @@ evutil_usleep_(const struct timeval *tv)
                return;
 #if defined(_WIN32)
        {
-               long msec = evutil_tv_to_msec_(tv);
-               Sleep((DWORD)msec);
+               __int64 usec;
+               LARGE_INTEGER li;
+               HANDLE timer;
+
+               usec = tv->tv_sec * 1000000LL + tv->tv_usec;
+               if (!usec)
+                       return;
+
+               li.QuadPart = -10LL * usec;
+               timer = CreateWaitableTimer(NULL, TRUE, NULL);
+               if (!timer)
+                       return;
+
+               SetWaitableTimer(timer, &li, 0, NULL, NULL, 0);
+               WaitForSingleObject(timer, INFINITE);
+               CloseHandle(timer);
        }
 #elif defined(EVENT__HAVE_NANOSLEEP)
        {
@@ -134,10 +173,54 @@ evutil_usleep_(const struct timeval *tv)
        sleep(tv->tv_sec);
        usleep(tv->tv_usec);
 #else
-       select(0, NULL, NULL, NULL, tv);
+       {
+               struct timeval tv2 = *tv;
+               select(0, NULL, NULL, NULL, &tv2);
+       }
 #endif
 }
 
+int
+evutil_date_rfc1123(char *date, const size_t datelen, const struct tm *tm)
+{
+       static const char *DAYS[] =
+               { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+       static const char *MONTHS[] =
+               { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+       time_t t = time(NULL);
+
+#if defined(EVENT__HAVE__GMTIME64_S) || !defined(_WIN32)
+       struct tm sys;
+#endif
+
+       /* If `tm` is null, set system's current time. */
+       if (tm == NULL) {
+#if !defined(_WIN32)
+               gmtime_r(&t, &sys);
+               tm = &sys;
+               /** detect _gmtime64()/_gmtime64_s() */
+#elif defined(EVENT__HAVE__GMTIME64_S)
+               errno_t err;
+               err = _gmtime64_s(&sys, &t);
+               if (err) {
+                       event_errx(1, "Invalid argument to _gmtime64_s");
+               } else {
+                       tm = &sys;
+               }
+#elif defined(EVENT__HAVE__GMTIME64)
+               tm = _gmtime64(&t);
+#else
+               tm = gmtime(&t);
+#endif
+       }
+
+       return evutil_snprintf(
+               date, datelen, "%s, %02d %s %4d %02d:%02d:%02d GMT",
+               DAYS[tm->tm_wday], tm->tm_mday, MONTHS[tm->tm_mon],
+               1900 + tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec);
+}
+
 /*
    This function assumes it's called repeatedly with a
    not-actually-so-monotonic time source whose outputs are in 'tv'. It
index a83160c8341b8ae9e348f15526c13356c2581b7a..feaf436d7421acf7b62c7b671a4ed13400ddc807 100644 (file)
@@ -18,9 +18,6 @@
 #define HTTP_WRITE_TIMEOUT     50
 #define HTTP_READ_TIMEOUT      50
 
-#define HTTP_PREFIX            "http://"
-#define HTTP_DEFAULTPORT       80
-
 enum message_read_status {
        ALL_DATA_READ = 1,
        MORE_DATA_EXPECTED = 0,
@@ -62,19 +59,23 @@ struct evhttp_connection {
        struct event retry_ev;          /* for retrying connects */
 
        char *bind_address;             /* address to use for binding the src */
-       u_short bind_port;              /* local port for binding the src */
+       ev_uint16_t bind_port;          /* local port for binding the src */
 
        char *address;                  /* address to connect to */
-       u_short port;
+       ev_uint16_t port;
 
        size_t max_headers_size;
        ev_uint64_t max_body_size;
 
        int flags;
-#define EVHTTP_CON_INCOMING    0x0001  /* only one request on it ever */
-#define EVHTTP_CON_OUTGOING    0x0002  /* multiple requests possible */
-#define EVHTTP_CON_CLOSEDETECT  0x0004  /* detecting if persistent close */
-#define EVHTTP_CON_AUTOFREE 0x0008  /* set when we want to auto free the connection */
+#define EVHTTP_CON_INCOMING    0x0001       /* only one request on it ever */
+#define EVHTTP_CON_OUTGOING    0x0002       /* multiple requests possible */
+#define EVHTTP_CON_CLOSEDETECT 0x0004   /* detecting if persistent close */
+/* set when we want to auto free the connection */
+#define EVHTTP_CON_AUTOFREE    EVHTTP_CON_PUBLIC_FLAGS_END
+/* Installed when attempt to read HTTP error after write failed, see
+ * EVHTTP_CON_READ_ON_WRITE_ERROR */
+#define EVHTTP_CON_READING_ERROR       (EVHTTP_CON_AUTOFREE << 1)
 
        struct timeval timeout;         /* timeout for events */
        int retry_cnt;                  /* retry count */
@@ -101,13 +102,6 @@ struct evhttp_connection {
        struct event_base *base;
        struct evdns_base *dns_base;
        int ai_family;
-
-       /* Saved conn_addr, to extract IP address from it.
-        *
-        * Because some servers may reset/close connection without waiting clients,
-        * in that case we can't extract IP address even in close_cb.
-        * So we need to save it, just after we connected to remote server. */
-       struct sockaddr_storage *conn_address;
 };
 
 /* A callback for an http server */
@@ -160,6 +154,7 @@ struct evhttp {
 
        size_t default_max_headers_size;
        ev_uint64_t default_max_body_size;
+       int flags;
        const char *default_content_type;
 
        /* Bitmask of all HTTP methods that we accept and pass to user
@@ -186,21 +181,26 @@ int evhttp_connection_connect_(struct evhttp_connection *);
 
 enum evhttp_request_error;
 /* notifies the current request that it failed; resets connection */
+EVENT2_EXPORT_SYMBOL
 void evhttp_connection_fail_(struct evhttp_connection *,
     enum evhttp_request_error error);
 
 enum message_read_status;
 
+EVENT2_EXPORT_SYMBOL
 enum message_read_status evhttp_parse_firstline_(struct evhttp_request *, struct evbuffer*);
+EVENT2_EXPORT_SYMBOL
 enum message_read_status evhttp_parse_headers_(struct evhttp_request *, struct evbuffer*);
 
 void evhttp_start_read_(struct evhttp_connection *);
+void evhttp_start_write_(struct evhttp_connection *);
 
 /* response sending HTML the data in the buffer */
 void evhttp_response_code_(struct evhttp_request *, int, const char *);
 void evhttp_send_page_(struct evhttp_request *, struct evbuffer *);
 
+EVENT2_EXPORT_SYMBOL
 int evhttp_decode_uri_internal(const char *uri, size_t length,
     char *ret, int decode_plus);
 
-#endif /* _HTTP_H */
+#endif /* HTTP_INTERNAL_H_INCLUDED_ */
index dd8c9cffddfc77905f56038ee0cf50d0879d8089..04f089bc01825135ee6d09e7bff87142176407cd 100644 (file)
 #include <sys/types.h>
 #endif
 
+#ifdef HAVE_SYS_IOCCOM_H
+#include <sys/ioccom.h>
+#endif
+#ifdef EVENT__HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
 #ifdef EVENT__HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
-#ifdef HAVE_SYS_IOCCOM_H
-#include <sys/ioccom.h>
+#ifdef EVENT__HAVE_SYS_WAIT_H
+#include <sys/wait.h>
 #endif
 
 #ifndef _WIN32
-#include <sys/resource.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
-#include <sys/wait.h>
-#else
+#else /* _WIN32 */
 #include <winsock2.h>
 #include <ws2tcpip.h>
+#endif /* _WIN32 */
+
+#ifdef EVENT__HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#ifdef EVENT__HAVE_AFUNIX_H
+#include <afunix.h>
 #endif
 
 #include <sys/queue.h>
@@ -74,9 +85,8 @@
 #include <string.h>
 #ifndef _WIN32
 #include <syslog.h>
-#endif
+#endif /* !_WIN32 */
 #include <signal.h>
-#include <time.h>
 #ifdef EVENT__HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -167,9 +177,10 @@ fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
 
 extern int debug;
 
-static evutil_socket_t bind_socket_ai(struct evutil_addrinfo *, int reuse);
+static evutil_socket_t create_bind_socket_nonblock(struct evutil_addrinfo *, int reuse);
 static evutil_socket_t bind_socket(const char *, ev_uint16_t, int reuse);
 static void name_from_addr(struct sockaddr *, ev_socklen_t, char **, char **);
+static struct evhttp_uri *evhttp_uri_parse_authority(char *source_uri);
 static int evhttp_associate_new_request_with_connection(
        struct evhttp_connection *evcon);
 static void evhttp_connection_start_detectclose(
@@ -347,6 +358,7 @@ evhttp_response_needs_body(struct evhttp_request *req)
        return (req->response_code != HTTP_NOCONTENT &&
                req->response_code != HTTP_NOTMODIFIED &&
                (req->response_code < 100 || req->response_code >= 200) &&
+               req->type != EVHTTP_REQ_CONNECT &&
                req->type != EVHTTP_REQ_HEAD);
 }
 
@@ -365,15 +377,15 @@ evhttp_write_buffer(struct evhttp_connection *evcon,
        evcon->cb_arg = arg;
 
        /* Disable the read callback: we don't actually care about data;
-        * we only care about close detection.  (We don't disable reading,
-        * since we *do* want to learn about any close events.) */
+        * we only care about close detection. (We don't disable reading --
+        * EV_READ, since we *do* want to learn about any close events.) */
        bufferevent_setcb(evcon->bufev,
            NULL, /*read*/
            evhttp_write_cb,
            evhttp_error_cb,
            evcon);
 
-       bufferevent_enable(evcon->bufev, EV_WRITE);
+       bufferevent_enable(evcon->bufev, EV_READ|EV_WRITE);
 }
 
 static void
@@ -431,7 +443,10 @@ evhttp_make_header_request(struct evhttp_connection *evcon,
        evhttp_remove_header(req->output_headers, "Proxy-Connection");
 
        /* Generate request line */
-       method = evhttp_method(req->type);
+       if (!(method = evhttp_method(req->type))) {
+               method = "NULL";
+       }
+
        evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
            "%s %s HTTP/%d.%d\r\n",
            method, req->uri, req->major, req->minor);
@@ -461,6 +476,16 @@ evhttp_is_connection_close(int flags, struct evkeyvalq* headers)
                return (connection != NULL && evutil_ascii_strcasecmp(connection, "close") == 0);
        }
 }
+static int
+evhttp_is_request_connection_close(struct evhttp_request *req)
+{
+       if (req->type == EVHTTP_REQ_CONNECT)
+               return 0;
+
+       return
+               evhttp_is_connection_close(req->flags, req->input_headers) ||
+               evhttp_is_connection_close(req->flags, req->output_headers);
+}
 
 /* Return true iff 'headers' contains 'Connection: keep-alive' */
 static int
@@ -477,19 +502,7 @@ evhttp_maybe_add_date_header(struct evkeyvalq *headers)
 {
        if (evhttp_find_header(headers, "Date") == NULL) {
                char date[50];
-#ifndef _WIN32
-               struct tm cur;
-#endif
-               struct tm *cur_p;
-               time_t t = time(NULL);
-#ifdef _WIN32
-               cur_p = gmtime(&t);
-#else
-               gmtime_r(&t, &cur);
-               cur_p = &cur;
-#endif
-               if (strftime(date, sizeof(date),
-                       "%a, %d %b %Y %H:%M:%S GMT", cur_p) != 0) {
+               if (sizeof(date) - evutil_date_rfc1123(date, sizeof(date), NULL) > 0) {
                        evhttp_add_header(headers, "Date", date);
                }
        }
@@ -569,6 +582,23 @@ evhttp_make_header_response(struct evhttp_connection *evcon,
        }
 }
 
+enum expect { NO, CONTINUE, OTHER };
+static enum expect evhttp_have_expect(struct evhttp_request *req, int input)
+{
+       const char *expect;
+       struct evkeyvalq *h = input ? req->input_headers : req->output_headers;
+
+       if (!(req->kind == EVHTTP_REQUEST) || !REQ_VERSION_ATLEAST(req, 1, 1))
+               return NO;
+
+       expect = evhttp_find_header(h, "Expect");
+       if (!expect)
+               return NO;
+
+       return !evutil_ascii_strcasecmp(expect, "100-continue") ? CONTINUE : OTHER;
+}
+
+
 /** Generate all headers appropriate for sending the http request in req (or
  * the response, if we're sending a response), and write them to evcon's
  * bufferevent. Also writes all data from req->output_buffer */
@@ -594,14 +624,12 @@ evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
        }
        evbuffer_add(output, "\r\n", 2);
 
-       if (evbuffer_get_length(req->output_buffer) > 0) {
+       if (evhttp_have_expect(req, 0) != CONTINUE &&
+               evbuffer_get_length(req->output_buffer)) {
                /*
                 * For a request, we add the POST data, for a reply, this
                 * is the regular data.
                 */
-               /* XXX We might want to support waiting (a limited amount of
-                  time) for a continue status line from the server before
-                  sending POST/PUT message bodies. */
                evbuffer_add_buffer(output, req->output_buffer);
        }
 }
@@ -629,6 +657,14 @@ static int
 evhttp_connection_incoming_fail(struct evhttp_request *req,
     enum evhttp_request_error error)
 {
+       switch (error) {
+               case EVREQ_HTTP_DATA_TOO_LONG:
+                       req->response_code = HTTP_ENTITYTOOLARGE;
+                       break;
+               default:
+                       req->response_code = HTTP_BADREQUEST;
+       }
+
        switch (error) {
        case EVREQ_HTTP_TIMEOUT:
        case EVREQ_HTTP_EOF:
@@ -674,6 +710,22 @@ evhttp_connection_incoming_fail(struct evhttp_request *req,
        return (0);
 }
 
+/* Free connection ownership of which can be acquired by user using
+ * evhttp_request_own(). */
+static inline void
+evhttp_request_free_auto(struct evhttp_request *req)
+{
+       if (!(req->flags & EVHTTP_USER_OWNED))
+               evhttp_request_free(req);
+}
+
+static void
+evhttp_request_free_(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+       TAILQ_REMOVE(&evcon->requests, req, next);
+       evhttp_request_free_auto(req);
+}
+
 /* Called when evcon has experienced a (non-recoverable? -NM) error, as
  * given in error. If it's an outgoing connection, reset the connection,
  * retry any pending requests, and inform the user.  If it's incoming,
@@ -722,8 +774,7 @@ evhttp_connection_fail_(struct evhttp_connection *evcon,
         * send over a new connection.   when a user cancels a request,
         * all other pending requests should be processed as normal
         */
-       TAILQ_REMOVE(&evcon->requests, req, next);
-       evhttp_request_free(req);
+       evhttp_request_free_(evcon, req);
 
        /* reset the connection */
        evhttp_connection_reset_(evcon);
@@ -731,6 +782,11 @@ evhttp_connection_fail_(struct evhttp_connection *evcon,
        /* We are trying the next request that was queued on us */
        if (TAILQ_FIRST(&evcon->requests) != NULL)
                evhttp_connection_connect_(evcon);
+       else
+               if ((evcon->flags & EVHTTP_CON_OUTGOING) &&
+                   (evcon->flags & EVHTTP_CON_AUTOFREE)) {
+                       evhttp_connection_free(evcon);
+               }
 
        /* The call to evhttp_connection_reset_ overwrote errno.
         * Let's restore the original errno, so that the user's
@@ -773,16 +829,12 @@ evhttp_connection_done(struct evhttp_connection *evcon)
 
        if (con_outgoing) {
                /* idle or close the connection */
-               int need_close;
+               int need_close = evhttp_is_request_connection_close(req);
                TAILQ_REMOVE(&evcon->requests, req, next);
                req->evcon = NULL;
 
                evcon->state = EVCON_IDLE;
 
-               need_close =
-                   evhttp_is_connection_close(req->flags, req->input_headers)||
-                   evhttp_is_connection_close(req->flags, req->output_headers);
-
                /* check if we got asked to close the connection */
                if (need_close)
                        evhttp_connection_reset_(evcon);
@@ -820,11 +872,9 @@ evhttp_connection_done(struct evhttp_connection *evcon)
        /* notify the user of the request */
        (*req->cb)(req, req->cb_arg);
 
-       /* if this was an outgoing request, we own and it's done. so free it.
-        * unless the callback specifically requested to own the request.
-        */
-       if (con_outgoing && ((req->flags & EVHTTP_USER_OWNED) == 0)) {
-               evhttp_request_free(req);
+       /* if this was an outgoing request, we own and it's done. so free it. */
+       if (con_outgoing) {
+               evhttp_request_free_auto(req);
        }
 
        /* If this was the last request of an outgoing connection and we're
@@ -960,11 +1010,39 @@ evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req)
        case MORE_DATA_EXPECTED:
        case REQUEST_CANCELED: /* ??? */
        default:
-               bufferevent_enable(evcon->bufev, EV_READ);
                break;
        }
 }
 
+static void
+evhttp_lingering_close(struct evhttp_connection *evcon,
+       struct evhttp_request *req)
+{
+       struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
+
+       size_t n = evbuffer_get_length(buf);
+       if (n > (size_t) req->ntoread)
+               n = (size_t) req->ntoread;
+       req->ntoread -= n;
+       req->body_size += n;
+
+       event_debug(("Request body is too long, left " EV_I64_FMT,
+               EV_I64_ARG(req->ntoread)));
+
+       evbuffer_drain(buf, n);
+       if (!req->ntoread)
+               evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
+}
+static void
+evhttp_lingering_fail(struct evhttp_connection *evcon,
+       struct evhttp_request *req)
+{
+       if (evcon->flags & EVHTTP_CON_LINGERING_CLOSE)
+               evhttp_lingering_close(evcon, req);
+       else
+               evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
+}
+
 static void
 evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
 {
@@ -985,7 +1063,7 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
                        return;
                case REQUEST_CANCELED:
                        /* request canceled */
-                       evhttp_request_free(req);
+                       evhttp_request_free_auto(req);
                        return;
                case MORE_DATA_EXPECTED:
                default:
@@ -1018,9 +1096,8 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
                (size_t)req->ntoread > req->evcon->max_body_size)) {
                /* XXX: The above casted comparison must checked for overflow */
                /* failed body length test */
-               event_debug(("Request body is too long"));
-               evhttp_connection_fail_(evcon,
-                                      EVREQ_HTTP_DATA_TOO_LONG);
+
+               evhttp_lingering_fail(evcon, req);
                return;
        }
 
@@ -1031,20 +1108,17 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
                evbuffer_drain(req->input_buffer,
                    evbuffer_get_length(req->input_buffer));
                if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) {
-                       evhttp_request_free(req);
+                       evhttp_request_free_auto(req);
                        return;
                }
        }
 
-       if (req->ntoread == 0) {
+       if (!req->ntoread) {
                bufferevent_disable(evcon->bufev, EV_READ);
                /* Completed content length */
                evhttp_connection_done(evcon);
                return;
        }
-
-       /* Read more! */
-       bufferevent_enable(evcon->bufev, EV_READ);
 }
 
 #define get_deferred_queue(evcon)              \
@@ -1113,7 +1187,9 @@ static void
 evhttp_deferred_read_cb(struct event_callback *cb, void *data)
 {
        struct evhttp_connection *evcon = data;
-       evhttp_read_cb(evcon->bufev, evcon);
+       struct bufferevent *bev = evcon->bufev;
+       if (bev->readcb)
+               (bev->readcb)(evcon->bufev, evcon);
 }
 
 static void
@@ -1121,10 +1197,16 @@ evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg)
 {
        /* This is after writing the request to the server */
        struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+       struct evbuffer *output = bufferevent_get_output(evcon->bufev);
        EVUTIL_ASSERT(req != NULL);
 
        EVUTIL_ASSERT(evcon->state == EVCON_WRITING);
 
+       /* We need to wait until we've written all of our output data before we can
+        * continue */
+       if (evbuffer_get_length(output) > 0)
+               return;
+
        /* We are done writing our header and are now expecting the response */
        req->kind = EVHTTP_RESPONSE;
 
@@ -1139,6 +1221,7 @@ void
 evhttp_connection_free(struct evhttp_connection *evcon)
 {
        struct evhttp_request *req;
+       int need_close = 0;
 
        /* notify interested parties that this connection is going down */
        if (evcon->fd != -1) {
@@ -1152,8 +1235,7 @@ evhttp_connection_free(struct evhttp_connection *evcon)
         * evhttp_connection_fail_.
         */
        while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) {
-               TAILQ_REMOVE(&evcon->requests, req, next);
-               evhttp_request_free(req);
+               evhttp_request_free_(evcon, req);
        }
 
        if (evcon->http_server != NULL) {
@@ -1166,17 +1248,22 @@ evhttp_connection_free(struct evhttp_connection *evcon)
                event_debug_unassign(&evcon->retry_ev);
        }
 
-       if (evcon->bufev != NULL)
-               bufferevent_free(evcon->bufev);
-
        event_deferred_cb_cancel_(get_deferred_queue(evcon),
            &evcon->read_more_deferred_cb);
 
+       if (evcon->bufev != NULL) {
+               need_close =
+                       !(bufferevent_get_options_(evcon->bufev) & BEV_OPT_CLOSE_ON_FREE);
+               if (evcon->fd == -1)
+                       evcon->fd = bufferevent_getfd(evcon->bufev);
+
+               bufferevent_free(evcon->bufev);
+       }
+
        if (evcon->fd != -1) {
                shutdown(evcon->fd, EVUTIL_SHUT_WR);
-               if (!(bufferevent_get_options_(evcon->bufev) & BEV_OPT_CLOSE_ON_FREE)) {
+               if (need_close)
                        evutil_closesocket(evcon->fd);
-               }
        }
 
        if (evcon->bind_address != NULL)
@@ -1185,9 +1272,6 @@ evhttp_connection_free(struct evhttp_connection *evcon)
        if (evcon->address != NULL)
                mm_free(evcon->address);
 
-       if (evcon->conn_address != NULL)
-               mm_free(evcon->conn_address);
-
        mm_free(evcon);
 }
 
@@ -1224,6 +1308,8 @@ evhttp_request_dispatch(struct evhttp_connection* evcon)
        if (req == NULL)
                return;
 
+       EVUTIL_ASSERT(req->kind == EVHTTP_REQUEST);
+
        /* delete possible close detection events */
        evhttp_connection_stop_detectclose(evcon);
 
@@ -1244,6 +1330,9 @@ void
 evhttp_connection_reset_(struct evhttp_connection *evcon)
 {
        struct evbuffer *tmp;
+       int err;
+
+       bufferevent_setcb(evcon->bufev, NULL, NULL, NULL, NULL);
 
        /* XXXX This is not actually an optimal fix.  Instead we ought to have
           an API for "stop connecting", or use bufferevent_setfd to turn off
@@ -1258,6 +1347,9 @@ evhttp_connection_reset_(struct evhttp_connection *evcon)
        */
        bufferevent_disable_hard_(evcon->bufev, EV_READ|EV_WRITE);
 
+       if (evcon->fd == -1)
+               evcon->fd = bufferevent_getfd(evcon->bufev);
+
        if (evcon->fd != -1) {
                /* inform interested parties about connection close */
                if (evhttp_connected(evcon) && evcon->closecb != NULL)
@@ -1265,15 +1357,20 @@ evhttp_connection_reset_(struct evhttp_connection *evcon)
 
                shutdown(evcon->fd, EVUTIL_SHUT_WR);
                evutil_closesocket(evcon->fd);
-               bufferevent_setfd(evcon->bufev, -1);
                evcon->fd = -1;
        }
+       err = bufferevent_setfd(evcon->bufev, -1);
+       EVUTIL_ASSERT(!err && "setfd");
 
        /* we need to clean up any buffered data */
        tmp = bufferevent_get_output(evcon->bufev);
-       evbuffer_drain(tmp, evbuffer_get_length(tmp));
+       err = evbuffer_drain(tmp, -1);
+       EVUTIL_ASSERT(!err && "drain output");
        tmp = bufferevent_get_input(evcon->bufev);
-       evbuffer_drain(tmp, evbuffer_get_length(tmp));
+       err = evbuffer_drain(tmp, -1);
+       EVUTIL_ASSERT(!err && "drain input");
+
+       evcon->flags &= ~EVHTTP_CON_READING_ERROR;
 
        evcon->state = EVCON_DISCONNECTED;
 }
@@ -1282,7 +1379,6 @@ static void
 evhttp_connection_start_detectclose(struct evhttp_connection *evcon)
 {
        evcon->flags |= EVHTTP_CON_CLOSEDETECT;
-
        bufferevent_enable(evcon->bufev, EV_READ);
 }
 
@@ -1290,7 +1386,6 @@ static void
 evhttp_connection_stop_detectclose(struct evhttp_connection *evcon)
 {
        evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
-
        bufferevent_disable(evcon->bufev, EV_READ);
 }
 
@@ -1352,8 +1447,32 @@ evhttp_connection_cb_cleanup(struct evhttp_connection *evcon)
 
                /* we might want to set an error here */
                request->cb(request, request->cb_arg);
-               evhttp_request_free(request);
+               evhttp_request_free_auto(request);
+       }
+}
+
+static void
+evhttp_connection_read_on_write_error(struct evhttp_connection *evcon,
+    struct evhttp_request *req)
+{
+       struct evbuffer *buf;
+
+       /** Second time, we can't read anything */
+       if (evcon->flags & EVHTTP_CON_READING_ERROR) {
+               evcon->flags &= ~EVHTTP_CON_READING_ERROR;
+               evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
+               return;
        }
+
+       req->kind = EVHTTP_RESPONSE;
+
+       buf = bufferevent_get_output(evcon->bufev);
+       evbuffer_unfreeze(buf, 1);
+       evbuffer_drain(buf, evbuffer_get_length(buf));
+       evbuffer_freeze(buf, 1);
+
+       evhttp_start_read_(evcon);
+       evcon->flags |= EVHTTP_CON_READING_ERROR;
 }
 
 static void
@@ -1425,6 +1544,20 @@ evhttp_error_cb(struct bufferevent *bufev, short what, void *arg)
        if (what & BEV_EVENT_TIMEOUT) {
                evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT);
        } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
+               if (what & BEV_EVENT_WRITING &&
+                       evcon->flags & EVHTTP_CON_READ_ON_WRITE_ERROR) {
+                       evhttp_connection_read_on_write_error(evcon, req);
+                       return;
+               }
+
+               if (what & BEV_EVENT_READING &&
+                       evcon->flags & EVHTTP_CON_READ_ON_WRITE_ERROR &&
+                       evbuffer_get_length(bufferevent_get_input(bufev))) {
+                       event_deferred_cb_schedule_(get_deferred_queue(evcon),
+                           &evcon->read_more_deferred_cb);
+                       return;
+               }
+
                evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
        } else if (what == BEV_EVENT_CONNECTED) {
        } else {
@@ -1441,7 +1574,6 @@ evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg)
        struct evhttp_connection *evcon = arg;
        int error;
        ev_socklen_t errsz = sizeof(error);
-       socklen_t conn_address_len = sizeof(*evcon->conn_address);
 
        if (evcon->fd == -1)
                evcon->fd = bufferevent_getfd(bufev);
@@ -1492,14 +1624,6 @@ evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg)
        evcon->retry_cnt = 0;
        evcon->state = EVCON_IDLE;
 
-       if (!evcon->conn_address) {
-               evcon->conn_address = mm_malloc(sizeof(*evcon->conn_address));
-       }
-       if (getpeername(evcon->fd, (struct sockaddr *)evcon->conn_address, &conn_address_len)) {
-               mm_free(evcon->conn_address);
-               evcon->conn_address = NULL;
-       }
-
        /* reset the bufferevent cbs */
        bufferevent_setcb(evcon->bufev,
            evhttp_read_cb,
@@ -1578,6 +1702,8 @@ evhttp_parse_response_line(struct evhttp_request *req, char *line)
                return (-1);
        }
 
+       if (req->response_code_line != NULL)
+               mm_free(req->response_code_line);
        if ((req->response_code_line = mm_strdup(readable)) == NULL) {
                event_warn("%s: strdup", __func__);
                return (-1);
@@ -1589,8 +1715,9 @@ evhttp_parse_response_line(struct evhttp_request *req, char *line)
 /* Parse the first line of a HTTP request */
 
 static int
-evhttp_parse_request_line(struct evhttp_request *req, char *line)
+evhttp_parse_request_line(struct evhttp_request *req, char *line, size_t len)
 {
+       char *eos = line + len;
        char *method;
        char *uri;
        char *version;
@@ -1599,16 +1726,24 @@ evhttp_parse_request_line(struct evhttp_request *req, char *line)
        size_t method_len;
        enum evhttp_cmd_type type;
 
+       while (eos > line && *(eos-1) == ' ') {
+               *(eos-1) = '\0';
+               --eos;
+               --len;
+       }
+       if (len < strlen("GET / HTTP/1.0"))
+               return -1;
+
        /* Parse the request line */
        method = strsep(&line, " ");
-       if (line == NULL)
-               return (-1);
-       uri = strsep(&line, " ");
-       if (line == NULL)
-               return (-1);
-       version = strsep(&line, " ");
-       if (line != NULL)
-               return (-1);
+       if (!line)
+               return -1;
+       uri = line;
+       version = strrchr(uri, ' ');
+       if (!version || uri == version)
+               return -1;
+       *version = '\0';
+       version++;
 
        method_len = (uri - method) - 1;
        type       = EVHTTP_REQ_UNKNOWN_;
@@ -1728,16 +1863,22 @@ evhttp_parse_request_line(struct evhttp_request *req, char *line)
        req->type = type;
 
        if (evhttp_parse_http_version(version, req) < 0)
-               return (-1);
+               return -1;
 
        if ((req->uri = mm_strdup(uri)) == NULL) {
                event_debug(("%s: mm_strdup", __func__));
-               return (-1);
+               return -1;
        }
 
-       if ((req->uri_elems = evhttp_uri_parse_with_flags(req->uri,
-                   EVHTTP_URI_NONCONFORMANT)) == NULL) {
-               return -1;
+       if (type == EVHTTP_REQ_CONNECT) {
+               if ((req->uri_elems = evhttp_uri_parse_authority(req->uri)) == NULL) {
+                       return -1;
+               }
+       } else {
+               if ((req->uri_elems = evhttp_uri_parse_with_flags(req->uri,
+                           EVHTTP_URI_NONCONFORMANT)) == NULL) {
+                       return -1;
+               }
        }
 
        /* If we have an absolute-URI, check to see if it is an http request
@@ -1751,7 +1892,7 @@ evhttp_parse_request_line(struct evhttp_request *req, char *line)
            !evhttp_find_vhost(req->evcon->http_server, NULL, hostname))
                req->flags |= EVHTTP_PROXY_REQUEST;
 
-       return (0);
+       return 0;
 }
 
 const char *
@@ -1886,9 +2027,9 @@ evhttp_parse_firstline_(struct evhttp_request *req, struct evbuffer *buffer)
        char *line;
        enum message_read_status status = ALL_DATA_READ;
 
-       size_t line_length;
+       size_t len;
        /* XXX try */
-       line = evbuffer_readln(buffer, &line_length, EVBUFFER_EOL_CRLF);
+       line = evbuffer_readln(buffer, &len, EVBUFFER_EOL_CRLF);
        if (line == NULL) {
                if (req->evcon != NULL &&
                    evbuffer_get_length(buffer) > req->evcon->max_headers_size)
@@ -1897,17 +2038,16 @@ evhttp_parse_firstline_(struct evhttp_request *req, struct evbuffer *buffer)
                        return (MORE_DATA_EXPECTED);
        }
 
-       if (req->evcon != NULL &&
-           line_length > req->evcon->max_headers_size) {
+       if (req->evcon != NULL && len > req->evcon->max_headers_size) {
                mm_free(line);
                return (DATA_TOO_LONG);
        }
 
-       req->headers_size = line_length;
+       req->headers_size = len;
 
        switch (req->kind) {
        case EVHTTP_REQUEST:
-               if (evhttp_parse_request_line(req, line) == -1)
+               if (evhttp_parse_request_line(req, line, len) == -1)
                        status = DATA_CORRUPTED;
                break;
        case EVHTTP_RESPONSE:
@@ -1960,12 +2100,12 @@ evhttp_parse_headers_(struct evhttp_request *req, struct evbuffer* buffer)
        enum message_read_status status = MORE_DATA_EXPECTED;
 
        struct evkeyvalq* headers = req->input_headers;
-       size_t line_length;
-       while ((line = evbuffer_readln(buffer, &line_length, EVBUFFER_EOL_CRLF))
+       size_t len;
+       while ((line = evbuffer_readln(buffer, &len, EVBUFFER_EOL_CRLF))
               != NULL) {
                char *skey, *svalue;
 
-               req->headers_size += line_length;
+               req->headers_size += len;
 
                if (req->evcon != NULL &&
                    req->headers_size > req->evcon->max_headers_size) {
@@ -2029,11 +2169,7 @@ evhttp_get_body_length(struct evhttp_request *req)
                req->ntoread = -1;
        else if (content_length == NULL &&
            evutil_ascii_strcasecmp(connection, "Close") != 0) {
-               /* Bad combination, we don't know when it will end */
-               event_warnx("%s: we got no content length, but the "
-                   "server wants to keep the connection open: %s.",
-                   __func__, connection);
-               return (-1);
+               req->ntoread = 0;
        } else if (content_length == NULL) {
                req->ntoread = -1;
        } else {
@@ -2061,16 +2197,15 @@ evhttp_method_may_have_body(enum evhttp_cmd_type type)
        case EVHTTP_REQ_POST:
        case EVHTTP_REQ_PUT:
        case EVHTTP_REQ_PATCH:
-               return 1;
-       case EVHTTP_REQ_TRACE:
-               return 0;
-       /* XXX May any of the below methods have a body? */
+
        case EVHTTP_REQ_GET:
-       case EVHTTP_REQ_HEAD:
        case EVHTTP_REQ_DELETE:
        case EVHTTP_REQ_OPTIONS:
        case EVHTTP_REQ_CONNECT:
-               return 0;
+               return 1;
+
+       case EVHTTP_REQ_TRACE:
+       case EVHTTP_REQ_HEAD:
        default:
                return 0;
        }
@@ -2094,8 +2229,7 @@ evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
                req->ntoread = -1;
        } else {
                if (evhttp_get_body_length(req) == -1) {
-                       evhttp_connection_fail_(evcon,
-                           EVREQ_HTTP_INVALID_HEADER);
+                       evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
                        return;
                }
                if (req->kind == EVHTTP_REQUEST && req->ntoread < 1) {
@@ -2107,12 +2241,8 @@ evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
        }
 
        /* Should we send a 100 Continue status line? */
-       if (req->kind == EVHTTP_REQUEST && REQ_VERSION_ATLEAST(req, 1, 1)) {
-               const char *expect;
-
-               expect = evhttp_find_header(req->input_headers, "Expect");
-               if (expect) {
-                       if (!evutil_ascii_strcasecmp(expect, "100-continue")) {
+       switch (evhttp_have_expect(req, 1)) {
+               case CONTINUE:
                                /* XXX It would be nice to do some sanity
                                   checking here. Does the resource exist?
                                   Should the resource accept post requests? If
@@ -2121,19 +2251,19 @@ evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
                                   send their message body. */
                                if (req->ntoread > 0) {
                                        /* ntoread is ev_int64_t, max_body_size is ev_uint64_t */ 
-                                       if ((req->evcon->max_body_size <= EV_INT64_MAX) && (ev_uint64_t)req->ntoread > req->evcon->max_body_size) {
-                                               evhttp_send_error(req, HTTP_ENTITYTOOLARGE, NULL);
+                                       if ((req->evcon->max_body_size <= EV_INT64_MAX) &&
+                                               (ev_uint64_t)req->ntoread > req->evcon->max_body_size) {
+                                               evhttp_lingering_fail(evcon, req);
                                                return;
                                        }
                                }
                                if (!evbuffer_get_length(bufferevent_get_input(evcon->bufev)))
                                        evhttp_send_continue(evcon, req);
-                       } else {
-                               evhttp_send_error(req, HTTP_EXPECTATIONFAILED,
-                                       NULL);
-                               return;
-                       }
-               }
+                       break;
+               case OTHER:
+                       evhttp_send_error(req, HTTP_EXPECTATIONFAILED, NULL);
+                       return;
+               case NO: break;
        }
 
        evhttp_read_body(evcon, req);
@@ -2181,9 +2311,6 @@ evhttp_read_header(struct evhttp_connection *evcon,
                return;
        }
 
-       /* 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) {
@@ -2204,7 +2331,9 @@ evhttp_read_header(struct evhttp_connection *evcon,
        case EVHTTP_RESPONSE:
                /* Start over if we got a 100 Continue response. */
                if (req->response_code == 100) {
-                       evhttp_start_read_(evcon);
+                       struct evbuffer *output = bufferevent_get_output(evcon->bufev);
+                       evbuffer_add_buffer(output, req->output_buffer);
+                       evhttp_start_write_(evcon);
                        return;
                }
                if (!evhttp_response_needs_body(req)) {
@@ -2241,14 +2370,14 @@ evhttp_read_header(struct evhttp_connection *evcon,
  */
 
 struct evhttp_connection *
-evhttp_connection_new(const char *address, unsigned short port)
+evhttp_connection_new(const char *address, ev_uint16_t port)
 {
        return (evhttp_connection_base_new(NULL, NULL, address, port));
 }
 
 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)
+    const char *address, ev_uint16_t port)
 {
        struct evhttp_connection *evcon = NULL;
 
@@ -2324,7 +2453,7 @@ evhttp_connection_get_server(struct evhttp_connection *evcon)
 
 struct evhttp_connection *
 evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase,
-    const char *address, unsigned short port)
+    const char *address, ev_uint16_t port)
 {
        return evhttp_connection_base_bufferevent_new(base, dnsbase, NULL, address, port);
 }
@@ -2335,6 +2464,22 @@ void evhttp_connection_set_family(struct evhttp_connection *evcon,
        evcon->ai_family = family;
 }
 
+int evhttp_connection_set_flags(struct evhttp_connection *evcon,
+       int flags)
+{
+       int avail_flags = 0;
+       avail_flags |= EVHTTP_CON_REUSE_CONNECTED_ADDR;
+       avail_flags |= EVHTTP_CON_READ_ON_WRITE_ERROR;
+
+       if (flags & ~avail_flags || flags > EVHTTP_CON_PUBLIC_FLAGS_END)
+               return 1;
+       evcon->flags &= ~avail_flags;
+
+       evcon->flags |= flags;
+
+       return 0;
+}
+
 void
 evhttp_connection_set_base(struct evhttp_connection *evcon,
     struct event_base *base)
@@ -2412,13 +2557,16 @@ evhttp_connection_get_peer(struct evhttp_connection *evcon,
 const struct sockaddr*
 evhttp_connection_get_addr(struct evhttp_connection *evcon)
 {
-       return (struct sockaddr *)evcon->conn_address;
+       return bufferevent_socket_get_conn_address_(evcon->bufev);
 }
 
 int
 evhttp_connection_connect_(struct evhttp_connection *evcon)
 {
        int old_state = evcon->state;
+       const char *address = evcon->address;
+       const struct sockaddr *sa = evhttp_connection_get_addr(evcon);
+       int ret;
 
        if (evcon->state == EVCON_CONNECTING)
                return (0);
@@ -2437,9 +2585,11 @@ evhttp_connection_connect_(struct evhttp_connection *evcon)
                        return (-1);
                }
 
-               bufferevent_setfd(evcon->bufev, evcon->fd);
+               if (bufferevent_setfd(evcon->bufev, evcon->fd))
+                       return (-1);
        } else {
-               bufferevent_setfd(evcon->bufev, -1);
+               if (bufferevent_setfd(evcon->bufev, -1))
+                       return (-1);
        }
 
        /* Set up a callback for successful connection setup */
@@ -2450,17 +2600,30 @@ evhttp_connection_connect_(struct evhttp_connection *evcon)
            evcon);
        if (!evutil_timerisset(&evcon->timeout)) {
                const struct timeval conn_tv = { HTTP_CONNECT_TIMEOUT, 0 };
-               bufferevent_set_timeouts(evcon->bufev, NULL, &conn_tv);
+               bufferevent_set_timeouts(evcon->bufev, &conn_tv, &conn_tv);
        } else {
-               bufferevent_set_timeouts(evcon->bufev, NULL, &evcon->timeout);
+               bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
        }
        /* make sure that we get a write callback */
-       bufferevent_enable(evcon->bufev, EV_WRITE);
+       if (bufferevent_enable(evcon->bufev, EV_WRITE))
+               return (-1);
 
        evcon->state = EVCON_CONNECTING;
 
-       if (bufferevent_socket_connect_hostname(evcon->bufev, evcon->dns_base,
-               evcon->ai_family, evcon->address, evcon->port) < 0) {
+       if (evcon->flags & EVHTTP_CON_REUSE_CONNECTED_ADDR &&
+               sa &&
+               (sa->sa_family == AF_INET || sa->sa_family == AF_INET6)) {
+               int socklen = sizeof(struct sockaddr_in);
+               if (sa->sa_family == AF_INET6) {
+                       socklen = sizeof(struct sockaddr_in6);
+               }
+               ret = bufferevent_socket_connect(evcon->bufev, sa, socklen);
+       } else {
+               ret = bufferevent_socket_connect_hostname(evcon->bufev,
+                               evcon->dns_base, evcon->ai_family, address, evcon->port);
+       }
+
+       if (ret < 0) {
                evcon->state = old_state;
                event_sock_warn(evcon->fd, "%s: connection to \"%s\" failed",
                    __func__, evcon->address);
@@ -2493,7 +2656,7 @@ evhttp_make_request(struct evhttp_connection *evcon,
                mm_free(req->uri);
        if ((req->uri = mm_strdup(uri)) == NULL) {
                event_warn("%s: strdup", __func__);
-               evhttp_request_free(req);
+               evhttp_request_free_auto(req);
                return (-1);
        }
 
@@ -2509,6 +2672,10 @@ evhttp_make_request(struct evhttp_connection *evcon,
 
        TAILQ_INSERT_TAIL(&evcon->requests, req, next);
 
+       /* We do not want to conflict with retry_ev */
+       if (evcon->retry_cnt)
+               return (0);
+
        /* If the connection object is not connected; make it so */
        if (!evhttp_connected(evcon)) {
                int res = evhttp_connection_connect_(evcon);
@@ -2519,7 +2686,7 @@ evhttp_make_request(struct evhttp_connection *evcon,
                if (res != 0)
                        TAILQ_REMOVE(&evcon->requests, req, next);
 
-               return res;
+               return (res);
        }
 
        /*
@@ -2556,7 +2723,7 @@ evhttp_cancel_request(struct evhttp_request *req)
                }
        }
 
-       evhttp_request_free(req);
+       evhttp_request_free_auto(req);
 }
 
 /*
@@ -2567,9 +2734,9 @@ evhttp_cancel_request(struct evhttp_request *req)
 void
 evhttp_start_read_(struct evhttp_connection *evcon)
 {
-       /* Set up an event to read the headers */
        bufferevent_disable(evcon->bufev, EV_WRITE);
        bufferevent_enable(evcon->bufev, EV_READ);
+
        evcon->state = EVCON_READING_FIRSTLINE;
        /* Reset the bufferevent callbacks */
        bufferevent_setcb(evcon->bufev,
@@ -2586,6 +2753,16 @@ evhttp_start_read_(struct evhttp_connection *evcon)
        }
 }
 
+void
+evhttp_start_write_(struct evhttp_connection *evcon)
+{
+       bufferevent_disable(evcon->bufev, EV_WRITE);
+       bufferevent_enable(evcon->bufev, EV_READ);
+
+       evcon->state = EVCON_WRITING;
+       evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
+}
+
 static void
 evhttp_send_done(struct evhttp_connection *evcon, void *arg)
 {
@@ -2599,9 +2776,8 @@ evhttp_send_done(struct evhttp_connection *evcon, void *arg)
 
        need_close =
            (REQ_VERSION_BEFORE(req, 1, 1) &&
-               !evhttp_is_connection_keepalive(req->input_headers))||
-           evhttp_is_connection_close(req->flags, req->input_headers) ||
-           evhttp_is_connection_close(req->flags, req->output_headers);
+           !evhttp_is_connection_keepalive(req->input_headers)) ||
+           evhttp_is_request_connection_close(req);
 
        EVUTIL_ASSERT(req->flags & EVHTTP_REQ_OWN_CONNECTION);
        evhttp_request_free(req);
@@ -2692,6 +2868,10 @@ evhttp_send_reply_start(struct evhttp_request *req, int code,
     const char *reason)
 {
        evhttp_response_code_(req, code, reason);
+
+       if (req->evcon == NULL)
+               return;
+
        if (evhttp_find_header(req->output_headers, "Content-Length") == NULL &&
            REQ_VERSION_ATLEAST(req, 1, 1) &&
            evhttp_response_needs_body(req)) {
@@ -2931,15 +3111,32 @@ evhttp_uriencode(const char *uri, ev_ssize_t len, int space_as_plus)
 {
        struct evbuffer *buf = evbuffer_new();
        const char *p, *end;
-       char *result;
+       char *result = NULL;
 
-       if (buf == NULL)
-               return (NULL);
+       if (!buf) {
+               goto out;
+       }
 
-       if (len >= 0)
-               end = uri+len;
-       else
-               end = uri+strlen(uri);
+       if (len >= 0) {
+               if (uri + len < uri) {
+                       goto out;
+               }
+
+               end = uri + len;
+       } else {
+               size_t slen = strlen(uri);
+
+               if (slen >= EV_SSIZE_MAX) {
+                       /* we don't want to mix signed and unsigned */
+                       goto out;
+               }
+
+               if (uri + slen < uri) {
+                       goto out;
+               }
+
+               end = uri + slen;
+       }
 
        for (p = uri; p < end; p++) {
                if (CHAR_IS_UNRESERVED(*p)) {
@@ -2950,13 +3147,17 @@ evhttp_uriencode(const char *uri, ev_ssize_t len, int space_as_plus)
                        evbuffer_add_printf(buf, "%%%02X", (unsigned char)(*p));
                }
        }
+
        evbuffer_add(buf, "", 1); /* NUL-terminator. */
        result = mm_malloc(evbuffer_get_length(buf));
+
        if (result)
                evbuffer_remove(buf, result, evbuffer_get_length(buf));
-       evbuffer_free(buf);
 
-       return (result);
+out:
+       if (buf)
+               evbuffer_free(buf);
+       return result;
 }
 
 char *
@@ -3085,6 +3286,7 @@ evhttp_parse_query_impl(const char *str, struct evkeyvalq *headers,
        p = argument = line;
        while (p != NULL && *p != '\0') {
                char *key, *value, *decoded_value;
+               int err;
                argument = strsep(&p, "&");
 
                value = argument;
@@ -3100,8 +3302,10 @@ evhttp_parse_query_impl(const char *str, struct evkeyvalq *headers,
                evhttp_decode_uri_internal(value, strlen(value),
                    decoded_value, 1 /*always_decode_plus*/);
                event_debug(("Query Param: %s -> %s\n", key, decoded_value));
-               evhttp_add_header_internal(headers, key, decoded_value);
+               err = evhttp_add_header_internal(headers, key, decoded_value);
                mm_free(decoded_value);
+               if (err)
+                       goto error;
        }
 
        result = 0;
@@ -3267,8 +3471,10 @@ evhttp_handle_request(struct evhttp_request *req, void *arg)
        /* we have a new request on which the user needs to take action */
        req->userdone = 0;
 
+       bufferevent_disable(req->evcon->bufev, EV_READ);
+
        if (req->type == 0 || req->uri == NULL) {
-               evhttp_send_error(req, HTTP_BADREQUEST, NULL);
+               evhttp_send_error(req, req->response_code, NULL);
                return;
        }
 
@@ -3354,13 +3560,16 @@ evhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint
 {
        evutil_socket_t fd;
        struct evhttp_bound_socket *bound;
+       int serrno;
 
        if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1)
                return (NULL);
 
        if (listen(fd, 128) == -1) {
+               serrno = EVUTIL_SOCKET_ERROR();
                event_sock_warn(fd, "%s: listen", __func__);
                evutil_closesocket(fd);
+               EVUTIL_SET_SOCKET_ERROR(serrno);
                return (NULL);
        }
 
@@ -3503,7 +3712,7 @@ evhttp_new(struct event_base *base)
  */
 
 struct evhttp *
-evhttp_start(const char *address, unsigned short port)
+evhttp_start(const char *address, ev_uint16_t port)
 {
        struct evhttp *http = NULL;
 
@@ -3657,6 +3866,20 @@ evhttp_set_timeout_tv(struct evhttp* http, const struct timeval* tv)
        }
 }
 
+int evhttp_set_flags(struct evhttp *http, int flags)
+{
+       int avail_flags = 0;
+       avail_flags |= EVHTTP_SERVER_LINGERING_CLOSE;
+
+       if (flags & ~avail_flags)
+               return 1;
+       http->flags &= ~avail_flags;
+
+       http->flags |= flags;
+
+       return 0;
+}
+
 void
 evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size)
 {
@@ -4006,6 +4229,13 @@ evhttp_get_request_connection(
        char *hostname = NULL, *portname = NULL;
        struct bufferevent* bev = NULL;
 
+#ifdef EVENT__HAVE_STRUCT_SOCKADDR_UN
+       if (sa->sa_family == AF_UNIX) {
+               struct sockaddr_un *sa_un = (struct sockaddr_un *)sa;
+               sa_un->sun_path[0] = '\0';
+       }
+#endif
+
        name_from_addr(sa, salen, &hostname, &portname);
        if (hostname == NULL || portname == NULL) {
                if (hostname) mm_free(hostname);
@@ -4029,15 +4259,27 @@ evhttp_get_request_connection(
 
        evcon->max_headers_size = http->default_max_headers_size;
        evcon->max_body_size = http->default_max_body_size;
+       if (http->flags & EVHTTP_SERVER_LINGERING_CLOSE)
+               evcon->flags |= EVHTTP_CON_LINGERING_CLOSE;
 
        evcon->flags |= EVHTTP_CON_INCOMING;
        evcon->state = EVCON_READING_FIRSTLINE;
 
        evcon->fd = fd;
 
-       bufferevent_setfd(evcon->bufev, fd);
+       if (bufferevent_setfd(evcon->bufev, fd))
+               goto err;
+       if (bufferevent_enable(evcon->bufev, EV_READ))
+               goto err;
+       if (bufferevent_disable(evcon->bufev, EV_WRITE))
+               goto err;
+       bufferevent_socket_set_conn_address_(evcon->bufev, sa, salen);
 
        return (evcon);
+
+err:
+       evhttp_connection_free(evcon);
+       return (NULL);
 }
 
 static int
@@ -4146,9 +4388,8 @@ name_from_addr(struct sockaddr *sa, ev_socklen_t salen,
 }
 
 /* Create a non-blocking socket and bind it */
-/* todo: rename this function */
 static evutil_socket_t
-bind_socket_ai(struct evutil_addrinfo *ai, int reuse)
+create_bind_socket_nonblock(struct evutil_addrinfo *ai, int reuse)
 {
        evutil_socket_t fd;
 
@@ -4222,14 +4463,14 @@ bind_socket(const char *address, ev_uint16_t port, int reuse)
 
        /* just create an unbound socket */
        if (address == NULL && port == 0)
-               return bind_socket_ai(NULL, 0);
+               return create_bind_socket_nonblock(NULL, 0);
 
        aitop = make_addrinfo(address, port);
 
        if (aitop == NULL)
                return (-1);
 
-       fd = bind_socket_ai(aitop, reuse);
+       fd = create_bind_socket_nonblock(aitop, reuse);
 
        evutil_freeaddrinfo(aitop);
 
@@ -4654,6 +4895,36 @@ err:
        return NULL;
 }
 
+static struct evhttp_uri *
+evhttp_uri_parse_authority(char *source_uri)
+{
+       struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri));
+       char *end;
+
+       if (uri == NULL) {
+               event_warn("%s: calloc", __func__);
+               goto err;
+       }
+       uri->port = -1;
+       uri->flags = 0;
+
+       end = end_of_authority(source_uri);
+       if (parse_authority(uri, source_uri, end) < 0)
+               goto err;
+
+       uri->path = mm_strdup("");
+       if (uri->path == NULL) {
+               event_warn("%s: strdup", __func__);
+               goto err;
+       }
+
+       return uri;
+err:
+       if (uri)
+               evhttp_uri_free(uri);
+       return NULL;
+}
+
 void
 evhttp_uri_free(struct evhttp_uri *uri)
 {
index 3a1b0c2c0e435cf6fd7a371b8a861bc99757d99d..ba5186713bb97aa283ed356e15863c181adf44a6 100644 (file)
@@ -63,8 +63,6 @@ extern "C" {
 #include <winsock2.h>
 #include <windows.h>
 #undef WIN32_LEAN_AND_MEAN
-typedef unsigned char u_char;
-typedef unsigned short u_short;
 #endif
 
 #include <event2/event_struct.h>
index 468588b9f141c200c2ab310afd1e448dd643e70f..88af3ae141b178cb0370ff1fb85ecf5090e667a1 100644 (file)
@@ -726,7 +726,8 @@ int evbuffer_write_atmost(struct evbuffer *buffer, evutil_socket_t fd,
 
   @param buffer the evbuffer to store the result
   @param fd the file descriptor to read from
-  @param howmuch the number of bytes to be read
+  @param howmuch the number of bytes to be read. If the given number is negative
+  or out of maximum bytes per one read, as many bytes as we can will be read.
   @return the number of bytes read, or -1 if an error occurred
   @see evbuffer_write()
  */
index c0bdd9d21f06e96631dd18a95d04295127005950..0ce10254487d4dc2ed670aeda1bf5889a4bb89d2 100644 (file)
@@ -37,7 +37,7 @@
 
 
 /**
-   Obsolete alias for evbuffer_readln(buffer, NULL, EOL_STYLE_ANY).
+   Obsolete alias for evbuffer_readln(buffer, NULL, EVBUFFER_EOL_ANY).
 
    @deprecated This function is deprecated because its behavior is not correct
       for almost any protocol, and also because it's wholly subsumed by
@@ -90,9 +90,10 @@ typedef void (*evbuffer_cb)(struct evbuffer *buffer, size_t old_len, size_t new_
   @param cb the callback function to invoke when the evbuffer is modified,
         or NULL to remove all callbacks.
   @param cbarg an argument to be provided to the callback function
+  @return 0 if successful, or -1 on error
  */
 EVENT2_EXPORT_SYMBOL
-void evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg);
+int evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg);
 
 
 /**
index fe8a74d348c635f04faed31032d4d9903b809f0e..48cd153563bb6b02294ceb610beff41e477e74de 100644 (file)
@@ -209,7 +209,7 @@ struct bufferevent *bufferevent_socket_new(struct event_base *base, evutil_socke
    @return 0 on success, -1 on failure.
  */
 EVENT2_EXPORT_SYMBOL
-int bufferevent_socket_connect(struct bufferevent *, struct sockaddr *, int);
+int bufferevent_socket_connect(struct bufferevent *, const struct sockaddr *, int);
 
 struct evdns_base;
 /**
@@ -491,7 +491,7 @@ short bufferevent_get_enabled(struct bufferevent *bufev);
 
   (In other words, if reading or writing is disabled, or if the
   bufferevent's read or write operation has been suspended because
-  there's no data to write, or not enough banwidth, or so on, the
+  there's no data to write, or not enough bandwidth, or so on, the
   timeout isn't active.  The timeout only becomes active when we we're
   willing to actually read or write.)
 
@@ -518,6 +518,9 @@ int bufferevent_set_timeouts(struct bufferevent *bufev,
   On input, a bufferevent does not invoke the user read callback unless
   there is at least low watermark data in the buffer.  If the read buffer
   is beyond the high watermark, the bufferevent stops reading from the network.
+  But be aware that bufferevent input/read buffer can overrun high watermark
+  limit (typical example is openssl bufferevent), so you should not relay in
+  this.
 
   On output, the user write callback is invoked whenever the buffered data
   falls below the low watermark.  Filters that write to this bufev will try
@@ -562,6 +565,32 @@ void bufferevent_lock(struct bufferevent *bufev);
 EVENT2_EXPORT_SYMBOL
 void bufferevent_unlock(struct bufferevent *bufev);
 
+
+/**
+ * Public interface to manually increase the reference count of a bufferevent
+ * this is useful in situations where a user may reference the bufferevent
+ * somewhere else (unknown to libevent)
+ *
+ * @param bufev the bufferevent to increase the refcount on
+ *
+ */
+EVENT2_EXPORT_SYMBOL
+void bufferevent_incref(struct bufferevent *bufev);
+
+/**
+ * Public interface to manually decrement the reference count of a bufferevent
+ *
+ * Warning: make sure you know what you're doing. This is mainly used in
+ * conjunction with bufferevent_incref(). This will free up all data associated
+ * with a bufferevent if the reference count hits 0.
+ *
+ * @param bufev the bufferevent to decrement the refcount on
+ *
+ * @return 1 if the bufferevent was freed, otherwise 0 (still referenced)
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_decref(struct bufferevent *bufev);
+
 /**
    Flags that can be passed into filters to let them know how to
    deal with the incoming data.
@@ -773,7 +802,7 @@ void ev_token_bucket_cfg_free(struct ev_token_bucket_cfg *cfg);
    They are: socket-based bufferevents (normal and IOCP-based), and SSL-based
    bufferevents.
 
-   Return 0 on sucess, -1 on failure.
+   Return 0 on success, -1 on failure.
  */
 EVENT2_EXPORT_SYMBOL
 int bufferevent_set_rate_limit(struct bufferevent *bev,
@@ -824,7 +853,7 @@ int bufferevent_rate_limit_group_set_cfg(
 
    The default min-share is currently 64 bytes.
 
-   Returns 0 on success, -1 on faulre.
+   Returns 0 on success, -1 on failure.
  */
 EVENT2_EXPORT_SYMBOL
 int bufferevent_rate_limit_group_set_min_share(
index 65482042f9d16b3f382aa2551162a53bbc312438..a5a3c7207d644009aeaa09f592ff0c6416004242 100644 (file)
@@ -28,6 +28,8 @@
 #ifndef EVENT2_BUFFEREVENT_COMPAT_H_INCLUDED_
 #define EVENT2_BUFFEREVENT_COMPAT_H_INCLUDED_
 
+#include <event2/visibility.h>
+
 #define evbuffercb bufferevent_data_cb
 #define everrorcb bufferevent_event_cb
 
@@ -72,6 +74,7 @@
          error occurred
   @see bufferevent_base_set(), bufferevent_free()
   */
+EVENT2_EXPORT_SYMBOL
 struct bufferevent *bufferevent_new(evutil_socket_t fd,
     evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg);
 
@@ -83,6 +86,7 @@ struct bufferevent *bufferevent_new(evutil_socket_t fd,
   @param timeout_read the read timeout
   @param timeout_write the write timeout
  */
+EVENT2_EXPORT_SYMBOL
 void bufferevent_settimeout(struct bufferevent *bufev,
     int timeout_read, int timeout_write);
 
index 17cd86a2ec2df91f515b056619e67a1ca2fca700..13ce027e4a8c77081f0e90f621d3299041e1c911 100644 (file)
@@ -179,11 +179,39 @@ extern "C" {
 
 #define DNS_QUERY_NO_SEARCH 1
 
+/* Allow searching */
 #define DNS_OPTION_SEARCH 1
+/* Parse "nameserver" and add default if no such section */
 #define DNS_OPTION_NAMESERVERS 2
+/* Parse additional options like:
+ * - timeout:
+ * - getaddrinfo-allow-skew:
+ * - max-timeouts:
+ * - max-inflight:
+ * - attempts:
+ * - randomize-case:
+ * - initial-probe-timeout:
+ */
 #define DNS_OPTION_MISC 4
+/* Load hosts file (i.e. "/etc/hosts") */
 #define DNS_OPTION_HOSTSFILE 8
-#define DNS_OPTIONS_ALL 15
+/**
+ * All above:
+ * - DNS_OPTION_SEARCH
+ * - DNS_OPTION_NAMESERVERS
+ * - DNS_OPTION_MISC
+ * - DNS_OPTION_HOSTSFILE
+ */
+#define DNS_OPTIONS_ALL (    \
+    DNS_OPTION_SEARCH      | \
+    DNS_OPTION_NAMESERVERS | \
+    DNS_OPTION_MISC        | \
+    DNS_OPTION_HOSTSFILE   | \
+    0                        \
+)
+/* Do not "default" nameserver (i.e. "127.0.0.1:53") if there is no nameservers
+ * in resolv.conf, (iff DNS_OPTION_NAMESERVERS is set) */
+#define DNS_OPTION_NAMESERVERS_NO_DEFAULT 16
 
 /* Obsolete name for DNS_QUERY_NO_SEARCH */
 #define DNS_NO_SEARCH DNS_QUERY_NO_SEARCH
@@ -208,6 +236,10 @@ struct event_base;
 /** Flag for evdns_base_new: Do not prevent the libevent event loop from
  * exiting when we have no active dns requests. */
 #define EVDNS_BASE_DISABLE_WHEN_INACTIVE 0x8000
+/** Flag for evdns_base_new: If EVDNS_BASE_INITIALIZE_NAMESERVERS isset, do not
+ * add default nameserver if there are no nameservers in resolv.conf
+ * @see DNS_OPTION_NAMESERVERS_NO_DEFAULT */
+#define EVDNS_BASE_NAMESERVERS_NO_DEFAULT 0x10000
 
 /**
   Initialize the asynchronous DNS library.
@@ -218,7 +250,7 @@ struct event_base;
 
   @param event_base the event base to associate the dns client with
   @param flags any of EVDNS_BASE_INITIALIZE_NAMESERVERS|
-    EVDNS_BASE_DISABLE_WHEN_INACTIVE
+    EVDNS_BASE_DISABLE_WHEN_INACTIVE|EVDNS_BASE_NAMESERVERS_NO_DEFAULT
   @return evdns_base object if successful, or NULL if an error occurred.
   @see evdns_base_free()
  */
@@ -423,7 +455,8 @@ void evdns_cancel_request(struct evdns_base *base, struct evdns_request *req);
   The currently available configuration options are:
 
     ndots, timeout, max-timeouts, max-inflight, attempts, randomize-case,
-    bind-to, initial-probe-timeout, getaddrinfo-allow-skew.
+    bind-to, initial-probe-timeout, getaddrinfo-allow-skew,
+    so-rcvbuf, so-sndbuf.
 
   In versions before Libevent 2.0.3-alpha, the option name needed to end with
   a colon.
@@ -453,7 +486,7 @@ int evdns_base_set_option(struct evdns_base *base, const char *option, const cha
 
   @param base the evdns_base to which to apply this operation
   @param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC|
-    DNS_OPTION_HOSTSFILE|DNS_OPTIONS_ALL
+    DNS_OPTION_HOSTSFILE|DNS_OPTIONS_ALL|DNS_OPTION_NAMESERVERS_NO_DEFAULT
   @param filename the path to the resolv.conf file
   @return 0 if successful, or various positive error codes if an error
     occurred (see above)
@@ -478,6 +511,7 @@ int evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char
 EVENT2_EXPORT_SYMBOL
 int evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname);
 
+#if defined(EVENT_IN_DOXYGEN_) || defined(_WIN32)
 /**
   Obtain nameserver information using the Windows API.
 
@@ -488,7 +522,6 @@ int evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname);
   @return 0 if successful, or -1 if an error occurred
   @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
@@ -615,7 +648,8 @@ typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, vo
     @param callback A function to invoke whenever we get a DNS request
       on the socket.
     @param user_data Data to pass to the callback.
-    @return an evdns_server_port structure for this server port.
+    @return an evdns_server_port structure for this server port or NULL if
+      an error occurred.
  */
 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);
index 965fd65445b476696702df665afae660b6759ecb..a58c4b29375ef8d60dd30b68694bd924c0229fe7 100644 (file)
@@ -49,6 +49,7 @@ extern "C" {
 
 /* For int types. */
 #include <event2/util.h>
+#include <event2/visibility.h>
 
 /**
   Initialize the asynchronous DNS library.
@@ -66,6 +67,7 @@ extern "C" {
   @return 0 if successful, or -1 if an error occurred
   @see evdns_shutdown()
  */
+EVENT2_EXPORT_SYMBOL
 int evdns_init(void);
 
 struct evdns_base;
@@ -76,6 +78,7 @@ struct evdns_base;
    @deprecated This function is deprecated because use of the global
      evdns_base is error-prone.
  */
+EVENT2_EXPORT_SYMBOL
 struct evdns_base *evdns_get_global_base(void);
 
 /**
@@ -93,6 +96,7 @@ struct evdns_base *evdns_get_global_base(void);
                active requests will return DNS_ERR_SHUTDOWN.
   @see evdns_init()
  */
+EVENT2_EXPORT_SYMBOL
 void evdns_shutdown(int fail_requests);
 
 /**
@@ -109,6 +113,7 @@ void evdns_shutdown(int fail_requests);
   @return 0 if successful, or -1 if an error occurred
   @see evdns_nameserver_ip_add()
  */
+EVENT2_EXPORT_SYMBOL
 int evdns_nameserver_add(unsigned long int address);
 
 /**
@@ -126,6 +131,7 @@ int evdns_nameserver_add(unsigned long int address);
   @return the number of configured nameservers
   @see evdns_nameserver_add()
  */
+EVENT2_EXPORT_SYMBOL
 int evdns_count_nameservers(void);
 
 /**
@@ -140,6 +146,7 @@ int evdns_count_nameservers(void);
   @return 0 if successful, or -1 if an error occurred
   @see evdns_resume()
  */
+EVENT2_EXPORT_SYMBOL
 int evdns_clear_nameservers_and_suspend(void);
 
 /**
@@ -155,6 +162,7 @@ int evdns_clear_nameservers_and_suspend(void);
   @return 0 if successful, or -1 if an error occurred
   @see evdns_clear_nameservers_and_suspend()
  */
+EVENT2_EXPORT_SYMBOL
 int evdns_resume(void);
 
 /**
@@ -170,6 +178,7 @@ int evdns_resume(void);
   @return 0 if successful, or -1 if an error occurred
   @see evdns_nameserver_add()
  */
+EVENT2_EXPORT_SYMBOL
 int evdns_nameserver_ip_add(const char *ip_as_string);
 
 /**
@@ -186,6 +195,7 @@ int evdns_nameserver_ip_add(const char *ip_as_string);
   @return 0 if successful, or -1 if an error occurred
   @see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
  */
+EVENT2_EXPORT_SYMBOL
 int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr);
 
 /**
@@ -198,6 +208,7 @@ int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback
   @return 0 if successful, or -1 if an error occurred
   @see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
  */
+EVENT2_EXPORT_SYMBOL
 int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr);
 
 struct in_addr;
@@ -217,6 +228,7 @@ struct in6_addr;
   @return 0 if successful, or -1 if an error occurred
   @see evdns_resolve_reverse_ipv6()
  */
+EVENT2_EXPORT_SYMBOL
 int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr);
 
 /**
@@ -233,6 +245,7 @@ int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_ty
   @return 0 if successful, or -1 if an error occurred
   @see evdns_resolve_reverse_ipv6()
  */
+EVENT2_EXPORT_SYMBOL
 int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr);
 
 /**
@@ -251,6 +264,7 @@ int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callb
   @param flags Ignored.
   @return 0 if successful, or -1 if an error occurred
  */
+EVENT2_EXPORT_SYMBOL
 int evdns_set_option(const char *option, const char *val, int flags);
 
 /**
@@ -278,6 +292,7 @@ int evdns_set_option(const char *option, const char *val, int flags);
     occurred (see above)
   @see resolv.conf(3), evdns_config_windows_nameservers()
  */
+EVENT2_EXPORT_SYMBOL
 int evdns_resolv_conf_parse(int flags, const char *const filename);
 
 /**
@@ -287,6 +302,7 @@ int evdns_resolv_conf_parse(int flags, const char *const filename);
     caller to specify which evdns_base it applies to.  The recommended
     function is evdns_base_search_clear().
  */
+EVENT2_EXPORT_SYMBOL
 void evdns_search_clear(void);
 
 /**
@@ -298,6 +314,7 @@ void evdns_search_clear(void);
 
   @param domain the domain to be added to the search list
  */
+EVENT2_EXPORT_SYMBOL
 void evdns_search_add(const char *domain);
 
 /**
@@ -312,6 +329,7 @@ void evdns_search_add(const char *domain);
 
   @param ndots the new ndots parameter
  */
+EVENT2_EXPORT_SYMBOL
 void evdns_search_ndots_set(const int ndots);
 
 /**
@@ -322,9 +340,13 @@ void evdns_search_ndots_set(const int ndots);
     function is evdns_add_server_port_with_base().
 
 */
-struct evdns_server_port *evdns_add_server_port(evutil_socket_t socket, int flags, evdns_request_callback_fn_type callback, void *user_data);
+EVENT2_EXPORT_SYMBOL
+struct evdns_server_port *
+evdns_add_server_port(evutil_socket_t socket, int flags,
+       evdns_request_callback_fn_type callback, void *user_data);
 
 #ifdef _WIN32
+EVENT2_EXPORT_SYMBOL
 int evdns_config_windows_nameservers(void);
 #define EVDNS_CONFIG_WINDOWS_NAMESERVERS_IMPLEMENTED
 #endif
index 570031f264b0bfc66589701ee2b66ff21f1afb4c..a6b6144a92be81d860b58c23e957d930b0686d43 100644 (file)
@@ -232,7 +232,7 @@ struct event_base
  *
  * Generally, you can create events with event_new(), then make them
  * pending with event_add().  As your event_base runs, it will run the
- * callbacks of an events whose conditions are triggered.  When you
+ * callbacks of an events whose conditions are triggered.  When you no
  * longer want the event, free it with event_free().
  *
  * In more depth:
@@ -285,7 +285,7 @@ struct event
  * There are many options that can be used to alter the behavior and
  * implementation of an event_base.  To avoid having to pass them all in a
  * complex many-argument constructor, we provide an abstract data type
- * wrhere you set up configation information before passing it to
+ * where you set up configuration information before passing it to
  * event_base_new_with_config().
  *
  * @see event_config_new(), event_config_free(), event_base_new_with_config(),
@@ -632,7 +632,7 @@ int event_config_set_num_cpus_hint(struct event_config *cfg, int cpus);
 /**
  * Record an interval and/or a number of callbacks after which the event base
  * should check for new events.  By default, the event base will run as many
- * events are as activated at the higest activated priority before checking
+ * events are as activated at the highest activated priority before checking
  * for new events.  If you configure it by setting max_interval, it will check
  * the time after each callback, and not allow more than max_interval to
  * elapse before checking for new events.  If you configure it by setting
@@ -692,10 +692,7 @@ EVENT2_EXPORT_SYMBOL
 void event_base_free(struct event_base *);
 
 /**
-   As event_free, but do not run finalizers.
-
-   THIS IS AN EXPERIMENTAL API. IT MIGHT CHANGE BEFORE THE LIBEVENT 2.1 SERIES
-   BECOMES STABLE.
+   As event_base_free, but do not run finalizers.
  */
 EVENT2_EXPORT_SYMBOL
 void event_base_free_nofinalize(struct event_base *);
@@ -777,10 +774,6 @@ void event_set_fatal_callback(event_fatal_cb cb);
 EVENT2_EXPORT_SYMBOL
 void event_enable_debug_logging(ev_uint32_t which);
 
-EVENT2_EXPORT_SYMBOL
-void
-event_disable_debug_mode(void);
-
 /**
   Associate a different event base with an event.
 
@@ -948,9 +941,6 @@ int event_base_got_break(struct event_base *);
  * To use this option safely, you may need to use event_finalize() or
  * event_free_finalize() in order to safely tear down an event in a
  * multithreaded application.  See those functions for more information.
- *
- * THIS IS AN EXPERIMENTAL API. IT MIGHT CHANGE BEFORE THE LIBEVENT 2.1 SERIES
- * BECOMES STABLE.
  **/
 #define EV_FINALIZE     0x40
 /**
@@ -967,11 +957,13 @@ int event_base_got_break(struct event_base *);
 /**
    @name evtimer_* macros
 
-    Aliases for working with one-shot timer events */
+   Aliases for working with one-shot timer events
+   If you need EV_PERSIST timer use event_*() functions.
+ */
 /**@{*/
 #define evtimer_assign(ev, b, cb, arg) \
        event_assign((ev), (b), -1, 0, (cb), (arg))
-#define evtimer_new(b, cb, arg)               event_new((b), -1, 0, (cb), (arg))
+#define evtimer_new(b, cb, arg)                event_new((b), -1, 0, (cb), (arg))
 #define evtimer_add(ev, tv)            event_add((ev), (tv))
 #define evtimer_del(ev)                        event_del(ev)
 #define evtimer_pending(ev, tv)                event_pending((ev), EV_TIMEOUT, (tv))
@@ -994,6 +986,20 @@ int event_base_got_break(struct event_base *);
 #define evsignal_initialized(ev)       event_initialized(ev)
 /**@}*/
 
+/**
+   @name evuser_* macros
+
+   Aliases for working with user-triggered events
+   If you need EV_PERSIST event use event_*() functions.
+ */
+/**@{*/
+#define evuser_new(b, cb, arg)         event_new((b), -1, 0, (cb), (arg))
+#define evuser_del(ev)                 event_del(ev)
+#define evuser_pending(ev, tv)         event_pending((ev), 0, (tv))
+#define evuser_initialized(ev)         event_initialized(ev)
+#define evuser_trigger(ev)             event_active((ev), 0, 0)
+/**@}*/
+
 /**
    A callback function for an event.
 
@@ -1033,7 +1039,7 @@ EVENT2_EXPORT_SYMBOL
 void *event_self_cbarg(void);
 
 /**
-  Allocate and asssign a new event structure, ready to be added.
+  Allocate and assign a new event structure, ready to be added.
 
   The function event_new() returns a new event that can be used in
   future calls to event_add() and event_del().  The fd and events
@@ -1059,10 +1065,10 @@ void *event_self_cbarg(void);
   The EV_TIMEOUT flag has no effect here.
 
   It is okay to have multiple events all listening on the same fds; but
-  they must either all be edge-triggered, or all not be edge triggerd.
+  they must either all be edge-triggered, or all not be edge triggered.
 
   When the event becomes active, the event loop will run the provided
-  callbuck function, with three arguments.  The first will be the provided
+  callback function, with three arguments.  The first will be the provided
   fd value.  The second will be a bitfield of the events that triggered:
   EV_READ, EV_WRITE, or EV_SIGNAL.  Here the EV_TIMEOUT flag indicates
   that a timeout occurred, and EV_ET indicates that an edge-triggered
@@ -1077,7 +1083,7 @@ void *event_self_cbarg(void);
   @param callback_arg an argument to be passed to the callback function
 
   @return a newly allocated struct event that must later be freed with
-    event_free().
+    event_free() or NULL if an error occurred.
   @see event_free(), event_add(), event_del(), event_assign()
  */
 EVENT2_EXPORT_SYMBOL
@@ -1128,18 +1134,14 @@ int event_assign(struct event *, struct event_base *, evutil_socket_t, short, ev
 /**
    Deallocate a struct event * returned by event_new().
 
-   If the event is pending or active, first make it non-pending and
-   non-active.
+   If the event is pending or active, this function makes it non-pending
+   and non-active first.
  */
 EVENT2_EXPORT_SYMBOL
 void event_free(struct event *);
 
 /**
  * Callback type for event_finalize and event_free_finalize().
- *
- * THIS IS AN EXPERIMENTAL API. IT MIGHT CHANGE BEFORE THE LIBEVENT 2.1 SERIES
- * BECOMES STABLE.
- *
  **/
 typedef void (*event_finalize_callback_fn)(struct event *, void *);
 /**
@@ -1167,13 +1169,10 @@ typedef void (*event_finalize_callback_fn)(struct event *, void *);
    event_finalize() does not.
 
    A finalizer callback must not make events pending or active.  It must not
-   add events, activate events, or attempt to "resucitate" the event being
+   add events, activate events, or attempt to "resuscitate" the event being
    finalized in any way.
 
-   THIS IS AN EXPERIMENTAL API. IT MIGHT CHANGE BEFORE THE LIBEVENT 2.1 SERIES
-   BECOMES STABLE.
-
-   @return 0 on succes, -1 on failure.
+   @return 0 on success, -1 on failure.
  */
 /**@{*/
 EVENT2_EXPORT_SYMBOL
@@ -1203,7 +1202,7 @@ int event_free_finalize(unsigned, struct event *, event_finalize_callback_fn);
   @param arg an argument to be passed to the callback function
   @param timeout the maximum amount of time to wait for the event. NULL
          makes an EV_READ/EV_WRITE event make forever; NULL makes an
-        EV_TIMEOUT event succees immediately.
+        EV_TIMEOUT event success immediately.
   @return 0 if successful, or -1 if an error occurred
  */
 EVENT2_EXPORT_SYMBOL
@@ -1214,7 +1213,7 @@ int event_base_once(struct event_base *, evutil_socket_t, short, event_callback_
 
   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
+  specified in timeout has elapsed.  If a timeout is NULL, no timeout
   occurs and the function will only be
   called if a matching event occurs.  The event in the
   ev argument must be already initialized by event_assign() or event_new()
@@ -1240,7 +1239,7 @@ int event_add(struct event *ev, const struct timeval *timeout);
    leaves the event otherwise pending.
 
    @param ev an event struct initialized via event_assign() or event_new()
-   @return 0 on success, or -1 if  an error occurrect.
+   @return 0 on success, or -1 if an error occurred.
 */
 EVENT2_EXPORT_SYMBOL
 int event_remove_timer(struct event *ev);
@@ -1263,9 +1262,6 @@ int event_del(struct event *);
    As event_del(), but never blocks while the event's callback is running
    in another thread, even if the event was constructed without the
    EV_FINALIZE flag.
-
-   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);
@@ -1273,9 +1269,6 @@ int event_del_noblock(struct event *ev);
    As event_del(), but always blocks while the event's callback is running
    in another thread, even if the event was constructed with the
    EV_FINALIZE flag.
-
-   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);
@@ -1328,7 +1321,7 @@ struct event *event_base_get_running_event(struct event_base *base);
   The event_initialized() function can be used to check if an event has been
   initialized.
 
-  Warning: This function is only useful for distinguishing a zeroed-out
+  Warning: This function is only useful for distinguishing a zeroed-out
     piece of memory from an initialized event, it can easily be confused by
     uninitialized memory.  Thus, it should ONLY be used to distinguish an
     initialized event from zero.
@@ -1535,7 +1528,7 @@ const struct timeval *event_base_init_common_timeout(struct event_base *base,
 
  Note also that if you are going to call this function, you should do so
  before any call to any Libevent function that does allocation.
- Otherwise, those funtions will allocate their memory using malloc(), but
+ Otherwise, those functions will allocate their memory using malloc(), but
  then later free it using your provided free_fn.
 
  @param malloc_fn A replacement for malloc.
@@ -1574,7 +1567,7 @@ void event_base_dump_events(struct event_base *, FILE *);
 
    @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}.
+   @param events One or more of EV_{READ,WRITE,TIMEOUT}.
  */
 EVENT2_EXPORT_SYMBOL
 void event_base_active_by_fd(struct event_base *base, evutil_socket_t fd, short events);
@@ -1631,7 +1624,7 @@ int event_base_foreach_event(struct event_base *base, event_base_foreach_event_c
     cached time.
 
     Generally, this value will only be cached while actually
-    processing event callbacks, and may be very inaccuate if your
+    processing event callbacks, and may be very inaccurate if your
     callbacks take a long time to execute.
 
     Returns 0 on success, negative on failure.
index 4284d5fc32bc21bffb8cde93c4422930616d0a67..2a41303ede0e3cd66fd7fb00185b725f95cbde59 100644 (file)
@@ -78,7 +78,8 @@ struct evdns_base;
  * Create a new HTTP server.
  *
  * @param base (optional) the event base to receive the HTTP events
- * @return a pointer to a newly initialized evhttp server structure
+ * @return a pointer to a newly initialized evhttp server structure or NULL
+ *   on error
  * @see evhttp_free()
  */
 EVENT2_EXPORT_SYMBOL
@@ -373,6 +374,19 @@ void evhttp_set_timeout(struct evhttp *http, int timeout_in_secs);
 EVENT2_EXPORT_SYMBOL
 void evhttp_set_timeout_tv(struct evhttp *http, const struct timeval* tv);
 
+/* Read all the clients body, and only after this respond with an error if the
+ * clients body exceed max_body_size */
+#define EVHTTP_SERVER_LINGERING_CLOSE  0x0001
+/**
+ * Set connection flags for HTTP server.
+ *
+ * @see EVHTTP_SERVER_*
+ * @return 0 on success, otherwise non zero (for example if flag doesn't
+ * supported).
+ */
+EVENT2_EXPORT_SYMBOL
+int evhttp_set_flags(struct evhttp *http, int flags);
+
 /* Request/Response functionality */
 
 /**
@@ -503,11 +517,12 @@ enum evhttp_request_kind { EVHTTP_REQUEST, EVHTTP_RESPONSE };
  *     when the connection closes.  It must have no fd set on it.
  * @param address the address to which to connect
  * @param port the port to connect to
- * @return an evhttp_connection object that can be used for making requests
+ * @return an evhttp_connection object that can be used for making requests or
+ *   NULL on error
  */
 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);
+       struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev, const char *address, ev_uint16_t port);
 
 /**
  * Return the bufferevent that an evhttp_connection is using.
@@ -623,19 +638,42 @@ void evhttp_request_free(struct evhttp_request *req);
  *     specified host name resolution will block.
  * @param address the address to which to connect
  * @param port the port to connect to
- * @return an evhttp_connection object that can be used for making requests
+ * @return an evhttp_connection object that can be used for making requests or
+ *   NULL on error
  */
 EVENT2_EXPORT_SYMBOL
 struct evhttp_connection *evhttp_connection_base_new(
        struct event_base *base, struct evdns_base *dnsbase,
-       const char *address, unsigned short port);
+       const char *address, ev_uint16_t port);
 
 /**
  * Set family hint for DNS requests.
  */
+EVENT2_EXPORT_SYMBOL
 void evhttp_connection_set_family(struct evhttp_connection *evcon,
        int family);
 
+/* reuse connection address on retry */
+#define EVHTTP_CON_REUSE_CONNECTED_ADDR        0x0008
+/* Try to read error, since server may already send and close
+ * connection, but if at that time we have some data to send then we
+ * can send get EPIPE and fail, while we can read that HTTP error. */
+#define EVHTTP_CON_READ_ON_WRITE_ERROR 0x0010
+/* @see EVHTTP_SERVER_LINGERING_CLOSE */
+#define EVHTTP_CON_LINGERING_CLOSE     0x0020
+/* Padding for public flags, @see EVHTTP_CON_* in http-internal.h */
+#define EVHTTP_CON_PUBLIC_FLAGS_END    0x100000
+/**
+ * Set connection flags.
+ *
+ * @see EVHTTP_CON_*
+ * @return 0 on success, otherwise non zero (for example if flag doesn't
+ * supported).
+ */
+EVENT2_EXPORT_SYMBOL
+int evhttp_connection_set_flags(struct evhttp_connection *evcon,
+       int flags);
+
 /** Takes ownership of the request object
  *
  * Can be used in a request callback to keep onto the request until
@@ -728,7 +766,7 @@ void evhttp_connection_get_peer(struct evhttp_connection *evcon,
     char **address, ev_uint16_t *port);
 
 /** Get the remote address associated with this connection.
- * extracted from getpeername().
+ * extracted from getpeername() OR from nameserver.
  *
  * @return NULL if getpeername() return non success,
  * or connection is not connected,
@@ -892,14 +930,14 @@ char *evhttp_uriencode(const char *str, ev_ssize_t size, int space_to_plus);
 
 /**
   Helper function to sort of decode a URI-encoded string.  Unlike
-  evhttp_get_decoded_uri, it decodes all plus characters that appear
+  evhttp_uridecode, it decodes all plus characters that appear
   _after_ the first question mark character, but no plusses that occur
   before.  This is not a good way to decode URIs in whole or in part.
 
   The returned string must be freed by the caller
 
   @deprecated  This function is deprecated; you probably want to use
-     evhttp_get_decoded_uri instead.
+     evhttp_uridecode instead.
 
   @param uri an encoded URI
   @return a newly allocated unencoded URI or NULL on failure
index 0d9af17f3feda103a0b9957a55589057e61b611a..794a581083e4e12dd9d48679cb06d89469e5e070 100644 (file)
@@ -56,9 +56,11 @@ extern "C" {
  *
  * @param address the address to which the HTTP server should be bound
  * @param port the port number on which the HTTP server should listen
- * @return an struct evhttp object
+ * @return a pointer to a newly initialized evhttp server structure
+ *   or NULL on error
  */
-struct evhttp *evhttp_start(const char *address, unsigned short port);
+EVENT2_EXPORT_SYMBOL
+struct evhttp *evhttp_start(const char *address, ev_uint16_t port);
 
 /**
  * A connection object that can be used to for making HTTP requests.  The
@@ -67,8 +69,9 @@ struct evhttp *evhttp_start(const char *address, unsigned short port);
  *
  * @deprecated It does not allow an event base to be specified
  */
+EVENT2_EXPORT_SYMBOL
 struct evhttp_connection *evhttp_connection_new(
-       const char *address, unsigned short port);
+       const char *address, ev_uint16_t port);
 
 /**
  * Associates an event base with the connection - can only be called
@@ -76,6 +79,7 @@ struct evhttp_connection *evhttp_connection_new(
  *
  * @deprecated XXXX Why?
  */
+EVENT2_EXPORT_SYMBOL
 void evhttp_connection_set_base(struct evhttp_connection *evcon,
     struct event_base *base);
 
index 84b4da055d8d24fa3edd1e4b1fa3f40f769991de..789a27c2aacc59cd336567234993b400d5f45d23 100644 (file)
@@ -97,6 +97,18 @@ typedef void (*evconnlistener_errorcb)(struct evconnlistener *, void *);
  * This is only available on Linux and kernel 3.9+
  */
 #define LEV_OPT_REUSEABLE_PORT         (1u<<7)
+/** Flag: Indicates that the listener wants to work only in IPv6 socket.
+ *
+ * According to RFC3493 and most Linux distributions, default value is to
+ * work in IPv4-mapped mode. If there is a requirement to bind same port
+ * on same ip addresses but different handlers for both IPv4 and IPv6,
+ * it is required to set IPV6_V6ONLY socket option to be sure that the
+ * code works as expected without affected by bindv6only sysctl setting in
+ * system.
+ *
+ * This socket option also supported by Windows.
+ */
+#define LEV_OPT_BIND_IPV6ONLY          (1u<<8)
 
 /**
    Allocate a new evconnlistener object to listen for incoming TCP connections
index dd43df266a179372c9baaae4579e8e3d3c2ef370..1bc31d57117eae99bfc8f78dc32b7e29d00c9989 100644 (file)
 #ifndef EVENT2_RPC_H_INCLUDED_
 #define EVENT2_RPC_H_INCLUDED_
 
+/* For int types. */
+#include <event2/util.h>
+#include <event2/visibility.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -178,6 +182,7 @@ EVRPC_STRUCT(rpcname) {     \
        struct evhttp_request* http_req; \
        struct evbuffer* rpc_data; \
 };                                                                  \
+EVENT2_EXPORT_SYMBOL \
 int evrpc_send_request_##rpcname(struct evrpc_pool *, \
     struct reqstruct *, struct rplystruct *, \
     void (*)(struct evrpc_status *, \
@@ -187,6 +192,7 @@ int evrpc_send_request_##rpcname(struct evrpc_pool *, \
 struct evrpc_pool;
 
 /** use EVRPC_GENERATE instead */
+EVENT2_EXPORT_SYMBOL
 struct evrpc_request_wrapper *evrpc_make_request_ctx(
        struct evrpc_pool *pool, void *request, void *reply,
        const char *rpcname,
@@ -257,10 +263,13 @@ struct evrpc_request_wrapper *evrpc_make_request_ctx(
 #define EVRPC_REQUEST_HTTP(rpc_req) (rpc_req)->http_req
 
 /** completes the server response to an rpc request */
+EVENT2_EXPORT_SYMBOL
 void evrpc_request_done(struct evrpc_req_generic *req);
 
 /** accessors for request and reply */
+EVENT2_EXPORT_SYMBOL
 void *evrpc_get_request(struct evrpc_req_generic *req);
+EVENT2_EXPORT_SYMBOL
 void *evrpc_get_reply(struct evrpc_req_generic *req);
 
 /** Creates the reply to an RPC request
@@ -285,9 +294,10 @@ struct evhttp;
 /** Creates a new rpc base from which RPC requests can be received
  *
  * @param server a pointer to an existing HTTP server
- * @return a newly allocated evrpc_base struct
+ * @return a newly allocated evrpc_base struct or NULL if an error occurred
  * @see evrpc_free()
  */
+EVENT2_EXPORT_SYMBOL
 struct evrpc_base *evrpc_init(struct evhttp *server);
 
 /**
@@ -298,6 +308,7 @@ struct evrpc_base *evrpc_init(struct evhttp *server);
  * @param base the evrpc_base object to be freed
  * @see evrpc_init
  */
+EVENT2_EXPORT_SYMBOL
 void evrpc_free(struct evrpc_base *base);
 
 /** register RPCs with the HTTP Server
@@ -319,10 +330,10 @@ void evrpc_free(struct evrpc_base *base);
 #define EVRPC_REGISTER(base, name, request, reply, callback, cbarg)    \
        evrpc_register_generic(base, #name,                             \
            (void (*)(struct evrpc_req_generic *, void *))callback, cbarg, \
-           (void *(*)(void *))request##_new, NULL,                     \
+           (void *(*)(void *))request##_new_with_arg, NULL,            \
            (void (*)(void *))request##_free,                           \
            (int (*)(void *, struct evbuffer *))request##_unmarshal,    \
-           (void *(*)(void *))reply##_new, NULL,                       \
+           (void *(*)(void *))reply##_new_with_arg, NULL,              \
            (void (*)(void *))reply##_free, \
            (int (*)(void *))reply##_complete, \
            (void (*)(struct evbuffer *, void *))reply##_marshal)
@@ -334,6 +345,7 @@ void evrpc_free(struct evrpc_base *base);
 
    @see EVRPC_REGISTER()
 */
+EVENT2_EXPORT_SYMBOL
 int evrpc_register_rpc(struct evrpc_base *, struct evrpc *,
     void (*)(struct evrpc_req_generic*, void *), void *);
 
@@ -347,6 +359,7 @@ int evrpc_register_rpc(struct evrpc_base *, struct evrpc *,
  */
 #define EVRPC_UNREGISTER(base, name) evrpc_unregister_rpc((base), #name)
 
+EVENT2_EXPORT_SYMBOL
 int evrpc_unregister_rpc(struct evrpc_base *base, const char *name);
 
 /*
@@ -385,6 +398,7 @@ struct evrpc_status;
    @returns 0 on success, -1 otherwise.
    @see EVRPC_MAKE_REQUEST(), EVRPC_MAKE_CTX()
 */
+EVENT2_EXPORT_SYMBOL
 int evrpc_make_request(struct evrpc_request_wrapper *ctx);
 
 /** creates an rpc connection pool
@@ -394,15 +408,18 @@ int evrpc_make_request(struct evrpc_request_wrapper *ctx);
  *
  * @param base a pointer to an struct event_based object; can be left NULL
  *   in singled-threaded applications
- * @return a newly allocated struct evrpc_pool object
+ * @return a newly allocated struct evrpc_pool object or NULL if an error
+ *   occurred
  * @see evrpc_pool_free()
  */
+EVENT2_EXPORT_SYMBOL
 struct evrpc_pool *evrpc_pool_new(struct event_base *base);
 /** frees an rpc connection pool
  *
  * @param pool a pointer to an evrpc_pool allocated via evrpc_pool_new()
  * @see evrpc_pool_new()
  */
+EVENT2_EXPORT_SYMBOL
 void evrpc_pool_free(struct evrpc_pool *pool);
 
 /**
@@ -413,6 +430,7 @@ void evrpc_pool_free(struct evrpc_pool *pool);
  * @param pool the pool to which to add the connection
  * @param evcon the connection to add to the pool.
  */
+EVENT2_EXPORT_SYMBOL
 void evrpc_pool_add_connection(struct evrpc_pool *pool,
     struct evhttp_connection *evcon);
 
@@ -424,6 +442,7 @@ void evrpc_pool_add_connection(struct evrpc_pool *pool,
  * @param pool the pool from which to remove the connection
  * @param evcon the connection to remove from the pool.
  */
+EVENT2_EXPORT_SYMBOL
 void evrpc_pool_remove_connection(struct evrpc_pool *pool,
     struct evhttp_connection *evcon);
 
@@ -442,6 +461,7 @@ void evrpc_pool_remove_connection(struct evrpc_pool *pool,
  * @param timeout_in_secs the number of seconds after which a request should
  *   timeout and a failure be returned to the callback.
  */
+EVENT2_EXPORT_SYMBOL
 void evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs);
 
 /**
@@ -489,6 +509,7 @@ enum EVRPC_HOOK_RESULT {
  * @return a handle to the hook so it can be removed later
  * @see evrpc_remove_hook()
  */
+EVENT2_EXPORT_SYMBOL
 void *evrpc_add_hook(void *vbase,
     enum EVRPC_HOOK_TYPE hook_type,
     int (*cb)(void *, struct evhttp_request *, struct evbuffer *, void *),
@@ -502,6 +523,7 @@ void *evrpc_add_hook(void *vbase,
  * @return 1 on success or 0 on failure
  * @see evrpc_add_hook()
  */
+EVENT2_EXPORT_SYMBOL
 int evrpc_remove_hook(void *vbase,
     enum EVRPC_HOOK_TYPE hook_type,
     void *handle);
@@ -511,8 +533,8 @@ int evrpc_remove_hook(void *vbase,
  * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool
  * @param ctx the context pointer provided to the original hook call
  */
-int
-evrpc_resume_request(void *vbase, void *ctx, enum EVRPC_HOOK_RESULT res);
+EVENT2_EXPORT_SYMBOL
+int evrpc_resume_request(void *vbase, void *ctx, enum EVRPC_HOOK_RESULT res);
 
 /** adds meta data to request
  *
@@ -525,6 +547,7 @@ evrpc_resume_request(void *vbase, void *ctx, enum EVRPC_HOOK_RESULT res);
  * @param data the data to be associated with the key
  * @param data_size the size of the data
  */
+EVENT2_EXPORT_SYMBOL
 void evrpc_hook_add_meta(void *ctx, const char *key,
     const void *data, size_t data_size);
 
@@ -538,6 +561,7 @@ void evrpc_hook_add_meta(void *ctx, const char *key,
  * @param data_size pointer to the size of the data
  * @return 0 on success or -1 on failure
  */
+EVENT2_EXPORT_SYMBOL
 int evrpc_hook_find_meta(void *ctx, const char *key,
     void **data, size_t *data_size);
 
@@ -545,8 +569,10 @@ int evrpc_hook_find_meta(void *ctx, const char *key,
  * returns the connection object associated with the request
  *
  * @param ctx the context provided to the hook call
- * @return a pointer to the evhttp_connection object
+ * @return a pointer to the evhttp_connection object or NULL if an error
+ *   occurred
  */
+EVENT2_EXPORT_SYMBOL
 struct evhttp_connection *evrpc_hook_get_connection(void *ctx);
 
 /**
@@ -556,6 +582,7 @@ struct evhttp_connection *evrpc_hook_get_connection(void *ctx);
 
    @see EVRPC_MAKE_REQUEST()
  */
+EVENT2_EXPORT_SYMBOL
 int evrpc_send_request_generic(struct evrpc_pool *pool,
     void *request, void *reply,
     void (*cb)(struct evrpc_status *, void *, void *, void *),
@@ -572,8 +599,8 @@ int evrpc_send_request_generic(struct evrpc_pool *pool,
 
    @see EVRPC_REGISTER()
  */
-int
-evrpc_register_generic(struct evrpc_base *base, const char *name,
+EVENT2_EXPORT_SYMBOL
+int evrpc_register_generic(struct evrpc_base *base, const char *name,
     void (*callback)(struct evrpc_req_generic *, void *), void *cbarg,
     void *(*req_new)(void *), void *req_new_arg, void (*req_free)(void *),
     int (*req_unmarshal)(void *, struct evbuffer *),
@@ -582,9 +609,12 @@ evrpc_register_generic(struct evrpc_base *base, const char *name,
     void (*rpl_marshal)(struct evbuffer *, void *));
 
 /** accessors for obscure and undocumented functionality */
+EVENT2_EXPORT_SYMBOL
 struct evrpc_pool* evrpc_request_get_pool(struct evrpc_request_wrapper *ctx);
+EVENT2_EXPORT_SYMBOL
 void evrpc_request_set_pool(struct evrpc_request_wrapper *ctx,
     struct evrpc_pool *pool);
+EVENT2_EXPORT_SYMBOL
 void evrpc_request_set_cb(struct evrpc_request_wrapper *ctx,
     void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg),
     void *cb_arg);
index 8f691f49fbcdd912b902dab29f283245046e8456..f3cb460aed413b4238b4ca25de5136088d16252a 100644 (file)
@@ -38,6 +38,16 @@ extern "C" {
 
  */
 
+/* Fix so that people don't have to run with <sys/queue.h> */
+#ifndef TAILQ_ENTRY
+#define EVENT_DEFINED_TQENTRY_
+#define TAILQ_ENTRY(type)                                              \
+struct {                                                               \
+       struct type *tqe_next;  /* next element */                      \
+       struct type **tqe_prev; /* address of previous next element */  \
+}
+#endif /* !TAILQ_ENTRY */
+
 /**
  * provides information about the completed RPC request.
  */
@@ -93,6 +103,10 @@ struct evrpc {
        struct evrpc_base *base;
 };
 
+#ifdef EVENT_DEFINED_TQENTRY_
+#undef TAILQ_ENTRY
+#endif
+
 #ifdef __cplusplus
 }
 #endif
index b152a4b40b5142f090212b7c091a3e8e700dbc0a..02aa7ba9dab8291f6c907ccb3c24f0dd4a016613 100644 (file)
@@ -58,9 +58,6 @@ extern "C" {
 #endif
 #include <stdarg.h>
 #ifdef EVENT__HAVE_NETDB_H
-#if !defined(_GNU_SOURCE)
-#define _GNU_SOURCE
-#endif
 #include <netdb.h>
 #endif
 
@@ -71,9 +68,14 @@ extern "C" {
 #include <ws2tcpip.h>
 #endif
 #else
+#ifdef EVENT__HAVE_ERRNO_H
+#include <errno.h>
+#endif
 #include <sys/socket.h>
 #endif
 
+#include <time.h>
+
 /* Some openbsd autoconf versions get the name of this macro wrong. */
 #if defined(EVENT__SIZEOF_VOID__) && !defined(EVENT__SIZEOF_VOID_P)
 #define EVENT__SIZEOF_VOID_P EVENT__SIZEOF_VOID__
@@ -233,6 +235,7 @@ extern "C" {
 
    @{
 */
+#ifndef EVENT__HAVE_STDINT_H
 #define EV_UINT64_MAX ((((ev_uint64_t)0xffffffffUL) << 32) | 0xffffffffUL)
 #define EV_INT64_MAX  ((((ev_int64_t) 0x7fffffffL) << 32) | 0xffffffffL)
 #define EV_INT64_MIN  ((-EV_INT64_MAX) - 1)
@@ -245,7 +248,22 @@ extern "C" {
 #define EV_UINT8_MAX  255
 #define EV_INT8_MAX   127
 #define EV_INT8_MIN   ((-EV_INT8_MAX) - 1)
+#else
+#define EV_UINT64_MAX UINT64_MAX
+#define EV_INT64_MAX  INT64_MAX
+#define EV_INT64_MIN  INT64_MIN
+#define EV_UINT32_MAX UINT32_MAX
+#define EV_INT32_MAX  INT32_MAX
+#define EV_INT32_MIN  INT32_MIN
+#define EV_UINT16_MAX UINT16_MAX
+#define EV_INT16_MIN  INT16_MIN
+#define EV_INT16_MAX  INT16_MAX
+#define EV_UINT8_MAX  UINT8_MAX
+#define EV_INT8_MAX   INT8_MAX
+#define EV_INT8_MIN   INT8_MIN
 /** @} */
+#endif
+
 
 /**
    @name Limits for SIZE_T and SSIZE_T
@@ -313,6 +331,15 @@ struct evutil_monotonic_timer
 #define EV_MONOT_PRECISE  1
 #define EV_MONOT_FALLBACK 2
 
+/** Format a date string using RFC 1123 format (used in HTTP).
+ * If `tm` is NULL, current system's time will be used.
+ * The number of characters written will be returned.
+ * One should check if the return value is smaller than `datelen` to check if
+ * the result is truncated or not.
+ */
+EVENT2_EXPORT_SYMBOL int
+evutil_date_rfc1123(char *date, const size_t datelen, const struct tm *tm);
+
 /** Allocate a new struct evutil_monotonic_timer for use with the
  * evutil_configure_monotonic_time() and evutil_gettime_monotonic()
  * functions.  You must configure the timer with
@@ -396,6 +423,18 @@ int evutil_make_listen_socket_reuseable(evutil_socket_t sock);
 EVENT2_EXPORT_SYMBOL
 int evutil_make_listen_socket_reuseable_port(evutil_socket_t sock);
 
+/** Set ipv6 only bind socket option to make listener work only in ipv6 sockets.
+
+    According to RFC3493 and most Linux distributions, default value for the
+    sockets is to work in IPv4-mapped mode. In IPv4-mapped mode, it is not possible
+    to bind same port from different IPv4 and IPv6 handlers.
+
+    @param sock The socket to make in ipv6only working mode
+    @return 0 on success, -1 on failure
+ */
+EVENT2_EXPORT_SYMBOL
+int evutil_make_listen_socket_ipv6only(evutil_socket_t sock);
+
 /** Do platform-specific operations as needed to close a socket upon a
     successful execution of one of the exec*() functions.
 
@@ -409,7 +448,8 @@ int evutil_make_socket_closeonexec(evutil_socket_t sock);
     socket() or accept().
 
     @param sock The socket to be closed
-    @return 0 on success, -1 on failure
+    @return 0 on success (whether the operation is supported or not),
+            -1 on failure
  */
 EVENT2_EXPORT_SYMBOL
 int evutil_closesocket(evutil_socket_t sock);
@@ -441,6 +481,7 @@ 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);
+#define EVUTIL_INVALID_SOCKET INVALID_SOCKET
 #elif defined(EVENT_IN_DOXYGEN_)
 /**
    @name Socket error functions
@@ -464,14 +505,16 @@ const char *evutil_socket_error_to_string(int errcode);
 #define evutil_socket_geterror(sock) ...
 /** Convert a socket error to a string. */
 #define evutil_socket_error_to_string(errcode) ...
+#define EVUTIL_INVALID_SOCKET -1
 /**@}*/
-#else
+#else /** !EVENT_IN_DOXYGEN_ && !_WIN32 */
 #define EVUTIL_SOCKET_ERROR() (errno)
 #define EVUTIL_SET_SOCKET_ERROR(errcode)               \
                do { errno = (errcode); } while (0)
 #define evutil_socket_geterror(sock) (errno)
 #define evutil_socket_error_to_string(errcode) (strerror(errcode))
-#endif
+#define EVUTIL_INVALID_SOCKET -1
+#endif /** !_WIN32 */
 
 
 /**
@@ -569,6 +612,12 @@ 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);
+/** Variation of inet_pton that also parses IPv6 scopes. Public for
+    unit tests. No reason to call this directly.
+ */
+EVENT2_EXPORT_SYMBOL
+int evutil_inet_pton_scope(int af, const char *src, void *dst,
+       unsigned *indexp);
 /** Replacement for inet_pton for platforms which lack it. */
 EVENT2_EXPORT_SYMBOL
 int evutil_inet_pton(int af, const char *src, void *dst);
@@ -813,6 +862,7 @@ int evutil_secure_rng_init(void);
 EVENT2_EXPORT_SYMBOL
 int evutil_secure_rng_set_urandom_device_file(char *fname);
 
+#if !defined(EVENT__HAVE_ARC4RANDOM) || defined(EVENT__HAVE_ARC4RANDOM_ADDRANDOM)
 /** Seed the random number generator with extra random bytes.
 
     You should almost never need to call this function; it should be
@@ -829,6 +879,7 @@ int evutil_secure_rng_set_urandom_device_file(char *fname);
  */
 EVENT2_EXPORT_SYMBOL
 void evutil_secure_rng_add_bytes(const char *dat, size_t datlen);
+#endif
 
 #ifdef __cplusplus
 }
index 5e7163a1e9934346e28eca534a842b8a6f25afbf..006bbf06d80f6d4c807c06ce531df33384b78bf1 100644 (file)
 
 #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
+#if defined(event_shared_EXPORTS) || \
+    defined(event_extra_shared_EXPORTS) || \
+    defined(event_core_shared_EXPORTS) || \
+    defined(event_pthreads_shared_EXPORTS) || \
+    defined(event_openssl_shared_EXPORTS)
 
-#else
+# 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 __declspec(dllexport)
+# else
+#  define EVENT2_EXPORT_SYMBOL /* unknown compiler */
+# endif
 
-#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
+#else /* event_*_EXPORTS */
+
+# define EVENT2_EXPORT_SYMBOL
+
+#endif /* event_*_EXPORTS */
 
+/** We need to dllimport event_debug_logging_mask_ into event_extra */
+#if defined(_MSC_VER)
+# if defined(event_core_shared_EXPORTS) /** from core export */
+#  define EVENT2_CORE_EXPORT_SYMBOL __declspec(dllexport)
+# elif defined(event_extra_shared_EXPORTS) || /** from extra import */ \
+       defined(EVENT_VISIBILITY_WANT_DLLIMPORT)
+#  define EVENT2_CORE_EXPORT_SYMBOL __declspec(dllimport)
+# endif
+#endif /* _MSC_VER */
+#if !defined(EVENT2_CORE_EXPORT_SYMBOL)
+# define EVENT2_CORE_EXPORT_SYMBOL EVENT2_EXPORT_SYMBOL
 #endif
 
 #endif /* EVENT2_VISIBILITY_H_INCLUDED_ */
index 9aad2dba4abe65d36f78be6fcefafccc5e255656..aaa2042af1f611b79b6a48ee2f62299f2190b7f7 100644 (file)
@@ -1,4 +1,4 @@
-# include/Makefile.am for libevent
+# include/include.am for libevent
 # Copyright 2000-2007 Niels Provos
 # Copyright 2007-2012 Niels Provos and Nick Mathewson
 #
@@ -11,7 +11,6 @@ EVENT2_EXPORT = \
        include/event2/buffer_compat.h \
        include/event2/bufferevent.h \
        include/event2/bufferevent_compat.h \
-       include/event2/bufferevent_ssl.h \
        include/event2/bufferevent_struct.h \
        include/event2/dns.h \
        include/event2/dns_compat.h \
@@ -33,6 +32,10 @@ EVENT2_EXPORT = \
        include/event2/util.h \
        include/event2/visibility.h
 
+if OPENSSL
+EVENT2_EXPORT += include/event2/bufferevent_ssl.h
+endif
+
 ## Without the nobase_ prefixing, Automake would strip "include/event2/" from
 ## the source header filename to derive the installed header filename.
 ## With nobase_ the installed path is $(includedir)/include/event2/ev*.h.
index 93dbe2b1a454e8a236d6487c62c25ecab831203b..21e0e0af68070daf13c9d089b2bec754cd3a8c3e 100644 (file)
@@ -92,6 +92,7 @@ struct event_iocp_port {
        HANDLE *shutdownSemaphore;
 };
 
+EVENT2_EXPORT_SYMBOL
 const struct win32_extension_fns *event_get_win32_extension_fns_(void);
 #else
 /* Dummy definition so we can test-compile more things on unix. */
@@ -106,12 +107,14 @@ struct event_overlapped {
     @param cb The callback that should be invoked once the IO operation has
        finished.
  */
+EVENT2_EXPORT_SYMBOL
 void event_overlapped_init_(struct event_overlapped *, iocp_callback cb);
 
 /** Allocate and return a new evbuffer that supports overlapped IO on a given
     socket.  The socket must be associated with an IO completion port using
     event_iocp_port_associate_.
 */
+EVENT2_EXPORT_SYMBOL
 struct evbuffer *evbuffer_overlapped_new_(evutil_socket_t fd);
 
 /** XXXX Document (nickm) */
@@ -131,6 +134,7 @@ void evbuffer_overlapped_set_fd_(struct evbuffer *buf, evutil_socket_t fd);
     @param ol Overlapped object with associated completion callback.
     @return 0 on success, -1 on error.
  */
+EVENT2_EXPORT_SYMBOL
 int evbuffer_launch_read_(struct evbuffer *buf, size_t n, struct event_overlapped *ol);
 
 /** Start writing data from the start of an evbuffer.
@@ -145,21 +149,26 @@ int evbuffer_launch_read_(struct evbuffer *buf, size_t n, struct event_overlappe
     @param ol Overlapped object with associated completion callback.
     @return 0 on success, -1 on error.
  */
+EVENT2_EXPORT_SYMBOL
 int evbuffer_launch_write_(struct evbuffer *buf, ev_ssize_t n, struct event_overlapped *ol);
 
 /** XXX document */
+EVENT2_EXPORT_SYMBOL
 void evbuffer_commit_read_(struct evbuffer *, ev_ssize_t);
+EVENT2_EXPORT_SYMBOL
 void evbuffer_commit_write_(struct evbuffer *, ev_ssize_t);
 
 /** Create an IOCP, and launch its worker threads.  Internal use only.
 
     This interface is unstable, and will change.
  */
+EVENT2_EXPORT_SYMBOL
 struct event_iocp_port *event_iocp_port_launch_(int n_cpus);
 
 /** Associate a file descriptor with an iocp, such that overlapped IO on the
     fd will happen on one of the iocp's worker threads.
 */
+EVENT2_EXPORT_SYMBOL
 int event_iocp_port_associate_(struct event_iocp_port *port, evutil_socket_t fd,
     ev_uintptr_t key);
 
@@ -169,22 +178,27 @@ int event_iocp_port_associate_(struct event_iocp_port *port, evutil_socket_t fd,
     0. Otherwise, return -1.  If you get a -1 return value, it is safe to call
     this function again.
 */
+EVENT2_EXPORT_SYMBOL
 int event_iocp_shutdown_(struct event_iocp_port *port, long waitMsec);
 
 /* FIXME document. */
+EVENT2_EXPORT_SYMBOL
 int event_iocp_activate_overlapped_(struct event_iocp_port *port,
     struct event_overlapped *o,
     ev_uintptr_t key, ev_uint32_t n_bytes);
 
 struct event_base;
 /* FIXME document. */
+EVENT2_EXPORT_SYMBOL
 struct event_iocp_port *event_base_get_iocp_(struct event_base *base);
 
 /* FIXME document. */
+EVENT2_EXPORT_SYMBOL
 int event_base_start_iocp_(struct event_base *base, int n_cpus);
 void event_base_stop_iocp_(struct event_base *base);
 
 /* FIXME document. */
+EVENT2_EXPORT_SYMBOL
 struct bufferevent *bufferevent_async_new_(struct event_base *base,
     evutil_socket_t fd, int options);
 
index a6578dfe1a57eb7e70777f4cc2797a70246168e7..dfd7751d649711d4e6f19cf5235cdecf1faeaee9 100644 (file)
@@ -37,6 +37,7 @@
 #endif
 #include <sys/queue.h>
 #include <sys/event.h>
+#include <limits.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 /* Some platforms apparently define the udata field of struct kevent as
  * intptr_t, whereas others define it as void*.  There doesn't seem to be an
  * easy way to tell them apart via autoconf, so we need to use OS macros. */
-#if defined(EVENT__HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__)
+#if defined(__NetBSD__)
+#define PTR_TO_UDATA(x) ((typeof(((struct kevent *)0)->udata))(x))
+#define INT_TO_UDATA(x) ((typeof(((struct kevent *)0)->udata))(intptr_t)(x))
+#elif defined(EVENT__HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__) && !defined(__CloudABI__)
 #define PTR_TO_UDATA(x)        ((intptr_t)(x))
 #define INT_TO_UDATA(x) ((intptr_t)(x))
 #else
@@ -62,6 +66,7 @@
 #include "log-internal.h"
 #include "evmap-internal.h"
 #include "event2/thread.h"
+#include "event2/util.h"
 #include "evthread-internal.h"
 #include "changelist-internal.h"
 
@@ -154,7 +159,7 @@ kq_init(struct event_base *base)
        if (kevent(kq,
                kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 ||
            (int)kqueueop->events[0].ident != -1 ||
-           kqueueop->events[0].flags != EV_ERROR) {
+           !(kqueueop->events[0].flags & EV_ERROR)) {
                event_warn("%s: detected broken kqueue; not using.", __func__);
                goto err;
        }
@@ -207,9 +212,17 @@ kq_build_changes_list(const struct event_changelist *changelist,
                struct event_change *in_ch = &changelist->changes[i];
                struct kevent *out_ch;
                if (n_changes >= kqop->changes_size - 1) {
-                       int newsize = kqop->changes_size * 2;
+                       int newsize;
                        struct kevent *newchanges;
 
+                       if (kqop->changes_size > INT_MAX / 2 ||
+                           (size_t)kqop->changes_size * 2 > EV_SIZE_MAX /
+                           sizeof(struct kevent)) {
+                               event_warnx("%s: int overflow", __func__);
+                               return (-1);
+                       }
+
+                       newsize = kqop->changes_size * 2;
                        newchanges = mm_realloc(kqop->changes,
                            newsize * sizeof(struct kevent));
                        if (newchanges == NULL) {
@@ -260,7 +273,8 @@ kq_dispatch(struct event_base *base, struct timeval *tv)
        int i, n_changes, res;
 
        if (tv != NULL) {
-               TIMEVAL_TO_TIMESPEC(tv, &ts);
+               ts.tv_sec = tv->tv_sec;
+               ts.tv_nsec = tv->tv_usec * 1000;
                ts_p = &ts;
        }
 
@@ -332,7 +346,7 @@ kq_dispatch(struct event_base *base, struct timeval *tv)
                         * on FreeBSD. */
                        case EINVAL:
                                continue;
-#if defined(__FreeBSD__) && defined(ENOTCAPABLE)
+#if defined(__FreeBSD__)
                        /*
                         * This currently occurs if an FD is closed
                         * before the EV_DELETE makes it out via kevent().
diff --git a/sntp/libevent/libevent_core.pc.in b/sntp/libevent/libevent_core.pc.in
new file mode 100644 (file)
index 0000000..98ab1ef
--- /dev/null
@@ -0,0 +1,16 @@
+#libevent pkg-config source file
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libevent_core
+Description: libevent_core
+Version: @VERSION@
+Requires:
+Conflicts:
+Libs: -L${libdir} -levent_core
+Libs.private: @LIBS@
+Cflags: -I${includedir}
+
diff --git a/sntp/libevent/libevent_extra.pc.in b/sntp/libevent/libevent_extra.pc.in
new file mode 100644 (file)
index 0000000..b963399
--- /dev/null
@@ -0,0 +1,16 @@
+#libevent pkg-config source file
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libevent_extra
+Description: libevent_extra
+Version: @VERSION@
+Requires:
+Conflicts:
+Libs: -L${libdir} -levent_extra
+Libs.private: @LIBS@
+Cflags: -I${includedir}
+
index 2af14e3a7b54aad9cb037b29f7f95de7c142d9d9..f5c00c9c0e305648850cf3d5b44cd91035637dce 100644 (file)
@@ -35,6 +35,7 @@
 #define _WIN32_WINNT 0x0403
 #endif
 #include <winsock2.h>
+#include <winerror.h>
 #include <ws2tcpip.h>
 #include <mswsock.h>
 #endif
@@ -245,6 +246,11 @@ evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb,
                        goto err;
        }
 
+       if (flags & LEV_OPT_BIND_IPV6ONLY) {
+               if (evutil_make_listen_socket_ipv6only(fd) < 0)
+                       goto err;
+       }
+
        if (sa) {
                if (bind(fd, sa, socklen)<0)
                        goto err;
@@ -421,11 +427,14 @@ listener_read_cb(evutil_socket_t fd, short what, void *p)
                if (lev->refcnt == 1) {
                        int freed = listener_decref_and_unlock(lev);
                        EVUTIL_ASSERT(freed);
-
-                       evutil_closesocket(new_fd);
                        return;
                }
                --lev->refcnt;
+               if (!lev->enabled) {
+                       /* the callback could have disabled the listener */
+                       UNLOCK(lev);
+                       return;
+               }
        }
        err = evutil_socket_geterror(fd);
        if (EVUTIL_ERR_ACCEPT_RETRIABLE(err)) {
@@ -442,6 +451,7 @@ listener_read_cb(evutil_socket_t fd, short what, void *p)
                listener_decref_and_unlock(lev);
        } else {
                event_sock_warn(fd, "Error from accept() call");
+               UNLOCK(lev);
        }
 }
 
@@ -503,7 +513,7 @@ new_accepting_socket(struct evconnlistener_iocp *lev, int family)
                return NULL;
 
        event_overlapped_init_(&res->overlapped, accepted_socket_cb);
-       res->s = INVALID_SOCKET;
+       res->s = EVUTIL_INVALID_SOCKET;
        res->lev = lev;
        res->buflen = buflen;
        res->family = family;
@@ -521,7 +531,7 @@ static void
 free_and_unlock_accepting_socket(struct accepting_socket *as)
 {
        /* requires lock. */
-       if (as->s != INVALID_SOCKET)
+       if (as->s != EVUTIL_INVALID_SOCKET)
                closesocket(as->s);
 
        LeaveCriticalSection(&as->lock);
@@ -541,7 +551,7 @@ start_accepting(struct accepting_socket *as)
        if (!as->lev->base.enabled)
                return 0;
 
-       if (s == INVALID_SOCKET) {
+       if (s == EVUTIL_INVALID_SOCKET) {
                error = WSAGetLastError();
                goto report_err;
        }
@@ -588,7 +598,7 @@ stop_accepting(struct accepting_socket *as)
 {
        /* requires lock. */
        SOCKET s = as->s;
-       as->s = INVALID_SOCKET;
+       as->s = EVUTIL_INVALID_SOCKET;
        closesocket(s);
 }
 
@@ -630,7 +640,7 @@ accepted_socket_invoke_user_cb(struct event_callback *dcb, void *arg)
                        &socklen_remote);
                sock = as->s;
                cb = lev->cb;
-               as->s = INVALID_SOCKET;
+               as->s = EVUTIL_INVALID_SOCKET;
 
                /* We need to call this so getsockname, getpeername, and
                 * shutdown work correctly on the accepted socket. */
@@ -678,7 +688,7 @@ accepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key, ev_ssize_t n, i
                free_and_unlock_accepting_socket(as);
                listener_decref_and_unlock(lev);
                return;
-       } else if (as->s == INVALID_SOCKET) {
+       } else if (as->s == EVUTIL_INVALID_SOCKET) {
                /* This is okay; we were disabled by iocp_listener_disable. */
                LeaveCriticalSection(&as->lock);
        } else {
@@ -716,7 +726,7 @@ iocp_listener_enable(struct evconnlistener *lev)
                if (!as)
                        continue;
                EnterCriticalSection(&as->lock);
-               if (!as->free_on_cb && as->s == INVALID_SOCKET)
+               if (!as->free_on_cb && as->s == EVUTIL_INVALID_SOCKET)
                        start_accepting(as);
                LeaveCriticalSection(&as->lock);
        }
@@ -738,7 +748,7 @@ iocp_listener_disable_impl(struct evconnlistener *lev, int shutdown)
                if (!as)
                        continue;
                EnterCriticalSection(&as->lock);
-               if (!as->free_on_cb && as->s != INVALID_SOCKET) {
+               if (!as->free_on_cb && as->s != EVUTIL_INVALID_SOCKET) {
                        if (shutdown)
                                as->free_on_cb = 1;
                        stop_accepting(as);
index 330478a9edd60ed1bfbd4bb5fa76d92a01149cfa..2c31608b25be59efe96fe2ed95c0f00adc17b93a 100644 (file)
 
 #include "event2/util.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #ifdef __GNUC__
 #define EV_CHECK_FMT(a,b) __attribute__((format(printf, a, b)))
 #define EV_NORETURN __attribute__((noreturn))
 
 #define EVENT_ERR_ABORT_ ((int)0xdeaddead)
 
-#define USE_GLOBAL_FOR_DEBUG_LOGGING
-
 #if !defined(EVENT__DISABLE_DEBUG_MODE) || defined(USE_DEBUG)
 #define EVENT_DEBUG_LOGGING_ENABLED
 #endif
 
 #ifdef EVENT_DEBUG_LOGGING_ENABLED
-#ifdef USE_GLOBAL_FOR_DEBUG_LOGGING
-extern ev_uint32_t event_debug_logging_mask_;
+EVENT2_CORE_EXPORT_SYMBOL extern ev_uint32_t event_debug_logging_mask_;
 #define event_debug_get_logging_mask_() (event_debug_logging_mask_)
 #else
-ev_uint32_t event_debug_get_logging_mask_(void);
-#endif
-#else
 #define event_debug_get_logging_mask_() (0)
 #endif
 
+EVENT2_EXPORT_SYMBOL
 void event_err(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3) EV_NORETURN;
+EVENT2_EXPORT_SYMBOL
 void event_warn(const char *fmt, ...) EV_CHECK_FMT(1,2);
+EVENT2_EXPORT_SYMBOL
 void event_sock_err(int eval, evutil_socket_t sock, const char *fmt, ...) EV_CHECK_FMT(3,4) EV_NORETURN;
+EVENT2_EXPORT_SYMBOL
 void event_sock_warn(evutil_socket_t sock, const char *fmt, ...) EV_CHECK_FMT(2,3);
+EVENT2_EXPORT_SYMBOL
 void event_errx(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3) EV_NORETURN;
+EVENT2_EXPORT_SYMBOL
 void event_warnx(const char *fmt, ...) EV_CHECK_FMT(1,2);
+EVENT2_EXPORT_SYMBOL
 void event_msgx(const char *fmt, ...) EV_CHECK_FMT(1,2);
+EVENT2_EXPORT_SYMBOL
 void event_debugx_(const char *fmt, ...) EV_CHECK_FMT(1,2);
 
+EVENT2_EXPORT_SYMBOL
 void event_logv_(int severity, const char *errstr, const char *fmt, va_list ap)
        EV_CHECK_FMT(3,0);
 
@@ -80,4 +87,8 @@ void event_logv_(int severity, const char *errstr, const char *fmt, va_list ap)
 
 #undef EV_CHECK_FMT
 
+#ifdef __cplusplus
+}
 #endif
+
+#endif /* LOG_INTERNAL_H_INCLUDED_ */
index e8ae9fdc310e0fb13b75ff778ecae21014cf6578..a9debb864e4f7fe52a6984580958bd2d51b3144a 100644 (file)
@@ -69,16 +69,7 @@ static event_fatal_cb fatal_fn = NULL;
 #define DEFAULT_MASK 0
 #endif
 
-#ifdef USE_GLOBAL_FOR_DEBUG_LOGGING
-ev_uint32_t event_debug_logging_mask_ = DEFAULT_MASK;
-#else
-static ev_uint32_t event_debug_logging_mask_ = DEFAULT_MASK;
-ev_uint32_t
-event_debug_get_logging_mask_(void)
-{
-       return event_debug_logging_mask_;
-}
-#endif
+EVENT2_EXPORT_SYMBOL ev_uint32_t event_debug_logging_mask_ = DEFAULT_MASK;
 #endif /* EVENT_DEBUG_LOGGING_ENABLED */
 
 void
diff --git a/sntp/libevent/ltmain.sh b/sntp/libevent/ltmain.sh
new file mode 100644 (file)
index 0000000..0f0a2da
--- /dev/null
@@ -0,0 +1,11147 @@
+#! /bin/sh
+## DO NOT EDIT - This file generated from ./build-aux/ltmain.in
+##               by inline-source v2014-01-03.01
+
+# libtool (GNU libtool) 2.4.6
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION=2.4.6
+package_revision=2.4.6
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# Run './libtool --help' for help with using this script from the
+# command line.
+
+
+## ------------------------------- ##
+## User overridable command paths. ##
+## ------------------------------- ##
+
+# After configure completes, it has a better idea of some of the
+# shell tools we need than the defaults used by the functions shared
+# with bootstrap, so set those here where they can still be over-
+# ridden by the user, but otherwise take precedence.
+
+: ${AUTOCONF="autoconf"}
+: ${AUTOMAKE="automake"}
+
+
+## -------------------------- ##
+## Source external libraries. ##
+## -------------------------- ##
+
+# Much of our low-level functionality needs to be sourced from external
+# libraries, which are installed to $pkgauxdir.
+
+# Set a version string for this script.
+scriptversion=2015-01-20.17; # UTC
+
+# General shell script boiler plate, and helper functions.
+# Written by Gary V. Vaughan, 2004
+
+# Copyright (C) 2004-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# As a special exception to the GNU General Public License, if you distribute
+# this file as part of a program or library that is built using GNU Libtool,
+# you may include this file under the same distribution terms that you use
+# for the rest of that program.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNES FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Please report bugs or propose patches to gary@gnu.org.
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# Evaluate this file near the top of your script to gain access to
+# the functions and variables defined here:
+#
+#   . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh
+#
+# If you need to override any of the default environment variable
+# settings, do that before evaluating this file.
+
+
+## -------------------- ##
+## Shell normalisation. ##
+## -------------------- ##
+
+# Some shells need a little help to be as Bourne compatible as possible.
+# Before doing anything else, make sure all that help has been provided!
+
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac
+fi
+
+# NLS nuisances: We save the old values in case they are required later.
+_G_user_locale=
+_G_safe_locale=
+for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+  eval "if test set = \"\${$_G_var+set}\"; then
+          save_$_G_var=\$$_G_var
+          $_G_var=C
+         export $_G_var
+         _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\"
+         _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\"
+       fi"
+done
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Make sure IFS has a sensible default
+sp=' '
+nl='
+'
+IFS="$sp       $nl"
+
+# There are apparently some retarded systems that use ';' as a PATH separator!
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+
+## ------------------------- ##
+## Locate command utilities. ##
+## ------------------------- ##
+
+
+# func_executable_p FILE
+# ----------------------
+# Check that FILE is an executable regular file.
+func_executable_p ()
+{
+    test -f "$1" && test -x "$1"
+}
+
+
+# func_path_progs PROGS_LIST CHECK_FUNC [PATH]
+# --------------------------------------------
+# Search for either a program that responds to --version with output
+# containing "GNU", or else returned by CHECK_FUNC otherwise, by
+# trying all the directories in PATH with each of the elements of
+# PROGS_LIST.
+#
+# CHECK_FUNC should accept the path to a candidate program, and
+# set $func_check_prog_result if it truncates its output less than
+# $_G_path_prog_max characters.
+func_path_progs ()
+{
+    _G_progs_list=$1
+    _G_check_func=$2
+    _G_PATH=${3-"$PATH"}
+
+    _G_path_prog_max=0
+    _G_path_prog_found=false
+    _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:}
+    for _G_dir in $_G_PATH; do
+      IFS=$_G_save_IFS
+      test -z "$_G_dir" && _G_dir=.
+      for _G_prog_name in $_G_progs_list; do
+        for _exeext in '' .EXE; do
+          _G_path_prog=$_G_dir/$_G_prog_name$_exeext
+          func_executable_p "$_G_path_prog" || continue
+          case `"$_G_path_prog" --version 2>&1` in
+            *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;;
+            *)     $_G_check_func $_G_path_prog
+                  func_path_progs_result=$func_check_prog_result
+                  ;;
+          esac
+          $_G_path_prog_found && break 3
+        done
+      done
+    done
+    IFS=$_G_save_IFS
+    test -z "$func_path_progs_result" && {
+      echo "no acceptable sed could be found in \$PATH" >&2
+      exit 1
+    }
+}
+
+
+# We want to be able to use the functions in this file before configure
+# has figured out where the best binaries are kept, which means we have
+# to search for them ourselves - except when the results are already set
+# where we skip the searches.
+
+# Unless the user overrides by setting SED, search the path for either GNU
+# sed, or the sed that truncates its output the least.
+test -z "$SED" && {
+  _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+  for _G_i in 1 2 3 4 5 6 7; do
+    _G_sed_script=$_G_sed_script$nl$_G_sed_script
+  done
+  echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed
+  _G_sed_script=
+
+  func_check_prog_sed ()
+  {
+    _G_path_prog=$1
+
+    _G_count=0
+    printf 0123456789 >conftest.in
+    while :
+    do
+      cat conftest.in conftest.in >conftest.tmp
+      mv conftest.tmp conftest.in
+      cp conftest.in conftest.nl
+      echo '' >> conftest.nl
+      "$_G_path_prog" -f conftest.sed <conftest.nl >conftest.out 2>/dev/null || break
+      diff conftest.out conftest.nl >/dev/null 2>&1 || break
+      _G_count=`expr $_G_count + 1`
+      if test "$_G_count" -gt "$_G_path_prog_max"; then
+        # Best one so far, save it but keep looking for a better one
+        func_check_prog_result=$_G_path_prog
+        _G_path_prog_max=$_G_count
+      fi
+      # 10*(2^10) chars as input seems more than enough
+      test 10 -lt "$_G_count" && break
+    done
+    rm -f conftest.in conftest.tmp conftest.nl conftest.out
+  }
+
+  func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin
+  rm -f conftest.sed
+  SED=$func_path_progs_result
+}
+
+
+# Unless the user overrides by setting GREP, search the path for either GNU
+# grep, or the grep that truncates its output the least.
+test -z "$GREP" && {
+  func_check_prog_grep ()
+  {
+    _G_path_prog=$1
+
+    _G_count=0
+    _G_path_prog_max=0
+    printf 0123456789 >conftest.in
+    while :
+    do
+      cat conftest.in conftest.in >conftest.tmp
+      mv conftest.tmp conftest.in
+      cp conftest.in conftest.nl
+      echo 'GREP' >> conftest.nl
+      "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' <conftest.nl >conftest.out 2>/dev/null || break
+      diff conftest.out conftest.nl >/dev/null 2>&1 || break
+      _G_count=`expr $_G_count + 1`
+      if test "$_G_count" -gt "$_G_path_prog_max"; then
+        # Best one so far, save it but keep looking for a better one
+        func_check_prog_result=$_G_path_prog
+        _G_path_prog_max=$_G_count
+      fi
+      # 10*(2^10) chars as input seems more than enough
+      test 10 -lt "$_G_count" && break
+    done
+    rm -f conftest.in conftest.tmp conftest.nl conftest.out
+  }
+
+  func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin
+  GREP=$func_path_progs_result
+}
+
+
+## ------------------------------- ##
+## User overridable command paths. ##
+## ------------------------------- ##
+
+# All uppercase variable names are used for environment variables.  These
+# variables can be overridden by the user before calling a script that
+# uses them if a suitable command of that name is not already available
+# in the command search PATH.
+
+: ${CP="cp -f"}
+: ${ECHO="printf %s\n"}
+: ${EGREP="$GREP -E"}
+: ${FGREP="$GREP -F"}
+: ${LN_S="ln -s"}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+
+
+## -------------------- ##
+## Useful sed snippets. ##
+## -------------------- ##
+
+sed_dirname='s|/[^/]*$||'
+sed_basename='s|^.*/||'
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
+
+# Same as above, but do not quote variable references.
+sed_double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution that turns a string into a regex matching for the
+# string literally.
+sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g'
+
+# Sed substitution that converts a w32 file name or path
+# that contains forward slashes, into one that contains
+# (escaped) backslashes.  A very naive implementation.
+sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+
+# Re-'\' parameter expansions in output of sed_double_quote_subst that
+# were '\'-ed in input to the same.  If an odd number of '\' preceded a
+# '$' in input to sed_double_quote_subst, that '$' was protected from
+# expansion.  Since each input '\' is now two '\'s, look for any number
+# of runs of four '\'s followed by two '\'s and then a '$'.  '\' that '$'.
+_G_bs='\\'
+_G_bs2='\\\\'
+_G_bs4='\\\\\\\\'
+_G_dollar='\$'
+sed_double_backslash="\
+  s/$_G_bs4/&\\
+/g
+  s/^$_G_bs2$_G_dollar/$_G_bs&/
+  s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g
+  s/\n//g"
+
+
+## ----------------- ##
+## Global variables. ##
+## ----------------- ##
+
+# Except for the global variables explicitly listed below, the following
+# functions in the '^func_' namespace, and the '^require_' namespace
+# variables initialised in the 'Resource management' section, sourcing
+# this file will not pollute your global namespace with anything
+# else. There's no portable way to scope variables in Bourne shell
+# though, so actually running these functions will sometimes place
+# results into a variable named after the function, and often use
+# temporary variables in the '^_G_' namespace. If you are careful to
+# avoid using those namespaces casually in your sourcing script, things
+# should continue to work as you expect. And, of course, you can freely
+# overwrite any of the functions or variables defined here before
+# calling anything to customize them.
+
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63  # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77     # $? = 77 is used to indicate a skipped test to automake.
+
+# Allow overriding, eg assuming that you follow the convention of
+# putting '$debug_cmd' at the start of all your functions, you can get
+# bash to show function call trace with:
+#
+#    debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name
+debug_cmd=${debug_cmd-":"}
+exit_cmd=:
+
+# By convention, finish your script with:
+#
+#    exit $exit_status
+#
+# so that you can set exit_status to non-zero if you want to indicate
+# something went wrong during execution without actually bailing out at
+# the point of failure.
+exit_status=$EXIT_SUCCESS
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath=$0
+
+# The name of this program.
+progname=`$ECHO "$progpath" |$SED "$sed_basename"`
+
+# Make sure we have an absolute progpath for reexecution:
+case $progpath in
+  [\\/]*|[A-Za-z]:\\*) ;;
+  *[\\/]*)
+     progdir=`$ECHO "$progpath" |$SED "$sed_dirname"`
+     progdir=`cd "$progdir" && pwd`
+     progpath=$progdir/$progname
+     ;;
+  *)
+     _G_IFS=$IFS
+     IFS=${PATH_SEPARATOR-:}
+     for progdir in $PATH; do
+       IFS=$_G_IFS
+       test -x "$progdir/$progname" && break
+     done
+     IFS=$_G_IFS
+     test -n "$progdir" || progdir=`pwd`
+     progpath=$progdir/$progname
+     ;;
+esac
+
+
+## ----------------- ##
+## Standard options. ##
+## ----------------- ##
+
+# The following options affect the operation of the functions defined
+# below, and should be set appropriately depending on run-time para-
+# meters passed on the command line.
+
+opt_dry_run=false
+opt_quiet=false
+opt_verbose=false
+
+# Categories 'all' and 'none' are always available.  Append any others
+# you will pass as the first argument to func_warning from your own
+# code.
+warning_categories=
+
+# By default, display warnings according to 'opt_warning_types'.  Set
+# 'warning_func'  to ':' to elide all warnings, or func_fatal_error to
+# treat the next displayed warning as a fatal error.
+warning_func=func_warn_and_continue
+
+# Set to 'all' to display all warnings, 'none' to suppress all
+# warnings, or a space delimited list of some subset of
+# 'warning_categories' to display only the listed warnings.
+opt_warning_types=all
+
+
+## -------------------- ##
+## Resource management. ##
+## -------------------- ##
+
+# This section contains definitions for functions that each ensure a
+# particular resource (a file, or a non-empty configuration variable for
+# example) is available, and if appropriate to extract default values
+# from pertinent package files. Call them using their associated
+# 'require_*' variable to ensure that they are executed, at most, once.
+#
+# It's entirely deliberate that calling these functions can set
+# variables that don't obey the namespace limitations obeyed by the rest
+# of this file, in order that that they be as useful as possible to
+# callers.
+
+
+# require_term_colors
+# -------------------
+# Allow display of bold text on terminals that support it.
+require_term_colors=func_require_term_colors
+func_require_term_colors ()
+{
+    $debug_cmd
+
+    test -t 1 && {
+      # COLORTERM and USE_ANSI_COLORS environment variables take
+      # precedence, because most terminfo databases neglect to describe
+      # whether color sequences are supported.
+      test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"}
+
+      if test 1 = "$USE_ANSI_COLORS"; then
+        # Standard ANSI escape sequences
+        tc_reset='\e[0m'
+        tc_bold='\e[1m';   tc_standout='\e[7m'
+        tc_red='\e[31m';   tc_green='\e[32m'
+        tc_blue='\e[34m';  tc_cyan='\e[36m'
+      else
+        # Otherwise trust the terminfo database after all.
+        test -n "`tput sgr0 2>/dev/null`" && {
+          tc_reset=`tput sgr0`
+          test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold`
+          tc_standout=$tc_bold
+          test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso`
+          test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1`
+          test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2`
+          test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4`
+          test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5`
+        }
+      fi
+    }
+
+    require_term_colors=:
+}
+
+
+## ----------------- ##
+## Function library. ##
+## ----------------- ##
+
+# This section contains a variety of useful functions to call in your
+# scripts. Take note of the portable wrappers for features provided by
+# some modern shells, which will fall back to slower equivalents on
+# less featureful shells.
+
+
+# func_append VAR VALUE
+# ---------------------
+# Append VALUE onto the existing contents of VAR.
+
+  # We should try to minimise forks, especially on Windows where they are
+  # unreasonably slow, so skip the feature probes when bash or zsh are
+  # being used:
+  if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then
+    : ${_G_HAVE_ARITH_OP="yes"}
+    : ${_G_HAVE_XSI_OPS="yes"}
+    # The += operator was introduced in bash 3.1
+    case $BASH_VERSION in
+      [12].* | 3.0 | 3.0*) ;;
+      *)
+        : ${_G_HAVE_PLUSEQ_OP="yes"}
+        ;;
+    esac
+  fi
+
+  # _G_HAVE_PLUSEQ_OP
+  # Can be empty, in which case the shell is probed, "yes" if += is
+  # useable or anything else if it does not work.
+  test -z "$_G_HAVE_PLUSEQ_OP" \
+    && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \
+    && _G_HAVE_PLUSEQ_OP=yes
+
+if test yes = "$_G_HAVE_PLUSEQ_OP"
+then
+  # This is an XSI compatible shell, allowing a faster implementation...
+  eval 'func_append ()
+  {
+    $debug_cmd
+
+    eval "$1+=\$2"
+  }'
+else
+  # ...otherwise fall back to using expr, which is often a shell builtin.
+  func_append ()
+  {
+    $debug_cmd
+
+    eval "$1=\$$1\$2"
+  }
+fi
+
+
+# func_append_quoted VAR VALUE
+# ----------------------------
+# Quote VALUE and append to the end of shell variable VAR, separated
+# by a space.
+if test yes = "$_G_HAVE_PLUSEQ_OP"; then
+  eval 'func_append_quoted ()
+  {
+    $debug_cmd
+
+    func_quote_for_eval "$2"
+    eval "$1+=\\ \$func_quote_for_eval_result"
+  }'
+else
+  func_append_quoted ()
+  {
+    $debug_cmd
+
+    func_quote_for_eval "$2"
+    eval "$1=\$$1\\ \$func_quote_for_eval_result"
+  }
+fi
+
+
+# func_append_uniq VAR VALUE
+# --------------------------
+# Append unique VALUE onto the existing contents of VAR, assuming
+# entries are delimited by the first character of VALUE.  For example:
+#
+#   func_append_uniq options " --another-option option-argument"
+#
+# will only append to $options if " --another-option option-argument "
+# is not already present somewhere in $options already (note spaces at
+# each end implied by leading space in second argument).
+func_append_uniq ()
+{
+    $debug_cmd
+
+    eval _G_current_value='`$ECHO $'$1'`'
+    _G_delim=`expr "$2" : '\(.\)'`
+
+    case $_G_delim$_G_current_value$_G_delim in
+      *"$2$_G_delim"*) ;;
+      *) func_append "$@" ;;
+    esac
+}
+
+
+# func_arith TERM...
+# ------------------
+# Set func_arith_result to the result of evaluating TERMs.
+  test -z "$_G_HAVE_ARITH_OP" \
+    && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \
+    && _G_HAVE_ARITH_OP=yes
+
+if test yes = "$_G_HAVE_ARITH_OP"; then
+  eval 'func_arith ()
+  {
+    $debug_cmd
+
+    func_arith_result=$(( $* ))
+  }'
+else
+  func_arith ()
+  {
+    $debug_cmd
+
+    func_arith_result=`expr "$@"`
+  }
+fi
+
+
+# func_basename FILE
+# ------------------
+# Set func_basename_result to FILE with everything up to and including
+# the last / stripped.
+if test yes = "$_G_HAVE_XSI_OPS"; then
+  # If this shell supports suffix pattern removal, then use it to avoid
+  # forking. Hide the definitions single quotes in case the shell chokes
+  # on unsupported syntax...
+  _b='func_basename_result=${1##*/}'
+  _d='case $1 in
+        */*) func_dirname_result=${1%/*}$2 ;;
+        *  ) func_dirname_result=$3        ;;
+      esac'
+
+else
+  # ...otherwise fall back to using sed.
+  _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`'
+  _d='func_dirname_result=`$ECHO "$1"  |$SED "$sed_dirname"`
+      if test "X$func_dirname_result" = "X$1"; then
+        func_dirname_result=$3
+      else
+        func_append func_dirname_result "$2"
+      fi'
+fi
+
+eval 'func_basename ()
+{
+    $debug_cmd
+
+    '"$_b"'
+}'
+
+
+# func_dirname FILE APPEND NONDIR_REPLACEMENT
+# -------------------------------------------
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+eval 'func_dirname ()
+{
+    $debug_cmd
+
+    '"$_d"'
+}'
+
+
+# func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT
+# --------------------------------------------------------
+# Perform func_basename and func_dirname in a single function
+# call:
+#   dirname:  Compute the dirname of FILE.  If nonempty,
+#             add APPEND to the result, otherwise set result
+#             to NONDIR_REPLACEMENT.
+#             value returned in "$func_dirname_result"
+#   basename: Compute filename of FILE.
+#             value retuned in "$func_basename_result"
+# For efficiency, we do not delegate to the functions above but instead
+# duplicate the functionality here.
+eval 'func_dirname_and_basename ()
+{
+    $debug_cmd
+
+    '"$_b"'
+    '"$_d"'
+}'
+
+
+# func_echo ARG...
+# ----------------
+# Echo program name prefixed message.
+func_echo ()
+{
+    $debug_cmd
+
+    _G_message=$*
+
+    func_echo_IFS=$IFS
+    IFS=$nl
+    for _G_line in $_G_message; do
+      IFS=$func_echo_IFS
+      $ECHO "$progname: $_G_line"
+    done
+    IFS=$func_echo_IFS
+}
+
+
+# func_echo_all ARG...
+# --------------------
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*"
+}
+
+
+# func_echo_infix_1 INFIX ARG...
+# ------------------------------
+# Echo program name, followed by INFIX on the first line, with any
+# additional lines not showing INFIX.
+func_echo_infix_1 ()
+{
+    $debug_cmd
+
+    $require_term_colors
+
+    _G_infix=$1; shift
+    _G_indent=$_G_infix
+    _G_prefix="$progname: $_G_infix: "
+    _G_message=$*
+
+    # Strip color escape sequences before counting printable length
+    for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan"
+    do
+      test -n "$_G_tc" && {
+        _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"`
+        _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"`
+      }
+    done
+    _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`"  " ## exclude from sc_prohibit_nested_quotes
+
+    func_echo_infix_1_IFS=$IFS
+    IFS=$nl
+    for _G_line in $_G_message; do
+      IFS=$func_echo_infix_1_IFS
+      $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2
+      _G_prefix=$_G_indent
+    done
+    IFS=$func_echo_infix_1_IFS
+}
+
+
+# func_error ARG...
+# -----------------
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+    $debug_cmd
+
+    $require_term_colors
+
+    func_echo_infix_1 "  $tc_standout${tc_red}error$tc_reset" "$*" >&2
+}
+
+
+# func_fatal_error ARG...
+# -----------------------
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+    $debug_cmd
+
+    func_error "$*"
+    exit $EXIT_FAILURE
+}
+
+
+# func_grep EXPRESSION FILENAME
+# -----------------------------
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+    $debug_cmd
+
+    $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_len STRING
+# ---------------
+# Set func_len_result to the length of STRING. STRING may not
+# start with a hyphen.
+  test -z "$_G_HAVE_XSI_OPS" \
+    && (eval 'x=a/b/c;
+      test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
+    && _G_HAVE_XSI_OPS=yes
+
+if test yes = "$_G_HAVE_XSI_OPS"; then
+  eval 'func_len ()
+  {
+    $debug_cmd
+
+    func_len_result=${#1}
+  }'
+else
+  func_len ()
+  {
+    $debug_cmd
+
+    func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len`
+  }
+fi
+
+
+# func_mkdir_p DIRECTORY-PATH
+# ---------------------------
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+    $debug_cmd
+
+    _G_directory_path=$1
+    _G_dir_list=
+
+    if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then
+
+      # Protect directory names starting with '-'
+      case $_G_directory_path in
+        -*) _G_directory_path=./$_G_directory_path ;;
+      esac
+
+      # While some portion of DIR does not yet exist...
+      while test ! -d "$_G_directory_path"; do
+        # ...make a list in topmost first order.  Use a colon delimited
+       # list incase some portion of path contains whitespace.
+        _G_dir_list=$_G_directory_path:$_G_dir_list
+
+        # If the last portion added has no slash in it, the list is done
+        case $_G_directory_path in */*) ;; *) break ;; esac
+
+        # ...otherwise throw away the child directory and loop
+        _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"`
+      done
+      _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'`
+
+      func_mkdir_p_IFS=$IFS; IFS=:
+      for _G_dir in $_G_dir_list; do
+       IFS=$func_mkdir_p_IFS
+        # mkdir can fail with a 'File exist' error if two processes
+        # try to create one of the directories concurrently.  Don't
+        # stop in that case!
+        $MKDIR "$_G_dir" 2>/dev/null || :
+      done
+      IFS=$func_mkdir_p_IFS
+
+      # Bail out if we (or some other process) failed to create a directory.
+      test -d "$_G_directory_path" || \
+        func_fatal_error "Failed to create '$1'"
+    fi
+}
+
+
+# func_mktempdir [BASENAME]
+# -------------------------
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible.  If
+# given, BASENAME is the basename for that directory.
+func_mktempdir ()
+{
+    $debug_cmd
+
+    _G_template=${TMPDIR-/tmp}/${1-$progname}
+
+    if test : = "$opt_dry_run"; then
+      # Return a directory name, but don't create it in dry-run mode
+      _G_tmpdir=$_G_template-$$
+    else
+
+      # If mktemp works, use that first and foremost
+      _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null`
+
+      if test ! -d "$_G_tmpdir"; then
+        # Failing that, at least try and use $RANDOM to avoid a race
+        _G_tmpdir=$_G_template-${RANDOM-0}$$
+
+        func_mktempdir_umask=`umask`
+        umask 0077
+        $MKDIR "$_G_tmpdir"
+        umask $func_mktempdir_umask
+      fi
+
+      # If we're not in dry-run mode, bomb out on failure
+      test -d "$_G_tmpdir" || \
+        func_fatal_error "cannot create temporary directory '$_G_tmpdir'"
+    fi
+
+    $ECHO "$_G_tmpdir"
+}
+
+
+# func_normal_abspath PATH
+# ------------------------
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+func_normal_abspath ()
+{
+    $debug_cmd
+
+    # These SED scripts presuppose an absolute path with a trailing slash.
+    _G_pathcar='s|^/\([^/]*\).*$|\1|'
+    _G_pathcdr='s|^/[^/]*||'
+    _G_removedotparts=':dotsl
+               s|/\./|/|g
+               t dotsl
+               s|/\.$|/|'
+    _G_collapseslashes='s|/\{1,\}|/|g'
+    _G_finalslash='s|/*$|/|'
+
+    # Start from root dir and reassemble the path.
+    func_normal_abspath_result=
+    func_normal_abspath_tpath=$1
+    func_normal_abspath_altnamespace=
+    case $func_normal_abspath_tpath in
+      "")
+        # Empty path, that just means $cwd.
+        func_stripname '' '/' "`pwd`"
+        func_normal_abspath_result=$func_stripname_result
+        return
+        ;;
+      # The next three entries are used to spot a run of precisely
+      # two leading slashes without using negated character classes;
+      # we take advantage of case's first-match behaviour.
+      ///*)
+        # Unusual form of absolute path, do nothing.
+        ;;
+      //*)
+        # Not necessarily an ordinary path; POSIX reserves leading '//'
+        # and for example Cygwin uses it to access remote file shares
+        # over CIFS/SMB, so we conserve a leading double slash if found.
+        func_normal_abspath_altnamespace=/
+        ;;
+      /*)
+        # Absolute path, do nothing.
+        ;;
+      *)
+        # Relative path, prepend $cwd.
+        func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+        ;;
+    esac
+
+    # Cancel out all the simple stuff to save iterations.  We also want
+    # the path to end with a slash for ease of parsing, so make sure
+    # there is one (and only one) here.
+    func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+          -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"`
+    while :; do
+      # Processed it all yet?
+      if test / = "$func_normal_abspath_tpath"; then
+        # If we ascended to the root using ".." the result may be empty now.
+        if test -z "$func_normal_abspath_result"; then
+          func_normal_abspath_result=/
+        fi
+        break
+      fi
+      func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+          -e "$_G_pathcar"`
+      func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+          -e "$_G_pathcdr"`
+      # Figure out what to do with it
+      case $func_normal_abspath_tcomponent in
+        "")
+          # Trailing empty path component, ignore it.
+          ;;
+        ..)
+          # Parent dir; strip last assembled component from result.
+          func_dirname "$func_normal_abspath_result"
+          func_normal_abspath_result=$func_dirname_result
+          ;;
+        *)
+          # Actual path component, append it.
+          func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent"
+          ;;
+      esac
+    done
+    # Restore leading double-slash if one was found on entry.
+    func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+
+# func_notquiet ARG...
+# --------------------
+# Echo program name prefixed message only when not in quiet mode.
+func_notquiet ()
+{
+    $debug_cmd
+
+    $opt_quiet || func_echo ${1+"$@"}
+
+    # A bug in bash halts the script if the last line of a function
+    # fails when set -e is in force, so we need another command to
+    # work around that:
+    :
+}
+
+
+# func_relative_path SRCDIR DSTDIR
+# --------------------------------
+# Set func_relative_path_result to the relative path from SRCDIR to DSTDIR.
+func_relative_path ()
+{
+    $debug_cmd
+
+    func_relative_path_result=
+    func_normal_abspath "$1"
+    func_relative_path_tlibdir=$func_normal_abspath_result
+    func_normal_abspath "$2"
+    func_relative_path_tbindir=$func_normal_abspath_result
+
+    # Ascend the tree starting from libdir
+    while :; do
+      # check if we have found a prefix of bindir
+      case $func_relative_path_tbindir in
+        $func_relative_path_tlibdir)
+          # found an exact match
+          func_relative_path_tcancelled=
+          break
+          ;;
+        $func_relative_path_tlibdir*)
+          # found a matching prefix
+          func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+          func_relative_path_tcancelled=$func_stripname_result
+          if test -z "$func_relative_path_result"; then
+            func_relative_path_result=.
+          fi
+          break
+          ;;
+        *)
+          func_dirname $func_relative_path_tlibdir
+          func_relative_path_tlibdir=$func_dirname_result
+          if test -z "$func_relative_path_tlibdir"; then
+            # Have to descend all the way to the root!
+            func_relative_path_result=../$func_relative_path_result
+            func_relative_path_tcancelled=$func_relative_path_tbindir
+            break
+          fi
+          func_relative_path_result=../$func_relative_path_result
+          ;;
+      esac
+    done
+
+    # Now calculate path; take care to avoid doubling-up slashes.
+    func_stripname '' '/' "$func_relative_path_result"
+    func_relative_path_result=$func_stripname_result
+    func_stripname '/' '/' "$func_relative_path_tcancelled"
+    if test -n "$func_stripname_result"; then
+      func_append func_relative_path_result "/$func_stripname_result"
+    fi
+
+    # Normalisation. If bindir is libdir, return '.' else relative path.
+    if test -n "$func_relative_path_result"; then
+      func_stripname './' '' "$func_relative_path_result"
+      func_relative_path_result=$func_stripname_result
+    fi
+
+    test -n "$func_relative_path_result" || func_relative_path_result=.
+
+    :
+}
+
+
+# func_quote_for_eval ARG...
+# --------------------------
+# Aesthetically quote ARGs to be evaled later.
+# This function returns two values:
+#   i) func_quote_for_eval_result
+#      double-quoted, suitable for a subsequent eval
+#  ii) func_quote_for_eval_unquoted_result
+#      has all characters that are still active within double
+#      quotes backslashified.
+func_quote_for_eval ()
+{
+    $debug_cmd
+
+    func_quote_for_eval_unquoted_result=
+    func_quote_for_eval_result=
+    while test 0 -lt $#; do
+      case $1 in
+        *[\\\`\"\$]*)
+         _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;;
+        *)
+          _G_unquoted_arg=$1 ;;
+      esac
+      if test -n "$func_quote_for_eval_unquoted_result"; then
+       func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg"
+      else
+        func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg"
+      fi
+
+      case $_G_unquoted_arg in
+        # Double-quote args containing shell metacharacters to delay
+        # word splitting, command substitution and variable expansion
+        # for a subsequent eval.
+        # Many Bourne shells cannot handle close brackets correctly
+        # in scan sets, so we specify it separately.
+        *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \  ]*|*]*|"")
+          _G_quoted_arg=\"$_G_unquoted_arg\"
+          ;;
+        *)
+          _G_quoted_arg=$_G_unquoted_arg
+         ;;
+      esac
+
+      if test -n "$func_quote_for_eval_result"; then
+       func_append func_quote_for_eval_result " $_G_quoted_arg"
+      else
+        func_append func_quote_for_eval_result "$_G_quoted_arg"
+      fi
+      shift
+    done
+}
+
+
+# func_quote_for_expand ARG
+# -------------------------
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+    $debug_cmd
+
+    case $1 in
+      *[\\\`\"]*)
+       _G_arg=`$ECHO "$1" | $SED \
+           -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;;
+      *)
+        _G_arg=$1 ;;
+    esac
+
+    case $_G_arg in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting and command substitution for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \    ]*|*]*|"")
+        _G_arg=\"$_G_arg\"
+        ;;
+    esac
+
+    func_quote_for_expand_result=$_G_arg
+}
+
+
+# func_stripname PREFIX SUFFIX NAME
+# ---------------------------------
+# strip PREFIX and SUFFIX from NAME, and store in func_stripname_result.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+if test yes = "$_G_HAVE_XSI_OPS"; then
+  eval 'func_stripname ()
+  {
+    $debug_cmd
+
+    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+    # positional parameters, so assign one to ordinary variable first.
+    func_stripname_result=$3
+    func_stripname_result=${func_stripname_result#"$1"}
+    func_stripname_result=${func_stripname_result%"$2"}
+  }'
+else
+  func_stripname ()
+  {
+    $debug_cmd
+
+    case $2 in
+      .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;;
+      *)  func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;;
+    esac
+  }
+fi
+
+
+# func_show_eval CMD [FAIL_EXP]
+# -----------------------------
+# Unless opt_quiet is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+    $debug_cmd
+
+    _G_cmd=$1
+    _G_fail_exp=${2-':'}
+
+    func_quote_for_expand "$_G_cmd"
+    eval "func_notquiet $func_quote_for_expand_result"
+
+    $opt_dry_run || {
+      eval "$_G_cmd"
+      _G_status=$?
+      if test 0 -ne "$_G_status"; then
+       eval "(exit $_G_status); $_G_fail_exp"
+      fi
+    }
+}
+
+
+# func_show_eval_locale CMD [FAIL_EXP]
+# ------------------------------------
+# Unless opt_quiet is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.  Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+    $debug_cmd
+
+    _G_cmd=$1
+    _G_fail_exp=${2-':'}
+
+    $opt_quiet || {
+      func_quote_for_expand "$_G_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    $opt_dry_run || {
+      eval "$_G_user_locale
+           $_G_cmd"
+      _G_status=$?
+      eval "$_G_safe_locale"
+      if test 0 -ne "$_G_status"; then
+       eval "(exit $_G_status); $_G_fail_exp"
+      fi
+    }
+}
+
+
+# func_tr_sh
+# ----------
+# Turn $1 into a string suitable for a shell variable name.
+# Result is stored in $func_tr_sh_result.  All characters
+# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
+# if $1 begins with a digit, a '_' is prepended as well.
+func_tr_sh ()
+{
+    $debug_cmd
+
+    case $1 in
+    [0-9]* | *[!a-zA-Z0-9_]*)
+      func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'`
+      ;;
+    * )
+      func_tr_sh_result=$1
+      ;;
+    esac
+}
+
+
+# func_verbose ARG...
+# -------------------
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+    $debug_cmd
+
+    $opt_verbose && func_echo "$*"
+
+    :
+}
+
+
+# func_warn_and_continue ARG...
+# -----------------------------
+# Echo program name prefixed warning message to standard error.
+func_warn_and_continue ()
+{
+    $debug_cmd
+
+    $require_term_colors
+
+    func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2
+}
+
+
+# func_warning CATEGORY ARG...
+# ----------------------------
+# Echo program name prefixed warning message to standard error. Warning
+# messages can be filtered according to CATEGORY, where this function
+# elides messages where CATEGORY is not listed in the global variable
+# 'opt_warning_types'.
+func_warning ()
+{
+    $debug_cmd
+
+    # CATEGORY must be in the warning_categories list!
+    case " $warning_categories " in
+      *" $1 "*) ;;
+      *) func_internal_error "invalid warning category '$1'" ;;
+    esac
+
+    _G_category=$1
+    shift
+
+    case " $opt_warning_types " in
+      *" $_G_category "*) $warning_func ${1+"$@"} ;;
+    esac
+}
+
+
+# func_sort_ver VER1 VER2
+# -----------------------
+# 'sort -V' is not generally available.
+# Note this deviates from the version comparison in automake
+# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a
+# but this should suffice as we won't be specifying old
+# version formats or redundant trailing .0 in bootstrap.conf.
+# If we did want full compatibility then we should probably
+# use m4_version_compare from autoconf.
+func_sort_ver ()
+{
+    $debug_cmd
+
+    printf '%s\n%s\n' "$1" "$2" \
+      | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n
+}
+
+# func_lt_ver PREV CURR
+# ---------------------
+# Return true if PREV and CURR are in the correct order according to
+# func_sort_ver, otherwise false.  Use it like this:
+#
+#  func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..."
+func_lt_ver ()
+{
+    $debug_cmd
+
+    test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q`
+}
+
+
+# Local variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-time-zone: "UTC"
+# End:
+#! /bin/sh
+
+# Set a version string for this script.
+scriptversion=2014-01-07.03; # UTC
+
+# A portable, pluggable option parser for Bourne shell.
+# Written by Gary V. Vaughan, 2010
+
+# Copyright (C) 2010-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Please report bugs or propose patches to gary@gnu.org.
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# This file is a library for parsing options in your shell scripts along
+# with assorted other useful supporting features that you can make use
+# of too.
+#
+# For the simplest scripts you might need only:
+#
+#   #!/bin/sh
+#   . relative/path/to/funclib.sh
+#   . relative/path/to/options-parser
+#   scriptversion=1.0
+#   func_options ${1+"$@"}
+#   eval set dummy "$func_options_result"; shift
+#   ...rest of your script...
+#
+# In order for the '--version' option to work, you will need to have a
+# suitably formatted comment like the one at the top of this file
+# starting with '# Written by ' and ending with '# warranty; '.
+#
+# For '-h' and '--help' to work, you will also need a one line
+# description of your script's purpose in a comment directly above the
+# '# Written by ' line, like the one at the top of this file.
+#
+# The default options also support '--debug', which will turn on shell
+# execution tracing (see the comment above debug_cmd below for another
+# use), and '--verbose' and the func_verbose function to allow your script
+# to display verbose messages only when your user has specified
+# '--verbose'.
+#
+# After sourcing this file, you can plug processing for additional
+# options by amending the variables from the 'Configuration' section
+# below, and following the instructions in the 'Option parsing'
+# section further down.
+
+## -------------- ##
+## Configuration. ##
+## -------------- ##
+
+# You should override these variables in your script after sourcing this
+# file so that they reflect the customisations you have added to the
+# option parser.
+
+# The usage line for option parsing errors and the start of '-h' and
+# '--help' output messages. You can embed shell variables for delayed
+# expansion at the time the message is displayed, but you will need to
+# quote other shell meta-characters carefully to prevent them being
+# expanded when the contents are evaled.
+usage='$progpath [OPTION]...'
+
+# Short help message in response to '-h' and '--help'.  Add to this or
+# override it after sourcing this library to reflect the full set of
+# options your script accepts.
+usage_message="\
+       --debug        enable verbose shell tracing
+   -W, --warnings=CATEGORY
+                      report the warnings falling in CATEGORY [all]
+   -v, --verbose      verbosely report processing
+       --version      print version information and exit
+   -h, --help         print short or long help message and exit
+"
+
+# Additional text appended to 'usage_message' in response to '--help'.
+long_help_message="
+Warning categories include:
+       'all'          show all warnings
+       'none'         turn off all the warnings
+       'error'        warnings are treated as fatal errors"
+
+# Help message printed before fatal option parsing errors.
+fatal_help="Try '\$progname --help' for more information."
+
+
+
+## ------------------------- ##
+## Hook function management. ##
+## ------------------------- ##
+
+# This section contains functions for adding, removing, and running hooks
+# to the main code.  A hook is just a named list of of function, that can
+# be run in order later on.
+
+# func_hookable FUNC_NAME
+# -----------------------
+# Declare that FUNC_NAME will run hooks added with
+# 'func_add_hook FUNC_NAME ...'.
+func_hookable ()
+{
+    $debug_cmd
+
+    func_append hookable_fns " $1"
+}
+
+
+# func_add_hook FUNC_NAME HOOK_FUNC
+# ---------------------------------
+# Request that FUNC_NAME call HOOK_FUNC before it returns.  FUNC_NAME must
+# first have been declared "hookable" by a call to 'func_hookable'.
+func_add_hook ()
+{
+    $debug_cmd
+
+    case " $hookable_fns " in
+      *" $1 "*) ;;
+      *) func_fatal_error "'$1' does not accept hook functions." ;;
+    esac
+
+    eval func_append ${1}_hooks '" $2"'
+}
+
+
+# func_remove_hook FUNC_NAME HOOK_FUNC
+# ------------------------------------
+# Remove HOOK_FUNC from the list of functions called by FUNC_NAME.
+func_remove_hook ()
+{
+    $debug_cmd
+
+    eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`'
+}
+
+
+# func_run_hooks FUNC_NAME [ARG]...
+# ---------------------------------
+# Run all hook functions registered to FUNC_NAME.
+# It is assumed that the list of hook functions contains nothing more
+# than a whitespace-delimited list of legal shell function names, and
+# no effort is wasted trying to catch shell meta-characters or preserve
+# whitespace.
+func_run_hooks ()
+{
+    $debug_cmd
+
+    case " $hookable_fns " in
+      *" $1 "*) ;;
+      *) func_fatal_error "'$1' does not support hook funcions.n" ;;
+    esac
+
+    eval _G_hook_fns=\$$1_hooks; shift
+
+    for _G_hook in $_G_hook_fns; do
+      eval $_G_hook '"$@"'
+
+      # store returned options list back into positional
+      # parameters for next 'cmd' execution.
+      eval _G_hook_result=\$${_G_hook}_result
+      eval set dummy "$_G_hook_result"; shift
+    done
+
+    func_quote_for_eval ${1+"$@"}
+    func_run_hooks_result=$func_quote_for_eval_result
+}
+
+
+
+## --------------- ##
+## Option parsing. ##
+## --------------- ##
+
+# In order to add your own option parsing hooks, you must accept the
+# full positional parameter list in your hook function, remove any
+# options that you action, and then pass back the remaining unprocessed
+# options in '<hooked_function_name>_result', escaped suitably for
+# 'eval'.  Like this:
+#
+#    my_options_prep ()
+#    {
+#        $debug_cmd
+#
+#        # Extend the existing usage message.
+#        usage_message=$usage_message'
+#      -s, --silent       don'\''t print informational messages
+#    '
+#
+#        func_quote_for_eval ${1+"$@"}
+#        my_options_prep_result=$func_quote_for_eval_result
+#    }
+#    func_add_hook func_options_prep my_options_prep
+#
+#
+#    my_silent_option ()
+#    {
+#        $debug_cmd
+#
+#        # Note that for efficiency, we parse as many options as we can
+#        # recognise in a loop before passing the remainder back to the
+#        # caller on the first unrecognised argument we encounter.
+#        while test $# -gt 0; do
+#          opt=$1; shift
+#          case $opt in
+#            --silent|-s) opt_silent=: ;;
+#            # Separate non-argument short options:
+#            -s*)         func_split_short_opt "$_G_opt"
+#                         set dummy "$func_split_short_opt_name" \
+#                             "-$func_split_short_opt_arg" ${1+"$@"}
+#                         shift
+#                         ;;
+#            *)            set dummy "$_G_opt" "$*"; shift; break ;;
+#          esac
+#        done
+#
+#        func_quote_for_eval ${1+"$@"}
+#        my_silent_option_result=$func_quote_for_eval_result
+#    }
+#    func_add_hook func_parse_options my_silent_option
+#
+#
+#    my_option_validation ()
+#    {
+#        $debug_cmd
+#
+#        $opt_silent && $opt_verbose && func_fatal_help "\
+#    '--silent' and '--verbose' options are mutually exclusive."
+#
+#        func_quote_for_eval ${1+"$@"}
+#        my_option_validation_result=$func_quote_for_eval_result
+#    }
+#    func_add_hook func_validate_options my_option_validation
+#
+# You'll alse need to manually amend $usage_message to reflect the extra
+# options you parse.  It's preferable to append if you can, so that
+# multiple option parsing hooks can be added safely.
+
+
+# func_options [ARG]...
+# ---------------------
+# All the functions called inside func_options are hookable. See the
+# individual implementations for details.
+func_hookable func_options
+func_options ()
+{
+    $debug_cmd
+
+    func_options_prep ${1+"$@"}
+    eval func_parse_options \
+        ${func_options_prep_result+"$func_options_prep_result"}
+    eval func_validate_options \
+        ${func_parse_options_result+"$func_parse_options_result"}
+
+    eval func_run_hooks func_options \
+        ${func_validate_options_result+"$func_validate_options_result"}
+
+    # save modified positional parameters for caller
+    func_options_result=$func_run_hooks_result
+}
+
+
+# func_options_prep [ARG]...
+# --------------------------
+# All initialisations required before starting the option parse loop.
+# Note that when calling hook functions, we pass through the list of
+# positional parameters.  If a hook function modifies that list, and
+# needs to propogate that back to rest of this script, then the complete
+# modified list must be put in 'func_run_hooks_result' before
+# returning.
+func_hookable func_options_prep
+func_options_prep ()
+{
+    $debug_cmd
+
+    # Option defaults:
+    opt_verbose=false
+    opt_warning_types=
+
+    func_run_hooks func_options_prep ${1+"$@"}
+
+    # save modified positional parameters for caller
+    func_options_prep_result=$func_run_hooks_result
+}
+
+
+# func_parse_options [ARG]...
+# ---------------------------
+# The main option parsing loop.
+func_hookable func_parse_options
+func_parse_options ()
+{
+    $debug_cmd
+
+    func_parse_options_result=
+
+    # this just eases exit handling
+    while test $# -gt 0; do
+      # Defer to hook functions for initial option parsing, so they
+      # get priority in the event of reusing an option name.
+      func_run_hooks func_parse_options ${1+"$@"}
+
+      # Adjust func_parse_options positional parameters to match
+      eval set dummy "$func_run_hooks_result"; shift
+
+      # Break out of the loop if we already parsed every option.
+      test $# -gt 0 || break
+
+      _G_opt=$1
+      shift
+      case $_G_opt in
+        --debug|-x)   debug_cmd='set -x'
+                      func_echo "enabling shell trace mode"
+                      $debug_cmd
+                      ;;
+
+        --no-warnings|--no-warning|--no-warn)
+                      set dummy --warnings none ${1+"$@"}
+                      shift
+                     ;;
+
+        --warnings|--warning|-W)
+                      test $# = 0 && func_missing_arg $_G_opt && break
+                      case " $warning_categories $1" in
+                        *" $1 "*)
+                          # trailing space prevents matching last $1 above
+                          func_append_uniq opt_warning_types " $1"
+                          ;;
+                        *all)
+                          opt_warning_types=$warning_categories
+                          ;;
+                        *none)
+                          opt_warning_types=none
+                          warning_func=:
+                          ;;
+                        *error)
+                          opt_warning_types=$warning_categories
+                          warning_func=func_fatal_error
+                          ;;
+                        *)
+                          func_fatal_error \
+                             "unsupported warning category: '$1'"
+                          ;;
+                      esac
+                      shift
+                      ;;
+
+        --verbose|-v) opt_verbose=: ;;
+        --version)    func_version ;;
+        -\?|-h)       func_usage ;;
+        --help)       func_help ;;
+
+       # Separate optargs to long options (plugins may need this):
+       --*=*)        func_split_equals "$_G_opt"
+                     set dummy "$func_split_equals_lhs" \
+                          "$func_split_equals_rhs" ${1+"$@"}
+                      shift
+                      ;;
+
+       # Separate optargs to short options:
+        -W*)
+                      func_split_short_opt "$_G_opt"
+                      set dummy "$func_split_short_opt_name" \
+                          "$func_split_short_opt_arg" ${1+"$@"}
+                      shift
+                      ;;
+
+        # Separate non-argument short options:
+        -\?*|-h*|-v*|-x*)
+                      func_split_short_opt "$_G_opt"
+                      set dummy "$func_split_short_opt_name" \
+                          "-$func_split_short_opt_arg" ${1+"$@"}
+                      shift
+                      ;;
+
+        --)           break ;;
+        -*)           func_fatal_help "unrecognised option: '$_G_opt'" ;;
+        *)            set dummy "$_G_opt" ${1+"$@"}; shift; break ;;
+      esac
+    done
+
+    # save modified positional parameters for caller
+    func_quote_for_eval ${1+"$@"}
+    func_parse_options_result=$func_quote_for_eval_result
+}
+
+
+# func_validate_options [ARG]...
+# ------------------------------
+# Perform any sanity checks on option settings and/or unconsumed
+# arguments.
+func_hookable func_validate_options
+func_validate_options ()
+{
+    $debug_cmd
+
+    # Display all warnings if -W was not given.
+    test -n "$opt_warning_types" || opt_warning_types=" $warning_categories"
+
+    func_run_hooks func_validate_options ${1+"$@"}
+
+    # Bail if the options were screwed!
+    $exit_cmd $EXIT_FAILURE
+
+    # save modified positional parameters for caller
+    func_validate_options_result=$func_run_hooks_result
+}
+
+
+
+## ----------------- ##
+## Helper functions. ##
+## ----------------- ##
+
+# This section contains the helper functions used by the rest of the
+# hookable option parser framework in ascii-betical order.
+
+
+# func_fatal_help ARG...
+# ----------------------
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+    $debug_cmd
+
+    eval \$ECHO \""Usage: $usage"\"
+    eval \$ECHO \""$fatal_help"\"
+    func_error ${1+"$@"}
+    exit $EXIT_FAILURE
+}
+
+
+# func_help
+# ---------
+# Echo long help message to standard output and exit.
+func_help ()
+{
+    $debug_cmd
+
+    func_usage_message
+    $ECHO "$long_help_message"
+    exit 0
+}
+
+
+# func_missing_arg ARGNAME
+# ------------------------
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+    $debug_cmd
+
+    func_error "Missing argument for '$1'."
+    exit_cmd=exit
+}
+
+
+# func_split_equals STRING
+# ------------------------
+# Set func_split_equals_lhs and func_split_equals_rhs shell variables after
+# splitting STRING at the '=' sign.
+test -z "$_G_HAVE_XSI_OPS" \
+    && (eval 'x=a/b/c;
+      test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
+    && _G_HAVE_XSI_OPS=yes
+
+if test yes = "$_G_HAVE_XSI_OPS"
+then
+  # This is an XSI compatible shell, allowing a faster implementation...
+  eval 'func_split_equals ()
+  {
+      $debug_cmd
+
+      func_split_equals_lhs=${1%%=*}
+      func_split_equals_rhs=${1#*=}
+      test "x$func_split_equals_lhs" = "x$1" \
+        && func_split_equals_rhs=
+  }'
+else
+  # ...otherwise fall back to using expr, which is often a shell builtin.
+  func_split_equals ()
+  {
+      $debug_cmd
+
+      func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'`
+      func_split_equals_rhs=
+      test "x$func_split_equals_lhs" = "x$1" \
+        || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'`
+  }
+fi #func_split_equals
+
+
+# func_split_short_opt SHORTOPT
+# -----------------------------
+# Set func_split_short_opt_name and func_split_short_opt_arg shell
+# variables after splitting SHORTOPT after the 2nd character.
+if test yes = "$_G_HAVE_XSI_OPS"
+then
+  # This is an XSI compatible shell, allowing a faster implementation...
+  eval 'func_split_short_opt ()
+  {
+      $debug_cmd
+
+      func_split_short_opt_arg=${1#??}
+      func_split_short_opt_name=${1%"$func_split_short_opt_arg"}
+  }'
+else
+  # ...otherwise fall back to using expr, which is often a shell builtin.
+  func_split_short_opt ()
+  {
+      $debug_cmd
+
+      func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'`
+      func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'`
+  }
+fi #func_split_short_opt
+
+
+# func_usage
+# ----------
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+    $debug_cmd
+
+    func_usage_message
+    $ECHO "Run '$progname --help |${PAGER-more}' for full usage"
+    exit 0
+}
+
+
+# func_usage_message
+# ------------------
+# Echo short help message to standard output.
+func_usage_message ()
+{
+    $debug_cmd
+
+    eval \$ECHO \""Usage: $usage"\"
+    echo
+    $SED -n 's|^# ||
+        /^Written by/{
+          x;p;x
+        }
+       h
+       /^Written by/q' < "$progpath"
+    echo
+    eval \$ECHO \""$usage_message"\"
+}
+
+
+# func_version
+# ------------
+# Echo version message to standard output and exit.
+func_version ()
+{
+    $debug_cmd
+
+    printf '%s\n' "$progname $scriptversion"
+    $SED -n '
+        /(C)/!b go
+        :more
+        /\./!{
+          N
+          s|\n# | |
+          b more
+        }
+        :go
+        /^# Written by /,/# warranty; / {
+          s|^# ||
+          s|^# *$||
+          s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2|
+          p
+        }
+        /^# Written by / {
+          s|^# ||
+          p
+        }
+        /^warranty; /q' < "$progpath"
+
+    exit $?
+}
+
+
+# Local variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-time-zone: "UTC"
+# End:
+
+# Set a version string.
+scriptversion='(GNU libtool) 2.4.6'
+
+
+# func_echo ARG...
+# ----------------
+# Libtool also displays the current mode in messages, so override
+# funclib.sh func_echo with this custom definition.
+func_echo ()
+{
+    $debug_cmd
+
+    _G_message=$*
+
+    func_echo_IFS=$IFS
+    IFS=$nl
+    for _G_line in $_G_message; do
+      IFS=$func_echo_IFS
+      $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line"
+    done
+    IFS=$func_echo_IFS
+}
+
+
+# func_warning ARG...
+# -------------------
+# Libtool warnings are not categorized, so override funclib.sh
+# func_warning with this simpler definition.
+func_warning ()
+{
+    $debug_cmd
+
+    $warning_func ${1+"$@"}
+}
+
+
+## ---------------- ##
+## Options parsing. ##
+## ---------------- ##
+
+# Hook in the functions to make sure our own options are parsed during
+# the option parsing loop.
+
+usage='$progpath [OPTION]... [MODE-ARG]...'
+
+# Short help message in response to '-h'.
+usage_message="Options:
+       --config             show all configuration variables
+       --debug              enable verbose shell tracing
+   -n, --dry-run            display commands without modifying any files
+       --features           display basic configuration information and exit
+       --mode=MODE          use operation mode MODE
+       --no-warnings        equivalent to '-Wnone'
+       --preserve-dup-deps  don't remove duplicate dependency libraries
+       --quiet, --silent    don't print informational messages
+       --tag=TAG            use configuration variables from tag TAG
+   -v, --verbose            print more informational messages than default
+       --version            print version information
+   -W, --warnings=CATEGORY  report the warnings falling in CATEGORY [all]
+   -h, --help, --help-all   print short, long, or detailed help message
+"
+
+# Additional text appended to 'usage_message' in response to '--help'.
+func_help ()
+{
+    $debug_cmd
+
+    func_usage_message
+    $ECHO "$long_help_message
+
+MODE must be one of the following:
+
+       clean           remove files from the build directory
+       compile         compile a source file into a libtool object
+       execute         automatically set library path, then run a program
+       finish          complete the installation of libtool libraries
+       install         install libraries or executables
+       link            create a library or an executable
+       uninstall       remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE.  When passed as first option,
+'--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that.
+Try '$progname --help --mode=MODE' for a more detailed description of MODE.
+
+When reporting a bug, please describe a test case to reproduce it and
+include the following information:
+
+       host-triplet:   $host
+       shell:          $SHELL
+       compiler:       $LTCC
+       compiler flags: $LTCFLAGS
+       linker:         $LD (gnu? $with_gnu_ld)
+       version:        $progname (GNU libtool) 2.4.6
+       automake:       `($AUTOMAKE --version) 2>/dev/null |$SED 1q`
+       autoconf:       `($AUTOCONF --version) 2>/dev/null |$SED 1q`
+
+Report bugs to <bug-libtool@gnu.org>.
+GNU libtool home page: <http://www.gnu.org/software/libtool/>.
+General help using GNU software: <http://www.gnu.org/gethelp/>."
+    exit 0
+}
+
+
+# func_lo2o OBJECT-NAME
+# ---------------------
+# Transform OBJECT-NAME from a '.lo' suffix to the platform specific
+# object suffix.
+
+lo2o=s/\\.lo\$/.$objext/
+o2lo=s/\\.$objext\$/.lo/
+
+if test yes = "$_G_HAVE_XSI_OPS"; then
+  eval 'func_lo2o ()
+  {
+    case $1 in
+      *.lo) func_lo2o_result=${1%.lo}.$objext ;;
+      *   ) func_lo2o_result=$1               ;;
+    esac
+  }'
+
+  # func_xform LIBOBJ-OR-SOURCE
+  # ---------------------------
+  # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise)
+  # suffix to a '.lo' libtool-object suffix.
+  eval 'func_xform ()
+  {
+    func_xform_result=${1%.*}.lo
+  }'
+else
+  # ...otherwise fall back to using sed.
+  func_lo2o ()
+  {
+    func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"`
+  }
+
+  func_xform ()
+  {
+    func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'`
+  }
+fi
+
+
+# func_fatal_configuration ARG...
+# -------------------------------
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+    func__fatal_error ${1+"$@"} \
+      "See the $PACKAGE documentation for more information." \
+      "Fatal configuration error."
+}
+
+
+# func_config
+# -----------
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+    re_begincf='^# ### BEGIN LIBTOOL'
+    re_endcf='^# ### END LIBTOOL'
+
+    # Default configuration.
+    $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+    # Now print the configurations for the tags.
+    for tagname in $taglist; do
+      $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+    done
+
+    exit $?
+}
+
+
+# func_features
+# -------------
+# Display the features supported by this script.
+func_features ()
+{
+    echo "host: $host"
+    if test yes = "$build_libtool_libs"; then
+      echo "enable shared libraries"
+    else
+      echo "disable shared libraries"
+    fi
+    if test yes = "$build_old_libs"; then
+      echo "enable static libraries"
+    else
+      echo "disable static libraries"
+    fi
+
+    exit $?
+}
+
+
+# func_enable_tag TAGNAME
+# -----------------------
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag.  We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+    # Global variable:
+    tagname=$1
+
+    re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+    re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+    sed_extractcf=/$re_begincf/,/$re_endcf/p
+
+    # Validate tagname.
+    case $tagname in
+      *[!-_A-Za-z0-9,/]*)
+        func_fatal_error "invalid tag name: $tagname"
+        ;;
+    esac
+
+    # Don't test for the "default" C tag, as we know it's
+    # there but not specially marked.
+    case $tagname in
+        CC) ;;
+    *)
+        if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+         taglist="$taglist $tagname"
+
+         # Evaluate the configuration.  Be careful to quote the path
+         # and the sed script, to avoid splitting on whitespace, but
+         # also don't use non-portable quotes within backquotes within
+         # quotes we have to do it in 2 steps:
+         extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+         eval "$extractedcf"
+        else
+         func_error "ignoring unknown tag $tagname"
+        fi
+        ;;
+    esac
+}
+
+
+# func_check_version_match
+# ------------------------
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+    if test "$package_revision" != "$macro_revision"; then
+      if test "$VERSION" != "$macro_version"; then
+        if test -z "$macro_version"; then
+          cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+        else
+          cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+        fi
+      else
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+      fi
+
+      exit $EXIT_MISMATCH
+    fi
+}
+
+
+# libtool_options_prep [ARG]...
+# -----------------------------
+# Preparation for options parsed by libtool.
+libtool_options_prep ()
+{
+    $debug_mode
+
+    # Option defaults:
+    opt_config=false
+    opt_dlopen=
+    opt_dry_run=false
+    opt_help=false
+    opt_mode=
+    opt_preserve_dup_deps=false
+    opt_quiet=false
+
+    nonopt=
+    preserve_args=
+
+    # Shorthand for --mode=foo, only valid as the first argument
+    case $1 in
+    clean|clea|cle|cl)
+      shift; set dummy --mode clean ${1+"$@"}; shift
+      ;;
+    compile|compil|compi|comp|com|co|c)
+      shift; set dummy --mode compile ${1+"$@"}; shift
+      ;;
+    execute|execut|execu|exec|exe|ex|e)
+      shift; set dummy --mode execute ${1+"$@"}; shift
+      ;;
+    finish|finis|fini|fin|fi|f)
+      shift; set dummy --mode finish ${1+"$@"}; shift
+      ;;
+    install|instal|insta|inst|ins|in|i)
+      shift; set dummy --mode install ${1+"$@"}; shift
+      ;;
+    link|lin|li|l)
+      shift; set dummy --mode link ${1+"$@"}; shift
+      ;;
+    uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+      shift; set dummy --mode uninstall ${1+"$@"}; shift
+      ;;
+    esac
+
+    # Pass back the list of options.
+    func_quote_for_eval ${1+"$@"}
+    libtool_options_prep_result=$func_quote_for_eval_result
+}
+func_add_hook func_options_prep libtool_options_prep
+
+
+# libtool_parse_options [ARG]...
+# ---------------------------------
+# Provide handling for libtool specific options.
+libtool_parse_options ()
+{
+    $debug_cmd
+
+    # Perform our own loop to consume as many options as possible in
+    # each iteration.
+    while test $# -gt 0; do
+      _G_opt=$1
+      shift
+      case $_G_opt in
+        --dry-run|--dryrun|-n)
+                        opt_dry_run=:
+                        ;;
+
+        --config)       func_config ;;
+
+        --dlopen|-dlopen)
+                        opt_dlopen="${opt_dlopen+$opt_dlopen
+}$1"
+                        shift
+                        ;;
+
+        --preserve-dup-deps)
+                        opt_preserve_dup_deps=: ;;
+
+        --features)     func_features ;;
+
+        --finish)       set dummy --mode finish ${1+"$@"}; shift ;;
+
+        --help)         opt_help=: ;;
+
+        --help-all)     opt_help=': help-all' ;;
+
+        --mode)         test $# = 0 && func_missing_arg $_G_opt && break
+                        opt_mode=$1
+                        case $1 in
+                          # Valid mode arguments:
+                          clean|compile|execute|finish|install|link|relink|uninstall) ;;
+
+                          # Catch anything else as an error
+                          *) func_error "invalid argument for $_G_opt"
+                             exit_cmd=exit
+                             break
+                             ;;
+                        esac
+                        shift
+                        ;;
+
+        --no-silent|--no-quiet)
+                        opt_quiet=false
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+        --no-warnings|--no-warning|--no-warn)
+                        opt_warning=false
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+        --no-verbose)
+                        opt_verbose=false
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+        --silent|--quiet)
+                        opt_quiet=:
+                        opt_verbose=false
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+        --tag)          test $# = 0 && func_missing_arg $_G_opt && break
+                        opt_tag=$1
+                        func_append preserve_args " $_G_opt $1"
+                        func_enable_tag "$1"
+                        shift
+                        ;;
+
+        --verbose|-v)   opt_quiet=false
+                        opt_verbose=:
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+       # An option not handled by this hook function:
+        *)             set dummy "$_G_opt" ${1+"$@"};  shift; break  ;;
+      esac
+    done
+
+
+    # save modified positional parameters for caller
+    func_quote_for_eval ${1+"$@"}
+    libtool_parse_options_result=$func_quote_for_eval_result
+}
+func_add_hook func_parse_options libtool_parse_options
+
+
+
+# libtool_validate_options [ARG]...
+# ---------------------------------
+# Perform any sanity checks on option settings and/or unconsumed
+# arguments.
+libtool_validate_options ()
+{
+    # save first non-option argument
+    if test 0 -lt $#; then
+      nonopt=$1
+      shift
+    fi
+
+    # preserve --debug
+    test : = "$debug_cmd" || func_append preserve_args " --debug"
+
+    case $host in
+      # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452
+      # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788
+      *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*)
+        # don't eliminate duplications in $postdeps and $predeps
+        opt_duplicate_compiler_generated_deps=:
+        ;;
+      *)
+        opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
+        ;;
+    esac
+
+    $opt_help || {
+      # Sanity checks first:
+      func_check_version_match
+
+      test yes != "$build_libtool_libs" \
+        && test yes != "$build_old_libs" \
+        && func_fatal_configuration "not configured to build any kind of library"
+
+      # Darwin sucks
+      eval std_shrext=\"$shrext_cmds\"
+
+      # Only execute mode is allowed to have -dlopen flags.
+      if test -n "$opt_dlopen" && test execute != "$opt_mode"; then
+        func_error "unrecognized option '-dlopen'"
+        $ECHO "$help" 1>&2
+        exit $EXIT_FAILURE
+      fi
+
+      # Change the help message to a mode-specific one.
+      generic_help=$help
+      help="Try '$progname --help --mode=$opt_mode' for more information."
+    }
+
+    # Pass back the unparsed argument list
+    func_quote_for_eval ${1+"$@"}
+    libtool_validate_options_result=$func_quote_for_eval_result
+}
+func_add_hook func_validate_options libtool_validate_options
+
+
+# Process options as early as possible so that --help and --version
+# can return quickly.
+func_options ${1+"$@"}
+eval set dummy "$func_options_result"; shift
+
+
+
+## ----------- ##
+##    Main.    ##
+## ----------- ##
+
+magic='%%%MAGIC variable%%%'
+magic_exe='%%%MAGIC EXE variable%%%'
+
+# Global variables.
+extracted_archives=
+extracted_serial=0
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end.  This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# func_generated_by_libtool
+# True iff stdin has been generated by Libtool. This function is only
+# a basic sanity check; it will hardly flush out determined imposters.
+func_generated_by_libtool_p ()
+{
+  $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_p file
+# True iff FILE is a libtool '.la' library or '.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+    test -f "$1" &&
+      $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool '.la' library or '.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs.  To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway.  Works if 'file' does not exist.
+func_lalib_unsafe_p ()
+{
+    lalib_p=no
+    if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+       for lalib_p_l in 1 2 3 4
+       do
+           read lalib_p_line
+           case $lalib_p_line in
+               \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+           esac
+       done
+       exec 0<&5 5<&-
+    fi
+    test yes = "$lalib_p"
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+    test -f "$1" &&
+      $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+    func_ltwrapper_exec_suffix=
+    case $1 in
+    *.exe) ;;
+    *) func_ltwrapper_exec_suffix=.exe ;;
+    esac
+    $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+    func_dirname_and_basename "$1" "" "."
+    func_stripname '' '.exe' "$func_basename_result"
+    func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+    func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+    $debug_cmd
+
+    save_ifs=$IFS; IFS='~'
+    for cmd in $1; do
+      IFS=$sp$nl
+      eval cmd=\"$cmd\"
+      IFS=$save_ifs
+      func_show_eval "$cmd" "${2-:}"
+    done
+    IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)!  Also, sourcing
+# 'FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+    $debug_cmd
+
+    case $1 in
+    */* | *\\*)        . "$1" ;;
+    *)         . "./$1" ;;
+    esac
+}
+
+
+# func_resolve_sysroot PATH
+# Replace a leading = in PATH with a sysroot.  Store the result into
+# func_resolve_sysroot_result
+func_resolve_sysroot ()
+{
+  func_resolve_sysroot_result=$1
+  case $func_resolve_sysroot_result in
+  =*)
+    func_stripname '=' '' "$func_resolve_sysroot_result"
+    func_resolve_sysroot_result=$lt_sysroot$func_stripname_result
+    ;;
+  esac
+}
+
+# func_replace_sysroot PATH
+# If PATH begins with the sysroot, replace it with = and
+# store the result into func_replace_sysroot_result.
+func_replace_sysroot ()
+{
+  case $lt_sysroot:$1 in
+  ?*:"$lt_sysroot"*)
+    func_stripname "$lt_sysroot" '' "$1"
+    func_replace_sysroot_result='='$func_stripname_result
+    ;;
+  *)
+    # Including no sysroot.
+    func_replace_sysroot_result=$1
+    ;;
+  esac
+}
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+    $debug_cmd
+
+    if test -n "$available_tags" && test -z "$tagname"; then
+      CC_quoted=
+      for arg in $CC; do
+       func_append_quoted CC_quoted "$arg"
+      done
+      CC_expanded=`func_echo_all $CC`
+      CC_quoted_expanded=`func_echo_all $CC_quoted`
+      case $@ in
+      # Blanks in the command may have been stripped by the calling shell,
+      # but not from the CC environment variable when configure was run.
+      " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+      " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+      # Blanks at the start of $base_compile will cause this to fail
+      # if we don't check for them as well.
+      *)
+       for z in $available_tags; do
+         if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+           # Evaluate the configuration.
+           eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+           CC_quoted=
+           for arg in $CC; do
+             # Double-quote args containing other shell metacharacters.
+             func_append_quoted CC_quoted "$arg"
+           done
+           CC_expanded=`func_echo_all $CC`
+           CC_quoted_expanded=`func_echo_all $CC_quoted`
+           case "$@ " in
+           " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+           " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+             # The compiler in the base compile command matches
+             # the one in the tagged configuration.
+             # Assume this is the tagged configuration we want.
+             tagname=$z
+             break
+             ;;
+           esac
+         fi
+       done
+       # If $tagname still isn't set, then no tagged configuration
+       # was found and let the user know that the "--tag" command
+       # line option must be used.
+       if test -z "$tagname"; then
+         func_echo "unable to infer tagged configuration"
+         func_fatal_error "specify a tag with '--tag'"
+#      else
+#        func_verbose "using $tagname tagged configuration"
+       fi
+       ;;
+      esac
+    fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+    write_libobj=$1
+    if test yes = "$build_libtool_libs"; then
+      write_lobj=\'$2\'
+    else
+      write_lobj=none
+    fi
+
+    if test yes = "$build_old_libs"; then
+      write_oldobj=\'$3\'
+    else
+      write_oldobj=none
+    fi
+
+    $opt_dry_run || {
+      cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+      $MV "${write_libobj}T" "$write_libobj"
+    }
+}
+
+
+##################################################
+# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS #
+##################################################
+
+# func_convert_core_file_wine_to_w32 ARG
+# Helper function used by file name conversion functions when $build is *nix,
+# and $host is mingw, cygwin, or some other w32 environment. Relies on a
+# correctly configured wine environment available, with the winepath program
+# in $build's $PATH.
+#
+# ARG is the $build file name to be converted to w32 format.
+# Result is available in $func_convert_core_file_wine_to_w32_result, and will
+# be empty on error (or when ARG is empty)
+func_convert_core_file_wine_to_w32 ()
+{
+  $debug_cmd
+
+  func_convert_core_file_wine_to_w32_result=$1
+  if test -n "$1"; then
+    # Unfortunately, winepath does not exit with a non-zero error code, so we
+    # are forced to check the contents of stdout. On the other hand, if the
+    # command is not found, the shell will set an exit code of 127 and print
+    # *an error message* to stdout. So we must check for both error code of
+    # zero AND non-empty stdout, which explains the odd construction:
+    func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null`
+    if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then
+      func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
+        $SED -e "$sed_naive_backslashify"`
+    else
+      func_convert_core_file_wine_to_w32_result=
+    fi
+  fi
+}
+# end: func_convert_core_file_wine_to_w32
+
+
+# func_convert_core_path_wine_to_w32 ARG
+# Helper function used by path conversion functions when $build is *nix, and
+# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
+# configured wine environment available, with the winepath program in $build's
+# $PATH. Assumes ARG has no leading or trailing path separator characters.
+#
+# ARG is path to be converted from $build format to win32.
+# Result is available in $func_convert_core_path_wine_to_w32_result.
+# Unconvertible file (directory) names in ARG are skipped; if no directory names
+# are convertible, then the result may be empty.
+func_convert_core_path_wine_to_w32 ()
+{
+  $debug_cmd
+
+  # unfortunately, winepath doesn't convert paths, only file names
+  func_convert_core_path_wine_to_w32_result=
+  if test -n "$1"; then
+    oldIFS=$IFS
+    IFS=:
+    for func_convert_core_path_wine_to_w32_f in $1; do
+      IFS=$oldIFS
+      func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f"
+      if test -n "$func_convert_core_file_wine_to_w32_result"; then
+        if test -z "$func_convert_core_path_wine_to_w32_result"; then
+          func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result
+        else
+          func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
+        fi
+      fi
+    done
+    IFS=$oldIFS
+  fi
+}
+# end: func_convert_core_path_wine_to_w32
+
+
+# func_cygpath ARGS...
+# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when
+# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2)
+# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or
+# (2), returns the Cygwin file name or path in func_cygpath_result (input
+# file name or path is assumed to be in w32 format, as previously converted
+# from $build's *nix or MSYS format). In case (3), returns the w32 file name
+# or path in func_cygpath_result (input file name or path is assumed to be in
+# Cygwin format). Returns an empty string on error.
+#
+# ARGS are passed to cygpath, with the last one being the file name or path to
+# be converted.
+#
+# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH
+# environment variable; do not put it in $PATH.
+func_cygpath ()
+{
+  $debug_cmd
+
+  if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
+    func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
+    if test "$?" -ne 0; then
+      # on failure, ensure result is empty
+      func_cygpath_result=
+    fi
+  else
+    func_cygpath_result=
+    func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'"
+  fi
+}
+#end: func_cygpath
+
+
+# func_convert_core_msys_to_w32 ARG
+# Convert file name or path ARG from MSYS format to w32 format.  Return
+# result in func_convert_core_msys_to_w32_result.
+func_convert_core_msys_to_w32 ()
+{
+  $debug_cmd
+
+  # awkward: cmd appends spaces to result
+  func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null |
+    $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"`
+}
+#end: func_convert_core_msys_to_w32
+
+
+# func_convert_file_check ARG1 ARG2
+# Verify that ARG1 (a file name in $build format) was converted to $host
+# format in ARG2. Otherwise, emit an error message, but continue (resetting
+# func_to_host_file_result to ARG1).
+func_convert_file_check ()
+{
+  $debug_cmd
+
+  if test -z "$2" && test -n "$1"; then
+    func_error "Could not determine host file name corresponding to"
+    func_error "  '$1'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback:
+    func_to_host_file_result=$1
+  fi
+}
+# end func_convert_file_check
+
+
+# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH
+# Verify that FROM_PATH (a path in $build format) was converted to $host
+# format in TO_PATH. Otherwise, emit an error message, but continue, resetting
+# func_to_host_file_result to a simplistic fallback value (see below).
+func_convert_path_check ()
+{
+  $debug_cmd
+
+  if test -z "$4" && test -n "$3"; then
+    func_error "Could not determine the host path corresponding to"
+    func_error "  '$3'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback.  This is a deliberately simplistic "conversion" and
+    # should not be "improved".  See libtool.info.
+    if test "x$1" != "x$2"; then
+      lt_replace_pathsep_chars="s|$1|$2|g"
+      func_to_host_path_result=`echo "$3" |
+        $SED -e "$lt_replace_pathsep_chars"`
+    else
+      func_to_host_path_result=$3
+    fi
+  fi
+}
+# end func_convert_path_check
+
+
+# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG
+# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT
+# and appending REPL if ORIG matches BACKPAT.
+func_convert_path_front_back_pathsep ()
+{
+  $debug_cmd
+
+  case $4 in
+  $1 ) func_to_host_path_result=$3$func_to_host_path_result
+    ;;
+  esac
+  case $4 in
+  $2 ) func_append func_to_host_path_result "$3"
+    ;;
+  esac
+}
+# end func_convert_path_front_back_pathsep
+
+
+##################################################
+# $build to $host FILE NAME CONVERSION FUNCTIONS #
+##################################################
+# invoked via '$to_host_file_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# Result will be available in $func_to_host_file_result.
+
+
+# func_to_host_file ARG
+# Converts the file name ARG from $build format to $host format. Return result
+# in func_to_host_file_result.
+func_to_host_file ()
+{
+  $debug_cmd
+
+  $to_host_file_cmd "$1"
+}
+# end func_to_host_file
+
+
+# func_to_tool_file ARG LAZY
+# converts the file name ARG from $build format to toolchain format. Return
+# result in func_to_tool_file_result.  If the conversion in use is listed
+# in (the comma separated) LAZY, no conversion takes place.
+func_to_tool_file ()
+{
+  $debug_cmd
+
+  case ,$2, in
+    *,"$to_tool_file_cmd",*)
+      func_to_tool_file_result=$1
+      ;;
+    *)
+      $to_tool_file_cmd "$1"
+      func_to_tool_file_result=$func_to_host_file_result
+      ;;
+  esac
+}
+# end func_to_tool_file
+
+
+# func_convert_file_noop ARG
+# Copy ARG to func_to_host_file_result.
+func_convert_file_noop ()
+{
+  func_to_host_file_result=$1
+}
+# end func_convert_file_noop
+
+
+# func_convert_file_msys_to_w32 ARG
+# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_file_result.
+func_convert_file_msys_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_file_result=$1
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_to_host_file_result=$func_convert_core_msys_to_w32_result
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_w32
+
+
+# func_convert_file_cygwin_to_w32 ARG
+# Convert file name ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_file_cygwin_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_file_result=$1
+  if test -n "$1"; then
+    # because $build is cygwin, we call "the" cygpath in $PATH; no need to use
+    # LT_CYGPATH in this case.
+    func_to_host_file_result=`cygpath -m "$1"`
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_cygwin_to_w32
+
+
+# func_convert_file_nix_to_w32 ARG
+# Convert file name ARG from *nix to w32 format.  Requires a wine environment
+# and a working winepath. Returns result in func_to_host_file_result.
+func_convert_file_nix_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_file_result=$1
+  if test -n "$1"; then
+    func_convert_core_file_wine_to_w32 "$1"
+    func_to_host_file_result=$func_convert_core_file_wine_to_w32_result
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_w32
+
+
+# func_convert_file_msys_to_cygwin ARG
+# Convert file name ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_file_msys_to_cygwin ()
+{
+  $debug_cmd
+
+  func_to_host_file_result=$1
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_msys_to_w32_result"
+    func_to_host_file_result=$func_cygpath_result
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_cygwin
+
+
+# func_convert_file_nix_to_cygwin ARG
+# Convert file name ARG from *nix to Cygwin format.  Requires Cygwin installed
+# in a wine environment, working winepath, and LT_CYGPATH set.  Returns result
+# in func_to_host_file_result.
+func_convert_file_nix_to_cygwin ()
+{
+  $debug_cmd
+
+  func_to_host_file_result=$1
+  if test -n "$1"; then
+    # convert from *nix to w32, then use cygpath to convert from w32 to cygwin.
+    func_convert_core_file_wine_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_file_wine_to_w32_result"
+    func_to_host_file_result=$func_cygpath_result
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_cygwin
+
+
+#############################################
+# $build to $host PATH CONVERSION FUNCTIONS #
+#############################################
+# invoked via '$to_host_path_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# The result will be available in $func_to_host_path_result.
+#
+# Path separators are also converted from $build format to $host format.  If
+# ARG begins or ends with a path separator character, it is preserved (but
+# converted to $host format) on output.
+#
+# All path conversion functions are named using the following convention:
+#   file name conversion function    : func_convert_file_X_to_Y ()
+#   path conversion function         : func_convert_path_X_to_Y ()
+# where, for any given $build/$host combination the 'X_to_Y' value is the
+# same.  If conversion functions are added for new $build/$host combinations,
+# the two new functions must follow this pattern, or func_init_to_host_path_cmd
+# will break.
+
+
+# func_init_to_host_path_cmd
+# Ensures that function "pointer" variable $to_host_path_cmd is set to the
+# appropriate value, based on the value of $to_host_file_cmd.
+to_host_path_cmd=
+func_init_to_host_path_cmd ()
+{
+  $debug_cmd
+
+  if test -z "$to_host_path_cmd"; then
+    func_stripname 'func_convert_file_' '' "$to_host_file_cmd"
+    to_host_path_cmd=func_convert_path_$func_stripname_result
+  fi
+}
+
+
+# func_to_host_path ARG
+# Converts the path ARG from $build format to $host format. Return result
+# in func_to_host_path_result.
+func_to_host_path ()
+{
+  $debug_cmd
+
+  func_init_to_host_path_cmd
+  $to_host_path_cmd "$1"
+}
+# end func_to_host_path
+
+
+# func_convert_path_noop ARG
+# Copy ARG to func_to_host_path_result.
+func_convert_path_noop ()
+{
+  func_to_host_path_result=$1
+}
+# end func_convert_path_noop
+
+
+# func_convert_path_msys_to_w32 ARG
+# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_path_result.
+func_convert_path_msys_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_path_result=$1
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from ARG.  MSYS
+    # behavior is inconsistent here; cygpath turns them into '.;' and ';.';
+    # and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result=$func_convert_core_msys_to_w32_result
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_msys_to_w32
+
+
+# func_convert_path_cygwin_to_w32 ARG
+# Convert path ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_path_cygwin_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_path_result=$1
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"`
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_cygwin_to_w32
+
+
+# func_convert_path_nix_to_w32 ARG
+# Convert path ARG from *nix to w32 format.  Requires a wine environment and
+# a working winepath.  Returns result in func_to_host_file_result.
+func_convert_path_nix_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_path_result=$1
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result=$func_convert_core_path_wine_to_w32_result
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_nix_to_w32
+
+
+# func_convert_path_msys_to_cygwin ARG
+# Convert path ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_path_msys_to_cygwin ()
+{
+  $debug_cmd
+
+  func_to_host_path_result=$1
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_msys_to_w32_result"
+    func_to_host_path_result=$func_cygpath_result
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_msys_to_cygwin
+
+
+# func_convert_path_nix_to_cygwin ARG
+# Convert path ARG from *nix to Cygwin format.  Requires Cygwin installed in a
+# a wine environment, working winepath, and LT_CYGPATH set.  Returns result in
+# func_to_host_file_result.
+func_convert_path_nix_to_cygwin ()
+{
+  $debug_cmd
+
+  func_to_host_path_result=$1
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from
+    # ARG. msys behavior is inconsistent here, cygpath turns them
+    # into '.;' and ';.', and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result"
+    func_to_host_path_result=$func_cygpath_result
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_nix_to_cygwin
+
+
+# func_dll_def_p FILE
+# True iff FILE is a Windows DLL '.def' file.
+# Keep in sync with _LT_DLL_DEF_P in libtool.m4
+func_dll_def_p ()
+{
+  $debug_cmd
+
+  func_dll_def_p_tmp=`$SED -n \
+    -e 's/^[    ]*//' \
+    -e '/^\(;.*\)*$/d' \
+    -e 's/^\(EXPORTS\|LIBRARY\)\([      ].*\)*$/DEF/p' \
+    -e q \
+    "$1"`
+  test DEF = "$func_dll_def_p_tmp"
+}
+
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+    $debug_cmd
+
+    # Get the compilation command and the source file.
+    base_compile=
+    srcfile=$nonopt  #  always keep a non-empty value in "srcfile"
+    suppress_opt=yes
+    suppress_output=
+    arg_mode=normal
+    libobj=
+    later=
+    pie_flag=
+
+    for arg
+    do
+      case $arg_mode in
+      arg  )
+       # do not "continue".  Instead, add this to base_compile
+       lastarg=$arg
+       arg_mode=normal
+       ;;
+
+      target )
+       libobj=$arg
+       arg_mode=normal
+       continue
+       ;;
+
+      normal )
+       # Accept any command-line options.
+       case $arg in
+       -o)
+         test -n "$libobj" && \
+           func_fatal_error "you cannot specify '-o' more than once"
+         arg_mode=target
+         continue
+         ;;
+
+       -pie | -fpie | -fPIE)
+          func_append pie_flag " $arg"
+         continue
+         ;;
+
+       -shared | -static | -prefer-pic | -prefer-non-pic)
+         func_append later " $arg"
+         continue
+         ;;
+
+       -no-suppress)
+         suppress_opt=no
+         continue
+         ;;
+
+       -Xcompiler)
+         arg_mode=arg  #  the next one goes into the "base_compile" arg list
+         continue      #  The current "srcfile" will either be retained or
+         ;;            #  replaced later.  I would guess that would be a bug.
+
+       -Wc,*)
+         func_stripname '-Wc,' '' "$arg"
+         args=$func_stripname_result
+         lastarg=
+         save_ifs=$IFS; IFS=,
+         for arg in $args; do
+           IFS=$save_ifs
+           func_append_quoted lastarg "$arg"
+         done
+         IFS=$save_ifs
+         func_stripname ' ' '' "$lastarg"
+         lastarg=$func_stripname_result
+
+         # Add the arguments to base_compile.
+         func_append base_compile " $lastarg"
+         continue
+         ;;
+
+       *)
+         # Accept the current argument as the source file.
+         # The previous "srcfile" becomes the current argument.
+         #
+         lastarg=$srcfile
+         srcfile=$arg
+         ;;
+       esac  #  case $arg
+       ;;
+      esac    #  case $arg_mode
+
+      # Aesthetically quote the previous argument.
+      func_append_quoted base_compile "$lastarg"
+    done # for arg
+
+    case $arg_mode in
+    arg)
+      func_fatal_error "you must specify an argument for -Xcompile"
+      ;;
+    target)
+      func_fatal_error "you must specify a target with '-o'"
+      ;;
+    *)
+      # Get the name of the library object.
+      test -z "$libobj" && {
+       func_basename "$srcfile"
+       libobj=$func_basename_result
+      }
+      ;;
+    esac
+
+    # Recognize several different file suffixes.
+    # If the user specifies -o file.o, it is replaced with file.lo
+    case $libobj in
+    *.[cCFSifmso] | \
+    *.ada | *.adb | *.ads | *.asm | \
+    *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+    *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
+      func_xform "$libobj"
+      libobj=$func_xform_result
+      ;;
+    esac
+
+    case $libobj in
+    *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+    *)
+      func_fatal_error "cannot determine name of library object from '$libobj'"
+      ;;
+    esac
+
+    func_infer_tag $base_compile
+
+    for arg in $later; do
+      case $arg in
+      -shared)
+       test yes = "$build_libtool_libs" \
+         || func_fatal_configuration "cannot build a shared library"
+       build_old_libs=no
+       continue
+       ;;
+
+      -static)
+       build_libtool_libs=no
+       build_old_libs=yes
+       continue
+       ;;
+
+      -prefer-pic)
+       pic_mode=yes
+       continue
+       ;;
+
+      -prefer-non-pic)
+       pic_mode=no
+       continue
+       ;;
+      esac
+    done
+
+    func_quote_for_eval "$libobj"
+    test "X$libobj" != "X$func_quote_for_eval_result" \
+      && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"'   &()|`$[]' \
+      && func_warning "libobj name '$libobj' may not contain shell special characters."
+    func_dirname_and_basename "$obj" "/" ""
+    objname=$func_basename_result
+    xdir=$func_dirname_result
+    lobj=$xdir$objdir/$objname
+
+    test -z "$base_compile" && \
+      func_fatal_help "you must specify a compilation command"
+
+    # Delete any leftover library objects.
+    if test yes = "$build_old_libs"; then
+      removelist="$obj $lobj $libobj ${libobj}T"
+    else
+      removelist="$lobj $libobj ${libobj}T"
+    fi
+
+    # On Cygwin there's no "real" PIC flag so we must build both object types
+    case $host_os in
+    cygwin* | mingw* | pw32* | os2* | cegcc*)
+      pic_mode=default
+      ;;
+    esac
+    if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then
+      # non-PIC code in shared libraries is not supported
+      pic_mode=default
+    fi
+
+    # Calculate the filename of the output object if compiler does
+    # not support -o with -c
+    if test no = "$compiler_c_o"; then
+      output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext
+      lockfile=$output_obj.lock
+    else
+      output_obj=
+      need_locks=no
+      lockfile=
+    fi
+
+    # Lock this critical section if it is needed
+    # We use this script file to make the link, it avoids creating a new file
+    if test yes = "$need_locks"; then
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+       func_echo "Waiting for $lockfile to be removed"
+       sleep 2
+      done
+    elif test warn = "$need_locks"; then
+      if test -f "$lockfile"; then
+       $ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+       $opt_dry_run || $RM $removelist
+       exit $EXIT_FAILURE
+      fi
+      func_append removelist " $output_obj"
+      $ECHO "$srcfile" > "$lockfile"
+    fi
+
+    $opt_dry_run || $RM $removelist
+    func_append removelist " $lockfile"
+    trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+    func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
+    srcfile=$func_to_tool_file_result
+    func_quote_for_eval "$srcfile"
+    qsrcfile=$func_quote_for_eval_result
+
+    # Only build a PIC object if we are building libtool libraries.
+    if test yes = "$build_libtool_libs"; then
+      # Without this assignment, base_compile gets emptied.
+      fbsd_hideous_sh_bug=$base_compile
+
+      if test no != "$pic_mode"; then
+       command="$base_compile $qsrcfile $pic_flag"
+      else
+       # Don't build PIC code
+       command="$base_compile $qsrcfile"
+      fi
+
+      func_mkdir_p "$xdir$objdir"
+
+      if test -z "$output_obj"; then
+       # Place PIC objects in $objdir
+       func_append command " -o $lobj"
+      fi
+
+      func_show_eval_locale "$command" \
+          'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+      if test warn = "$need_locks" &&
+        test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+       $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+       $opt_dry_run || $RM $removelist
+       exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed, then go on to compile the next one
+      if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+       func_show_eval '$MV "$output_obj" "$lobj"' \
+         'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+
+      # Allow error messages only from the first compilation.
+      if test yes = "$suppress_opt"; then
+       suppress_output=' >/dev/null 2>&1'
+      fi
+    fi
+
+    # Only build a position-dependent object if we build old libraries.
+    if test yes = "$build_old_libs"; then
+      if test yes != "$pic_mode"; then
+       # Don't build PIC code
+       command="$base_compile $qsrcfile$pie_flag"
+      else
+       command="$base_compile $qsrcfile $pic_flag"
+      fi
+      if test yes = "$compiler_c_o"; then
+       func_append command " -o $obj"
+      fi
+
+      # Suppress compiler output if we already did a PIC compilation.
+      func_append command "$suppress_output"
+      func_show_eval_locale "$command" \
+        '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+      if test warn = "$need_locks" &&
+        test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+       $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+       $opt_dry_run || $RM $removelist
+       exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed
+      if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+       func_show_eval '$MV "$output_obj" "$obj"' \
+         'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+    fi
+
+    $opt_dry_run || {
+      func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+      # Unlock the critical section if it was locked
+      if test no != "$need_locks"; then
+       removelist=$lockfile
+        $RM "$lockfile"
+      fi
+    }
+
+    exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+  test compile = "$opt_mode" && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+    # We need to display help for each of the modes.
+    case $opt_mode in
+      "")
+        # Generic help is extracted from the usage comments
+        # at the start of this file.
+        func_help
+        ;;
+
+      clean)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically '/bin/rm').  RM-OPTIONS are options (such as '-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      compile)
+      $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+  -o OUTPUT-FILE    set the output file name to OUTPUT-FILE
+  -no-suppress      do not suppress compiler output for multiple passes
+  -prefer-pic       try to build PIC objects only
+  -prefer-non-pic   try to build non-PIC objects only
+  -shared           do not build a '.o' file suitable for static linking
+  -static           only build a '.o' file suitable for static linking
+  -Wc,FLAG          pass FLAG directly to the compiler
+
+COMPILE-COMMAND is a command to be used in creating a 'standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix '.c' with the
+library object suffix, '.lo'."
+        ;;
+
+      execute)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+  -dlopen FILE      add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to '-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+        ;;
+
+      finish)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges.  Use
+the '--dry-run' option if you just want to see what would be executed."
+        ;;
+
+      install)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command.  The first component should be
+either the 'install' or 'cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+  -inst-prefix-dir PREFIX-DIR  Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+        ;;
+
+      link)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+  -all-static       do not do any dynamic linking at all
+  -avoid-version    do not add a version suffix if possible
+  -bindir BINDIR    specify path to binaries directory (for systems where
+                    libraries must be found in the PATH setting at runtime)
+  -dlopen FILE      '-dlpreopen' FILE if it cannot be dlopened at runtime
+  -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
+  -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+  -export-symbols SYMFILE
+                    try to export only the symbols listed in SYMFILE
+  -export-symbols-regex REGEX
+                    try to export only the symbols matching REGEX
+  -LLIBDIR          search LIBDIR for required installed libraries
+  -lNAME            OUTPUT-FILE requires the installed library libNAME
+  -module           build a library that can dlopened
+  -no-fast-install  disable the fast-install mode
+  -no-install       link a not-installable executable
+  -no-undefined     declare that a library does not refer to external symbols
+  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
+  -objectlist FILE  use a list of object files found in FILE to specify objects
+  -os2dllname NAME  force a short DLL name on OS/2 (no effect on other OSes)
+  -precious-files-regex REGEX
+                    don't remove output files matching REGEX
+  -release RELEASE  specify package release information
+  -rpath LIBDIR     the created library will eventually be installed in LIBDIR
+  -R[ ]LIBDIR       add LIBDIR to the runtime path of programs and libraries
+  -shared           only do dynamic linking of libtool libraries
+  -shrext SUFFIX    override the standard shared library file extension
+  -static           do not do any dynamic linking of uninstalled libtool libraries
+  -static-libtool-libs
+                    do not do any dynamic linking of libtool libraries
+  -version-info CURRENT[:REVISION[:AGE]]
+                    specify library version info [each variable defaults to 0]
+  -weak LIBNAME     declare that the target provides the LIBNAME interface
+  -Wc,FLAG
+  -Xcompiler FLAG   pass linker-specific FLAG directly to the compiler
+  -Wl,FLAG
+  -Xlinker FLAG     pass linker-specific FLAG directly to the linker
+  -XCClinker FLAG   pass link-specific FLAG to the compiler driver (CC)
+
+All other options (arguments beginning with '-') are ignored.
+
+Every other argument is treated as a filename.  Files ending in '.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in '.la', then a libtool library is created,
+only library objects ('.lo' files) may be specified, and '-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created
+using 'ar' and 'ranlib', or on Windows using 'lib'.
+
+If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file
+is created, otherwise an executable program is created."
+        ;;
+
+      uninstall)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically '/bin/rm').  RM-OPTIONS are options (such as '-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      *)
+        func_fatal_help "invalid operation mode '$opt_mode'"
+        ;;
+    esac
+
+    echo
+    $ECHO "Try '$progname --help' for more information about other modes."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+  if test : = "$opt_help"; then
+    func_mode_help
+  else
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+       func_mode_help
+      done
+    } | $SED -n '1p; 2,$s/^Usage:/  or: /p'
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+       echo
+       func_mode_help
+      done
+    } |
+    $SED '1d
+      /^When reporting/,/^Report/{
+       H
+       d
+      }
+      $x
+      /information about other modes/d
+      /more detailed .*MODE/d
+      s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+  fi
+  exit $?
+fi
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+    $debug_cmd
+
+    # The first argument is the command name.
+    cmd=$nonopt
+    test -z "$cmd" && \
+      func_fatal_help "you must specify a COMMAND"
+
+    # Handle -dlopen flags immediately.
+    for file in $opt_dlopen; do
+      test -f "$file" \
+       || func_fatal_help "'$file' is not a file"
+
+      dir=
+      case $file in
+      *.la)
+       func_resolve_sysroot "$file"
+       file=$func_resolve_sysroot_result
+
+       # Check to see that this really is a libtool archive.
+       func_lalib_unsafe_p "$file" \
+         || func_fatal_help "'$lib' is not a valid libtool archive"
+
+       # Read the libtool library.
+       dlname=
+       library_names=
+       func_source "$file"
+
+       # Skip this library if it cannot be dlopened.
+       if test -z "$dlname"; then
+         # Warn if it was a shared library.
+         test -n "$library_names" && \
+           func_warning "'$file' was not linked with '-export-dynamic'"
+         continue
+       fi
+
+       func_dirname "$file" "" "."
+       dir=$func_dirname_result
+
+       if test -f "$dir/$objdir/$dlname"; then
+         func_append dir "/$objdir"
+       else
+         if test ! -f "$dir/$dlname"; then
+           func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'"
+         fi
+       fi
+       ;;
+
+      *.lo)
+       # Just add the directory containing the .lo file.
+       func_dirname "$file" "" "."
+       dir=$func_dirname_result
+       ;;
+
+      *)
+       func_warning "'-dlopen' is ignored for non-libtool libraries and objects"
+       continue
+       ;;
+      esac
+
+      # Get the absolute pathname.
+      absdir=`cd "$dir" && pwd`
+      test -n "$absdir" && dir=$absdir
+
+      # Now add the directory to shlibpath_var.
+      if eval "test -z \"\$$shlibpath_var\""; then
+       eval "$shlibpath_var=\"\$dir\""
+      else
+       eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+      fi
+    done
+
+    # This variable tells wrapper scripts just to set shlibpath_var
+    # rather than running their programs.
+    libtool_execute_magic=$magic
+
+    # Check if any of the arguments is a wrapper script.
+    args=
+    for file
+    do
+      case $file in
+      -* | *.la | *.lo ) ;;
+      *)
+       # Do a test to see if this is really a libtool program.
+       if func_ltwrapper_script_p "$file"; then
+         func_source "$file"
+         # Transform arg to wrapped name.
+         file=$progdir/$program
+       elif func_ltwrapper_executable_p "$file"; then
+         func_ltwrapper_scriptname "$file"
+         func_source "$func_ltwrapper_scriptname_result"
+         # Transform arg to wrapped name.
+         file=$progdir/$program
+       fi
+       ;;
+      esac
+      # Quote arguments (to preserve shell metacharacters).
+      func_append_quoted args "$file"
+    done
+
+    if $opt_dry_run; then
+      # Display what would be done.
+      if test -n "$shlibpath_var"; then
+       eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+       echo "export $shlibpath_var"
+      fi
+      $ECHO "$cmd$args"
+      exit $EXIT_SUCCESS
+    else
+      if test -n "$shlibpath_var"; then
+       # Export the shlibpath_var.
+       eval "export $shlibpath_var"
+      fi
+
+      # Restore saved environment variables
+      for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+      do
+       eval "if test \"\${save_$lt_var+set}\" = set; then
+                $lt_var=\$save_$lt_var; export $lt_var
+             else
+               $lt_unset $lt_var
+             fi"
+      done
+
+      # Now prepare to actually exec the command.
+      exec_cmd=\$cmd$args
+    fi
+}
+
+test execute = "$opt_mode" && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+    $debug_cmd
+
+    libs=
+    libdirs=
+    admincmds=
+
+    for opt in "$nonopt" ${1+"$@"}
+    do
+      if test -d "$opt"; then
+       func_append libdirs " $opt"
+
+      elif test -f "$opt"; then
+       if func_lalib_unsafe_p "$opt"; then
+         func_append libs " $opt"
+       else
+         func_warning "'$opt' is not a valid libtool archive"
+       fi
+
+      else
+       func_fatal_error "invalid argument '$opt'"
+      fi
+    done
+
+    if test -n "$libs"; then
+      if test -n "$lt_sysroot"; then
+        sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"`
+        sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;"
+      else
+        sysroot_cmd=
+      fi
+
+      # Remove sysroot references
+      if $opt_dry_run; then
+        for lib in $libs; do
+          echo "removing references to $lt_sysroot and '=' prefixes from $lib"
+        done
+      else
+        tmpdir=`func_mktempdir`
+        for lib in $libs; do
+         $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
+           > $tmpdir/tmp-la
+         mv -f $tmpdir/tmp-la $lib
+       done
+        ${RM}r "$tmpdir"
+      fi
+    fi
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      for libdir in $libdirs; do
+       if test -n "$finish_cmds"; then
+         # Do each command in the finish commands.
+         func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+       fi
+       if test -n "$finish_eval"; then
+         # Do the single finish_eval.
+         eval cmds=\"$finish_eval\"
+         $opt_dry_run || eval "$cmds" || func_append admincmds "
+       $cmds"
+       fi
+      done
+    fi
+
+    # Exit here if they wanted silent mode.
+    $opt_quiet && exit $EXIT_SUCCESS
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      echo "----------------------------------------------------------------------"
+      echo "Libraries have been installed in:"
+      for libdir in $libdirs; do
+       $ECHO "   $libdir"
+      done
+      echo
+      echo "If you ever happen to want to link against installed libraries"
+      echo "in a given directory, LIBDIR, you must either use libtool, and"
+      echo "specify the full pathname of the library, or use the '-LLIBDIR'"
+      echo "flag during linking and do at least one of the following:"
+      if test -n "$shlibpath_var"; then
+       echo "   - add LIBDIR to the '$shlibpath_var' environment variable"
+       echo "     during execution"
+      fi
+      if test -n "$runpath_var"; then
+       echo "   - add LIBDIR to the '$runpath_var' environment variable"
+       echo "     during linking"
+      fi
+      if test -n "$hardcode_libdir_flag_spec"; then
+       libdir=LIBDIR
+       eval flag=\"$hardcode_libdir_flag_spec\"
+
+       $ECHO "   - use the '$flag' linker flag"
+      fi
+      if test -n "$admincmds"; then
+       $ECHO "   - have your system administrator run these commands:$admincmds"
+      fi
+      if test -f /etc/ld.so.conf; then
+       echo "   - have your system administrator add LIBDIR to '/etc/ld.so.conf'"
+      fi
+      echo
+
+      echo "See any operating system documentation about shared libraries for"
+      case $host in
+       solaris2.[6789]|solaris2.1[0-9])
+         echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+         echo "pages."
+         ;;
+       *)
+         echo "more information, such as the ld(1) and ld.so(8) manual pages."
+         ;;
+      esac
+      echo "----------------------------------------------------------------------"
+    fi
+    exit $EXIT_SUCCESS
+}
+
+test finish = "$opt_mode" && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+    $debug_cmd
+
+    # There may be an optional sh(1) argument at the beginning of
+    # install_prog (especially on Windows NT).
+    if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" ||
+       # Allow the use of GNU shtool's install command.
+       case $nonopt in *shtool*) :;; *) false;; esac
+    then
+      # Aesthetically quote it.
+      func_quote_for_eval "$nonopt"
+      install_prog="$func_quote_for_eval_result "
+      arg=$1
+      shift
+    else
+      install_prog=
+      arg=$nonopt
+    fi
+
+    # The real first argument should be the name of the installation program.
+    # Aesthetically quote it.
+    func_quote_for_eval "$arg"
+    func_append install_prog "$func_quote_for_eval_result"
+    install_shared_prog=$install_prog
+    case " $install_prog " in
+      *[\\\ /]cp\ *) install_cp=: ;;
+      *) install_cp=false ;;
+    esac
+
+    # We need to accept at least all the BSD install flags.
+    dest=
+    files=
+    opts=
+    prev=
+    install_type=
+    isdir=false
+    stripme=
+    no_mode=:
+    for arg
+    do
+      arg2=
+      if test -n "$dest"; then
+       func_append files " $dest"
+       dest=$arg
+       continue
+      fi
+
+      case $arg in
+      -d) isdir=: ;;
+      -f)
+       if $install_cp; then :; else
+         prev=$arg
+       fi
+       ;;
+      -g | -m | -o)
+       prev=$arg
+       ;;
+      -s)
+       stripme=" -s"
+       continue
+       ;;
+      -*)
+       ;;
+      *)
+       # If the previous option needed an argument, then skip it.
+       if test -n "$prev"; then
+         if test X-m = "X$prev" && test -n "$install_override_mode"; then
+           arg2=$install_override_mode
+           no_mode=false
+         fi
+         prev=
+       else
+         dest=$arg
+         continue
+       fi
+       ;;
+      esac
+
+      # Aesthetically quote the argument.
+      func_quote_for_eval "$arg"
+      func_append install_prog " $func_quote_for_eval_result"
+      if test -n "$arg2"; then
+       func_quote_for_eval "$arg2"
+      fi
+      func_append install_shared_prog " $func_quote_for_eval_result"
+    done
+
+    test -z "$install_prog" && \
+      func_fatal_help "you must specify an install program"
+
+    test -n "$prev" && \
+      func_fatal_help "the '$prev' option requires an argument"
+
+    if test -n "$install_override_mode" && $no_mode; then
+      if $install_cp; then :; else
+       func_quote_for_eval "$install_override_mode"
+       func_append install_shared_prog " -m $func_quote_for_eval_result"
+      fi
+    fi
+
+    if test -z "$files"; then
+      if test -z "$dest"; then
+       func_fatal_help "no file or destination specified"
+      else
+       func_fatal_help "you must specify a destination"
+      fi
+    fi
+
+    # Strip any trailing slash from the destination.
+    func_stripname '' '/' "$dest"
+    dest=$func_stripname_result
+
+    # Check to see that the destination is a directory.
+    test -d "$dest" && isdir=:
+    if $isdir; then
+      destdir=$dest
+      destname=
+    else
+      func_dirname_and_basename "$dest" "" "."
+      destdir=$func_dirname_result
+      destname=$func_basename_result
+
+      # Not a directory, so check to see that there is only one file specified.
+      set dummy $files; shift
+      test "$#" -gt 1 && \
+       func_fatal_help "'$dest' is not a directory"
+    fi
+    case $destdir in
+    [\\/]* | [A-Za-z]:[\\/]*) ;;
+    *)
+      for file in $files; do
+       case $file in
+       *.lo) ;;
+       *)
+         func_fatal_help "'$destdir' must be an absolute directory name"
+         ;;
+       esac
+      done
+      ;;
+    esac
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic=$magic
+
+    staticlibs=
+    future_libdirs=
+    current_libdirs=
+    for file in $files; do
+
+      # Do each installation.
+      case $file in
+      *.$libext)
+       # Do the static libraries later.
+       func_append staticlibs " $file"
+       ;;
+
+      *.la)
+       func_resolve_sysroot "$file"
+       file=$func_resolve_sysroot_result
+
+       # Check to see that this really is a libtool archive.
+       func_lalib_unsafe_p "$file" \
+         || func_fatal_help "'$file' is not a valid libtool archive"
+
+       library_names=
+       old_library=
+       relink_command=
+       func_source "$file"
+
+       # Add the libdir to current_libdirs if it is the destination.
+       if test "X$destdir" = "X$libdir"; then
+         case "$current_libdirs " in
+         *" $libdir "*) ;;
+         *) func_append current_libdirs " $libdir" ;;
+         esac
+       else
+         # Note the libdir as a future libdir.
+         case "$future_libdirs " in
+         *" $libdir "*) ;;
+         *) func_append future_libdirs " $libdir" ;;
+         esac
+       fi
+
+       func_dirname "$file" "/" ""
+       dir=$func_dirname_result
+       func_append dir "$objdir"
+
+       if test -n "$relink_command"; then
+         # Determine the prefix the user has applied to our future dir.
+         inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
+
+         # Don't allow the user to place us outside of our expected
+         # location b/c this prevents finding dependent libraries that
+         # are installed to the same prefix.
+         # At present, this check doesn't affect windows .dll's that
+         # are installed into $libdir/../bin (currently, that works fine)
+         # but it's something to keep an eye on.
+         test "$inst_prefix_dir" = "$destdir" && \
+           func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir"
+
+         if test -n "$inst_prefix_dir"; then
+           # Stick the inst_prefix_dir data into the link command.
+           relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+         else
+           relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+         fi
+
+         func_warning "relinking '$file'"
+         func_show_eval "$relink_command" \
+           'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"'
+       fi
+
+       # See the names of the shared library.
+       set dummy $library_names; shift
+       if test -n "$1"; then
+         realname=$1
+         shift
+
+         srcname=$realname
+         test -n "$relink_command" && srcname=${realname}T
+
+         # Install the shared library and build the symlinks.
+         func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
+             'exit $?'
+         tstripme=$stripme
+         case $host_os in
+         cygwin* | mingw* | pw32* | cegcc*)
+           case $realname in
+           *.dll.a)
+             tstripme=
+             ;;
+           esac
+           ;;
+         os2*)
+           case $realname in
+           *_dll.a)
+             tstripme=
+             ;;
+           esac
+           ;;
+         esac
+         if test -n "$tstripme" && test -n "$striplib"; then
+           func_show_eval "$striplib $destdir/$realname" 'exit $?'
+         fi
+
+         if test "$#" -gt 0; then
+           # Delete the old symlinks, and create new ones.
+           # Try 'ln -sf' first, because the 'ln' binary might depend on
+           # the symlink we replace!  Solaris /bin/ln does not understand -f,
+           # so we also need to try rm && ln -s.
+           for linkname
+           do
+             test "$linkname" != "$realname" \
+               && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+           done
+         fi
+
+         # Do each command in the postinstall commands.
+         lib=$destdir/$realname
+         func_execute_cmds "$postinstall_cmds" 'exit $?'
+       fi
+
+       # Install the pseudo-library for information purposes.
+       func_basename "$file"
+       name=$func_basename_result
+       instname=$dir/${name}i
+       func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+       # Maybe install the static library, too.
+       test -n "$old_library" && func_append staticlibs " $dir/$old_library"
+       ;;
+
+      *.lo)
+       # Install (i.e. copy) a libtool object.
+
+       # Figure out destination file name, if it wasn't already specified.
+       if test -n "$destname"; then
+         destfile=$destdir/$destname
+       else
+         func_basename "$file"
+         destfile=$func_basename_result
+         destfile=$destdir/$destfile
+       fi
+
+       # Deduce the name of the destination old-style object file.
+       case $destfile in
+       *.lo)
+         func_lo2o "$destfile"
+         staticdest=$func_lo2o_result
+         ;;
+       *.$objext)
+         staticdest=$destfile
+         destfile=
+         ;;
+       *)
+         func_fatal_help "cannot copy a libtool object to '$destfile'"
+         ;;
+       esac
+
+       # Install the libtool object if requested.
+       test -n "$destfile" && \
+         func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+       # Install the old object if enabled.
+       if test yes = "$build_old_libs"; then
+         # Deduce the name of the old-style object file.
+         func_lo2o "$file"
+         staticobj=$func_lo2o_result
+         func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+       fi
+       exit $EXIT_SUCCESS
+       ;;
+
+      *)
+       # Figure out destination file name, if it wasn't already specified.
+       if test -n "$destname"; then
+         destfile=$destdir/$destname
+       else
+         func_basename "$file"
+         destfile=$func_basename_result
+         destfile=$destdir/$destfile
+       fi
+
+       # If the file is missing, and there is a .exe on the end, strip it
+       # because it is most likely a libtool script we actually want to
+       # install
+       stripped_ext=
+       case $file in
+         *.exe)
+           if test ! -f "$file"; then
+             func_stripname '' '.exe' "$file"
+             file=$func_stripname_result
+             stripped_ext=.exe
+           fi
+           ;;
+       esac
+
+       # Do a test to see if this is really a libtool program.
+       case $host in
+       *cygwin* | *mingw*)
+           if func_ltwrapper_executable_p "$file"; then
+             func_ltwrapper_scriptname "$file"
+             wrapper=$func_ltwrapper_scriptname_result
+           else
+             func_stripname '' '.exe' "$file"
+             wrapper=$func_stripname_result
+           fi
+           ;;
+       *)
+           wrapper=$file
+           ;;
+       esac
+       if func_ltwrapper_script_p "$wrapper"; then
+         notinst_deplibs=
+         relink_command=
+
+         func_source "$wrapper"
+
+         # Check the variables that should have been set.
+         test -z "$generated_by_libtool_version" && \
+           func_fatal_error "invalid libtool wrapper script '$wrapper'"
+
+         finalize=:
+         for lib in $notinst_deplibs; do
+           # Check to see that each library is installed.
+           libdir=
+           if test -f "$lib"; then
+             func_source "$lib"
+           fi
+           libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'`
+           if test -n "$libdir" && test ! -f "$libfile"; then
+             func_warning "'$lib' has not been installed in '$libdir'"
+             finalize=false
+           fi
+         done
+
+         relink_command=
+         func_source "$wrapper"
+
+         outputname=
+         if test no = "$fast_install" && test -n "$relink_command"; then
+           $opt_dry_run || {
+             if $finalize; then
+               tmpdir=`func_mktempdir`
+               func_basename "$file$stripped_ext"
+               file=$func_basename_result
+               outputname=$tmpdir/$file
+               # Replace the output file specification.
+               relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
+
+               $opt_quiet || {
+                 func_quote_for_expand "$relink_command"
+                 eval "func_echo $func_quote_for_expand_result"
+               }
+               if eval "$relink_command"; then :
+                 else
+                 func_error "error: relink '$file' with the above command before installing it"
+                 $opt_dry_run || ${RM}r "$tmpdir"
+                 continue
+               fi
+               file=$outputname
+             else
+               func_warning "cannot relink '$file'"
+             fi
+           }
+         else
+           # Install the binary that we compiled earlier.
+           file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
+         fi
+       fi
+
+       # remove .exe since cygwin /usr/bin/install will append another
+       # one anyway
+       case $install_prog,$host in
+       */usr/bin/install*,*cygwin*)
+         case $file:$destfile in
+         *.exe:*.exe)
+           # this is ok
+           ;;
+         *.exe:*)
+           destfile=$destfile.exe
+           ;;
+         *:*.exe)
+           func_stripname '' '.exe' "$destfile"
+           destfile=$func_stripname_result
+           ;;
+         esac
+         ;;
+       esac
+       func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+       $opt_dry_run || if test -n "$outputname"; then
+         ${RM}r "$tmpdir"
+       fi
+       ;;
+      esac
+    done
+
+    for file in $staticlibs; do
+      func_basename "$file"
+      name=$func_basename_result
+
+      # Set up the ranlib parameters.
+      oldlib=$destdir/$name
+      func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+      tool_oldlib=$func_to_tool_file_result
+
+      func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+      if test -n "$stripme" && test -n "$old_striplib"; then
+       func_show_eval "$old_striplib $tool_oldlib" 'exit $?'
+      fi
+
+      # Do each command in the postinstall commands.
+      func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+    done
+
+    test -n "$future_libdirs" && \
+      func_warning "remember to run '$progname --finish$future_libdirs'"
+
+    if test -n "$current_libdirs"; then
+      # Maybe just do a dry run.
+      $opt_dry_run && current_libdirs=" -n$current_libdirs"
+      exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs'
+    else
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test install = "$opt_mode" && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+    $debug_cmd
+
+    my_outputname=$1
+    my_originator=$2
+    my_pic_p=${3-false}
+    my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'`
+    my_dlsyms=
+
+    if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+      if test -n "$NM" && test -n "$global_symbol_pipe"; then
+       my_dlsyms=${my_outputname}S.c
+      else
+       func_error "not configured to extract global symbols from dlpreopened files"
+      fi
+    fi
+
+    if test -n "$my_dlsyms"; then
+      case $my_dlsyms in
+      "") ;;
+      *.c)
+       # Discover the nlist of each of the dlfiles.
+       nlist=$output_objdir/$my_outputname.nm
+
+       func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+       # Parse the name list into a source file.
+       func_verbose "creating $output_objdir/$my_dlsyms"
+
+       $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+#if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT_DLSYM_CONST
+#elif defined __osf__
+/* This system does not cope well with relocations in const data.  */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
+
+/* External symbol declarations for the compiler. */\
+"
+
+       if test yes = "$dlself"; then
+         func_verbose "generating symbol list for '$output'"
+
+         $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+         # Add our own program objects to the symbol list.
+         progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+         for progfile in $progfiles; do
+           func_to_tool_file "$progfile" func_convert_file_msys_to_w32
+           func_verbose "extracting global C symbols from '$func_to_tool_file_result'"
+           $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
+         done
+
+         if test -n "$exclude_expsyms"; then
+           $opt_dry_run || {
+             eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+             eval '$MV "$nlist"T "$nlist"'
+           }
+         fi
+
+         if test -n "$export_symbols_regex"; then
+           $opt_dry_run || {
+             eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+             eval '$MV "$nlist"T "$nlist"'
+           }
+         fi
+
+         # Prepare the list of exported symbols
+         if test -z "$export_symbols"; then
+           export_symbols=$output_objdir/$outputname.exp
+           $opt_dry_run || {
+             $RM $export_symbols
+             eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+             case $host in
+             *cygwin* | *mingw* | *cegcc* )
+                eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+                eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+               ;;
+             esac
+           }
+         else
+           $opt_dry_run || {
+             eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+             eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+             eval '$MV "$nlist"T "$nlist"'
+             case $host in
+               *cygwin* | *mingw* | *cegcc* )
+                 eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+                 eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+                 ;;
+             esac
+           }
+         fi
+       fi
+
+       for dlprefile in $dlprefiles; do
+         func_verbose "extracting global C symbols from '$dlprefile'"
+         func_basename "$dlprefile"
+         name=$func_basename_result
+          case $host in
+           *cygwin* | *mingw* | *cegcc* )
+             # if an import library, we need to obtain dlname
+             if func_win32_import_lib_p "$dlprefile"; then
+               func_tr_sh "$dlprefile"
+               eval "curr_lafile=\$libfile_$func_tr_sh_result"
+               dlprefile_dlbasename=
+               if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
+                 # Use subshell, to avoid clobbering current variable values
+                 dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
+                 if test -n "$dlprefile_dlname"; then
+                   func_basename "$dlprefile_dlname"
+                   dlprefile_dlbasename=$func_basename_result
+                 else
+                   # no lafile. user explicitly requested -dlpreopen <import library>.
+                   $sharedlib_from_linklib_cmd "$dlprefile"
+                   dlprefile_dlbasename=$sharedlib_from_linklib_result
+                 fi
+               fi
+               $opt_dry_run || {
+                 if test -n "$dlprefile_dlbasename"; then
+                   eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
+                 else
+                   func_warning "Could not compute DLL name from $name"
+                   eval '$ECHO ": $name " >> "$nlist"'
+                 fi
+                 func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+                 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe |
+                   $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'"
+               }
+             else # not an import lib
+               $opt_dry_run || {
+                 eval '$ECHO ": $name " >> "$nlist"'
+                 func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+                 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+               }
+             fi
+           ;;
+           *)
+             $opt_dry_run || {
+               eval '$ECHO ": $name " >> "$nlist"'
+               func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+               eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+             }
+           ;;
+          esac
+       done
+
+       $opt_dry_run || {
+         # Make sure we have at least an empty file.
+         test -f "$nlist" || : > "$nlist"
+
+         if test -n "$exclude_expsyms"; then
+           $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+           $MV "$nlist"T "$nlist"
+         fi
+
+         # Try sorting and uniquifying the output.
+         if $GREP -v "^: " < "$nlist" |
+             if sort -k 3 </dev/null >/dev/null 2>&1; then
+               sort -k 3
+             else
+               sort +2
+             fi |
+             uniq > "$nlist"S; then
+           :
+         else
+           $GREP -v "^: " < "$nlist" > "$nlist"S
+         fi
+
+         if test -f "$nlist"S; then
+           eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+         else
+           echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
+         fi
+
+         func_show_eval '$RM "${nlist}I"'
+         if test -n "$global_symbol_to_import"; then
+           eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I'
+         fi
+
+         echo >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols.  */
+typedef struct {
+  const char *name;
+  void *address;
+} lt_dlsymlist;
+extern LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];\
+"
+
+         if test -s "$nlist"I; then
+           echo >> "$output_objdir/$my_dlsyms" "\
+static void lt_syminit(void)
+{
+  LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols;
+  for (; symbol->name; ++symbol)
+    {"
+           $SED 's/.*/      if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms"
+           echo >> "$output_objdir/$my_dlsyms" "\
+    }
+}"
+         fi
+         echo >> "$output_objdir/$my_dlsyms" "\
+LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{ {\"$my_originator\", (void *) 0},"
+
+         if test -s "$nlist"I; then
+           echo >> "$output_objdir/$my_dlsyms" "\
+  {\"@INIT@\", (void *) &lt_syminit},"
+         fi
+
+         case $need_lib_prefix in
+         no)
+           eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+           ;;
+         *)
+           eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+           ;;
+         esac
+         echo >> "$output_objdir/$my_dlsyms" "\
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+       } # !$opt_dry_run
+
+       pic_flag_for_symtable=
+       case "$compile_command " in
+       *" -static "*) ;;
+       *)
+         case $host in
+         # compiling the symbol table file with pic_flag works around
+         # a FreeBSD bug that causes programs to crash when -lm is
+         # linked before any other PIC object.  But we must not use
+         # pic_flag when linking with -static.  The problem exists in
+         # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+         *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+           pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+         *-*-hpux*)
+           pic_flag_for_symtable=" $pic_flag"  ;;
+         *)
+           $my_pic_p && pic_flag_for_symtable=" $pic_flag"
+           ;;
+         esac
+         ;;
+       esac
+       symtab_cflags=
+       for arg in $LTCFLAGS; do
+         case $arg in
+         -pie | -fpie | -fPIE) ;;
+         *) func_append symtab_cflags " $arg" ;;
+         esac
+       done
+
+       # Now compile the dynamic symbol file.
+       func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+       # Clean up the generated files.
+       func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"'
+
+       # Transform the symbol file into the correct name.
+       symfileobj=$output_objdir/${my_outputname}S.$objext
+       case $host in
+       *cygwin* | *mingw* | *cegcc* )
+         if test -f "$output_objdir/$my_outputname.def"; then
+           compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+           finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+         else
+           compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+           finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+         fi
+         ;;
+       *)
+         compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+         finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+         ;;
+       esac
+       ;;
+      *)
+       func_fatal_error "unknown suffix for '$my_dlsyms'"
+       ;;
+      esac
+    else
+      # We keep going just in case the user didn't refer to
+      # lt_preloaded_symbols.  The linker will fail if global_symbol_pipe
+      # really was required.
+
+      # Nullify the symbol file.
+      compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+      finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
+    fi
+}
+
+# func_cygming_gnu_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is a GNU/binutils-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_gnu_implib_p ()
+{
+  $debug_cmd
+
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
+  test -n "$func_cygming_gnu_implib_tmp"
+}
+
+# func_cygming_ms_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is an MS-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_ms_implib_p ()
+{
+  $debug_cmd
+
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
+  test -n "$func_cygming_ms_implib_tmp"
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
+func_win32_libid ()
+{
+  $debug_cmd
+
+  win32_libid_type=unknown
+  win32_fileres=`file -L $1 2>/dev/null`
+  case $win32_fileres in
+  *ar\ archive\ import\ library*) # definitely import
+    win32_libid_type="x86 archive import"
+    ;;
+  *ar\ archive*) # could be an import, or static
+    # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
+    if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+       $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+      case $nm_interface in
+      "MS dumpbin")
+       if func_cygming_ms_implib_p "$1" ||
+          func_cygming_gnu_implib_p "$1"
+       then
+         win32_nmres=import
+       else
+         win32_nmres=
+       fi
+       ;;
+      *)
+       func_to_tool_file "$1" func_convert_file_msys_to_w32
+       win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
+         $SED -n -e '
+           1,100{
+               / I /{
+                   s|.*|import|
+                   p
+                   q
+               }
+           }'`
+       ;;
+      esac
+      case $win32_nmres in
+      import*)  win32_libid_type="x86 archive import";;
+      *)        win32_libid_type="x86 archive static";;
+      esac
+    fi
+    ;;
+  *DLL*)
+    win32_libid_type="x86 DLL"
+    ;;
+  *executable*) # but shell scripts are "executable" too...
+    case $win32_fileres in
+    *MS\ Windows\ PE\ Intel*)
+      win32_libid_type="x86 DLL"
+      ;;
+    esac
+    ;;
+  esac
+  $ECHO "$win32_libid_type"
+}
+
+# func_cygming_dll_for_implib ARG
+#
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib ()
+{
+  $debug_cmd
+
+  sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
+}
+
+# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs
+#
+# The is the core of a fallback implementation of a
+# platform-specific function to extract the name of the
+# DLL associated with the specified import library LIBNAME.
+#
+# SECTION_NAME is either .idata$6 or .idata$7, depending
+# on the platform and compiler that created the implib.
+#
+# Echos the name of the DLL associated with the
+# specified import library.
+func_cygming_dll_for_implib_fallback_core ()
+{
+  $debug_cmd
+
+  match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"`
+  $OBJDUMP -s --section "$1" "$2" 2>/dev/null |
+    $SED '/^Contents of section '"$match_literal"':/{
+      # Place marker at beginning of archive member dllname section
+      s/.*/====MARK====/
+      p
+      d
+    }
+    # These lines can sometimes be longer than 43 characters, but
+    # are always uninteresting
+    /:[         ]*file format pe[i]\{,1\}-/d
+    /^In archive [^:]*:/d
+    # Ensure marker is printed
+    /^====MARK====/p
+    # Remove all lines with less than 43 characters
+    /^.\{43\}/!d
+    # From remaining lines, remove first 43 characters
+    s/^.\{43\}//' |
+    $SED -n '
+      # Join marker and all lines until next marker into a single line
+      /^====MARK====/ b para
+      H
+      $ b para
+      b
+      :para
+      x
+      s/\n//g
+      # Remove the marker
+      s/^====MARK====//
+      # Remove trailing dots and whitespace
+      s/[\. \t]*$//
+      # Print
+      /./p' |
+    # we now have a list, one entry per line, of the stringified
+    # contents of the appropriate section of all members of the
+    # archive that possess that section. Heuristic: eliminate
+    # all those that have a first or second character that is
+    # a '.' (that is, objdump's representation of an unprintable
+    # character.) This should work for all archives with less than
+    # 0x302f exports -- but will fail for DLLs whose name actually
+    # begins with a literal '.' or a single character followed by
+    # a '.'.
+    #
+    # Of those that remain, print the first one.
+    $SED -e '/^\./d;/^.\./d;q'
+}
+
+# func_cygming_dll_for_implib_fallback ARG
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+#
+# This fallback implementation is for use when $DLLTOOL
+# does not support the --identify-strict option.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib_fallback ()
+{
+  $debug_cmd
+
+  if func_cygming_gnu_implib_p "$1"; then
+    # binutils import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
+  elif func_cygming_ms_implib_p "$1"; then
+    # ms-generated import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
+  else
+    # unknown
+    sharedlib_from_linklib_result=
+  fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+    $debug_cmd
+
+    f_ex_an_ar_dir=$1; shift
+    f_ex_an_ar_oldlib=$1
+    if test yes = "$lock_old_archive_extraction"; then
+      lockfile=$f_ex_an_ar_oldlib.lock
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+       func_echo "Waiting for $lockfile to be removed"
+       sleep 2
+      done
+    fi
+    func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+                  'stat=$?; rm -f "$lockfile"; exit $stat'
+    if test yes = "$lock_old_archive_extraction"; then
+      $opt_dry_run || rm -f "$lockfile"
+    fi
+    if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+     :
+    else
+      func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+    fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+    $debug_cmd
+
+    my_gentop=$1; shift
+    my_oldlibs=${1+"$@"}
+    my_oldobjs=
+    my_xlib=
+    my_xabs=
+    my_xdir=
+
+    for my_xlib in $my_oldlibs; do
+      # Extract the objects.
+      case $my_xlib in
+       [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;;
+       *) my_xabs=`pwd`"/$my_xlib" ;;
+      esac
+      func_basename "$my_xlib"
+      my_xlib=$func_basename_result
+      my_xlib_u=$my_xlib
+      while :; do
+        case " $extracted_archives " in
+       *" $my_xlib_u "*)
+         func_arith $extracted_serial + 1
+         extracted_serial=$func_arith_result
+         my_xlib_u=lt$extracted_serial-$my_xlib ;;
+       *) break ;;
+       esac
+      done
+      extracted_archives="$extracted_archives $my_xlib_u"
+      my_xdir=$my_gentop/$my_xlib_u
+
+      func_mkdir_p "$my_xdir"
+
+      case $host in
+      *-darwin*)
+       func_verbose "Extracting $my_xabs"
+       # Do not bother doing anything if just a dry run
+       $opt_dry_run || {
+         darwin_orig_dir=`pwd`
+         cd $my_xdir || exit $?
+         darwin_archive=$my_xabs
+         darwin_curdir=`pwd`
+         func_basename "$darwin_archive"
+         darwin_base_archive=$func_basename_result
+         darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+         if test -n "$darwin_arches"; then
+           darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+           darwin_arch=
+           func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+           for darwin_arch in  $darwin_arches; do
+             func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch"
+             $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive"
+             cd "unfat-$$/$darwin_base_archive-$darwin_arch"
+             func_extract_an_archive "`pwd`" "$darwin_base_archive"
+             cd "$darwin_curdir"
+             $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive"
+           done # $darwin_arches
+            ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+           darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u`
+           darwin_file=
+           darwin_files=
+           for darwin_file in $darwin_filelist; do
+             darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
+             $LIPO -create -output "$darwin_file" $darwin_files
+           done # $darwin_filelist
+           $RM -rf unfat-$$
+           cd "$darwin_orig_dir"
+         else
+           cd $darwin_orig_dir
+           func_extract_an_archive "$my_xdir" "$my_xabs"
+         fi # $darwin_arches
+       } # !$opt_dry_run
+       ;;
+      *)
+        func_extract_an_archive "$my_xdir" "$my_xabs"
+       ;;
+      esac
+      my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
+    done
+
+    func_extract_archives_result=$my_oldobjs
+}
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable.  Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take.  If 'yes', then the emitted script
+# will assume that the directory where it is stored is
+# the $objdir directory.  This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+       func_emit_wrapper_arg1=${1-no}
+
+       $ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+  # install mode needs the following variables:
+  generated_by_libtool_version='$macro_version'
+  notinst_deplibs='$notinst_deplibs'
+else
+  # When we are sourced in execute mode, \$file and \$ECHO are already set.
+  if test \"\$libtool_execute_magic\" != \"$magic\"; then
+    file=\"\$0\""
+
+    qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+    $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+    ECHO=\"$qECHO\"
+  fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ that is used only on
+# windows platforms, and (c) all begin with the string "--lt-"
+# (application programs are unlikely to have options that match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's $0 value, followed by "$@".
+lt_option_debug=
+func_parse_lt_options ()
+{
+  lt_script_arg0=\$0
+  shift
+  for lt_opt
+  do
+    case \"\$lt_opt\" in
+    --lt-debug) lt_option_debug=1 ;;
+    --lt-dump-script)
+        lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
+        test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
+        lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
+        cat \"\$lt_dump_D/\$lt_dump_F\"
+        exit 0
+      ;;
+    --lt-*)
+        \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
+        exit 1
+      ;;
+    esac
+  done
+
+  # Print the debug banner immediately:
+  if test -n \"\$lt_option_debug\"; then
+    echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2
+  fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+  lt_dump_args_N=1;
+  for lt_arg
+  do
+    \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\"
+    lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
+  done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+"
+  case $host in
+  # Backslashes separate directories on plain windows
+  *-*-mingw | *-*-os2* | *-cegcc*)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+    ;;
+
+  *)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+    ;;
+  esac
+  $ECHO "\
+      \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+      exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from \$@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+  case \" \$* \" in
+  *\\ --lt-*)
+    for lt_wr_arg
+    do
+      case \$lt_wr_arg in
+      --lt-*) ;;
+      *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
+      esac
+      shift
+    done ;;
+  esac
+  func_exec_program_core \${1+\"\$@\"}
+}
+
+  # Parse options
+  func_parse_lt_options \"\$0\" \${1+\"\$@\"}
+
+  # Find the directory that this script lives in.
+  thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
+  test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
+  while test -n \"\$file\"; do
+    destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
+
+    # If there was a directory component, then change thisdir.
+    if test \"x\$destdir\" != \"x\$file\"; then
+      case \"\$destdir\" in
+      [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+      *) thisdir=\"\$thisdir/\$destdir\" ;;
+      esac
+    fi
+
+    file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+  done
+
+  # Usually 'no', except on cygwin/mingw when embedded into
+  # the cwrapper.
+  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
+  if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+    # special case for '.'
+    if test \"\$thisdir\" = \".\"; then
+      thisdir=\`pwd\`
+    fi
+    # remove .libs from thisdir
+    case \"\$thisdir\" in
+    *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
+    $objdir )   thisdir=. ;;
+    esac
+  fi
+
+  # Try to get the absolute directory name.
+  absdir=\`cd \"\$thisdir\" && pwd\`
+  test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+       if test yes = "$fast_install"; then
+         $ECHO "\
+  program=lt-'$outputname'$exeext
+  progdir=\"\$thisdir/$objdir\"
+
+  if test ! -f \"\$progdir/\$program\" ||
+     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\
+       test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+    file=\"\$\$-\$program\"
+
+    if test ! -d \"\$progdir\"; then
+      $MKDIR \"\$progdir\"
+    else
+      $RM \"\$progdir/\$file\"
+    fi"
+
+         $ECHO "\
+
+    # relink executable if necessary
+    if test -n \"\$relink_command\"; then
+      if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+      else
+       \$ECHO \"\$relink_command_output\" >&2
+       $RM \"\$progdir/\$file\"
+       exit 1
+      fi
+    fi
+
+    $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+    { $RM \"\$progdir/\$program\";
+      $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+    $RM \"\$progdir/\$file\"
+  fi"
+       else
+         $ECHO "\
+  program='$outputname'
+  progdir=\"\$thisdir/$objdir\"
+"
+       fi
+
+       $ECHO "\
+
+  if test -f \"\$progdir/\$program\"; then"
+
+       # fixup the dll searchpath if we need to.
+       #
+       # Fix the DLL searchpath if we need to.  Do this before prepending
+       # to shlibpath, because on Windows, both are PATH and uninstalled
+       # libraries must come first.
+       if test -n "$dllsearchpath"; then
+         $ECHO "\
+    # Add the dll search path components to the executable PATH
+    PATH=$dllsearchpath:\$PATH
+"
+       fi
+
+       # Export our shlibpath_var if we have one.
+       if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+         $ECHO "\
+    # Add our own library path to $shlibpath_var
+    $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+    # Some systems cannot cope with colon-terminated $shlibpath_var
+    # The second colon is a workaround for a bug in BeOS R4 sed
+    $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
+
+    export $shlibpath_var
+"
+       fi
+
+       $ECHO "\
+    if test \"\$libtool_execute_magic\" != \"$magic\"; then
+      # Run the actual program with our arguments.
+      func_exec_program \${1+\"\$@\"}
+    fi
+  else
+    # The program doesn't exist.
+    \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2
+    \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+    \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+    exit 1
+  fi
+fi\
+"
+}
+
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+       cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+   Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+
+   The $output program cannot be directly executed until all the libtool
+   libraries that it depends on are installed.
+
+   This wrapper executable should never be moved out of the build directory.
+   If it is, it will not operate correctly.
+*/
+EOF
+           cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+#  include <io.h>
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
+
+/* declarations of non-ANSI functions */
+#if defined __MINGW32__
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined __CYGWIN__
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined other_platform || defined ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined _MSC_VER
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+# define S_IXUSR _S_IEXEC
+#elif defined __MINGW32__
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+#elif defined __CYGWIN__
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined other platforms ... */
+#endif
+
+#if defined PATH_MAX
+# define LT_PATHMAX PATH_MAX
+#elif defined MAXPATHLEN
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+/* path handling portability macros */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \
+  defined __OS2__
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+#  define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+#  define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+       (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num)      ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+  if (stale) { free (stale); stale = 0; } \
+} while (0)
+
+#if defined LT_DEBUGWRAPPER
+static int lt_debug = 1;
+#else
+static int lt_debug = 0;
+#endif
+
+const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_debugprintf (const char *file, int line, const char *fmt, ...);
+void lt_fatal (const char *file, int line, const char *message, ...);
+static const char *nonnull (const char *s);
+static const char *nonempty (const char *s);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+EOF
+
+           cat <<EOF
+#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
+# define externally_visible volatile
+#else
+# define externally_visible __attribute__((externally_visible)) volatile
+#endif
+externally_visible const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+           if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+              func_to_host_path "$temp_rpath"
+             cat <<EOF
+const char * LIB_PATH_VALUE   = "$func_to_host_path_result";
+EOF
+           else
+             cat <<"EOF"
+const char * LIB_PATH_VALUE   = "";
+EOF
+           fi
+
+           if test -n "$dllsearchpath"; then
+              func_to_host_path "$dllsearchpath:"
+             cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE   = "$func_to_host_path_result";
+EOF
+           else
+             cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE   = "";
+EOF
+           fi
+
+           if test yes = "$fast_install"; then
+             cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+           else
+             cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+           fi
+
+
+           cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX         "--lt-"
+
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+static const char *dumpscript_opt       = LTWRAPPER_OPTION_PREFIX "dump-script";
+static const char *debug_opt            = LTWRAPPER_OPTION_PREFIX "debug";
+
+int
+main (int argc, char *argv[])
+{
+  char **newargz;
+  int  newargc;
+  char *tmp_pathspec;
+  char *actual_cwrapper_path;
+  char *actual_cwrapper_name;
+  char *target_name;
+  char *lt_argv_zero;
+  int rval = 127;
+
+  int i;
+
+  program_name = (char *) xstrdup (base_name (argv[0]));
+  newargz = XMALLOC (char *, (size_t) argc + 1);
+
+  /* very simple arg parsing; don't want to rely on getopt
+   * also, copy all non cwrapper options to newargz, except
+   * argz[0], which is handled differently
+   */
+  newargc=0;
+  for (i = 1; i < argc; i++)
+    {
+      if (STREQ (argv[i], dumpscript_opt))
+       {
+EOF
+           case $host in
+             *mingw* | *cygwin* )
+               # make stdout use "unix" line endings
+               echo "          setmode(1,_O_BINARY);"
+               ;;
+             esac
+
+           cat <<"EOF"
+         lt_dump_script (stdout);
+         return 0;
+       }
+      if (STREQ (argv[i], debug_opt))
+       {
+          lt_debug = 1;
+          continue;
+       }
+      if (STREQ (argv[i], ltwrapper_option_prefix))
+        {
+          /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+             namespace, but it is not one of the ones we know about and
+             have already dealt with, above (inluding dump-script), then
+             report an error. Otherwise, targets might begin to believe
+             they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+             namespace. The first time any user complains about this, we'll
+             need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+             or a configure.ac-settable value.
+           */
+          lt_fatal (__FILE__, __LINE__,
+                   "unrecognized %s option: '%s'",
+                    ltwrapper_option_prefix, argv[i]);
+        }
+      /* otherwise ... */
+      newargz[++newargc] = xstrdup (argv[i]);
+    }
+  newargz[++newargc] = NULL;
+
+EOF
+           cat <<EOF
+  /* The GNU banner must be the first non-error debug message */
+  lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE) $VERSION\n");
+EOF
+           cat <<"EOF"
+  lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name);
+
+  tmp_pathspec = find_executable (argv[0]);
+  if (tmp_pathspec == NULL)
+    lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (before symlink chase) at: %s\n",
+                 tmp_pathspec);
+
+  actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (after symlink chase) at: %s\n",
+                 actual_cwrapper_path);
+  XFREE (tmp_pathspec);
+
+  actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path));
+  strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+  /* wrapper name transforms */
+  strendzap (actual_cwrapper_name, ".exe");
+  tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+  XFREE (actual_cwrapper_name);
+  actual_cwrapper_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  /* target_name transforms -- use actual target program name; might have lt- prefix */
+  target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+  strendzap (target_name, ".exe");
+  tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+  XFREE (target_name);
+  target_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  lt_debugprintf (__FILE__, __LINE__,
+                 "(main) libtool target name: %s\n",
+                 target_name);
+EOF
+
+           cat <<EOF
+  newargz[0] =
+    XMALLOC (char, (strlen (actual_cwrapper_path) +
+                   strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+  strcpy (newargz[0], actual_cwrapper_path);
+  strcat (newargz[0], "$objdir");
+  strcat (newargz[0], "/");
+EOF
+
+           cat <<"EOF"
+  /* stop here, and copy so we don't have to do this twice */
+  tmp_pathspec = xstrdup (newargz[0]);
+
+  /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+  strcat (newargz[0], actual_cwrapper_name);
+
+  /* DO want the lt- prefix here if it exists, so use target_name */
+  lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+  XFREE (tmp_pathspec);
+  tmp_pathspec = NULL;
+EOF
+
+           case $host_os in
+             mingw*)
+           cat <<"EOF"
+  {
+    char* p;
+    while ((p = strchr (newargz[0], '\\')) != NULL)
+      {
+       *p = '/';
+      }
+    while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+      {
+       *p = '/';
+      }
+  }
+EOF
+           ;;
+           esac
+
+           cat <<"EOF"
+  XFREE (target_name);
+  XFREE (actual_cwrapper_path);
+  XFREE (actual_cwrapper_name);
+
+  lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+  lt_setenv ("DUALCASE", "1");  /* for MSK sh */
+  /* Update the DLL searchpath.  EXE_PATH_VALUE ($dllsearchpath) must
+     be prepended before (that is, appear after) LIB_PATH_VALUE ($temp_rpath)
+     because on Windows, both *_VARNAMEs are PATH but uninstalled
+     libraries must come first. */
+  lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+  lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+
+  lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n",
+                 nonnull (lt_argv_zero));
+  for (i = 0; i < newargc; i++)
+    {
+      lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n",
+                     i, nonnull (newargz[i]));
+    }
+
+EOF
+
+           case $host_os in
+             mingw*)
+               cat <<"EOF"
+  /* execv doesn't actually work on mingw as expected on unix */
+  newargz = prepare_spawn (newargz);
+  rval = (int) _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+  if (rval == -1)
+    {
+      /* failed to start process */
+      lt_debugprintf (__FILE__, __LINE__,
+                     "(main) failed to launch target \"%s\": %s\n",
+                     lt_argv_zero, nonnull (strerror (errno)));
+      return 127;
+    }
+  return rval;
+EOF
+               ;;
+             *)
+               cat <<"EOF"
+  execv (lt_argv_zero, newargz);
+  return rval; /* =127, but avoids unused variable warning */
+EOF
+               ;;
+           esac
+
+           cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+  void *p = (void *) malloc (num);
+  if (!p)
+    lt_fatal (__FILE__, __LINE__, "memory exhausted");
+
+  return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+  return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+                         string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+  const char *base;
+
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+  /* Skip over the disk name in MSDOS pathnames. */
+  if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+    name += 2;
+#endif
+
+  for (base = name; *name; name++)
+    if (IS_DIR_SEPARATOR (*name))
+      base = name + 1;
+  return base;
+}
+
+int
+check_executable (const char *path)
+{
+  struct stat st;
+
+  lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n",
+                  nonempty (path));
+  if ((!path) || (!*path))
+    return 0;
+
+  if ((stat (path, &st) >= 0)
+      && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+    return 1;
+  else
+    return 0;
+}
+
+int
+make_executable (const char *path)
+{
+  int rval = 0;
+  struct stat st;
+
+  lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
+                  nonempty (path));
+  if ((!path) || (!*path))
+    return 0;
+
+  if (stat (path, &st) >= 0)
+    {
+      rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+    }
+  return rval;
+}
+
+/* Searches for the full path of the wrapper.  Returns
+   newly allocated full path name if found, NULL otherwise
+   Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+  int has_slash = 0;
+  const char *p;
+  const char *p_next;
+  /* static buffer for getcwd */
+  char tmp[LT_PATHMAX + 1];
+  size_t tmp_len;
+  char *concat_name;
+
+  lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
+                  nonempty (wrapper));
+
+  if ((wrapper == NULL) || (*wrapper == '\0'))
+    return NULL;
+
+  /* Absolute path? */
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+  if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+    {
+      concat_name = xstrdup (wrapper);
+      if (check_executable (concat_name))
+       return concat_name;
+      XFREE (concat_name);
+    }
+  else
+    {
+#endif
+      if (IS_DIR_SEPARATOR (wrapper[0]))
+       {
+         concat_name = xstrdup (wrapper);
+         if (check_executable (concat_name))
+           return concat_name;
+         XFREE (concat_name);
+       }
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+    }
+#endif
+
+  for (p = wrapper; *p; p++)
+    if (*p == '/')
+      {
+       has_slash = 1;
+       break;
+      }
+  if (!has_slash)
+    {
+      /* no slashes; search PATH */
+      const char *path = getenv ("PATH");
+      if (path != NULL)
+       {
+         for (p = path; *p; p = p_next)
+           {
+             const char *q;
+             size_t p_len;
+             for (q = p; *q; q++)
+               if (IS_PATH_SEPARATOR (*q))
+                 break;
+             p_len = (size_t) (q - p);
+             p_next = (*q == '\0' ? q : q + 1);
+             if (p_len == 0)
+               {
+                 /* empty path: current directory */
+                 if (getcwd (tmp, LT_PATHMAX) == NULL)
+                   lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+                              nonnull (strerror (errno)));
+                 tmp_len = strlen (tmp);
+                 concat_name =
+                   XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+                 memcpy (concat_name, tmp, tmp_len);
+                 concat_name[tmp_len] = '/';
+                 strcpy (concat_name + tmp_len + 1, wrapper);
+               }
+             else
+               {
+                 concat_name =
+                   XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+                 memcpy (concat_name, p, p_len);
+                 concat_name[p_len] = '/';
+                 strcpy (concat_name + p_len + 1, wrapper);
+               }
+             if (check_executable (concat_name))
+               return concat_name;
+             XFREE (concat_name);
+           }
+       }
+      /* not found in PATH; assume curdir */
+    }
+  /* Relative path | not found in path: prepend cwd */
+  if (getcwd (tmp, LT_PATHMAX) == NULL)
+    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+              nonnull (strerror (errno)));
+  tmp_len = strlen (tmp);
+  concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+  memcpy (concat_name, tmp, tmp_len);
+  concat_name[tmp_len] = '/';
+  strcpy (concat_name + tmp_len + 1, wrapper);
+
+  if (check_executable (concat_name))
+    return concat_name;
+  XFREE (concat_name);
+  return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+  return xstrdup (pathspec);
+#else
+  char buf[LT_PATHMAX];
+  struct stat s;
+  char *tmp_pathspec = xstrdup (pathspec);
+  char *p;
+  int has_symlinks = 0;
+  while (strlen (tmp_pathspec) && !has_symlinks)
+    {
+      lt_debugprintf (__FILE__, __LINE__,
+                     "checking path component for symlinks: %s\n",
+                     tmp_pathspec);
+      if (lstat (tmp_pathspec, &s) == 0)
+       {
+         if (S_ISLNK (s.st_mode) != 0)
+           {
+             has_symlinks = 1;
+             break;
+           }
+
+         /* search backwards for last DIR_SEPARATOR */
+         p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+         while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+           p--;
+         if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+           {
+             /* no more DIR_SEPARATORS left */
+             break;
+           }
+         *p = '\0';
+       }
+      else
+       {
+         lt_fatal (__FILE__, __LINE__,
+                   "error accessing file \"%s\": %s",
+                   tmp_pathspec, nonnull (strerror (errno)));
+       }
+    }
+  XFREE (tmp_pathspec);
+
+  if (!has_symlinks)
+    {
+      return xstrdup (pathspec);
+    }
+
+  tmp_pathspec = realpath (pathspec, buf);
+  if (tmp_pathspec == 0)
+    {
+      lt_fatal (__FILE__, __LINE__,
+               "could not follow symlinks for %s", pathspec);
+    }
+  return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+  size_t len, patlen;
+
+  assert (str != NULL);
+  assert (pat != NULL);
+
+  len = strlen (str);
+  patlen = strlen (pat);
+
+  if (patlen <= len)
+    {
+      str += len - patlen;
+      if (STREQ (str, pat))
+       *str = '\0';
+    }
+  return str;
+}
+
+void
+lt_debugprintf (const char *file, int line, const char *fmt, ...)
+{
+  va_list args;
+  if (lt_debug)
+    {
+      (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
+      va_start (args, fmt);
+      (void) vfprintf (stderr, fmt, args);
+      va_end (args);
+    }
+}
+
+static void
+lt_error_core (int exit_status, const char *file,
+              int line, const char *mode,
+              const char *message, va_list ap)
+{
+  fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
+  vfprintf (stderr, message, ap);
+  fprintf (stderr, ".\n");
+
+  if (exit_status >= 0)
+    exit (exit_status);
+}
+
+void
+lt_fatal (const char *file, int line, const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
+  va_end (ap);
+}
+
+static const char *
+nonnull (const char *s)
+{
+  return s ? s : "(null)";
+}
+
+static const char *
+nonempty (const char *s)
+{
+  return (s && !*s) ? "(empty)" : nonnull (s);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+                 "(lt_setenv) setting '%s' to '%s'\n",
+                  nonnull (name), nonnull (value));
+  {
+#ifdef HAVE_SETENV
+    /* always make a copy, for consistency with !HAVE_SETENV */
+    char *str = xstrdup (value);
+    setenv (name, str, 1);
+#else
+    size_t len = strlen (name) + 1 + strlen (value) + 1;
+    char *str = XMALLOC (char, len);
+    sprintf (str, "%s=%s", name, value);
+    if (putenv (str) != EXIT_SUCCESS)
+      {
+        XFREE (str);
+      }
+#endif
+  }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+  char *new_value;
+  if (orig_value && *orig_value)
+    {
+      size_t orig_value_len = strlen (orig_value);
+      size_t add_len = strlen (add);
+      new_value = XMALLOC (char, add_len + orig_value_len + 1);
+      if (to_end)
+        {
+          strcpy (new_value, orig_value);
+          strcpy (new_value + orig_value_len, add);
+        }
+      else
+        {
+          strcpy (new_value, add);
+          strcpy (new_value + add_len, orig_value);
+        }
+    }
+  else
+    {
+      new_value = xstrdup (add);
+    }
+  return new_value;
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+                 "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      /* some systems can't cope with a ':'-terminated path #' */
+      size_t len = strlen (new_value);
+      while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+        {
+          new_value[--len] = '\0';
+        }
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+                 "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+EOF
+           case $host_os in
+             mingw*)
+               cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+   Note that spawn() does not by itself call the command interpreter
+     (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+      ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+         GetVersionEx(&v);
+         v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+      }) ? "cmd.exe" : "command.com").
+   Instead it simply concatenates the arguments, separated by ' ', and calls
+   CreateProcess().  We must quote the arguments since Win32 CreateProcess()
+   interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+   special way:
+   - Space and tab are interpreted as delimiters. They are not treated as
+     delimiters if they are surrounded by double quotes: "...".
+   - Unescaped double quotes are removed from the input. Their only effect is
+     that within double quotes, space and tab are treated like normal
+     characters.
+   - Backslashes not followed by double quotes are not special.
+   - But 2*n+1 backslashes followed by a double quote become
+     n backslashes followed by a double quote (n >= 0):
+       \" -> "
+       \\\" -> \"
+       \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+  size_t argc;
+  char **new_argv;
+  size_t i;
+
+  /* Count number of arguments.  */
+  for (argc = 0; argv[argc] != NULL; argc++)
+    ;
+
+  /* Allocate new argument vector.  */
+  new_argv = XMALLOC (char *, argc + 1);
+
+  /* Put quoted arguments into the new argument vector.  */
+  for (i = 0; i < argc; i++)
+    {
+      const char *string = argv[i];
+
+      if (string[0] == '\0')
+       new_argv[i] = xstrdup ("\"\"");
+      else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+       {
+         int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+         size_t length;
+         unsigned int backslashes;
+         const char *s;
+         char *quoted_string;
+         char *p;
+
+         length = 0;
+         backslashes = 0;
+         if (quote_around)
+           length++;
+         for (s = string; *s != '\0'; s++)
+           {
+             char c = *s;
+             if (c == '"')
+               length += backslashes + 1;
+             length++;
+             if (c == '\\')
+               backslashes++;
+             else
+               backslashes = 0;
+           }
+         if (quote_around)
+           length += backslashes + 1;
+
+         quoted_string = XMALLOC (char, length + 1);
+
+         p = quoted_string;
+         backslashes = 0;
+         if (quote_around)
+           *p++ = '"';
+         for (s = string; *s != '\0'; s++)
+           {
+             char c = *s;
+             if (c == '"')
+               {
+                 unsigned int j;
+                 for (j = backslashes + 1; j > 0; j--)
+                   *p++ = '\\';
+               }
+             *p++ = c;
+             if (c == '\\')
+               backslashes++;
+             else
+               backslashes = 0;
+           }
+         if (quote_around)
+           {
+             unsigned int j;
+             for (j = backslashes; j > 0; j--)
+               *p++ = '\\';
+             *p++ = '"';
+           }
+         *p = '\0';
+
+         new_argv[i] = quoted_string;
+       }
+      else
+       new_argv[i] = (char *) string;
+    }
+  new_argv[argc] = NULL;
+
+  return new_argv;
+}
+EOF
+               ;;
+           esac
+
+            cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+           func_emit_wrapper yes |
+             $SED -n -e '
+s/^\(.\{79\}\)\(..*\)/\1\
+\2/
+h
+s/\([\\"]\)/\\\1/g
+s/$/\\n/
+s/\([^\n]*\).*/  fputs ("\1", f);/p
+g
+D'
+            cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+    $debug_cmd
+
+    case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
+    *import*) : ;;
+    *) false ;;
+    esac
+}
+
+# func_suncc_cstd_abi
+# !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!!
+# Several compiler flags select an ABI that is incompatible with the
+# Cstd library. Avoid specifying it if any are in CXXFLAGS.
+func_suncc_cstd_abi ()
+{
+    $debug_cmd
+
+    case " $compile_command " in
+    *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*)
+      suncc_use_cstd_abi=no
+      ;;
+    *)
+      suncc_use_cstd_abi=yes
+      ;;
+    esac
+}
+
+# func_mode_link arg...
+func_mode_link ()
+{
+    $debug_cmd
+
+    case $host in
+    *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+      # It is impossible to link a dll without this setting, and
+      # we shouldn't force the makefile maintainer to figure out
+      # what system we are compiling for in order to pass an extra
+      # flag for every libtool invocation.
+      # allow_undefined=no
+
+      # FIXME: Unfortunately, there are problems with the above when trying
+      # to make a dll that has undefined symbols, in which case not
+      # even a static library is built.  For now, we need to specify
+      # -no-undefined on the libtool link line when we can be certain
+      # that all symbols are satisfied, otherwise we get a static library.
+      allow_undefined=yes
+      ;;
+    *)
+      allow_undefined=yes
+      ;;
+    esac
+    libtool_args=$nonopt
+    base_compile="$nonopt $@"
+    compile_command=$nonopt
+    finalize_command=$nonopt
+
+    compile_rpath=
+    finalize_rpath=
+    compile_shlibpath=
+    finalize_shlibpath=
+    convenience=
+    old_convenience=
+    deplibs=
+    old_deplibs=
+    compiler_flags=
+    linker_flags=
+    dllsearchpath=
+    lib_search_path=`pwd`
+    inst_prefix_dir=
+    new_inherited_linker_flags=
+
+    avoid_version=no
+    bindir=
+    dlfiles=
+    dlprefiles=
+    dlself=no
+    export_dynamic=no
+    export_symbols=
+    export_symbols_regex=
+    generated=
+    libobjs=
+    ltlibs=
+    module=no
+    no_install=no
+    objs=
+    os2dllname=
+    non_pic_objects=
+    precious_files_regex=
+    prefer_static_libs=no
+    preload=false
+    prev=
+    prevarg=
+    release=
+    rpath=
+    xrpath=
+    perm_rpath=
+    temp_rpath=
+    thread_safe=no
+    vinfo=
+    vinfo_number=no
+    weak_libs=
+    single_module=$wl-single_module
+    func_infer_tag $base_compile
+
+    # We need to know -static, to get the right output filenames.
+    for arg
+    do
+      case $arg in
+      -shared)
+       test yes != "$build_libtool_libs" \
+         && func_fatal_configuration "cannot build a shared library"
+       build_old_libs=no
+       break
+       ;;
+      -all-static | -static | -static-libtool-libs)
+       case $arg in
+       -all-static)
+         if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then
+           func_warning "complete static linking is impossible in this configuration"
+         fi
+         if test -n "$link_static_flag"; then
+           dlopen_self=$dlopen_self_static
+         fi
+         prefer_static_libs=yes
+         ;;
+       -static)
+         if test -z "$pic_flag" && test -n "$link_static_flag"; then
+           dlopen_self=$dlopen_self_static
+         fi
+         prefer_static_libs=built
+         ;;
+       -static-libtool-libs)
+         if test -z "$pic_flag" && test -n "$link_static_flag"; then
+           dlopen_self=$dlopen_self_static
+         fi
+         prefer_static_libs=yes
+         ;;
+       esac
+       build_libtool_libs=no
+       build_old_libs=yes
+       break
+       ;;
+      esac
+    done
+
+    # See if our shared archives depend on static archives.
+    test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+    # Go through the arguments, transforming them on the way.
+    while test "$#" -gt 0; do
+      arg=$1
+      shift
+      func_quote_for_eval "$arg"
+      qarg=$func_quote_for_eval_unquoted_result
+      func_append libtool_args " $func_quote_for_eval_result"
+
+      # If the previous option needs an argument, assign it.
+      if test -n "$prev"; then
+       case $prev in
+       output)
+         func_append compile_command " @OUTPUT@"
+         func_append finalize_command " @OUTPUT@"
+         ;;
+       esac
+
+       case $prev in
+       bindir)
+         bindir=$arg
+         prev=
+         continue
+         ;;
+       dlfiles|dlprefiles)
+         $preload || {
+           # Add the symbol object into the linking commands.
+           func_append compile_command " @SYMFILE@"
+           func_append finalize_command " @SYMFILE@"
+           preload=:
+         }
+         case $arg in
+         *.la | *.lo) ;;  # We handle these cases below.
+         force)
+           if test no = "$dlself"; then
+             dlself=needless
+             export_dynamic=yes
+           fi
+           prev=
+           continue
+           ;;
+         self)
+           if test dlprefiles = "$prev"; then
+             dlself=yes
+           elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then
+             dlself=yes
+           else
+             dlself=needless
+             export_dynamic=yes
+           fi
+           prev=
+           continue
+           ;;
+         *)
+           if test dlfiles = "$prev"; then
+             func_append dlfiles " $arg"
+           else
+             func_append dlprefiles " $arg"
+           fi
+           prev=
+           continue
+           ;;
+         esac
+         ;;
+       expsyms)
+         export_symbols=$arg
+         test -f "$arg" \
+           || func_fatal_error "symbol file '$arg' does not exist"
+         prev=
+         continue
+         ;;
+       expsyms_regex)
+         export_symbols_regex=$arg
+         prev=
+         continue
+         ;;
+       framework)
+         case $host in
+           *-*-darwin*)
+             case "$deplibs " in
+               *" $qarg.ltframework "*) ;;
+               *) func_append deplibs " $qarg.ltframework" # this is fixed later
+                  ;;
+             esac
+             ;;
+         esac
+         prev=
+         continue
+         ;;
+       inst_prefix)
+         inst_prefix_dir=$arg
+         prev=
+         continue
+         ;;
+       mllvm)
+         # Clang does not use LLVM to link, so we can simply discard any
+         # '-mllvm $arg' options when doing the link step.
+         prev=
+         continue
+         ;;
+       objectlist)
+         if test -f "$arg"; then
+           save_arg=$arg
+           moreargs=
+           for fil in `cat "$save_arg"`
+           do
+#            func_append moreargs " $fil"
+             arg=$fil
+             # A libtool-controlled object.
+
+             # Check to see that this really is a libtool object.
+             if func_lalib_unsafe_p "$arg"; then
+               pic_object=
+               non_pic_object=
+
+               # Read the .lo file
+               func_source "$arg"
+
+               if test -z "$pic_object" ||
+                  test -z "$non_pic_object" ||
+                  test none = "$pic_object" &&
+                  test none = "$non_pic_object"; then
+                 func_fatal_error "cannot find name of object for '$arg'"
+               fi
+
+               # Extract subdirectory from the argument.
+               func_dirname "$arg" "/" ""
+               xdir=$func_dirname_result
+
+               if test none != "$pic_object"; then
+                 # Prepend the subdirectory the object is found in.
+                 pic_object=$xdir$pic_object
+
+                 if test dlfiles = "$prev"; then
+                   if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
+                     func_append dlfiles " $pic_object"
+                     prev=
+                     continue
+                   else
+                     # If libtool objects are unsupported, then we need to preload.
+                     prev=dlprefiles
+                   fi
+                 fi
+
+                 # CHECK ME:  I think I busted this.  -Ossama
+                 if test dlprefiles = "$prev"; then
+                   # Preload the old-style object.
+                   func_append dlprefiles " $pic_object"
+                   prev=
+                 fi
+
+                 # A PIC object.
+                 func_append libobjs " $pic_object"
+                 arg=$pic_object
+               fi
+
+               # Non-PIC object.
+               if test none != "$non_pic_object"; then
+                 # Prepend the subdirectory the object is found in.
+                 non_pic_object=$xdir$non_pic_object
+
+                 # A standard non-PIC object
+                 func_append non_pic_objects " $non_pic_object"
+                 if test -z "$pic_object" || test none = "$pic_object"; then
+                   arg=$non_pic_object
+                 fi
+               else
+                 # If the PIC object exists, use it instead.
+                 # $xdir was prepended to $pic_object above.
+                 non_pic_object=$pic_object
+                 func_append non_pic_objects " $non_pic_object"
+               fi
+             else
+               # Only an error if not doing a dry-run.
+               if $opt_dry_run; then
+                 # Extract subdirectory from the argument.
+                 func_dirname "$arg" "/" ""
+                 xdir=$func_dirname_result
+
+                 func_lo2o "$arg"
+                 pic_object=$xdir$objdir/$func_lo2o_result
+                 non_pic_object=$xdir$func_lo2o_result
+                 func_append libobjs " $pic_object"
+                 func_append non_pic_objects " $non_pic_object"
+               else
+                 func_fatal_error "'$arg' is not a valid libtool object"
+               fi
+             fi
+           done
+         else
+           func_fatal_error "link input file '$arg' does not exist"
+         fi
+         arg=$save_arg
+         prev=
+         continue
+         ;;
+       os2dllname)
+         os2dllname=$arg
+         prev=
+         continue
+         ;;
+       precious_regex)
+         precious_files_regex=$arg
+         prev=
+         continue
+         ;;
+       release)
+         release=-$arg
+         prev=
+         continue
+         ;;
+       rpath | xrpath)
+         # We need an absolute path.
+         case $arg in
+         [\\/]* | [A-Za-z]:[\\/]*) ;;
+         *)
+           func_fatal_error "only absolute run-paths are allowed"
+           ;;
+         esac
+         if test rpath = "$prev"; then
+           case "$rpath " in
+           *" $arg "*) ;;
+           *) func_append rpath " $arg" ;;
+           esac
+         else
+           case "$xrpath " in
+           *" $arg "*) ;;
+           *) func_append xrpath " $arg" ;;
+           esac
+         fi
+         prev=
+         continue
+         ;;
+       shrext)
+         shrext_cmds=$arg
+         prev=
+         continue
+         ;;
+       weak)
+         func_append weak_libs " $arg"
+         prev=
+         continue
+         ;;
+       xcclinker)
+         func_append linker_flags " $qarg"
+         func_append compiler_flags " $qarg"
+         prev=
+         func_append compile_command " $qarg"
+         func_append finalize_command " $qarg"
+         continue
+         ;;
+       xcompiler)
+         func_append compiler_flags " $qarg"
+         prev=
+         func_append compile_command " $qarg"
+         func_append finalize_command " $qarg"
+         continue
+         ;;
+       xlinker)
+         func_append linker_flags " $qarg"
+         func_append compiler_flags " $wl$qarg"
+         prev=
+         func_append compile_command " $wl$qarg"
+         func_append finalize_command " $wl$qarg"
+         continue
+         ;;
+       *)
+         eval "$prev=\"\$arg\""
+         prev=
+         continue
+         ;;
+       esac
+      fi # test -n "$prev"
+
+      prevarg=$arg
+
+      case $arg in
+      -all-static)
+       if test -n "$link_static_flag"; then
+         # See comment for -static flag below, for more details.
+         func_append compile_command " $link_static_flag"
+         func_append finalize_command " $link_static_flag"
+       fi
+       continue
+       ;;
+
+      -allow-undefined)
+       # FIXME: remove this flag sometime in the future.
+       func_fatal_error "'-allow-undefined' must not be used because it is the default"
+       ;;
+
+      -avoid-version)
+       avoid_version=yes
+       continue
+       ;;
+
+      -bindir)
+       prev=bindir
+       continue
+       ;;
+
+      -dlopen)
+       prev=dlfiles
+       continue
+       ;;
+
+      -dlpreopen)
+       prev=dlprefiles
+       continue
+       ;;
+
+      -export-dynamic)
+       export_dynamic=yes
+       continue
+       ;;
+
+      -export-symbols | -export-symbols-regex)
+       if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+         func_fatal_error "more than one -exported-symbols argument is not allowed"
+       fi
+       if test X-export-symbols = "X$arg"; then
+         prev=expsyms
+       else
+         prev=expsyms_regex
+       fi
+       continue
+       ;;
+
+      -framework)
+       prev=framework
+       continue
+       ;;
+
+      -inst-prefix-dir)
+       prev=inst_prefix
+       continue
+       ;;
+
+      # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+      # so, if we see these flags be careful not to treat them like -L
+      -L[A-Z][A-Z]*:*)
+       case $with_gcc/$host in
+       no/*-*-irix* | /*-*-irix*)
+         func_append compile_command " $arg"
+         func_append finalize_command " $arg"
+         ;;
+       esac
+       continue
+       ;;
+
+      -L*)
+       func_stripname "-L" '' "$arg"
+       if test -z "$func_stripname_result"; then
+         if test "$#" -gt 0; then
+           func_fatal_error "require no space between '-L' and '$1'"
+         else
+           func_fatal_error "need path for '-L' option"
+         fi
+       fi
+       func_resolve_sysroot "$func_stripname_result"
+       dir=$func_resolve_sysroot_result
+       # We need an absolute path.
+       case $dir in
+       [\\/]* | [A-Za-z]:[\\/]*) ;;
+       *)
+         absdir=`cd "$dir" && pwd`
+         test -z "$absdir" && \
+           func_fatal_error "cannot determine absolute directory name of '$dir'"
+         dir=$absdir
+         ;;
+       esac
+       case "$deplibs " in
+       *" -L$dir "* | *" $arg "*)
+         # Will only happen for absolute or sysroot arguments
+         ;;
+       *)
+         # Preserve sysroot, but never include relative directories
+         case $dir in
+           [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;;
+           *) func_append deplibs " -L$dir" ;;
+         esac
+         func_append lib_search_path " $dir"
+         ;;
+       esac
+       case $host in
+       *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+         testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
+         case :$dllsearchpath: in
+         *":$dir:"*) ;;
+         ::) dllsearchpath=$dir;;
+         *) func_append dllsearchpath ":$dir";;
+         esac
+         case :$dllsearchpath: in
+         *":$testbindir:"*) ;;
+         ::) dllsearchpath=$testbindir;;
+         *) func_append dllsearchpath ":$testbindir";;
+         esac
+         ;;
+       esac
+       continue
+       ;;
+
+      -l*)
+       if test X-lc = "X$arg" || test X-lm = "X$arg"; then
+         case $host in
+         *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+           # These systems don't actually have a C or math library (as such)
+           continue
+           ;;
+         *-*-os2*)
+           # These systems don't actually have a C library (as such)
+           test X-lc = "X$arg" && continue
+           ;;
+         *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
+           # Do not include libc due to us having libc/libc_r.
+           test X-lc = "X$arg" && continue
+           ;;
+         *-*-rhapsody* | *-*-darwin1.[012])
+           # Rhapsody C and math libraries are in the System framework
+           func_append deplibs " System.ltframework"
+           continue
+           ;;
+         *-*-sco3.2v5* | *-*-sco5v6*)
+           # Causes problems with __ctype
+           test X-lc = "X$arg" && continue
+           ;;
+         *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+           # Compiler inserts libc in the correct place for threads to work
+           test X-lc = "X$arg" && continue
+           ;;
+         esac
+       elif test X-lc_r = "X$arg"; then
+        case $host in
+        *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
+          # Do not include libc_r directly, use -pthread flag.
+          continue
+          ;;
+        esac
+       fi
+       func_append deplibs " $arg"
+       continue
+       ;;
+
+      -mllvm)
+       prev=mllvm
+       continue
+       ;;
+
+      -module)
+       module=yes
+       continue
+       ;;
+
+      # Tru64 UNIX uses -model [arg] to determine the layout of C++
+      # classes, name mangling, and exception handling.
+      # Darwin uses the -arch flag to determine output architecture.
+      -model|-arch|-isysroot|--sysroot)
+       func_append compiler_flags " $arg"
+       func_append compile_command " $arg"
+       func_append finalize_command " $arg"
+       prev=xcompiler
+       continue
+       ;;
+
+      -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+      |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+       func_append compiler_flags " $arg"
+       func_append compile_command " $arg"
+       func_append finalize_command " $arg"
+       case "$new_inherited_linker_flags " in
+           *" $arg "*) ;;
+           * ) func_append new_inherited_linker_flags " $arg" ;;
+       esac
+       continue
+       ;;
+
+      -multi_module)
+       single_module=$wl-multi_module
+       continue
+       ;;
+
+      -no-fast-install)
+       fast_install=no
+       continue
+       ;;
+
+      -no-install)
+       case $host in
+       *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+         # The PATH hackery in wrapper scripts is required on Windows
+         # and Darwin in order for the loader to find any dlls it needs.
+         func_warning "'-no-install' is ignored for $host"
+         func_warning "assuming '-no-fast-install' instead"
+         fast_install=no
+         ;;
+       *) no_install=yes ;;
+       esac
+       continue
+       ;;
+
+      -no-undefined)
+       allow_undefined=no
+       continue
+       ;;
+
+      -objectlist)
+       prev=objectlist
+       continue
+       ;;
+
+      -os2dllname)
+       prev=os2dllname
+       continue
+       ;;
+
+      -o) prev=output ;;
+
+      -precious-files-regex)
+       prev=precious_regex
+       continue
+       ;;
+
+      -release)
+       prev=release
+       continue
+       ;;
+
+      -rpath)
+       prev=rpath
+       continue
+       ;;
+
+      -R)
+       prev=xrpath
+       continue
+       ;;
+
+      -R*)
+       func_stripname '-R' '' "$arg"
+       dir=$func_stripname_result
+       # We need an absolute path.
+       case $dir in
+       [\\/]* | [A-Za-z]:[\\/]*) ;;
+       =*)
+         func_stripname '=' '' "$dir"
+         dir=$lt_sysroot$func_stripname_result
+         ;;
+       *)
+         func_fatal_error "only absolute run-paths are allowed"
+         ;;
+       esac
+       case "$xrpath " in
+       *" $dir "*) ;;
+       *) func_append xrpath " $dir" ;;
+       esac
+       continue
+       ;;
+
+      -shared)
+       # The effects of -shared are defined in a previous loop.
+       continue
+       ;;
+
+      -shrext)
+       prev=shrext
+       continue
+       ;;
+
+      -static | -static-libtool-libs)
+       # The effects of -static are defined in a previous loop.
+       # We used to do the same as -all-static on platforms that
+       # didn't have a PIC flag, but the assumption that the effects
+       # would be equivalent was wrong.  It would break on at least
+       # Digital Unix and AIX.
+       continue
+       ;;
+
+      -thread-safe)
+       thread_safe=yes
+       continue
+       ;;
+
+      -version-info)
+       prev=vinfo
+       continue
+       ;;
+
+      -version-number)
+       prev=vinfo
+       vinfo_number=yes
+       continue
+       ;;
+
+      -weak)
+        prev=weak
+       continue
+       ;;
+
+      -Wc,*)
+       func_stripname '-Wc,' '' "$arg"
+       args=$func_stripname_result
+       arg=
+       save_ifs=$IFS; IFS=,
+       for flag in $args; do
+         IFS=$save_ifs
+          func_quote_for_eval "$flag"
+         func_append arg " $func_quote_for_eval_result"
+         func_append compiler_flags " $func_quote_for_eval_result"
+       done
+       IFS=$save_ifs
+       func_stripname ' ' '' "$arg"
+       arg=$func_stripname_result
+       ;;
+
+      -Wl,*)
+       func_stripname '-Wl,' '' "$arg"
+       args=$func_stripname_result
+       arg=
+       save_ifs=$IFS; IFS=,
+       for flag in $args; do
+         IFS=$save_ifs
+          func_quote_for_eval "$flag"
+         func_append arg " $wl$func_quote_for_eval_result"
+         func_append compiler_flags " $wl$func_quote_for_eval_result"
+         func_append linker_flags " $func_quote_for_eval_result"
+       done
+       IFS=$save_ifs
+       func_stripname ' ' '' "$arg"
+       arg=$func_stripname_result
+       ;;
+
+      -Xcompiler)
+       prev=xcompiler
+       continue
+       ;;
+
+      -Xlinker)
+       prev=xlinker
+       continue
+       ;;
+
+      -XCClinker)
+       prev=xcclinker
+       continue
+       ;;
+
+      # -msg_* for osf cc
+      -msg_*)
+       func_quote_for_eval "$arg"
+       arg=$func_quote_for_eval_result
+       ;;
+
+      # Flags to be passed through unchanged, with rationale:
+      # -64, -mips[0-9]      enable 64-bit mode for the SGI compiler
+      # -r[0-9][0-9]*        specify processor for the SGI compiler
+      # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
+      # +DA*, +DD*           enable 64-bit mode for the HP compiler
+      # -q*                  compiler args for the IBM compiler
+      # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
+      # -F/path              path to uninstalled frameworks, gcc on darwin
+      # -p, -pg, --coverage, -fprofile-*  profiling flags for GCC
+      # -fstack-protector*   stack protector flags for GCC
+      # @file                GCC response files
+      # -tp=*                Portland pgcc target processor selection
+      # --sysroot=*          for sysroot support
+      # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+      # -stdlib=*            select c++ std lib with clang
+      -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+      -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*)
+        func_quote_for_eval "$arg"
+       arg=$func_quote_for_eval_result
+        func_append compile_command " $arg"
+        func_append finalize_command " $arg"
+        func_append compiler_flags " $arg"
+        continue
+        ;;
+
+      -Z*)
+        if test os2 = "`expr $host : '.*\(os2\)'`"; then
+          # OS/2 uses -Zxxx to specify OS/2-specific options
+         compiler_flags="$compiler_flags $arg"
+         func_append compile_command " $arg"
+         func_append finalize_command " $arg"
+         case $arg in
+         -Zlinker | -Zstack)
+           prev=xcompiler
+           ;;
+         esac
+         continue
+        else
+         # Otherwise treat like 'Some other compiler flag' below
+         func_quote_for_eval "$arg"
+         arg=$func_quote_for_eval_result
+        fi
+       ;;
+
+      # Some other compiler flag.
+      -* | +*)
+        func_quote_for_eval "$arg"
+       arg=$func_quote_for_eval_result
+       ;;
+
+      *.$objext)
+       # A standard object.
+       func_append objs " $arg"
+       ;;
+
+      *.lo)
+       # A libtool-controlled object.
+
+       # Check to see that this really is a libtool object.
+       if func_lalib_unsafe_p "$arg"; then
+         pic_object=
+         non_pic_object=
+
+         # Read the .lo file
+         func_source "$arg"
+
+         if test -z "$pic_object" ||
+            test -z "$non_pic_object" ||
+            test none = "$pic_object" &&
+            test none = "$non_pic_object"; then
+           func_fatal_error "cannot find name of object for '$arg'"
+         fi
+
+         # Extract subdirectory from the argument.
+         func_dirname "$arg" "/" ""
+         xdir=$func_dirname_result
+
+         test none = "$pic_object" || {
+           # Prepend the subdirectory the object is found in.
+           pic_object=$xdir$pic_object
+
+           if test dlfiles = "$prev"; then
+             if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
+               func_append dlfiles " $pic_object"
+               prev=
+               continue
+             else
+               # If libtool objects are unsupported, then we need to preload.
+               prev=dlprefiles
+             fi
+           fi
+
+           # CHECK ME:  I think I busted this.  -Ossama
+           if test dlprefiles = "$prev"; then
+             # Preload the old-style object.
+             func_append dlprefiles " $pic_object"
+             prev=
+           fi
+
+           # A PIC object.
+           func_append libobjs " $pic_object"
+           arg=$pic_object
+         }
+
+         # Non-PIC object.
+         if test none != "$non_pic_object"; then
+           # Prepend the subdirectory the object is found in.
+           non_pic_object=$xdir$non_pic_object
+
+           # A standard non-PIC object
+           func_append non_pic_objects " $non_pic_object"
+           if test -z "$pic_object" || test none = "$pic_object"; then
+             arg=$non_pic_object
+           fi
+         else
+           # If the PIC object exists, use it instead.
+           # $xdir was prepended to $pic_object above.
+           non_pic_object=$pic_object
+           func_append non_pic_objects " $non_pic_object"
+         fi
+       else
+         # Only an error if not doing a dry-run.
+         if $opt_dry_run; then
+           # Extract subdirectory from the argument.
+           func_dirname "$arg" "/" ""
+           xdir=$func_dirname_result
+
+           func_lo2o "$arg"
+           pic_object=$xdir$objdir/$func_lo2o_result
+           non_pic_object=$xdir$func_lo2o_result
+           func_append libobjs " $pic_object"
+           func_append non_pic_objects " $non_pic_object"
+         else
+           func_fatal_error "'$arg' is not a valid libtool object"
+         fi
+       fi
+       ;;
+
+      *.$libext)
+       # An archive.
+       func_append deplibs " $arg"
+       func_append old_deplibs " $arg"
+       continue
+       ;;
+
+      *.la)
+       # A libtool-controlled library.
+
+       func_resolve_sysroot "$arg"
+       if test dlfiles = "$prev"; then
+         # This library was specified with -dlopen.
+         func_append dlfiles " $func_resolve_sysroot_result"
+         prev=
+       elif test dlprefiles = "$prev"; then
+         # The library was specified with -dlpreopen.
+         func_append dlprefiles " $func_resolve_sysroot_result"
+         prev=
+       else
+         func_append deplibs " $func_resolve_sysroot_result"
+       fi
+       continue
+       ;;
+
+      # Some other compiler argument.
+      *)
+       # Unknown arguments in both finalize_command and compile_command need
+       # to be aesthetically quoted because they are evaled later.
+       func_quote_for_eval "$arg"
+       arg=$func_quote_for_eval_result
+       ;;
+      esac # arg
+
+      # Now actually substitute the argument into the commands.
+      if test -n "$arg"; then
+       func_append compile_command " $arg"
+       func_append finalize_command " $arg"
+      fi
+    done # argument parsing loop
+
+    test -n "$prev" && \
+      func_fatal_help "the '$prevarg' option requires an argument"
+
+    if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then
+      eval arg=\"$export_dynamic_flag_spec\"
+      func_append compile_command " $arg"
+      func_append finalize_command " $arg"
+    fi
+
+    oldlibs=
+    # calculate the name of the file, without its directory
+    func_basename "$output"
+    outputname=$func_basename_result
+    libobjs_save=$libobjs
+
+    if test -n "$shlibpath_var"; then
+      # get the directories listed in $shlibpath_var
+      eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\`
+    else
+      shlib_search_path=
+    fi
+    eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+    eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+    # Definition is injected by LT_CONFIG during libtool generation.
+    func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH"
+
+    func_dirname "$output" "/" ""
+    output_objdir=$func_dirname_result$objdir
+    func_to_tool_file "$output_objdir/"
+    tool_output_objdir=$func_to_tool_file_result
+    # Create the object directory.
+    func_mkdir_p "$output_objdir"
+
+    # Determine the type of output
+    case $output in
+    "")
+      func_fatal_help "you must specify an output file"
+      ;;
+    *.$libext) linkmode=oldlib ;;
+    *.lo | *.$objext) linkmode=obj ;;
+    *.la) linkmode=lib ;;
+    *) linkmode=prog ;; # Anything else should be a program.
+    esac
+
+    specialdeplibs=
+
+    libs=
+    # Find all interdependent deplibs by searching for libraries
+    # that are linked more than once (e.g. -la -lb -la)
+    for deplib in $deplibs; do
+      if $opt_preserve_dup_deps; then
+       case "$libs " in
+       *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+       esac
+      fi
+      func_append libs " $deplib"
+    done
+
+    if test lib = "$linkmode"; then
+      libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+      # Compute libraries that are listed more than once in $predeps
+      # $postdeps and mark them as special (i.e., whose duplicates are
+      # not to be eliminated).
+      pre_post_deps=
+      if $opt_duplicate_compiler_generated_deps; then
+       for pre_post_dep in $predeps $postdeps; do
+         case "$pre_post_deps " in
+         *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;;
+         esac
+         func_append pre_post_deps " $pre_post_dep"
+       done
+      fi
+      pre_post_deps=
+    fi
+
+    deplibs=
+    newdependency_libs=
+    newlib_search_path=
+    need_relink=no # whether we're linking any uninstalled libtool libraries
+    notinst_deplibs= # not-installed libtool libraries
+    notinst_path= # paths that contain not-installed libtool libraries
+
+    case $linkmode in
+    lib)
+       passes="conv dlpreopen link"
+       for file in $dlfiles $dlprefiles; do
+         case $file in
+         *.la) ;;
+         *)
+           func_fatal_help "libraries can '-dlopen' only libtool libraries: $file"
+           ;;
+         esac
+       done
+       ;;
+    prog)
+       compile_deplibs=
+       finalize_deplibs=
+       alldeplibs=false
+       newdlfiles=
+       newdlprefiles=
+       passes="conv scan dlopen dlpreopen link"
+       ;;
+    *)  passes="conv"
+       ;;
+    esac
+
+    for pass in $passes; do
+      # The preopen pass in lib mode reverses $deplibs; put it back here
+      # so that -L comes before libs that need it for instance...
+      if test lib,link = "$linkmode,$pass"; then
+       ## FIXME: Find the place where the list is rebuilt in the wrong
+       ##        order, and fix it there properly
+        tmp_deplibs=
+       for deplib in $deplibs; do
+         tmp_deplibs="$deplib $tmp_deplibs"
+       done
+       deplibs=$tmp_deplibs
+      fi
+
+      if test lib,link = "$linkmode,$pass" ||
+        test prog,scan = "$linkmode,$pass"; then
+       libs=$deplibs
+       deplibs=
+      fi
+      if test prog = "$linkmode"; then
+       case $pass in
+       dlopen) libs=$dlfiles ;;
+       dlpreopen) libs=$dlprefiles ;;
+       link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+       esac
+      fi
+      if test lib,dlpreopen = "$linkmode,$pass"; then
+       # Collect and forward deplibs of preopened libtool libs
+       for lib in $dlprefiles; do
+         # Ignore non-libtool-libs
+         dependency_libs=
+         func_resolve_sysroot "$lib"
+         case $lib in
+         *.la) func_source "$func_resolve_sysroot_result" ;;
+         esac
+
+         # Collect preopened libtool deplibs, except any this library
+         # has declared as weak libs
+         for deplib in $dependency_libs; do
+           func_basename "$deplib"
+            deplib_base=$func_basename_result
+           case " $weak_libs " in
+           *" $deplib_base "*) ;;
+           *) func_append deplibs " $deplib" ;;
+           esac
+         done
+       done
+       libs=$dlprefiles
+      fi
+      if test dlopen = "$pass"; then
+       # Collect dlpreopened libraries
+       save_deplibs=$deplibs
+       deplibs=
+      fi
+
+      for deplib in $libs; do
+       lib=
+       found=false
+       case $deplib in
+       -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+        |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+         if test prog,link = "$linkmode,$pass"; then
+           compile_deplibs="$deplib $compile_deplibs"
+           finalize_deplibs="$deplib $finalize_deplibs"
+         else
+           func_append compiler_flags " $deplib"
+           if test lib = "$linkmode"; then
+               case "$new_inherited_linker_flags " in
+                   *" $deplib "*) ;;
+                   * ) func_append new_inherited_linker_flags " $deplib" ;;
+               esac
+           fi
+         fi
+         continue
+         ;;
+       -l*)
+         if test lib != "$linkmode" && test prog != "$linkmode"; then
+           func_warning "'-l' is ignored for archives/objects"
+           continue
+         fi
+         func_stripname '-l' '' "$deplib"
+         name=$func_stripname_result
+         if test lib = "$linkmode"; then
+           searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+         else
+           searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+         fi
+         for searchdir in $searchdirs; do
+           for search_ext in .la $std_shrext .so .a; do
+             # Search the libtool library
+             lib=$searchdir/lib$name$search_ext
+             if test -f "$lib"; then
+               if test .la = "$search_ext"; then
+                 found=:
+               else
+                 found=false
+               fi
+               break 2
+             fi
+           done
+         done
+         if $found; then
+           # deplib is a libtool library
+           # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+           # We need to do some special things here, and not later.
+           if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+             case " $predeps $postdeps " in
+             *" $deplib "*)
+               if func_lalib_p "$lib"; then
+                 library_names=
+                 old_library=
+                 func_source "$lib"
+                 for l in $old_library $library_names; do
+                   ll=$l
+                 done
+                 if test "X$ll" = "X$old_library"; then # only static version available
+                   found=false
+                   func_dirname "$lib" "" "."
+                   ladir=$func_dirname_result
+                   lib=$ladir/$old_library
+                   if test prog,link = "$linkmode,$pass"; then
+                     compile_deplibs="$deplib $compile_deplibs"
+                     finalize_deplibs="$deplib $finalize_deplibs"
+                   else
+                     deplibs="$deplib $deplibs"
+                     test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
+                   fi
+                   continue
+                 fi
+               fi
+               ;;
+             *) ;;
+             esac
+           fi
+         else
+           # deplib doesn't seem to be a libtool library
+           if test prog,link = "$linkmode,$pass"; then
+             compile_deplibs="$deplib $compile_deplibs"
+             finalize_deplibs="$deplib $finalize_deplibs"
+           else
+             deplibs="$deplib $deplibs"
+             test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
+           fi
+           continue
+         fi
+         ;; # -l
+       *.ltframework)
+         if test prog,link = "$linkmode,$pass"; then
+           compile_deplibs="$deplib $compile_deplibs"
+           finalize_deplibs="$deplib $finalize_deplibs"
+         else
+           deplibs="$deplib $deplibs"
+           if test lib = "$linkmode"; then
+               case "$new_inherited_linker_flags " in
+                   *" $deplib "*) ;;
+                   * ) func_append new_inherited_linker_flags " $deplib" ;;
+               esac
+           fi
+         fi
+         continue
+         ;;
+       -L*)
+         case $linkmode in
+         lib)
+           deplibs="$deplib $deplibs"
+           test conv = "$pass" && continue
+           newdependency_libs="$deplib $newdependency_libs"
+           func_stripname '-L' '' "$deplib"
+           func_resolve_sysroot "$func_stripname_result"
+           func_append newlib_search_path " $func_resolve_sysroot_result"
+           ;;
+         prog)
+           if test conv = "$pass"; then
+             deplibs="$deplib $deplibs"
+             continue
+           fi
+           if test scan = "$pass"; then
+             deplibs="$deplib $deplibs"
+           else
+             compile_deplibs="$deplib $compile_deplibs"
+             finalize_deplibs="$deplib $finalize_deplibs"
+           fi
+           func_stripname '-L' '' "$deplib"
+           func_resolve_sysroot "$func_stripname_result"
+           func_append newlib_search_path " $func_resolve_sysroot_result"
+           ;;
+         *)
+           func_warning "'-L' is ignored for archives/objects"
+           ;;
+         esac # linkmode
+         continue
+         ;; # -L
+       -R*)
+         if test link = "$pass"; then
+           func_stripname '-R' '' "$deplib"
+           func_resolve_sysroot "$func_stripname_result"
+           dir=$func_resolve_sysroot_result
+           # Make sure the xrpath contains only unique directories.
+           case "$xrpath " in
+           *" $dir "*) ;;
+           *) func_append xrpath " $dir" ;;
+           esac
+         fi
+         deplibs="$deplib $deplibs"
+         continue
+         ;;
+       *.la)
+         func_resolve_sysroot "$deplib"
+         lib=$func_resolve_sysroot_result
+         ;;
+       *.$libext)
+         if test conv = "$pass"; then
+           deplibs="$deplib $deplibs"
+           continue
+         fi
+         case $linkmode in
+         lib)
+           # Linking convenience modules into shared libraries is allowed,
+           # but linking other static libraries is non-portable.
+           case " $dlpreconveniencelibs " in
+           *" $deplib "*) ;;
+           *)
+             valid_a_lib=false
+             case $deplibs_check_method in
+               match_pattern*)
+                 set dummy $deplibs_check_method; shift
+                 match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+                 if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
+                   | $EGREP "$match_pattern_regex" > /dev/null; then
+                   valid_a_lib=:
+                 fi
+               ;;
+               pass_all)
+                 valid_a_lib=:
+               ;;
+             esac
+             if $valid_a_lib; then
+               echo
+               $ECHO "*** Warning: Linking the shared library $output against the"
+               $ECHO "*** static library $deplib is not portable!"
+               deplibs="$deplib $deplibs"
+             else
+               echo
+               $ECHO "*** Warning: Trying to link with static lib archive $deplib."
+               echo "*** I have the capability to make that library automatically link in when"
+               echo "*** you link to this library.  But I can only do this if you have a"
+               echo "*** shared version of the library, which you do not appear to have"
+               echo "*** because the file extensions .$libext of this argument makes me believe"
+               echo "*** that it is just a static archive that I should not use here."
+             fi
+             ;;
+           esac
+           continue
+           ;;
+         prog)
+           if test link != "$pass"; then
+             deplibs="$deplib $deplibs"
+           else
+             compile_deplibs="$deplib $compile_deplibs"
+             finalize_deplibs="$deplib $finalize_deplibs"
+           fi
+           continue
+           ;;
+         esac # linkmode
+         ;; # *.$libext
+       *.lo | *.$objext)
+         if test conv = "$pass"; then
+           deplibs="$deplib $deplibs"
+         elif test prog = "$linkmode"; then
+           if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then
+             # If there is no dlopen support or we're linking statically,
+             # we need to preload.
+             func_append newdlprefiles " $deplib"
+             compile_deplibs="$deplib $compile_deplibs"
+             finalize_deplibs="$deplib $finalize_deplibs"
+           else
+             func_append newdlfiles " $deplib"
+           fi
+         fi
+         continue
+         ;;
+       %DEPLIBS%)
+         alldeplibs=:
+         continue
+         ;;
+       esac # case $deplib
+
+       $found || test -f "$lib" \
+         || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'"
+
+       # Check to see that this really is a libtool archive.
+       func_lalib_unsafe_p "$lib" \
+         || func_fatal_error "'$lib' is not a valid libtool archive"
+
+       func_dirname "$lib" "" "."
+       ladir=$func_dirname_result
+
+       dlname=
+       dlopen=
+       dlpreopen=
+       libdir=
+       library_names=
+       old_library=
+       inherited_linker_flags=
+       # If the library was installed with an old release of libtool,
+       # it will not redefine variables installed, or shouldnotlink
+       installed=yes
+       shouldnotlink=no
+       avoidtemprpath=
+
+
+       # Read the .la file
+       func_source "$lib"
+
+       # Convert "-framework foo" to "foo.ltframework"
+       if test -n "$inherited_linker_flags"; then
+         tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
+         for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+           case " $new_inherited_linker_flags " in
+             *" $tmp_inherited_linker_flag "*) ;;
+             *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";;
+           esac
+         done
+       fi
+       dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+       if test lib,link = "$linkmode,$pass" ||
+          test prog,scan = "$linkmode,$pass" ||
+          { test prog != "$linkmode" && test lib != "$linkmode"; }; then
+         test -n "$dlopen" && func_append dlfiles " $dlopen"
+         test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen"
+       fi
+
+       if test conv = "$pass"; then
+         # Only check for convenience libraries
+         deplibs="$lib $deplibs"
+         if test -z "$libdir"; then
+           if test -z "$old_library"; then
+             func_fatal_error "cannot find name of link library for '$lib'"
+           fi
+           # It is a libtool convenience library, so add in its objects.
+           func_append convenience " $ladir/$objdir/$old_library"
+           func_append old_convenience " $ladir/$objdir/$old_library"
+         elif test prog != "$linkmode" && test lib != "$linkmode"; then
+           func_fatal_error "'$lib' is not a convenience library"
+         fi
+         tmp_libs=
+         for deplib in $dependency_libs; do
+           deplibs="$deplib $deplibs"
+           if $opt_preserve_dup_deps; then
+             case "$tmp_libs " in
+             *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+             esac
+           fi
+           func_append tmp_libs " $deplib"
+         done
+         continue
+       fi # $pass = conv
+
+
+       # Get the name of the library we link against.
+       linklib=
+       if test -n "$old_library" &&
+          { test yes = "$prefer_static_libs" ||
+            test built,no = "$prefer_static_libs,$installed"; }; then
+         linklib=$old_library
+       else
+         for l in $old_library $library_names; do
+           linklib=$l
+         done
+       fi
+       if test -z "$linklib"; then
+         func_fatal_error "cannot find name of link library for '$lib'"
+       fi
+
+       # This library was specified with -dlopen.
+       if test dlopen = "$pass"; then
+         test -z "$libdir" \
+           && func_fatal_error "cannot -dlopen a convenience library: '$lib'"
+         if test -z "$dlname" ||
+            test yes != "$dlopen_support" ||
+            test no = "$build_libtool_libs"
+         then
+           # If there is no dlname, no dlopen support or we're linking
+           # statically, we need to preload.  We also need to preload any
+           # dependent libraries so libltdl's deplib preloader doesn't
+           # bomb out in the load deplibs phase.
+           func_append dlprefiles " $lib $dependency_libs"
+         else
+           func_append newdlfiles " $lib"
+         fi
+         continue
+       fi # $pass = dlopen
+
+       # We need an absolute path.
+       case $ladir in
+       [\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;;
+       *)
+         abs_ladir=`cd "$ladir" && pwd`
+         if test -z "$abs_ladir"; then
+           func_warning "cannot determine absolute directory name of '$ladir'"
+           func_warning "passing it literally to the linker, although it might fail"
+           abs_ladir=$ladir
+         fi
+         ;;
+       esac
+       func_basename "$lib"
+       laname=$func_basename_result
+
+       # Find the relevant object directory and library name.
+       if test yes = "$installed"; then
+         if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+           func_warning "library '$lib' was moved."
+           dir=$ladir
+           absdir=$abs_ladir
+           libdir=$abs_ladir
+         else
+           dir=$lt_sysroot$libdir
+           absdir=$lt_sysroot$libdir
+         fi
+         test yes = "$hardcode_automatic" && avoidtemprpath=yes
+       else
+         if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+           dir=$ladir
+           absdir=$abs_ladir
+           # Remove this search path later
+           func_append notinst_path " $abs_ladir"
+         else
+           dir=$ladir/$objdir
+           absdir=$abs_ladir/$objdir
+           # Remove this search path later
+           func_append notinst_path " $abs_ladir"
+         fi
+       fi # $installed = yes
+       func_stripname 'lib' '.la' "$laname"
+       name=$func_stripname_result
+
+       # This library was specified with -dlpreopen.
+       if test dlpreopen = "$pass"; then
+         if test -z "$libdir" && test prog = "$linkmode"; then
+           func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'"
+         fi
+         case $host in
+           # special handling for platforms with PE-DLLs.
+           *cygwin* | *mingw* | *cegcc* )
+             # Linker will automatically link against shared library if both
+             # static and shared are present.  Therefore, ensure we extract
+             # symbols from the import library if a shared library is present
+             # (otherwise, the dlopen module name will be incorrect).  We do
+             # this by putting the import library name into $newdlprefiles.
+             # We recover the dlopen module name by 'saving' the la file
+             # name in a special purpose variable, and (later) extracting the
+             # dlname from the la file.
+             if test -n "$dlname"; then
+               func_tr_sh "$dir/$linklib"
+               eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
+               func_append newdlprefiles " $dir/$linklib"
+             else
+               func_append newdlprefiles " $dir/$old_library"
+               # Keep a list of preopened convenience libraries to check
+               # that they are being used correctly in the link pass.
+               test -z "$libdir" && \
+                 func_append dlpreconveniencelibs " $dir/$old_library"
+             fi
+           ;;
+           * )
+             # Prefer using a static library (so that no silly _DYNAMIC symbols
+             # are required to link).
+             if test -n "$old_library"; then
+               func_append newdlprefiles " $dir/$old_library"
+               # Keep a list of preopened convenience libraries to check
+               # that they are being used correctly in the link pass.
+               test -z "$libdir" && \
+                 func_append dlpreconveniencelibs " $dir/$old_library"
+             # Otherwise, use the dlname, so that lt_dlopen finds it.
+             elif test -n "$dlname"; then
+               func_append newdlprefiles " $dir/$dlname"
+             else
+               func_append newdlprefiles " $dir/$linklib"
+             fi
+           ;;
+         esac
+       fi # $pass = dlpreopen
+
+       if test -z "$libdir"; then
+         # Link the convenience library
+         if test lib = "$linkmode"; then
+           deplibs="$dir/$old_library $deplibs"
+         elif test prog,link = "$linkmode,$pass"; then
+           compile_deplibs="$dir/$old_library $compile_deplibs"
+           finalize_deplibs="$dir/$old_library $finalize_deplibs"
+         else
+           deplibs="$lib $deplibs" # used for prog,scan pass
+         fi
+         continue
+       fi
+
+
+       if test prog = "$linkmode" && test link != "$pass"; then
+         func_append newlib_search_path " $ladir"
+         deplibs="$lib $deplibs"
+
+         linkalldeplibs=false
+         if test no != "$link_all_deplibs" || test -z "$library_names" ||
+            test no = "$build_libtool_libs"; then
+           linkalldeplibs=:
+         fi
+
+         tmp_libs=
+         for deplib in $dependency_libs; do
+           case $deplib in
+           -L*) func_stripname '-L' '' "$deplib"
+                func_resolve_sysroot "$func_stripname_result"
+                func_append newlib_search_path " $func_resolve_sysroot_result"
+                ;;
+           esac
+           # Need to link against all dependency_libs?
+           if $linkalldeplibs; then
+             deplibs="$deplib $deplibs"
+           else
+             # Need to hardcode shared library paths
+             # or/and link against static libraries
+             newdependency_libs="$deplib $newdependency_libs"
+           fi
+           if $opt_preserve_dup_deps; then
+             case "$tmp_libs " in
+             *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+             esac
+           fi
+           func_append tmp_libs " $deplib"
+         done # for deplib
+         continue
+       fi # $linkmode = prog...
+
+       if test prog,link = "$linkmode,$pass"; then
+         if test -n "$library_names" &&
+            { { test no = "$prefer_static_libs" ||
+                test built,yes = "$prefer_static_libs,$installed"; } ||
+              test -z "$old_library"; }; then
+           # We need to hardcode the library path
+           if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then
+             # Make sure the rpath contains only unique directories.
+             case $temp_rpath: in
+             *"$absdir:"*) ;;
+             *) func_append temp_rpath "$absdir:" ;;
+             esac
+           fi
+
+           # Hardcode the library path.
+           # Skip directories that are in the system default run-time
+           # search path.
+           case " $sys_lib_dlsearch_path " in
+           *" $absdir "*) ;;
+           *)
+             case "$compile_rpath " in
+             *" $absdir "*) ;;
+             *) func_append compile_rpath " $absdir" ;;
+             esac
+             ;;
+           esac
+           case " $sys_lib_dlsearch_path " in
+           *" $libdir "*) ;;
+           *)
+             case "$finalize_rpath " in
+             *" $libdir "*) ;;
+             *) func_append finalize_rpath " $libdir" ;;
+             esac
+             ;;
+           esac
+         fi # $linkmode,$pass = prog,link...
+
+         if $alldeplibs &&
+            { test pass_all = "$deplibs_check_method" ||
+              { test yes = "$build_libtool_libs" &&
+                test -n "$library_names"; }; }; then
+           # We only need to search for static libraries
+           continue
+         fi
+       fi
+
+       link_static=no # Whether the deplib will be linked statically
+       use_static_libs=$prefer_static_libs
+       if test built = "$use_static_libs" && test yes = "$installed"; then
+         use_static_libs=no
+       fi
+       if test -n "$library_names" &&
+          { test no = "$use_static_libs" || test -z "$old_library"; }; then
+         case $host in
+         *cygwin* | *mingw* | *cegcc* | *os2*)
+             # No point in relinking DLLs because paths are not encoded
+             func_append notinst_deplibs " $lib"
+             need_relink=no
+           ;;
+         *)
+           if test no = "$installed"; then
+             func_append notinst_deplibs " $lib"
+             need_relink=yes
+           fi
+           ;;
+         esac
+         # This is a shared library
+
+         # Warn about portability, can't link against -module's on some
+         # systems (darwin).  Don't bleat about dlopened modules though!
+         dlopenmodule=
+         for dlpremoduletest in $dlprefiles; do
+           if test "X$dlpremoduletest" = "X$lib"; then
+             dlopenmodule=$dlpremoduletest
+             break
+           fi
+         done
+         if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then
+           echo
+           if test prog = "$linkmode"; then
+             $ECHO "*** Warning: Linking the executable $output against the loadable module"
+           else
+             $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+           fi
+           $ECHO "*** $linklib is not portable!"
+         fi
+         if test lib = "$linkmode" &&
+            test yes = "$hardcode_into_libs"; then
+           # Hardcode the library path.
+           # Skip directories that are in the system default run-time
+           # search path.
+           case " $sys_lib_dlsearch_path " in
+           *" $absdir "*) ;;
+           *)
+             case "$compile_rpath " in
+             *" $absdir "*) ;;
+             *) func_append compile_rpath " $absdir" ;;
+             esac
+             ;;
+           esac
+           case " $sys_lib_dlsearch_path " in
+           *" $libdir "*) ;;
+           *)
+             case "$finalize_rpath " in
+             *" $libdir "*) ;;
+             *) func_append finalize_rpath " $libdir" ;;
+             esac
+             ;;
+           esac
+         fi
+
+         if test -n "$old_archive_from_expsyms_cmds"; then
+           # figure out the soname
+           set dummy $library_names
+           shift
+           realname=$1
+           shift
+           libname=`eval "\\$ECHO \"$libname_spec\""`
+           # use dlname if we got it. it's perfectly good, no?
+           if test -n "$dlname"; then
+             soname=$dlname
+           elif test -n "$soname_spec"; then
+             # bleh windows
+             case $host in
+             *cygwin* | mingw* | *cegcc* | *os2*)
+               func_arith $current - $age
+               major=$func_arith_result
+               versuffix=-$major
+               ;;
+             esac
+             eval soname=\"$soname_spec\"
+           else
+             soname=$realname
+           fi
+
+           # Make a new name for the extract_expsyms_cmds to use
+           soroot=$soname
+           func_basename "$soroot"
+           soname=$func_basename_result
+           func_stripname 'lib' '.dll' "$soname"
+           newlib=libimp-$func_stripname_result.a
+
+           # If the library has no export list, then create one now
+           if test -f "$output_objdir/$soname-def"; then :
+           else
+             func_verbose "extracting exported symbol list from '$soname'"
+             func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+           fi
+
+           # Create $newlib
+           if test -f "$output_objdir/$newlib"; then :; else
+             func_verbose "generating import library for '$soname'"
+             func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+           fi
+           # make sure the library variables are pointing to the new library
+           dir=$output_objdir
+           linklib=$newlib
+         fi # test -n "$old_archive_from_expsyms_cmds"
+
+         if test prog = "$linkmode" || test relink != "$opt_mode"; then
+           add_shlibpath=
+           add_dir=
+           add=
+           lib_linked=yes
+           case $hardcode_action in
+           immediate | unsupported)
+             if test no = "$hardcode_direct"; then
+               add=$dir/$linklib
+               case $host in
+                 *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;;
+                 *-*-sysv4*uw2*) add_dir=-L$dir ;;
+                 *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+                   *-*-unixware7*) add_dir=-L$dir ;;
+                 *-*-darwin* )
+                   # if the lib is a (non-dlopened) module then we cannot
+                   # link against it, someone is ignoring the earlier warnings
+                   if /usr/bin/file -L $add 2> /dev/null |
+                        $GREP ": [^:]* bundle" >/dev/null; then
+                     if test "X$dlopenmodule" != "X$lib"; then
+                       $ECHO "*** Warning: lib $linklib is a module, not a shared library"
+                       if test -z "$old_library"; then
+                         echo
+                         echo "*** And there doesn't seem to be a static archive available"
+                         echo "*** The link will probably fail, sorry"
+                       else
+                         add=$dir/$old_library
+                       fi
+                     elif test -n "$old_library"; then
+                       add=$dir/$old_library
+                     fi
+                   fi
+               esac
+             elif test no = "$hardcode_minus_L"; then
+               case $host in
+               *-*-sunos*) add_shlibpath=$dir ;;
+               esac
+               add_dir=-L$dir
+               add=-l$name
+             elif test no = "$hardcode_shlibpath_var"; then
+               add_shlibpath=$dir
+               add=-l$name
+             else
+               lib_linked=no
+             fi
+             ;;
+           relink)
+             if test yes = "$hardcode_direct" &&
+                test no = "$hardcode_direct_absolute"; then
+               add=$dir/$linklib
+             elif test yes = "$hardcode_minus_L"; then
+               add_dir=-L$absdir
+               # Try looking first in the location we're being installed to.
+               if test -n "$inst_prefix_dir"; then
+                 case $libdir in
+                   [\\/]*)
+                     func_append add_dir " -L$inst_prefix_dir$libdir"
+                     ;;
+                 esac
+               fi
+               add=-l$name
+             elif test yes = "$hardcode_shlibpath_var"; then
+               add_shlibpath=$dir
+               add=-l$name
+             else
+               lib_linked=no
+             fi
+             ;;
+           *) lib_linked=no ;;
+           esac
+
+           if test yes != "$lib_linked"; then
+             func_fatal_configuration "unsupported hardcode properties"
+           fi
+
+           if test -n "$add_shlibpath"; then
+             case :$compile_shlibpath: in
+             *":$add_shlibpath:"*) ;;
+             *) func_append compile_shlibpath "$add_shlibpath:" ;;
+             esac
+           fi
+           if test prog = "$linkmode"; then
+             test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+             test -n "$add" && compile_deplibs="$add $compile_deplibs"
+           else
+             test -n "$add_dir" && deplibs="$add_dir $deplibs"
+             test -n "$add" && deplibs="$add $deplibs"
+             if test yes != "$hardcode_direct" &&
+                test yes != "$hardcode_minus_L" &&
+                test yes = "$hardcode_shlibpath_var"; then
+               case :$finalize_shlibpath: in
+               *":$libdir:"*) ;;
+               *) func_append finalize_shlibpath "$libdir:" ;;
+               esac
+             fi
+           fi
+         fi
+
+         if test prog = "$linkmode" || test relink = "$opt_mode"; then
+           add_shlibpath=
+           add_dir=
+           add=
+           # Finalize command for both is simple: just hardcode it.
+           if test yes = "$hardcode_direct" &&
+              test no = "$hardcode_direct_absolute"; then
+             add=$libdir/$linklib
+           elif test yes = "$hardcode_minus_L"; then
+             add_dir=-L$libdir
+             add=-l$name
+           elif test yes = "$hardcode_shlibpath_var"; then
+             case :$finalize_shlibpath: in
+             *":$libdir:"*) ;;
+             *) func_append finalize_shlibpath "$libdir:" ;;
+             esac
+             add=-l$name
+           elif test yes = "$hardcode_automatic"; then
+             if test -n "$inst_prefix_dir" &&
+                test -f "$inst_prefix_dir$libdir/$linklib"; then
+               add=$inst_prefix_dir$libdir/$linklib
+             else
+               add=$libdir/$linklib
+             fi
+           else
+             # We cannot seem to hardcode it, guess we'll fake it.
+             add_dir=-L$libdir
+             # Try looking first in the location we're being installed to.
+             if test -n "$inst_prefix_dir"; then
+               case $libdir in
+                 [\\/]*)
+                   func_append add_dir " -L$inst_prefix_dir$libdir"
+                   ;;
+               esac
+             fi
+             add=-l$name
+           fi
+
+           if test prog = "$linkmode"; then
+             test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+             test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+           else
+             test -n "$add_dir" && deplibs="$add_dir $deplibs"
+             test -n "$add" && deplibs="$add $deplibs"
+           fi
+         fi
+       elif test prog = "$linkmode"; then
+         # Here we assume that one of hardcode_direct or hardcode_minus_L
+         # is not unsupported.  This is valid on all known static and
+         # shared platforms.
+         if test unsupported != "$hardcode_direct"; then
+           test -n "$old_library" && linklib=$old_library
+           compile_deplibs="$dir/$linklib $compile_deplibs"
+           finalize_deplibs="$dir/$linklib $finalize_deplibs"
+         else
+           compile_deplibs="-l$name -L$dir $compile_deplibs"
+           finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+         fi
+       elif test yes = "$build_libtool_libs"; then
+         # Not a shared library
+         if test pass_all != "$deplibs_check_method"; then
+           # We're trying link a shared library against a static one
+           # but the system doesn't support it.
+
+           # Just print a warning and add the library to dependency_libs so
+           # that the program can be linked against the static library.
+           echo
+           $ECHO "*** Warning: This system cannot link to static lib archive $lib."
+           echo "*** I have the capability to make that library automatically link in when"
+           echo "*** you link to this library.  But I can only do this if you have a"
+           echo "*** shared version of the library, which you do not appear to have."
+           if test yes = "$module"; then
+             echo "*** But as you try to build a module library, libtool will still create "
+             echo "*** a static module, that should work as long as the dlopening application"
+             echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+             if test -z "$global_symbol_pipe"; then
+               echo
+               echo "*** However, this would only work if libtool was able to extract symbol"
+               echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
+               echo "*** not find such a program.  So, this module is probably useless."
+               echo "*** 'nm' from GNU binutils and a full rebuild may help."
+             fi
+             if test no = "$build_old_libs"; then
+               build_libtool_libs=module
+               build_old_libs=yes
+             else
+               build_libtool_libs=no
+             fi
+           fi
+         else
+           deplibs="$dir/$old_library $deplibs"
+           link_static=yes
+         fi
+       fi # link shared/static library?
+
+       if test lib = "$linkmode"; then
+         if test -n "$dependency_libs" &&
+            { test yes != "$hardcode_into_libs" ||
+              test yes = "$build_old_libs" ||
+              test yes = "$link_static"; }; then
+           # Extract -R from dependency_libs
+           temp_deplibs=
+           for libdir in $dependency_libs; do
+             case $libdir in
+             -R*) func_stripname '-R' '' "$libdir"
+                  temp_xrpath=$func_stripname_result
+                  case " $xrpath " in
+                  *" $temp_xrpath "*) ;;
+                  *) func_append xrpath " $temp_xrpath";;
+                  esac;;
+             *) func_append temp_deplibs " $libdir";;
+             esac
+           done
+           dependency_libs=$temp_deplibs
+         fi
+
+         func_append newlib_search_path " $absdir"
+         # Link against this library
+         test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+         # ... and its dependency_libs
+         tmp_libs=
+         for deplib in $dependency_libs; do
+           newdependency_libs="$deplib $newdependency_libs"
+           case $deplib in
+              -L*) func_stripname '-L' '' "$deplib"
+                   func_resolve_sysroot "$func_stripname_result";;
+              *) func_resolve_sysroot "$deplib" ;;
+            esac
+           if $opt_preserve_dup_deps; then
+             case "$tmp_libs " in
+             *" $func_resolve_sysroot_result "*)
+                func_append specialdeplibs " $func_resolve_sysroot_result" ;;
+             esac
+           fi
+           func_append tmp_libs " $func_resolve_sysroot_result"
+         done
+
+         if test no != "$link_all_deplibs"; then
+           # Add the search paths of all dependency libraries
+           for deplib in $dependency_libs; do
+             path=
+             case $deplib in
+             -L*) path=$deplib ;;
+             *.la)
+               func_resolve_sysroot "$deplib"
+               deplib=$func_resolve_sysroot_result
+               func_dirname "$deplib" "" "."
+               dir=$func_dirname_result
+               # We need an absolute path.
+               case $dir in
+               [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;;
+               *)
+                 absdir=`cd "$dir" && pwd`
+                 if test -z "$absdir"; then
+                   func_warning "cannot determine absolute directory name of '$dir'"
+                   absdir=$dir
+                 fi
+                 ;;
+               esac
+               if $GREP "^installed=no" $deplib > /dev/null; then
+               case $host in
+               *-*-darwin*)
+                 depdepl=
+                 eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+                 if test -n "$deplibrary_names"; then
+                   for tmp in $deplibrary_names; do
+                     depdepl=$tmp
+                   done
+                   if test -f "$absdir/$objdir/$depdepl"; then
+                     depdepl=$absdir/$objdir/$depdepl
+                     darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+                      if test -z "$darwin_install_name"; then
+                          darwin_install_name=`$OTOOL64 -L $depdepl  | awk '{if (NR == 2) {print $1;exit}}'`
+                      fi
+                     func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl"
+                     func_append linker_flags " -dylib_file $darwin_install_name:$depdepl"
+                     path=
+                   fi
+                 fi
+                 ;;
+               *)
+                 path=-L$absdir/$objdir
+                 ;;
+               esac
+               else
+                 eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+                 test -z "$libdir" && \
+                   func_fatal_error "'$deplib' is not a valid libtool archive"
+                 test "$absdir" != "$libdir" && \
+                   func_warning "'$deplib' seems to be moved"
+
+                 path=-L$absdir
+               fi
+               ;;
+             esac
+             case " $deplibs " in
+             *" $path "*) ;;
+             *) deplibs="$path $deplibs" ;;
+             esac
+           done
+         fi # link_all_deplibs != no
+       fi # linkmode = lib
+      done # for deplib in $libs
+      if test link = "$pass"; then
+       if test prog = "$linkmode"; then
+         compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+         finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+       else
+         compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+       fi
+      fi
+      dependency_libs=$newdependency_libs
+      if test dlpreopen = "$pass"; then
+       # Link the dlpreopened libraries before other libraries
+       for deplib in $save_deplibs; do
+         deplibs="$deplib $deplibs"
+       done
+      fi
+      if test dlopen != "$pass"; then
+       test conv = "$pass" || {
+         # Make sure lib_search_path contains only unique directories.
+         lib_search_path=
+         for dir in $newlib_search_path; do
+           case "$lib_search_path " in
+           *" $dir "*) ;;
+           *) func_append lib_search_path " $dir" ;;
+           esac
+         done
+         newlib_search_path=
+       }
+
+       if test prog,link = "$linkmode,$pass"; then
+         vars="compile_deplibs finalize_deplibs"
+       else
+         vars=deplibs
+       fi
+       for var in $vars dependency_libs; do
+         # Add libraries to $var in reverse order
+         eval tmp_libs=\"\$$var\"
+         new_libs=
+         for deplib in $tmp_libs; do
+           # FIXME: Pedantically, this is the right thing to do, so
+           #        that some nasty dependency loop isn't accidentally
+           #        broken:
+           #new_libs="$deplib $new_libs"
+           # Pragmatically, this seems to cause very few problems in
+           # practice:
+           case $deplib in
+           -L*) new_libs="$deplib $new_libs" ;;
+           -R*) ;;
+           *)
+             # And here is the reason: when a library appears more
+             # than once as an explicit dependence of a library, or
+             # is implicitly linked in more than once by the
+             # compiler, it is considered special, and multiple
+             # occurrences thereof are not removed.  Compare this
+             # with having the same library being listed as a
+             # dependency of multiple other libraries: in this case,
+             # we know (pedantically, we assume) the library does not
+             # need to be listed more than once, so we keep only the
+             # last copy.  This is not always right, but it is rare
+             # enough that we require users that really mean to play
+             # such unportable linking tricks to link the library
+             # using -Wl,-lname, so that libtool does not consider it
+             # for duplicate removal.
+             case " $specialdeplibs " in
+             *" $deplib "*) new_libs="$deplib $new_libs" ;;
+             *)
+               case " $new_libs " in
+               *" $deplib "*) ;;
+               *) new_libs="$deplib $new_libs" ;;
+               esac
+               ;;
+             esac
+             ;;
+           esac
+         done
+         tmp_libs=
+         for deplib in $new_libs; do
+           case $deplib in
+           -L*)
+             case " $tmp_libs " in
+             *" $deplib "*) ;;
+             *) func_append tmp_libs " $deplib" ;;
+             esac
+             ;;
+           *) func_append tmp_libs " $deplib" ;;
+           esac
+         done
+         eval $var=\"$tmp_libs\"
+       done # for var
+      fi
+
+      # Add Sun CC postdeps if required:
+      test CXX = "$tagname" && {
+        case $host_os in
+        linux*)
+          case `$CC -V 2>&1 | sed 5q` in
+          *Sun\ C*) # Sun C++ 5.9
+            func_suncc_cstd_abi
+
+            if test no != "$suncc_use_cstd_abi"; then
+              func_append postdeps ' -library=Cstd -library=Crun'
+            fi
+            ;;
+          esac
+          ;;
+
+        solaris*)
+          func_cc_basename "$CC"
+          case $func_cc_basename_result in
+          CC* | sunCC*)
+            func_suncc_cstd_abi
+
+            if test no != "$suncc_use_cstd_abi"; then
+              func_append postdeps ' -library=Cstd -library=Crun'
+            fi
+            ;;
+          esac
+          ;;
+        esac
+      }
+
+      # Last step: remove runtime libs from dependency_libs
+      # (they stay in deplibs)
+      tmp_libs=
+      for i in $dependency_libs; do
+       case " $predeps $postdeps $compiler_lib_search_path " in
+       *" $i "*)
+         i=
+         ;;
+       esac
+       if test -n "$i"; then
+         func_append tmp_libs " $i"
+       fi
+      done
+      dependency_libs=$tmp_libs
+    done # for pass
+    if test prog = "$linkmode"; then
+      dlfiles=$newdlfiles
+    fi
+    if test prog = "$linkmode" || test lib = "$linkmode"; then
+      dlprefiles=$newdlprefiles
+    fi
+
+    case $linkmode in
+    oldlib)
+      if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+       func_warning "'-dlopen' is ignored for archives"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+       func_warning "'-l' and '-L' are ignored for archives" ;;
+      esac
+
+      test -n "$rpath" && \
+       func_warning "'-rpath' is ignored for archives"
+
+      test -n "$xrpath" && \
+       func_warning "'-R' is ignored for archives"
+
+      test -n "$vinfo" && \
+       func_warning "'-version-info/-version-number' is ignored for archives"
+
+      test -n "$release" && \
+       func_warning "'-release' is ignored for archives"
+
+      test -n "$export_symbols$export_symbols_regex" && \
+       func_warning "'-export-symbols' is ignored for archives"
+
+      # Now set the variables for building old libraries.
+      build_libtool_libs=no
+      oldlibs=$output
+      func_append objs "$old_deplibs"
+      ;;
+
+    lib)
+      # Make sure we only generate libraries of the form 'libNAME.la'.
+      case $outputname in
+      lib*)
+       func_stripname 'lib' '.la' "$outputname"
+       name=$func_stripname_result
+       eval shared_ext=\"$shrext_cmds\"
+       eval libname=\"$libname_spec\"
+       ;;
+      *)
+       test no = "$module" \
+         && func_fatal_help "libtool library '$output' must begin with 'lib'"
+
+       if test no != "$need_lib_prefix"; then
+         # Add the "lib" prefix for modules if required
+         func_stripname '' '.la' "$outputname"
+         name=$func_stripname_result
+         eval shared_ext=\"$shrext_cmds\"
+         eval libname=\"$libname_spec\"
+       else
+         func_stripname '' '.la' "$outputname"
+         libname=$func_stripname_result
+       fi
+       ;;
+      esac
+
+      if test -n "$objs"; then
+       if test pass_all != "$deplibs_check_method"; then
+         func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs"
+       else
+         echo
+         $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+         $ECHO "*** objects $objs is not portable!"
+         func_append libobjs " $objs"
+       fi
+      fi
+
+      test no = "$dlself" \
+       || func_warning "'-dlopen self' is ignored for libtool libraries"
+
+      set dummy $rpath
+      shift
+      test 1 -lt "$#" \
+       && func_warning "ignoring multiple '-rpath's for a libtool library"
+
+      install_libdir=$1
+
+      oldlibs=
+      if test -z "$rpath"; then
+       if test yes = "$build_libtool_libs"; then
+         # Building a libtool convenience library.
+         # Some compilers have problems with a '.al' extension so
+         # convenience libraries should have the same extension an
+         # archive normally would.
+         oldlibs="$output_objdir/$libname.$libext $oldlibs"
+         build_libtool_libs=convenience
+         build_old_libs=yes
+       fi
+
+       test -n "$vinfo" && \
+         func_warning "'-version-info/-version-number' is ignored for convenience libraries"
+
+       test -n "$release" && \
+         func_warning "'-release' is ignored for convenience libraries"
+      else
+
+       # Parse the version information argument.
+       save_ifs=$IFS; IFS=:
+       set dummy $vinfo 0 0 0
+       shift
+       IFS=$save_ifs
+
+       test -n "$7" && \
+         func_fatal_help "too many parameters to '-version-info'"
+
+       # convert absolute version numbers to libtool ages
+       # this retains compatibility with .la files and attempts
+       # to make the code below a bit more comprehensible
+
+       case $vinfo_number in
+       yes)
+         number_major=$1
+         number_minor=$2
+         number_revision=$3
+         #
+         # There are really only two kinds -- those that
+         # use the current revision as the major version
+         # and those that subtract age and use age as
+         # a minor version.  But, then there is irix
+         # that has an extra 1 added just for fun
+         #
+         case $version_type in
+         # correct linux to gnu/linux during the next big refactor
+         darwin|freebsd-elf|linux|osf|windows|none)
+           func_arith $number_major + $number_minor
+           current=$func_arith_result
+           age=$number_minor
+           revision=$number_revision
+           ;;
+         freebsd-aout|qnx|sunos)
+           current=$number_major
+           revision=$number_minor
+           age=0
+           ;;
+         irix|nonstopux)
+           func_arith $number_major + $number_minor
+           current=$func_arith_result
+           age=$number_minor
+           revision=$number_minor
+           lt_irix_increment=no
+           ;;
+         esac
+         ;;
+       no)
+         current=$1
+         revision=$2
+         age=$3
+         ;;
+       esac
+
+       # Check that each of the things are valid numbers.
+       case $current in
+       0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+       *)
+         func_error "CURRENT '$current' must be a nonnegative integer"
+         func_fatal_error "'$vinfo' is not valid version information"
+         ;;
+       esac
+
+       case $revision in
+       0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+       *)
+         func_error "REVISION '$revision' must be a nonnegative integer"
+         func_fatal_error "'$vinfo' is not valid version information"
+         ;;
+       esac
+
+       case $age in
+       0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+       *)
+         func_error "AGE '$age' must be a nonnegative integer"
+         func_fatal_error "'$vinfo' is not valid version information"
+         ;;
+       esac
+
+       if test "$age" -gt "$current"; then
+         func_error "AGE '$age' is greater than the current interface number '$current'"
+         func_fatal_error "'$vinfo' is not valid version information"
+       fi
+
+       # Calculate the version variables.
+       major=
+       versuffix=
+       verstring=
+       case $version_type in
+       none) ;;
+
+       darwin)
+         # Like Linux, but with the current version available in
+         # verstring for coding it into the library header
+         func_arith $current - $age
+         major=.$func_arith_result
+         versuffix=$major.$age.$revision
+         # Darwin ld doesn't like 0 for these options...
+         func_arith $current + 1
+         minor_current=$func_arith_result
+         xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
+         verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+          # On Darwin other compilers
+          case $CC in
+              nagfor*)
+                  verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
+                  ;;
+              *)
+                  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+                  ;;
+          esac
+         ;;
+
+       freebsd-aout)
+         major=.$current
+         versuffix=.$current.$revision
+         ;;
+
+       freebsd-elf)
+         func_arith $current - $age
+         major=.$func_arith_result
+         versuffix=$major.$age.$revision
+         ;;
+
+       irix | nonstopux)
+         if test no = "$lt_irix_increment"; then
+           func_arith $current - $age
+         else
+           func_arith $current - $age + 1
+         fi
+         major=$func_arith_result
+
+         case $version_type in
+           nonstopux) verstring_prefix=nonstopux ;;
+           *)         verstring_prefix=sgi ;;
+         esac
+         verstring=$verstring_prefix$major.$revision
+
+         # Add in all the interfaces that we are compatible with.
+         loop=$revision
+         while test 0 -ne "$loop"; do
+           func_arith $revision - $loop
+           iface=$func_arith_result
+           func_arith $loop - 1
+           loop=$func_arith_result
+           verstring=$verstring_prefix$major.$iface:$verstring
+         done
+
+         # Before this point, $major must not contain '.'.
+         major=.$major
+         versuffix=$major.$revision
+         ;;
+
+       linux) # correct to gnu/linux during the next big refactor
+         func_arith $current - $age
+         major=.$func_arith_result
+         versuffix=$major.$age.$revision
+         ;;
+
+       osf)
+         func_arith $current - $age
+         major=.$func_arith_result
+         versuffix=.$current.$age.$revision
+         verstring=$current.$age.$revision
+
+         # Add in all the interfaces that we are compatible with.
+         loop=$age
+         while test 0 -ne "$loop"; do
+           func_arith $current - $loop
+           iface=$func_arith_result
+           func_arith $loop - 1
+           loop=$func_arith_result
+           verstring=$verstring:$iface.0
+         done
+
+         # Make executables depend on our current version.
+         func_append verstring ":$current.0"
+         ;;
+
+       qnx)
+         major=.$current
+         versuffix=.$current
+         ;;
+
+       sco)
+         major=.$current
+         versuffix=.$current
+         ;;
+
+       sunos)
+         major=.$current
+         versuffix=.$current.$revision
+         ;;
+
+       windows)
+         # Use '-' rather than '.', since we only want one
+         # extension on DOS 8.3 file systems.
+         func_arith $current - $age
+         major=$func_arith_result
+         versuffix=-$major
+         ;;
+
+       *)
+         func_fatal_configuration "unknown library version type '$version_type'"
+         ;;
+       esac
+
+       # Clear the version info if we defaulted, and they specified a release.
+       if test -z "$vinfo" && test -n "$release"; then
+         major=
+         case $version_type in
+         darwin)
+           # we can't check for "0.0" in archive_cmds due to quoting
+           # problems, so we reset it completely
+           verstring=
+           ;;
+         *)
+           verstring=0.0
+           ;;
+         esac
+         if test no = "$need_version"; then
+           versuffix=
+         else
+           versuffix=.0.0
+         fi
+       fi
+
+       # Remove version info from name if versioning should be avoided
+       if test yes,no = "$avoid_version,$need_version"; then
+         major=
+         versuffix=
+         verstring=
+       fi
+
+       # Check to see if the archive will have undefined symbols.
+       if test yes = "$allow_undefined"; then
+         if test unsupported = "$allow_undefined_flag"; then
+           if test yes = "$build_old_libs"; then
+             func_warning "undefined symbols not allowed in $host shared libraries; building static only"
+             build_libtool_libs=no
+           else
+             func_fatal_error "can't build $host shared library unless -no-undefined is specified"
+           fi
+         fi
+       else
+         # Don't allow undefined symbols.
+         allow_undefined_flag=$no_undefined_flag
+       fi
+
+      fi
+
+      func_generate_dlsyms "$libname" "$libname" :
+      func_append libobjs " $symfileobj"
+      test " " = "$libobjs" && libobjs=
+
+      if test relink != "$opt_mode"; then
+       # Remove our outputs, but don't remove object files since they
+       # may have been created when compiling PIC objects.
+       removelist=
+       tempremovelist=`$ECHO "$output_objdir/*"`
+       for p in $tempremovelist; do
+         case $p in
+           *.$objext | *.gcno)
+              ;;
+           $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*)
+              if test -n "$precious_files_regex"; then
+                if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+                then
+                  continue
+                fi
+              fi
+              func_append removelist " $p"
+              ;;
+           *) ;;
+         esac
+       done
+       test -n "$removelist" && \
+         func_show_eval "${RM}r \$removelist"
+      fi
+
+      # Now set the variables for building old libraries.
+      if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then
+       func_append oldlibs " $output_objdir/$libname.$libext"
+
+       # Transform .lo files to .o files.
+       oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP`
+      fi
+
+      # Eliminate all temporary directories.
+      #for path in $notinst_path; do
+      #        lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+      #        deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+      #        dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
+      #done
+
+      if test -n "$xrpath"; then
+       # If the user specified any rpath flags, then add them.
+       temp_xrpath=
+       for libdir in $xrpath; do
+         func_replace_sysroot "$libdir"
+         func_append temp_xrpath " -R$func_replace_sysroot_result"
+         case "$finalize_rpath " in
+         *" $libdir "*) ;;
+         *) func_append finalize_rpath " $libdir" ;;
+         esac
+       done
+       if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then
+         dependency_libs="$temp_xrpath $dependency_libs"
+       fi
+      fi
+
+      # Make sure dlfiles contains only unique files that won't be dlpreopened
+      old_dlfiles=$dlfiles
+      dlfiles=
+      for lib in $old_dlfiles; do
+       case " $dlprefiles $dlfiles " in
+       *" $lib "*) ;;
+       *) func_append dlfiles " $lib" ;;
+       esac
+      done
+
+      # Make sure dlprefiles contains only unique files
+      old_dlprefiles=$dlprefiles
+      dlprefiles=
+      for lib in $old_dlprefiles; do
+       case "$dlprefiles " in
+       *" $lib "*) ;;
+       *) func_append dlprefiles " $lib" ;;
+       esac
+      done
+
+      if test yes = "$build_libtool_libs"; then
+       if test -n "$rpath"; then
+         case $host in
+         *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+           # these systems don't actually have a c library (as such)!
+           ;;
+         *-*-rhapsody* | *-*-darwin1.[012])
+           # Rhapsody C library is in the System framework
+           func_append deplibs " System.ltframework"
+           ;;
+         *-*-netbsd*)
+           # Don't link with libc until the a.out ld.so is fixed.
+           ;;
+         *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+           # Do not include libc due to us having libc/libc_r.
+           ;;
+         *-*-sco3.2v5* | *-*-sco5v6*)
+           # Causes problems with __ctype
+           ;;
+         *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+           # Compiler inserts libc in the correct place for threads to work
+           ;;
+         *)
+           # Add libc to deplibs on all other systems if necessary.
+           if test yes = "$build_libtool_need_lc"; then
+             func_append deplibs " -lc"
+           fi
+           ;;
+         esac
+       fi
+
+       # Transform deplibs into only deplibs that can be linked in shared.
+       name_save=$name
+       libname_save=$libname
+       release_save=$release
+       versuffix_save=$versuffix
+       major_save=$major
+       # I'm not sure if I'm treating the release correctly.  I think
+       # release should show up in the -l (ie -lgmp5) so we don't want to
+       # add it in twice.  Is that correct?
+       release=
+       versuffix=
+       major=
+       newdeplibs=
+       droppeddeps=no
+       case $deplibs_check_method in
+       pass_all)
+         # Don't check for shared/static.  Everything works.
+         # This might be a little naive.  We might want to check
+         # whether the library exists or not.  But this is on
+         # osf3 & osf4 and I'm not really sure... Just
+         # implementing what was already the behavior.
+         newdeplibs=$deplibs
+         ;;
+       test_compile)
+         # This code stresses the "libraries are programs" paradigm to its
+         # limits. Maybe even breaks it.  We compile a program, linking it
+         # against the deplibs as a proxy for the library.  Then we can check
+         # whether they linked in statically or dynamically with ldd.
+         $opt_dry_run || $RM conftest.c
+         cat > conftest.c <<EOF
+         int main() { return 0; }
+EOF
+         $opt_dry_run || $RM conftest
+         if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+           ldd_output=`ldd conftest`
+           for i in $deplibs; do
+             case $i in
+             -l*)
+               func_stripname -l '' "$i"
+               name=$func_stripname_result
+               if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+                 case " $predeps $postdeps " in
+                 *" $i "*)
+                   func_append newdeplibs " $i"
+                   i=
+                   ;;
+                 esac
+               fi
+               if test -n "$i"; then
+                 libname=`eval "\\$ECHO \"$libname_spec\""`
+                 deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+                 set dummy $deplib_matches; shift
+                 deplib_match=$1
+                 if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
+                   func_append newdeplibs " $i"
+                 else
+                   droppeddeps=yes
+                   echo
+                   $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+                   echo "*** I have the capability to make that library automatically link in when"
+                   echo "*** you link to this library.  But I can only do this if you have a"
+                   echo "*** shared version of the library, which I believe you do not have"
+                   echo "*** because a test_compile did reveal that the linker did not use it for"
+                   echo "*** its dynamic dependency list that programs get resolved with at runtime."
+                 fi
+               fi
+               ;;
+             *)
+               func_append newdeplibs " $i"
+               ;;
+             esac
+           done
+         else
+           # Error occurred in the first compile.  Let's try to salvage
+           # the situation: Compile a separate program for each library.
+           for i in $deplibs; do
+             case $i in
+             -l*)
+               func_stripname -l '' "$i"
+               name=$func_stripname_result
+               $opt_dry_run || $RM conftest
+               if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+                 ldd_output=`ldd conftest`
+                 if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+                   case " $predeps $postdeps " in
+                   *" $i "*)
+                     func_append newdeplibs " $i"
+                     i=
+                     ;;
+                   esac
+                 fi
+                 if test -n "$i"; then
+                   libname=`eval "\\$ECHO \"$libname_spec\""`
+                   deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+                   set dummy $deplib_matches; shift
+                   deplib_match=$1
+                   if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
+                     func_append newdeplibs " $i"
+                   else
+                     droppeddeps=yes
+                     echo
+                     $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+                     echo "*** I have the capability to make that library automatically link in when"
+                     echo "*** you link to this library.  But I can only do this if you have a"
+                     echo "*** shared version of the library, which you do not appear to have"
+                     echo "*** because a test_compile did reveal that the linker did not use this one"
+                     echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+                   fi
+                 fi
+               else
+                 droppeddeps=yes
+                 echo
+                 $ECHO "*** Warning!  Library $i is needed by this library but I was not able to"
+                 echo "*** make it link in!  You will probably need to install it or some"
+                 echo "*** library that it depends on before this library will be fully"
+                 echo "*** functional.  Installing it before continuing would be even better."
+               fi
+               ;;
+             *)
+               func_append newdeplibs " $i"
+               ;;
+             esac
+           done
+         fi
+         ;;
+       file_magic*)
+         set dummy $deplibs_check_method; shift
+         file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+         for a_deplib in $deplibs; do
+           case $a_deplib in
+           -l*)
+             func_stripname -l '' "$a_deplib"
+             name=$func_stripname_result
+             if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+               case " $predeps $postdeps " in
+               *" $a_deplib "*)
+                 func_append newdeplibs " $a_deplib"
+                 a_deplib=
+                 ;;
+               esac
+             fi
+             if test -n "$a_deplib"; then
+               libname=`eval "\\$ECHO \"$libname_spec\""`
+               if test -n "$file_magic_glob"; then
+                 libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob`
+               else
+                 libnameglob=$libname
+               fi
+               test yes = "$want_nocaseglob" && nocaseglob=`shopt -p nocaseglob`
+               for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+                 if test yes = "$want_nocaseglob"; then
+                   shopt -s nocaseglob
+                   potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+                   $nocaseglob
+                 else
+                   potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+                 fi
+                 for potent_lib in $potential_libs; do
+                     # Follow soft links.
+                     if ls -lLd "$potent_lib" 2>/dev/null |
+                        $GREP " -> " >/dev/null; then
+                       continue
+                     fi
+                     # The statement above tries to avoid entering an
+                     # endless loop below, in case of cyclic links.
+                     # We might still enter an endless loop, since a link
+                     # loop can be closed while we follow links,
+                     # but so what?
+                     potlib=$potent_lib
+                     while test -h "$potlib" 2>/dev/null; do
+                       potliblink=`ls -ld $potlib | $SED 's/.* -> //'`
+                       case $potliblink in
+                       [\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;;
+                       *) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";;
+                       esac
+                     done
+                     if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+                        $SED -e 10q |
+                        $EGREP "$file_magic_regex" > /dev/null; then
+                       func_append newdeplibs " $a_deplib"
+                       a_deplib=
+                       break 2
+                     fi
+                 done
+               done
+             fi
+             if test -n "$a_deplib"; then
+               droppeddeps=yes
+               echo
+               $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+               echo "*** I have the capability to make that library automatically link in when"
+               echo "*** you link to this library.  But I can only do this if you have a"
+               echo "*** shared version of the library, which you do not appear to have"
+               echo "*** because I did check the linker path looking for a file starting"
+               if test -z "$potlib"; then
+                 $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+               else
+                 $ECHO "*** with $libname and none of the candidates passed a file format test"
+                 $ECHO "*** using a file magic. Last file checked: $potlib"
+               fi
+             fi
+             ;;
+           *)
+             # Add a -L argument.
+             func_append newdeplibs " $a_deplib"
+             ;;
+           esac
+         done # Gone through all deplibs.
+         ;;
+       match_pattern*)
+         set dummy $deplibs_check_method; shift
+         match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+         for a_deplib in $deplibs; do
+           case $a_deplib in
+           -l*)
+             func_stripname -l '' "$a_deplib"
+             name=$func_stripname_result
+             if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+               case " $predeps $postdeps " in
+               *" $a_deplib "*)
+                 func_append newdeplibs " $a_deplib"
+                 a_deplib=
+                 ;;
+               esac
+             fi
+             if test -n "$a_deplib"; then
+               libname=`eval "\\$ECHO \"$libname_spec\""`
+               for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+                 potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+                 for potent_lib in $potential_libs; do
+                   potlib=$potent_lib # see symlink-check above in file_magic test
+                   if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
+                      $EGREP "$match_pattern_regex" > /dev/null; then
+                     func_append newdeplibs " $a_deplib"
+                     a_deplib=
+                     break 2
+                   fi
+                 done
+               done
+             fi
+             if test -n "$a_deplib"; then
+               droppeddeps=yes
+               echo
+               $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+               echo "*** I have the capability to make that library automatically link in when"
+               echo "*** you link to this library.  But I can only do this if you have a"
+               echo "*** shared version of the library, which you do not appear to have"
+               echo "*** because I did check the linker path looking for a file starting"
+               if test -z "$potlib"; then
+                 $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+               else
+                 $ECHO "*** with $libname and none of the candidates passed a file format test"
+                 $ECHO "*** using a regex pattern. Last file checked: $potlib"
+               fi
+             fi
+             ;;
+           *)
+             # Add a -L argument.
+             func_append newdeplibs " $a_deplib"
+             ;;
+           esac
+         done # Gone through all deplibs.
+         ;;
+       none | unknown | *)
+         newdeplibs=
+         tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
+         if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+           for i in $predeps $postdeps; do
+             # can't use Xsed below, because $i might contain '/'
+             tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"`
+           done
+         fi
+         case $tmp_deplibs in
+         *[!\  \ ]*)
+           echo
+           if test none = "$deplibs_check_method"; then
+             echo "*** Warning: inter-library dependencies are not supported in this platform."
+           else
+             echo "*** Warning: inter-library dependencies are not known to be supported."
+           fi
+           echo "*** All declared inter-library dependencies are being dropped."
+           droppeddeps=yes
+           ;;
+         esac
+         ;;
+       esac
+       versuffix=$versuffix_save
+       major=$major_save
+       release=$release_save
+       libname=$libname_save
+       name=$name_save
+
+       case $host in
+       *-*-rhapsody* | *-*-darwin1.[012])
+         # On Rhapsody replace the C library with the System framework
+         newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
+         ;;
+       esac
+
+       if test yes = "$droppeddeps"; then
+         if test yes = "$module"; then
+           echo
+           echo "*** Warning: libtool could not satisfy all declared inter-library"
+           $ECHO "*** dependencies of module $libname.  Therefore, libtool will create"
+           echo "*** a static module, that should work as long as the dlopening"
+           echo "*** application is linked with the -dlopen flag."
+           if test -z "$global_symbol_pipe"; then
+             echo
+             echo "*** However, this would only work if libtool was able to extract symbol"
+             echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
+             echo "*** not find such a program.  So, this module is probably useless."
+             echo "*** 'nm' from GNU binutils and a full rebuild may help."
+           fi
+           if test no = "$build_old_libs"; then
+             oldlibs=$output_objdir/$libname.$libext
+             build_libtool_libs=module
+             build_old_libs=yes
+           else
+             build_libtool_libs=no
+           fi
+         else
+           echo "*** The inter-library dependencies that have been dropped here will be"
+           echo "*** automatically added whenever a program is linked with this library"
+           echo "*** or is declared to -dlopen it."
+
+           if test no = "$allow_undefined"; then
+             echo
+             echo "*** Since this library must not contain undefined symbols,"
+             echo "*** because either the platform does not support them or"
+             echo "*** it was explicitly requested with -no-undefined,"
+             echo "*** libtool will only create a static version of it."
+             if test no = "$build_old_libs"; then
+               oldlibs=$output_objdir/$libname.$libext
+               build_libtool_libs=module
+               build_old_libs=yes
+             else
+               build_libtool_libs=no
+             fi
+           fi
+         fi
+       fi
+       # Done checking deplibs!
+       deplibs=$newdeplibs
+      fi
+      # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+      case $host in
+       *-*-darwin*)
+         newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+         new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+         deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+         ;;
+      esac
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+       case " $new_libs " in
+       *" -L$path/$objdir "*) ;;
+       *)
+         case " $deplibs " in
+         *" -L$path/$objdir "*)
+           func_append new_libs " -L$path/$objdir" ;;
+         esac
+         ;;
+       esac
+      done
+      for deplib in $deplibs; do
+       case $deplib in
+       -L*)
+         case " $new_libs " in
+         *" $deplib "*) ;;
+         *) func_append new_libs " $deplib" ;;
+         esac
+         ;;
+       *) func_append new_libs " $deplib" ;;
+       esac
+      done
+      deplibs=$new_libs
+
+      # All the library-specific variables (install_libdir is set above).
+      library_names=
+      old_library=
+      dlname=
+
+      # Test again, we may have decided not to build it any more
+      if test yes = "$build_libtool_libs"; then
+       # Remove $wl instances when linking with ld.
+       # FIXME: should test the right _cmds variable.
+       case $archive_cmds in
+         *\$LD\ *) wl= ;;
+        esac
+       if test yes = "$hardcode_into_libs"; then
+         # Hardcode the library paths
+         hardcode_libdirs=
+         dep_rpath=
+         rpath=$finalize_rpath
+         test relink = "$opt_mode" || rpath=$compile_rpath$rpath
+         for libdir in $rpath; do
+           if test -n "$hardcode_libdir_flag_spec"; then
+             if test -n "$hardcode_libdir_separator"; then
+               func_replace_sysroot "$libdir"
+               libdir=$func_replace_sysroot_result
+               if test -z "$hardcode_libdirs"; then
+                 hardcode_libdirs=$libdir
+               else
+                 # Just accumulate the unique libdirs.
+                 case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+                 *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+                   ;;
+                 *)
+                   func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+                   ;;
+                 esac
+               fi
+             else
+               eval flag=\"$hardcode_libdir_flag_spec\"
+               func_append dep_rpath " $flag"
+             fi
+           elif test -n "$runpath_var"; then
+             case "$perm_rpath " in
+             *" $libdir "*) ;;
+             *) func_append perm_rpath " $libdir" ;;
+             esac
+           fi
+         done
+         # Substitute the hardcoded libdirs into the rpath.
+         if test -n "$hardcode_libdir_separator" &&
+            test -n "$hardcode_libdirs"; then
+           libdir=$hardcode_libdirs
+           eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
+         fi
+         if test -n "$runpath_var" && test -n "$perm_rpath"; then
+           # We should set the runpath_var.
+           rpath=
+           for dir in $perm_rpath; do
+             func_append rpath "$dir:"
+           done
+           eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+         fi
+         test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+       fi
+
+       shlibpath=$finalize_shlibpath
+       test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath
+       if test -n "$shlibpath"; then
+         eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+       fi
+
+       # Get the real and link names of the library.
+       eval shared_ext=\"$shrext_cmds\"
+       eval library_names=\"$library_names_spec\"
+       set dummy $library_names
+       shift
+       realname=$1
+       shift
+
+       if test -n "$soname_spec"; then
+         eval soname=\"$soname_spec\"
+       else
+         soname=$realname
+       fi
+       if test -z "$dlname"; then
+         dlname=$soname
+       fi
+
+       lib=$output_objdir/$realname
+       linknames=
+       for link
+       do
+         func_append linknames " $link"
+       done
+
+       # Use standard objects if they are pic
+       test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+       test "X$libobjs" = "X " && libobjs=
+
+       delfiles=
+       if test -n "$export_symbols" && test -n "$include_expsyms"; then
+         $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+         export_symbols=$output_objdir/$libname.uexp
+         func_append delfiles " $export_symbols"
+       fi
+
+       orig_export_symbols=
+       case $host_os in
+       cygwin* | mingw* | cegcc*)
+         if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+           # exporting using user supplied symfile
+           func_dll_def_p "$export_symbols" || {
+             # and it's NOT already a .def file. Must figure out
+             # which of the given symbols are data symbols and tag
+             # them as such. So, trigger use of export_symbols_cmds.
+             # export_symbols gets reassigned inside the "prepare
+             # the list of exported symbols" if statement, so the
+             # include_expsyms logic still works.
+             orig_export_symbols=$export_symbols
+             export_symbols=
+             always_export_symbols=yes
+           }
+         fi
+         ;;
+       esac
+
+       # Prepare the list of exported symbols
+       if test -z "$export_symbols"; then
+         if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then
+           func_verbose "generating symbol list for '$libname.la'"
+           export_symbols=$output_objdir/$libname.exp
+           $opt_dry_run || $RM $export_symbols
+           cmds=$export_symbols_cmds
+           save_ifs=$IFS; IFS='~'
+           for cmd1 in $cmds; do
+             IFS=$save_ifs
+             # Take the normal branch if the nm_file_list_spec branch
+             # doesn't work or if tool conversion is not needed.
+             case $nm_file_list_spec~$to_tool_file_cmd in
+               *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*)
+                 try_normal_branch=yes
+                 eval cmd=\"$cmd1\"
+                 func_len " $cmd"
+                 len=$func_len_result
+                 ;;
+               *)
+                 try_normal_branch=no
+                 ;;
+             esac
+             if test yes = "$try_normal_branch" \
+                && { test "$len" -lt "$max_cmd_len" \
+                     || test "$max_cmd_len" -le -1; }
+             then
+               func_show_eval "$cmd" 'exit $?'
+               skipped_export=false
+             elif test -n "$nm_file_list_spec"; then
+               func_basename "$output"
+               output_la=$func_basename_result
+               save_libobjs=$libobjs
+               save_output=$output
+               output=$output_objdir/$output_la.nm
+               func_to_tool_file "$output"
+               libobjs=$nm_file_list_spec$func_to_tool_file_result
+               func_append delfiles " $output"
+               func_verbose "creating $NM input file list: $output"
+               for obj in $save_libobjs; do
+                 func_to_tool_file "$obj"
+                 $ECHO "$func_to_tool_file_result"
+               done > "$output"
+               eval cmd=\"$cmd1\"
+               func_show_eval "$cmd" 'exit $?'
+               output=$save_output
+               libobjs=$save_libobjs
+               skipped_export=false
+             else
+               # The command line is too long to execute in one step.
+               func_verbose "using reloadable object file for export list..."
+               skipped_export=:
+               # Break out early, otherwise skipped_export may be
+               # set to false by a later but shorter cmd.
+               break
+             fi
+           done
+           IFS=$save_ifs
+           if test -n "$export_symbols_regex" && test : != "$skipped_export"; then
+             func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+             func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+           fi
+         fi
+       fi
+
+       if test -n "$export_symbols" && test -n "$include_expsyms"; then
+         tmp_export_symbols=$export_symbols
+         test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
+         $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+       fi
+
+       if test : != "$skipped_export" && test -n "$orig_export_symbols"; then
+         # The given exports_symbols file has to be filtered, so filter it.
+         func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
+         # FIXME: $output_objdir/$libname.filter potentially contains lots of
+         # 's' commands, which not all seds can handle. GNU sed should be fine
+         # though. Also, the filter scales superlinearly with the number of
+         # global variables. join(1) would be nice here, but unfortunately
+         # isn't a blessed tool.
+         $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+         func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+         export_symbols=$output_objdir/$libname.def
+         $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+       fi
+
+       tmp_deplibs=
+       for test_deplib in $deplibs; do
+         case " $convenience " in
+         *" $test_deplib "*) ;;
+         *)
+           func_append tmp_deplibs " $test_deplib"
+           ;;
+         esac
+       done
+       deplibs=$tmp_deplibs
+
+       if test -n "$convenience"; then
+         if test -n "$whole_archive_flag_spec" &&
+           test yes = "$compiler_needs_object" &&
+           test -z "$libobjs"; then
+           # extract the archives, so we have objects to list.
+           # TODO: could optimize this to just extract one archive.
+           whole_archive_flag_spec=
+         fi
+         if test -n "$whole_archive_flag_spec"; then
+           save_libobjs=$libobjs
+           eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+           test "X$libobjs" = "X " && libobjs=
+         else
+           gentop=$output_objdir/${outputname}x
+           func_append generated " $gentop"
+
+           func_extract_archives $gentop $convenience
+           func_append libobjs " $func_extract_archives_result"
+           test "X$libobjs" = "X " && libobjs=
+         fi
+       fi
+
+       if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then
+         eval flag=\"$thread_safe_flag_spec\"
+         func_append linker_flags " $flag"
+       fi
+
+       # Make a backup of the uninstalled library when relinking
+       if test relink = "$opt_mode"; then
+         $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+       fi
+
+       # Do each of the archive commands.
+       if test yes = "$module" && test -n "$module_cmds"; then
+         if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+           eval test_cmds=\"$module_expsym_cmds\"
+           cmds=$module_expsym_cmds
+         else
+           eval test_cmds=\"$module_cmds\"
+           cmds=$module_cmds
+         fi
+       else
+         if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+           eval test_cmds=\"$archive_expsym_cmds\"
+           cmds=$archive_expsym_cmds
+         else
+           eval test_cmds=\"$archive_cmds\"
+           cmds=$archive_cmds
+         fi
+       fi
+
+       if test : != "$skipped_export" &&
+          func_len " $test_cmds" &&
+          len=$func_len_result &&
+          test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+         :
+       else
+         # The command line is too long to link in one step, link piecewise
+         # or, if using GNU ld and skipped_export is not :, use a linker
+         # script.
+
+         # Save the value of $output and $libobjs because we want to
+         # use them later.  If we have whole_archive_flag_spec, we
+         # want to use save_libobjs as it was before
+         # whole_archive_flag_spec was expanded, because we can't
+         # assume the linker understands whole_archive_flag_spec.
+         # This may have to be revisited, in case too many
+         # convenience libraries get linked in and end up exceeding
+         # the spec.
+         if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+           save_libobjs=$libobjs
+         fi
+         save_output=$output
+         func_basename "$output"
+         output_la=$func_basename_result
+
+         # Clear the reloadable object creation command queue and
+         # initialize k to one.
+         test_cmds=
+         concat_cmds=
+         objlist=
+         last_robj=
+         k=1
+
+         if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then
+           output=$output_objdir/$output_la.lnkscript
+           func_verbose "creating GNU ld script: $output"
+           echo 'INPUT (' > $output
+           for obj in $save_libobjs
+           do
+             func_to_tool_file "$obj"
+             $ECHO "$func_to_tool_file_result" >> $output
+           done
+           echo ')' >> $output
+           func_append delfiles " $output"
+           func_to_tool_file "$output"
+           output=$func_to_tool_file_result
+         elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then
+           output=$output_objdir/$output_la.lnk
+           func_verbose "creating linker input file list: $output"
+           : > $output
+           set x $save_libobjs
+           shift
+           firstobj=
+           if test yes = "$compiler_needs_object"; then
+             firstobj="$1 "
+             shift
+           fi
+           for obj
+           do
+             func_to_tool_file "$obj"
+             $ECHO "$func_to_tool_file_result" >> $output
+           done
+           func_append delfiles " $output"
+           func_to_tool_file "$output"
+           output=$firstobj\"$file_list_spec$func_to_tool_file_result\"
+         else
+           if test -n "$save_libobjs"; then
+             func_verbose "creating reloadable object files..."
+             output=$output_objdir/$output_la-$k.$objext
+             eval test_cmds=\"$reload_cmds\"
+             func_len " $test_cmds"
+             len0=$func_len_result
+             len=$len0
+
+             # Loop over the list of objects to be linked.
+             for obj in $save_libobjs
+             do
+               func_len " $obj"
+               func_arith $len + $func_len_result
+               len=$func_arith_result
+               if test -z "$objlist" ||
+                  test "$len" -lt "$max_cmd_len"; then
+                 func_append objlist " $obj"
+               else
+                 # The command $test_cmds is almost too long, add a
+                 # command to the queue.
+                 if test 1 -eq "$k"; then
+                   # The first file doesn't have a previous command to add.
+                   reload_objs=$objlist
+                   eval concat_cmds=\"$reload_cmds\"
+                 else
+                   # All subsequent reloadable object files will link in
+                   # the last one created.
+                   reload_objs="$objlist $last_robj"
+                   eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
+                 fi
+                 last_robj=$output_objdir/$output_la-$k.$objext
+                 func_arith $k + 1
+                 k=$func_arith_result
+                 output=$output_objdir/$output_la-$k.$objext
+                 objlist=" $obj"
+                 func_len " $last_robj"
+                 func_arith $len0 + $func_len_result
+                 len=$func_arith_result
+               fi
+             done
+             # Handle the remaining objects by creating one last
+             # reloadable object file.  All subsequent reloadable object
+             # files will link in the last one created.
+             test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+             reload_objs="$objlist $last_robj"
+             eval concat_cmds=\"\$concat_cmds$reload_cmds\"
+             if test -n "$last_robj"; then
+               eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+             fi
+             func_append delfiles " $output"
+
+           else
+             output=
+           fi
+
+           ${skipped_export-false} && {
+             func_verbose "generating symbol list for '$libname.la'"
+             export_symbols=$output_objdir/$libname.exp
+             $opt_dry_run || $RM $export_symbols
+             libobjs=$output
+             # Append the command to create the export file.
+             test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+             eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+             if test -n "$last_robj"; then
+               eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+             fi
+           }
+
+           test -n "$save_libobjs" &&
+             func_verbose "creating a temporary reloadable object file: $output"
+
+           # Loop through the commands generated above and execute them.
+           save_ifs=$IFS; IFS='~'
+           for cmd in $concat_cmds; do
+             IFS=$save_ifs
+             $opt_quiet || {
+                 func_quote_for_expand "$cmd"
+                 eval "func_echo $func_quote_for_expand_result"
+             }
+             $opt_dry_run || eval "$cmd" || {
+               lt_exit=$?
+
+               # Restore the uninstalled library and exit
+               if test relink = "$opt_mode"; then
+                 ( cd "$output_objdir" && \
+                   $RM "${realname}T" && \
+                   $MV "${realname}U" "$realname" )
+               fi
+
+               exit $lt_exit
+             }
+           done
+           IFS=$save_ifs
+
+           if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+             func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+             func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+           fi
+         fi
+
+          ${skipped_export-false} && {
+           if test -n "$export_symbols" && test -n "$include_expsyms"; then
+             tmp_export_symbols=$export_symbols
+             test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
+             $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+           fi
+
+           if test -n "$orig_export_symbols"; then
+             # The given exports_symbols file has to be filtered, so filter it.
+             func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
+             # FIXME: $output_objdir/$libname.filter potentially contains lots of
+             # 's' commands, which not all seds can handle. GNU sed should be fine
+             # though. Also, the filter scales superlinearly with the number of
+             # global variables. join(1) would be nice here, but unfortunately
+             # isn't a blessed tool.
+             $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+             func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+             export_symbols=$output_objdir/$libname.def
+             $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+           fi
+         }
+
+         libobjs=$output
+         # Restore the value of output.
+         output=$save_output
+
+         if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+           eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+           test "X$libobjs" = "X " && libobjs=
+         fi
+         # Expand the library linking commands again to reset the
+         # value of $libobjs for piecewise linking.
+
+         # Do each of the archive commands.
+         if test yes = "$module" && test -n "$module_cmds"; then
+           if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+             cmds=$module_expsym_cmds
+           else
+             cmds=$module_cmds
+           fi
+         else
+           if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+             cmds=$archive_expsym_cmds
+           else
+             cmds=$archive_cmds
+           fi
+         fi
+       fi
+
+       if test -n "$delfiles"; then
+         # Append the command to remove temporary files to $cmds.
+         eval cmds=\"\$cmds~\$RM $delfiles\"
+       fi
+
+       # Add any objects from preloaded convenience libraries
+       if test -n "$dlprefiles"; then
+         gentop=$output_objdir/${outputname}x
+         func_append generated " $gentop"
+
+         func_extract_archives $gentop $dlprefiles
+         func_append libobjs " $func_extract_archives_result"
+         test "X$libobjs" = "X " && libobjs=
+       fi
+
+       save_ifs=$IFS; IFS='~'
+       for cmd in $cmds; do
+         IFS=$sp$nl
+         eval cmd=\"$cmd\"
+         IFS=$save_ifs
+         $opt_quiet || {
+           func_quote_for_expand "$cmd"
+           eval "func_echo $func_quote_for_expand_result"
+         }
+         $opt_dry_run || eval "$cmd" || {
+           lt_exit=$?
+
+           # Restore the uninstalled library and exit
+           if test relink = "$opt_mode"; then
+             ( cd "$output_objdir" && \
+               $RM "${realname}T" && \
+               $MV "${realname}U" "$realname" )
+           fi
+
+           exit $lt_exit
+         }
+       done
+       IFS=$save_ifs
+
+       # Restore the uninstalled library and exit
+       if test relink = "$opt_mode"; then
+         $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+         if test -n "$convenience"; then
+           if test -z "$whole_archive_flag_spec"; then
+             func_show_eval '${RM}r "$gentop"'
+           fi
+         fi
+
+         exit $EXIT_SUCCESS
+       fi
+
+       # Create links to the real library.
+       for linkname in $linknames; do
+         if test "$realname" != "$linkname"; then
+           func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+         fi
+       done
+
+       # If -module or -export-dynamic was specified, set the dlname.
+       if test yes = "$module" || test yes = "$export_dynamic"; then
+         # On all known operating systems, these are identical.
+         dlname=$soname
+       fi
+      fi
+      ;;
+
+    obj)
+      if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+       func_warning "'-dlopen' is ignored for objects"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+       func_warning "'-l' and '-L' are ignored for objects" ;;
+      esac
+
+      test -n "$rpath" && \
+       func_warning "'-rpath' is ignored for objects"
+
+      test -n "$xrpath" && \
+       func_warning "'-R' is ignored for objects"
+
+      test -n "$vinfo" && \
+       func_warning "'-version-info' is ignored for objects"
+
+      test -n "$release" && \
+       func_warning "'-release' is ignored for objects"
+
+      case $output in
+      *.lo)
+       test -n "$objs$old_deplibs" && \
+         func_fatal_error "cannot build library object '$output' from non-libtool objects"
+
+       libobj=$output
+       func_lo2o "$libobj"
+       obj=$func_lo2o_result
+       ;;
+      *)
+       libobj=
+       obj=$output
+       ;;
+      esac
+
+      # Delete the old objects.
+      $opt_dry_run || $RM $obj $libobj
+
+      # Objects from convenience libraries.  This assumes
+      # single-version convenience libraries.  Whenever we create
+      # different ones for PIC/non-PIC, this we'll have to duplicate
+      # the extraction.
+      reload_conv_objs=
+      gentop=
+      # if reload_cmds runs $LD directly, get rid of -Wl from
+      # whole_archive_flag_spec and hope we can get by with turning comma
+      # into space.
+      case $reload_cmds in
+        *\$LD[\ \$]*) wl= ;;
+      esac
+      if test -n "$convenience"; then
+       if test -n "$whole_archive_flag_spec"; then
+         eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+         test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+         reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags
+       else
+         gentop=$output_objdir/${obj}x
+         func_append generated " $gentop"
+
+         func_extract_archives $gentop $convenience
+         reload_conv_objs="$reload_objs $func_extract_archives_result"
+       fi
+      fi
+
+      # If we're not building shared, we need to use non_pic_objs
+      test yes = "$build_libtool_libs" || libobjs=$non_pic_objects
+
+      # Create the old-style object.
+      reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs
+
+      output=$obj
+      func_execute_cmds "$reload_cmds" 'exit $?'
+
+      # Exit if we aren't doing a library object file.
+      if test -z "$libobj"; then
+       if test -n "$gentop"; then
+         func_show_eval '${RM}r "$gentop"'
+       fi
+
+       exit $EXIT_SUCCESS
+      fi
+
+      test yes = "$build_libtool_libs" || {
+       if test -n "$gentop"; then
+         func_show_eval '${RM}r "$gentop"'
+       fi
+
+       # Create an invalid libtool object if no PIC, so that we don't
+       # accidentally link it into a program.
+       # $show "echo timestamp > $libobj"
+       # $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+       exit $EXIT_SUCCESS
+      }
+
+      if test -n "$pic_flag" || test default != "$pic_mode"; then
+       # Only do commands if we really have different PIC objects.
+       reload_objs="$libobjs $reload_conv_objs"
+       output=$libobj
+       func_execute_cmds "$reload_cmds" 'exit $?'
+      fi
+
+      if test -n "$gentop"; then
+       func_show_eval '${RM}r "$gentop"'
+      fi
+
+      exit $EXIT_SUCCESS
+      ;;
+
+    prog)
+      case $host in
+       *cygwin*) func_stripname '' '.exe' "$output"
+                 output=$func_stripname_result.exe;;
+      esac
+      test -n "$vinfo" && \
+       func_warning "'-version-info' is ignored for programs"
+
+      test -n "$release" && \
+       func_warning "'-release' is ignored for programs"
+
+      $preload \
+       && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \
+       && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+      case $host in
+      *-*-rhapsody* | *-*-darwin1.[012])
+       # On Rhapsody replace the C library is the System framework
+       compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+       finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
+       ;;
+      esac
+
+      case $host in
+      *-*-darwin*)
+       # Don't allow lazy linking, it breaks C++ global constructors
+       # But is supposedly fixed on 10.4 or later (yay!).
+       if test CXX = "$tagname"; then
+         case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+           10.[0123])
+             func_append compile_command " $wl-bind_at_load"
+             func_append finalize_command " $wl-bind_at_load"
+           ;;
+         esac
+       fi
+       # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+       compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+       finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+       ;;
+      esac
+
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+       case " $new_libs " in
+       *" -L$path/$objdir "*) ;;
+       *)
+         case " $compile_deplibs " in
+         *" -L$path/$objdir "*)
+           func_append new_libs " -L$path/$objdir" ;;
+         esac
+         ;;
+       esac
+      done
+      for deplib in $compile_deplibs; do
+       case $deplib in
+       -L*)
+         case " $new_libs " in
+         *" $deplib "*) ;;
+         *) func_append new_libs " $deplib" ;;
+         esac
+         ;;
+       *) func_append new_libs " $deplib" ;;
+       esac
+      done
+      compile_deplibs=$new_libs
+
+
+      func_append compile_command " $compile_deplibs"
+      func_append finalize_command " $finalize_deplibs"
+
+      if test -n "$rpath$xrpath"; then
+       # If the user specified any rpath flags, then add them.
+       for libdir in $rpath $xrpath; do
+         # This is the magic to use -rpath.
+         case "$finalize_rpath " in
+         *" $libdir "*) ;;
+         *) func_append finalize_rpath " $libdir" ;;
+         esac
+       done
+      fi
+
+      # Now hardcode the library paths
+      rpath=
+      hardcode_libdirs=
+      for libdir in $compile_rpath $finalize_rpath; do
+       if test -n "$hardcode_libdir_flag_spec"; then
+         if test -n "$hardcode_libdir_separator"; then
+           if test -z "$hardcode_libdirs"; then
+             hardcode_libdirs=$libdir
+           else
+             # Just accumulate the unique libdirs.
+             case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+             *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+               ;;
+             *)
+               func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+               ;;
+             esac
+           fi
+         else
+           eval flag=\"$hardcode_libdir_flag_spec\"
+           func_append rpath " $flag"
+         fi
+       elif test -n "$runpath_var"; then
+         case "$perm_rpath " in
+         *" $libdir "*) ;;
+         *) func_append perm_rpath " $libdir" ;;
+         esac
+       fi
+       case $host in
+       *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+         testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'`
+         case :$dllsearchpath: in
+         *":$libdir:"*) ;;
+         ::) dllsearchpath=$libdir;;
+         *) func_append dllsearchpath ":$libdir";;
+         esac
+         case :$dllsearchpath: in
+         *":$testbindir:"*) ;;
+         ::) dllsearchpath=$testbindir;;
+         *) func_append dllsearchpath ":$testbindir";;
+         esac
+         ;;
+       esac
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+        test -n "$hardcode_libdirs"; then
+       libdir=$hardcode_libdirs
+       eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      compile_rpath=$rpath
+
+      rpath=
+      hardcode_libdirs=
+      for libdir in $finalize_rpath; do
+       if test -n "$hardcode_libdir_flag_spec"; then
+         if test -n "$hardcode_libdir_separator"; then
+           if test -z "$hardcode_libdirs"; then
+             hardcode_libdirs=$libdir
+           else
+             # Just accumulate the unique libdirs.
+             case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+             *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+               ;;
+             *)
+               func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+               ;;
+             esac
+           fi
+         else
+           eval flag=\"$hardcode_libdir_flag_spec\"
+           func_append rpath " $flag"
+         fi
+       elif test -n "$runpath_var"; then
+         case "$finalize_perm_rpath " in
+         *" $libdir "*) ;;
+         *) func_append finalize_perm_rpath " $libdir" ;;
+         esac
+       fi
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+        test -n "$hardcode_libdirs"; then
+       libdir=$hardcode_libdirs
+       eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      finalize_rpath=$rpath
+
+      if test -n "$libobjs" && test yes = "$build_old_libs"; then
+       # Transform all the library objects into standard objects.
+       compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+       finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+      fi
+
+      func_generate_dlsyms "$outputname" "@PROGRAM@" false
+
+      # template prelinking step
+      if test -n "$prelink_cmds"; then
+       func_execute_cmds "$prelink_cmds" 'exit $?'
+      fi
+
+      wrappers_required=:
+      case $host in
+      *cegcc* | *mingw32ce*)
+        # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+        wrappers_required=false
+        ;;
+      *cygwin* | *mingw* )
+        test yes = "$build_libtool_libs" || wrappers_required=false
+        ;;
+      *)
+        if test no = "$need_relink" || test yes != "$build_libtool_libs"; then
+          wrappers_required=false
+        fi
+        ;;
+      esac
+      $wrappers_required || {
+       # Replace the output file specification.
+       compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+       link_command=$compile_command$compile_rpath
+
+       # We have no uninstalled library dependencies, so finalize right now.
+       exit_status=0
+       func_show_eval "$link_command" 'exit_status=$?'
+
+       if test -n "$postlink_cmds"; then
+         func_to_tool_file "$output"
+         postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+         func_execute_cmds "$postlink_cmds" 'exit $?'
+       fi
+
+       # Delete the generated files.
+       if test -f "$output_objdir/${outputname}S.$objext"; then
+         func_show_eval '$RM "$output_objdir/${outputname}S.$objext"'
+       fi
+
+       exit $exit_status
+      }
+
+      if test -n "$compile_shlibpath$finalize_shlibpath"; then
+       compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+      fi
+      if test -n "$finalize_shlibpath"; then
+       finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+      fi
+
+      compile_var=
+      finalize_var=
+      if test -n "$runpath_var"; then
+       if test -n "$perm_rpath"; then
+         # We should set the runpath_var.
+         rpath=
+         for dir in $perm_rpath; do
+           func_append rpath "$dir:"
+         done
+         compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+       fi
+       if test -n "$finalize_perm_rpath"; then
+         # We should set the runpath_var.
+         rpath=
+         for dir in $finalize_perm_rpath; do
+           func_append rpath "$dir:"
+         done
+         finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+       fi
+      fi
+
+      if test yes = "$no_install"; then
+       # We don't need to create a wrapper script.
+       link_command=$compile_var$compile_command$compile_rpath
+       # Replace the output file specification.
+       link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+       # Delete the old output file.
+       $opt_dry_run || $RM $output
+       # Link the executable and exit
+       func_show_eval "$link_command" 'exit $?'
+
+       if test -n "$postlink_cmds"; then
+         func_to_tool_file "$output"
+         postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+         func_execute_cmds "$postlink_cmds" 'exit $?'
+       fi
+
+       exit $EXIT_SUCCESS
+      fi
+
+      case $hardcode_action,$fast_install in
+        relink,*)
+         # Fast installation is not supported
+         link_command=$compile_var$compile_command$compile_rpath
+         relink_command=$finalize_var$finalize_command$finalize_rpath
+
+         func_warning "this platform does not like uninstalled shared libraries"
+         func_warning "'$output' will be relinked during installation"
+         ;;
+        *,yes)
+         link_command=$finalize_var$compile_command$finalize_rpath
+         relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+          ;;
+       *,no)
+         link_command=$compile_var$compile_command$compile_rpath
+         relink_command=$finalize_var$finalize_command$finalize_rpath
+          ;;
+       *,needless)
+         link_command=$finalize_var$compile_command$finalize_rpath
+         relink_command=
+          ;;
+      esac
+
+      # Replace the output file specification.
+      link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+      # Delete the old output files.
+      $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+      func_show_eval "$link_command" 'exit $?'
+
+      if test -n "$postlink_cmds"; then
+       func_to_tool_file "$output_objdir/$outputname"
+       postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+       func_execute_cmds "$postlink_cmds" 'exit $?'
+      fi
+
+      # Now create the wrapper script.
+      func_verbose "creating $output"
+
+      # Quote the relink command for shipping.
+      if test -n "$relink_command"; then
+       # Preserve any variables that may affect compiler behavior
+       for var in $variables_saved_for_relink; do
+         if eval test -z \"\${$var+set}\"; then
+           relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+         elif eval var_value=\$$var; test -z "$var_value"; then
+           relink_command="$var=; export $var; $relink_command"
+         else
+           func_quote_for_eval "$var_value"
+           relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+         fi
+       done
+       relink_command="(cd `pwd`; $relink_command)"
+       relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      fi
+
+      # Only actually do things if not in dry run mode.
+      $opt_dry_run || {
+       # win32 will think the script is a binary if it has
+       # a .exe suffix, so we strip it off here.
+       case $output in
+         *.exe) func_stripname '' '.exe' "$output"
+                output=$func_stripname_result ;;
+       esac
+       # test for cygwin because mv fails w/o .exe extensions
+       case $host in
+         *cygwin*)
+           exeext=.exe
+           func_stripname '' '.exe' "$outputname"
+           outputname=$func_stripname_result ;;
+         *) exeext= ;;
+       esac
+       case $host in
+         *cygwin* | *mingw* )
+           func_dirname_and_basename "$output" "" "."
+           output_name=$func_basename_result
+           output_path=$func_dirname_result
+           cwrappersource=$output_path/$objdir/lt-$output_name.c
+           cwrapper=$output_path/$output_name.exe
+           $RM $cwrappersource $cwrapper
+           trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+           func_emit_cwrapperexe_src > $cwrappersource
+
+           # The wrapper executable is built using the $host compiler,
+           # because it contains $host paths and files. If cross-
+           # compiling, it, like the target executable, must be
+           # executed on the $host or under an emulation environment.
+           $opt_dry_run || {
+             $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+             $STRIP $cwrapper
+           }
+
+           # Now, create the wrapper script for func_source use:
+           func_ltwrapper_scriptname $cwrapper
+           $RM $func_ltwrapper_scriptname_result
+           trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+           $opt_dry_run || {
+             # note: this script will not be executed, so do not chmod.
+             if test "x$build" = "x$host"; then
+               $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+             else
+               func_emit_wrapper no > $func_ltwrapper_scriptname_result
+             fi
+           }
+         ;;
+         * )
+           $RM $output
+           trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+           func_emit_wrapper no > $output
+           chmod +x $output
+         ;;
+       esac
+      }
+      exit $EXIT_SUCCESS
+      ;;
+    esac
+
+    # See if we need to build an old-fashioned archive.
+    for oldlib in $oldlibs; do
+
+      case $build_libtool_libs in
+        convenience)
+         oldobjs="$libobjs_save $symfileobj"
+         addlibs=$convenience
+         build_libtool_libs=no
+         ;;
+       module)
+         oldobjs=$libobjs_save
+         addlibs=$old_convenience
+         build_libtool_libs=no
+          ;;
+       *)
+         oldobjs="$old_deplibs $non_pic_objects"
+         $preload && test -f "$symfileobj" \
+           && func_append oldobjs " $symfileobj"
+         addlibs=$old_convenience
+         ;;
+      esac
+
+      if test -n "$addlibs"; then
+       gentop=$output_objdir/${outputname}x
+       func_append generated " $gentop"
+
+       func_extract_archives $gentop $addlibs
+       func_append oldobjs " $func_extract_archives_result"
+      fi
+
+      # Do each command in the archive commands.
+      if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then
+       cmds=$old_archive_from_new_cmds
+      else
+
+       # Add any objects from preloaded convenience libraries
+       if test -n "$dlprefiles"; then
+         gentop=$output_objdir/${outputname}x
+         func_append generated " $gentop"
+
+         func_extract_archives $gentop $dlprefiles
+         func_append oldobjs " $func_extract_archives_result"
+       fi
+
+       # POSIX demands no paths to be encoded in archives.  We have
+       # to avoid creating archives with duplicate basenames if we
+       # might have to extract them afterwards, e.g., when creating a
+       # static archive out of a convenience library, or when linking
+       # the entirety of a libtool archive into another (currently
+       # not supported by libtool).
+       if (for obj in $oldobjs
+           do
+             func_basename "$obj"
+             $ECHO "$func_basename_result"
+           done | sort | sort -uc >/dev/null 2>&1); then
+         :
+       else
+         echo "copying selected object files to avoid basename conflicts..."
+         gentop=$output_objdir/${outputname}x
+         func_append generated " $gentop"
+         func_mkdir_p "$gentop"
+         save_oldobjs=$oldobjs
+         oldobjs=
+         counter=1
+         for obj in $save_oldobjs
+         do
+           func_basename "$obj"
+           objbase=$func_basename_result
+           case " $oldobjs " in
+           " ") oldobjs=$obj ;;
+           *[\ /]"$objbase "*)
+             while :; do
+               # Make sure we don't pick an alternate name that also
+               # overlaps.
+               newobj=lt$counter-$objbase
+               func_arith $counter + 1
+               counter=$func_arith_result
+               case " $oldobjs " in
+               *[\ /]"$newobj "*) ;;
+               *) if test ! -f "$gentop/$newobj"; then break; fi ;;
+               esac
+             done
+             func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+             func_append oldobjs " $gentop/$newobj"
+             ;;
+           *) func_append oldobjs " $obj" ;;
+           esac
+         done
+       fi
+       func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+       tool_oldlib=$func_to_tool_file_result
+       eval cmds=\"$old_archive_cmds\"
+
+       func_len " $cmds"
+       len=$func_len_result
+       if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+         cmds=$old_archive_cmds
+       elif test -n "$archiver_list_spec"; then
+         func_verbose "using command file archive linking..."
+         for obj in $oldobjs
+         do
+           func_to_tool_file "$obj"
+           $ECHO "$func_to_tool_file_result"
+         done > $output_objdir/$libname.libcmd
+         func_to_tool_file "$output_objdir/$libname.libcmd"
+         oldobjs=" $archiver_list_spec$func_to_tool_file_result"
+         cmds=$old_archive_cmds
+       else
+         # the command line is too long to link in one step, link in parts
+         func_verbose "using piecewise archive linking..."
+         save_RANLIB=$RANLIB
+         RANLIB=:
+         objlist=
+         concat_cmds=
+         save_oldobjs=$oldobjs
+         oldobjs=
+         # Is there a better way of finding the last object in the list?
+         for obj in $save_oldobjs
+         do
+           last_oldobj=$obj
+         done
+         eval test_cmds=\"$old_archive_cmds\"
+         func_len " $test_cmds"
+         len0=$func_len_result
+         len=$len0
+         for obj in $save_oldobjs
+         do
+           func_len " $obj"
+           func_arith $len + $func_len_result
+           len=$func_arith_result
+           func_append objlist " $obj"
+           if test "$len" -lt "$max_cmd_len"; then
+             :
+           else
+             # the above command should be used before it gets too long
+             oldobjs=$objlist
+             if test "$obj" = "$last_oldobj"; then
+               RANLIB=$save_RANLIB
+             fi
+             test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+             eval concat_cmds=\"\$concat_cmds$old_archive_cmds\"
+             objlist=
+             len=$len0
+           fi
+         done
+         RANLIB=$save_RANLIB
+         oldobjs=$objlist
+         if test -z "$oldobjs"; then
+           eval cmds=\"\$concat_cmds\"
+         else
+           eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+         fi
+       fi
+      fi
+      func_execute_cmds "$cmds" 'exit $?'
+    done
+
+    test -n "$generated" && \
+      func_show_eval "${RM}r$generated"
+
+    # Now create the libtool archive.
+    case $output in
+    *.la)
+      old_library=
+      test yes = "$build_old_libs" && old_library=$libname.$libext
+      func_verbose "creating $output"
+
+      # Preserve any variables that may affect compiler behavior
+      for var in $variables_saved_for_relink; do
+       if eval test -z \"\${$var+set}\"; then
+         relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+       elif eval var_value=\$$var; test -z "$var_value"; then
+         relink_command="$var=; export $var; $relink_command"
+       else
+         func_quote_for_eval "$var_value"
+         relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+       fi
+      done
+      # Quote the link command for shipping.
+      relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+      relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      if test yes = "$hardcode_automatic"; then
+       relink_command=
+      fi
+
+      # Only create the output if not a dry run.
+      $opt_dry_run || {
+       for installed in no yes; do
+         if test yes = "$installed"; then
+           if test -z "$install_libdir"; then
+             break
+           fi
+           output=$output_objdir/${outputname}i
+           # Replace all uninstalled libtool libraries with the installed ones
+           newdependency_libs=
+           for deplib in $dependency_libs; do
+             case $deplib in
+             *.la)
+               func_basename "$deplib"
+               name=$func_basename_result
+               func_resolve_sysroot "$deplib"
+               eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
+               test -z "$libdir" && \
+                 func_fatal_error "'$deplib' is not a valid libtool archive"
+               func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
+               ;;
+             -L*)
+               func_stripname -L '' "$deplib"
+               func_replace_sysroot "$func_stripname_result"
+               func_append newdependency_libs " -L$func_replace_sysroot_result"
+               ;;
+             -R*)
+               func_stripname -R '' "$deplib"
+               func_replace_sysroot "$func_stripname_result"
+               func_append newdependency_libs " -R$func_replace_sysroot_result"
+               ;;
+             *) func_append newdependency_libs " $deplib" ;;
+             esac
+           done
+           dependency_libs=$newdependency_libs
+           newdlfiles=
+
+           for lib in $dlfiles; do
+             case $lib in
+             *.la)
+               func_basename "$lib"
+               name=$func_basename_result
+               eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+               test -z "$libdir" && \
+                 func_fatal_error "'$lib' is not a valid libtool archive"
+               func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name"
+               ;;
+             *) func_append newdlfiles " $lib" ;;
+             esac
+           done
+           dlfiles=$newdlfiles
+           newdlprefiles=
+           for lib in $dlprefiles; do
+             case $lib in
+             *.la)
+               # Only pass preopened files to the pseudo-archive (for
+               # eventual linking with the app. that links it) if we
+               # didn't already link the preopened objects directly into
+               # the library:
+               func_basename "$lib"
+               name=$func_basename_result
+               eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+               test -z "$libdir" && \
+                 func_fatal_error "'$lib' is not a valid libtool archive"
+               func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
+               ;;
+             esac
+           done
+           dlprefiles=$newdlprefiles
+         else
+           newdlfiles=
+           for lib in $dlfiles; do
+             case $lib in
+               [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
+               *) abs=`pwd`"/$lib" ;;
+             esac
+             func_append newdlfiles " $abs"
+           done
+           dlfiles=$newdlfiles
+           newdlprefiles=
+           for lib in $dlprefiles; do
+             case $lib in
+               [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
+               *) abs=`pwd`"/$lib" ;;
+             esac
+             func_append newdlprefiles " $abs"
+           done
+           dlprefiles=$newdlprefiles
+         fi
+         $RM $output
+         # place dlname in correct position for cygwin
+         # In fact, it would be nice if we could use this code for all target
+         # systems that can't hard-code library paths into their executables
+         # and that have no shared library path variable independent of PATH,
+         # but it turns out we can't easily determine that from inspecting
+         # libtool variables, so we have to hard-code the OSs to which it
+         # applies here; at the moment, that means platforms that use the PE
+         # object format with DLL files.  See the long comment at the top of
+         # tests/bindir.at for full details.
+         tdlname=$dlname
+         case $host,$output,$installed,$module,$dlname in
+           *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+             # If a -bindir argument was supplied, place the dll there.
+             if test -n "$bindir"; then
+               func_relative_path "$install_libdir" "$bindir"
+               tdlname=$func_relative_path_result/$dlname
+             else
+               # Otherwise fall back on heuristic.
+               tdlname=../bin/$dlname
+             fi
+             ;;
+         esac
+         $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that cannot go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+         if test no,yes = "$installed,$need_relink"; then
+           $ECHO >> $output "\
+relink_command=\"$relink_command\""
+         fi
+       done
+      }
+
+      # Do a symbolic link so that the libtool archive can be found in
+      # LD_LIBRARY_PATH before the program is installed.
+      func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+      ;;
+    esac
+    exit $EXIT_SUCCESS
+}
+
+if test link = "$opt_mode" || test relink = "$opt_mode"; then
+  func_mode_link ${1+"$@"}
+fi
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+    $debug_cmd
+
+    RM=$nonopt
+    files=
+    rmforce=false
+    exit_status=0
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic=$magic
+
+    for arg
+    do
+      case $arg in
+      -f) func_append RM " $arg"; rmforce=: ;;
+      -*) func_append RM " $arg" ;;
+      *) func_append files " $arg" ;;
+      esac
+    done
+
+    test -z "$RM" && \
+      func_fatal_help "you must specify an RM program"
+
+    rmdirs=
+
+    for file in $files; do
+      func_dirname "$file" "" "."
+      dir=$func_dirname_result
+      if test . = "$dir"; then
+       odir=$objdir
+      else
+       odir=$dir/$objdir
+      fi
+      func_basename "$file"
+      name=$func_basename_result
+      test uninstall = "$opt_mode" && odir=$dir
+
+      # Remember odir for removal later, being careful to avoid duplicates
+      if test clean = "$opt_mode"; then
+       case " $rmdirs " in
+         *" $odir "*) ;;
+         *) func_append rmdirs " $odir" ;;
+       esac
+      fi
+
+      # Don't error if the file doesn't exist and rm -f was used.
+      if { test -L "$file"; } >/dev/null 2>&1 ||
+        { test -h "$file"; } >/dev/null 2>&1 ||
+        test -f "$file"; then
+       :
+      elif test -d "$file"; then
+       exit_status=1
+       continue
+      elif $rmforce; then
+       continue
+      fi
+
+      rmfiles=$file
+
+      case $name in
+      *.la)
+       # Possibly a libtool archive, so verify it.
+       if func_lalib_p "$file"; then
+         func_source $dir/$name
+
+         # Delete the libtool libraries and symlinks.
+         for n in $library_names; do
+           func_append rmfiles " $odir/$n"
+         done
+         test -n "$old_library" && func_append rmfiles " $odir/$old_library"
+
+         case $opt_mode in
+         clean)
+           case " $library_names " in
+           *" $dlname "*) ;;
+           *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;;
+           esac
+           test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i"
+           ;;
+         uninstall)
+           if test -n "$library_names"; then
+             # Do each command in the postuninstall commands.
+             func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1'
+           fi
+
+           if test -n "$old_library"; then
+             # Do each command in the old_postuninstall commands.
+             func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1'
+           fi
+           # FIXME: should reinstall the best remaining shared library.
+           ;;
+         esac
+       fi
+       ;;
+
+      *.lo)
+       # Possibly a libtool object, so verify it.
+       if func_lalib_p "$file"; then
+
+         # Read the .lo file
+         func_source $dir/$name
+
+         # Add PIC object to the list of files to remove.
+         if test -n "$pic_object" && test none != "$pic_object"; then
+           func_append rmfiles " $dir/$pic_object"
+         fi
+
+         # Add non-PIC object to the list of files to remove.
+         if test -n "$non_pic_object" && test none != "$non_pic_object"; then
+           func_append rmfiles " $dir/$non_pic_object"
+         fi
+       fi
+       ;;
+
+      *)
+       if test clean = "$opt_mode"; then
+         noexename=$name
+         case $file in
+         *.exe)
+           func_stripname '' '.exe' "$file"
+           file=$func_stripname_result
+           func_stripname '' '.exe' "$name"
+           noexename=$func_stripname_result
+           # $file with .exe has already been added to rmfiles,
+           # add $file without .exe
+           func_append rmfiles " $file"
+           ;;
+         esac
+         # Do a test to see if this is a libtool program.
+         if func_ltwrapper_p "$file"; then
+           if func_ltwrapper_executable_p "$file"; then
+             func_ltwrapper_scriptname "$file"
+             relink_command=
+             func_source $func_ltwrapper_scriptname_result
+             func_append rmfiles " $func_ltwrapper_scriptname_result"
+           else
+             relink_command=
+             func_source $dir/$noexename
+           fi
+
+           # note $name still contains .exe if it was in $file originally
+           # as does the version of $file that was added into $rmfiles
+           func_append rmfiles " $odir/$name $odir/${name}S.$objext"
+           if test yes = "$fast_install" && test -n "$relink_command"; then
+             func_append rmfiles " $odir/lt-$name"
+           fi
+           if test "X$noexename" != "X$name"; then
+             func_append rmfiles " $odir/lt-$noexename.c"
+           fi
+         fi
+       fi
+       ;;
+      esac
+      func_show_eval "$RM $rmfiles" 'exit_status=1'
+    done
+
+    # Try to remove the $objdir's in the directories where we deleted files
+    for dir in $rmdirs; do
+      if test -d "$dir"; then
+       func_show_eval "rmdir $dir >/dev/null 2>&1"
+      fi
+    done
+
+    exit $exit_status
+}
+
+if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then
+  func_mode_uninstall ${1+"$@"}
+fi
+
+test -z "$opt_mode" && {
+  help=$generic_help
+  func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+  func_fatal_help "invalid operation mode '$opt_mode'"
+
+if test -n "$exec_cmd"; then
+  eval exec "$exec_cmd"
+  exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# where we disable both kinds of libraries.  Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them.  This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration.  But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/sntp/libevent/m4/ax_check_funcs_ex.m4 b/sntp/libevent/m4/ax_check_funcs_ex.m4
new file mode 100644 (file)
index 0000000..7aaa58b
--- /dev/null
@@ -0,0 +1,22 @@
+# Check if the function is available.
+# HAVE_XXX will be defined if yes.
+
+# $1: the name of function
+# $2: the headers in where the function declared
+AC_DEFUN([AX_CHECK_DECL_EX], [dnl
+       AS_IF([test "x$2" = "x"], [AC_MSG_ERROR([header not privided])])
+       AS_VAR_PUSHDEF([have_func_var], [HAVE_[]m4_toupper($1)])
+       AC_CHECK_DECL([$1],dnl
+               [AC_DEFINE([have_func_var], [1], [Define to 1 if you have the `$1' function.])],,dnl
+               [$2]dnl
+       )
+       AS_VAR_POPDEF([have_func_var])dnl
+])
+
+AC_DEFUN([AX_CHECK_DECLS_EX], [dnl
+       AS_IF([test "x$2" = "x"], [AC_MSG_ERROR([header not privided])])
+       m4_foreach([decl],dnl
+               m4_split(m4_normalize($1)),dnl
+               [AX_CHECK_DECL_EX([decl], [$2])]dnl
+       )
+])
diff --git a/sntp/libevent/m4/ax_prog_doxygen.m4 b/sntp/libevent/m4/ax_prog_doxygen.m4
new file mode 100644 (file)
index 0000000..e5bdeb5
--- /dev/null
@@ -0,0 +1,600 @@
+# ===========================================================================
+#     https://www.gnu.org/software/autoconf-archive/ax_prog_doxygen.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   DX_INIT_DOXYGEN(PROJECT-NAME, [DOXYFILE-PATH], [OUTPUT-DIR], ...)
+#   DX_DOXYGEN_FEATURE(ON|OFF)
+#   DX_DOT_FEATURE(ON|OFF)
+#   DX_HTML_FEATURE(ON|OFF)
+#   DX_CHM_FEATURE(ON|OFF)
+#   DX_CHI_FEATURE(ON|OFF)
+#   DX_MAN_FEATURE(ON|OFF)
+#   DX_RTF_FEATURE(ON|OFF)
+#   DX_XML_FEATURE(ON|OFF)
+#   DX_PDF_FEATURE(ON|OFF)
+#   DX_PS_FEATURE(ON|OFF)
+#
+# DESCRIPTION
+#
+#   The DX_*_FEATURE macros control the default setting for the given
+#   Doxygen feature. Supported features are 'DOXYGEN' itself, 'DOT' for
+#   generating graphics, 'HTML' for plain HTML, 'CHM' for compressed HTML
+#   help (for MS users), 'CHI' for generating a separate .chi file by the
+#   .chm file, and 'MAN', 'RTF', 'XML', 'PDF' and 'PS' for the appropriate
+#   output formats. The environment variable DOXYGEN_PAPER_SIZE may be
+#   specified to override the default 'a4wide' paper size.
+#
+#   By default, HTML, PDF and PS documentation is generated as this seems to
+#   be the most popular and portable combination. MAN pages created by
+#   Doxygen are usually problematic, though by picking an appropriate subset
+#   and doing some massaging they might be better than nothing. CHM and RTF
+#   are specific for MS (note that you can't generate both HTML and CHM at
+#   the same time). The XML is rather useless unless you apply specialized
+#   post-processing to it.
+#
+#   The macros mainly control the default state of the feature. The use can
+#   override the default by specifying --enable or --disable. The macros
+#   ensure that contradictory flags are not given (e.g.,
+#   --enable-doxygen-html and --enable-doxygen-chm,
+#   --enable-doxygen-anything with --disable-doxygen, etc.) Finally, each
+#   feature will be automatically disabled (with a warning) if the required
+#   programs are missing.
+#
+#   Once all the feature defaults have been specified, call DX_INIT_DOXYGEN
+#   with the following parameters: a one-word name for the project for use
+#   as a filename base etc., an optional configuration file name (the
+#   default is '$(srcdir)/Doxyfile', the same as Doxygen's default), and an
+#   optional output directory name (the default is 'doxygen-doc'). To run
+#   doxygen multiple times for different configuration files and output
+#   directories provide more parameters: the second, forth, sixth, etc
+#   parameter are configuration file names and the third, fifth, seventh,
+#   etc parameter are output directories. No checking is done to catch
+#   duplicates.
+#
+#   Automake Support
+#
+#   The DX_RULES substitution can be used to add all needed rules to the
+#   Makefile. Note that this is a substitution without being a variable:
+#   only the @DX_RULES@ syntax will work.
+#
+#   The provided targets are:
+#
+#     doxygen-doc: Generate all doxygen documentation.
+#
+#     doxygen-run: Run doxygen, which will generate some of the
+#                  documentation (HTML, CHM, CHI, MAN, RTF, XML)
+#                  but will not do the post processing required
+#                  for the rest of it (PS, PDF).
+#
+#     doxygen-ps:  Generate doxygen PostScript documentation.
+#
+#     doxygen-pdf: Generate doxygen PDF documentation.
+#
+#   Note that by default these are not integrated into the automake targets.
+#   If doxygen is used to generate man pages, you can achieve this
+#   integration by setting man3_MANS to the list of man pages generated and
+#   then adding the dependency:
+#
+#     $(man3_MANS): doxygen-doc
+#
+#   This will cause make to run doxygen and generate all the documentation.
+#
+#   The following variable is intended for use in Makefile.am:
+#
+#     DX_CLEANFILES = everything to clean.
+#
+#   Then add this variable to MOSTLYCLEANFILES.
+#
+# LICENSE
+#
+#   Copyright (c) 2009 Oren Ben-Kiki <oren@ben-kiki.org>
+#   Copyright (c) 2015 Olaf Mandel <olaf@mandel.name>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 24
+
+## ----------##
+## Defaults. ##
+## ----------##
+
+DX_ENV=""
+AC_DEFUN([DX_FEATURE_doc],  OFF)
+AC_DEFUN([DX_FEATURE_dot],  OFF)
+AC_DEFUN([DX_FEATURE_man],  OFF)
+AC_DEFUN([DX_FEATURE_html], ON)
+AC_DEFUN([DX_FEATURE_chm],  OFF)
+AC_DEFUN([DX_FEATURE_chi],  OFF)
+AC_DEFUN([DX_FEATURE_rtf],  OFF)
+AC_DEFUN([DX_FEATURE_xml],  OFF)
+AC_DEFUN([DX_FEATURE_pdf],  ON)
+AC_DEFUN([DX_FEATURE_ps],   ON)
+
+## --------------- ##
+## Private macros. ##
+## --------------- ##
+
+# DX_ENV_APPEND(VARIABLE, VALUE)
+# ------------------------------
+# Append VARIABLE="VALUE" to DX_ENV for invoking doxygen and add it
+# as a substitution (but not a Makefile variable). The substitution
+# is skipped if the variable name is VERSION.
+AC_DEFUN([DX_ENV_APPEND],
+[AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])dnl
+m4_if([$1], [VERSION], [], [AC_SUBST([$1], [$2])dnl
+AM_SUBST_NOTMAKE([$1])])dnl
+])
+
+# DX_DIRNAME_EXPR
+# ---------------
+# Expand into a shell expression prints the directory part of a path.
+AC_DEFUN([DX_DIRNAME_EXPR],
+         [[expr ".$1" : '\(\.\)[^/]*$' \| "x$1" : 'x\(.*\)/[^/]*$']])
+
+# DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF)
+# -------------------------------------
+# Expands according to the M4 (static) status of the feature.
+AC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])])
+
+# DX_REQUIRE_PROG(VARIABLE, PROGRAM)
+# ----------------------------------
+# Require the specified program to be found for the DX_CURRENT_FEATURE to work.
+AC_DEFUN([DX_REQUIRE_PROG], [
+AC_PATH_TOOL([$1], [$2])
+if test "$DX_FLAG_[]DX_CURRENT_FEATURE$$1" = 1; then
+    if test "x$2" = "xdoxygen"; then
+        AC_MSG_ERROR([$2 not found - will not DX_CURRENT_DESCRIPTION])
+    else
+        AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION])
+    fi
+    AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0)
+fi
+])
+
+# DX_TEST_FEATURE(FEATURE)
+# ------------------------
+# Expand to a shell expression testing whether the feature is active.
+AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1])
+
+# DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE)
+# -------------------------------------------------
+# Verify that a required features has the right state before trying to turn on
+# the DX_CURRENT_FEATURE.
+AC_DEFUN([DX_CHECK_DEPEND], [
+test "$DX_FLAG_$1" = "$2" \
+|| AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1,
+                            requires, contradicts) doxygen-$1])
+])
+
+# DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE)
+# ----------------------------------------------------------
+# Turn off the DX_CURRENT_FEATURE if the required feature is off.
+AC_DEFUN([DX_CLEAR_DEPEND], [
+test "$DX_FLAG_$1" = "$2" || AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0)
+])
+
+# DX_FEATURE_ARG(FEATURE, DESCRIPTION,
+#                CHECK_DEPEND, CLEAR_DEPEND,
+#                REQUIRE, DO-IF-ON, DO-IF-OFF)
+# --------------------------------------------
+# Parse the command-line option controlling a feature. CHECK_DEPEND is called
+# if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND),
+# otherwise CLEAR_DEPEND is called to turn off the default state if a required
+# feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional
+# requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and
+# DO-IF-ON or DO-IF-OFF are called according to the final state of the feature.
+AC_DEFUN([DX_ARG_ABLE], [
+    AC_DEFUN([DX_CURRENT_FEATURE], [$1])
+    AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2])
+    AC_ARG_ENABLE(doxygen-$1,
+                  [AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1],
+                                                      [--enable-doxygen-$1]),
+                                  DX_IF_FEATURE([$1], [don't $2], [$2]))],
+                  [
+case "$enableval" in
+#(
+y|Y|yes|Yes|YES)
+    AC_SUBST([DX_FLAG_$1], 1)
+    $3
+;; #(
+n|N|no|No|NO)
+    AC_SUBST([DX_FLAG_$1], 0)
+;; #(
+*)
+    AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1])
+;;
+esac
+], [
+AC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)])
+$4
+])
+if DX_TEST_FEATURE([$1]); then
+    $5
+    :
+fi
+if DX_TEST_FEATURE([$1]); then
+    $6
+    :
+else
+    $7
+    :
+fi
+])
+
+## -------------- ##
+## Public macros. ##
+## -------------- ##
+
+# DX_XXX_FEATURE(DEFAULT_STATE)
+# -----------------------------
+AC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc],  [$1])])
+AC_DEFUN([DX_DOT_FEATURE],     [AC_DEFUN([DX_FEATURE_dot], [$1])])
+AC_DEFUN([DX_MAN_FEATURE],     [AC_DEFUN([DX_FEATURE_man],  [$1])])
+AC_DEFUN([DX_HTML_FEATURE],    [AC_DEFUN([DX_FEATURE_html], [$1])])
+AC_DEFUN([DX_CHM_FEATURE],     [AC_DEFUN([DX_FEATURE_chm],  [$1])])
+AC_DEFUN([DX_CHI_FEATURE],     [AC_DEFUN([DX_FEATURE_chi],  [$1])])
+AC_DEFUN([DX_RTF_FEATURE],     [AC_DEFUN([DX_FEATURE_rtf],  [$1])])
+AC_DEFUN([DX_XML_FEATURE],     [AC_DEFUN([DX_FEATURE_xml],  [$1])])
+AC_DEFUN([DX_XML_FEATURE],     [AC_DEFUN([DX_FEATURE_xml],  [$1])])
+AC_DEFUN([DX_PDF_FEATURE],     [AC_DEFUN([DX_FEATURE_pdf],  [$1])])
+AC_DEFUN([DX_PS_FEATURE],      [AC_DEFUN([DX_FEATURE_ps],   [$1])])
+
+# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR], ...)
+# --------------------------------------------------------------
+# PROJECT also serves as the base name for the documentation files.
+# The default CONFIG-FILE is "$(srcdir)/Doxyfile" and OUTPUT-DOC-DIR is
+# "doxygen-doc".
+# More arguments are interpreted as interleaved CONFIG-FILE and
+# OUTPUT-DOC-DIR values.
+AC_DEFUN([DX_INIT_DOXYGEN], [
+
+# Files:
+AC_SUBST([DX_PROJECT], [$1])
+AC_SUBST([DX_CONFIG], ['ifelse([$2], [], [$(srcdir)/Doxyfile], [$2])'])
+AC_SUBST([DX_DOCDIR], ['ifelse([$3], [], [doxygen-doc], [$3])'])
+m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 4, m4_count($@), 2,
+      [AC_SUBST([DX_CONFIG]m4_eval(DX_i[/2]),
+                'm4_default_nblank_quoted(m4_argn(DX_i, $@),
+                                          [$(srcdir)/Doxyfile])')])])dnl
+m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 5, m4_count($@,), 2,
+      [AC_SUBST([DX_DOCDIR]m4_eval([(]DX_i[-1)/2]),
+                'm4_default_nblank_quoted(m4_argn(DX_i, $@),
+                                          [doxygen-doc])')])])dnl
+m4_define([DX_loop], m4_dquote(m4_if(m4_eval(3 < m4_count($@)), 1,
+          [m4_for([DX_i], 4, m4_count($@), 2, [, m4_eval(DX_i[/2])])],
+          [])))dnl
+
+# Environment variables used inside doxygen.cfg:
+DX_ENV_APPEND(SRCDIR, $srcdir)
+DX_ENV_APPEND(PROJECT, $DX_PROJECT)
+DX_ENV_APPEND(VERSION, $PACKAGE_VERSION)
+
+# Doxygen itself:
+DX_ARG_ABLE(doc, [generate any doxygen documentation],
+            [],
+            [],
+            [DX_REQUIRE_PROG([DX_DOXYGEN], doxygen)
+             DX_REQUIRE_PROG([DX_PERL], perl)],
+            [DX_ENV_APPEND(PERL_PATH, $DX_PERL)])
+
+# Dot for graphics:
+DX_ARG_ABLE(dot, [generate graphics for doxygen documentation],
+            [DX_CHECK_DEPEND(doc, 1)],
+            [DX_CLEAR_DEPEND(doc, 1)],
+            [DX_REQUIRE_PROG([DX_DOT], dot)],
+            [DX_ENV_APPEND(HAVE_DOT, YES)
+             DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])],
+            [DX_ENV_APPEND(HAVE_DOT, NO)])
+
+# Man pages generation:
+DX_ARG_ABLE(man, [generate doxygen manual pages],
+            [DX_CHECK_DEPEND(doc, 1)],
+            [DX_CLEAR_DEPEND(doc, 1)],
+            [],
+            [DX_ENV_APPEND(GENERATE_MAN, YES)],
+            [DX_ENV_APPEND(GENERATE_MAN, NO)])
+
+# RTF file generation:
+DX_ARG_ABLE(rtf, [generate doxygen RTF documentation],
+            [DX_CHECK_DEPEND(doc, 1)],
+            [DX_CLEAR_DEPEND(doc, 1)],
+            [],
+            [DX_ENV_APPEND(GENERATE_RTF, YES)],
+            [DX_ENV_APPEND(GENERATE_RTF, NO)])
+
+# XML file generation:
+DX_ARG_ABLE(xml, [generate doxygen XML documentation],
+            [DX_CHECK_DEPEND(doc, 1)],
+            [DX_CLEAR_DEPEND(doc, 1)],
+            [],
+            [DX_ENV_APPEND(GENERATE_XML, YES)],
+            [DX_ENV_APPEND(GENERATE_XML, NO)])
+
+# (Compressed) HTML help generation:
+DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation],
+            [DX_CHECK_DEPEND(doc, 1)],
+            [DX_CLEAR_DEPEND(doc, 1)],
+            [DX_REQUIRE_PROG([DX_HHC], hhc)],
+            [DX_ENV_APPEND(HHC_PATH, $DX_HHC)
+             DX_ENV_APPEND(GENERATE_HTML, YES)
+             DX_ENV_APPEND(GENERATE_HTMLHELP, YES)],
+            [DX_ENV_APPEND(GENERATE_HTMLHELP, NO)])
+
+# Separate CHI file generation.
+DX_ARG_ABLE(chi, [generate doxygen separate compressed HTML help index file],
+            [DX_CHECK_DEPEND(chm, 1)],
+            [DX_CLEAR_DEPEND(chm, 1)],
+            [],
+            [DX_ENV_APPEND(GENERATE_CHI, YES)],
+            [DX_ENV_APPEND(GENERATE_CHI, NO)])
+
+# Plain HTML pages generation:
+DX_ARG_ABLE(html, [generate doxygen plain HTML documentation],
+            [DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)],
+            [DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)],
+            [],
+            [DX_ENV_APPEND(GENERATE_HTML, YES)],
+            [DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)])
+
+# PostScript file generation:
+DX_ARG_ABLE(ps, [generate doxygen PostScript documentation],
+            [DX_CHECK_DEPEND(doc, 1)],
+            [DX_CLEAR_DEPEND(doc, 1)],
+            [DX_REQUIRE_PROG([DX_LATEX], latex)
+             DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
+             DX_REQUIRE_PROG([DX_DVIPS], dvips)
+             DX_REQUIRE_PROG([DX_EGREP], egrep)])
+
+# PDF file generation:
+DX_ARG_ABLE(pdf, [generate doxygen PDF documentation],
+            [DX_CHECK_DEPEND(doc, 1)],
+            [DX_CLEAR_DEPEND(doc, 1)],
+            [DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex)
+             DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
+             DX_REQUIRE_PROG([DX_EGREP], egrep)])
+
+# LaTeX generation for PS and/or PDF:
+if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then
+    DX_ENV_APPEND(GENERATE_LATEX, YES)
+else
+    DX_ENV_APPEND(GENERATE_LATEX, NO)
+fi
+
+# Paper size for PS and/or PDF:
+AC_ARG_VAR(DOXYGEN_PAPER_SIZE,
+           [a4wide (default), a4, letter, legal or executive])
+case "$DOXYGEN_PAPER_SIZE" in
+#(
+"")
+    AC_SUBST(DOXYGEN_PAPER_SIZE, "")
+;; #(
+a4wide|a4|letter|legal|executive)
+    DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE)
+;; #(
+*)
+    AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE'])
+;;
+esac
+
+# Rules:
+AS_IF([[test $DX_FLAG_html -eq 1]],
+[[DX_SNIPPET_html="## ------------------------------- ##
+## Rules specific for HTML output. ##
+## ------------------------------- ##
+
+DX_CLEAN_HTML = \$(DX_DOCDIR)/html]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+                \$(DX_DOCDIR]DX_i[)/html]])[
+
+"]],
+[[DX_SNIPPET_html=""]])
+AS_IF([[test $DX_FLAG_chi -eq 1]],
+[[DX_SNIPPET_chi="
+DX_CLEAN_CHI = \$(DX_DOCDIR)/\$(PACKAGE).chi]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).chi]])["]],
+[[DX_SNIPPET_chi=""]])
+AS_IF([[test $DX_FLAG_chm -eq 1]],
+[[DX_SNIPPET_chm="## ------------------------------ ##
+## Rules specific for CHM output. ##
+## ------------------------------ ##
+
+DX_CLEAN_CHM = \$(DX_DOCDIR)/chm]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/chm]])[\
+${DX_SNIPPET_chi}
+
+"]],
+[[DX_SNIPPET_chm=""]])
+AS_IF([[test $DX_FLAG_man -eq 1]],
+[[DX_SNIPPET_man="## ------------------------------ ##
+## Rules specific for MAN output. ##
+## ------------------------------ ##
+
+DX_CLEAN_MAN = \$(DX_DOCDIR)/man]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/man]])[
+
+"]],
+[[DX_SNIPPET_man=""]])
+AS_IF([[test $DX_FLAG_rtf -eq 1]],
+[[DX_SNIPPET_rtf="## ------------------------------ ##
+## Rules specific for RTF output. ##
+## ------------------------------ ##
+
+DX_CLEAN_RTF = \$(DX_DOCDIR)/rtf]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/rtf]])[
+
+"]],
+[[DX_SNIPPET_rtf=""]])
+AS_IF([[test $DX_FLAG_xml -eq 1]],
+[[DX_SNIPPET_xml="## ------------------------------ ##
+## Rules specific for XML output. ##
+## ------------------------------ ##
+
+DX_CLEAN_XML = \$(DX_DOCDIR)/xml]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/xml]])[
+
+"]],
+[[DX_SNIPPET_xml=""]])
+AS_IF([[test $DX_FLAG_ps -eq 1]],
+[[DX_SNIPPET_ps="## ----------------------------- ##
+## Rules specific for PS output. ##
+## ----------------------------- ##
+
+DX_CLEAN_PS = \$(DX_DOCDIR)/\$(PACKAGE).ps]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+              \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).ps]])[
+
+DX_PS_GOAL = doxygen-ps
+
+doxygen-ps: \$(DX_CLEAN_PS)
+
+]m4_foreach([DX_i], [DX_loop],
+[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).ps: \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag
+       \$(DX_V_LATEX)cd \$(DX_DOCDIR]DX_i[)/latex; \\
+       rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\
+       \$(DX_LATEX) refman.tex; \\
+       \$(DX_MAKEINDEX) refman.idx; \\
+       \$(DX_LATEX) refman.tex; \\
+       countdown=5; \\
+       while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\
+                         refman.log > /dev/null 2>&1 \\
+          && test \$\$countdown -gt 0; do \\
+           \$(DX_LATEX) refman.tex; \\
+            countdown=\`expr \$\$countdown - 1\`; \\
+       done; \\
+       \$(DX_DVIPS) -o ../\$(PACKAGE).ps refman.dvi
+
+]])["]],
+[[DX_SNIPPET_ps=""]])
+AS_IF([[test $DX_FLAG_pdf -eq 1]],
+[[DX_SNIPPET_pdf="## ------------------------------ ##
+## Rules specific for PDF output. ##
+## ------------------------------ ##
+
+DX_CLEAN_PDF = \$(DX_DOCDIR)/\$(PACKAGE).pdf]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).pdf]])[
+
+DX_PDF_GOAL = doxygen-pdf
+
+doxygen-pdf: \$(DX_CLEAN_PDF)
+
+]m4_foreach([DX_i], [DX_loop],
+[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).pdf: \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag
+       \$(DX_V_LATEX)cd \$(DX_DOCDIR]DX_i[)/latex; \\
+       rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\
+       \$(DX_PDFLATEX) refman.tex; \\
+       \$(DX_MAKEINDEX) refman.idx; \\
+       \$(DX_PDFLATEX) refman.tex; \\
+       countdown=5; \\
+       while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\
+                         refman.log > /dev/null 2>&1 \\
+          && test \$\$countdown -gt 0; do \\
+           \$(DX_PDFLATEX) refman.tex; \\
+           countdown=\`expr \$\$countdown - 1\`; \\
+       done; \\
+       mv refman.pdf ../\$(PACKAGE).pdf
+
+]])["]],
+[[DX_SNIPPET_pdf=""]])
+AS_IF([[test $DX_FLAG_ps -eq 1 -o $DX_FLAG_pdf -eq 1]],
+[[DX_SNIPPET_latex="## ------------------------------------------------- ##
+## Rules specific for LaTeX (shared for PS and PDF). ##
+## ------------------------------------------------- ##
+
+DX_V_LATEX = \$(_DX_v_LATEX_\$(V))
+_DX_v_LATEX_ = \$(_DX_v_LATEX_\$(AM_DEFAULT_VERBOSITY))
+_DX_v_LATEX_0 = @echo \"  LATEX \" \$][@;
+
+DX_CLEAN_LATEX = \$(DX_DOCDIR)/latex]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+                 \$(DX_DOCDIR]DX_i[)/latex]])[
+
+"]],
+[[DX_SNIPPET_latex=""]])
+
+AS_IF([[test $DX_FLAG_doc -eq 1]],
+[[DX_SNIPPET_doc="## --------------------------------- ##
+## Format-independent Doxygen rules. ##
+## --------------------------------- ##
+
+${DX_SNIPPET_html}\
+${DX_SNIPPET_chm}\
+${DX_SNIPPET_man}\
+${DX_SNIPPET_rtf}\
+${DX_SNIPPET_xml}\
+${DX_SNIPPET_ps}\
+${DX_SNIPPET_pdf}\
+${DX_SNIPPET_latex}\
+DX_V_DXGEN = \$(_DX_v_DXGEN_\$(V))
+_DX_v_DXGEN_ = \$(_DX_v_DXGEN_\$(AM_DEFAULT_VERBOSITY))
+_DX_v_DXGEN_0 = @echo \"  DXGEN \" \$<;
+
+.PHONY: doxygen-run doxygen-doc \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
+
+.INTERMEDIATE: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
+
+doxygen-run:]m4_foreach([DX_i], [DX_loop],
+                         [[ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag]])[
+
+doxygen-doc: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
+
+]m4_foreach([DX_i], [DX_loop],
+[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag: \$(DX_CONFIG]DX_i[) \$(pkginclude_HEADERS)
+       \$(A""M_V_at)rm -rf \$(DX_DOCDIR]DX_i[)
+       \$(DX_V_DXGEN)\$(DX_ENV) DOCDIR=\$(DX_DOCDIR]DX_i[) \$(DX_DOXYGEN) \$(DX_CONFIG]DX_i[)
+       \$(A""M_V_at)echo Timestamp >\$][@
+
+]])dnl
+[DX_CLEANFILES = \\]
+m4_foreach([DX_i], [DX_loop],
+[[     \$(DX_DOCDIR]DX_i[)/doxygen_sqlite3.db \\
+       \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag \\
+]])dnl
+[      -r \\
+       \$(DX_CLEAN_HTML) \\
+       \$(DX_CLEAN_CHM) \\
+       \$(DX_CLEAN_CHI) \\
+       \$(DX_CLEAN_MAN) \\
+       \$(DX_CLEAN_RTF) \\
+       \$(DX_CLEAN_XML) \\
+       \$(DX_CLEAN_PS) \\
+       \$(DX_CLEAN_PDF) \\
+       \$(DX_CLEAN_LATEX)
+DX_INSTALL_DOCS = \\
+       \$(DX_CLEAN_HTML) \\
+       \$(DX_CLEAN_CHM) \\
+       \$(DX_CLEAN_CHI) \\
+       \$(DX_CLEAN_RTF) \\
+       \$(DX_CLEAN_XML) \\
+       \$(DX_CLEAN_PS) \\
+       \$(DX_CLEAN_PDF) \\
+       \$(DX_CLEAN_LATEX)
+    "]],
+[[DX_SNIPPET_doc=""]])
+AC_SUBST([DX_RULES],
+["${DX_SNIPPET_doc}"])dnl
+AM_SUBST_NOTMAKE([DX_RULES])
+
+#For debugging:
+#echo DX_FLAG_doc=$DX_FLAG_doc
+#echo DX_FLAG_dot=$DX_FLAG_dot
+#echo DX_FLAG_man=$DX_FLAG_man
+#echo DX_FLAG_html=$DX_FLAG_html
+#echo DX_FLAG_chm=$DX_FLAG_chm
+#echo DX_FLAG_chi=$DX_FLAG_chi
+#echo DX_FLAG_rtf=$DX_FLAG_rtf
+#echo DX_FLAG_xml=$DX_FLAG_xml
+#echo DX_FLAG_pdf=$DX_FLAG_pdf
+#echo DX_FLAG_ps=$DX_FLAG_ps
+#echo DX_ENV=$DX_ENV
+])
index 3cb064a0bd369308e00f754e33e3fda2123e245e..a5ea67620067fb7301b0f420152300e95ef8a2b4 100644 (file)
@@ -26,18 +26,32 @@ case "$enable_openssl" in
        save_LIBS="$LIBS"
        LIBS=""
        OPENSSL_LIBS=""
-       AC_SEARCH_LIBS([SSL_new], [ssl],
-           [have_openssl=yes
-           OPENSSL_LIBS="$LIBS -lcrypto $EV_LIB_GDI $EV_LIB_WS32 $OPENSSL_LIBADD"],
-           [have_openssl=no],
-           [-lcrypto $EV_LIB_GDI $EV_LIB_WS32 $OPENSSL_LIBADD])
-       LIBS="$save_LIBS"
+       for lib in crypto eay32; do
+               # clear cache
+               unset ac_cv_search_SSL_new
+               AC_SEARCH_LIBS([SSL_new], [ssl ssl32],
+                   [have_openssl=yes
+                   OPENSSL_LIBS="$LIBS -l$lib $EV_LIB_GDI $EV_LIB_WS32 $OPENSSL_LIBADD"],
+                   [have_openssl=no],
+                   [-l$lib $EV_LIB_GDI $EV_LIB_WS32 $OPENSSL_LIBADD])
+               LIBS="$save_LIBS"
+               test "$have_openssl" = "yes" && break
+       done
        ;;
     esac
+    CPPFLAGS_SAVE=$CPPFLAGS
+    CPPFLAGS="$CPPFLAGS $OPENSSL_INCS"
+    AC_CHECK_HEADERS([openssl/ssl.h], [], [have_openssl=no])
+    CPPFLAGS=$CPPFLAGS_SAVE
     AC_SUBST(OPENSSL_INCS)
     AC_SUBST(OPENSSL_LIBS)
     case "$have_openssl" in
      yes)  AC_DEFINE(HAVE_OPENSSL, 1, [Define if the system has openssl]) ;;
+     *) AC_MSG_ERROR([openssl is a must but can not be found. You should add the \
+directory containing `openssl.pc' to the `PKG_CONFIG_PATH' environment variable, \
+or set `CFLAGS' and `LDFLAGS' directly for openssl, or use `--disable-openssl' \
+to disable support for openssl encryption])
+       ;;
     esac
     ;;
 esac
index e31018a2dd55377e03da5106e4755f6cbdd92930..3dc404b5cc47c03da4c0db617e9ec2588fd9cfac 100644 (file)
@@ -18,6 +18,10 @@ $a\
 \
 #endif /* event2/event-config.h */
 
-s/#\( *\)define /#\1define EVENT__/
-s/#\( *\)undef /#\1undef EVENT__/
-s/#\( *\)if\(n*\)def /#\1if\2def EVENT__/
+/#\( *\)undef STDC_HEADERS\>/b
+/#\( *\)define STDC_HEADERS\>/b
+
+# Only rewrite symbols starting with capitals
+s/#\( *\)define \([A-Z]\)/#\1define EVENT__\2/
+s/#\( *\)undef \([A-Z]\)/#\1undef EVENT__\2/
+s/#\( *\)if\(n*\)def \([A-Z]\)/#\1if\2def EVENT__\2/
index b3b6f1fd497e52be859e5c158f15b1533e2c5af6..b3a0eb1fb5897ab68a6db9ee5281fea74024976d 100644 (file)
@@ -70,7 +70,7 @@ struct event* min_heap_top_(min_heap_t* s) { return s->n ? *s->p : 0; }
 
 int min_heap_push_(min_heap_t* s, struct event* e)
 {
-       if (min_heap_reserve_(s, s->n + 1))
+       if (s->n == UINT32_MAX || min_heap_reserve_(s, s->n + 1))
                return -1;
        min_heap_shift_up_(s, s->n++, e);
        return 0;
@@ -138,6 +138,10 @@ int min_heap_reserve_(min_heap_t* s, unsigned n)
                unsigned a = s->a ? s->a * 2 : 8;
                if (a < n)
                        a = n;
+#if (SIZE_MAX == UINT32_MAX)
+               if (a > SIZE_MAX / sizeof *p)
+                       return -1;
+#endif
                if (!(p = (struct event**)mm_realloc(s->p, a * sizeof *p)))
                        return -1;
                s->p = p;
diff --git a/sntp/libevent/missing b/sntp/libevent/missing
new file mode 100755 (executable)
index 0000000..f62bbae
--- /dev/null
@@ -0,0 +1,215 @@
+#! /bin/sh
+# Common wrapper for a few potentially missing GNU programs.
+
+scriptversion=2013-10-28.13; # UTC
+
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try '$0 --help' for more information"
+  exit 1
+fi
+
+case $1 in
+
+  --is-lightweight)
+    # Used by our autoconf macros to check whether the available missing
+    # script is modern enough.
+    exit 0
+    ;;
+
+  --run)
+    # Back-compat with the calling convention used by older automake.
+    shift
+    ;;
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
+to PROGRAM being missing or too old.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+
+Supported PROGRAM values:
+  aclocal   autoconf  autoheader   autom4te  automake  makeinfo
+  bison     yacc      flex         lex       help2man
+
+Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
+'g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+    exit $?
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing $scriptversion (GNU Automake)"
+    exit $?
+    ;;
+
+  -*)
+    echo 1>&2 "$0: unknown '$1' option"
+    echo 1>&2 "Try '$0 --help' for more information"
+    exit 1
+    ;;
+
+esac
+
+# Run the given program, remember its exit status.
+"$@"; st=$?
+
+# If it succeeded, we are done.
+test $st -eq 0 && exit 0
+
+# Also exit now if we it failed (or wasn't found), and '--version' was
+# passed; such an option is passed most likely to detect whether the
+# program is present and works.
+case $2 in --version|--help) exit $st;; esac
+
+# Exit code 63 means version mismatch.  This often happens when the user
+# tries to use an ancient version of a tool on a file that requires a
+# minimum version.
+if test $st -eq 63; then
+  msg="probably too old"
+elif test $st -eq 127; then
+  # Program was missing.
+  msg="missing on your system"
+else
+  # Program was found and executed, but failed.  Give up.
+  exit $st
+fi
+
+perl_URL=http://www.perl.org/
+flex_URL=http://flex.sourceforge.net/
+gnu_software_URL=http://www.gnu.org/software
+
+program_details ()
+{
+  case $1 in
+    aclocal|automake)
+      echo "The '$1' program is part of the GNU Automake package:"
+      echo "<$gnu_software_URL/automake>"
+      echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
+      echo "<$gnu_software_URL/autoconf>"
+      echo "<$gnu_software_URL/m4/>"
+      echo "<$perl_URL>"
+      ;;
+    autoconf|autom4te|autoheader)
+      echo "The '$1' program is part of the GNU Autoconf package:"
+      echo "<$gnu_software_URL/autoconf/>"
+      echo "It also requires GNU m4 and Perl in order to run:"
+      echo "<$gnu_software_URL/m4/>"
+      echo "<$perl_URL>"
+      ;;
+  esac
+}
+
+give_advice ()
+{
+  # Normalize program name to check for.
+  normalized_program=`echo "$1" | sed '
+    s/^gnu-//; t
+    s/^gnu//; t
+    s/^g//; t'`
+
+  printf '%s\n' "'$1' is $msg."
+
+  configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
+  case $normalized_program in
+    autoconf*)
+      echo "You should only need it if you modified 'configure.ac',"
+      echo "or m4 files included by it."
+      program_details 'autoconf'
+      ;;
+    autoheader*)
+      echo "You should only need it if you modified 'acconfig.h' or"
+      echo "$configure_deps."
+      program_details 'autoheader'
+      ;;
+    automake*)
+      echo "You should only need it if you modified 'Makefile.am' or"
+      echo "$configure_deps."
+      program_details 'automake'
+      ;;
+    aclocal*)
+      echo "You should only need it if you modified 'acinclude.m4' or"
+      echo "$configure_deps."
+      program_details 'aclocal'
+      ;;
+   autom4te*)
+      echo "You might have modified some maintainer files that require"
+      echo "the 'autom4te' program to be rebuilt."
+      program_details 'autom4te'
+      ;;
+    bison*|yacc*)
+      echo "You should only need it if you modified a '.y' file."
+      echo "You may want to install the GNU Bison package:"
+      echo "<$gnu_software_URL/bison/>"
+      ;;
+    lex*|flex*)
+      echo "You should only need it if you modified a '.l' file."
+      echo "You may want to install the Fast Lexical Analyzer package:"
+      echo "<$flex_URL>"
+      ;;
+    help2man*)
+      echo "You should only need it if you modified a dependency" \
+           "of a man page."
+      echo "You may want to install the GNU Help2man package:"
+      echo "<$gnu_software_URL/help2man/>"
+    ;;
+    makeinfo*)
+      echo "You should only need it if you modified a '.texi' file, or"
+      echo "any other file indirectly affecting the aspect of the manual."
+      echo "You might want to install the Texinfo package:"
+      echo "<$gnu_software_URL/texinfo/>"
+      echo "The spurious makeinfo call might also be the consequence of"
+      echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
+      echo "want to install GNU make:"
+      echo "<$gnu_software_URL/make/>"
+      ;;
+    *)
+      echo "You might have modified some files without having the proper"
+      echo "tools for further handling them.  Check the 'README' file, it"
+      echo "often tells you about the needed prerequisites for installing"
+      echo "this package.  You may also peek at any GNU archive site, in"
+      echo "case some other package contains this missing '$1' program."
+      ;;
+  esac
+}
+
+give_advice "$1" | sed -e '1s/^/WARNING: /' \
+                       -e '2,$s/^/         /' >&2
+
+# Propagate the correct exit status (expected to be 127 for a program
+# not found, 63 for a program that failed due to version mismatch).
+exit $st
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
index 4ba6fce4adaf7b67a54d036bed37ffaa98195627..7a95c995612024621692ddc9f5008cf9fa6469e7 100644 (file)
@@ -43,6 +43,7 @@ extern "C" {
  *     On failure, set errno to ENOMEM and return NULL.
  *     If the argument sz is 0, simply return NULL.
  */
+EVENT2_EXPORT_SYMBOL
 void *event_mm_malloc_(size_t sz);
 
 /** Allocate memory initialized to zero.
@@ -53,6 +54,7 @@ void *event_mm_malloc_(size_t sz);
  *     set errno to ENOMEM and return NULL.
  *     If either arguments are 0, simply return NULL.
  */
+EVENT2_EXPORT_SYMBOL
 void *event_mm_calloc_(size_t count, size_t size);
 
 /** Duplicate a string.
@@ -63,9 +65,12 @@ void *event_mm_calloc_(size_t count, size_t size);
  *     occurs (or would occur) in the process.
  *     If the argument str is NULL, set errno to EINVAL and return NULL.
  */
+EVENT2_EXPORT_SYMBOL
 char *event_mm_strdup_(const char *str);
 
+EVENT2_EXPORT_SYMBOL
 void *event_mm_realloc_(void *p, size_t sz);
+EVENT2_EXPORT_SYMBOL
 void event_mm_free_(void *p);
 #define mm_malloc(sz) event_mm_malloc_(sz)
 #define mm_calloc(count, size) event_mm_calloc_((count), (size))
diff --git a/sntp/libevent/openssl-compat.h b/sntp/libevent/openssl-compat.h
new file mode 100644 (file)
index 0000000..a23e342
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef OPENSSL_COMPAT_H
+#define OPENSSL_COMPAT_H
+
+#include <openssl/bio.h>
+#include "util-internal.h"
+
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+       (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
+
+static inline BIO_METHOD *BIO_meth_new(int type, const char *name)
+{
+       BIO_METHOD *biom = calloc(1, sizeof(BIO_METHOD));
+
+       if (biom != NULL) {
+               biom->type = type;
+               biom->name = name;
+       }
+       return biom;
+}
+
+#define BIO_meth_set_write(b, f) (b)->bwrite = (f)
+#define BIO_meth_set_read(b, f) (b)->bread = (f)
+#define BIO_meth_set_puts(b, f) (b)->bputs = (f)
+#define BIO_meth_set_ctrl(b, f) (b)->ctrl = (f)
+#define BIO_meth_set_create(b, f) (b)->create = (f)
+#define BIO_meth_set_destroy(b, f) (b)->destroy = (f)
+
+#define BIO_set_init(b, val) (b)->init = (val)
+#define BIO_set_data(b, val) (b)->ptr = (val)
+#define BIO_set_shutdown(b, val) (b)->shutdown = (val)
+#define BIO_get_init(b) (b)->init
+#define BIO_get_data(b) (b)->ptr
+#define BIO_get_shutdown(b) (b)->shutdown
+
+#define TLS_method SSLv23_method
+
+#define X509_getm_notBefore X509_get_notBefore
+#define X509_getm_notAfter X509_get_notAfter
+
+#endif /* (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+       (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) */
+
+#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x20700000L
+#define BIO_get_init(b) (b)->init
+#endif
+
+#endif /* OPENSSL_COMPAT_H */
index 51475934b3480e705239eba7664df430eff79de4..c3c9aac52a85bd99ac6da38b6709b817c4810858 100644 (file)
 #include "evthread-internal.h"
 #include "time-internal.h"
 
+/* Since Linux 2.6.17, poll is able to report about peer half-closed connection
+   using special POLLRDHUP flag on a read event.
+*/
+#if !defined(POLLRDHUP)
+#define POLLRDHUP 0
+#define EARLY_CLOSE_IF_HAVE_RDHUP 0
+#else
+#define EARLY_CLOSE_IF_HAVE_RDHUP EV_FEATURE_EARLY_CLOSE
+#endif
+
+
 struct pollidx {
        int idxplus1;
 };
@@ -79,8 +90,8 @@ const struct eventop pollops = {
        poll_del,
        poll_dispatch,
        poll_dealloc,
-       0, /* doesn't need_reinit */
-       EV_FEATURE_FDS,
+       1, /* need_reinit */
+       EV_FEATURE_FDS|EARLY_CLOSE_IF_HAVE_RDHUP,
        sizeof(struct pollidx),
 };
 
@@ -198,12 +209,14 @@ poll_dispatch(struct event_base *base, struct timeval *tv)
                res = 0;
 
                /* If the file gets closed notify */
-               if (what & (POLLHUP|POLLERR))
+               if (what & (POLLHUP|POLLERR|POLLNVAL))
                        what |= POLLIN|POLLOUT;
                if (what & POLLIN)
                        res |= EV_READ;
                if (what & POLLOUT)
                        res |= EV_WRITE;
+               if (what & POLLRDHUP)
+                       res |= EV_CLOSED;
                if (res == 0)
                        continue;
 
@@ -222,7 +235,7 @@ poll_add(struct event_base *base, int fd, short old, short events, void *idx_)
        int i;
 
        EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
-       if (!(events & (EV_READ|EV_WRITE)))
+       if (!(events & (EV_READ|EV_WRITE|EV_CLOSED)))
                return (0);
 
        poll_check_ok(pop);
@@ -265,6 +278,8 @@ poll_add(struct event_base *base, int fd, short old, short events, void *idx_)
                pfd->events |= POLLOUT;
        if (events & EV_READ)
                pfd->events |= POLLIN;
+       if (events & EV_CLOSED)
+               pfd->events |= POLLRDHUP;
        poll_check_ok(pop);
 
        return (0);
@@ -283,7 +298,7 @@ poll_del(struct event_base *base, int fd, short old, short events, void *idx_)
        int i;
 
        EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
-       if (!(events & (EV_READ|EV_WRITE)))
+       if (!(events & (EV_READ|EV_WRITE|EV_CLOSED)))
                return (0);
 
        poll_check_ok(pop);
@@ -297,6 +312,8 @@ poll_del(struct event_base *base, int fd, short old, short events, void *idx_)
                pfd->events &= ~POLLIN;
        if (events & EV_WRITE)
                pfd->events &= ~POLLOUT;
+       if (events & EV_CLOSED)
+               pfd->events &= ~POLLRDHUP;
        poll_check_ok(pop);
        if (pfd->events)
                /* Another event cares about that fd. */
index 15e48ce4bc66f60398084e30ae16789167df0a04..2d07c3874bcaada1b376e74bc10ad5f4f10857a9 100644 (file)
 
 #include <sys/types.h>
 
+#ifdef EVENT__HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
 #ifdef _WIN32
 #include <winsock2.h>
 #include <ws2tcpip.h>
+#include <getopt.h>
 #else
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -73,6 +78,8 @@ gai_callback(int err, struct evutil_addrinfo *ai, void *arg)
 {
        const char *name = arg;
        int i;
+       struct evutil_addrinfo *first_ai = ai;
+
        if (err) {
                printf("%s: %s\n", name, evutil_gai_strerror(err));
        }
@@ -94,6 +101,9 @@ gai_callback(int err, struct evutil_addrinfo *ai, void *arg)
                        printf("[%d] %s: %s\n",i,name,buf);
                }
        }
+
+       if (first_ai)
+               evutil_freeaddrinfo(first_ai);
 }
 
 static void
@@ -141,34 +151,36 @@ logfn(int is_warn, const char *msg) {
 
 int
 main(int c, char **v) {
-       int idx;
-       int reverse = 0, servertest = 0, use_getaddrinfo = 0;
+       struct options {
+               int reverse;
+               int use_getaddrinfo;
+               int servertest;
+               const char *resolv_conf;
+               const char *ns;
+       };
+       struct options o;
+       int opt;
        struct event_base *event_base = NULL;
        struct evdns_base *evdns_base = NULL;
-       const char *resolv_conf = NULL;
-       if (c<2) {
-               fprintf(stderr, "syntax: %s [-x] [-v] [-c resolv.conf] hostname\n", v[0]);
-               fprintf(stderr, "syntax: %s [-servertest]\n", v[0]);
+
+       memset(&o, 0, sizeof(o));
+
+       if (c < 2) {
+               fprintf(stderr, "syntax: %s [-x] [-v] [-c resolv.conf] [-s ns] hostname\n", v[0]);
+               fprintf(stderr, "syntax: %s [-T]\n", v[0]);
                return 1;
        }
-       idx = 1;
-       while (idx < c && v[idx][0] == '-') {
-               if (!strcmp(v[idx], "-x"))
-                       reverse = 1;
-               else if (!strcmp(v[idx], "-v"))
-                       verbose = 1;
-               else if (!strcmp(v[idx], "-g"))
-                       use_getaddrinfo = 1;
-               else if (!strcmp(v[idx], "-servertest"))
-                       servertest = 1;
-               else if (!strcmp(v[idx], "-c")) {
-                       if (idx + 1 < c)
-                               resolv_conf = v[++idx];
-                       else
-                               fprintf(stderr, "-c needs an argument\n");
-               } else
-                       fprintf(stderr, "Unknown option %s\n", v[idx]);
-               ++idx;
+
+       while ((opt = getopt(c, v, "xvc:Ts:g")) != -1) {
+               switch (opt) {
+                       case 'x': o.reverse = 1; break;
+                       case 'v': ++verbose; break;
+                       case 'g': o.use_getaddrinfo = 1; break;
+                       case 'T': o.servertest = 1; break;
+                       case 'c': o.resolv_conf = optarg; break;
+                       case 's': o.ns = optarg; break;
+                       default : fprintf(stderr, "Unknown option %c\n", opt); break;
+               }
        }
 
 #ifdef _WIN32
@@ -182,7 +194,7 @@ main(int c, char **v) {
        evdns_base = evdns_base_new(event_base, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
        evdns_set_log_fn(logfn);
 
-       if (servertest) {
+       if (o.servertest) {
                evutil_socket_t sock;
                struct sockaddr_in my_addr;
                sock = socket(PF_INET, SOCK_DGRAM, 0);
@@ -200,49 +212,53 @@ main(int c, char **v) {
                }
                evdns_add_server_port_with_base(event_base, sock, 0, evdns_server_callback, NULL);
        }
-       if (idx < c) {
+       if (optind < c) {
                int res;
 #ifdef _WIN32
-               if (resolv_conf == NULL)
+               if (o.resolv_conf == NULL && !o.ns)
                        res = evdns_base_config_windows_nameservers(evdns_base);
                else
 #endif
+               if (o.ns)
+                       res = evdns_base_nameserver_ip_add(evdns_base, o.ns);
+               else
                        res = evdns_base_resolv_conf_parse(evdns_base,
-                           DNS_OPTION_NAMESERVERS,
-                           resolv_conf ? resolv_conf : "/etc/resolv.conf");
+                           DNS_OPTION_NAMESERVERS, o.resolv_conf);
 
-               if (res < 0) {
-                       fprintf(stderr, "Couldn't configure nameservers");
+               if (res) {
+                       fprintf(stderr, "Couldn't configure nameservers\n");
                        return 1;
                }
        }
 
        printf("EVUTIL_AI_CANONNAME in example = %d\n", EVUTIL_AI_CANONNAME);
-       for (; idx < c; ++idx) {
-               if (reverse) {
+       for (; optind < c; ++optind) {
+               if (o.reverse) {
                        struct in_addr addr;
-                       if (evutil_inet_pton(AF_INET, v[idx], &addr)!=1) {
-                               fprintf(stderr, "Skipping non-IP %s\n", v[idx]);
+                       if (evutil_inet_pton(AF_INET, v[optind], &addr)!=1) {
+                               fprintf(stderr, "Skipping non-IP %s\n", v[optind]);
                                continue;
                        }
-                       fprintf(stderr, "resolving %s...\n",v[idx]);
-                       evdns_base_resolve_reverse(evdns_base, &addr, 0, main_callback, v[idx]);
-               } else if (use_getaddrinfo) {
+                       fprintf(stderr, "resolving %s...\n",v[optind]);
+                       evdns_base_resolve_reverse(evdns_base, &addr, 0, main_callback, v[optind]);
+               } else if (o.use_getaddrinfo) {
                        struct evutil_addrinfo hints;
                        memset(&hints, 0, sizeof(hints));
                        hints.ai_family = PF_UNSPEC;
                        hints.ai_protocol = IPPROTO_TCP;
                        hints.ai_flags = EVUTIL_AI_CANONNAME;
-                       fprintf(stderr, "resolving (fwd) %s...\n",v[idx]);
-                       evdns_getaddrinfo(evdns_base, v[idx], NULL, &hints,
-                           gai_callback, v[idx]);
+                       fprintf(stderr, "resolving (fwd) %s...\n",v[optind]);
+                       evdns_getaddrinfo(evdns_base, v[optind], NULL, &hints,
+                           gai_callback, v[optind]);
                } else {
-                       fprintf(stderr, "resolving (fwd) %s...\n",v[idx]);
-                       evdns_base_resolve_ipv4(evdns_base, v[idx], 0, main_callback, v[idx]);
+                       fprintf(stderr, "resolving (fwd) %s...\n",v[optind]);
+                       evdns_base_resolve_ipv4(evdns_base, v[optind], 0, main_callback, v[optind]);
                }
        }
        fflush(stdout);
        event_base_dispatch(event_base);
+       evdns_base_free(evdns_base, 1);
+       event_base_free(event_base);
        return 0;
 }
 
index 27b0b530d5c1972873357e7f22715ce0ba3413fe..a17b9bd9ae45639fa59989136b98393cb44b6dfe 100644 (file)
@@ -129,10 +129,10 @@ main(int argc, char **argv)
 
        fprintf(stderr, "Write data to %s\n", fifo);
 #endif
-       /* Initalize the event library */
+       /* Initialize the event library */
        base = event_base_new();
 
-       /* Initalize one event */
+       /* Initialize one event */
 #ifdef _WIN32
        evfifo = event_new(base, (evutil_socket_t)socket, EV_READ|EV_PERSIST, fifo_read,
                            event_self_cbarg());
index d3cf058a8b5550695b398a60988ed98e792d311f..a13e06af612dd0cf949c621339495548b2a4a869 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  This exmple program provides a trivial server program that listens for TCP
+  This example program provides a trivial server program that listens for TCP
   connections on port 9995.  When they arrive, it writes a short message to
   each client connection, and closes each connection once it is flushed.
 
@@ -42,7 +42,7 @@ main(int argc, char **argv)
        struct evconnlistener *listener;
        struct event *signal_event;
 
-       struct sockaddr_in sin;
+       struct sockaddr_in sin = {0};
 #ifdef _WIN32
        WSADATA wsa_data;
        WSAStartup(0x0201, &wsa_data);
@@ -54,7 +54,6 @@ main(int argc, char **argv)
                return 1;
        }
 
-       memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
        sin.sin_port = htons(PORT);
 
diff --git a/sntp/libevent/sample/http-connect.c b/sntp/libevent/sample/http-connect.c
new file mode 100644 (file)
index 0000000..53f816d
--- /dev/null
@@ -0,0 +1,131 @@
+#include "event2/event-config.h"
+
+#include <event2/event.h>
+#include <event2/http.h>
+#include <event2/http_struct.h>
+#include <event2/buffer.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+
+#define VERIFY(cond) do {                       \
+       if (!(cond)) {                              \
+               fprintf(stderr, "[error] %s\n", #cond); \
+               exit(EXIT_FAILURE);                     \
+       }                                           \
+} while (0);                                    \
+
+#define URL_MAX 4096
+
+struct connect_base
+{
+       struct evhttp_connection *evcon;
+       struct evhttp_uri *location;
+};
+
+static struct evhttp_uri* uri_parse(const char *str)
+{
+       struct evhttp_uri *uri;
+       VERIFY(uri = evhttp_uri_parse(str));
+       VERIFY(evhttp_uri_get_host(uri));
+       VERIFY(evhttp_uri_get_port(uri) > 0);
+       return uri;
+}
+static char* uri_path(struct evhttp_uri *uri, char buffer[URL_MAX])
+{
+       struct evhttp_uri *path;
+
+       VERIFY(evhttp_uri_join(uri, buffer, URL_MAX));
+
+       path = evhttp_uri_parse(buffer);
+       evhttp_uri_set_scheme(path, NULL);
+       evhttp_uri_set_userinfo(path, 0);
+       evhttp_uri_set_host(path, NULL);
+       evhttp_uri_set_port(path, -1);
+       VERIFY(evhttp_uri_join(path, buffer, URL_MAX));
+       return buffer;
+}
+static char* uri_hostport(struct evhttp_uri *uri, char buffer[URL_MAX])
+{
+       VERIFY(evhttp_uri_join(uri, buffer, URL_MAX));
+       VERIFY(evhttp_uri_get_host(uri));
+       VERIFY(evhttp_uri_get_port(uri) > 0);
+       evutil_snprintf(buffer, URL_MAX, "%s:%d",
+               evhttp_uri_get_host(uri), evhttp_uri_get_port(uri));
+       return buffer;
+}
+
+static void get_cb(struct evhttp_request *req, void *arg)
+{
+       ev_ssize_t len;
+       struct evbuffer *evbuf;
+
+       VERIFY(req);
+
+       evbuf = evhttp_request_get_input_buffer(req);
+       len = evbuffer_get_length(evbuf);
+       fwrite(evbuffer_pullup(evbuf, len), len, 1, stdout);
+       evbuffer_drain(evbuf, len);
+}
+
+static void connect_cb(struct evhttp_request *proxy_req, void *arg)
+{
+       struct connect_base *base = arg;
+       struct evhttp_connection *evcon = base->evcon;
+       struct evhttp_uri *location = base->location;
+       struct evhttp_request *req;
+       char buffer[URL_MAX];
+
+       VERIFY(proxy_req);
+       VERIFY(evcon);
+
+       req = evhttp_request_new(get_cb, NULL);
+       evhttp_add_header(req->output_headers, "Connection", "close");
+       evhttp_add_header(req->output_headers, "Host", evhttp_uri_get_host(location));
+       VERIFY(!evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
+               uri_path(location, buffer)));
+}
+
+int main(int argc, const char **argv)
+{
+       char hostport[URL_MAX];
+
+       struct evhttp_uri *location;
+       struct evhttp_uri *proxy;
+
+       struct event_base *base;
+       struct evhttp_connection *evcon;
+       struct evhttp_request *req;
+
+       struct connect_base connect_base;
+
+       if (argc != 3) {
+               printf("Usage: %s proxy url\n", argv[0]);
+               return 1;
+       }
+
+       proxy    = uri_parse(argv[1]);
+       location = uri_parse(argv[2]);
+
+       VERIFY(base = event_base_new());
+       VERIFY(evcon = evhttp_connection_base_new(base, NULL,
+               evhttp_uri_get_host(proxy), evhttp_uri_get_port(proxy)));
+       connect_base.evcon = evcon;
+       connect_base.location = location;
+       VERIFY(req = evhttp_request_new(connect_cb, &connect_base));
+
+       uri_hostport(location, hostport);
+       evhttp_add_header(req->output_headers, "Connection", "keep-alive");
+       evhttp_add_header(req->output_headers, "Proxy-Connection", "keep-alive");
+       evhttp_add_header(req->output_headers, "Host", hostport);
+       evhttp_make_request(evcon, req, EVHTTP_REQ_CONNECT, hostport);
+
+       event_base_dispatch(base);
+
+       evhttp_connection_free(evcon);
+       event_base_free(base);
+       evhttp_uri_free(proxy);
+       evhttp_uri_free(location);
+
+       return 0;
+}
index 904621d8df43b6b2be2c9998860b52f6e4dab755..049aabc4418ea2c6e936c358311ff47ed9cf02a3 100644 (file)
 #include <winsock2.h>
 #include <ws2tcpip.h>
 #include <windows.h>
+#include <getopt.h>
 #include <io.h>
 #include <fcntl.h>
 #ifndef S_ISDIR
 #define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
 #endif
-#else
+#else /* !_WIN32 */
 #include <sys/stat.h>
 #include <sys/socket.h>
-#include <signal.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <dirent.h>
+#endif /* _WIN32 */
+#include <signal.h>
+
+#ifdef EVENT__HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#ifdef EVENT__HAVE_AFUNIX_H
+#include <afunix.h>
 #endif
 
 #include <event2/event.h>
 #include <event2/http.h>
+#include <event2/listener.h>
 #include <event2/buffer.h>
 #include <event2/util.h>
 #include <event2/keyvalq_struct.h>
 
+#ifdef _WIN32
+#include <event2/thread.h>
+#endif /* _WIN32 */
+
 #ifdef EVENT__HAVE_NETINET_IN_H
 #include <netinet/in.h>
 # ifdef _XOPEN_SOURCE_EXTENDED
@@ -63,7 +76,7 @@
 #ifndef O_RDONLY
 #define O_RDONLY _O_RDONLY
 #endif
-#endif
+#endif /* _WIN32 */
 
 char uri_root[512];
 
@@ -82,10 +95,20 @@ static const struct table_entry {
        { "jpeg", "image/jpeg" },
        { "png", "image/png" },
        { "pdf", "application/pdf" },
-       { "ps", "application/postsript" },
+       { "ps", "application/postscript" },
        { NULL, NULL },
 };
 
+struct options {
+       int port;
+       int iocp;
+       int verbose;
+
+       int unlink;
+       const char *unixsock;
+       const char *docroot;
+};
+
 /* Try to guess a good content-type for 'path' */
 static const char *
 guess_content_type(const char *path)
@@ -159,7 +182,7 @@ static void
 send_document_cb(struct evhttp_request *req, void *arg)
 {
        struct evbuffer *evb = NULL;
-       const char *docroot = arg;
+       struct options *o = arg;
        const char *uri = evhttp_request_get_uri(req);
        struct evhttp_uri *decoded = NULL;
        const char *path;
@@ -199,12 +222,12 @@ send_document_cb(struct evhttp_request *req, void *arg)
        if (strstr(decoded_path, ".."))
                goto err;
 
-       len = strlen(decoded_path)+strlen(docroot)+2;
+       len = strlen(decoded_path)+strlen(o->docroot)+2;
        if (!(whole_path = malloc(len))) {
                perror("malloc");
                goto err;
        }
-       evutil_snprintf(whole_path, len, "%s/%s", docroot, decoded_path);
+       evutil_snprintf(whole_path, len, "%s/%s", o->docroot, decoded_path);
 
        if (stat(whole_path, &st)<0) {
                goto err;
@@ -233,10 +256,6 @@ send_document_cb(struct evhttp_request *req, void *arg)
 #ifdef _WIN32
                dirlen = strlen(whole_path);
                pattern = malloc(dirlen+3);
-               if (!pattern) {
-                       perror("malloc");
-                       goto err;
-               }
                memcpy(pattern, whole_path, dirlen);
                pattern[dirlen] = '\\';
                pattern[dirlen+1] = '*';
@@ -325,42 +344,161 @@ done:
 }
 
 static void
-syntax(void)
+print_usage(FILE *out, const char *prog, int exit_code)
+{
+       fprintf(out,
+               "Syntax: %s [ OPTS ] <docroot>\n"
+               " -p      - port\n"
+               " -U      - bind to unix socket\n"
+               " -u      - unlink unix socket before bind\n"
+               " -I      - IOCP\n"
+               " -v      - verbosity, enables libevent debug logging too\n", prog);
+       exit(exit_code);
+}
+static struct options
+parse_opts(int argc, char **argv)
 {
-       fprintf(stdout, "Syntax: http-server <docroot>\n");
+       struct options o;
+       int opt;
+
+       memset(&o, 0, sizeof(o));
+
+       while ((opt = getopt(argc, argv, "hp:U:uIv")) != -1) {
+               switch (opt) {
+                       case 'p': o.port = atoi(optarg); break;
+                       case 'U': o.unixsock = optarg; break;
+                       case 'u': o.unlink = 1; break;
+                       case 'I': o.iocp = 1; break;
+                       case 'v': ++o.verbose; break;
+                       case 'h': print_usage(stdout, argv[0], 0); break;
+                       default : fprintf(stderr, "Unknown option %c\n", opt); break;
+               }
+       }
+
+       if (optind >= argc || (argc - optind) > 1) {
+               print_usage(stdout, argv[0], 1);
+       }
+       o.docroot = argv[optind];
+
+       return o;
+}
+
+static void
+do_term(int sig, short events, void *arg)
+{
+       struct event_base *base = arg;
+       event_base_loopbreak(base);
+       fprintf(stderr, "Got %i, Terminating\n", sig);
+}
+
+static int
+display_listen_sock(struct evhttp_bound_socket *handle)
+{
+       struct sockaddr_storage ss;
+       evutil_socket_t fd;
+       ev_socklen_t socklen = sizeof(ss);
+       char addrbuf[128];
+       void *inaddr;
+       const char *addr;
+       int got_port = -1;
+
+       fd = evhttp_bound_socket_get_fd(handle);
+       memset(&ss, 0, sizeof(ss));
+       if (getsockname(fd, (struct sockaddr *)&ss, &socklen)) {
+               perror("getsockname() failed");
+               return 1;
+       }
+
+       if (ss.ss_family == AF_INET) {
+               got_port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
+               inaddr = &((struct sockaddr_in*)&ss)->sin_addr;
+       } else if (ss.ss_family == AF_INET6) {
+               got_port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port);
+               inaddr = &((struct sockaddr_in6*)&ss)->sin6_addr;
+       }
+#ifdef EVENT__HAVE_STRUCT_SOCKADDR_UN
+       else if (ss.ss_family == AF_UNIX) {
+               printf("Listening on <%s>\n", ((struct sockaddr_un*)&ss)->sun_path);
+               return 0;
+       }
+#endif
+       else {
+               fprintf(stderr, "Weird address family %d\n",
+                   ss.ss_family);
+               return 1;
+       }
+
+       addr = evutil_inet_ntop(ss.ss_family, inaddr, addrbuf,
+           sizeof(addrbuf));
+       if (addr) {
+               printf("Listening on %s:%d\n", addr, got_port);
+               evutil_snprintf(uri_root, sizeof(uri_root),
+                   "http://%s:%d",addr,got_port);
+       } else {
+               fprintf(stderr, "evutil_inet_ntop failed\n");
+               return 1;
+       }
+
+       return 0;
 }
 
 int
 main(int argc, char **argv)
 {
-       struct event_base *base;
-       struct evhttp *http;
-       struct evhttp_bound_socket *handle;
+       struct event_config *cfg = NULL;
+       struct event_base *base = NULL;
+       struct evhttp *http = NULL;
+       struct evhttp_bound_socket *handle = NULL;
+       struct evconnlistener *lev = NULL;
+       struct event *term = NULL;
+       struct options o = parse_opts(argc, argv);
+       int ret = 0;
 
-       unsigned short port = 0;
 #ifdef _WIN32
-       WSADATA WSAData;
-       WSAStartup(0x101, &WSAData);
+       {
+               WORD wVersionRequested;
+               WSADATA wsaData;
+               wVersionRequested = MAKEWORD(2, 2);
+               WSAStartup(wVersionRequested, &wsaData);
+       }
 #else
-       if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
-               return (1);
+       if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
+               ret = 1;
+               goto err;
+       }
 #endif
-       if (argc < 2) {
-               syntax();
-               return 1;
+
+       setbuf(stdout, NULL);
+       setbuf(stderr, NULL);
+
+       /** Read env like in regress */
+       if (o.verbose || getenv("EVENT_DEBUG_LOGGING_ALL"))
+               event_enable_debug_logging(EVENT_DBG_ALL);
+
+       cfg = event_config_new();
+#ifdef _WIN32
+       if (o.iocp) {
+#ifdef EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
+               evthread_use_windows_threads();
+               event_config_set_num_cpus_hint(cfg, 8);
+#endif
+               event_config_set_flag(cfg, EVENT_BASE_FLAG_STARTUP_IOCP);
        }
+#endif
 
-       base = event_base_new();
+       base = event_base_new_with_config(cfg);
        if (!base) {
                fprintf(stderr, "Couldn't create an event_base: exiting\n");
-               return 1;
+               ret = 1;
        }
+       event_config_free(cfg);
+       cfg = NULL;
 
        /* Create a new evhttp object to handle requests. */
        http = evhttp_new(base);
        if (!http) {
                fprintf(stderr, "couldn't create evhttp. Exiting.\n");
-               return 1;
+               ret = 1;
        }
 
        /* The /dump URI will dump all requests to stdout and say 200 ok. */
@@ -368,55 +506,77 @@ main(int argc, char **argv)
 
        /* We want to accept arbitrary requests, so we need to set a "generic"
         * cb.  We can also add callbacks for specific paths. */
-       evhttp_set_gencb(http, send_document_cb, argv[1]);
+       evhttp_set_gencb(http, send_document_cb, &o);
 
-       /* Now we tell the evhttp what port to listen on */
-       handle = evhttp_bind_socket_with_handle(http, "0.0.0.0", port);
-       if (!handle) {
-               fprintf(stderr, "couldn't bind to port %d. Exiting.\n",
-                   (int)port);
-               return 1;
-       }
+       if (o.unixsock) {
+#ifdef EVENT__HAVE_STRUCT_SOCKADDR_UN
+               struct sockaddr_un addr;
 
-       {
-               /* Extract and display the address we're listening on. */
-               struct sockaddr_storage ss;
-               evutil_socket_t fd;
-               ev_socklen_t socklen = sizeof(ss);
-               char addrbuf[128];
-               void *inaddr;
-               const char *addr;
-               int got_port = -1;
-               fd = evhttp_bound_socket_get_fd(handle);
-               memset(&ss, 0, sizeof(ss));
-               if (getsockname(fd, (struct sockaddr *)&ss, &socklen)) {
-                       perror("getsockname() failed");
-                       return 1;
+               if (o.unlink && (unlink(o.unixsock) && errno != ENOENT)) {
+                       perror(o.unixsock);
+                       ret = 1;
+                       goto err;
                }
-               if (ss.ss_family == AF_INET) {
-                       got_port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
-                       inaddr = &((struct sockaddr_in*)&ss)->sin_addr;
-               } else if (ss.ss_family == AF_INET6) {
-                       got_port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port);
-                       inaddr = &((struct sockaddr_in6*)&ss)->sin6_addr;
-               } else {
-                       fprintf(stderr, "Weird address family %d\n",
-                           ss.ss_family);
-                       return 1;
+
+               addr.sun_family = AF_UNIX;
+               strcpy(addr.sun_path, o.unixsock);
+
+               lev = evconnlistener_new_bind(base, NULL, NULL,
+                       LEV_OPT_CLOSE_ON_FREE, -1,
+                       (struct sockaddr *)&addr, sizeof(addr));
+               if (!lev) {
+                       perror("Cannot create listener");
+                       ret = 1;
+                       goto err;
+               }
+
+               handle = evhttp_bind_listener(http, lev);
+               if (!handle) {
+                       fprintf(stderr, "couldn't bind to %s. Exiting.\n", o.unixsock);
+                       ret = 1;
+                       goto err;
                }
-               addr = evutil_inet_ntop(ss.ss_family, inaddr, addrbuf,
-                   sizeof(addrbuf));
-               if (addr) {
-                       printf("Listening on %s:%d\n", addr, got_port);
-                       evutil_snprintf(uri_root, sizeof(uri_root),
-                           "http://%s:%d",addr,got_port);
-               } else {
-                       fprintf(stderr, "evutil_inet_ntop failed\n");
-                       return 1;
+#else /* !EVENT__HAVE_STRUCT_SOCKADDR_UN */
+               fprintf(stderr, "-U is not supported on this platform. Exiting.\n");
+               ret = 1;
+               goto err;
+#endif /* EVENT__HAVE_STRUCT_SOCKADDR_UN */
+       }
+       else {
+               handle = evhttp_bind_socket_with_handle(http, "0.0.0.0", o.port);
+               if (!handle) {
+                       fprintf(stderr, "couldn't bind to port %d. Exiting.\n", o.port);
+                       ret = 1;
+                       goto err;
                }
        }
 
+       if (display_listen_sock(handle)) {
+               ret = 1;
+               goto err;
+       }
+
+       term = evsignal_new(base, SIGINT, do_term, base);
+       if (!term)
+               goto err;
+       if (event_add(term, NULL))
+               goto err;
+
        event_base_dispatch(base);
 
-       return 0;
+#ifdef _WIN32
+       WSACleanup();
+#endif
+
+err:
+       if (cfg)
+               event_config_free(cfg);
+       if (http)
+               evhttp_free(http);
+       if (term)
+               event_free(term);
+       if (base)
+               event_base_free(base);
+
+       return ret;
 }
index fbd5de8c59c2a8be4382a15a4182796d9919a3ca..5136acebd79ad57c00ffdfce60c1a972b49a63ed 100644 (file)
@@ -45,7 +45,6 @@
 
 #include "openssl_hostname_validation.h"
 
-static struct event_base *base;
 static int ignore_cert = 0;
 
 static void
@@ -54,7 +53,7 @@ http_request_done(struct evhttp_request *req, void *ctx)
        char buffer[256];
        int nread;
 
-       if (req == NULL) {
+       if (!req || !evhttp_request_get_response_code(req)) {
                /* If req is NULL, it means an error occurred, but
                 * sadly we are mostly left guessing what the error
                 * might have been.  We'll do our best... */
@@ -96,22 +95,19 @@ static void
 syntax(void)
 {
        fputs("Syntax:\n", stderr);
-       fputs("   https-client -url <https-url> [-data data-file.bin] [-ignore-cert] [-retries num]\n", stderr);
+       fputs("   https-client -url <https-url> [-data data-file.bin] [-ignore-cert] [-retries num] [-timeout sec] [-crt crt]\n", stderr);
        fputs("Example:\n", stderr);
        fputs("   https-client -url https://ip.appspot.com/\n", stderr);
-
-       exit(1);
 }
 
 static void
-die(const char *msg)
+err(const char *msg)
 {
        fputs(msg, stderr);
-       exit(1);
 }
 
 static void
-die_openssl(const char *func)
+err_openssl(const char *func)
 {
        fprintf (stderr, "%s failed:\n", func);
 
@@ -185,27 +181,61 @@ static int cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg)
        }
 }
 
+#ifdef _WIN32
+static int
+add_cert_for_store(X509_STORE *store, const char *name)
+{
+       HCERTSTORE sys_store = NULL;
+       PCCERT_CONTEXT ctx = NULL;
+       int r = 0;
+
+       sys_store = CertOpenSystemStore(0, name);
+       if (!sys_store) {
+               err("failed to open system certificate store");
+               return -1;
+       }
+       while ((ctx = CertEnumCertificatesInStore(sys_store, ctx))) {
+               X509 *x509 = d2i_X509(NULL, (unsigned char const **)&ctx->pbCertEncoded,
+                       ctx->cbCertEncoded);
+               if (x509) {
+                       X509_STORE_add_cert(store, x509);
+                       X509_free(x509);
+               } else {
+                       r = -1;
+                       err_openssl("d2i_X509");
+                       break;
+               }
+       }
+       CertCloseStore(sys_store, 0);
+       return r;
+}
+#endif
+
 int
 main(int argc, char **argv)
 {
        int r;
-
-       struct evhttp_uri *http_uri;
+       struct event_base *base = NULL;
+       struct evhttp_uri *http_uri = NULL;
        const char *url = NULL, *data_file = NULL;
+       const char *crt = NULL;
        const char *scheme, *host, *path, *query;
        char uri[256];
        int port;
        int retries = 0;
+       int timeout = -1;
 
-       SSL_CTX *ssl_ctx;
-       SSL *ssl;
+       SSL_CTX *ssl_ctx = NULL;
+       SSL *ssl = NULL;
        struct bufferevent *bev;
-       struct evhttp_connection *evcon;
+       struct evhttp_connection *evcon = NULL;
        struct evhttp_request *req;
        struct evkeyvalq *output_headers;
-       struct evbuffer * output_buffer;
+       struct evbuffer *output_buffer;
 
        int i;
+       int ret = 0;
+       enum { HTTP, HTTPS } type = HTTP;
 
        for (i = 1; i < argc; i++) {
                if (!strcmp("-url", argv[i])) {
@@ -213,6 +243,14 @@ main(int argc, char **argv)
                                url = argv[i + 1];
                        } else {
                                syntax();
+                               goto error;
+                       }
+               } else if (!strcmp("-crt", argv[i])) {
+                       if (i < argc - 1) {
+                               crt = argv[i + 1];
+                       } else {
+                               syntax();
+                               goto error;
                        }
                } else if (!strcmp("-ignore-cert", argv[i])) {
                        ignore_cert = 1;
@@ -221,20 +259,31 @@ main(int argc, char **argv)
                                data_file = argv[i + 1];
                        } else {
                                syntax();
+                               goto error;
                        }
                } else if (!strcmp("-retries", argv[i])) {
                        if (i < argc - 1) {
                                retries = atoi(argv[i + 1]);
                        } else {
                                syntax();
+                               goto error;
+                       }
+               } else if (!strcmp("-timeout", argv[i])) {
+                       if (i < argc - 1) {
+                               timeout = atoi(argv[i + 1]);
+                       } else {
+                               syntax();
+                               goto error;
                        }
                } else if (!strcmp("-help", argv[i])) {
                        syntax();
+                       goto error;
                }
        }
 
        if (!url) {
                syntax();
+               goto error;
        }
 
 #ifdef _WIN32
@@ -248,25 +297,28 @@ main(int argc, char **argv)
                err = WSAStartup(wVersionRequested, &wsaData);
                if (err != 0) {
                        printf("WSAStartup failed with error: %d\n", err);
-                       return 1;
+                       goto error;
                }
        }
 #endif // _WIN32
 
        http_uri = evhttp_uri_parse(url);
        if (http_uri == NULL) {
-               die("malformed url");
+               err("malformed url");
+               goto error;
        }
 
        scheme = evhttp_uri_get_scheme(http_uri);
        if (scheme == NULL || (strcasecmp(scheme, "https") != 0 &&
                               strcasecmp(scheme, "http") != 0)) {
-               die("url must be http or https");
+               err("url must be http or https");
+               goto error;
        }
 
        host = evhttp_uri_get_host(http_uri);
        if (host == NULL) {
-               die("url must have a host");
+               err("url must have a host");
+               goto error;
        }
 
        port = evhttp_uri_get_port(http_uri);
@@ -275,7 +327,7 @@ main(int argc, char **argv)
        }
 
        path = evhttp_uri_get_path(http_uri);
-       if (path == NULL) {
+       if (strlen(path) == 0) {
                path = "/";
        }
 
@@ -287,33 +339,52 @@ main(int argc, char **argv)
        }
        uri[sizeof(uri) - 1] = '\0';
 
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+       (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
        // Initialize OpenSSL
        SSL_library_init();
        ERR_load_crypto_strings();
        SSL_load_error_strings();
        OpenSSL_add_all_algorithms();
+#endif
 
        /* This isn't strictly necessary... OpenSSL performs RAND_poll
         * automatically on first use of random number generator. */
        r = RAND_poll();
        if (r == 0) {
-               die_openssl("RAND_poll");
+               err_openssl("RAND_poll");
+               goto error;
        }
 
        /* Create a new OpenSSL context */
        ssl_ctx = SSL_CTX_new(SSLv23_method());
-       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,
-                                              "/etc/ssl/certs/ca-certificates.crt",
-                                              NULL))
-               die_openssl("SSL_CTX_load_verify_locations");
+       if (!ssl_ctx) {
+               err_openssl("SSL_CTX_new");
+               goto error;
+       }
+
+       if (crt == NULL) {
+               X509_STORE *store;
+               /* Attempt to use the system's trusted root certificates. */
+               store = SSL_CTX_get_cert_store(ssl_ctx);
+#ifdef _WIN32
+               if (add_cert_for_store(store, "CA") < 0 ||
+                   add_cert_for_store(store, "AuthRoot") < 0 ||
+                   add_cert_for_store(store, "ROOT") < 0) {
+                       goto error;
+               }
+#else // _WIN32
+               if (X509_STORE_set_default_paths(store) != 1) {
+                       err_openssl("X509_STORE_set_default_paths");
+                       goto error;
+               }
+#endif // _WIN32
+       } else {
+               if (SSL_CTX_load_verify_locations(ssl_ctx, crt, NULL) != 1) {
+                       err_openssl("SSL_CTX_load_verify_locations");
+                       goto error;
+               }
+       }
        /* Ask OpenSSL to verify the server certificate.  Note that this
         * does NOT include verifying that the hostname is correct.
         * So, by itself, this means anyone with any legitimate
@@ -336,21 +407,21 @@ main(int argc, char **argv)
         * OpenSSL's built-in routine which would have been called if
         * we hadn't set the callback.  Therefore, we're just
         * "wrapping" OpenSSL's routine, not replacing it. */
-       SSL_CTX_set_cert_verify_callback (ssl_ctx, cert_verify_callback,
+       SSL_CTX_set_cert_verify_callback(ssl_ctx, cert_verify_callback,
                                          (void *) host);
-       #endif // not _WIN32
 
        // Create event base
        base = event_base_new();
        if (!base) {
                perror("event_base_new()");
-               return 1;
+               goto error;
        }
 
        // Create OpenSSL bufferevent and stack evhttp on top of it
        ssl = SSL_new(ssl_ctx);
        if (ssl == NULL) {
-               die_openssl("SSL_new()");
+               err_openssl("SSL_new()");
+               goto error;
        }
 
        #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
@@ -361,6 +432,7 @@ main(int argc, char **argv)
        if (strcasecmp(scheme, "http") == 0) {
                bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
        } else {
+               type = HTTPS;
                bev = bufferevent_openssl_socket_new(base, -1, ssl,
                        BUFFEREVENT_SSL_CONNECTING,
                        BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
@@ -368,7 +440,7 @@ main(int argc, char **argv)
 
        if (bev == NULL) {
                fprintf(stderr, "bufferevent_openssl_socket_new() failed\n");
-               return 1;
+               goto error;
        }
 
        bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
@@ -379,18 +451,21 @@ main(int argc, char **argv)
                host, port);
        if (evcon == NULL) {
                fprintf(stderr, "evhttp_connection_base_bufferevent_new() failed\n");
-               return 1;
+               goto error;
        }
 
        if (retries > 0) {
                evhttp_connection_set_retries(evcon, retries);
        }
+       if (timeout >= 0) {
+               evhttp_connection_set_timeout(evcon, timeout);
+       }
 
        // Fire off the request
        req = evhttp_request_new(http_request_done, bev);
        if (req == NULL) {
                fprintf(stderr, "evhttp_request_new() failed\n");
-               return 1;
+               goto error;
        }
 
        output_headers = evhttp_request_get_output_headers(req);
@@ -408,6 +483,7 @@ main(int argc, char **argv)
 
                if (!f) {
                        syntax();
+                       goto error;
                }
 
                output_buffer = evhttp_request_get_output_buffer(req);
@@ -423,17 +499,46 @@ main(int argc, char **argv)
        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;
+               goto error;
        }
 
        event_base_dispatch(base);
+       goto cleanup;
+
+error:
+       ret = 1;
+cleanup:
+       if (evcon)
+               evhttp_connection_free(evcon);
+       if (http_uri)
+               evhttp_uri_free(http_uri);
+       if (base)
+               event_base_free(base);
+
+       if (ssl_ctx)
+               SSL_CTX_free(ssl_ctx);
+       if (type == HTTP && ssl)
+               SSL_free(ssl);
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+       (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
+       EVP_cleanup();
+       ERR_free_strings();
+
+#if OPENSSL_VERSION_NUMBER < 0x10000000L
+       ERR_remove_state(0);
+#else
+       ERR_remove_thread_state(NULL);
+#endif
+
+       CRYPTO_cleanup_all_ex_data();
 
-       evhttp_connection_free(evcon);
-       event_base_free(base);
+       sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
+#endif /* (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+       (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) */
 
 #ifdef _WIN32
        WSACleanup();
 #endif
 
-       return 0;
+       return ret;
 }
index 75f87c70d961c112dea44caeefa2e687b60b60f9..b6894d46e5fe12bf4654018e50c6be2ce34baa7e 100644 (file)
@@ -9,22 +9,26 @@ SAMPLES = \
        sample/event-read-fifo                  \
        sample/hello-world                              \
        sample/http-server                              \
+       sample/http-connect                             \
        sample/signal-test                              \
        sample/time-test
 
 if OPENSSL
 SAMPLES += sample/le-proxy
 sample_le_proxy_SOURCES = sample/le-proxy.c
-sample_le_proxy_LDADD = libevent.la libevent_openssl.la ${OPENSSL_LIBS} ${OPENSSL_LIBADD}
-sample_le_proxy_INCLUDES = $(OPENSSL_INCS)
+sample_le_proxy_LDADD = libevent.la libevent_openssl.la $(OPENSSL_LIBS) $(OPENSSL_LIBADD)
+sample_le_proxy_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_INCS)
 
 SAMPLES += sample/https-client
 sample_https_client_SOURCES = \
        sample/https-client.c \
        sample/hostcheck.c \
        sample/openssl_hostname_validation.c
-sample_https_client_LDADD = libevent.la libevent_openssl.la ${OPENSSL_LIBS} ${OPENSSL_LIBADD}
-sample_https_client_INCLUDES = $(OPENSSL_INCS)
+sample_https_client_LDADD = libevent.la libevent_openssl.la $(OPENSSL_LIBS) $(OPENSSL_LIBADD)
+if BUILD_WIN32
+sample_https_client_LDADD += -lcrypt32
+endif
+sample_https_client_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_INCS)
 noinst_HEADERS += \
        sample/hostcheck.h \
        sample/openssl_hostname_validation.h
@@ -48,6 +52,5 @@ sample_hello_world_SOURCES = sample/hello-world.c
 sample_hello_world_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la
 sample_http_server_SOURCES = sample/http-server.c
 sample_http_server_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la
-
-
-
+sample_http_connect_SOURCES = sample/http-connect.c
+sample_http_connect_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la
index 30e0a5f6b9c6ebde9111bc5c000471ba4c3f08e5..13e0e2aea9181d96a793eba4e64c7d28a6714e9d 100644 (file)
 #include <event2/listener.h>
 #include <event2/util.h>
 
+#include "util-internal.h"
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 #include <openssl/rand.h>
+#include "openssl-compat.h"
 
 static struct event_base *base;
 static struct sockaddr_storage listen_on_addr;
@@ -193,6 +195,7 @@ accept_cb(struct evconnlistener *listener, evutil_socket_t fd,
                        perror("Bufferevent_openssl_new");
                        bufferevent_free(b_out);
                        bufferevent_free(b_in);
+                       return;
                }
                b_out = b_ssl;
        }
@@ -213,6 +216,13 @@ main(int argc, char **argv)
        int use_ssl = 0;
        struct evconnlistener *listener;
 
+#ifdef _WIN32
+       WORD wVersionRequested;
+       WSADATA wsaData;
+       wVersionRequested = MAKEWORD(2, 2);
+       (void) WSAStartup(wVersionRequested, &wsaData);
+#endif
+
        if (argc < 3)
                syntax();
 
@@ -258,16 +268,19 @@ main(int argc, char **argv)
 
        if (use_ssl) {
                int r;
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+       (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
                SSL_library_init();
                ERR_load_crypto_strings();
                SSL_load_error_strings();
                OpenSSL_add_all_algorithms();
+#endif
                r = RAND_poll();
                if (r == 0) {
                        fprintf(stderr, "RAND_poll() failed.\n");
                        return 1;
                }
-               ssl_ctx = SSL_CTX_new(SSLv23_method());
+               ssl_ctx = SSL_CTX_new(TLS_method());
        }
 
        listener = evconnlistener_new_bind(base, accept_cb, NULL,
@@ -284,5 +297,9 @@ main(int argc, char **argv)
        evconnlistener_free(listener);
        event_base_free(base);
 
+#ifdef _WIN32
+       WSACleanup();
+#endif
+
        return 0;
 }
index b5adc67b8aafe1f3fb8b25bc6a5ebf9938babf20..4036ccbaabc9356cae62f408a1175accfd8f6e94 100644 (file)
@@ -41,12 +41,18 @@ SOFTWARE.
 
 #include <openssl/x509v3.h>
 #include <openssl/ssl.h>
+#include <string.h>
 
 #include "openssl_hostname_validation.h"
 #include "hostcheck.h"
 
 #define HOSTNAME_MAX_SIZE 255
 
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+       (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#define ASN1_STRING_get0_data ASN1_STRING_data
+#endif
+
 /**
 * Tries to find a match for hostname in the certificate's Common Name field.
 *
@@ -59,7 +65,7 @@ static HostnameValidationResult matches_common_name(const char *hostname, const
         int common_name_loc = -1;
         X509_NAME_ENTRY *common_name_entry = NULL;
         ASN1_STRING *common_name_asn1 = NULL;
-        char *common_name_str = NULL;
+        const char *common_name_str = NULL;
 
         // Find the position of the CN field in the Subject field of the certificate
         common_name_loc = X509_NAME_get_index_by_NID(X509_get_subject_name((X509 *) server_cert), NID_commonName, -1);
@@ -78,7 +84,7 @@ static HostnameValidationResult matches_common_name(const char *hostname, const
         if (common_name_asn1 == NULL) {
                 return Error;
         }
-        common_name_str = (char *) ASN1_STRING_data(common_name_asn1);
+        common_name_str = (char *) ASN1_STRING_get0_data(common_name_asn1);
 
         // Make sure there isn't an embedded NUL character in the CN
         if ((size_t)ASN1_STRING_length(common_name_asn1) != strlen(common_name_str)) {
@@ -122,7 +128,7 @@ static HostnameValidationResult matches_subject_alternative_name(const char *hos
 
                 if (current_name->type == GEN_DNS) {
                         // Current name is a DNS name, let's check it
-                        char *dns_name = (char *) ASN1_STRING_data(current_name->d.dNSName);
+                        const char *dns_name = (char *) ASN1_STRING_get0_data(current_name->d.dNSName);
 
                         // Make sure there isn't an embedded NUL character in the DNS name
                         if ((size_t)ASN1_STRING_length(current_name->d.dNSName) != strlen(dns_name)) {
index a61642f325e3fb5db281c4597b2527e4efe9bff7..4aef42051574a775b3c3831767a1fddb63cbac20 100644 (file)
 
 #include <event2/event.h>
 
-#ifdef EVENT____func__
-#define __func__ EVENT____func__
-#endif
-
 int called = 0;
 
 static void
@@ -37,7 +33,7 @@ signal_cb(evutil_socket_t fd, short event, void *arg)
 {
        struct event *signal = arg;
 
-       printf("%s: got signal %d\n", __func__, event_get_signal(signal));
+       printf("signal_cb: got signal %d\n", event_get_signal(signal));
 
        if (called >= 2)
                event_del(signal);
@@ -48,8 +44,9 @@ signal_cb(evutil_socket_t fd, short event, void *arg)
 int
 main(int argc, char **argv)
 {
-       struct event *signal_int;
+       struct event *signal_int = NULL;
        struct event_base* base;
+       int ret = 0;
 #ifdef _WIN32
        WORD wVersionRequested;
        WSADATA wsaData;
@@ -59,17 +56,28 @@ main(int argc, char **argv)
        (void) WSAStartup(wVersionRequested, &wsaData);
 #endif
 
-       /* Initalize the event library */
+       /* Initialize the event library */
        base = event_base_new();
+       if (!base) {
+               ret = 1;
+               goto out;
+       }
 
-       /* Initalize one event */
+       /* Initialize one event */
        signal_int = evsignal_new(base, SIGINT, signal_cb, event_self_cbarg());
-
+       if (!signal_int) {
+               ret = 2;
+               goto out;
+       }
        event_add(signal_int, NULL);
 
        event_base_dispatch(base);
-       event_base_free(base);
 
-       return (0);
+out:
+       if (signal_int)
+               event_free(signal_int);
+       if (base)
+               event_base_free(base);
+       return ret;
 }
 
index c94c18a5004efd21e2405ac6be0c98573bf79c1f..671a1d2108e2e911c7f513b5340828658c65d693 100644 (file)
@@ -88,10 +88,10 @@ main(int argc, char **argv)
                flags = 0;
        }
 
-       /* Initalize the event library */
+       /* Initialize the event library */
        base = event_base_new();
 
-       /* Initalize one event */
+       /* Initialize one event */
        event_assign(&timeout, base, -1, flags, timeout_cb, (void*) &timeout);
 
        evutil_timerclear(&tv);
@@ -100,6 +100,9 @@ main(int argc, char **argv)
 
        evutil_gettimeofday(&lasttime, NULL);
 
+       setbuf(stdout, NULL);
+       setbuf(stderr, NULL);
+
        event_base_dispatch(base);
 
        return (0);
index 8ae53cc11ec56afa7a81dee8310c17e47350fed1..b1db0e44b605147119d45b34530ffc77461ab21e 100644 (file)
@@ -98,7 +98,7 @@ const struct eventop selectops = {
        select_del,
        select_dispatch,
        select_dealloc,
-       0, /* doesn't need reinit. */
+       1, /* need_reinit. */
        EV_FEATURE_FDS,
        0,
 };
index 3f46295024e572cfdf7e000a7fb0881f1ba00160..89f5fc1717638f58d0608fd82588f6a17dad0559 100644 (file)
 #ifndef _WIN32
 /* Windows wants us to call our signal handlers as __cdecl.  Nobody else
  * expects you to do anything crazy like this. */
+#ifndef __cdecl
 #define __cdecl
 #endif
+#endif
 
 static int evsig_add(struct event_base *, evutil_socket_t, short, short, void *);
 static int evsig_del(struct event_base *, evutil_socket_t, short, short, void *);
index cfc27ec662764d8b3de68b3815c3bf045cdcb44b..4151d601d0b1ffb8e5cd4660ca4788aafc1ce8d4 100644 (file)
@@ -6,10 +6,12 @@ extern "C" {
 #endif
 
 #include "event2/event-config.h"
+#include "event2/visibility.h"
 #include "evconfig-private.h"
 
 #ifndef EVENT__HAVE_STRLCPY
 #include <string.h>
+EVENT2_EXPORT_SYMBOL
 size_t event_strlcpy_(char *dst, const char *src, size_t siz);
 #define strlcpy event_strlcpy_
 #endif
diff --git a/sntp/libevent/test-driver b/sntp/libevent/test-driver
new file mode 100755 (executable)
index 0000000..8e575b0
--- /dev/null
@@ -0,0 +1,148 @@
+#! /bin/sh
+# test-driver - basic testsuite driver script.
+
+scriptversion=2013-07-13.22; # UTC
+
+# Copyright (C) 2011-2014 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+# Make unconditional expansion of undefined variables an error.  This
+# helps a lot in preventing typo-related bugs.
+set -u
+
+usage_error ()
+{
+  echo "$0: $*" >&2
+  print_usage >&2
+  exit 2
+}
+
+print_usage ()
+{
+  cat <<END
+Usage:
+  test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
+              [--expect-failure={yes|no}] [--color-tests={yes|no}]
+              [--enable-hard-errors={yes|no}] [--]
+              TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
+The '--test-name', '--log-file' and '--trs-file' options are mandatory.
+END
+}
+
+test_name= # Used for reporting.
+log_file=  # Where to save the output of the test script.
+trs_file=  # Where to save the metadata of the test run.
+expect_failure=no
+color_tests=no
+enable_hard_errors=yes
+while test $# -gt 0; do
+  case $1 in
+  --help) print_usage; exit $?;;
+  --version) echo "test-driver $scriptversion"; exit $?;;
+  --test-name) test_name=$2; shift;;
+  --log-file) log_file=$2; shift;;
+  --trs-file) trs_file=$2; shift;;
+  --color-tests) color_tests=$2; shift;;
+  --expect-failure) expect_failure=$2; shift;;
+  --enable-hard-errors) enable_hard_errors=$2; shift;;
+  --) shift; break;;
+  -*) usage_error "invalid option: '$1'";;
+   *) break;;
+  esac
+  shift
+done
+
+missing_opts=
+test x"$test_name" = x && missing_opts="$missing_opts --test-name"
+test x"$log_file"  = x && missing_opts="$missing_opts --log-file"
+test x"$trs_file"  = x && missing_opts="$missing_opts --trs-file"
+if test x"$missing_opts" != x; then
+  usage_error "the following mandatory options are missing:$missing_opts"
+fi
+
+if test $# -eq 0; then
+  usage_error "missing argument"
+fi
+
+if test $color_tests = yes; then
+  # Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
+  red='\e[0;31m' # Red.
+  grn='\e[0;32m' # Green.
+  lgn='\e[1;32m' # Light green.
+  blu='\e[1;34m' # Blue.
+  mgn='\e[0;35m' # Magenta.
+  std='\e[m'     # No color.
+else
+  red= grn= lgn= blu= mgn= std=
+fi
+
+do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
+trap "st=129; $do_exit" 1
+trap "st=130; $do_exit" 2
+trap "st=141; $do_exit" 13
+trap "st=143; $do_exit" 15
+
+# Test script is run here.
+"$@" >$log_file 2>&1
+estatus=$?
+
+if test $enable_hard_errors = no && test $estatus -eq 99; then
+  tweaked_estatus=1
+else
+  tweaked_estatus=$estatus
+fi
+
+case $tweaked_estatus:$expect_failure in
+  0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
+  0:*)   col=$grn res=PASS  recheck=no  gcopy=no;;
+  77:*)  col=$blu res=SKIP  recheck=no  gcopy=yes;;
+  99:*)  col=$mgn res=ERROR recheck=yes gcopy=yes;;
+  *:yes) col=$lgn res=XFAIL recheck=no  gcopy=yes;;
+  *:*)   col=$red res=FAIL  recheck=yes gcopy=yes;;
+esac
+
+# Report the test outcome and exit status in the logs, so that one can
+# know whether the test passed or failed simply by looking at the '.log'
+# file, without the need of also peaking into the corresponding '.trs'
+# file (automake bug#11814).
+echo "$res $test_name (exit status: $estatus)" >>$log_file
+
+# Report outcome to console.
+echo "${col}${res}${std}: $test_name"
+
+# Register the test result, and other relevant metadata.
+echo ":test-result: $res" > $trs_file
+echo ":global-test-result: $res" >> $trs_file
+echo ":recheck: $recheck" >> $trs_file
+echo ":copy-in-global-log: $gcopy" >> $trs_file
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
index 922a743add4bf03b67ad02303dcba76b5e5c80cc..f2af4d3f30d1ff3703fd574b8014f7cef1f344a6 100644 (file)
@@ -34,6 +34,7 @@
  */
 
 #include "event2/event-config.h"
+#include "../util-internal.h"
 
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <event.h>
 #include <evutil.h>
 
-static int count, writes, fired, failures;
+static ev_ssize_t count, fired;
+static int writes, failures;
 static evutil_socket_t *pipes;
 static int num_pipes, num_active, num_writes;
 static struct event *events;
+static struct event_base *base;
 
 
 static void
 read_cb(evutil_socket_t fd, short which, void *arg)
 {
        ev_intptr_t idx = (ev_intptr_t) arg, widx = idx + 1;
-       u_char ch;
+       unsigned char ch;
        ev_ssize_t n;
 
        n = recv(fd, (char*)&ch, sizeof(ch), 0);
@@ -103,11 +106,11 @@ run_once(void)
        for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
                if (event_initialized(&events[i]))
                        event_del(&events[i]);
-               event_set(&events[i], cp[0], EV_READ | EV_PERSIST, read_cb, (void *)(ev_intptr_t) i);
+               event_assign(&events[i], base, cp[0], EV_READ | EV_PERSIST, read_cb, (void *)(ev_intptr_t) i);
                event_add(&events[i], NULL);
        }
 
-       event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK);
+       event_base_loop(base, EVLOOP_ONCE | EVLOOP_NONBLOCK);
 
        fired = 0;
        space = num_pipes / num_active;
@@ -117,15 +120,18 @@ run_once(void)
 
        count = 0;
        writes = num_writes;
-       { int xcount = 0;
-       evutil_gettimeofday(&ts, NULL);
-       do {
-               event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK);
-               xcount++;
-       } while (count != fired);
-       evutil_gettimeofday(&te, NULL);
-
-       if (xcount != count) fprintf(stderr, "Xcount: %d, Rcount: %d\n", xcount, count);
+       {
+               int xcount = 0;
+               evutil_gettimeofday(&ts, NULL);
+               do {
+                       event_base_loop(base, EVLOOP_ONCE | EVLOOP_NONBLOCK);
+                       xcount++;
+               } while (count != fired);
+               evutil_gettimeofday(&te, NULL);
+
+               if (xcount != count)
+                       fprintf(stderr, "Xcount: %d, Rcount: " EV_SSIZE_FMT "\n",
+                               xcount, count);
        }
 
        evutil_timersub(&te, &ts, &te);
@@ -136,12 +142,15 @@ run_once(void)
 int
 main(int argc, char **argv)
 {
-#ifdef HAVE_SETRLIMIT 
+#ifdef EVENT__HAVE_SETRLIMIT
        struct rlimit rl;
 #endif
        int i, c;
        struct timeval *tv;
        evutil_socket_t *cp;
+       const char **methods;
+       const char *method = NULL;
+       struct event_config *cfg = NULL;
 
 #ifdef _WIN32
        WSADATA WSAData;
@@ -150,7 +159,7 @@ main(int argc, char **argv)
        num_pipes = 100;
        num_active = 1;
        num_writes = num_pipes;
-       while ((c = getopt(argc, argv, "n:a:w:")) != -1) {
+       while ((c = getopt(argc, argv, "n:a:w:m:l")) != -1) {
                switch (c) {
                case 'n':
                        num_pipes = atoi(optarg);
@@ -161,13 +170,23 @@ main(int argc, char **argv)
                case 'w':
                        num_writes = atoi(optarg);
                        break;
+               case 'm':
+                       method = optarg;
+                       break;
+               case 'l':
+                       methods = event_get_supported_methods();
+                       fprintf(stdout, "Using Libevent %s. Available methods are:\n",
+                               event_get_version());
+                       for (i = 0; methods[i] != NULL; ++i)
+                               printf("    %s\n", methods[i]);
+                       exit(0);
                default:
                        fprintf(stderr, "Illegal argument \"%c\"\n", c);
                        exit(1);
                }
        }
 
-#ifdef HAVE_SETRLIMIT
+#ifdef EVENT__HAVE_SETRLIMIT
        rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50;
        if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
                perror("setrlimit");
@@ -182,7 +201,16 @@ main(int argc, char **argv)
                exit(1);
        }
 
-       event_init();
+       if (method != NULL) {
+               cfg = event_config_new();
+               methods = event_get_supported_methods();
+               for (i = 0; methods[i] != NULL; ++i)
+                       if (strcmp(methods[i], method))
+                               event_config_avoid_method(cfg, methods[i]);
+               base = event_base_new_with_config(cfg);
+               event_config_free(cfg);
+       } else
+               base = event_base_new();
 
        for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
 #ifdef USE_PIPES
index 2d85cc1f1038995ed250628be6f71a7023201259..29a3203ecdd693c3d9756d16e1cb03ef19b3bfea 100644 (file)
@@ -35,7 +35,8 @@
 #ifdef _WIN32
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
-#else
+#include <getopt.h>
+#else /* _WIN32 */
 #include <sys/socket.h>
 #include <sys/resource.h>
 #endif
@@ -48,7 +49,6 @@
 #include <unistd.h>
 #endif
 #include <errno.h>
-#include <getopt.h>
 #include <event.h>
 #include <evutil.h>
 
@@ -139,7 +139,7 @@ run_once(int num_pipes)
 int
 main(int argc, char **argv)
 {
-#ifdef HAVE_SETRLIMIT
+#ifdef EVENT__HAVE_SETRLIMIT
        struct rlimit rl;
 #endif
        int i, c;
@@ -162,7 +162,7 @@ main(int argc, char **argv)
                }
        }
 
-#ifdef HAVE_SETRLIMIT 
+#ifdef EVENT__HAVE_SETRLIMIT
        rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50;
        if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
                perror("setrlimit");
index 6d0d971799b5b106672d481aaca540d8824d4370..80377ee60583bbd5de31e38b39cf85e281d94317 100644 (file)
@@ -90,7 +90,7 @@ main(int argc, char **argv)
        int i;
        int c;
        int use_iocp = 0;
-       unsigned short port = 8080;
+       ev_uint16_t port = 8080;
        char *endptr = NULL;
 
 #ifdef _WIN32
@@ -101,6 +101,9 @@ main(int argc, char **argv)
                return (1);
 #endif
 
+       setbuf(stdout, NULL);
+       setbuf(stderr, NULL);
+
        for (i = 1; i < argc; ++i) {
                if (*argv[i] != '-')
                        continue;
@@ -138,7 +141,9 @@ main(int argc, char **argv)
 #ifdef _WIN32
                case 'i':
                        use_iocp = 1;
+#ifdef EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
                        evthread_use_windows_threads();
+#endif
                        event_config_set_flag(cfg,EVENT_BASE_FLAG_STARTUP_IOCP);
                        break;
 #endif
index 1573e365bfd418ef0d93c0fb483c436008108e32..7c7ee470a307e154426ba3419d6c892ac3ca85d8 100644 (file)
@@ -113,13 +113,13 @@ errorcb(struct bufferevent *b, short what, void *arg)
 static void
 frob_socket(evutil_socket_t sock)
 {
-#ifdef HAVE_SO_LINGER
+#ifdef EVENT__HAVE_STRUCT_LINGER
        struct linger l;
 #endif
        int one = 1;
        if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&one, sizeof(one))<0)
                perror("setsockopt(SO_REUSEADDR)");
-#ifdef HAVE_SO_LINGER
+#ifdef EVENT__HAVE_STRUCT_LINGER
        l.l_onoff = 1;
        l.l_linger = 0;
        if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&l, sizeof(l))<0)
@@ -151,7 +151,7 @@ launch_request(void)
        }
        frob_socket(sock);
        if (connect(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
-               int e = errno;
+               int e = evutil_socket_geterror(sock);
                if (! EVUTIL_ERR_CONNECT_RETRIABLE(e)) {
                        evutil_closesocket(sock);
                        return -1;
@@ -159,10 +159,6 @@ launch_request(void)
        }
 
        ri = malloc(sizeof(*ri));
-       if (ri == NULL) {
-               printf("Unable to allocate memory in launch_request()\n");
-               return -1;
-       }
        ri->n_read = 0;
        evutil_gettimeofday(&ri->started, NULL);
 
@@ -185,6 +181,12 @@ main(int argc, char **argv)
        struct timeval start, end, total;
        long long usec;
        double throughput;
+
+#ifdef _WIN32
+       WSADATA WSAData;
+       WSAStartup(0x101, &WSAData);
+#endif
+
        resource = "/ref";
 
        setvbuf(stdout, NULL, _IONBF, 0);
@@ -230,5 +232,9 @@ main(int argc, char **argv)
            (double)(usec/1000) / total_n_handled,
            (I64_TYP)total_n_bytes, n_errors);
 
+#ifdef _WIN32
+       WSACleanup();
+#endif
+
        return 0;
 }
index 16fe9bc92fdf21acbf97170f058479b1775e4603..3e1df30c4f406775f7da6f2ec989549a0fc9c1f8 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python
 #
 # Post-process the output of test-dumpevents and check it for correctness.
 #
@@ -15,12 +15,12 @@ try:
     got_inserted_pos = text.index("Inserted events:\n")
     got_active_pos = text.index("Active events:\n")
 except ValueError:
-    print >>sys.stderr, "Missing expected dividing line in dumpevents output"
+    sys.stderr.write("Missing expected dividing line in dumpevents output")
     sys.exit(1)
 
 if not (expect_inserted_pos < expect_active_pos <
         got_inserted_pos < got_active_pos):
-    print >>sys.stderr, "Sections out of order in dumpevents output"
+    sys.stderr.write("Sections out of order in dumpevents output")
     sys.exit(1)
 
 now,T= text[1].split()
@@ -45,10 +45,10 @@ cleaned_inserted = set( pat.sub(replace_time, s) for s in got_inserted
                         if "Internal" not in s)
 
 if cleaned_inserted != want_inserted:
-    print >>sys.stderr, "Inserted event lists were not as expected!"
+    sys.stderr.write("Inserted event lists were not as expected!")
     sys.exit(1)
 
 if set(got_active) != set(want_active):
-    print >>sys.stderr, "Active event lists were not as expected!"
+    sys.stderr.write("Active event lists were not as expected!")
     sys.exit(1)
 
index 4cd49ef6306f8dc0877e050021cfbf8065af1f51..043752471aed7793319b22829a2af9c12bf8108c 100644 (file)
@@ -12,6 +12,7 @@ EXTRA_DIST+=                                  \
        test/regress.gen.h                              \
        test/regress.rpc                                \
        test/rpcgen_wrapper.sh                  \
+       test/print-winsock-errors.c                     \
        test/test.sh
 
 TESTPROGRAMS = \
@@ -42,14 +43,41 @@ noinst_HEADERS+=                            \
        test/tinytest_local.h                   \
        test/tinytest_macros.h
 
-# We need to copy this file, since automake doesn't want us to use top_srcdir
-# in TESTS.
-TESTS = test/test-script.sh
+TESTS = \
+       test_runner_epoll \
+       test_runner_select \
+       test_runner_kqueue \
+       test_runner_evport \
+       test_runner_devpoll \
+       test_runner_poll \
+       test_runner_win32 \
+       test_runner_timerfd \
+       test_runner_changelist \
+       test_runner_timerfd_changelist
+LOG_COMPILER = true
+TESTS_COMPILER = true
+
+test_runner_epoll: $(top_srcdir)/test/test.sh
+       $(top_srcdir)/test/test.sh -b EPOLL
+test_runner_select: $(top_srcdir)/test/test.sh
+       $(top_srcdir)/test/test.sh -b SELECT
+test_runner_kqueue: $(top_srcdir)/test/test.sh
+       $(top_srcdir)/test/test.sh -b KQUEUE
+test_runner_evport: $(top_srcdir)/test/test.sh
+       $(top_srcdir)/test/test.sh -b EVPORT
+test_runner_devpoll: $(top_srcdir)/test/test.sh
+       $(top_srcdir)/test/test.sh -b DEVPOLL
+test_runner_poll: $(top_srcdir)/test/test.sh
+       $(top_srcdir)/test/test.sh -b POLL
+test_runner_win32: $(top_srcdir)/test/test.sh
+       $(top_srcdir)/test/test.sh -b WIN32
+test_runner_timerfd: $(top_srcdir)/test/test.sh
+       $(top_srcdir)/test/test.sh -b "" -t
+test_runner_changelist: $(top_srcdir)/test/test.sh
+       $(top_srcdir)/test/test.sh -b "" -c
+test_runner_timerfd_changelist: $(top_srcdir)/test/test.sh
+       $(top_srcdir)/test/test.sh -b "" -T
 
-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
@@ -101,8 +129,10 @@ regress_thread_SOURCES = test/regress_thread.c
 PTHREAD_LIBS += libevent_pthreads.la
 endif
 if BUILD_WIN32
+if THREADS
 regress_thread_SOURCES = test/regress_thread.c
 endif
+endif
 if ZLIB_REGRESS
 regress_zlib_SOURCES = test/regress_zlib.c
 endif
@@ -110,7 +140,7 @@ if BUILD_WIN32
 test_regress_SOURCES += test/regress_iocp.c
 endif
 
-test_regress_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la $(PTHREAD_LIBS) $(ZLIB_LIBS)
+test_regress_LDADD = $(LIBEVENT_GC_SECTIONS) libevent_core.la libevent_extra.la $(PTHREAD_LIBS) $(ZLIB_LIBS)
 test_regress_CPPFLAGS = $(AM_CPPFLAGS) $(PTHREAD_CFLAGS) $(ZLIB_CFLAGS) -Itest
 test_regress_LDFLAGS = $(PTHREAD_CFLAGS)
 
index ab6e610e84dba8e66a568e7b3ecacc91b334bc5d..64d6b0e70e4de0f59b611092aa31815aa9d1ff7d 100644 (file)
@@ -15,7 +15,9 @@ int main (int argc, char **argv)
   int i, j;
   const char *s1, *s2;
 
+#ifdef EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
   evthread_use_windows_threads ();
+#endif
 
   s1 = evutil_socket_error_to_string (WSAEINTR);
 
index 2d887f02f8eed5f8bd3fd9f3b9e6c49518900727..08c30fab9b9b48ea6690b6d3d980e17750dba2dd 100644 (file)
@@ -42,6 +42,7 @@
 #ifndef _WIN32
 #include <sys/socket.h>
 #include <sys/wait.h>
+#include <limits.h>
 #include <signal.h>
 #include <unistd.h>
 #include <netdb.h>
@@ -68,6 +69,7 @@
 #include "time-internal.h"
 
 #include "regress.h"
+#include "regress_thread.h"
 
 #ifndef _WIN32
 #include "regress.gen.h"
@@ -89,10 +91,6 @@ static struct timeval tcalled;
 
 #define TEST1  "this is a test"
 
-#ifndef SHUT_WR
-#define SHUT_WR 1
-#endif
-
 #ifdef _WIN32
 #define write(fd,buf,len) send((fd),(buf),(int)(len),0)
 #define read(fd,buf,len) recv((fd),(buf),(int)(len),0)
@@ -196,7 +194,7 @@ multiple_write_cb(evutil_socket_t fd, short event, void *arg)
        woff += len;
 
        if (woff >= (int)sizeof(wbuf)) {
-               shutdown(fd, SHUT_WR);
+               shutdown(fd, EVUTIL_SHUT_WR);
                if (usepersist)
                        event_del(ev);
                return;
@@ -276,7 +274,7 @@ combined_write_cb(evutil_socket_t fd, short event, void *arg)
        if (len == -1)
                fprintf(stderr, "%s: write\n", __func__);
        if (len <= 0) {
-               shutdown(fd, SHUT_WR);
+               shutdown(fd, EVUTIL_SHUT_WR);
                return;
        }
 
@@ -306,7 +304,7 @@ test_simpleread(void)
                tt_fail_perror("write");
        }
 
-       shutdown(pair[0], SHUT_WR);
+       shutdown(pair[0], EVUTIL_SHUT_WR);
 
        event_set(&ev, pair[1], EV_READ, simple_read_cb, &ev);
        if (event_add(&ev, NULL) == -1)
@@ -351,7 +349,7 @@ test_simpleread_multiple(void)
                tt_fail_perror("write");
        }
 
-       shutdown(pair[0], SHUT_WR);
+       shutdown(pair[0], EVUTIL_SHUT_WR);
 
        event_set(&one, pair[1], EV_READ, simpleread_multiple_cb, NULL);
        if (event_add(&one, NULL) == -1)
@@ -389,7 +387,7 @@ record_event_cb(evutil_socket_t s, short what, void *ptr)
 }
 
 static void
-test_simpleclose(void *ptr)
+test_simpleclose_rw(void *ptr)
 {
        /* Test that a close of FD is detected as a read and as a write. */
        struct event_base *base = event_base_new();
@@ -471,6 +469,56 @@ end:
                event_base_free(base);
 }
 
+static void
+test_simpleclose(void *ptr)
+{
+       struct basic_test_data *data = ptr;
+       struct event_base *base      = data->base;
+       evutil_socket_t *pair        = data->pair;
+       const char *flags            = (const char *)data->setup_data;
+       int et                       = !!strstr(flags, "ET");
+       int persist                  = !!strstr(flags, "persist");
+       short events                 = EV_CLOSED | (et ? EV_ET : 0) | (persist ? EV_PERSIST : 0);
+       struct event *ev = NULL;
+       short got_event;
+
+       if (!(event_base_get_features(data->base) & EV_FEATURE_EARLY_CLOSE))
+               tt_skip();
+
+       /* XXX: should this code moved to regress_et.c ? */
+       if (et && !(event_base_get_features(data->base) & EV_FEATURE_ET))
+               tt_skip();
+
+       ev = event_new(base, pair[0], events, record_event_cb, &got_event);
+       tt_assert(ev);
+       tt_assert(!event_add(ev, NULL));
+
+       got_event = 0;
+       if (strstr(flags, "close")) {
+               tt_assert(!evutil_closesocket(pair[1]));
+               /* avoid closing in setup routines */
+               pair[1] = -1;
+       } else if (strstr(flags, "shutdown")) {
+               tt_assert(!shutdown(pair[1], EVUTIL_SHUT_WR));
+       } else {
+               tt_abort_msg("unknown flags");
+       }
+
+       /* w/o edge-triggerd but w/ persist it will not stop */
+       if (!et && persist) {
+               struct timeval tv;
+               tv.tv_sec = 0;
+               tv.tv_usec = 10000;
+               tt_assert(!event_base_loopexit(base, &tv));
+       }
+
+       tt_int_op(event_base_loop(base, EVLOOP_NONBLOCK), ==, !persist);
+       tt_int_op(got_event, ==, (events & ~EV_PERSIST));
+
+end:
+       if (ev)
+               event_free(ev);
+}
 
 static void
 test_multiple(void)
@@ -817,33 +865,82 @@ end:
 }
 
 #ifndef _WIN32
-static void signal_cb(evutil_socket_t fd, short event, void *arg);
 
 #define current_base event_global_current_base_
 extern struct event_base *current_base;
 
 static void
-child_signal_cb(evutil_socket_t fd, short event, void *arg)
+fork_signal_cb(evutil_socket_t fd, short events, void *arg)
 {
-       struct timeval tv;
-       int *pint = arg;
+       event_del(arg);
+}
 
-       *pint = 1;
+int child_pair[2] = { -1, -1 };
+static void
+simple_child_read_cb(evutil_socket_t fd, short event, void *arg)
+{
+       char buf[256];
+       int len;
 
-       tv.tv_usec = 500000;
-       tv.tv_sec = 0;
-       event_loopexit(&tv);
+       len = read(fd, buf, sizeof(buf));
+       if (write(child_pair[0], "", 1) < 0)
+               tt_fail_perror("write");
+
+       if (len) {
+               if (!called) {
+                       if (event_add(arg, NULL) == -1)
+                               exit(1);
+               }
+       } else if (called == 1)
+               test_ok = 1;
+
+       called++;
 }
 
+#define TEST_FORK_EXIT_SUCCESS 76
+static void fork_wait_check(int pid)
+{
+       int status;
+
+       TT_BLATHER(("Before waitpid"));
+
+#ifdef WNOWAIT
+       if ((waitpid(pid, &status, WNOWAIT) == -1 && errno == EINVAL) &&
+#else
+       if (
+#endif
+           waitpid(pid, &status, 0) == -1) {
+               perror("waitpid");
+               exit(1);
+       }
+       TT_BLATHER(("After waitpid"));
+
+       if (WEXITSTATUS(status) != TEST_FORK_EXIT_SUCCESS) {
+               fprintf(stdout, "FAILED (exit): %d\n", WEXITSTATUS(status));
+               exit(1);
+       }
+}
 static void
 test_fork(void)
 {
-       int status, got_sigchld = 0;
-       struct event ev, sig_ev;
+       char c;
+       struct event ev, sig_ev, usr_ev, existing_ev;
        pid_t pid;
 
        setup_test("After fork: ");
 
+       {
+               if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, child_pair) == -1) {
+                       fprintf(stderr, "%s: socketpair\n", __func__);
+                       exit(1);
+               }
+
+               if (evutil_make_socket_nonblocking(child_pair[0]) == -1) {
+                       fprintf(stderr, "fcntl(O_NONBLOCK)");
+                       exit(1);
+               }
+       }
+
        tt_assert(current_base);
        evthread_make_base_notifiable(current_base);
 
@@ -851,13 +948,16 @@ test_fork(void)
                tt_fail_perror("write");
        }
 
-       event_set(&ev, pair[1], EV_READ, simple_read_cb, &ev);
+       event_set(&ev, pair[1], EV_READ, simple_child_read_cb, &ev);
        if (event_add(&ev, NULL) == -1)
                exit(1);
 
-       evsignal_set(&sig_ev, SIGCHLD, child_signal_cb, &got_sigchld);
+       evsignal_set(&sig_ev, SIGCHLD, fork_signal_cb, &sig_ev);
        evsignal_add(&sig_ev, NULL);
 
+       evsignal_set(&existing_ev, SIGUSR2, fork_signal_cb, &existing_ev);
+       evsignal_add(&existing_ev, NULL);
+
        event_base_assert_ok_(current_base);
        TT_BLATHER(("Before fork"));
        if ((pid = regress_fork()) == 0) {
@@ -874,6 +974,11 @@ test_fork(void)
 
                evsignal_del(&sig_ev);
 
+               evsignal_set(&usr_ev, SIGUSR1, fork_signal_cb, &usr_ev);
+               evsignal_add(&usr_ev, NULL);
+               kill(getpid(), SIGUSR1);
+               kill(getpid(), SIGUSR2);
+
                called = 0;
 
                event_dispatch();
@@ -883,51 +988,135 @@ test_fork(void)
                /* we do not send an EOF; simple_read_cb requires an EOF
                 * to set test_ok.  we just verify that the callback was
                 * called. */
-               exit(test_ok != 0 || called != 2 ? -2 : 76);
+               exit(test_ok != 0 || called != 2 ? -2 : TEST_FORK_EXIT_SUCCESS);
        }
 
-       /* wait for the child to read the data */
-       {
-               const struct timeval tv = { 0, 100000 };
-               evutil_usleep_(&tv);
+       /** wait until client read first message */
+       if (read(child_pair[1], &c, 1) < 0) {
+               tt_fail_perror("read");
        }
-
        if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
                tt_fail_perror("write");
        }
 
-       TT_BLATHER(("Before waitpid"));
-       if (waitpid(pid, &status, 0) == -1) {
-               fprintf(stdout, "FAILED (fork)\n");
-               exit(1);
-       }
-       TT_BLATHER(("After waitpid"));
-
-       if (WEXITSTATUS(status) != 76) {
-               fprintf(stdout, "FAILED (exit): %d\n", WEXITSTATUS(status));
-               exit(1);
-       }
+       fork_wait_check(pid);
 
        /* test that the current event loop still works */
        if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
                fprintf(stderr, "%s: write\n", __func__);
        }
 
-       shutdown(pair[0], SHUT_WR);
+       shutdown(pair[0], EVUTIL_SHUT_WR);
 
-       event_dispatch();
+       evsignal_set(&usr_ev, SIGUSR1, fork_signal_cb, &usr_ev);
+       evsignal_add(&usr_ev, NULL);
+       kill(getpid(), SIGUSR1);
+       kill(getpid(), SIGUSR2);
 
-       if (!got_sigchld) {
-               fprintf(stdout, "FAILED (sigchld)\n");
-               exit(1);
-       }
+       event_dispatch();
 
        evsignal_del(&sig_ev);
+       tt_int_op(test_ok, ==, 1);
 
        end:
        cleanup_test();
+       if (child_pair[0] != -1)
+               evutil_closesocket(child_pair[0]);
+       if (child_pair[1] != -1)
+               evutil_closesocket(child_pair[1]);
+}
+
+#ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED
+static void* del_wait_thread(void *arg)
+{
+       struct timeval tv_start, tv_end;
+
+       evutil_gettimeofday(&tv_start, NULL);
+       event_dispatch();
+       evutil_gettimeofday(&tv_end, NULL);
+
+       test_timeval_diff_eq(&tv_start, &tv_end, 300);
+
+       end:
+       return NULL;
+}
+
+static void
+del_wait_cb(evutil_socket_t fd, short event, void *arg)
+{
+       struct timeval delay = { 0, 300*1000 };
+       TT_BLATHER(("Sleeping: %i", test_ok));
+       evutil_usleep_(&delay);
+       ++test_ok;
+}
+
+static void
+test_del_wait(void)
+{
+       struct event ev;
+       THREAD_T thread;
+
+       setup_test("event_del will wait: ");
+
+       event_set(&ev, pair[1], EV_READ|EV_PERSIST, del_wait_cb, &ev);
+       event_add(&ev, NULL);
+
+       THREAD_START(thread, del_wait_thread, NULL);
+
+       if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
+               tt_fail_perror("write");
+       }
+
+       {
+               struct timeval delay = { 0, 30*1000 };
+               evutil_usleep_(&delay);
+       }
+
+       {
+               struct timeval tv_start, tv_end;
+               evutil_gettimeofday(&tv_start, NULL);
+               event_del(&ev);
+               evutil_gettimeofday(&tv_end, NULL);
+               test_timeval_diff_eq(&tv_start, &tv_end, 270);
+       }
+
+       THREAD_JOIN(thread);
+
+       tt_int_op(test_ok, ==, 1);
+
+       end:
+       ;
 }
 
+static void null_cb(evutil_socket_t fd, short what, void *arg) {}
+static void* test_del_notify_thread(void *arg)
+{
+       event_dispatch();
+       return NULL;
+}
+static void
+test_del_notify(void)
+{
+       struct event ev;
+       THREAD_T thread;
+
+       test_ok = 1;
+
+       event_set(&ev, -1, EV_READ, null_cb, &ev);
+       event_add(&ev, NULL);
+
+       THREAD_START(thread, test_del_notify_thread, NULL);
+
+       {
+               struct timeval delay = { 0, 1000 };
+               evutil_usleep_(&delay);
+       }
+
+       event_del(&ev);
+       THREAD_JOIN(thread);
+}
+#endif
+
 static void
 signal_cb_sa(int sig)
 {
@@ -1024,7 +1213,7 @@ test_immediatesignal(void)
        test_ok = 0;
        evsignal_set(&ev, SIGUSR1, signal_cb, &ev);
        evsignal_add(&ev, NULL);
-       raise(SIGUSR1);
+       kill(getpid(), SIGUSR1);
        event_loop(EVLOOP_NONBLOCK);
        evsignal_del(&ev);
        cleanup_test();
@@ -1097,7 +1286,7 @@ test_signal_switchbase(void)
 
        test_ok = 0;
        /* can handle signal before loop is called */
-       raise(SIGUSR1);
+       kill(getpid(), SIGUSR1);
        event_base_loop(base2, EVLOOP_NONBLOCK);
        if (is_kqueue) {
                if (!test_ok)
@@ -1110,7 +1299,7 @@ test_signal_switchbase(void)
 
                /* set base1 to handle signals */
                event_base_loop(base1, EVLOOP_NONBLOCK);
-               raise(SIGUSR1);
+               kill(getpid(), SIGUSR1);
                event_base_loop(base1, EVLOOP_NONBLOCK);
                event_base_loop(base2, EVLOOP_NONBLOCK);
        }
@@ -1139,7 +1328,7 @@ test_signal_assert(void)
         */
        evsignal_del(&ev);
 
-       raise(SIGCONT);
+       kill(getpid(), SIGCONT);
 #if 0
        /* only way to verify we were in evsig_handler() */
        /* XXXX Now there's no longer a good way. */
@@ -1183,7 +1372,7 @@ test_signal_restore(void)
        evsignal_add(&ev, NULL);
        evsignal_del(&ev);
 
-       raise(SIGUSR1);
+       kill(getpid(), SIGUSR1);
        /* 1 == signal_cb, 2 == signal_cb_sa, we want our previous handler */
        if (test_ok != 2)
                test_ok = 0;
@@ -1198,7 +1387,7 @@ signal_cb_swp(int sig, short event, void *arg)
 {
        called++;
        if (called < 5)
-               raise(sig);
+               kill(getpid(), sig);
        else
                event_loopexit(NULL);
 }
@@ -1210,7 +1399,7 @@ timeout_cb_swp(evutil_socket_t fd, short event, void *arg)
 
                called = 0;
                evtimer_add((struct event *)arg, &tv);
-               raise(SIGUSR1);
+               kill(getpid(), SIGUSR1);
                return;
        }
        test_ok = 0;
@@ -1248,18 +1437,14 @@ test_free_active_base(void *ptr)
        struct event ev1;
 
        base1 = event_init();
-       if (base1) {
-               event_assign(&ev1, base1, data->pair[1], EV_READ,
-                            dummy_read_cb, NULL);
-               event_add(&ev1, NULL);
-               event_base_free(base1);  /* should not crash */
-       } else {
-               tt_fail_msg("failed to create event_base for test");
-       }
+       tt_assert(base1);
+       event_assign(&ev1, base1, data->pair[1], EV_READ, dummy_read_cb, NULL);
+       event_add(&ev1, NULL);
+       event_base_free(base1);  /* should not crash */
 
        base1 = event_init();
        tt_assert(base1);
-       event_assign(&ev1, base1, 0, 0, dummy_read_cb, NULL);
+       event_assign(&ev1, base1, data->pair[0], 0, dummy_read_cb, NULL);
        event_active(&ev1, EV_READ, 1);
        event_base_free(base1);
 end:
@@ -1737,7 +1922,8 @@ static void send_a_byte_cb(evutil_socket_t fd, short what, void *arg)
 {
        evutil_socket_t *sockp = arg;
        (void) fd; (void) what;
-       (void) write(*sockp, "A", 1);
+       if (write(*sockp, "A", 1) < 0)
+               tt_fail_perror("write");
 }
 struct read_not_timeout_param
 {
@@ -1820,7 +2006,7 @@ test_event_base_new(void *ptr)
                tt_abort_printf(("initial write fell short (%d of %d bytes)",
                                 len, towrite));
 
-       if (shutdown(data->pair[0], SHUT_WR))
+       if (shutdown(data->pair[0], EVUTIL_SHUT_WR))
                tt_abort_perror("initial write shutdown");
 
        base = event_base_new();
@@ -1967,60 +2153,48 @@ re_add_read_cb(evutil_socket_t fd, short event, void *arg)
        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;
        }
 }
-
 static void
-test_nonpersist_readd(void)
+test_nonpersist_readd(void *_data)
 {
        struct event ev1, ev2;
+       struct basic_test_data *data = _data;
 
-       setup_test("Re-add nonpersistent events: ");
-       event_set(&ev1, pair[0], EV_READ, re_add_read_cb, &ev2);
-       event_set(&ev2, pair[1], EV_READ, re_add_read_cb, &ev1);
+       memset(&ev1, 0, sizeof(ev1));
+       memset(&ev2, 0, sizeof(ev2));
 
-       if (write(pair[0], "Hello", 5) < 0) {
-               tt_fail_perror("write(pair[0])");
-       }
+       tt_assert(!event_assign(&ev1, data->base, data->pair[0], EV_READ, re_add_read_cb, &ev2));
+       tt_assert(!event_assign(&ev2, data->base, data->pair[1], EV_READ, re_add_read_cb, &ev1));
 
-       if (write(pair[1], "Hello", 5) < 0) {
-               tt_fail_perror("write(pair[1])\n");
-       }
+       tt_int_op(write(data->pair[0], "Hello", 5), ==, 5);
+       tt_int_op(write(data->pair[1], "Hello", 5), ==, 5);
+
+       tt_int_op(event_add(&ev1, NULL), ==, 0);
+       tt_int_op(event_add(&ev2, NULL), ==, 0);
+       tt_int_op(event_base_loop(data->base, EVLOOP_ONCE), ==, 0);
+       tt_int_op(test_ok, ==, 2);
 
-       if (event_add(&ev1, NULL) == -1 ||
-           event_add(&ev2, NULL) == -1) {
-               test_ok = 0;
-       }
-       if (test_ok != 0)
-               exit(1);
-       event_loop(EVLOOP_ONCE);
-       if (test_ok != 2)
-               exit(1);
        /* At this point, we executed both callbacks.  Whichever one got
         * called first added the second, but the second then immediately got
         * deleted before its callback was called.  At this point, though, it
         * re-added the first.
         */
-       if (!readd_test_event_last_added) {
-               test_ok = 0;
-       } else if (readd_test_event_last_added == &ev1) {
-               if (!event_pending(&ev1, EV_READ, NULL) ||
-                   event_pending(&ev2, EV_READ, NULL))
-                       test_ok = 0;
+       tt_assert(readd_test_event_last_added);
+       if (readd_test_event_last_added == &ev1) {
+               tt_assert(event_pending(&ev1, EV_READ, NULL) && !event_pending(&ev2, EV_READ, NULL));
        } else {
-               if (event_pending(&ev1, EV_READ, NULL) ||
-                   !event_pending(&ev2, EV_READ, NULL))
-                       test_ok = 0;
+               tt_assert(event_pending(&ev2, EV_READ, NULL) && !event_pending(&ev1, EV_READ, NULL));
        }
 
-       event_del(&ev1);
-       event_del(&ev2);
-
-       cleanup_test();
+end:
+       if (event_initialized(&ev1))
+               event_del(&ev1);
+       if (event_initialized(&ev2))
+               event_del(&ev2);
 }
 
 struct test_pri_event {
@@ -2290,7 +2464,7 @@ end:
 static void
 evtag_fuzz(void *ptr)
 {
-       u_char buffer[4096];
+       unsigned char buffer[4096];
        struct evbuffer *tmp = evbuffer_new();
        struct timeval tv;
        int i, j;
@@ -2649,7 +2823,7 @@ test_event_once(void *ptr)
                tt_fail_perror("write");
        }
 
-       shutdown(data->pair[1], SHUT_WR);
+       shutdown(data->pair[1], EVUTIL_SHUT_WR);
 
        event_base_dispatch(data->base);
 
@@ -2733,15 +2907,47 @@ end:
        }
 }
 
-#ifndef _WIN32
-/* You can't do this test on windows, since dup2 doesn't work on sockets */
-
 static void
 dfd_cb(evutil_socket_t fd, short e, void *data)
 {
        *(int*)data = (int)e;
 }
 
+static void
+test_event_closed_fd_poll(void *arg)
+{
+       struct timeval tv;
+       struct event *e;
+       struct basic_test_data *data = (struct basic_test_data *)arg;
+       int i = 0;
+
+       if (strcmp(event_base_get_method(data->base), "poll")) {
+               tinytest_set_test_skipped_();
+               return;
+       }
+
+       e = event_new(data->base, data->pair[0], EV_READ, dfd_cb, &i);
+       tt_assert(e);
+
+       tv.tv_sec = 0;
+       tv.tv_usec = 500 * 1000;
+       event_add(e, &tv);
+       tt_assert(event_pending(e, EV_READ, NULL));
+       close(data->pair[0]);
+       data->pair[0] = -1; /** avoids double-close */
+       event_base_loop(data->base, EVLOOP_ONCE);
+       tt_int_op(i, ==, EV_READ);
+
+end:
+       if (e) {
+               event_del(e);
+               event_free(e);
+       }
+}
+
+#ifndef _WIN32
+/* You can't do this test on windows, since dup2 doesn't work on sockets */
+
 /* Regression test for our workaround for a fun epoll/linux related bug
  * where fd2 = dup(fd1); add(fd2); close(fd2); dup2(fd1,fd2); add(fd2)
  * will get you an EEXIST */
@@ -2823,10 +3029,6 @@ static void *
 dummy_malloc(size_t len)
 {
        char *mem = malloc(len+16);
-       if (mem == NULL) {
-               fprintf(stderr, "Unable to allocate memory in dummy_malloc()\n");
-               return NULL;
-       }
        memcpy(mem, "{[<guardedram>]}", 16);
        return mem+16;
 }
@@ -2910,6 +3112,7 @@ test_many_events(void *arg)
                 * instance of that. */
                sock[i] = socket(AF_INET, SOCK_DGRAM, 0);
                tt_assert(sock[i] >= 0);
+               tt_assert(!evutil_make_socket_nonblocking(sock[i]));
                called[i] = 0;
                ev[i] = event_new(base, sock[i], EV_WRITE|evflags,
                    many_event_cb, &called[i]);
@@ -2963,7 +3166,7 @@ test_get_assignment(void *arg)
        event_get_assignment(ev1, &b, &s, &what, &cb, &cb_arg);
 
        tt_ptr_op(b, ==, base);
-       tt_int_op(s, ==, data->pair[1]);
+       tt_fd_op(s, ==, data->pair[1]);
        tt_int_op(what, ==, EV_READ);
        tt_ptr_op(cb, ==, dummy_read_cb);
        tt_ptr_op(cb_arg, ==, str);
@@ -3148,6 +3351,46 @@ tabf_cb(evutil_socket_t fd, short what, void *arg)
        *ptr += 0x10000;
 }
 
+static void
+test_evmap_invalid_slots(void *arg)
+{
+       struct basic_test_data *data = arg;
+       struct event_base *base = data->base;
+       struct event *ev1 = NULL, *ev2 = NULL;
+       int e1, e2;
+#ifndef _WIN32
+       struct event *ev3 = NULL, *ev4 = NULL;
+       int e3, e4;
+#endif
+
+       ev1 = evsignal_new(base, -1, dummy_read_cb, (void *)base);
+       ev2 = evsignal_new(base, NSIG, dummy_read_cb, (void *)base);
+       tt_assert(ev1);
+       tt_assert(ev2);
+       e1 = event_add(ev1, NULL);
+       e2 = event_add(ev2, NULL);
+       tt_int_op(e1, !=, 0);
+       tt_int_op(e2, !=, 0);
+#ifndef _WIN32
+       ev3 = event_new(base, INT_MAX, EV_READ, dummy_read_cb, (void *)base);
+       ev4 = event_new(base, INT_MAX / 2, EV_READ, dummy_read_cb, (void *)base);
+       tt_assert(ev3);
+       tt_assert(ev4);
+       e3 = event_add(ev3, NULL);
+       e4 = event_add(ev4, NULL);
+       tt_int_op(e3, !=, 0);
+       tt_int_op(e4, !=, 0);
+#endif
+
+end:
+       event_free(ev1);
+       event_free(ev2);
+#ifndef _WIN32
+       event_free(ev3);
+       event_free(ev4);
+#endif
+}
+
 static void
 test_active_by_fd(void *arg)
 {
@@ -3199,6 +3442,7 @@ test_active_by_fd(void *arg)
        /* 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);
+       event_base_active_by_fd(base, data->pair[1], EV_TIMEOUT);
 #ifndef _WIN32
        event_base_active_by_signal(base, SIGHUP);
 #endif
@@ -3211,7 +3455,7 @@ test_active_by_fd(void *arg)
        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);
+       tt_int_op((e4 & ~EV_WRITE), ==, EV_READ | EV_TIMEOUT | 0x10000);
 #ifndef _WIN32
        tt_int_op(es, ==, EV_SIGNAL | 0x10000);
 #endif
@@ -3246,17 +3490,18 @@ struct testcase_t main_testcases[] = {
        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(evmap_invalid_slots, 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),
-       BASIC(active_later, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR),
+       BASIC(active_later, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR|TT_RETRIABLE),
        BASIC(event_remove_timeout, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR),
 
        /* These are still using the old API */
        LEGACY(persistent_timeout, TT_FORK|TT_NEED_BASE),
        { "persistent_timeout_jump", test_persistent_timeout_jump, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
        { "persistent_active_timeout", test_persistent_active_timeout,
-         TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+         TT_FORK|TT_NEED_BASE|TT_RETRIABLE, &basic_setup, NULL },
        LEGACY(priorities, TT_FORK|TT_NEED_BASE),
        BASIC(priority_active_inversion, TT_FORK|TT_NEED_BASE),
        { "common_timeout", test_common_timeout, TT_FORK|TT_NEED_BASE,
@@ -3266,8 +3511,35 @@ struct testcase_t main_testcases[] = {
        LEGACY(simpleread, TT_ISOLATED),
        LEGACY(simpleread_multiple, TT_ISOLATED),
        LEGACY(simplewrite, TT_ISOLATED),
-       { "simpleclose", test_simpleclose, TT_FORK, &basic_setup,
-         NULL },
+       { "simpleclose_rw", test_simpleclose_rw, TT_FORK, &basic_setup, NULL },
+       /* simpleclose */
+       { "simpleclose_close", test_simpleclose,
+         TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE,
+         &basic_setup, (void *)"close" },
+       { "simpleclose_shutdown", test_simpleclose,
+         TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE,
+         &basic_setup, (void *)"shutdown" },
+       /* simpleclose_*_persist */
+       { "simpleclose_close_persist", test_simpleclose,
+         TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE,
+         &basic_setup, (void *)"close_persist" },
+       { "simpleclose_shutdown_persist", test_simpleclose,
+         TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE,
+         &basic_setup, (void *)"shutdown_persist" },
+       /* simpleclose_*_et */
+       { "simpleclose_close_et", test_simpleclose,
+         TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE,
+         &basic_setup, (void *)"close_ET" },
+       { "simpleclose_shutdown_et", test_simpleclose,
+         TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE,
+         &basic_setup, (void *)"shutdown_ET" },
+       /* simpleclose_*_persist_et */
+       { "simpleclose_close_persist_et", test_simpleclose,
+         TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE,
+         &basic_setup, (void *)"close_persist_ET" },
+       { "simpleclose_shutdown_persist_et", test_simpleclose,
+         TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE,
+         &basic_setup, (void *)"shutdown_persist_ET" },
        LEGACY(multiple, TT_ISOLATED),
        LEGACY(persistent, TT_ISOLATED),
        LEGACY(combined, TT_ISOLATED),
@@ -3275,13 +3547,16 @@ struct testcase_t main_testcases[] = {
        LEGACY(loopbreak, TT_ISOLATED),
        LEGACY(loopexit, TT_ISOLATED),
        LEGACY(loopexit_multiple, TT_ISOLATED),
-       LEGACY(nonpersist_readd, TT_ISOLATED),
+       { "nonpersist_readd", test_nonpersist_readd, TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, &basic_setup, NULL },
        LEGACY(multiple_events_for_same_fd, TT_ISOLATED),
        LEGACY(want_only_once, TT_ISOLATED),
        { "event_once", test_event_once, TT_ISOLATED, &basic_setup, NULL },
        { "event_once_never", test_event_once_never, TT_ISOLATED, &basic_setup, NULL },
        { "event_pending", test_event_pending, TT_ISOLATED, &basic_setup,
          NULL },
+       { "event_closed_fd_poll", test_event_closed_fd_poll, TT_ISOLATED, &basic_setup,
+         NULL },
+
 #ifndef _WIN32
        { "dup_fd", test_dup_fd, TT_ISOLATED, &basic_setup, NULL },
 #endif
@@ -3304,6 +3579,12 @@ struct testcase_t main_testcases[] = {
 #ifndef _WIN32
        LEGACY(fork, TT_ISOLATED),
 #endif
+
+#ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED
+       LEGACY(del_wait, TT_ISOLATED|TT_NEED_THREADS|TT_RETRIABLE),
+       LEGACY(del_notify, TT_ISOLATED|TT_NEED_THREADS),
+#endif
+
        END_OF_TESTCASES
 };
 
index bbfefe6739e449ae5ea2fd4b8a2f4bc2cf1fb400..43cb4eaf1e690a42b34a7ec9d4031a4e902ba407 100644 (file)
@@ -43,6 +43,7 @@ extern struct testcase_t bufferevent_iocp_testcases[];
 extern struct testcase_t util_testcases[];
 extern struct testcase_t signal_testcases[];
 extern struct testcase_t http_testcases[];
+extern struct testcase_t http_iocp_testcases[];
 extern struct testcase_t dns_testcases[];
 extern struct testcase_t rpc_testcases[];
 extern struct testcase_t edgetriggered_testcases[];
@@ -94,6 +95,7 @@ extern int libevent_tests_running_in_debug_mode;
 #define TT_NO_LOGS             (TT_FIRST_USER_FLAG<<5)
 #define TT_ENABLE_IOCP_FLAG    (TT_FIRST_USER_FLAG<<6)
 #define TT_ENABLE_IOCP         (TT_ENABLE_IOCP_FLAG|TT_NEED_THREADS)
+#define TT_ENABLE_DEBUG_MODE   (TT_ENABLE_IOCP_FLAG<<7)
 
 /* All the flags that a legacy test needs. */
 #define TT_ISOLATED TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE
@@ -129,6 +131,17 @@ long timeval_msec_diff(const struct timeval *start, const struct timeval *end);
 pid_t regress_fork(void);
 #endif
 
+#ifdef EVENT__HAVE_OPENSSL
+#include <openssl/ssl.h>
+EVP_PKEY *ssl_getkey(void);
+X509 *ssl_getcert(EVP_PKEY *key);
+SSL_CTX *get_ssl_ctx(void);
+void init_ssl(void);
+#endif
+
+void * basic_test_setup(const struct testcase_t *testcase);
+int    basic_test_cleanup(const struct testcase_t *testcase, void *ptr);
+
 #ifdef __cplusplus
 }
 #endif
index 4d6a5de20b33a376386b39c897c8c84f6708a7f1..f259b924bff06b8c10861debddf5c3434903fad5 100644 (file)
@@ -63,6 +63,8 @@
 
 #include "regress.h"
 
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
 /* Validates that an evbuffer is good. Returns false if it isn't, true if it
  * is*/
 static int
@@ -198,7 +200,7 @@ test_evbuffer(void *ptr)
 
        tt_assert(evbuffer_get_length(evb_two) == 0);
        tt_assert(evbuffer_get_length(evb) == 7);
-       tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1/hello", 7) != 0);
+       tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1/hello", 7));
 
        memset(buffer, 0, sizeof(buffer));
        evbuffer_add(evb, buffer, sizeof(buffer));
@@ -294,33 +296,306 @@ no_cleanup(const void *data, size_t datalen, void *extra)
 static void
 test_evbuffer_remove_buffer_with_empty(void *ptr)
 {
-    struct evbuffer *src = evbuffer_new();
-    struct evbuffer *dst = evbuffer_new();
-    char buf[2];
+       struct evbuffer *src = evbuffer_new();
+       struct evbuffer *dst = evbuffer_new();
+       char buf[2] = { 'A', 'A' };
 
-    evbuffer_validate(src);
-    evbuffer_validate(dst);
+       evbuffer_validate(src);
+       evbuffer_validate(dst);
 
-    /* setup the buffers */
-    /* we need more data in src than we will move later */
-    evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL);
-    evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL);
-    /* we need one buffer in dst and one empty buffer at the end */
-    evbuffer_add(dst, buf, sizeof(buf));
-    evbuffer_add_reference(dst, buf, 0, no_cleanup, NULL);
+       /* setup the buffers */
+       /* we need more data in src than we will move later */
+       evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL);
+       evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL);
+       /* we need one buffer in dst and one empty buffer at the end */
+       evbuffer_add(dst, buf, sizeof(buf));
+       evbuffer_add_reference(dst, buf, 0, no_cleanup, NULL);
 
-    evbuffer_validate(src);
-    evbuffer_validate(dst);
+       evbuffer_validate(src);
+       evbuffer_validate(dst);
 
-    /* move three bytes over */
-    evbuffer_remove_buffer(src, dst, 3);
+       tt_mem_op(evbuffer_pullup(src, -1), ==, "AAAA", 4);
+       tt_mem_op(evbuffer_pullup(dst, -1), ==, "AA", 2);
 
-    evbuffer_validate(src);
-    evbuffer_validate(dst);
+       /* move three bytes over */
+       evbuffer_remove_buffer(src, dst, 3);
 
-end:
-    evbuffer_free(src);
-    evbuffer_free(dst);
+       evbuffer_validate(src);
+       evbuffer_validate(dst);
+
+       tt_mem_op(evbuffer_pullup(src, -1), ==, "A", 1);
+       tt_mem_op(evbuffer_pullup(dst, -1), ==, "AAAAA", 5);
+
+ end:
+       evbuffer_free(src);
+       evbuffer_free(dst);
+}
+
+static void
+test_evbuffer_remove_buffer_with_empty2(void *ptr)
+{
+       struct evbuffer *src = evbuffer_new();
+       struct evbuffer *dst = evbuffer_new();
+       struct evbuffer *buf = evbuffer_new();
+
+       evbuffer_add(buf, "foo", 3);
+       evbuffer_add_reference(buf, "foo", 3, NULL, NULL);
+
+       evbuffer_add_reference(src, "foo", 3, NULL, NULL);
+       evbuffer_add_reference(src, NULL, 0, NULL, NULL);
+       evbuffer_add_buffer(src, buf);
+
+       evbuffer_add(buf, "foo", 3);
+       evbuffer_add_reference(buf, "foo", 3, NULL, NULL);
+
+       evbuffer_add_reference(dst, "foo", 3, NULL, NULL);
+       evbuffer_add_reference(dst, NULL, 0, NULL, NULL);
+       evbuffer_add_buffer(dst, buf);
+
+       tt_int_op(evbuffer_get_length(src), ==, 9);
+       tt_int_op(evbuffer_get_length(dst), ==, 9);
+
+       evbuffer_validate(src);
+       evbuffer_validate(dst);
+
+       tt_mem_op(evbuffer_pullup(src, -1), ==, "foofoofoo", 9);
+       tt_mem_op(evbuffer_pullup(dst, -1), ==, "foofoofoo", 9);
+
+       evbuffer_remove_buffer(src, dst, 8);
+
+       evbuffer_validate(src);
+       evbuffer_validate(dst);
+
+       tt_int_op(evbuffer_get_length(src), ==, 1);
+       tt_int_op(evbuffer_get_length(dst), ==, 17);
+
+       tt_mem_op(evbuffer_pullup(src, -1), ==, "o", 1);
+       tt_mem_op(evbuffer_pullup(dst, -1), ==, "foofoofoofoofoofo", 17);
+
+ end:
+       evbuffer_free(src);
+       evbuffer_free(dst);
+       evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_remove_buffer_with_empty3(void *ptr)
+{
+       struct evbuffer *src = evbuffer_new();
+       struct evbuffer *dst = evbuffer_new();
+       struct evbuffer *buf = evbuffer_new();
+
+       evbuffer_add(buf, "foo", 3);
+       evbuffer_add_reference(buf, NULL, 0, NULL, NULL);
+
+       evbuffer_add_reference(src, "foo", 3, NULL, NULL);
+       evbuffer_add_reference(src, NULL, 0, NULL, NULL);
+       evbuffer_prepend_buffer(src, buf);
+
+       evbuffer_add(buf, "foo", 3);
+       evbuffer_add_reference(buf, NULL, 0, NULL, NULL);
+
+       evbuffer_add_reference(dst, "foo", 3, NULL, NULL);
+       evbuffer_add_reference(dst, NULL, 0, NULL, NULL);
+       evbuffer_prepend_buffer(dst, buf);
+
+       tt_int_op(evbuffer_get_length(src), ==, 6);
+       tt_int_op(evbuffer_get_length(dst), ==, 6);
+
+       evbuffer_validate(src);
+       evbuffer_validate(dst);
+
+       tt_mem_op(evbuffer_pullup(src, -1), ==, "foofoo", 6);
+       tt_mem_op(evbuffer_pullup(dst, -1), ==, "foofoo", 6);
+
+       evbuffer_remove_buffer(src, dst, 5);
+
+       evbuffer_validate(src);
+       evbuffer_validate(dst);
+
+       tt_int_op(evbuffer_get_length(src), ==, 1);
+       tt_int_op(evbuffer_get_length(dst), ==, 11);
+
+       tt_mem_op(evbuffer_pullup(src, -1), ==, "o", 1);
+       tt_mem_op(evbuffer_pullup(dst, -1), ==, "foofoofoofo", 11);
+
+ end:
+       evbuffer_free(src);
+       evbuffer_free(dst);
+       evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_pullup_with_empty(void *ptr)
+{
+       struct evbuffer *buf = NULL;
+
+       buf = evbuffer_new();
+       evbuffer_add(buf, "foo", 3);
+       evbuffer_add_reference(buf, NULL, 0, NULL, NULL);
+       evbuffer_validate(buf);
+       tt_int_op(evbuffer_get_length(buf), ==, 3);
+       tt_mem_op(evbuffer_pullup(buf, -1), ==, "foo", 3);
+
+       evbuffer_free(buf);
+       buf = evbuffer_new();
+       evbuffer_validate(buf);
+       tt_int_op(evbuffer_get_length(buf), ==, 0);
+       tt_int_op(evbuffer_pullup(buf, -1), ==, NULL);
+
+       evbuffer_free(buf);
+       buf = evbuffer_new();
+       evbuffer_add(buf, "foo", 3);
+       evbuffer_add_reference(buf, NULL, 0, NULL, NULL);
+       evbuffer_validate(buf);
+       tt_mem_op(evbuffer_pullup(buf, 3), ==, "foo", 3);
+
+ end:
+       if (buf)
+               evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_remove_buffer_with_empty_front(void *ptr)
+{
+       struct evbuffer *buf1 = NULL, *buf2 = NULL;
+
+       buf1 = evbuffer_new();
+       tt_assert(buf1);
+
+       buf2 = evbuffer_new();
+       tt_assert(buf2);
+
+       tt_int_op(evbuffer_add_reference(buf1, "foo", 3, NULL, NULL), ==, 0);
+       tt_int_op(evbuffer_prepend(buf1, "", 0), ==, 0);
+       tt_int_op(evbuffer_remove_buffer(buf1, buf2, 1), ==, 1);
+       tt_int_op(evbuffer_add(buf1, "bar", 3), ==, 0);
+       tt_mem_op(evbuffer_pullup(buf1, -1), ==, "oobar", 5);
+
+       evbuffer_validate(buf1);
+       evbuffer_validate(buf2);
+
+ end:
+       if (buf1)
+               evbuffer_free(buf1);
+       if (buf2)
+               evbuffer_free(buf2);
+}
+
+static void
+test_evbuffer_remove_buffer_adjust_last_with_datap_with_empty(void *ptr)
+{
+       struct evbuffer *buf1 = NULL, *buf2 = NULL;
+
+       buf1 = evbuffer_new();
+       tt_assert(buf1);
+
+       buf2 = evbuffer_new();
+       tt_assert(buf2);
+
+       tt_int_op(evbuffer_add(buf1, "aaaaaa", 6), ==, 0);
+
+       // buf1: aaaaaab
+       // buf2:
+       {
+               struct evbuffer_iovec iovecs[2];
+               /** we want two chains, to leave one chain empty */
+               tt_int_op(evbuffer_reserve_space(buf1, 971, iovecs, 2), ==, 2);
+               tt_int_op(iovecs[0].iov_len, >=, 1);
+               tt_int_op(iovecs[1].iov_len, >=, 1);
+               tt_assert(*(char *)(iovecs[0].iov_base) = 'b');
+               tt_assert(iovecs[0].iov_len = 1);
+               tt_int_op(evbuffer_commit_space(buf1, iovecs, 1), ==, 0);
+       }
+
+       // buf1: aaaaaab
+       // buf2: dddcc
+       tt_int_op(evbuffer_add(buf2, "cc", 2), ==, 0);
+       tt_int_op(evbuffer_prepend(buf2, "ddd", 3), ==, 0);
+
+       // buf1:
+       // buf2: aaaaaabdddcc
+       tt_int_op(evbuffer_prepend_buffer(buf2, buf1), ==, 0);
+
+       // buf1: aaaaaabdddcc
+       // buf2:
+       tt_int_op(evbuffer_add_buffer(buf1, buf2), ==, 0);
+
+       // buf1: c
+       // buf2: aaaaaabdddc
+       tt_int_op(evbuffer_remove_buffer(buf1, buf2, 11), ==, 11);
+
+       // This fails today, we observe "aaaaaabcddd" instead!
+       tt_mem_op(evbuffer_pullup(buf2, -1), ==, "aaaaaabdddc", 11);
+
+       evbuffer_validate(buf1);
+       evbuffer_validate(buf2);
+
+ end:
+       if (buf1)
+               evbuffer_free(buf1);
+       if (buf2)
+               evbuffer_free(buf2);
+}
+
+static void
+test_evbuffer_add_buffer_with_empty(void *ptr)
+{
+       struct evbuffer *src = evbuffer_new();
+       struct evbuffer *dst = evbuffer_new();
+       struct evbuffer *buf = evbuffer_new();
+
+       evbuffer_add(buf, "foo", 3);
+
+       evbuffer_add_reference(src, "foo", 3, NULL, NULL);
+       evbuffer_add_reference(src, NULL, 0, NULL, NULL);
+       evbuffer_add_buffer(src, buf);
+
+       evbuffer_add(buf, "foo", 3);
+
+       evbuffer_add_reference(dst, "foo", 3, NULL, NULL);
+       evbuffer_add_reference(dst, NULL, 0, NULL, NULL);
+       evbuffer_add_buffer(dst, buf);
+
+       tt_int_op(evbuffer_get_length(src), ==, 6);
+       tt_int_op(evbuffer_get_length(dst), ==, 6);
+
+       evbuffer_validate(src);
+       evbuffer_validate(dst);
+
+ end:
+       evbuffer_free(src);
+       evbuffer_free(dst);
+       evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_add_buffer_with_empty2(void *ptr)
+{
+       struct evbuffer *src = evbuffer_new();
+       struct evbuffer *dst = evbuffer_new();
+       struct evbuffer *buf = evbuffer_new();
+
+       evbuffer_add(buf, "foo", 3);
+
+       evbuffer_add_reference(src, NULL, 0, NULL, NULL);
+       evbuffer_add_buffer(src, buf);
+
+       evbuffer_add(buf, "foo", 3);
+
+       evbuffer_add_reference(dst, NULL, 0, NULL, NULL);
+       evbuffer_add_buffer(dst, buf);
+
+       tt_int_op(evbuffer_get_length(src), ==, 3);
+       tt_int_op(evbuffer_get_length(dst), ==, 3);
+
+       evbuffer_validate(src);
+       evbuffer_validate(dst);
+
+ end:
+       evbuffer_free(src);
+       evbuffer_free(dst);
+       evbuffer_free(buf);
 }
 
 static void
@@ -492,6 +767,63 @@ end:
        evbuffer_free(buf);
 }
 
+static void
+test_evbuffer_reserve_with_empty(void *ptr)
+{
+       struct evbuffer *buf;
+       struct evbuffer_iovec v[2];
+
+       tt_assert(buf = evbuffer_new());
+       evbuffer_add(buf, "a", 1);
+       tt_int_op(evbuffer_reserve_space(buf, 1<<12, v, 2), ==, 2);
+       v[0].iov_len = 1;
+       *(char *)v[0].iov_base = 'b';
+       tt_int_op(evbuffer_commit_space(buf, v, 1), ==, 0);
+       evbuffer_add(buf, "c", 1);
+       tt_mem_op(evbuffer_pullup(buf, -1), ==, "abc", 2);
+
+       evbuffer_validate(buf);
+
+ end:
+       if (buf)
+               evbuffer_free(buf);
+}
+
+/* regression for evbuffer_expand_fast_() with invalid last_with_datap that has
+ * been left after evbuffer_prepend() with empty chain in it */
+static void
+test_evbuffer_reserve_invalid_last_with_datap(void *ptr)
+{
+       struct evbuffer *buf = NULL;
+       struct evbuffer_iovec vec[2];
+       const int nvec = ARRAY_SIZE(vec);
+       int i, avec;
+
+       buf = evbuffer_new();
+       tt_assert(buf);
+
+       /* prepend with an empty chain */
+       evbuffer_add_reference(buf, "", 0, NULL, NULL);
+       evbuffer_prepend(buf, "foo", 3);
+       /* after invalid last_with_datap will create new chain */
+       evbuffer_add(buf, "", 0);
+       /* we need to create at least 2 "used" (in evbuffer_expand_fast_()) chains */
+       tt_int_op(avec = evbuffer_reserve_space(buf, 1<<12, vec, nvec), >=, 1);
+       for (i = 0; i < avec; ++i)
+               vec[i].iov_len = 0;
+       tt_int_op(evbuffer_commit_space(buf, vec, avec), ==, 0);
+
+       /* and an actual problem, that triggers an assert(chain == buf->first) in
+        * evbuffer_expand_fast_() */
+       tt_int_op(evbuffer_reserve_space(buf, 1<<13, vec, nvec), >=, 1);
+
+       evbuffer_validate(buf);
+
+end:
+       if (buf)
+               evbuffer_free(buf);
+}
+
 static void
 test_evbuffer_expand(void *ptr)
 {
@@ -566,6 +898,77 @@ end:
        evbuffer_free(buf);
 }
 
+static void
+test_evbuffer_expand_overflow(void *ptr)
+{
+       struct evbuffer *buf;
+
+       buf = evbuffer_new();
+       evbuffer_add(buf, "1", 1);
+       evbuffer_expand(buf, EVBUFFER_CHAIN_MAX);
+       evbuffer_validate(buf);
+
+       evbuffer_expand(buf, EV_SIZE_MAX);
+       evbuffer_validate(buf);
+
+end:
+       evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_add1(void *ptr)
+{
+       struct evbuffer *buf;
+       char *str;
+
+       buf = evbuffer_new();
+       evbuffer_add(buf, "1", 1);
+       evbuffer_validate(buf);
+       evbuffer_expand(buf, 2048);
+       evbuffer_validate(buf);
+       evbuffer_add(buf, "2", 1);
+       evbuffer_validate(buf);
+       evbuffer_add_printf(buf, "3");
+       evbuffer_validate(buf);
+
+       tt_assert(evbuffer_get_length(buf) == 3);
+       str = (char *)evbuffer_pullup(buf, -1);
+       tt_assert(str[0] == '1');
+       tt_assert(str[1] == '2');
+       tt_assert(str[2] == '3');
+end:
+       evbuffer_free(buf);
+}
+
+static void
+test_evbuffer_add2(void *ptr)
+{
+       struct evbuffer *buf;
+       static char data[4096];
+       int data_len = MIN_BUFFER_SIZE-EVBUFFER_CHAIN_SIZE-10;
+       char *str;
+       int len;
+
+       memset(data, 'P', sizeof(data));
+       buf = evbuffer_new();
+       evbuffer_add(buf, data, data_len);
+       evbuffer_validate(buf);
+       evbuffer_expand(buf, 100);
+       evbuffer_validate(buf);
+       evbuffer_add(buf, "2", 1);
+       evbuffer_validate(buf);
+       evbuffer_add_printf(buf, "3");
+       evbuffer_validate(buf);
+
+       len = evbuffer_get_length(buf);
+       tt_assert(len == data_len+2);
+       str = (char *)evbuffer_pullup(buf, -1);
+       tt_assert(str[len-3] == 'P');
+       tt_assert(str[len-2] == '2');
+       tt_assert(str[len-1] == '3');
+end:
+       evbuffer_free(buf);
+}
 
 static int reference_cb_called;
 static void
@@ -622,10 +1025,40 @@ test_evbuffer_reference(void *ptr)
        evbuffer_free(src);
 }
 
-static struct event_base *addfile_test_event_base = NULL;
-static int addfile_test_done_writing = 0;
-static int addfile_test_total_written = 0;
-static int addfile_test_total_read = 0;
+static void
+test_evbuffer_reference2(void *ptr)
+{
+       struct evbuffer *buf;
+       static char data[4096];
+       int data_len = MIN_BUFFER_SIZE-EVBUFFER_CHAIN_SIZE-10;
+       char *str;
+       int len;
+
+       memset(data, 'P', sizeof(data));
+       buf = evbuffer_new();
+       evbuffer_add(buf, data, data_len);
+       evbuffer_validate(buf);
+       evbuffer_expand(buf, 100);
+       evbuffer_validate(buf);
+       evbuffer_add_reference(buf, "2", 1, no_cleanup, NULL);
+       evbuffer_validate(buf);
+       evbuffer_add_printf(buf, "3");
+       evbuffer_validate(buf);
+
+       len = evbuffer_get_length(buf);
+       tt_assert(len == data_len+2);
+       str = (char *)evbuffer_pullup(buf, -1);
+       tt_assert(str[len-3] == 'P');
+       tt_assert(str[len-2] == '2');
+       tt_assert(str[len-1] == '3');
+end:
+       evbuffer_free(buf);
+}
+
+static struct event_base *addfile_test_event_base;
+static int addfile_test_done_writing;
+static int addfile_test_total_written;
+static int addfile_test_total_read;
 
 static void
 addfile_test_writecb(evutil_socket_t fd, short what, void *arg)
@@ -827,6 +1260,10 @@ test_evbuffer_add_file(void *ptr)
        evbuffer_validate(src);
 
        addfile_test_event_base = base;
+       addfile_test_done_writing = 0;
+       addfile_test_total_written = 0;
+       addfile_test_total_read = 0;
+
        wev = event_new(base, pair[0], EV_WRITE|EV_PERSIST,
            addfile_test_writecb, src);
        rev = event_new(base, pair[1], EV_READ|EV_PERSIST,
@@ -1292,7 +1729,7 @@ test_evbuffer_iterative(void *ptr)
 static void
 test_evbuffer_find(void *ptr)
 {
-       u_char* p;
+       unsigned char* p;
        const char* test1 = "1234567890\r\n";
        const char* test2 = "1234567890\r";
 #define EVBUFFER_INITIAL_LENGTH 256
@@ -1303,13 +1740,13 @@ test_evbuffer_find(void *ptr)
        tt_assert(buf);
 
        /* make sure evbuffer_find doesn't match past the end of the buffer */
-       evbuffer_add(buf, (u_char*)test1, strlen(test1));
+       evbuffer_add(buf, (unsigned char*)test1, strlen(test1));
        evbuffer_validate(buf);
        evbuffer_drain(buf, strlen(test1));
        evbuffer_validate(buf);
-       evbuffer_add(buf, (u_char*)test2, strlen(test2));
+       evbuffer_add(buf, (unsigned char*)test2, strlen(test2));
        evbuffer_validate(buf);
-       p = evbuffer_find(buf, (u_char*)"\r\n", 2);
+       p = evbuffer_find(buf, (unsigned char*)"\r\n", 2);
        tt_want(p == NULL);
 
        /*
@@ -1321,13 +1758,13 @@ test_evbuffer_find(void *ptr)
        for (i = 0; i < EVBUFFER_INITIAL_LENGTH; ++i)
                test3[i] = 'a';
        test3[EVBUFFER_INITIAL_LENGTH - 1] = 'x';
-       evbuffer_add(buf, (u_char *)test3, EVBUFFER_INITIAL_LENGTH);
+       evbuffer_add(buf, (unsigned char *)test3, EVBUFFER_INITIAL_LENGTH);
        evbuffer_validate(buf);
-       p = evbuffer_find(buf, (u_char *)"xy", 2);
+       p = evbuffer_find(buf, (unsigned char *)"xy", 2);
        tt_want(p == NULL);
 
        /* simple test for match at end of allocated buffer */
-       p = evbuffer_find(buf, (u_char *)"ax", 2);
+       p = evbuffer_find(buf, (unsigned char *)"ax", 2);
        tt_assert(p != NULL);
        tt_want(strncmp((char*)p, "ax", 2) == 0);
 
@@ -1549,12 +1986,12 @@ test_evbuffer_callbacks(void *ptr)
        tt_assert(cb1 != NULL);
        cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
        tt_assert(cb2 != NULL);
-       evbuffer_setcb(buf, self_draining_callback, NULL);
+       tt_int_op(evbuffer_setcb(buf, self_draining_callback, NULL), ==, 0);
        evbuffer_add_printf(buf, "This should get drained right away.");
        tt_uint_op(evbuffer_get_length(buf), ==, 0);
        tt_uint_op(evbuffer_get_length(buf_out1), ==, 0);
        tt_uint_op(evbuffer_get_length(buf_out2), ==, 0);
-       evbuffer_setcb(buf, NULL, NULL);
+       tt_int_op(evbuffer_setcb(buf, NULL, NULL), ==, 0);
        evbuffer_add_printf(buf, "This will not.");
        tt_str_op((const char *) evbuffer_pullup(buf, -1), ==, "This will not.");
        evbuffer_validate(buf);
@@ -1580,6 +2017,14 @@ test_evbuffer_callbacks(void *ptr)
                  "0->15; 15->11; 11->0; ");
 #endif
 
+       /* the next call to readline should fail */
+#ifndef EVENT__DISABLE_MM_REPLACEMENT
+       event_set_mem_functions(failing_malloc, realloc, free);
+       tt_int_op(evbuffer_setcb(buf, self_draining_callback, NULL), ==, -1);
+       evbuffer_validate(buf);
+       event_set_mem_functions(malloc, realloc, free);
+#endif
+
  end:
        if (buf)
                evbuffer_free(buf);
@@ -1782,12 +2227,23 @@ end:
                evbuffer_free(buf2);
 }
 
+static void
+check_prepend(struct evbuffer *buffer,
+    const struct evbuffer_cb_info *cbinfo,
+    void *arg)
+{
+       tt_int_op(cbinfo->orig_size, ==, 3);
+       tt_int_op(cbinfo->n_added, ==, 8096);
+       tt_int_op(cbinfo->n_deleted, ==, 0);
+end:
+       ;
+}
 /* Some cases that we didn't get in test_evbuffer() above, for more coverage. */
 static void
 test_evbuffer_prepend(void *ptr)
 {
        struct evbuffer *buf1 = NULL, *buf2 = NULL;
-       char tmp[128];
+       char tmp[128], *buffer = malloc(8096);
        int n;
 
        buf1 = evbuffer_new();
@@ -1835,7 +2291,23 @@ test_evbuffer_prepend(void *ptr)
        tmp[n]='\0';
        tt_str_op(tmp,==,"Here is string 1000. Here is string 999. ");
 
+       /* Case 5: evbuffer_prepend() will need a new buffer, with callbacks */
+       memset(buffer, 'A', 8096);
+       evbuffer_free(buf2);
+       buf2 = evbuffer_new();
+       tt_assert(buf2);
+       evbuffer_prepend(buf2, "foo", 3);
+       evbuffer_add_cb(buf2, check_prepend, NULL);
+       evbuffer_prepend(buf2, buffer, 8096);
+       evbuffer_remove_cb(buf2, check_prepend, NULL);
+       evbuffer_validate(buf2);
+       tt_nstr_op(8096,(char *)evbuffer_pullup(buf2, 8096),==,buffer);
+       evbuffer_drain(buf2, 8096);
+       tt_nstr_op(3,(char *)evbuffer_pullup(buf2, 3),==,"foo");
+       evbuffer_drain(buf2, 3);
+
 end:
+       free(buffer);
        if (buf1)
                evbuffer_free(buf1);
        if (buf2)
@@ -1843,6 +2315,58 @@ end:
 
 }
 
+static void
+test_evbuffer_empty_reference_prepend(void *ptr)
+{
+       struct evbuffer *buf = NULL;
+
+       buf = evbuffer_new();
+       tt_assert(buf);
+
+       /** empty chain could leave invalid last_with_datap */
+       evbuffer_add_reference(buf, "", 0, NULL, NULL);
+       evbuffer_validate(buf);
+       evbuffer_prepend(buf, "foo", 3);
+
+       evbuffer_validate(buf);
+       tt_assert(!strncmp((char *)evbuffer_pullup(buf, -1), "foo", 3));
+       evbuffer_validate(buf);
+
+end:
+       if (buf)
+               evbuffer_free(buf);
+}
+static void
+test_evbuffer_empty_reference_prepend_buffer(void *ptr)
+{
+       struct evbuffer *buf1 = NULL, *buf2 = NULL;
+
+       buf1 = evbuffer_new();
+       tt_assert(buf1);
+       buf2 = evbuffer_new();
+       tt_assert(buf2);
+
+       /** empty chain could leave invalid last_with_datap */
+       evbuffer_add_reference(buf1, "", 0, NULL, NULL);
+       evbuffer_validate(buf1);
+       evbuffer_add(buf2, "foo", 3);
+       evbuffer_validate(buf2);
+       evbuffer_prepend_buffer(buf2, buf1);
+       evbuffer_validate(buf2);
+
+       tt_assert(!strncmp((char *)evbuffer_pullup(buf2, -1), "foo", 3));
+       evbuffer_validate(buf2);
+
+       tt_assert(evbuffer_pullup(buf1, -1) == NULL);
+       evbuffer_validate(buf2);
+
+end:
+       if (buf1)
+               evbuffer_free(buf1);
+       if (buf2)
+               evbuffer_free(buf2);
+}
+
 static void
 test_evbuffer_peek_first_gt(void *info)
 {
@@ -2000,28 +2524,37 @@ end:
 static void
 test_evbuffer_freeze(void *ptr)
 {
-       struct evbuffer *buf = NULL, *tmp_buf=NULL;
+       struct basic_test_data *testdata = ptr;
+       evutil_socket_t *pair = testdata->pair;
+       struct evbuffer *buf = NULL, *buf_two = NULL, *tmp_buf = NULL;
        const char string[] = /* Year's End, Richard Wilbur */
            "I've known the wind by water banks to shake\n"
            "The late leaves down, which frozen where they fell\n"
            "And held in ice as dancers in a spell\n"
            "Fluttered all winter long into a lake...";
-       const int start = !strcmp(ptr, "start");
+       const int start = !strcmp(testdata->setup_data, "start");
+       const char tmpfilecontent[] = "file_freeze_test_file";
        char *cp;
        char charbuf[128];
+       char *tmpfilename = NULL;
+       int fd = -1;
        int r;
-       size_t orig_length;
+       size_t orig_length, len;
        struct evbuffer_iovec v[1];
 
        if (!start)
-               tt_str_op(ptr, ==, "end");
+               tt_str_op(testdata->setup_data, ==, "end");
 
        buf = evbuffer_new();
+       buf_two = evbuffer_new();
        tmp_buf = evbuffer_new();
        tt_assert(tmp_buf);
 
        evbuffer_add(buf, string, strlen(string));
+       evbuffer_add(buf_two, "abc", 3);
+       evbuffer_add(tmp_buf, "xyz", 3);
        evbuffer_freeze(buf, start); /* Freeze the start or the end.*/
+       evbuffer_freeze(buf_two, start);
 
 #define FREEZE_EQ(a, startcase, endcase)               \
        do {                                            \
@@ -2050,7 +2583,22 @@ test_evbuffer_freeze(void *ptr)
        FREEZE_EQ(r, 0, -1);
        r = evbuffer_add_printf(buf, "Hello %s", "world");
        FREEZE_EQ(r, 11, -1);
-       /* TODO: test add_buffer, add_file, read */
+
+       r = evbuffer_add_buffer(buf, tmp_buf);
+       FREEZE_EQ(r, 0, -1);
+       len = strlen(tmpfilecontent);
+       fd = regress_make_tmpfile(tmpfilecontent, len, &tmpfilename);
+       r = evbuffer_add_file(buf, fd, 0, len);
+       FREEZE_EQ(r, 0, -1);
+
+       if (start)
+               evbuffer_add(tmp_buf, "xyz", 3);
+
+       tt_assert(evbuffer_get_length(tmp_buf));
+       len = evbuffer_get_length(tmp_buf);
+       evbuffer_write(tmp_buf, pair[0]);
+       r = evbuffer_read(buf, pair[1], -1);
+       FREEZE_EQ(r, len, -1);
 
        if (!start)
                tt_int_op(orig_length, ==, evbuffer_get_length(buf));
@@ -2068,7 +2616,24 @@ test_evbuffer_freeze(void *ptr)
        FREEZE_EQ(cp==NULL, 1, 0);
        if (cp)
                free(cp);
-       /* TODO: Test remove_buffer, add_buffer, write, prepend_buffer */
+
+       evbuffer_add(tmp_buf, "xyz", 3);
+       tt_assert(evbuffer_get_length(tmp_buf));
+       r = evbuffer_remove_buffer(buf, tmp_buf, 3);
+       FREEZE_EQ(r, -1, 3);
+       r = evbuffer_drain(buf, 3);
+       FREEZE_EQ(r, -1, 0);
+       r = evbuffer_prepend_buffer(buf, tmp_buf);
+       FREEZE_EQ(r, -1, 0);
+
+       len = evbuffer_get_length(buf);
+       r = evbuffer_write(buf, pair[0]);
+       evbuffer_read(tmp_buf, pair[1], -1);
+       FREEZE_EQ(r, -1, len);
+       len = evbuffer_get_length(buf_two);
+       r = evbuffer_write_atmost(buf_two, pair[0], -1);
+       evbuffer_read(tmp_buf, pair[1], -1);
+       FREEZE_EQ(r, -1, len);
 
        if (start)
                tt_int_op(orig_length, ==, evbuffer_get_length(buf));
@@ -2077,8 +2642,16 @@ end:
        if (buf)
                evbuffer_free(buf);
 
+       if (buf_two)
+               evbuffer_free(buf_two);
+
        if (tmp_buf)
                evbuffer_free(tmp_buf);
+
+       if (tmpfilename) {
+               unlink(tmpfilename);
+               free(tmpfilename);
+       }
 }
 
 static void
@@ -2228,12 +2801,25 @@ static const struct testcase_setup_t nil_setup = {
 struct testcase_t evbuffer_testcases[] = {
        { "evbuffer", test_evbuffer, 0, NULL, NULL },
        { "remove_buffer_with_empty", test_evbuffer_remove_buffer_with_empty, 0, NULL, NULL },
+       { "remove_buffer_with_empty2", test_evbuffer_remove_buffer_with_empty2, 0, NULL, NULL },
+       { "remove_buffer_with_empty3", test_evbuffer_remove_buffer_with_empty3, 0, NULL, NULL },
+       { "remove_buffer_with_empty_front", test_evbuffer_remove_buffer_with_empty_front, 0, NULL, NULL },
+       { "remove_buffer_adjust_last_with_datap_with_empty",
+         test_evbuffer_remove_buffer_adjust_last_with_datap_with_empty, 0, NULL, NULL },
+       { "add_buffer_with_empty", test_evbuffer_add_buffer_with_empty, 0, NULL, NULL },
+       { "add_buffer_with_empty2", test_evbuffer_add_buffer_with_empty2, 0, NULL, NULL },
        { "reserve2", test_evbuffer_reserve2, 0, NULL, NULL },
        { "reserve_many", test_evbuffer_reserve_many, 0, NULL, NULL },
        { "reserve_many2", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"add" },
        { "reserve_many3", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"fill" },
+       { "reserve_with_empty", test_evbuffer_reserve_with_empty, 0, NULL, NULL },
+       { "reserve_invalid_last_with_datap", test_evbuffer_reserve_invalid_last_with_datap, TT_FORK, NULL, NULL },
        { "expand", test_evbuffer_expand, 0, NULL, NULL },
+       { "expand_overflow", test_evbuffer_expand_overflow, 0, NULL, NULL },
+       { "add1", test_evbuffer_add1, 0, NULL, NULL },
+       { "add2", test_evbuffer_add2, 0, NULL, NULL },
        { "reference", test_evbuffer_reference, 0, NULL, NULL },
+       { "reference2", test_evbuffer_reference2, 0, NULL, NULL },
        { "iterative", test_evbuffer_iterative, 0, NULL, NULL },
        { "readln", test_evbuffer_readln, TT_NO_LOGS, &basic_setup, NULL },
        { "search_eol", test_evbuffer_search_eol, 0, NULL, NULL },
@@ -2245,13 +2831,16 @@ struct testcase_t evbuffer_testcases[] = {
        { "multicast", test_evbuffer_multicast, 0, NULL, NULL },
        { "multicast_drain", test_evbuffer_multicast_drain, 0, NULL, NULL },
        { "prepend", test_evbuffer_prepend, TT_FORK, NULL, NULL },
+       { "empty_reference_prepend", test_evbuffer_empty_reference_prepend, TT_FORK, NULL, NULL },
+       { "empty_reference_prepend_buffer", test_evbuffer_empty_reference_prepend_buffer, TT_FORK, NULL, NULL },
        { "peek", test_evbuffer_peek, 0, NULL, NULL },
        { "peek_first_gt", test_evbuffer_peek_first_gt, 0, NULL, NULL },
-       { "freeze_start", test_evbuffer_freeze, 0, &nil_setup, (void*)"start" },
-       { "freeze_end", test_evbuffer_freeze, 0, &nil_setup, (void*)"end" },
+       { "freeze_start", test_evbuffer_freeze, TT_NEED_SOCKETPAIR, &basic_setup, (void*)"start" },
+       { "freeze_end", test_evbuffer_freeze, TT_NEED_SOCKETPAIR, &basic_setup, (void*)"end" },
        { "add_iovec", test_evbuffer_add_iovec, 0, NULL, NULL},
        { "copyout", test_evbuffer_copyout, 0, NULL, NULL},
        { "file_segment_add_cleanup_cb", test_evbuffer_file_segment_add_cleanup_cb, 0, NULL, NULL },
+       { "pullup_with_empty", test_evbuffer_pullup_with_empty, 0, NULL, NULL },
 
 #define ADDFILE_TEST(name, parameters)                                 \
        { name, test_evbuffer_add_file, TT_FORK|TT_NEED_BASE,           \
index a1998ba62cd1de161c2598584651b52b3caa4fd4..c276a0e5d1c32ea5affea576fb3785e913d9ab67 100644 (file)
 /* The old tests here need assertions to work. */
 #undef NDEBUG
 
+/**
+ * - clang supports __has_feature
+ * - gcc supports __SANITIZE_ADDRESS__
+ *
+ * Let's set __SANITIZE_ADDRESS__ if __has_feature(address_sanitizer)
+ */
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+#if !defined(__SANITIZE_ADDRESS__) && __has_feature(address_sanitizer)
+#define __SANITIZE_ADDRESS__
+#endif
+
 #ifdef _WIN32
 #include <winsock2.h>
 #include <windows.h>
@@ -123,11 +136,12 @@ errorcb(struct bufferevent *bev, short what, void *arg)
 }
 
 static void
-test_bufferevent_impl(int use_pair)
+test_bufferevent_impl(int use_pair, int flush)
 {
        struct bufferevent *bev1 = NULL, *bev2 = NULL;
        char buffer[8333];
        int i;
+       int expected = 2;
 
        if (use_pair) {
                struct bufferevent *pair[2];
@@ -136,14 +150,14 @@ test_bufferevent_impl(int use_pair)
                bev2 = pair[1];
                bufferevent_setcb(bev1, readcb, writecb, errorcb, bev1);
                bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL);
-               tt_int_op(bufferevent_getfd(bev1), ==, -1);
+               tt_fd_op(bufferevent_getfd(bev1), ==, EVUTIL_INVALID_SOCKET);
                tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL);
                tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, bev2);
                tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, bev1);
        } else {
                bev1 = bufferevent_new(pair[0], readcb, writecb, errorcb, NULL);
                bev2 = bufferevent_new(pair[1], readcb, writecb, errorcb, NULL);
-               tt_int_op(bufferevent_getfd(bev1), ==, pair[0]);
+               tt_fd_op(bufferevent_getfd(bev1), ==, pair[0]);
                tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL);
                tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL);
                tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, NULL);
@@ -171,6 +185,9 @@ test_bufferevent_impl(int use_pair)
                buffer[i] = i;
 
        bufferevent_write(bev1, buffer, sizeof(buffer));
+       if (flush >= 0) {
+               tt_int_op(bufferevent_flush(bev1, EV_WRITE, flush), >=, 0);
+       }
 
        event_dispatch();
 
@@ -178,25 +195,28 @@ test_bufferevent_impl(int use_pair)
        tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL);
        bufferevent_free(bev1);
 
-       if (test_ok != 2)
+       /** Only pair call errorcb for BEV_FINISHED */
+       if (use_pair && flush == BEV_FINISHED) {
+               expected = -1;
+       }
+       if (test_ok != expected)
                test_ok = 0;
 end:
        ;
 }
 
-static void
-test_bufferevent(void)
-{
-       test_bufferevent_impl(0);
-}
+static void test_bufferevent(void) { test_bufferevent_impl(0, -1); }
+static void test_bufferevent_pair(void) { test_bufferevent_impl(1, -1); }
 
-static void
-test_bufferevent_pair(void)
-{
-       test_bufferevent_impl(1);
-}
+static void test_bufferevent_flush_normal(void) { test_bufferevent_impl(0, BEV_NORMAL); }
+static void test_bufferevent_flush_flush(void) { test_bufferevent_impl(0, BEV_FLUSH); }
+static void test_bufferevent_flush_finished(void) { test_bufferevent_impl(0, BEV_FINISHED); }
+
+static void test_bufferevent_pair_flush_normal(void) { test_bufferevent_impl(1, BEV_NORMAL); }
+static void test_bufferevent_pair_flush_flush(void) { test_bufferevent_impl(1, BEV_FLUSH); }
+static void test_bufferevent_pair_flush_finished(void) { test_bufferevent_impl(1, BEV_FINISHED); }
 
-#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
+#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED) && !defined(__SANITIZE_ADDRESS__)
 /**
  * Trace lock/unlock/alloc/free for locks.
  * (More heavier then evthread_debug*)
@@ -233,10 +253,11 @@ static lock_wrapper *lu_find(void *lock_)
 
 static void *trace_lock_alloc(unsigned locktype)
 {
+       void *lock;
        ++lu_base.nr_locks;
        lu_base.locks = realloc(lu_base.locks,
                sizeof(lock_wrapper) * lu_base.nr_locks);
-       void *lock = lu_base.cbs.alloc(locktype);
+       lock = lu_base.cbs.alloc(locktype);
        lu_base.locks[lu_base.nr_locks - 1] = (lock_wrapper){ lock, ALLOC, 0 };
        return lock;
 }
@@ -244,7 +265,6 @@ static void trace_lock_free(void *lock_, unsigned locktype)
 {
        lock_wrapper *lock = lu_find(lock_);
        if (!lock || lock->status == FREE || lock->locked) {
-               __asm__("int3");
                TT_FAIL(("lock: free error"));
        } else {
                lock->status = FREE;
@@ -273,10 +293,13 @@ static int trace_lock_unlock(unsigned mode, void *lock_)
                return lu_base.cbs.unlock(mode, lock_);
        }
 }
-static void lock_unlock_free_thread_cbs()
+static void lock_unlock_free_thread_cbs(void)
 {
        event_base_free(NULL);
 
+       if (libevent_tests_running_in_debug_mode)
+               libevent_global_shutdown();
+
        /** drop immutable flag */
        evthread_set_lock_callbacks(NULL);
        /** avoid calling of event_global_setup_locks_() for new cbs */
@@ -310,6 +333,9 @@ static int use_lock_unlock_profiler(void)
 }
 static void free_lock_unlock_profiler(struct basic_test_data *data)
 {
+       /** fix "held_by" for kqueue */
+       evthread_set_lock_callbacks(NULL);
+
        lock_unlock_free_thread_cbs();
        free(lu_base.locks);
        data->base = NULL;
@@ -474,11 +500,11 @@ bufferevent_input_filter(struct evbuffer *src, struct evbuffer *dst,
 
        buffer = evbuffer_pullup(src, evbuffer_get_length(src));
        for (i = 0; i < evbuffer_get_length(src); i += 2) {
+               if (buffer[i] == '-')
+                       continue;
+
                assert(buffer[i] == 'x');
                evbuffer_add(dst, buffer + i + 1, 1);
-
-               if (i + 2 > evbuffer_get_length(src))
-                       break;
        }
 
        evbuffer_drain(src, i);
@@ -493,19 +519,35 @@ bufferevent_output_filter(struct evbuffer *src, struct evbuffer *dst,
 {
        const unsigned char *buffer;
        unsigned i;
+       struct bufferevent **bevp = ctx;
 
-       buffer = evbuffer_pullup(src, evbuffer_get_length(src));
-       for (i = 0; i < evbuffer_get_length(src); ++i) {
-               evbuffer_add(dst, "x", 1);
-               evbuffer_add(dst, buffer + i, 1);
+       ++test_ok;
+
+       if (test_ok == 1) {
+               buffer = evbuffer_pullup(src, evbuffer_get_length(src));
+               for (i = 0; i < evbuffer_get_length(src); ++i) {
+                       evbuffer_add(dst, "x", 1);
+                       evbuffer_add(dst, buffer + i, 1);
+               }
+               evbuffer_drain(src, evbuffer_get_length(src));
+       } else {
+               return BEV_ERROR;
+       }
+
+       if (bevp && test_ok == 1) {
+               int prev = ++test_ok;
+               bufferevent_write(*bevp, "-", 1);
+               /* check that during this bufferevent_write()
+                * bufferevent_output_filter() will not be called again */
+               assert(test_ok == prev);
+               --test_ok;
        }
 
-       evbuffer_drain(src, evbuffer_get_length(src));
        return (BEV_OK);
 }
 
 static void
-test_bufferevent_filters_impl(int use_pair)
+test_bufferevent_filters_impl(int use_pair, int disable)
 {
        struct bufferevent *bev1 = NULL, *bev2 = NULL;
        struct bufferevent *bev1_base = NULL, *bev2_base = NULL;
@@ -530,7 +572,8 @@ test_bufferevent_filters_impl(int use_pair)
                buffer[i] = i;
 
        bev1 = bufferevent_filter_new(bev1, NULL, bufferevent_output_filter,
-                                     BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
+                                     BEV_OPT_CLOSE_ON_FREE, NULL,
+                                         disable ? &bev1 : NULL);
 
        bev2 = bufferevent_filter_new(bev2, bufferevent_input_filter,
                                      NULL, BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
@@ -539,8 +582,8 @@ test_bufferevent_filters_impl(int use_pair)
 
        tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev1_base);
        tt_ptr_op(bufferevent_get_underlying(bev2), ==, bev2_base);
-       tt_int_op(bufferevent_getfd(bev1), ==, -1);
-       tt_int_op(bufferevent_getfd(bev2), ==, -1);
+       tt_fd_op(bufferevent_getfd(bev1), ==, bufferevent_getfd(bev1_base));
+       tt_fd_op(bufferevent_getfd(bev2), ==, bufferevent_getfd(bev2_base));
 
        bufferevent_disable(bev1, EV_READ);
        bufferevent_enable(bev2, EV_READ);
@@ -549,7 +592,7 @@ test_bufferevent_filters_impl(int use_pair)
 
        event_dispatch();
 
-       if (test_ok != 2)
+       if (test_ok != 3 + !!disable)
                test_ok = 0;
 
 end:
@@ -560,17 +603,14 @@ end:
 
 }
 
-static void
-test_bufferevent_filters(void)
-{
-       test_bufferevent_filters_impl(0);
-}
-
-static void
-test_bufferevent_pair_filters(void)
-{
-       test_bufferevent_filters_impl(1);
-}
+static void test_bufferevent_filters(void)
+{ test_bufferevent_filters_impl(0, 0); }
+static void test_bufferevent_pair_filters(void)
+{ test_bufferevent_filters_impl(1, 0); }
+static void test_bufferevent_filters_disable(void)
+{ test_bufferevent_filters_impl(0, 1); }
+static void test_bufferevent_pair_filters_disable(void)
+{ test_bufferevent_filters_impl(1, 1); }
 
 
 static void
@@ -593,6 +633,7 @@ 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;
+static int n_events_invoked = 0;
 
 #define TEST_STR "Now is the time for all good events to signal for " \
        "the good of their protocol"
@@ -612,6 +653,31 @@ end:
        ;
 }
 
+static evutil_socket_t
+fake_listener_create(struct sockaddr_in *localhost)
+{
+       struct sockaddr *sa = (struct sockaddr *)localhost;
+       evutil_socket_t fd = -1;
+       ev_socklen_t slen = sizeof(*localhost);
+
+       memset(localhost, 0, sizeof(*localhost));
+       localhost->sin_port = 0; /* have the kernel pick a port */
+       localhost->sin_addr.s_addr = htonl(0x7f000001L);
+       localhost->sin_family = AF_INET;
+
+       /* bind, but don't listen or accept. should trigger
+          "Connection refused" reliably on most platforms. */
+       fd = socket(localhost->sin_family, SOCK_STREAM, 0);
+       tt_assert(fd >= 0);
+       tt_assert(bind(fd, sa, slen) == 0);
+       tt_assert(getsockname(fd, sa, &slen) == 0);
+
+       return fd;
+
+end:
+       return -1;
+}
+
 static void
 reader_eventcb(struct bufferevent *bev, short what, void *ctx)
 {
@@ -641,6 +707,14 @@ end:
        ;
 }
 
+static void
+reader_eventcb_simple(struct bufferevent *bev, short what, void *ctx)
+{
+       TT_BLATHER(("Read eventcb simple invoked on %d.",
+               (int)bufferevent_getfd(bev)));
+       n_events_invoked++;
+}
+
 static void
 reader_readcb(struct bufferevent *bev, void *ctx)
 {
@@ -726,6 +800,70 @@ end:
                bufferevent_free(bev2);
 }
 
+static void
+close_socket_cb(evutil_socket_t fd, short what, void *arg)
+{
+       evutil_socket_t *fdp = arg;
+       if (*fdp >= 0) {
+               evutil_closesocket(*fdp);
+               *fdp = -1;
+       }
+}
+
+static void
+test_bufferevent_connect_fail_eventcb(void *arg)
+{
+       struct basic_test_data *data = arg;
+       int flags = BEV_OPT_CLOSE_ON_FREE | (long)data->setup_data;
+       struct event close_listener_event;
+       struct bufferevent *bev = NULL;
+       struct evconnlistener *lev = NULL;
+       struct sockaddr_in localhost;
+       struct timeval close_timeout = { 0, 300000 };
+       ev_socklen_t slen = sizeof(localhost);
+       evutil_socket_t fake_listener = -1;
+       int r;
+
+       fake_listener = fake_listener_create(&localhost);
+
+       tt_int_op(n_events_invoked, ==, 0);
+
+       bev = bufferevent_socket_new(data->base, -1, flags);
+       tt_assert(bev);
+       bufferevent_setcb(bev, reader_readcb, reader_readcb,
+               reader_eventcb_simple, data->base);
+       bufferevent_enable(bev, EV_READ|EV_WRITE);
+       tt_int_op(n_events_invoked, ==, 0);
+       tt_int_op(n_reads_invoked, ==, 0);
+
+       /** @see also test_bufferevent_connect_fail() */
+       r = bufferevent_socket_connect(bev, (struct sockaddr *)&localhost, slen);
+       /* XXXX we'd like to test the '0' case everywhere, but FreeBSD tells
+        * detects the error immediately, which is not really wrong of it. */
+       tt_want(r == 0 || r == -1);
+
+       tt_int_op(n_events_invoked, ==, 0);
+       tt_int_op(n_reads_invoked, ==, 0);
+
+       /* Close the listener socket after a delay. This should trigger
+          "connection refused" on some other platforms, including OSX. */
+       evtimer_assign(&close_listener_event, data->base, close_socket_cb,
+           &fake_listener);
+       event_add(&close_listener_event, &close_timeout);
+
+       event_base_dispatch(data->base);
+       tt_int_op(n_events_invoked, ==, 1);
+       tt_int_op(n_reads_invoked, ==, 0);
+
+end:
+       if (lev)
+               evconnlistener_free(lev);
+       if (bev)
+               bufferevent_free(bev);
+       if (fake_listener >= 0)
+               evutil_closesocket(fake_listener);
+}
+
 static void
 want_fail_eventcb(struct bufferevent *bev, short what, void *ctx)
 {
@@ -746,58 +884,37 @@ want_fail_eventcb(struct bufferevent *bev, short what, void *ctx)
        event_base_loopexit(base, NULL);
 }
 
-static void
-close_socket_cb(evutil_socket_t fd, short what, void *arg)
-{
-       evutil_socket_t *fdp = arg;
-       if (*fdp >= 0) {
-               evutil_closesocket(*fdp);
-               *fdp = -1;
-       }
-}
-
 static void
 test_bufferevent_connect_fail(void *arg)
 {
        struct basic_test_data *data = (struct basic_test_data *)arg;
        struct bufferevent *bev=NULL;
-       struct sockaddr_in localhost;
-       struct sockaddr *sa = (struct sockaddr*)&localhost;
-       evutil_socket_t fake_listener = -1;
-       ev_socklen_t slen = sizeof(localhost);
        struct event close_listener_event;
        int close_listener_event_added = 0;
-       struct timeval one_second = { 1, 0 };
+       struct timeval close_timeout = { 0, 300000 };
+       struct sockaddr_in localhost;
+       ev_socklen_t slen = sizeof(localhost);
+       evutil_socket_t fake_listener = -1;
        int r;
 
        test_ok = 0;
 
-       memset(&localhost, 0, sizeof(localhost));
-       localhost.sin_port = 0; /* have the kernel pick a port */
-       localhost.sin_addr.s_addr = htonl(0x7f000001L);
-       localhost.sin_family = AF_INET;
-
-       /* bind, but don't listen or accept. should trigger
-          "Connection refused" reliably on most platforms. */
-       fake_listener = socket(localhost.sin_family, SOCK_STREAM, 0);
-       tt_assert(fake_listener >= 0);
-       tt_assert(bind(fake_listener, sa, slen) == 0);
-       tt_assert(getsockname(fake_listener, sa, &slen) == 0);
+       fake_listener = fake_listener_create(&localhost);
        bev = bufferevent_socket_new(data->base, -1,
                BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
        tt_assert(bev);
        bufferevent_setcb(bev, NULL, NULL, want_fail_eventcb, data->base);
 
-       r = bufferevent_socket_connect(bev, sa, slen);
+       r = bufferevent_socket_connect(bev, (struct sockaddr *)&localhost, slen);
        /* XXXX we'd like to test the '0' case everywhere, but FreeBSD tells
         * detects the error immediately, which is not really wrong of it. */
        tt_want(r == 0 || r == -1);
 
-       /* Close the listener socket after a second. This should trigger
+       /* Close the listener socket after a delay. This should trigger
           "connection refused" on some other platforms, including OSX. */
        evtimer_assign(&close_listener_event, data->base, close_socket_cb,
            &fake_listener);
-       event_add(&close_listener_event, &one_second);
+       event_add(&close_listener_event, &close_timeout);
        close_listener_event_added = 1;
 
        event_base_dispatch(data->base);
@@ -819,18 +936,24 @@ struct timeout_cb_result {
        struct timeval read_timeout_at;
        struct timeval write_timeout_at;
        struct timeval last_wrote_at;
+       struct timeval last_read_at;
        int n_read_timeouts;
        int n_write_timeouts;
        int total_calls;
 };
 
+static void
+bev_timeout_read_cb(struct bufferevent *bev, void *arg)
+{
+       struct timeout_cb_result *res = arg;
+       evutil_gettimeofday(&res->last_read_at, NULL);
+}
 static void
 bev_timeout_write_cb(struct bufferevent *bev, void *arg)
 {
        struct timeout_cb_result *res = arg;
        evutil_gettimeofday(&res->last_wrote_at, NULL);
 }
-
 static void
 bev_timeout_event_cb(struct bufferevent *bev, short what, void *arg)
 {
@@ -858,7 +981,6 @@ test_bufferevent_timeouts(void *arg)
        int use_pair = 0, use_filter = 0;
        struct timeval tv_w, tv_r, started_at;
        struct timeout_cb_result res1, res2;
-       char buf[1024];
 
        memset(&res1, 0, sizeof(res1));
        memset(&res2, 0, sizeof(res2));
@@ -877,7 +999,6 @@ test_bufferevent_timeouts(void *arg)
                bev1 = bufferevent_socket_new(data->base, data->pair[0], 0);
                bev2 = bufferevent_socket_new(data->base, data->pair[1], 0);
        }
-
        tt_assert(bev1);
        tt_assert(bev2);
 
@@ -901,30 +1022,14 @@ test_bufferevent_timeouts(void *arg)
        tv_w.tv_sec = tv_r.tv_sec = 0;
        tv_w.tv_usec = 100*1000;
        tv_r.tv_usec = 150*1000;
-       bufferevent_setcb(bev1, NULL, bev_timeout_write_cb,
+       bufferevent_setcb(bev1, bev_timeout_read_cb, bev_timeout_write_cb,
            bev_timeout_event_cb, &res1);
-       bufferevent_setwatermark(bev1, EV_WRITE, 1024*1024+10, 0);
        bufferevent_set_timeouts(bev1, &tv_r, &tv_w);
-       if (use_pair) {
-               /* For a pair, the fact that the other side isn't reading
-                * makes the writer stall */
-               bufferevent_write(bev1, "ABCDEFG", 7);
-       } else {
-               /* For a real socket, the kernel's TCP buffers can eat a
-                * fair number of bytes; make sure that at some point we
-                * have some bytes that will stall. */
-               struct evbuffer *output = bufferevent_get_output(bev1);
-               int i;
-               memset(buf, 0xbb, sizeof(buf));
-               for (i=0;i<1024;++i) {
-                       evbuffer_add_reference(output, buf, sizeof(buf),
-                           NULL, NULL);
-               }
-       }
+       bufferevent_write(bev1, "ABCDEFG", 7);
        bufferevent_enable(bev1, EV_READ|EV_WRITE);
 
        /* bev2 has nothing to say, and isn't listening. */
-       bufferevent_setcb(bev2, NULL,  bev_timeout_write_cb,
+       bufferevent_setcb(bev2, bev_timeout_read_cb, bev_timeout_write_cb,
            bev_timeout_event_cb, &res2);
        tv_w.tv_sec = tv_r.tv_sec = 0;
        tv_w.tv_usec = 200*1000;
@@ -941,15 +1046,26 @@ test_bufferevent_timeouts(void *arg)
        /* XXXX Test that actually reading or writing a little resets the
         * timeouts. */
 
-       /* Each buf1 timeout happens, and happens only once. */
-       tt_want(res1.n_read_timeouts);
-       tt_want(res1.n_write_timeouts);
+       tt_want(res1.total_calls == 2);
        tt_want(res1.n_read_timeouts == 1);
        tt_want(res1.n_write_timeouts == 1);
+       tt_want(res2.total_calls == !(use_pair && !use_filter));
+       tt_want(res2.n_write_timeouts == !(use_pair && !use_filter));
+       tt_want(!res2.n_read_timeouts);
 
        test_timeval_diff_eq(&started_at, &res1.read_timeout_at, 150);
        test_timeval_diff_eq(&started_at, &res1.write_timeout_at, 100);
 
+#define tt_assert_timeval_empty(tv) do {  \
+       tt_int_op((tv).tv_sec, ==, 0);   \
+       tt_int_op((tv).tv_usec, ==, 0);  \
+} while(0)
+       tt_assert_timeval_empty(res1.last_read_at);
+       tt_assert_timeval_empty(res2.last_read_at);
+       tt_assert_timeval_empty(res2.last_wrote_at);
+       tt_assert_timeval_empty(res2.last_wrote_at);
+#undef tt_assert_timeval_empty
+
 end:
        if (bev1)
                bufferevent_free(bev1);
@@ -1083,19 +1199,182 @@ end:
                bufferevent_free(bev);
 }
 
+static void
+test_bufferevent_socket_filter_inactive(void *arg)
+{
+       struct basic_test_data *data = arg;
+       struct bufferevent *bev = NULL, *bevf = NULL;
+
+       bev = bufferevent_socket_new(data->base, -1, 0);
+       tt_assert(bev);
+       bevf = bufferevent_filter_new(bev, NULL, NULL, 0, NULL, NULL);
+       tt_assert(bevf);
+
+end:
+       if (bevf)
+               bufferevent_free(bevf);
+       if (bev)
+               bufferevent_free(bev);
+}
+
+static void
+pair_flush_eventcb(struct bufferevent *bev, short what, void *ctx)
+{
+       int *callback_what = ctx;
+       *callback_what = what;
+}
+
+static void
+test_bufferevent_pair_flush(void *arg)
+{
+       struct basic_test_data *data = arg;
+       struct bufferevent *pair[2];
+       struct bufferevent *bev1 = NULL;
+       struct bufferevent *bev2 = NULL;
+       int callback_what = 0;
+
+       tt_assert(0 == bufferevent_pair_new(data->base, 0, pair));
+       bev1 = pair[0];
+       bev2 = pair[1];
+       tt_assert(0 == bufferevent_enable(bev1, EV_WRITE));
+       tt_assert(0 == bufferevent_enable(bev2, EV_READ));
+
+       bufferevent_setcb(bev2, NULL, NULL, pair_flush_eventcb, &callback_what);
+
+       bufferevent_flush(bev1, EV_WRITE, BEV_FINISHED);
+
+       event_base_loop(data->base, EVLOOP_ONCE);
+
+       tt_assert(callback_what == (BEV_EVENT_READING | BEV_EVENT_EOF));
+
+end:
+       if (bev1)
+               bufferevent_free(bev1);
+       if (bev2)
+               bufferevent_free(bev2);
+}
+
+struct bufferevent_filter_data_stuck {
+       size_t header_size;
+       size_t total_read;
+};
+
+static void
+bufferevent_filter_data_stuck_readcb(struct bufferevent *bev, void *arg)
+{
+       struct bufferevent_filter_data_stuck *filter_data = arg;
+       struct evbuffer *input = bufferevent_get_input(bev);
+       size_t read_size = evbuffer_get_length(input);
+       evbuffer_drain(input, read_size);
+       filter_data->total_read += read_size;
+}
+
+/**
+ * This filter prepends header once before forwarding data.
+ */
+static enum bufferevent_filter_result
+bufferevent_filter_data_stuck_inputcb(
+    struct evbuffer *src, struct evbuffer *dst, ev_ssize_t dst_limit,
+    enum bufferevent_flush_mode mode, void *ctx)
+{
+       struct bufferevent_filter_data_stuck *filter_data = ctx;
+       static int header_inserted = 0;
+       size_t payload_size;
+       size_t header_size = 0;
+
+       if (!header_inserted) {
+               char *header = calloc(filter_data->header_size, 1);
+               evbuffer_add(dst, header, filter_data->header_size);
+               free(header);
+               header_size = filter_data->header_size;
+               header_inserted = 1;
+       }
+
+       payload_size = evbuffer_get_length(src);
+       if (payload_size > dst_limit - header_size) {
+               payload_size = dst_limit - header_size;
+       }
+
+       tt_int_op(payload_size, ==, evbuffer_remove_buffer(src, dst, payload_size));
+
+end:
+       return BEV_OK;
+}
+
+static void
+test_bufferevent_filter_data_stuck(void *arg)
+{
+       const size_t read_high_wm = 4096;
+       struct bufferevent_filter_data_stuck filter_data;
+       struct basic_test_data *data = arg;
+       struct bufferevent *pair[2];
+       struct bufferevent *filter = NULL;
+
+       int options = BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS;
+
+       char payload[4096];
+       int payload_size = sizeof(payload);
+
+       memset(&filter_data, 0, sizeof(filter_data));
+       filter_data.header_size = 20;
+
+       tt_assert(bufferevent_pair_new(data->base, options, pair) == 0);
+
+       bufferevent_setwatermark(pair[0], EV_READ, 0, read_high_wm);
+       bufferevent_setwatermark(pair[1], EV_READ, 0, read_high_wm);
+
+       tt_assert(
+               filter =
+                bufferevent_filter_new(pair[1],
+                bufferevent_filter_data_stuck_inputcb,
+                NULL,
+                options,
+                NULL,
+                &filter_data));
+
+       bufferevent_setcb(filter,
+               bufferevent_filter_data_stuck_readcb,
+               NULL,
+               NULL,
+               &filter_data);
+
+       tt_assert(bufferevent_enable(filter, EV_READ|EV_WRITE) == 0);
+
+       bufferevent_setwatermark(filter, EV_READ, 0, read_high_wm);
+
+       tt_assert(bufferevent_write(pair[0], payload, sizeof(payload)) == 0);
+
+       event_base_dispatch(data->base);
+
+       tt_int_op(filter_data.total_read, ==, payload_size + filter_data.header_size);
+end:
+       if (pair[0])
+               bufferevent_free(pair[0]);
+       if (filter)
+               bufferevent_free(filter);
+}
+
 struct testcase_t bufferevent_testcases[] = {
 
        LEGACY(bufferevent, TT_ISOLATED),
        LEGACY(bufferevent_pair, TT_ISOLATED),
-#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
+       LEGACY(bufferevent_flush_normal, TT_ISOLATED),
+       LEGACY(bufferevent_flush_flush, TT_ISOLATED),
+       LEGACY(bufferevent_flush_finished, TT_ISOLATED),
+       LEGACY(bufferevent_pair_flush_normal, TT_ISOLATED),
+       LEGACY(bufferevent_pair_flush_flush, TT_ISOLATED),
+       LEGACY(bufferevent_pair_flush_finished, TT_ISOLATED),
+#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED) && !defined(__SANITIZE_ADDRESS__)
        { "bufferevent_pair_release_lock", test_bufferevent_pair_release_lock,
-         TT_FORK|TT_ISOLATED|TT_NEED_THREADS|TT_NEED_BASE|TT_LEGACY,
+         TT_FORK|TT_ISOLATED|TT_NEED_THREADS|TT_NEED_BASE|TT_LEGACY|TT_NO_LOGS,
          &basic_setup, NULL },
 #endif
        LEGACY(bufferevent_watermarks, TT_ISOLATED),
        LEGACY(bufferevent_pair_watermarks, TT_ISOLATED),
        LEGACY(bufferevent_filters, TT_ISOLATED),
        LEGACY(bufferevent_pair_filters, TT_ISOLATED),
+       LEGACY(bufferevent_filters_disable, TT_ISOLATED),
+       LEGACY(bufferevent_pair_filters_disable, TT_ISOLATED),
        { "bufferevent_connect", test_bufferevent_connect, TT_FORK|TT_NEED_BASE,
          &basic_setup, (void*)"" },
        { "bufferevent_connect_defer", test_bufferevent_connect,
@@ -1111,7 +1390,7 @@ struct testcase_t bufferevent_testcases[] = {
        { "bufferevent_connect_fail", test_bufferevent_connect_fail,
          TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
        { "bufferevent_timeout", test_bufferevent_timeouts,
-         TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR, &basic_setup, (void*)"" },
+         TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"" },
        { "bufferevent_timeout_pair", test_bufferevent_timeouts,
          TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"pair" },
        { "bufferevent_timeout_filter", test_bufferevent_timeouts,
@@ -1134,29 +1413,55 @@ struct testcase_t bufferevent_testcases[] = {
        { "bufferevent_zlib", NULL, TT_SKIP, NULL, NULL },
 #endif
 
+       { "bufferevent_connect_fail_eventcb_defer",
+         test_bufferevent_connect_fail_eventcb,
+         TT_FORK|TT_NEED_BASE, &basic_setup, (void*)BEV_OPT_DEFER_CALLBACKS },
+       { "bufferevent_connect_fail_eventcb",
+         test_bufferevent_connect_fail_eventcb,
+         TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+
+       { "bufferevent_socket_filter_inactive",
+         test_bufferevent_socket_filter_inactive,
+         TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+       { "bufferevent_pair_flush",
+         test_bufferevent_pair_flush,
+         TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+       { "bufferevent_filter_data_stuck",
+         test_bufferevent_filter_data_stuck,
+         TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+
        END_OF_TESTCASES,
 };
 
+#define TT_IOCP (TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP)
+#define TT_IOCP_LEGACY (TT_ISOLATED|TT_ENABLE_IOCP)
 struct testcase_t bufferevent_iocp_testcases[] = {
+       LEGACY(bufferevent, TT_IOCP_LEGACY),
+       LEGACY(bufferevent_flush_normal, TT_ISOLATED),
+       LEGACY(bufferevent_flush_flush, TT_ISOLATED),
+       LEGACY(bufferevent_flush_finished, TT_ISOLATED),
+       LEGACY(bufferevent_watermarks, TT_IOCP_LEGACY),
+       LEGACY(bufferevent_filters, TT_IOCP_LEGACY),
+       LEGACY(bufferevent_filters_disable, TT_IOCP_LEGACY),
 
-       LEGACY(bufferevent, TT_ISOLATED|TT_ENABLE_IOCP),
-       LEGACY(bufferevent_watermarks, TT_ISOLATED|TT_ENABLE_IOCP),
-       LEGACY(bufferevent_filters, TT_ISOLATED|TT_ENABLE_IOCP),
        { "bufferevent_connect", test_bufferevent_connect,
-         TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, (void*)"" },
+         TT_IOCP, &basic_setup, (void*)"" },
        { "bufferevent_connect_defer", test_bufferevent_connect,
-         TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, (void*)"defer" },
+         TT_IOCP, &basic_setup, (void*)"defer" },
        { "bufferevent_connect_lock", test_bufferevent_connect,
-         TT_FORK|TT_NEED_BASE|TT_NEED_THREADS|TT_ENABLE_IOCP, &basic_setup,
-         (void*)"lock" },
+         TT_IOCP, &basic_setup, (void*)"lock" },
        { "bufferevent_connect_lock_defer", test_bufferevent_connect,
-         TT_FORK|TT_NEED_BASE|TT_NEED_THREADS|TT_ENABLE_IOCP, &basic_setup,
-         (void*)"defer lock" },
+         TT_IOCP, &basic_setup, (void*)"defer lock" },
        { "bufferevent_connect_fail", test_bufferevent_connect_fail,
-         TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL },
+         TT_IOCP, &basic_setup, NULL },
        { "bufferevent_connect_nonblocking", test_bufferevent_connect,
-         TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup,
-         (void*)"unset_connectex" },
+         TT_IOCP, &basic_setup, (void*)"unset_connectex" },
+
+       { "bufferevent_connect_fail_eventcb_defer",
+         test_bufferevent_connect_fail_eventcb,
+         TT_IOCP, &basic_setup, (void*)BEV_OPT_DEFER_CALLBACKS },
+       { "bufferevent_connect_fail_eventcb",
+         test_bufferevent_connect_fail_eventcb, TT_IOCP, &basic_setup, NULL },
 
        END_OF_TESTCASES,
 };
index 31811407e046a786ffff7da8248b8843e1532e94..9a8bff4f15269efc3191b9a68332adadd14e4f76 100644 (file)
 #include <string.h>
 #include <errno.h>
 
+#ifdef EVENT__HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
 #include "event2/dns.h"
 #include "event2/dns_compat.h"
 #include "event2/dns_struct.h"
 #include "event2/util.h"
 #include "event2/listener.h"
 #include "event2/bufferevent.h"
+#include <event2/thread.h>
 #include "log-internal.h"
+#include "evthread-internal.h"
 #include "regress.h"
 #include "regress_testutils.h"
+#include "regress_thread.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
 
 static int dns_ok = 0;
 static int dns_got_cancel = 0;
@@ -195,7 +204,7 @@ dns_resolve_reverse(void *ptr)
 {
        struct in_addr in;
        struct event_base *base = event_base_new();
-       struct evdns_base *dns = evdns_base_new(base, 1/* init name servers */);
+       struct evdns_base *dns = evdns_base_new(base, EVDNS_BASE_INITIALIZE_NAMESERVERS);
        struct evdns_request *req = NULL;
 
        tt_assert(base);
@@ -511,25 +520,25 @@ generic_dns_callback(int result, char type, int count, int ttl, void *addresses,
 }
 
 static struct regress_dns_server_table search_table[] = {
-       { "host.a.example.com", "err", "3", 0 },
-       { "host.b.example.com", "err", "3", 0 },
-       { "host.c.example.com", "A", "11.22.33.44", 0 },
-       { "host2.a.example.com", "err", "3", 0 },
-       { "host2.b.example.com", "A", "200.100.0.100", 0 },
-       { "host2.c.example.com", "err", "3", 0 },
-       { "hostn.a.example.com", "errsoa", "0", 0 },
-       { "hostn.b.example.com", "errsoa", "3", 0 },
-       { "hostn.c.example.com", "err", "0", 0 },
-
-       { "host", "err", "3", 0 },
-       { "host2", "err", "3", 0 },
-       { "*", "err", "3", 0 },
-       { NULL, NULL, NULL, 0 }
+       { "host.a.example.com", "err", "3", 0, 0 },
+       { "host.b.example.com", "err", "3", 0, 0 },
+       { "host.c.example.com", "A", "11.22.33.44", 0, 0 },
+       { "host2.a.example.com", "err", "3", 0, 0 },
+       { "host2.b.example.com", "A", "200.100.0.100", 0, 0 },
+       { "host2.c.example.com", "err", "3", 0, 0 },
+       { "hostn.a.example.com", "errsoa", "0", 0, 0 },
+       { "hostn.b.example.com", "errsoa", "3", 0, 0 },
+       { "hostn.c.example.com", "err", "0", 0, 0 },
+
+       { "host", "err", "3", 0, 0 },
+       { "host2", "err", "3", 0, 0 },
+       { "*", "err", "3", 0, 0 },
+       { NULL, NULL, NULL, 0, 0 }
 };
-
 static void
-dns_search_test(void *arg)
+dns_search_test_impl(void *arg, int lower)
 {
+       struct regress_dns_server_table table[ARRAY_SIZE(search_table)];
        struct basic_test_data *data = arg;
        struct event_base *base = data->base;
        struct evdns_base *dns = NULL;
@@ -537,8 +546,14 @@ dns_search_test(void *arg)
        char buf[64];
 
        struct generic_dns_callback_result r[8];
+       size_t i;
 
-       tt_assert(regress_dnsserver(base, &portnum, search_table));
+       for (i = 0; i < ARRAY_SIZE(table); ++i) {
+               table[i] = search_table[i];
+               table[i].lower = lower;
+       }
+
+       tt_assert(regress_dnsserver(base, &portnum, table));
        evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
 
        dns = evdns_base_new(base, 0);
@@ -548,7 +563,7 @@ dns_search_test(void *arg)
        evdns_base_search_add(dns, "b.example.com");
        evdns_base_search_add(dns, "c.example.com");
 
-       n_replies_left = sizeof(r)/sizeof(r[0]);
+       n_replies_left = ARRAY_SIZE(r);
        exit_base = base;
 
        evdns_base_resolve_ipv4(dns, "host", 0, generic_dns_callback, &r[0]);
@@ -584,6 +599,28 @@ end:
 
        regress_clean_dnsserver();
 }
+static void
+dns_search_empty_test(void *arg)
+{
+       struct basic_test_data *data = arg;
+       struct event_base *base = data->base;
+       struct evdns_base *dns = NULL;
+
+       dns = evdns_base_new(base, 0);
+
+       evdns_base_search_add(dns, "whatever.example.com");
+
+       n_replies_left = 1;
+       exit_base = base;
+
+       tt_ptr_op(evdns_base_resolve_ipv4(dns, "", 0, generic_dns_callback, NULL), ==, NULL);
+
+end:
+       if (dns)
+               evdns_base_free(dns, 0);
+}
+static void dns_search_test(void *arg) { dns_search_test_impl(arg, 0); }
+static void dns_search_lower_test(void *arg) { dns_search_test_impl(arg, 1); }
 
 static int request_count = 0;
 static struct evdns_request *current_req = NULL;
@@ -776,13 +813,13 @@ static struct regress_dns_server_table internal_error_table[] = {
 
           XXXX we should reissue under a much wider set of circumstances!
         */
-       { "foof.example.com", "err", "4", 0 },
-       { NULL, NULL, NULL, 0 }
+       { "foof.example.com", "err", "4", 0, 0 },
+       { NULL, NULL, NULL, 0, 0 }
 };
 
 static struct regress_dns_server_table reissue_table[] = {
-       { "foof.example.com", "A", "240.15.240.15", 0 },
-       { NULL, NULL, NULL, 0 }
+       { "foof.example.com", "A", "240.15.240.15", 0, 0 },
+       { NULL, NULL, NULL, 0, 0 }
 };
 
 static void
@@ -967,6 +1004,59 @@ end:
                event_base_free(inactive_base);
 }
 
+static void
+dns_initialize_nameservers_test(void *arg)
+{
+       struct basic_test_data *data = arg;
+       struct event_base *base = data->base;
+       struct evdns_base *dns = NULL;
+
+       dns = evdns_base_new(base, 0);
+       tt_assert(dns);
+       tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, -1);
+       evdns_base_free(dns, 0);
+
+       dns = evdns_base_new(base, EVDNS_BASE_INITIALIZE_NAMESERVERS);
+       tt_assert(dns);
+       tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, sizeof(struct sockaddr));
+
+end:
+       if (dns)
+               evdns_base_free(dns, 0);
+}
+#ifndef _WIN32
+#define RESOLV_FILE "empty-resolv.conf"
+static void
+dns_nameservers_no_default_test(void *arg)
+{
+       struct basic_test_data *data = arg;
+       struct event_base *base = data->base;
+       struct evdns_base *dns = NULL;
+       int ok = access(RESOLV_FILE, R_OK);
+
+       tt_assert(ok);
+
+       dns = evdns_base_new(base, 0);
+       tt_assert(dns);
+       tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, -1);
+
+       /* We cannot test
+        * EVDNS_BASE_INITIALIZE_NAMESERVERS|EVDNS_BASE_NAMESERVERS_NO_DEFAULT
+        * because we cannot mock "/etc/resolv.conf" (yet). */
+
+       evdns_base_resolv_conf_parse(dns,
+               DNS_OPTIONS_ALL|DNS_OPTION_NAMESERVERS_NO_DEFAULT, RESOLV_FILE);
+       tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, -1);
+
+       evdns_base_resolv_conf_parse(dns, DNS_OPTIONS_ALL, RESOLV_FILE);
+       tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, sizeof(struct sockaddr));
+
+end:
+       if (dns)
+               evdns_base_free(dns, 0);
+}
+#endif
+
 /* === Test for bufferevent_socket_connect_hostname */
 
 static int total_connected_or_failed = 0;
@@ -983,7 +1073,7 @@ be_getaddrinfo_server_cb(struct evdns_server_request *req, void *data)
        int added_any=0;
        ++*n_got_p;
 
-       for (i=0;i<req->nquestions;++i) {
+       for (i = 0; i < req->nquestions; ++i) {
                const int qtype = req->questions[i]->type;
                const int qclass = req->questions[i]->dns_question_class;
                const char *qname = req->questions[i]->name;
@@ -1127,27 +1217,36 @@ static void
 be_connect_hostname_event_cb(struct bufferevent *bev, short what, void *ctx)
 {
        struct be_conn_hostname_result *got = ctx;
-       if (!got->what) {
-               TT_BLATHER(("Got a bufferevent event %d", what));
-               got->what = what;
-
-               if ((what & BEV_EVENT_CONNECTED) || (what & BEV_EVENT_ERROR)) {
-                       int r;
-                       if ((r = bufferevent_socket_get_dns_error(bev))) {
-                               got->dnserr = r;
-                               TT_BLATHER(("DNS error %d: %s", r,
-                                          evutil_gai_strerror(r)));
-                       }                       ++total_connected_or_failed;
-                       TT_BLATHER(("Got %d connections or errors.", total_connected_or_failed));
-
-                       if (total_n_accepted >= 3 && total_connected_or_failed >= 5)
-                               event_base_loopexit(be_connect_hostname_base,
-                                   NULL);
-               }
-       } else {
+
+       if (got->what) {
                TT_FAIL(("Two events on one bufferevent. %d,%d",
                        got->what, (int)what));
        }
+
+       TT_BLATHER(("Got a bufferevent event %d", what));
+       got->what = what;
+
+       if ((what & BEV_EVENT_CONNECTED) || (what & BEV_EVENT_ERROR)) {
+               int expected = 3;
+               int r = bufferevent_socket_get_dns_error(bev);
+
+               if (r) {
+                       got->dnserr = r;
+                       TT_BLATHER(("DNS error %d: %s", r,
+                                  evutil_gai_strerror(r)));
+               }
+               ++total_connected_or_failed;
+               TT_BLATHER(("Got %d connections or errors.", total_connected_or_failed));
+
+               /** emfile test */
+               if (errno == EMFILE) {
+                       expected = 0;
+               }
+
+               if (total_n_accepted >= expected && total_connected_or_failed >= 5)
+                       event_base_loopexit(be_connect_hostname_base,
+                           NULL);
+       }
 }
 
 static void
@@ -1155,10 +1254,9 @@ test_bufferevent_connect_hostname(void *arg)
 {
        struct basic_test_data *data = arg;
        struct evconnlistener *listener = NULL;
-       struct bufferevent *be1=NULL, *be2=NULL, *be3=NULL, *be4=NULL, *be5=NULL;
-       struct be_conn_hostname_result be1_outcome={0,0}, be2_outcome={0,0},
-              be3_outcome={0,0}, be4_outcome={0,0}, be5_outcome={0,0};
-       int expect_err5;
+       struct bufferevent *be[5];
+       struct be_conn_hostname_result be_outcome[ARRAY_SIZE(be)];
+       int expect_err;
        struct evdns_base *dns=NULL;
        struct evdns_server_port *port=NULL;
        struct sockaddr_in sin;
@@ -1166,6 +1264,9 @@ test_bufferevent_connect_hostname(void *arg)
        ev_uint16_t dns_port=0;
        int n_accept=0, n_dns=0;
        char buf[128];
+       int emfile = data->setup_data && !strcmp(data->setup_data, "emfile");
+       unsigned i;
+       int ret;
 
        be_connect_hostname_base = data->base;
 
@@ -1192,41 +1293,34 @@ test_bufferevent_connect_hostname(void *arg)
        evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)dns_port);
        evdns_base_nameserver_ip_add(dns, buf);
 
+#ifdef EVENT__HAVE_SETRLIMIT
+       if (emfile) {
+               int fd = socket(AF_INET, SOCK_STREAM, 0);
+               struct rlimit file = { fd, fd };
+
+               tt_int_op(fd, >=, 0);
+               tt_assert(!close(fd));
+
+               tt_assert(!setrlimit(RLIMIT_NOFILE, &file));
+       }
+#endif
+
        /* Now, finally, at long last, launch the bufferevents.  One should do
         * a failing lookup IP, one should do a successful lookup by IP,
         * and one should do a successful lookup by hostname. */
-       be1 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
-       be2 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
-       be3 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
-       be4 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
-       be5 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
-
-       bufferevent_setcb(be1, NULL, NULL, be_connect_hostname_event_cb,
-           &be1_outcome);
-       bufferevent_setcb(be2, NULL, NULL, be_connect_hostname_event_cb,
-           &be2_outcome);
-       bufferevent_setcb(be3, NULL, NULL, be_connect_hostname_event_cb,
-           &be3_outcome);
-       bufferevent_setcb(be4, NULL, NULL, be_connect_hostname_event_cb,
-           &be4_outcome);
-       bufferevent_setcb(be5, NULL, NULL, be_connect_hostname_event_cb,
-           &be5_outcome);
+       for (i = 0; i < ARRAY_SIZE(be); ++i) {
+               memset(&be_outcome[i], 0, sizeof(be_outcome[i]));
+               be[i] = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
+               bufferevent_setcb(be[i], NULL, NULL, be_connect_hostname_event_cb,
+                       &be_outcome[i]);
+       }
 
-       /* Launch an async resolve that will fail. */
-       tt_assert(!bufferevent_socket_connect_hostname(be1, dns, AF_INET,
-               "nosuchplace.example.com", listener_port));
-       /* Connect to the IP without resolving. */
-       tt_assert(!bufferevent_socket_connect_hostname(be2, dns, AF_INET,
-               "127.0.0.1", listener_port));
-       /* Launch an async resolve that will succeed. */
-       tt_assert(!bufferevent_socket_connect_hostname(be3, dns, AF_INET,
-               "nobodaddy.example.com", listener_port));
        /* Use the blocking resolver.  This one will fail if your resolver
         * can't resolve localhost to 127.0.0.1 */
-       tt_assert(!bufferevent_socket_connect_hostname(be4, NULL, AF_INET,
+       tt_assert(!bufferevent_socket_connect_hostname(be[3], NULL, AF_INET,
                "localhost", listener_port));
        /* Use the blocking resolver with a nonexistent hostname. */
-       tt_assert(!bufferevent_socket_connect_hostname(be5, NULL, AF_INET,
+       tt_assert(!bufferevent_socket_connect_hostname(be[4], NULL, AF_INET,
                "nonesuch.nowhere.example.com", 80));
        {
                /* The blocking resolver will use the system nameserver, which
@@ -1237,26 +1331,53 @@ test_bufferevent_connect_hostname(void *arg)
                hints.ai_family = AF_INET;
                hints.ai_socktype = SOCK_STREAM;
                hints.ai_protocol = IPPROTO_TCP;
-               expect_err5 = evutil_getaddrinfo(
+               expect_err = evutil_getaddrinfo(
                        "nonesuch.nowhere.example.com", "80", &hints, &ai);
        }
+       /* Launch an async resolve that will fail. */
+       tt_assert(!bufferevent_socket_connect_hostname(be[0], dns, AF_INET,
+               "nosuchplace.example.com", listener_port));
+       /* Connect to the IP without resolving. */
+       tt_assert(!bufferevent_socket_connect_hostname(be[1], dns, AF_INET,
+               "127.0.0.1", listener_port));
+       /* Launch an async resolve that will succeed. */
+       tt_assert(!bufferevent_socket_connect_hostname(be[2], dns, AF_INET,
+               "nobodaddy.example.com", listener_port));
 
-       event_base_dispatch(data->base);
+       ret = event_base_dispatch(data->base);
+#ifdef __sun__
+       if (emfile && !strcmp(event_base_get_method(data->base), "devpoll")) {
+               tt_int_op(ret, ==, -1);
+               /** DP_POLL failed */
+               tt_skip();
+       } else
+#endif
+       {
+               tt_int_op(ret, ==, 0);
+       }
 
-       tt_int_op(be1_outcome.what, ==, BEV_EVENT_ERROR);
-       tt_int_op(be1_outcome.dnserr, ==, EVUTIL_EAI_NONAME);
-       tt_int_op(be2_outcome.what, ==, BEV_EVENT_CONNECTED);
-       tt_int_op(be2_outcome.dnserr, ==, 0);
-       tt_int_op(be3_outcome.what, ==, BEV_EVENT_CONNECTED);
-       tt_int_op(be3_outcome.dnserr, ==, 0);
-       tt_int_op(be4_outcome.what, ==, BEV_EVENT_CONNECTED);
-       tt_int_op(be4_outcome.dnserr, ==, 0);
-       if (expect_err5) {
-               tt_int_op(be5_outcome.what, ==, BEV_EVENT_ERROR);
-               tt_int_op(be5_outcome.dnserr, ==, expect_err5);
+       tt_int_op(be_outcome[0].what, ==, BEV_EVENT_ERROR);
+       tt_int_op(be_outcome[0].dnserr, ==, EVUTIL_EAI_NONAME);
+       tt_int_op(be_outcome[1].what, ==, !emfile ? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR);
+       tt_int_op(be_outcome[1].dnserr, ==, 0);
+       tt_int_op(be_outcome[2].what, ==, !emfile ? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR);
+       tt_int_op(be_outcome[2].dnserr, ==, 0);
+       tt_int_op(be_outcome[3].what, ==, !emfile ? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR);
+       if (!emfile) {
+               tt_int_op(be_outcome[3].dnserr, ==, 0);
+       } else {
+               tt_int_op(be_outcome[3].dnserr, !=, 0);
+       }
+       if (expect_err) {
+               tt_int_op(be_outcome[4].what, ==, BEV_EVENT_ERROR);
+               tt_int_op(be_outcome[4].dnserr, ==, expect_err);
        }
 
-       tt_int_op(n_accept, ==, 3);
+       if (emfile) {
+               tt_int_op(n_accept, ==, 0);
+       } else {
+               tt_int_op(n_accept, ==, 3);
+       }
        tt_int_op(n_dns, ==, 2);
 
 end:
@@ -1266,16 +1387,10 @@ end:
                evdns_close_server_port(port);
        if (dns)
                evdns_base_free(dns, 0);
-       if (be1)
-               bufferevent_free(be1);
-       if (be2)
-               bufferevent_free(be2);
-       if (be3)
-               bufferevent_free(be3);
-       if (be4)
-               bufferevent_free(be4);
-       if (be5)
-               bufferevent_free(be5);
+       for (i = 0; i < ARRAY_SIZE(be); ++i) {
+               if (be[i])
+                       bufferevent_free(be[i]);
+       }
 }
 
 
@@ -1314,7 +1429,7 @@ test_getaddrinfo_async(void *arg)
        struct evutil_addrinfo hints, *a;
        struct gai_outcome local_outcome;
        struct gai_outcome a_out[12];
-       int i;
+       unsigned i;
        struct evdns_getaddrinfo_request *r;
        char buf[128];
        struct evdns_server_port *port = NULL;
@@ -1322,7 +1437,7 @@ test_getaddrinfo_async(void *arg)
        int n_dns_questions = 0;
        struct evdns_base *dns_base;
 
-       memset(&a_out, 0, sizeof(a_out));
+       memset(a_out, 0, sizeof(a_out));
        memset(&local_outcome, 0, sizeof(local_outcome));
 
        dns_base = evdns_base_new(data->base, 0);
@@ -1672,8 +1787,7 @@ test_getaddrinfo_async(void *arg)
 end:
        if (local_outcome.ai)
                evutil_freeaddrinfo(local_outcome.ai);
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
-       for (i=0;i<(int)ARRAY_SIZE(a_out);++i) {
+       for (i = 0; i < ARRAY_SIZE(a_out); ++i) {
                if (a_out[i].ai)
                        evutil_freeaddrinfo(a_out[i].ai);
        }
@@ -1694,7 +1808,8 @@ struct gaic_request_status {
 
 #define GAIC_MAGIC 0x1234abcd
 
-static int pending = 0;
+static int gaic_pending = 0;
+static int gaic_freed = 0;
 
 static void
 gaic_cancel_request_cb(evutil_socket_t fd, short what, void *arg)
@@ -1739,15 +1854,20 @@ gaic_getaddrinfo_cb(int result, struct evutil_addrinfo *res, void *arg)
        free(status);
 
 end:
-       if (--pending <= 0)
+       if (res)
+       {
+               TT_BLATHER(("evutil_freeaddrinfo(%p)", res));
+               evutil_freeaddrinfo(res);
+               ++gaic_freed;
+       }
+       if (--gaic_pending <= 0)
                event_base_loopexit(base, NULL);
 }
 
 static void
 gaic_launch(struct event_base *base, struct evdns_base *dns_base)
 {
-       struct gaic_request_status *status = calloc(1, sizeof(*status));
-       tt_assert(status);
+       struct gaic_request_status *status = calloc(1,sizeof(*status));
        struct timeval tv = { 0, 10000 };
        status->magic = GAIC_MAGIC;
        status->base = base;
@@ -1758,7 +1878,7 @@ gaic_launch(struct event_base *base, struct evdns_base *dns_base)
            "foobar.bazquux.example.com", "80", NULL, gaic_getaddrinfo_cb,
            status);
        event_add(&status->cancel_event, &tv);
-       ++pending;
+       ++gaic_pending;
 }
 
 #ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
@@ -1886,29 +2006,22 @@ dbg_leak_resume(void *env_, int cancel, int send_err_shutdown)
                tt_assert(!evdns_base_resume(env->dns_base));
        }
 
+       event_base_loop(env->base, EVLOOP_NONBLOCK);
        /**
-        * Because we don't cancel request,
-        * and want our callback to recieve DNS_ERR_SHUTDOWN,
-        * we use deferred callback, and there was
+        * Because we don't cancel request, and want our callback to recieve
+        * DNS_ERR_SHUTDOWN, we use deferred callback, and there was:
         * - one extra malloc(),
         *   @see reply_schedule_callback()
         * - and one missing free
         *   @see request_finished() (req->handle->pending_cb = 1)
-        * than we don't need to count in testleak_cleanup()
-        *
-        * So just decrement allocated_chunks to 2,
-        * like we already take care about it.
+        * than we don't need to count in testleak_cleanup(), but we can clean them
+        * if we will run loop once again, but *after* evdns base freed.
         */
-       if (!cancel && send_err_shutdown) {
-               allocated_chunks -= 2;
-       }
-
-       event_base_loop(env->base, EVLOOP_NONBLOCK);
-
-end:
        evdns_base_free(env->dns_base, send_err_shutdown);
        env->dns_base = 0;
+       event_base_loop(env->base, EVLOOP_NONBLOCK);
 
+end:
        event_base_free(env->base);
        env->base = 0;
 }
@@ -1955,7 +2068,7 @@ test_getaddrinfo_async_cancel_stress(void *ptr)
        struct sockaddr_in sin;
        struct sockaddr_storage ss;
        ev_socklen_t slen;
-       int i;
+       unsigned i;
 
        base = event_base_new();
        dns_base = evdns_base_new(base, 0);
@@ -1988,6 +2101,9 @@ test_getaddrinfo_async_cancel_stress(void *ptr)
 
        event_base_dispatch(base);
 
+       // at least some was canceled via external event
+       tt_int_op(gaic_freed, !=, 1000);
+
 end:
        if (dns_base)
                evdns_base_free(dns_base, 1);
@@ -1999,6 +2115,327 @@ end:
                evutil_closesocket(fd);
 }
 
+static void
+dns_client_fail_requests_test(void *arg)
+{
+       struct basic_test_data *data = arg;
+       struct event_base *base = data->base;
+       int limit_inflight = data->setup_data && !strcmp(data->setup_data, "limit-inflight");
+       struct evdns_base *dns = NULL;
+       struct evdns_server_port *dns_port = NULL;
+       ev_uint16_t portnum = 0;
+       char buf[64];
+
+       struct generic_dns_callback_result r[20];
+       unsigned i;
+
+       dns_port = regress_get_dnsserver(base, &portnum, NULL,
+               regress_dns_server_cb, reissue_table);
+       tt_assert(dns_port);
+
+       evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
+
+       dns = evdns_base_new(base, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
+       tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
+
+       if (limit_inflight)
+               tt_assert(!evdns_base_set_option(dns, "max-inflight:", "11"));
+
+       for (i = 0; i < 20; ++i)
+               evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r[i]);
+
+       n_replies_left = 20;
+       exit_base = base;
+
+       evdns_base_free(dns, 1 /** fail requests */);
+       /** run defered callbacks, to trigger UAF */
+       event_base_dispatch(base);
+
+       tt_int_op(n_replies_left, ==, 0);
+       for (i = 0; i < 20; ++i)
+               tt_int_op(r[i].result, ==, DNS_ERR_SHUTDOWN);
+
+end:
+       evdns_close_server_port(dns_port);
+}
+
+static void
+getaddrinfo_cb(int err, struct evutil_addrinfo *res, void *ptr)
+{
+       generic_dns_callback(err, 0, 0, 0, NULL, ptr);
+}
+static void
+dns_client_fail_requests_getaddrinfo_test(void *arg)
+{
+       struct basic_test_data *data = arg;
+       struct event_base *base = data->base;
+       struct evdns_base *dns = NULL;
+       struct evdns_server_port *dns_port = NULL;
+       ev_uint16_t portnum = 0;
+       char buf[64];
+
+       struct generic_dns_callback_result r[20];
+       int i;
+
+       dns_port = regress_get_dnsserver(base, &portnum, NULL,
+               regress_dns_server_cb, reissue_table);
+       tt_assert(dns_port);
+
+       evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
+
+       dns = evdns_base_new(base, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
+       tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
+
+       for (i = 0; i < 20; ++i)
+               tt_assert(evdns_getaddrinfo(dns, "foof.example.com", "80", NULL, getaddrinfo_cb, &r[i]));
+
+       n_replies_left = 20;
+       exit_base = base;
+
+       evdns_base_free(dns, 1 /** fail requests */);
+       /** run defered callbacks, to trigger UAF */
+       event_base_dispatch(base);
+
+       tt_int_op(n_replies_left, ==, 0);
+       for (i = 0; i < 20; ++i)
+               tt_int_op(r[i].result, ==, EVUTIL_EAI_FAIL);
+
+end:
+       evdns_close_server_port(dns_port);
+}
+
+#ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED
+struct race_param
+{
+       void *lock;
+       void *reqs_cmpl_cond;
+       int bw_threads;
+       void *bw_threads_exited_cond;
+       volatile int stopping;
+       void *base;
+       void *dns;
+
+       int locked;
+};
+static void *
+race_base_run(void *arg)
+{
+       struct race_param *rp = (struct race_param *)arg;
+       event_base_loop(rp->base, EVLOOP_NO_EXIT_ON_EMPTY);
+       THREAD_RETURN();
+}
+static void *
+race_busywait_run(void *arg)
+{
+       struct race_param *rp = (struct race_param *)arg;
+       struct sockaddr_storage ss;
+       while (!rp->stopping)
+               evdns_base_get_nameserver_addr(rp->dns, 0, (struct sockaddr *)&ss, sizeof(ss));
+       EVLOCK_LOCK(rp->lock, 0);
+       if (--rp->bw_threads == 0)
+               EVTHREAD_COND_SIGNAL(rp->bw_threads_exited_cond);
+       EVLOCK_UNLOCK(rp->lock, 0);
+       THREAD_RETURN();
+}
+static void
+race_gai_cb(int result, struct evutil_addrinfo *res, void *arg)
+{
+       struct race_param *rp = arg;
+       (void)result;
+       (void)res;
+
+       --n_replies_left;
+       if (n_replies_left == 0) {
+               EVLOCK_LOCK(rp->lock, 0);
+               EVTHREAD_COND_SIGNAL(rp->reqs_cmpl_cond);
+               EVLOCK_UNLOCK(rp->lock, 0);
+       }
+}
+static void
+getaddrinfo_race_gotresolve_test(void *arg)
+{
+       struct race_param rp;
+       struct evdns_server_port *dns_port = NULL;
+       ev_uint16_t portnum = 0;
+       char buf[64];
+       int i;
+
+       // Some stress is needed to yield inside getaddrinfo between resolve_ipv4 and resolve_ipv6
+       int n_reqs = 16384;
+#ifdef _SC_NPROCESSORS_ONLN
+       int n_threads = sysconf(_SC_NPROCESSORS_ONLN) + 1;
+#else
+       int n_threads = 17;
+#endif
+       THREAD_T thread[n_threads];
+       struct timeval tv;
+
+       (void)arg;
+
+       evthread_use_pthreads();
+
+       rp.base = event_base_new();
+       tt_assert(rp.base);
+       if (evthread_make_base_notifiable(rp.base) < 0)
+               tt_abort_msg("Couldn't make base notifiable!");
+
+       dns_port = regress_get_dnsserver(rp.base, &portnum, NULL,
+                                                                        regress_dns_server_cb, reissue_table);
+       tt_assert(dns_port);
+
+       evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
+
+       rp.dns = evdns_base_new(rp.base, 0);
+       tt_assert(!evdns_base_nameserver_ip_add(rp.dns, buf));
+
+       n_replies_left = n_reqs;
+
+       EVTHREAD_ALLOC_LOCK(rp.lock, 0);
+       EVTHREAD_ALLOC_COND(rp.reqs_cmpl_cond);
+       EVTHREAD_ALLOC_COND(rp.bw_threads_exited_cond);
+       tt_assert(rp.lock);
+       tt_assert(rp.reqs_cmpl_cond);
+       tt_assert(rp.bw_threads_exited_cond);
+       rp.bw_threads = 0;
+       rp.stopping = 0;
+
+       // Run resolver thread
+       THREAD_START(thread[0], race_base_run, &rp);
+       // Run busy-wait threads used to force yield this thread
+       for (i = 1; i < n_threads; i++) {
+               rp.bw_threads++;
+               THREAD_START(thread[i], race_busywait_run, &rp);
+       }
+
+       EVLOCK_LOCK(rp.lock, 0);
+       rp.locked = 1;
+
+       for (i = 0; i < n_reqs; ++i) {
+               tt_assert(evdns_getaddrinfo(rp.dns, "foof.example.com", "80", NULL, race_gai_cb, &rp));
+               // This magic along with busy-wait threads make this thread yield frequently
+               if (i % 100 == 0) {
+                       tv.tv_sec = 0;
+                       tv.tv_usec = 10000;
+                       evutil_usleep_(&tv);
+               }
+       }
+
+       exit_base = rp.base;
+
+       // Wait for some time
+       tv.tv_sec = 5;
+       tv.tv_usec = 0;
+       EVTHREAD_COND_WAIT_TIMED(rp.reqs_cmpl_cond, rp.lock, &tv);
+
+       // Stop busy-wait threads
+       tv.tv_sec = 1;
+       tv.tv_usec = 0;
+       rp.stopping = 1;
+       tt_assert(EVTHREAD_COND_WAIT_TIMED(rp.bw_threads_exited_cond, rp.lock, &tv) == 0);
+
+       EVLOCK_UNLOCK(rp.lock, 0);
+       rp.locked = 0;
+
+       evdns_base_free(rp.dns, 1 /** fail requests */);
+
+       tt_int_op(n_replies_left, ==, 0);
+
+end:
+       if (rp.locked)
+               EVLOCK_UNLOCK(rp.lock, 0);
+       EVTHREAD_FREE_LOCK(rp.lock, 0);
+       EVTHREAD_FREE_COND(rp.reqs_cmpl_cond);
+       EVTHREAD_FREE_COND(rp.bw_threads_exited_cond);
+       evdns_close_server_port(dns_port);
+       event_base_loopbreak(rp.base);
+       event_base_free(rp.base);
+}
+#endif
+
+static void
+test_set_so_rcvbuf_so_sndbuf(void *arg)
+{
+       struct basic_test_data *data = arg;
+       struct evdns_base *dns_base;
+
+       dns_base = evdns_base_new(data->base, 0);
+       tt_assert(dns_base);
+
+       tt_assert(!evdns_base_set_option(dns_base, "so-rcvbuf", "10240"));
+       tt_assert(!evdns_base_set_option(dns_base, "so-sndbuf", "10240"));
+
+       /* actually check SO_RCVBUF/SO_SNDBUF not fails */
+       tt_assert(!evdns_base_nameserver_ip_add(dns_base, "127.0.0.1"));
+
+end:
+       if (dns_base)
+               evdns_base_free(dns_base, 0);
+}
+
+static void
+test_set_option(void *arg)
+{
+#define SUCCESS 0
+#define FAIL -1
+       struct basic_test_data *data = arg;
+       struct evdns_base *dns_base;
+       size_t i;
+       /* Option names are allowed to have ':' at the end.
+        * So all test option names come in pairs.
+        */
+       const char *int_options[] = {
+               "ndots", "ndots:",
+               "max-timeouts", "max-timeouts:",
+               "max-inflight", "max-inflight:",
+               "attempts", "attempts:",
+               "randomize-case", "randomize-case:",
+               "so-rcvbuf", "so-rcvbuf:",
+               "so-sndbuf", "so-sndbuf:",
+       };
+       const char *timeval_options[] = {
+               "timeout", "timeout:",
+               "getaddrinfo-allow-skew", "getaddrinfo-allow-skew:",
+               "initial-probe-timeout", "initial-probe-timeout:",
+       };
+       const char *addr_port_options[] = {
+               "bind-to", "bind-to:",
+       };
+
+       dns_base = evdns_base_new(data->base, 0);
+       tt_assert(dns_base);
+
+       for (i = 0; i < ARRAY_SIZE(int_options); ++i) {
+               tt_assert(SUCCESS == evdns_base_set_option(dns_base, int_options[i], "0"));
+               tt_assert(SUCCESS == evdns_base_set_option(dns_base, int_options[i], "1"));
+               tt_assert(SUCCESS == evdns_base_set_option(dns_base, int_options[i], "10000"));
+               tt_assert(FAIL == evdns_base_set_option(dns_base, int_options[i], "foo"));
+               tt_assert(FAIL == evdns_base_set_option(dns_base, int_options[i], "3.14"));
+       }
+
+       for (i = 0; i < ARRAY_SIZE(timeval_options); ++i) {
+               tt_assert(SUCCESS == evdns_base_set_option(dns_base, timeval_options[i], "1"));
+               tt_assert(SUCCESS == evdns_base_set_option(dns_base, timeval_options[i], "0.001"));
+               tt_assert(SUCCESS == evdns_base_set_option(dns_base, timeval_options[i], "3.14"));
+               tt_assert(SUCCESS == evdns_base_set_option(dns_base, timeval_options[i], "10000"));
+               tt_assert(FAIL == evdns_base_set_option(dns_base, timeval_options[i], "0"));
+               tt_assert(FAIL == evdns_base_set_option(dns_base, timeval_options[i], "foo"));
+       }
+
+       for (i = 0; i < ARRAY_SIZE(addr_port_options); ++i) {
+               tt_assert(SUCCESS == evdns_base_set_option(dns_base, addr_port_options[i], "8.8.8.8:80"));
+               tt_assert(SUCCESS == evdns_base_set_option(dns_base, addr_port_options[i], "1.2.3.4"));
+               tt_assert(SUCCESS == evdns_base_set_option(dns_base, addr_port_options[i], "::1:82"));
+               tt_assert(SUCCESS == evdns_base_set_option(dns_base, addr_port_options[i], "3::4"));
+               tt_assert(FAIL == evdns_base_set_option(dns_base, addr_port_options[i], "3.14"));
+               tt_assert(FAIL == evdns_base_set_option(dns_base, addr_port_options[i], "foo"));
+       }
+
+#undef SUCCESS
+#undef FAIL
+end:
+       if (dns_base)
+               evdns_base_free(dns_base, 0);
+}
 
 #define DNS_LEGACY(name, flags)                                               \
        { #name, run_legacy_test_fn, flags|TT_LEGACY, &legacy_setup,   \
@@ -2010,7 +2447,9 @@ struct testcase_t dns_testcases[] = {
        DNS_LEGACY(gethostbyname6, TT_FORK|TT_NEED_BASE|TT_NEED_DNS|TT_OFF_BY_DEFAULT),
        DNS_LEGACY(gethostbyaddr, TT_FORK|TT_NEED_BASE|TT_NEED_DNS|TT_OFF_BY_DEFAULT),
        { "resolve_reverse", dns_resolve_reverse, TT_FORK|TT_OFF_BY_DEFAULT, NULL, NULL },
+       { "search_empty", dns_search_empty_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
        { "search", dns_search_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+       { "search_lower", dns_search_lower_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
        { "search_cancel", dns_search_cancel_test,
          TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
        { "retry", dns_retry_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
@@ -2022,10 +2461,21 @@ struct testcase_t dns_testcases[] = {
        { "inflight", dns_inflight_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
        { "bufferevent_connect_hostname", test_bufferevent_connect_hostname,
          TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+#ifdef EVENT__HAVE_SETRLIMIT
+       { "bufferevent_connect_hostname_emfile", test_bufferevent_connect_hostname,
+         TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"emfile" },
+#endif
        { "disable_when_inactive", dns_disable_when_inactive_test,
          TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
        { "disable_when_inactive_no_ns", dns_disable_when_inactive_no_ns_test,
+         TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
+
+       { "initialize_nameservers", dns_initialize_nameservers_test,
+         TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+#ifndef _WIN32
+       { "nameservers_no_default", dns_nameservers_no_default_test,
          TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+#endif
 
        { "getaddrinfo_async", test_getaddrinfo_async,
          TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"" },
@@ -2045,6 +2495,24 @@ struct testcase_t dns_testcases[] = {
          TT_FORK, &testleak_funcs, NULL },
 #endif
 
+       { "client_fail_requests", dns_client_fail_requests_test,
+         TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
+       { "client_fail_waiting_requests", dns_client_fail_requests_test,
+         TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, (char*)"limit-inflight" },
+       { "client_fail_requests_getaddrinfo",
+         dns_client_fail_requests_getaddrinfo_test,
+         TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
+#ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED
+       { "getaddrinfo_race_gotresolve",
+         getaddrinfo_race_gotresolve_test,
+         TT_FORK|TT_OFF_BY_DEFAULT, NULL, NULL },
+#endif
+
+       { "set_SO_RCVBUF_SO_SNDBUF", test_set_so_rcvbuf_so_sndbuf,
+         TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+       { "set_options", test_set_option,
+         TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+
        END_OF_TESTCASES
 };
 
index 229a78e2d429722fdcab5de36b35415f627655cd..1b1f819eda19800206a0de2b27912fdfdf5681bb 100644 (file)
 
 static int was_et = 0;
 
+static int base_supports_et(struct event_base *base)
+{
+       return
+               (!strcmp(event_base_get_method(base), "epoll") ||
+               !strcmp(event_base_get_method(base), "epoll (with changelist)") ||
+               !strcmp(event_base_get_method(base), "kqueue"));
+}
+
 static void
 read_cb(evutil_socket_t fd, short event, void *arg)
 {
@@ -67,23 +75,14 @@ read_cb(evutil_socket_t fd, short event, void *arg)
                event_del(arg);
 }
 
-#ifndef SHUT_WR
-#define SHUT_WR 1
-#endif
-
-#ifdef _WIN32
-#define LOCAL_SOCKETPAIR_AF AF_INET
-#else
-#define LOCAL_SOCKETPAIR_AF AF_UNIX
-#endif
-
 static void
-test_edgetriggered(void *et)
+test_edgetriggered(void *data_)
 {
+       struct basic_test_data *data = data_;
+       struct event_base *base = data->base;
+       evutil_socket_t *pair = data->pair;
        struct event *ev = NULL;
-       struct event_base *base = NULL;
        const char *test = "test string";
-       evutil_socket_t pair[2] = {-1,-1};
        int supports_et;
 
        /* On Linux 3.2.1 (at least, as patched by Fedora and tested by Nick),
@@ -92,39 +91,21 @@ test_edgetriggered(void *et)
         * get edge-triggered behavior.  Yuck!  Linux 3.1.9 didn't have this
         * problem.
         */
-#ifdef __linux__
-       if (evutil_ersatz_socketpair_(AF_INET, SOCK_STREAM, 0, pair) == -1) {
-               tt_abort_perror("socketpair");
-       }
-#else
-       if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair) == -1) {
-               tt_abort_perror("socketpair");
-       }
-#endif
 
        called = was_et = 0;
 
        tt_int_op(send(pair[0], test, (int)strlen(test)+1, 0), >, 0);
-       shutdown(pair[0], SHUT_WR);
-
-       /* Initalize the event library */
-       base = event_base_new();
-
-       if (!strcmp(event_base_get_method(base), "epoll") ||
-           !strcmp(event_base_get_method(base), "epoll (with changelist)") ||
-           !strcmp(event_base_get_method(base), "kqueue"))
-               supports_et = 1;
-       else
-               supports_et = 0;
+       tt_int_op(shutdown(pair[0], EVUTIL_SHUT_WR), ==, 0);
 
+       supports_et = base_supports_et(base);
        TT_BLATHER(("Checking for edge-triggered events with %s, which should %s"
                                "support edge-triggering", event_base_get_method(base),
                                supports_et?"":"not "));
 
-       /* Initalize one event */
+       /* Initialize one event */
        ev = event_new(base, pair[1], EV_READ|EV_ET|EV_PERSIST, read_cb, &ev);
-
-       event_add(ev, NULL);
+       tt_assert(ev != NULL);
+       tt_int_op(event_add(ev, NULL), ==, 0);
 
        /* We're going to call the dispatch function twice.  The first invocation
         * will read a single byte from pair[1] in either case.  If we're edge
@@ -133,8 +114,8 @@ test_edgetriggered(void *et)
         * do nothing.  If we're level triggered, the second invocation of
         * event_base_loop will also activate the event (because there's still
         * data to read). */
-       event_base_loop(base,EVLOOP_NONBLOCK|EVLOOP_ONCE);
-       event_base_loop(base,EVLOOP_NONBLOCK|EVLOOP_ONCE);
+       tt_int_op(event_base_loop(base,EVLOOP_NONBLOCK|EVLOOP_ONCE), ==, 0);
+       tt_int_op(event_base_loop(base,EVLOOP_NONBLOCK|EVLOOP_ONCE), ==, 0);
 
        if (supports_et) {
                tt_int_op(called, ==, 1);
@@ -144,15 +125,11 @@ test_edgetriggered(void *et)
                tt_assert(!was_et);
        }
 
- end:
+end:
        if (ev) {
                event_del(ev);
                event_free(ev);
        }
-       if (base)
-               event_base_free(base);
-       evutil_closesocket(pair[0]);
-       evutil_closesocket(pair[1]);
 }
 
 static void
@@ -200,9 +177,94 @@ end:
                event_base_free(base);
 }
 
+static int read_notification_count;
+static int last_read_notification_was_et;
+static void
+read_notification_cb(evutil_socket_t fd, short event, void *arg)
+{
+       read_notification_count++;
+       last_read_notification_was_et = (event & EV_ET);
+}
+
+static int write_notification_count;
+static int last_write_notification_was_et;
+static void
+write_notification_cb(evutil_socket_t fd, short event, void *arg)
+{
+       write_notification_count++;
+       last_write_notification_was_et = (event & EV_ET);
+}
+
+/* After two or more events have been registered for the same
+ * file descriptor using EV_ET, if one of the events is
+ * deleted, then the epoll_ctl() call issued by libevent drops
+ * the EPOLLET flag resulting in level triggered
+ * notifications.
+ */
+static void
+test_edge_triggered_multiple_events(void *data_)
+{
+       struct basic_test_data *data = data_;
+       struct event *read_ev = NULL;
+       struct event *write_ev = NULL;
+       const char c = 'A';
+       struct event_base *base = data->base;
+       evutil_socket_t *pair = data->pair;
+
+       if (!base_supports_et(base)) {
+               tt_skip();
+               return;
+       }
+
+       read_notification_count = 0;
+       last_read_notification_was_et = 0;
+       write_notification_count = 0;
+       last_write_notification_was_et = 0;
+
+       /* Make pair[1] readable */
+       tt_int_op(send(pair[0], &c, 1, 0), >, 0);
+
+       read_ev = event_new(base, pair[1], EV_READ|EV_ET|EV_PERSIST,
+               read_notification_cb, NULL);
+       write_ev = event_new(base, pair[1], EV_WRITE|EV_ET|EV_PERSIST,
+               write_notification_cb, NULL);
+
+       event_add(read_ev, NULL);
+       event_add(write_ev, NULL);
+       event_base_loop(base, EVLOOP_NONBLOCK|EVLOOP_ONCE);
+       event_base_loop(base, EVLOOP_NONBLOCK|EVLOOP_ONCE);
+
+       tt_assert(last_read_notification_was_et);
+       tt_int_op(read_notification_count, ==, 1);
+       tt_assert(last_write_notification_was_et);
+       tt_int_op(write_notification_count, ==, 1);
+
+       event_del(read_ev);
+
+       /* trigger acitivity second time for the backend that can have multiple
+        * events for one fd (like kqueue) */
+       close(pair[0]);
+       pair[0] = -1;
+
+       /* Verify that we are still edge-triggered for write notifications */
+       event_base_loop(base, EVLOOP_NONBLOCK|EVLOOP_ONCE);
+       event_base_loop(base, EVLOOP_NONBLOCK|EVLOOP_ONCE);
+       tt_assert(last_write_notification_was_et);
+       tt_int_op(write_notification_count, ==, 2);
+
+end:
+       if (read_ev)
+               event_free(read_ev);
+       if (write_ev)
+               event_free(write_ev);
+}
+
 struct testcase_t edgetriggered_testcases[] = {
-       { "et", test_edgetriggered, TT_FORK, NULL, NULL },
+       { "et", test_edgetriggered,
+         TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR, &basic_setup, NULL },
        { "et_mix_error", test_edgetriggered_mix_error,
          TT_FORK|TT_NEED_SOCKETPAIR|TT_NO_LOGS, &basic_setup, NULL },
+       { "et_multiple_events", test_edge_triggered_multiple_events,
+         TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR, &basic_setup, NULL },
        END_OF_TESTCASES
 };
index 552210fe9d01c2539d5590da2862e56c543461e5..9e57188121d1174d51a5b9be52c71e9b696ac43e 100644 (file)
@@ -290,6 +290,53 @@ end:
        ;
 }
 
+static void
+event_finalize_callback_free(struct event *ev, void *arg)
+{
+       struct event_base *base = arg;
+       int err;
+       if (base) {
+               err = event_assign(ev, base, -1, EV_TIMEOUT, NULL, NULL);
+               tt_int_op(err, ==, 0);
+               test_ok += 1;
+       } else {
+               free(ev);
+               test_ok += 1;
+       }
+
+end:
+       ;
+}
+static void
+test_fin_debug_use_after_free(void *arg)
+{
+       struct basic_test_data *data = arg;
+       struct event_base *base = data->base;
+       struct event *ev;
+
+       tt_ptr_op(ev = event_new(base, -1, EV_TIMEOUT, NULL, base), !=, NULL);
+       tt_int_op(event_add(ev, NULL), ==, 0);
+       tt_int_op(event_finalize(0, ev, event_finalize_callback_free), ==, 0);
+
+       // Dispatch base to trigger callbacks
+       event_base_dispatch(base);
+       event_base_assert_ok_(base);
+       tt_int_op(test_ok, ==, 1);
+
+       // Now add again, since we did event_assign in event_finalize_callback_free
+       // This used to fail in event_debug_assert_is_setup_
+       tt_int_op(event_add(ev, NULL), ==, 0);
+
+       // Finalize and dispatch again
+       tt_int_op(event_finalize(0, ev, event_finalize_callback_free), ==, 0);
+       event_base_dispatch(base);
+       event_base_assert_ok_(base);
+       tt_int_op(test_ok, ==, 2);
+
+end:
+       ;
+}
+
 #if 0
 static void
 timer_callback_3(evutil_socket_t *fd, short what, void *arg)
@@ -339,6 +386,7 @@ struct testcase_t finalize_testcases[] = {
        TEST(cb_invoked, TT_FORK|TT_NEED_BASE),
        TEST(free_finalize, TT_FORK),
        TEST(within_cb, TT_FORK|TT_NEED_BASE),
+       TEST(debug_use_after_free, TT_FORK|TT_NEED_BASE|TT_ENABLE_DEBUG_MODE),
 //     TEST(many, TT_FORK|TT_NEED_BASE),
 
 
index 147f6ff1a76aa0f0049f85d4cead6046fce85d33..4493907163e2806ed06315f25c79df7f28378eac 100644 (file)
 #include "event2/http.h"
 #include "event2/buffer.h"
 #include "event2/bufferevent.h"
+#include "event2/bufferevent_ssl.h"
 #include "event2/util.h"
+#include "event2/listener.h"
 #include "log-internal.h"
 #include "http-internal.h"
 #include "regress.h"
 #include "regress_testutils.h"
 
-static struct evhttp *http;
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
 /* set if a test needs to call loopexit on a base */
 static struct event_base *exit_base;
 
 static char const BASIC_REQUEST_BODY[] = "This is funny";
 
-#define IMPL_HTTP_REQUEST_ERROR_CB(name, expecting_error)                    \
-       static void                                                              \
-       http_request_error_cb_with_##name##_(enum evhttp_request_error error,    \
-                                            void *arg)                          \
-       {                                                                        \
-               if (error != expecting_error) {                                                                          \
-                       fprintf(stderr, "FAILED\n");                                                                     \
-                       exit(1);                                                                                                                 \
-               }                                                                                                                                        \
-               test_ok = 1;                                                                                                             \
-       }
-IMPL_HTTP_REQUEST_ERROR_CB(cancel, EVREQ_HTTP_REQUEST_CANCEL)
-
 static void http_basic_cb(struct evhttp_request *req, void *arg);
+static void http_timeout_cb(struct evhttp_request *req, void *arg);
+static void http_large_cb(struct evhttp_request *req, void *arg);
 static void http_chunked_cb(struct evhttp_request *req, void *arg);
 static void http_post_cb(struct evhttp_request *req, void *arg);
 static void http_put_cb(struct evhttp_request *req, void *arg);
@@ -94,11 +86,15 @@ 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);
 
+#define HTTP_BIND_IPV6 1
+#define HTTP_BIND_SSL 2
+#define HTTP_SSL_FILTER 4
 static int
-http_bind(struct evhttp *myhttp, ev_uint16_t *pport, int ipv6)
+http_bind(struct evhttp *myhttp, ev_uint16_t *pport, int mask)
 {
        int port;
        struct evhttp_bound_socket *sock;
+       int ipv6 = mask & HTTP_BIND_IPV6;
 
        if (ipv6)
                sock = evhttp_bind_socket_with_handle(myhttp, "::1", *pport);
@@ -120,19 +116,45 @@ http_bind(struct evhttp *myhttp, ev_uint16_t *pport, int ipv6)
        return 0;
 }
 
+#ifdef EVENT__HAVE_OPENSSL
+static struct bufferevent *
+https_bev(struct event_base *base, void *arg)
+{
+       SSL *ssl = SSL_new(get_ssl_ctx());
+
+       SSL_use_certificate(ssl, ssl_getcert(ssl_getkey()));
+       SSL_use_PrivateKey(ssl, ssl_getkey());
+
+       return bufferevent_openssl_socket_new(
+               base, -1, ssl, BUFFEREVENT_SSL_ACCEPTING,
+               BEV_OPT_CLOSE_ON_FREE);
+}
+#endif
 static struct evhttp *
-http_setup(ev_uint16_t *pport, struct event_base *base, int ipv6)
+http_setup_gencb(ev_uint16_t *pport, struct event_base *base, int mask,
+       void (*cb)(struct evhttp_request *, void *), void *cbarg)
 {
        struct evhttp *myhttp;
 
        /* Try a few different ports */
        myhttp = evhttp_new(base);
 
-       if (http_bind(myhttp, pport, ipv6) < 0)
+       if (http_bind(myhttp, pport, mask) < 0)
                return NULL;
+#ifdef EVENT__HAVE_OPENSSL
+       if (mask & HTTP_BIND_SSL) {
+               init_ssl();
+               evhttp_set_bevcb(myhttp, https_bev, NULL);
+       }
+#endif
+
+       evhttp_set_gencb(myhttp, cb, cbarg);
 
        /* Register a callback for certain types of requests */
-       evhttp_set_cb(myhttp, "/test", http_basic_cb, base);
+       evhttp_set_cb(myhttp, "/test", http_basic_cb, myhttp);
+       evhttp_set_cb(myhttp, "/test nonconformant", http_basic_cb, myhttp);
+       evhttp_set_cb(myhttp, "/timeout", http_timeout_cb, myhttp);
+       evhttp_set_cb(myhttp, "/large", http_large_cb, base);
        evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, base);
        evhttp_set_cb(myhttp, "/streamed", http_chunked_cb, base);
        evhttp_set_cb(myhttp, "/postit", http_post_cb, base);
@@ -145,20 +167,23 @@ http_setup(ev_uint16_t *pport, struct event_base *base, int ipv6)
        evhttp_set_cb(myhttp, "/", http_dispatcher_cb, base);
        return (myhttp);
 }
+static struct evhttp *
+http_setup(ev_uint16_t *pport, struct event_base *base, int mask)
+{ return http_setup_gencb(pport, base, mask, NULL, NULL); }
 
 #ifndef NI_MAXSERV
 #define NI_MAXSERV 1024
 #endif
 
 static evutil_socket_t
-http_connect(const char *address, u_short port)
+http_connect(const char *address, ev_uint16_t port)
 {
        /* Stupid code for connecting */
        struct evutil_addrinfo ai, *aitop;
        char strport[NI_MAXSERV];
 
        struct sockaddr *sa;
-       int slen;
+       size_t slen;
        evutil_socket_t fd;
 
        memset(&ai, 0, sizeof(ai));
@@ -207,6 +232,8 @@ evbuffer_datacmp(struct evbuffer *buf, const char *s)
                return -1;
 
        d = evbuffer_pullup(buf, s_sz);
+       if (!d)
+               d = (unsigned char *)"";
        if ((r = memcmp(d, s, s_sz)))
                return r;
 
@@ -276,6 +303,9 @@ http_writecb(struct bufferevent *bev, void *arg)
 static void
 http_errorcb(struct bufferevent *bev, short what, void *arg)
 {
+       /** For ssl */
+       if (what & BEV_EVENT_CONNECTED)
+               return;
        test_ok = -2;
        event_base_loopexit(arg, NULL);
 }
@@ -289,11 +319,30 @@ http_basic_cb(struct evhttp_request *req, void *arg)
        struct evbuffer *evb = evbuffer_new();
        struct evhttp_connection *evcon;
        int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
-       event_debug(("%s: called\n", __func__));
+
+       TT_BLATHER(("%s: called\n", __func__));
        evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
 
        evcon = evhttp_request_get_connection(req);
-       tt_assert(evhttp_connection_get_server(evcon) == http);
+       tt_assert(evhttp_connection_get_server(evcon) == arg);
+
+       {
+               const struct sockaddr *sa;
+               char addrbuf[128];
+
+               sa = evhttp_connection_get_addr(evcon);
+               tt_assert(sa);
+
+               if (sa->sa_family == AF_INET) {
+                       evutil_format_sockaddr_port_((struct sockaddr *)sa, addrbuf, sizeof(addrbuf));
+                       tt_assert(!strncmp(addrbuf, "127.0.0.1:", strlen("127.0.0.1:")));
+               } else if (sa->sa_family == AF_INET6) {
+                       evutil_format_sockaddr_port_((struct sockaddr *)sa, addrbuf, sizeof(addrbuf));
+                       tt_assert(!strncmp(addrbuf, "[::1]:", strlen("[::1]:")));
+               } else {
+                       tt_fail_msg("Unsupported family");
+               }
+       }
 
        /* For multi-line headers test */
        {
@@ -329,6 +378,33 @@ end:
        evbuffer_free(evb);
 }
 
+static void http_timeout_reply_cb(evutil_socket_t fd, short events, void *arg)
+{
+       struct evhttp_request *req = arg;
+       evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
+       test_ok++;
+}
+static void
+http_timeout_cb(struct evhttp_request *req, void *arg)
+{
+       struct timeval when = { 0, 100 };
+       event_base_once(exit_base, -1, EV_TIMEOUT,
+           http_timeout_reply_cb, req, &when);
+}
+
+static void
+http_large_cb(struct evhttp_request *req, void *arg)
+{
+       struct evbuffer *evb = evbuffer_new();
+       int i;
+
+       for (i = 0; i < 1<<20; ++i) {
+               evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
+       }
+       evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
+       evbuffer_free(evb);
+}
+
 static char const* const CHUNKS[] = {
        "This is funny",
        "but not hilarious.",
@@ -366,11 +442,7 @@ http_chunked_cb(struct evhttp_request *req, void *arg)
 {
        struct timeval when = { 0, 0 };
        struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));
-       event_debug(("%s: called\n", __func__));
-       if (state == NULL) {
-               fprintf(stderr, "Unable to allocate memory in http_chunked_cb()\n");
-               exit(1);
-       }
+       TT_BLATHER(("%s: called\n", __func__));
 
        memset(state, 0, sizeof(struct chunk_req_state));
        state->req = req;
@@ -388,32 +460,65 @@ http_chunked_cb(struct evhttp_request *req, void *arg)
        event_base_once(arg, -1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
 }
 
+static struct bufferevent *
+create_bev(struct event_base *base, evutil_socket_t fd, int ssl_mask, int flags_)
+{
+       int flags = BEV_OPT_DEFER_CALLBACKS | flags_;
+       struct bufferevent *bev = NULL;
+
+       if (!ssl_mask) {
+               bev = bufferevent_socket_new(base, fd, flags);
+       } else {
+#ifdef EVENT__HAVE_OPENSSL
+               SSL *ssl = SSL_new(get_ssl_ctx());
+               if (ssl_mask & HTTP_SSL_FILTER) {
+                       struct bufferevent *underlying =
+                               bufferevent_socket_new(base, fd, flags);
+                       bev = bufferevent_openssl_filter_new(
+                               base, underlying, ssl, BUFFEREVENT_SSL_CONNECTING, flags);
+               } else {
+                       bev = bufferevent_openssl_socket_new(
+                               base, fd, ssl, BUFFEREVENT_SSL_CONNECTING, flags);
+               }
+               bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
+#endif
+       }
+
+       return bev;
+}
+
 static void
-http_complete_write(evutil_socket_t fd, short what, void *arg)
+http_half_writecb(struct bufferevent *bev, void *arg)
 {
-       struct bufferevent *bev = arg;
-       const char *http_request = "host\r\n"
-           "Connection: close\r\n"
-           "\r\n";
-       bufferevent_write(bev, http_request, strlen(http_request));
+       if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
+               if (!test_ok) {
+                       const char http_request[] = "host\r\n"
+                               "Connection: close\r\n"
+                               "\r\n";
+                       bufferevent_write(bev, http_request, strlen(http_request));
+               }
+               /* enable reading of the reply */
+               bufferevent_enable(bev, EV_READ);
+               test_ok++;
+       }
 }
 
 static void
-http_basic_test(void *arg)
+http_basic_test_impl(void *arg, int ssl, const char *request_line)
 {
        struct basic_test_data *data = arg;
-       struct timeval tv;
        struct bufferevent *bev = NULL;
        evutil_socket_t fd;
        const char *http_request;
        ev_uint16_t port = 0, port2 = 0;
+       int server_flags = ssl ? HTTP_BIND_SSL : 0;
+       struct evhttp *http = http_setup(&port, data->base, server_flags);
+       struct evbuffer *out;
 
-       test_ok = 0;
-
-       http = http_setup(&port, data->base, 0);
+       exit_base = data->base;
 
        /* bind to a second socket */
-       if (http_bind(http, &port2, 0) == -1) {
+       if (http_bind(http, &port2, server_flags) == -1) {
                fprintf(stdout, "FAILED (bind)\n");
                exit(1);
        }
@@ -421,56 +526,48 @@ http_basic_test(void *arg)
        fd = http_connect("127.0.0.1", port);
 
        /* Stupid thing to send a request */
-       bev = bufferevent_socket_new(data->base, fd, 0);
-       bufferevent_setcb(bev, http_readcb, http_writecb,
+       bev = create_bev(data->base, fd, ssl, BEV_OPT_CLOSE_ON_FREE);
+       bufferevent_setcb(bev, http_readcb, http_half_writecb,
            http_errorcb, data->base);
+       out = bufferevent_get_output(bev);
 
        /* first half of the http request */
-       http_request =
-           "GET /test HTTP/1.1\r\n"
-           "Host: some";
-
-       bufferevent_write(bev, http_request, strlen(http_request));
-       evutil_timerclear(&tv);
-       tv.tv_usec = 10000;
-       event_base_once(data->base,
-           -1, EV_TIMEOUT, http_complete_write, bev, &tv);
+       evbuffer_add_printf(out,
+           "%s\r\n"
+           "Host: some", request_line);
 
+       test_ok = 0;
        event_base_dispatch(data->base);
-
-       tt_assert(test_ok == 3);
+       tt_int_op(test_ok, ==, 3);
 
        /* connect to the second port */
        bufferevent_free(bev);
-       evutil_closesocket(fd);
 
        fd = http_connect("127.0.0.1", port2);
 
        /* Stupid thing to send a request */
-       bev = bufferevent_socket_new(data->base, fd, 0);
+       bev = create_bev(data->base, fd, ssl, BEV_OPT_CLOSE_ON_FREE);
        bufferevent_setcb(bev, http_readcb, http_writecb,
            http_errorcb, data->base);
+       out = bufferevent_get_output(bev);
 
-       http_request =
-           "GET /test HTTP/1.1\r\n"
+       evbuffer_add_printf(out,
+           "%s\r\n"
            "Host: somehost\r\n"
            "Connection: close\r\n"
-           "\r\n";
-
-       bufferevent_write(bev, http_request, strlen(http_request));
+           "\r\n", request_line);
 
+       test_ok = 0;
        event_base_dispatch(data->base);
-
-       tt_assert(test_ok == 5);
+       tt_int_op(test_ok, ==, 2);
 
        /* Connect to the second port again. This time, send an absolute uri. */
        bufferevent_free(bev);
-       evutil_closesocket(fd);
 
        fd = http_connect("127.0.0.1", port2);
 
        /* Stupid thing to send a request */
-       bev = bufferevent_socket_new(data->base, fd, 0);
+       bev = create_bev(data->base, fd, ssl, BEV_OPT_CLOSE_ON_FREE);
        bufferevent_setcb(bev, http_readcb, http_writecb,
            http_errorcb, data->base);
 
@@ -482,15 +579,19 @@ http_basic_test(void *arg)
 
        bufferevent_write(bev, http_request, strlen(http_request));
 
+       test_ok = 0;
        event_base_dispatch(data->base);
-
-       tt_assert(test_ok == 7);
+       tt_int_op(test_ok, ==, 2);
 
        evhttp_free(http);
- end:
+end:
        if (bev)
                bufferevent_free(bev);
 }
+static void http_basic_test(void *arg)\
+{ http_basic_test_impl(arg, 0, "GET /test HTTP/1.1"); }
+static void http_basic_trailing_space_test(void *arg)
+{ http_basic_test_impl(arg, 0, "GET /test HTTP/1.1 "); }
 
 
 static void
@@ -529,18 +630,10 @@ http_badreq_cb(struct evhttp_request *req, void *arg)
 static void
 http_badreq_errorcb(struct bufferevent *bev, short what, void *arg)
 {
-       event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
+       TT_BLATHER(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
        /* ignore */
 }
 
-#ifndef SHUT_WR
-#ifdef _WIN32
-#define SHUT_WR SD_SEND
-#else
-#define SHUT_WR 1
-#endif
-#endif
-
 static void
 http_badreq_readcb(struct bufferevent *bev, void *arg)
 {
@@ -577,13 +670,13 @@ http_badreq_readcb(struct bufferevent *bev, void *arg)
                evbuffer_drain(bufferevent_get_input(bev), evbuffer_get_length(bufferevent_get_input(bev)));
        }
 
-       shutdown(bufferevent_getfd(bev), SHUT_WR);
+       shutdown(bufferevent_getfd(bev), EVUTIL_SHUT_WR);
 }
 
 static void
 http_badreq_successcb(evutil_socket_t fd, short what, void *arg)
 {
-       event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
+       TT_BLATHER(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
        event_base_loopexit(exit_base, NULL);
 }
 
@@ -593,22 +686,21 @@ http_bad_request_test(void *arg)
        struct basic_test_data *data = arg;
        struct timeval tv;
        struct bufferevent *bev = NULL;
-       evutil_socket_t fd = -1;
+       evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
        const char *http_request;
        ev_uint16_t port=0, port2=0;
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
        test_ok = 0;
        exit_base = data->base;
 
-       http = http_setup(&port, data->base, 0);
-
        /* bind to a second socket */
        if (http_bind(http, &port2, 0) == -1)
                TT_DIE(("Bind socket failed"));
 
        /* NULL request test */
        fd = http_connect("127.0.0.1", port);
-       tt_int_op(fd, >=, 0);
+       tt_assert(fd != EVUTIL_INVALID_SOCKET);
 
        /* Stupid thing to send a request */
        bev = bufferevent_socket_new(data->base, fd, 0);
@@ -621,7 +713,7 @@ http_bad_request_test(void *arg)
 
        bufferevent_write(bev, http_request, strlen(http_request));
 
-       shutdown(fd, SHUT_WR);
+       shutdown(fd, EVUTIL_SHUT_WR);
        timerclear(&tv);
        tv.tv_usec = 10000;
        event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
@@ -640,6 +732,7 @@ http_bad_request_test(void *arg)
 
        /* connect to the second port */
        fd = http_connect("127.0.0.1", port2);
+       tt_assert(fd != EVUTIL_INVALID_SOCKET);
 
        /* Stupid thing to send a request */
        bev = bufferevent_socket_new(data->base, fd, 0);
@@ -700,7 +793,7 @@ http_delete_cb(struct evhttp_request *req, void *arg)
                exit(1);
        }
 
-       event_debug(("%s: called\n", __func__));
+       TT_BLATHER(("%s: called\n", __func__));
        evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
 
        /* allow sending of an empty reply */
@@ -715,17 +808,17 @@ http_delete_test(void *arg)
 {
        struct basic_test_data *data = arg;
        struct bufferevent *bev;
-       evutil_socket_t fd = -1;
+       evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
        const char *http_request;
        ev_uint16_t port = 0;
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
+       exit_base = data->base;
        test_ok = 0;
 
-       http = http_setup(&port, data->base, 0);
-
        tt_assert(http);
        fd = http_connect("127.0.0.1", port);
-       tt_int_op(fd, >=, 0);
+       tt_assert(fd != EVUTIL_INVALID_SOCKET);
 
        /* Stupid thing to send a request */
        bev = bufferevent_socket_new(data->base, fd, 0);
@@ -744,7 +837,7 @@ http_delete_test(void *arg)
 
        bufferevent_free(bev);
        evutil_closesocket(fd);
-       fd = -1;
+       fd = EVUTIL_INVALID_SOCKET;
 
        evhttp_free(http);
 
@@ -771,7 +864,7 @@ http_sent_cb(struct evhttp_request *req, void *arg)
                exit(1);
        }
 
-       event_debug(("%s: called\n", __func__));
+       TT_BLATHER(("%s: called\n", __func__));
 
        ++test_ok;
 }
@@ -783,7 +876,7 @@ http_on_complete_cb(struct evhttp_request *req, void *arg)
 
        evhttp_request_set_on_complete_cb(req, http_sent_cb, (void *)0xDEADBEEF);
 
-       event_debug(("%s: called\n", __func__));
+       TT_BLATHER(("%s: called\n", __func__));
        evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
 
        /* allow sending of an empty reply */
@@ -799,16 +892,16 @@ http_on_complete_test(void *arg)
 {
        struct basic_test_data *data = arg;
        struct bufferevent *bev;
-       evutil_socket_t fd = -1;
+       evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
        const char *http_request;
        ev_uint16_t port = 0;
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
+       exit_base = data->base;
        test_ok = 0;
 
-       http = http_setup(&port, data->base, 0);
-
        fd = http_connect("127.0.0.1", port);
-       tt_int_op(fd, >=, 0);
+       tt_assert(fd != EVUTIL_INVALID_SOCKET);
 
        /* Stupid thing to send a request */
        bev = bufferevent_socket_new(data->base, fd, 0);
@@ -863,14 +956,13 @@ http_allowed_methods_test(void *arg)
        const char *http_request;
        char *result1=NULL, *result2=NULL, *result3=NULL;
        ev_uint16_t port = 0;
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
        exit_base = data->base;
        test_ok = 0;
 
-       http = http_setup(&port, data->base, 0);
-
        fd1 = http_connect("127.0.0.1", port);
-       tt_int_op(fd1, >=, 0);
+       tt_assert(fd1 != EVUTIL_INVALID_SOCKET);
 
        /* GET is out; PATCH is in. */
        evhttp_set_allowed_methods(http, EVHTTP_REQ_PATCH);
@@ -892,7 +984,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);
+       tt_assert(fd2 != EVUTIL_INVALID_SOCKET);
 
        bev2 = bufferevent_socket_new(data->base, fd2, 0);
        bufferevent_enable(bev2, EV_READ|EV_WRITE);
@@ -910,7 +1002,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);
+       tt_assert(fd3 != EVUTIL_INVALID_SOCKET);
 
        bev3 = bufferevent_socket_new(data->base, fd3, 0);
        bufferevent_enable(bev3, EV_READ|EV_WRITE);
@@ -960,26 +1052,49 @@ http_allowed_methods_test(void *arg)
                evutil_closesocket(fd3);
 }
 
+static void http_request_no_action_done(struct evhttp_request *, void *);
 static void http_request_done(struct evhttp_request *, void *);
 static void http_request_empty_done(struct evhttp_request *, void *);
 
 static void
 http_connection_test_(struct basic_test_data *data, int persistent,
-       const char *address, struct evdns_base *dnsbase, int ipv6, int family)
+       const char *address, struct evdns_base *dnsbase, int ipv6, int family,
+       int ssl)
 {
        ev_uint16_t port = 0;
        struct evhttp_connection *evcon = NULL;
        struct evhttp_request *req = NULL;
+       struct evhttp *http;
 
-       test_ok = 0;
+       int mask = 0;
+       if (ipv6)
+               mask |= HTTP_BIND_IPV6;
+       if (ssl)
+               mask |= HTTP_BIND_SSL;
+
+       http = http_setup(&port, data->base, mask);
 
-       http = http_setup(&port, data->base, ipv6);
+       test_ok = 0;
        if (!http && ipv6) {
                tt_skip();
        }
        tt_assert(http);
 
-       evcon = evhttp_connection_base_new(data->base, dnsbase, address, port);
+       if (ssl) {
+#ifdef EVENT__HAVE_OPENSSL
+               SSL *ssl = SSL_new(get_ssl_ctx());
+               struct bufferevent *bev = bufferevent_openssl_socket_new(
+                       data->base, -1, ssl,
+                       BUFFEREVENT_SSL_CONNECTING, BEV_OPT_DEFER_CALLBACKS);
+               bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
+
+               evcon = evhttp_connection_base_bufferevent_new(data->base, dnsbase, bev, address, port);
+#else
+               tt_skip();
+#endif
+       } else {
+               evcon = evhttp_connection_base_new(data->base, dnsbase, address, port);
+       }
        tt_assert(evcon);
        evhttp_connection_set_family(evcon, family);
 
@@ -1055,17 +1170,17 @@ http_connection_test_(struct basic_test_data *data, int persistent,
 static void
 http_connection_test(void *arg)
 {
-       http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC);
+       http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC, 0);
 }
 static void
 http_persist_connection_test(void *arg)
 {
-       http_connection_test_(arg, 1, "127.0.0.1", NULL, 0, AF_UNSPEC);
+       http_connection_test_(arg, 1, "127.0.0.1", NULL, 0, AF_UNSPEC, 0);
 }
 
 static struct regress_dns_server_table search_table[] = {
-       { "localhost", "A", "127.0.0.1", 0 },
-       { NULL, NULL, NULL, 0 }
+       { "localhost", "A", "127.0.0.1", 0, 0 },
+       { NULL, NULL, NULL, 0, 0 }
 };
 
 static void
@@ -1078,6 +1193,7 @@ http_connection_async_test(void *arg)
        struct evdns_base *dns_base = NULL;
        ev_uint16_t portnum = 0;
        char address[64];
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
        exit_base = data->base;
        tt_assert(regress_dnsserver(data->base, &portnum, search_table));
@@ -1092,8 +1208,6 @@ http_connection_async_test(void *arg)
 
        test_ok = 0;
 
-       http = http_setup(&port, data->base, 0);
-
        evcon = evhttp_connection_base_new(data->base, dns_base, "127.0.0.1", port);
        tt_assert(evcon);
 
@@ -1170,9 +1284,10 @@ http_autofree_connection_test(void *arg)
        ev_uint16_t port = 0;
        struct evhttp_connection *evcon = NULL;
        struct evhttp_request *req[2] = { NULL };
+       struct evhttp *http = http_setup(&port, data->base, 0);
+       size_t i;
 
        test_ok = 0;
-       http = http_setup(&port, data->base, 0);
 
        evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
        tt_assert(evcon);
@@ -1185,19 +1300,14 @@ http_autofree_connection_test(void *arg)
        req[1] = evhttp_request_new(http_request_empty_done, data->base);
 
        /* Add the information that we care about */
-       evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Host", "somehost");
-       evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Connection", "close");
-       evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Empty", "itis");
-       evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Host", "somehost");
-       evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Connection", "close");
-       evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Empty", "itis");
+       for (i = 0; i < ARRAY_SIZE(req); ++i) {
+               evhttp_add_header(evhttp_request_get_output_headers(req[i]), "Host", "somehost");
+               evhttp_add_header(evhttp_request_get_output_headers(req[i]), "Connection", "close");
+               evhttp_add_header(evhttp_request_get_output_headers(req[i]), "Empty", "itis");
 
-       /* We give ownership of the request to the connection */
-       if (evhttp_make_request(evcon, req[0], EVHTTP_REQ_GET, "/test") == -1) {
-               tt_abort_msg("couldn't make request");
-       }
-       if (evhttp_make_request(evcon, req[1], EVHTTP_REQ_GET, "/test") == -1) {
-               tt_abort_msg("couldn't make request");
+               if (evhttp_make_request(evcon, req[i], EVHTTP_REQ_GET, "/test") == -1) {
+                       tt_abort_msg("couldn't make request");
+               }
        }
 
        /*
@@ -1208,7 +1318,8 @@ http_autofree_connection_test(void *arg)
        evhttp_connection_free_on_completion(evcon);
        evcon = NULL;
 
-       event_base_dispatch(data->base);
+       for (i = 0; i < ARRAY_SIZE(req); ++i)
+               event_base_dispatch(data->base);
 
        /* at this point, the http server should have no connection */
        tt_assert(TAILQ_FIRST(&http->connections) == NULL);
@@ -1226,25 +1337,116 @@ http_request_never_call(struct evhttp_request *req, void *arg)
        fprintf(stdout, "FAILED\n");
        exit(1);
 }
+static void
+http_failed_request_done(struct evhttp_request *req, void *arg)
+{
+       tt_assert(!req);
+end:
+       event_base_loopexit(arg, NULL);
+}
+#ifndef _WIN32
+static void
+http_timed_out_request_done(struct evhttp_request *req, void *arg)
+{
+       tt_assert(req);
+       tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK);
+end:
+       event_base_loopexit(arg, NULL);
+}
+#endif
+
+static void
+http_request_error_cb_with_cancel(enum evhttp_request_error error, void *arg)
+{
+       if (error != EVREQ_HTTP_REQUEST_CANCEL) {
+               fprintf(stderr, "FAILED\n");
+               exit(1);
+       }
+       test_ok = 1;
 
+       {
+               struct timeval tv;
+               evutil_timerclear(&tv);
+               tv.tv_sec = 0;
+               tv.tv_usec = 500 * 1000;
+               event_base_loopexit(exit_base, &tv);
+       }
+}
 static void
 http_do_cancel(evutil_socket_t fd, short what, void *arg)
 {
        struct evhttp_request *req = arg;
-       struct timeval tv;
-       struct event_base *base;
-       evutil_timerclear(&tv);
-       tv.tv_sec = 0;
-       tv.tv_usec = 500 * 1000;
-
-       base = evhttp_connection_get_base(evhttp_request_get_connection(req));
        evhttp_cancel_request(req);
+       ++test_ok;
+}
+static void
+http_no_write(struct evbuffer *buffer, const struct evbuffer_cb_info *info, void *arg)
+{
+       fprintf(stdout, "FAILED\n");
+       exit(1);
+}
+static void
+http_free_evcons(struct evhttp_connection **evcons)
+{
+       struct evhttp_connection *evcon, **orig = evcons;
 
-       event_base_loopexit(base, &tv);
+       if (!evcons)
+               return;
 
-       ++test_ok;
+       while ((evcon = *evcons++)) {
+               evhttp_connection_free(evcon);
+       }
+       free(orig);
+}
+/** fill the backlog to force server drop packages for timeouts */
+static struct evhttp_connection **
+http_fill_backlog(struct event_base *base, int port)
+{
+#define BACKLOG_SIZE 256
+               struct evhttp_connection **evcon = malloc(sizeof(*evcon) * (BACKLOG_SIZE + 1));
+               int i;
+
+               for (i = 0; i < BACKLOG_SIZE; ++i) {
+                       struct evhttp_request *req;
+
+                       evcon[i] = evhttp_connection_base_new(base, NULL, "127.0.0.1", port);
+                       tt_assert(evcon[i]);
+                       evhttp_connection_set_timeout(evcon[i], 5);
+
+                       req = evhttp_request_new(http_request_never_call, NULL);
+                       tt_assert(req);
+                       tt_int_op(evhttp_make_request(evcon[i], req, EVHTTP_REQ_GET, "/delay"), !=, -1);
+               }
+               evcon[i] = NULL;
+
+               return evcon;
+ end:
+               fprintf(stderr, "Couldn't fill the backlog");
+               return NULL;
 }
 
+enum http_cancel_test_type {
+       BASIC = 1,
+       BY_HOST = 2,
+       NO_NS = 4,
+       INACTIVE_SERVER = 8,
+       SERVER_TIMEOUT = 16,
+       NS_TIMEOUT = 32,
+};
+static struct evhttp_request *
+http_cancel_test_bad_request_new(enum http_cancel_test_type type,
+       struct event_base *base)
+{
+#ifndef _WIN32
+       if (!(type & NO_NS) && (type & SERVER_TIMEOUT))
+               return evhttp_request_new(http_timed_out_request_done, base);
+       else
+#endif
+       if ((type & INACTIVE_SERVER) || (type & NO_NS))
+               return evhttp_request_new(http_failed_request_done, base);
+       else
+               return NULL;
+}
 static void
 http_cancel_test(void *arg)
 {
@@ -1252,24 +1454,76 @@ http_cancel_test(void *arg)
        ev_uint16_t port = 0;
        struct evhttp_connection *evcon = NULL;
        struct evhttp_request *req = NULL;
+       struct bufferevent *bufev = NULL;
        struct timeval tv;
+       struct evdns_base *dns_base = NULL;
+       ev_uint16_t portnum = 0;
+       char address[64];
+       struct evhttp *inactive_http = NULL;
+       struct event_base *inactive_base = NULL;
+       struct evhttp_connection **evcons = NULL;
+       struct event_base *base_to_fill = data->base;
+
+       enum http_cancel_test_type type =
+               (enum http_cancel_test_type)data->setup_data;
+       struct evhttp *http = http_setup(&port, data->base, 0);
+
+       if (type & BY_HOST) {
+               const char *timeout = (type & NS_TIMEOUT) ? "6" : "3";
+
+               tt_assert(regress_dnsserver(data->base, &portnum, search_table));
+
+               dns_base = evdns_base_new(data->base, 0/* init name servers */);
+               tt_assert(dns_base);
+
+               /** XXX: Hack the port to make timeout after resolving */
+               if (type & NO_NS)
+                       ++portnum;
+
+               evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
+               evdns_base_nameserver_ip_add(dns_base, address);
+
+               evdns_base_set_option(dns_base, "timeout:", timeout);
+               evdns_base_set_option(dns_base, "initial-probe-timeout:", timeout);
+               evdns_base_set_option(dns_base, "attempts:", "1");
+       }
 
        exit_base = data->base;
 
        test_ok = 0;
 
-       http = http_setup(&port, data->base, 0);
+       if (type & INACTIVE_SERVER) {
+               port = 0;
+               inactive_base = event_base_new();
+               inactive_http = http_setup(&port, inactive_base, 0);
 
-       evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+               base_to_fill = inactive_base;
+       }
+
+       if (type & SERVER_TIMEOUT)
+               evcons = http_fill_backlog(base_to_fill, port);
+
+       evcon = evhttp_connection_base_new(
+               data->base, dns_base,
+               type & BY_HOST ? "localhost" : "127.0.0.1",
+               port);
+       if (type & INACTIVE_SERVER)
+               evhttp_connection_set_timeout(evcon, 5);
        tt_assert(evcon);
 
+       bufev = evhttp_connection_get_bufferevent(evcon);
+       /* Guarantee that we stack in connect() not after waiting EV_READ after
+        * write() */
+       if (type & SERVER_TIMEOUT)
+               evbuffer_add_cb(bufferevent_get_output(bufev), http_no_write, NULL);
+
        /*
         * At this point, we want to schedule a request to the HTTP
         * server using our make request method.
         */
 
        req = evhttp_request_new(http_request_never_call, NULL);
-       evhttp_request_set_error_cb(req, http_request_error_cb_with_cancel_);
+       evhttp_request_set_error_cb(req, http_request_error_cb_with_cancel);
 
        /* Add the information that we care about */
        evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
@@ -1286,12 +1540,21 @@ http_cancel_test(void *arg)
 
        event_base_dispatch(data->base);
 
-       tt_int_op(test_ok, ==, 3);
+       if (type & NO_NS || type & INACTIVE_SERVER)
+               tt_int_op(test_ok, ==, 2); /** no servers responses */
+       else
+               tt_int_op(test_ok, ==, 3);
 
        /* try to make another request over the same connection */
        test_ok = 0;
 
-       req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+       http_free_evcons(evcons);
+       if (type & SERVER_TIMEOUT)
+               evcons = http_fill_backlog(base_to_fill, port);
+
+       req = http_cancel_test_bad_request_new(type, data->base);
+       if (!req)
+               req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
 
        /* Add the information that we care about */
        evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
@@ -1305,7 +1568,13 @@ http_cancel_test(void *arg)
        /* make another request: request empty reply */
        test_ok = 0;
 
-       req = evhttp_request_new(http_request_empty_done, data->base);
+       http_free_evcons(evcons);
+       if (type & SERVER_TIMEOUT)
+               evcons = http_fill_backlog(base_to_fill, port);
+
+       req = http_cancel_test_bad_request_new(type, data->base);
+       if (!req)
+               req = evhttp_request_new(http_request_empty_done, data->base);
 
        /* Add the information that we care about */
        evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
@@ -1317,10 +1586,27 @@ http_cancel_test(void *arg)
        event_base_dispatch(data->base);
 
  end:
+       http_free_evcons(evcons);
+       if (bufev)
+               evbuffer_remove_cb(bufferevent_get_output(bufev), http_no_write, NULL);
        if (evcon)
                evhttp_connection_free(evcon);
        if (http)
                evhttp_free(http);
+       if (dns_base)
+               evdns_base_free(dns_base, 0);
+       regress_clean_dnsserver();
+       if (inactive_http)
+               evhttp_free(inactive_http);
+       if (inactive_base)
+               event_base_free(inactive_base);
+}
+
+static void
+http_request_no_action_done(struct evhttp_request *req, void *arg)
+{
+       EVUTIL_ASSERT(exit_base);
+       event_base_loopexit(exit_base, NULL);
 }
 
 static void
@@ -1328,6 +1614,11 @@ http_request_done(struct evhttp_request *req, void *arg)
 {
        const char *what = arg;
 
+       if (!req) {
+               fprintf(stderr, "FAILED\n");
+               exit(1);
+       }
+
        if (evhttp_request_get_response_code(req) != HTTP_OK) {
                fprintf(stderr, "FAILED\n");
                exit(1);
@@ -1378,16 +1669,15 @@ http_virtual_host_test(void *arg)
        evutil_socket_t fd;
        struct bufferevent *bev;
        const char *http_request;
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
        exit_base = data->base;
 
-       http = http_setup(&port, data->base, 0);
-
        /* virtual host */
        second = evhttp_new(NULL);
-       evhttp_set_cb(second, "/funnybunny", http_basic_cb, NULL);
+       evhttp_set_cb(second, "/funnybunny", http_basic_cb, http);
        third = evhttp_new(NULL);
-       evhttp_set_cb(third, "/blackcoffee", http_basic_cb, NULL);
+       evhttp_set_cb(third, "/blackcoffee", http_basic_cb, http);
 
        if (evhttp_add_virtual_host(http, "foo.com", second) == -1) {
                tt_abort_msg("Couldn't add vhost");
@@ -1497,6 +1787,7 @@ http_virtual_host_test(void *arg)
 
        /* Now make a raw request with an absolute URI. */
        fd = http_connect("127.0.0.1", port);
+       tt_assert(fd != EVUTIL_INVALID_SOCKET);
 
        /* Stupid thing to send a request */
        bev = bufferevent_socket_new(data->base, fd, 0);
@@ -1532,6 +1823,11 @@ http_virtual_host_test(void *arg)
 static void
 http_request_empty_done(struct evhttp_request *req, void *arg)
 {
+       if (!req) {
+               fprintf(stderr, "FAILED\n");
+               exit(1);
+       }
+
        if (evhttp_request_get_response_code(req) != HTTP_OK) {
                fprintf(stderr, "FAILED\n");
                exit(1);
@@ -1573,7 +1869,7 @@ http_dispatcher_cb(struct evhttp_request *req, void *arg)
 {
 
        struct evbuffer *evb = evbuffer_new();
-       event_debug(("%s: called\n", __func__));
+       TT_BLATHER(("%s: called\n", __func__));
        evbuffer_add_printf(evb, "DISPATCHER_TEST");
 
        evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
@@ -1587,6 +1883,11 @@ http_dispatcher_test_done(struct evhttp_request *req, void *arg)
        struct event_base *base = arg;
        const char *what = "DISPATCHER_TEST";
 
+       if (!req) {
+               fprintf(stderr, "FAILED\n");
+               exit(1);
+       }
+
        if (evhttp_request_get_response_code(req) != HTTP_OK) {
                fprintf(stderr, "FAILED\n");
                exit(1);
@@ -1619,11 +1920,10 @@ http_dispatcher_test(void *arg)
        ev_uint16_t port = 0;
        struct evhttp_connection *evcon = NULL;
        struct evhttp_request *req = NULL;
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
        test_ok = 0;
 
-       http = http_setup(&port, data->base, 0);
-
        evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
        tt_assert(evcon);
 
@@ -1669,11 +1969,10 @@ http_post_test(void *arg)
        ev_uint16_t port = 0;
        struct evhttp_connection *evcon = NULL;
        struct evhttp_request *req = NULL;
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
        test_ok = 0;
 
-       http = http_setup(&port, data->base, 0);
-
        evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
        tt_assert(evcon);
 
@@ -1728,7 +2027,7 @@ void
 http_post_cb(struct evhttp_request *req, void *arg)
 {
        struct evbuffer *evb;
-       event_debug(("%s: called\n", __func__));
+       TT_BLATHER(("%s: called\n", __func__));
 
        /* Yes, we are expecting a post request */
        if (evhttp_request_get_command(req) != EVHTTP_REQ_POST) {
@@ -1809,11 +2108,10 @@ http_put_test(void *arg)
        ev_uint16_t port = 0;
        struct evhttp_connection *evcon = NULL;
        struct evhttp_request *req = NULL;
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
        test_ok = 0;
 
-       http = http_setup(&port, data->base, 0);
-
        evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
        tt_assert(evcon);
 
@@ -1846,7 +2144,7 @@ void
 http_put_cb(struct evhttp_request *req, void *arg)
 {
        struct evbuffer *evb;
-       event_debug(("%s: called\n", __func__));
+       TT_BLATHER(("%s: called\n", __func__));
 
        /* Expecting a PUT request */
        if (evhttp_request_get_command(req) != EVHTTP_REQ_PUT) {
@@ -1932,16 +2230,15 @@ http_failure_test(void *arg)
 {
        struct basic_test_data *data = arg;
        struct bufferevent *bev;
-       evutil_socket_t fd = -1;
+       evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
        const char *http_request;
        ev_uint16_t port = 0;
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
        test_ok = 0;
 
-       http = http_setup(&port, data->base, 0);
-
        fd = http_connect("127.0.0.1", port);
-       tt_int_op(fd, >=, 0);
+       tt_assert(fd != EVUTIL_INVALID_SOCKET);
 
        /* Stupid thing to send a request */
        bev = bufferevent_socket_new(data->base, fd, 0);
@@ -2026,9 +2323,9 @@ http_close_detection_(struct basic_test_data *data, int with_delay)
        struct evhttp_connection *evcon = NULL;
        struct evhttp_request *req = NULL;
        const struct timeval sec_tenth = { 0, 100000 };
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
        test_ok = 0;
-       http = http_setup(&port, data->base, 0);
 
        /* .1 second timeout */
        evhttp_set_timeout_tv(http, &sec_tenth);
@@ -2197,6 +2494,27 @@ http_parse_query_test(void *ptr)
        tt_want(validate_header(&headers, "q3", "") == 0);
        evhttp_clear_headers(&headers);
 
+end:
+       evhttp_clear_headers(&headers);
+}
+static void
+http_parse_query_str_test(void *ptr)
+{
+       struct evkeyvalq headers;
+       int r;
+
+       TAILQ_INIT(&headers);
+
+       r = evhttp_parse_query_str("http://www.test.com/?q=test", &headers);
+       tt_assert(evhttp_find_header(&headers, "q") == NULL);
+       tt_int_op(r, ==, 0);
+       evhttp_clear_headers(&headers);
+
+       r = evhttp_parse_query_str("q=test", &headers);
+       tt_want(validate_header(&headers, "q", "test") == 0);
+       tt_int_op(r, ==, 0);
+       evhttp_clear_headers(&headers);
+
 end:
        evhttp_clear_headers(&headers);
 }
@@ -2702,14 +3020,15 @@ http_base_test(void *ptr)
        evutil_socket_t fd;
        const char *http_request;
        ev_uint16_t port = 0;
-
+       struct evhttp *http;
+       
        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);
+       tt_assert(fd != EVUTIL_INVALID_SOCKET);
 
        /* Stupid thing to send a request */
        bev = bufferevent_socket_new(base, fd, 0);
@@ -2754,6 +3073,10 @@ http_incomplete_readcb(struct bufferevent *bev, void *arg)
 static void
 http_incomplete_errorcb(struct bufferevent *bev, short what, void *arg)
 {
+       /** For ssl */
+       if (what & BEV_EVENT_CONNECTED)
+               return;
+
        if (what == (BEV_EVENT_READING|BEV_EVENT_EOF))
                test_ok++;
        else
@@ -2767,7 +3090,7 @@ http_incomplete_writecb(struct bufferevent *bev, void *arg)
        if (arg != NULL) {
                evutil_socket_t fd = *(evutil_socket_t *)arg;
                /* terminate the write side to simulate EOF */
-               shutdown(fd, SHUT_WR);
+               shutdown(fd, EVUTIL_SHUT_WR);
        }
        if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
                /* enable reading of the reply */
@@ -2777,26 +3100,25 @@ http_incomplete_writecb(struct bufferevent *bev, void *arg)
 }
 
 static void
-http_incomplete_test_(struct basic_test_data *data, int use_timeout)
+http_incomplete_test_(struct basic_test_data *data, int use_timeout, int ssl)
 {
        struct bufferevent *bev;
        evutil_socket_t fd;
        const char *http_request;
        ev_uint16_t port = 0;
        struct timeval tv_start, tv_end;
+       struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
 
        exit_base = data->base;
-
        test_ok = 0;
 
-       http = http_setup(&port, data->base, 0);
        evhttp_set_timeout(http, 1);
 
        fd = http_connect("127.0.0.1", port);
-       tt_int_op(fd, >=, 0);
+       tt_assert(fd != EVUTIL_INVALID_SOCKET);
 
        /* Stupid thing to send a request */
-       bev = bufferevent_socket_new(data->base, fd, 0);
+       bev = create_bev(data->base, fd, ssl, 0);
        bufferevent_setcb(bev,
            http_incomplete_readcb, http_incomplete_writecb,
            http_incomplete_errorcb, use_timeout ? NULL : &fd);
@@ -2817,7 +3139,7 @@ http_incomplete_test_(struct basic_test_data *data, int use_timeout)
        bufferevent_free(bev);
        if (use_timeout) {
                evutil_closesocket(fd);
-               fd = -1;
+               fd = EVUTIL_INVALID_SOCKET;
        }
 
        evhttp_free(http);
@@ -2834,16 +3156,11 @@ http_incomplete_test_(struct basic_test_data *data, int use_timeout)
        if (fd >= 0)
                evutil_closesocket(fd);
 }
-static void
-http_incomplete_test(void *arg)
-{
-       http_incomplete_test_(arg, 0);
-}
-static void
-http_incomplete_timeout_test(void *arg)
-{
-       http_incomplete_test_(arg, 1);
-}
+static void http_incomplete_test(void *arg)
+{ http_incomplete_test_(arg, 0, 0); }
+static void http_incomplete_timeout_test(void *arg)
+{ http_incomplete_test_(arg, 1, 0); }
+
 
 /*
  * the server is going to reply with chunked data.
@@ -2860,7 +3177,11 @@ http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
 {
        struct evhttp_request *req = NULL;
 
-       if (!test_ok)
+       /** SSL */
+       if (what & BEV_EVENT_CONNECTED)
+               return;
+
+       if (!test_ok)
                goto out;
 
        test_ok = -1;
@@ -2994,10 +3315,10 @@ http_chunked_request_done(struct evhttp_request *req, void *arg)
 }
 
 static void
-http_chunk_out_test(void *arg)
+http_chunk_out_test_impl(void *arg, int ssl)
 {
        struct basic_test_data *data = arg;
-       struct bufferevent *bev;
+       struct bufferevent *bev = NULL;
        evutil_socket_t fd;
        const char *http_request;
        ev_uint16_t port = 0;
@@ -3005,16 +3326,16 @@ http_chunk_out_test(void *arg)
        struct evhttp_connection *evcon = NULL;
        struct evhttp_request *req = NULL;
        int i;
+       struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
 
        exit_base = data->base;
        test_ok = 0;
 
-       http = http_setup(&port, data->base, 0);
-
        fd = http_connect("127.0.0.1", port);
+       tt_assert(fd != EVUTIL_INVALID_SOCKET);
 
        /* Stupid thing to send a request */
-       bev = bufferevent_socket_new(data->base, fd, 0);
+       bev = create_bev(data->base, fd, ssl, BEV_OPT_CLOSE_ON_FREE);
        bufferevent_setcb(bev,
            http_chunked_readcb, http_chunked_writecb,
            http_chunked_errorcb, data->base);
@@ -3032,6 +3353,7 @@ http_chunk_out_test(void *arg)
        event_base_dispatch(data->base);
 
        bufferevent_free(bev);
+       bev = NULL;
 
        evutil_gettimeofday(&tv_end, NULL);
        evutil_timersub(&tv_end, &tv_start, &tv_end);
@@ -3041,20 +3363,21 @@ http_chunk_out_test(void *arg)
        tt_int_op(test_ok, ==, 2);
 
        /* now try again with the regular connection object */
-       evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+       bev = create_bev(data->base, -1, ssl, BEV_OPT_CLOSE_ON_FREE);
+       evcon = evhttp_connection_base_bufferevent_new(
+               data->base, NULL, bev, "127.0.0.1", port);
        tt_assert(evcon);
 
        /* make two requests to check the keepalive behavior */
        for (i = 0; i < 2; i++) {
                test_ok = 0;
-               req = evhttp_request_new(http_chunked_request_done,data->base);
+               req = evhttp_request_new(http_chunked_request_done, data->base);
 
                /* Add the information that we care about */
                evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
 
                /* We give ownership of the request to the connection */
-               if (evhttp_make_request(evcon, req,
-                       EVHTTP_REQ_GET, "/chunked") == -1) {
+               if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/chunked") == -1) {
                        tt_abort_msg("Couldn't make request");
                }
 
@@ -3069,21 +3392,25 @@ http_chunk_out_test(void *arg)
        if (http)
                evhttp_free(http);
 }
+static void http_chunk_out_test(void *arg)
+{ http_chunk_out_test_impl(arg, 0); }
 
 static void
-http_stream_out_test(void *arg)
+http_stream_out_test_impl(void *arg, int ssl)
 {
        struct basic_test_data *data = arg;
        ev_uint16_t port = 0;
        struct evhttp_connection *evcon = NULL;
        struct evhttp_request *req = NULL;
+       struct bufferevent *bev;
+       struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
 
        test_ok = 0;
        exit_base = data->base;
 
-       http = http_setup(&port, data->base, 0);
-
-       evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+       bev = create_bev(data->base, -1, ssl, 0);
+       evcon = evhttp_connection_base_bufferevent_new(
+               data->base, NULL, bev, "127.0.0.1", port);
        tt_assert(evcon);
 
        /*
@@ -3111,6 +3438,8 @@ http_stream_out_test(void *arg)
        if (http)
                evhttp_free(http);
 }
+static void http_stream_out_test(void *arg)
+{ http_stream_out_test_impl(arg, 0); }
 
 static void
 http_stream_in_chunk(struct evhttp_request *req, void *arg)
@@ -3147,9 +3476,9 @@ http_stream_in_test_(struct basic_test_data *data, char const *url,
        struct evbuffer *reply = evbuffer_new();
        struct evhttp_request *req = NULL;
        ev_uint16_t port = 0;
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
        exit_base = data->base;
-       http = http_setup(&port, data->base, 0);
 
        evcon = evhttp_connection_base_new(data->base, NULL,"127.0.0.1", port);
        tt_assert(evcon);
@@ -3219,8 +3548,7 @@ http_stream_in_cancel_test(void *arg)
        struct evhttp_connection *evcon;
        struct evhttp_request *req = NULL;
        ev_uint16_t port = 0;
-
-       http = http_setup(&port, data->base, 0);
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
        evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
        tt_assert(evcon);
@@ -3245,65 +3573,69 @@ http_stream_in_cancel_test(void *arg)
 static void
 http_connection_fail_done(struct evhttp_request *req, void *arg)
 {
-       struct evhttp_connection *evcon = arg;
-       struct event_base *base = evhttp_connection_get_base(evcon);
+       struct evhttp_connection *evcon = arg;
+       struct event_base *base = evhttp_connection_get_base(evcon);
 
-       /* An ENETUNREACH error results in an unrecoverable
-        * evhttp_connection error (see evhttp_connection_fail_()).  The
-        * connection will be reset, and the user will be notified with a NULL
-        * req parameter. */
-       tt_assert(!req);
+       /* An ENETUNREACH error results in an unrecoverable
+        * evhttp_connection error (see evhttp_connection_fail_()).  The
+        * connection will be reset, and the user will be notified with a NULL
+        * req parameter. */
+       tt_assert(!req);
 
-       evhttp_connection_free(evcon);
+       evhttp_connection_free(evcon);
 
-       test_ok = 1;
+       test_ok = 1;
 
  end:
-       event_base_loopexit(base, NULL);
+       event_base_loopexit(base, NULL);
 }
 
 /* Test unrecoverable evhttp_connection errors by generating an ENETUNREACH
  * error on connection. */
 static void
-http_connection_fail_test(void *arg)
+http_connection_fail_test_impl(void *arg, int ssl)
 {
-       struct basic_test_data *data = arg;
-       ev_uint16_t port = 0;
-       struct evhttp_connection *evcon = NULL;
-       struct evhttp_request *req = NULL;
+       struct basic_test_data *data = arg;
+       ev_uint16_t port = 0;
+       struct evhttp_connection *evcon = NULL;
+       struct evhttp_request *req = NULL;
+       struct bufferevent *bev;
+       struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
 
-       exit_base = data->base;
-       test_ok = 0;
+       exit_base = data->base;
+       test_ok = 0;
 
-       /* auto detect a port */
-       http = http_setup(&port, data->base, 0);
-       evhttp_free(http);
-       http = NULL;
+       /* auto detect a port */
+       evhttp_free(http);
 
-       /* Pick an unroutable address.  This administratively scoped multicast
-       * address should do when working with TCP. */
-       evcon = evhttp_connection_base_new(data->base, NULL, "239.10.20.30", 80);
-       tt_assert(evcon);
+       bev = create_bev(data->base, -1, ssl, 0);
+       /* Pick an unroutable address. This administratively scoped multicast
+        * address should do when working with TCP. */
+       evcon = evhttp_connection_base_bufferevent_new(
+               data->base, NULL, bev, "239.10.20.30", 80);
+       tt_assert(evcon);
 
-       /*
-        * At this point, we want to schedule an HTTP GET request
-        * server using our make request method.
-        */
+       /*
+        * At this point, we want to schedule an HTTP GET request
+        * server using our make request method.
+        */
 
-       req = evhttp_request_new(http_connection_fail_done, evcon);
-       tt_assert(req);
+       req = evhttp_request_new(http_connection_fail_done, evcon);
+       tt_assert(req);
 
-       if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/") == -1) {
-               tt_abort_msg("Couldn't make request");
-       }
+       if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/") == -1) {
+               tt_abort_msg("Couldn't make request");
+       }
 
-       event_base_dispatch(data->base);
+       event_base_dispatch(data->base);
 
-       tt_int_op(test_ok, ==, 1);
+       tt_int_op(test_ok, ==, 1);
 
  end:
-        ;
+       ;
 }
+static void http_connection_fail_test(void *arg)
+{ http_connection_fail_test_impl(arg, 0); }
 
 static void
 http_connection_retry_done(struct evhttp_request *req, void *arg)
@@ -3321,33 +3653,85 @@ http_connection_retry_done(struct evhttp_request *req, void *arg)
        event_base_loopexit(arg,NULL);
 }
 
+struct http_server
+{
+       ev_uint16_t port;
+       int ssl;
+       struct evhttp *http;
+};
 static struct event_base *http_make_web_server_base=NULL;
 static void
 http_make_web_server(evutil_socket_t fd, short what, void *arg)
 {
-       ev_uint16_t port = *(ev_uint16_t*)arg;
-       http = http_setup(&port, http_make_web_server_base, 0);
+       struct http_server *hs = (struct http_server *)arg;
+       hs->http = http_setup(&hs->port, http_make_web_server_base, hs->ssl ? HTTP_BIND_SSL : 0);
 }
 
 static void
-http_connection_retry_test(void *arg)
+http_simple_test_impl(void *arg, int ssl, int dirty, const char *uri)
+{
+       struct basic_test_data *data = arg;
+       struct evhttp_connection *evcon = NULL;
+       struct evhttp_request *req = NULL;
+       struct bufferevent *bev;
+       struct http_server hs = { 0, ssl, NULL, };
+       struct evhttp *http = http_setup(&hs.port, data->base, ssl ? HTTP_BIND_SSL : 0);
+
+       exit_base = data->base;
+       test_ok = 0;
+
+       bev = create_bev(data->base, -1, ssl, 0);
+#ifdef EVENT__HAVE_OPENSSL
+       bufferevent_openssl_set_allow_dirty_shutdown(bev, dirty);
+#endif
+
+       evcon = evhttp_connection_base_bufferevent_new(
+               data->base, NULL, bev, "127.0.0.1", hs.port);
+       tt_assert(evcon);
+       evhttp_connection_set_local_address(evcon, "127.0.0.1");
+
+       req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
+       tt_assert(req);
+
+       if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, uri) == -1)
+               tt_abort_msg("Couldn't make request");
+
+       event_base_dispatch(data->base);
+       tt_int_op(test_ok, ==, 1);
+
+ end:
+       if (evcon)
+               evhttp_connection_free(evcon);
+       if (http)
+               evhttp_free(http);
+}
+static void http_simple_test(void *arg)
+{ http_simple_test_impl(arg, 0, 0, "/test"); }
+static void http_simple_nonconformant_test(void *arg)
+{ http_simple_test_impl(arg, 0, 0, "/test nonconformant"); }
+
+static void
+http_connection_retry_test_basic(void *arg, const char *addr, struct evdns_base *dns_base, int ssl)
 {
        struct basic_test_data *data = arg;
-       ev_uint16_t port = 0;
        struct evhttp_connection *evcon = NULL;
        struct evhttp_request *req = NULL;
        struct timeval tv, tv_start, tv_end;
+       struct bufferevent *bev;
+       struct http_server hs = { 0, ssl, NULL, };
+       struct evhttp *http = http_setup(&hs.port, data->base, ssl ? HTTP_BIND_SSL : 0);
 
        exit_base = data->base;
        test_ok = 0;
 
        /* auto detect a port */
-       http = http_setup(&port, data->base, 0);
        evhttp_free(http);
-       http = NULL;
 
-       evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+       bev = create_bev(data->base, -1, ssl, 0);
+       evcon = evhttp_connection_base_bufferevent_new(data->base, dns_base, bev, addr, hs.port);
        tt_assert(evcon);
+       if (dns_base)
+               tt_assert(!evhttp_connection_set_flags(evcon, EVHTTP_CON_REUSE_CONNECTED_ADDR));
 
        evhttp_connection_set_timeout(evcon, 1);
        /* also bind to local host */
@@ -3381,6 +3765,9 @@ http_connection_retry_test(void *arg)
         * now test the same but with retries
         */
        test_ok = 0;
+       /** Shutdown dns server, to test conn_address reusing */
+       if (dns_base)
+               regress_clean_dnsserver();
 
        {
                const struct timeval tv_timeout = { 0, 500000 };
@@ -3436,7 +3823,7 @@ http_connection_retry_test(void *arg)
        evutil_timerclear(&tv);
        tv.tv_usec = 200000;
        http_make_web_server_base = data->base;
-       event_base_once(data->base, -1, EV_TIMEOUT, http_make_web_server, &port, &tv);
+       event_base_once(data->base, -1, EV_TIMEOUT, http_make_web_server, &hs, &tv);
 
        evutil_gettimeofday(&tv_start, NULL);
        event_base_dispatch(data->base);
@@ -3450,9 +3837,45 @@ http_connection_retry_test(void *arg)
        if (evcon)
                evhttp_connection_free(evcon);
        if (http)
-               evhttp_free(http);
+               evhttp_free(hs.http);
 }
 
+static void
+http_connection_retry_conn_address_test_impl(void *arg, int ssl)
+{
+       struct basic_test_data *data = arg;
+       ev_uint16_t portnum = 0;
+       struct evdns_base *dns_base = NULL;
+       char address[64];
+
+       tt_assert(regress_dnsserver(data->base, &portnum, search_table));
+       dns_base = evdns_base_new(data->base, 0/* init name servers */);
+       tt_assert(dns_base);
+
+       /* Add ourself as the only nameserver, and make sure we really are
+        * the only nameserver. */
+       evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
+       evdns_base_nameserver_ip_add(dns_base, address);
+
+       http_connection_retry_test_basic(arg, "localhost", dns_base, ssl);
+
+ end:
+       if (dns_base)
+               evdns_base_free(dns_base, 0);
+       /** dnsserver will be cleaned in http_connection_retry_test_basic() */
+}
+static void http_connection_retry_conn_address_test(void *arg)
+{ http_connection_retry_conn_address_test_impl(arg, 0); }
+
+static void
+http_connection_retry_test_impl(void *arg, int ssl)
+{
+       http_connection_retry_test_basic(arg, "127.0.0.1", NULL, ssl);
+}
+static void
+http_connection_retry_test(void *arg)
+{ http_connection_retry_test_impl(arg, 0); }
+
 static void
 http_primitives(void *ptr)
 {
@@ -3470,11 +3893,11 @@ http_primitives(void *ptr)
 
        http = evhttp_new(NULL);
        tt_assert(http);
-       tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, 0);
-       tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, -1);
+       tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, http), ==, 0);
+       tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, http), ==, -1);
        tt_int_op(evhttp_del_cb(http, "/test"), ==, 0);
        tt_int_op(evhttp_del_cb(http, "/test"), ==, -1);
-       tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, 0);
+       tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, http), ==, 0);
 
  end:
        if (escaped)
@@ -3488,19 +3911,18 @@ http_multi_line_header_test(void *arg)
 {
        struct basic_test_data *data = arg;
        struct bufferevent *bev= NULL;
-       evutil_socket_t fd = -1;
+       evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
        const char *http_start_request;
        ev_uint16_t port = 0;
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
+       exit_base = data->base;
        test_ok = 0;
 
-       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);
+       tt_assert(fd != EVUTIL_INVALID_SOCKET);
 
        /* Stupid thing to send a request */
        bev = bufferevent_socket_new(data->base, fd, 0);
@@ -3556,11 +3978,10 @@ http_negative_content_length_test(void *arg)
        ev_uint16_t port = 0;
        struct evhttp_connection *evcon = NULL;
        struct evhttp_request *req = NULL;
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
        test_ok = 0;
 
-       http = http_setup(&port, data->base, 0);
-
        evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
        tt_assert(evcon);
 
@@ -3597,7 +4018,6 @@ http_data_length_constraints_test_done(struct evhttp_request *req, void *arg)
 end:
        event_base_loopexit(arg, NULL);
 }
-
 static void
 http_large_entity_test_done(struct evhttp_request *req, void *arg)
 {
@@ -3606,41 +4026,56 @@ http_large_entity_test_done(struct evhttp_request *req, void *arg)
 end:
        event_base_loopexit(arg, NULL);
 }
+static void
+http_expectation_failed_done(struct evhttp_request *req, void *arg)
+{
+       tt_assert(req);
+       tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_EXPECTATIONFAILED);
+end:
+       event_base_loopexit(arg, NULL);
+}
 
 static void
-http_data_length_constraints_test(void *arg)
+http_data_length_constraints_test_impl(void *arg, int read_on_write_error)
 {
        struct basic_test_data *data = arg;
        ev_uint16_t port = 0;
        struct evhttp_connection *evcon = NULL;
        struct evhttp_request *req = NULL;
-       char long_str[8192];
+       char *long_str = NULL;
+       const size_t continue_size = 1<<20;
+       const size_t size = (1<<20) * 3;
+       void (*cb)(struct evhttp_request *, void *);
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
        test_ok = 0;
+       cb = http_failed_request_done;
+       if (read_on_write_error)
+               cb = http_data_length_constraints_test_done;
+
+       tt_assert(continue_size < size);
 
-       http = http_setup(&port, data->base, 0);
+       long_str = malloc(size);
+       memset(long_str, 'a', size);
+       long_str[size - 1] = '\0';
 
+       TT_BLATHER(("Creating connection to :%i", port));
        evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
        tt_assert(evcon);
 
-       /* also bind to local host */
+       if (read_on_write_error)
+               tt_assert(!evhttp_connection_set_flags(evcon, EVHTTP_CON_READ_ON_WRITE_ERROR));
+
        evhttp_connection_set_local_address(evcon, "127.0.0.1");
 
-       /*
-        * At this point, we want to schedule an HTTP GET request
-        * server using our make request method.
-        */
+       evhttp_set_max_headers_size(http, size - 1);
+       TT_BLATHER(("Set max header size %zu", size - 1));
 
        req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
        tt_assert(req);
-
-       memset(long_str, 'a', 8192);
-       long_str[8191] = '\0';
-       /* Add the information that we care about */
-       evhttp_set_max_headers_size(http, 8191);
        evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
        evhttp_add_header(evhttp_request_get_output_headers(req), "Longheader", long_str);
-
+       TT_BLATHER(("GET /?arg=val"));
        if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
                tt_abort_msg("Couldn't make request");
        }
@@ -3649,17 +4084,22 @@ http_data_length_constraints_test(void *arg)
        req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
        tt_assert(req);
        evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
-
        /* GET /?arg=verylongvalue HTTP/1.1 */
+       TT_BLATHER(("GET %s", long_str));
        if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, long_str) == -1) {
                tt_abort_msg("Couldn't make request");
        }
        event_base_dispatch(data->base);
 
-       evhttp_set_max_body_size(http, 8190);
-       req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
+       evhttp_set_max_body_size(http, size - 2);
+       TT_BLATHER(("Set body header size %zu", size - 2));
+
+       if (read_on_write_error)
+               cb = http_large_entity_test_done;
+       req = evhttp_request_new(cb, data->base);
        evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
        evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
+       TT_BLATHER(("POST /"));
        if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
                tt_abort_msg("Couldn't make request");
        }
@@ -3669,6 +4109,89 @@ http_data_length_constraints_test(void *arg)
        evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
        evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
        evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
+       TT_BLATHER(("POST / (Expect: 100-continue, http_large_entity_test_done)"));
+       if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
+               tt_abort_msg("Couldn't make request");
+       }
+       event_base_dispatch(data->base);
+
+       long_str[continue_size] = '\0';
+
+       req = evhttp_request_new(http_dispatcher_test_done, data->base);
+       evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+       evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
+       evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
+       TT_BLATHER(("POST / (Expect: 100-continue, http_dispatcher_test_done)"));
+       if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
+               tt_abort_msg("Couldn't make request");
+       }
+       event_base_dispatch(data->base);
+
+       if (read_on_write_error)
+               cb = http_expectation_failed_done;
+       req = evhttp_request_new(cb, data->base);
+       evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+       evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "101-continue");
+       evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
+       TT_BLATHER(("POST / (Expect: 101-continue)"));
+       if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
+               tt_abort_msg("Couldn't make request");
+       }
+       event_base_dispatch(data->base);
+
+       test_ok = 1;
+ end:
+       if (evcon)
+               evhttp_connection_free(evcon);
+       if (http)
+               evhttp_free(http);
+       if (long_str)
+               free(long_str);
+}
+static void http_data_length_constraints_test(void *arg)
+{ http_data_length_constraints_test_impl(arg, 0); }
+static void http_read_on_write_error_test(void *arg)
+{ http_data_length_constraints_test_impl(arg, 1); }
+
+static void
+http_lingering_close_test_impl(void *arg, int lingering)
+{
+       struct basic_test_data *data = arg;
+       ev_uint16_t port = 0;
+       struct evhttp_connection *evcon = NULL;
+       struct evhttp_request *req = NULL;
+       char *long_str = NULL;
+       size_t size = (1<<20) * 3;
+       void (*cb)(struct evhttp_request *, void *);
+       struct evhttp *http = http_setup(&port, data->base, 0);
+
+       test_ok = 0;
+
+       if (lingering)
+               tt_assert(!evhttp_set_flags(http, EVHTTP_SERVER_LINGERING_CLOSE));
+       evhttp_set_max_body_size(http, size / 2);
+
+       evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+       tt_assert(evcon);
+       evhttp_connection_set_local_address(evcon, "127.0.0.1");
+
+       /*
+        * At this point, we want to schedule an HTTP GET request
+        * server using our make request method.
+        */
+
+       long_str = malloc(size);
+       memset(long_str, 'a', size);
+       long_str[size - 1] = '\0';
+
+       if (lingering)
+               cb = http_large_entity_test_done;
+       else
+               cb = http_failed_request_done;
+       req = evhttp_request_new(cb, data->base);
+       tt_assert(req);
+       evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+       evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
        if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
                tt_abort_msg("Couldn't make request");
        }
@@ -3680,7 +4203,13 @@ http_data_length_constraints_test(void *arg)
                evhttp_connection_free(evcon);
        if (http)
                evhttp_free(http);
+       if (long_str)
+               free(long_str);
 }
+static void http_non_lingering_close_test(void *arg)
+{ http_lingering_close_test_impl(arg, 0); }
+static void http_lingering_close_test(void *arg)
+{ http_lingering_close_test_impl(arg, 1); }
 
 /*
  * Testing client reset of server chunked connections
@@ -3692,6 +4221,7 @@ struct terminate_state {
        struct bufferevent *bev;
        evutil_socket_t fd;
        int gotclosecb: 1;
+       int oneshot: 1;
 };
 
 static void
@@ -3699,7 +4229,10 @@ terminate_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
 {
        struct terminate_state *state = arg;
        struct evbuffer *evb;
-       struct timeval tv;
+
+       if (!state->req) {
+               return;
+       }
 
        if (evhttp_request_get_connection(state->req) == NULL) {
                test_ok = 1;
@@ -3713,11 +4246,14 @@ terminate_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
        evhttp_send_reply_chunk(state->req, evb);
        evbuffer_free(evb);
 
-       tv.tv_sec = 0;
-       tv.tv_usec = 3000;
-       EVUTIL_ASSERT(state);
-       EVUTIL_ASSERT(state->base);
-       event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
+       if (!state->oneshot) {
+               struct timeval tv;
+               tv.tv_sec = 0;
+               tv.tv_usec = 3000;
+               EVUTIL_ASSERT(state);
+               EVUTIL_ASSERT(state->base);
+               event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
+       }
 }
 
 static void
@@ -3725,6 +4261,13 @@ terminate_chunked_close_cb(struct evhttp_connection *evcon, void *arg)
 {
        struct terminate_state *state = arg;
        state->gotclosecb = 1;
+
+       /** TODO: though we can do this unconditionally */
+       if (state->oneshot) {
+               evhttp_request_free(state->req);
+               state->req = NULL;
+               event_base_loopexit(state->base,NULL);
+       }
 }
 
 static void
@@ -3764,24 +4307,25 @@ terminate_readcb(struct bufferevent *bev, void *arg)
 
 
 static void
-http_terminate_chunked_test(void *arg)
+http_terminate_chunked_test_impl(void *arg, int oneshot)
 {
        struct basic_test_data *data = arg;
        struct bufferevent *bev = NULL;
        struct timeval tv;
        const char *http_request;
        ev_uint16_t port = 0;
-       evutil_socket_t fd = -1;
+       evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
        struct terminate_state terminate_state;
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
        test_ok = 0;
 
-       http = http_setup(&port, data->base, 0);
        evhttp_del_cb(http, "/test");
        tt_assert(evhttp_set_cb(http, "/test",
                terminate_chunked_cb, &terminate_state) == 0);
 
        fd = http_connect("127.0.0.1", port);
+       tt_assert(fd != EVUTIL_INVALID_SOCKET);
 
        /* Stupid thing to send a request */
        bev = bufferevent_socket_new(data->base, fd, 0);
@@ -3793,6 +4337,7 @@ http_terminate_chunked_test(void *arg)
        terminate_state.fd = fd;
        terminate_state.bev = bev;
        terminate_state.gotclosecb = 0;
+       terminate_state.oneshot = oneshot;
 
        /* first half of the http request */
        http_request =
@@ -3816,10 +4361,20 @@ http_terminate_chunked_test(void *arg)
        if (http)
                evhttp_free(http);
 }
+static void
+http_terminate_chunked_test(void *arg)
+{
+       http_terminate_chunked_test_impl(arg, 0);
+}
+static void
+http_terminate_chunked_oneshot_test(void *arg)
+{
+       http_terminate_chunked_test_impl(arg, 1);
+}
 
 static struct regress_dns_server_table ipv6_search_table[] = {
-       { "localhost", "AAAA", "::1", 0 },
-       { NULL, NULL, NULL, 0 }
+       { "localhost", "AAAA", "::1", 0, 0 },
+       { NULL, NULL, NULL, 0, 0 }
 };
 
 static void
@@ -3841,7 +4396,7 @@ http_ipv6_for_domain_test_impl(void *arg, int family)
        evdns_base_nameserver_ip_add(dns_base, address);
 
        http_connection_test_(arg, 0 /* not persistent */, "localhost", dns_base,
-               1 /* ipv6 */, family);
+               1 /* ipv6 */, family, 0);
 
  end:
        if (dns_base)
@@ -3884,12 +4439,11 @@ http_get_addr_test(void *arg)
        ev_uint16_t port = 0;
        struct evhttp_connection *evcon = NULL;
        struct evhttp_request *req = NULL;
+       struct evhttp *http = http_setup(&port, data->base, 0);
 
        test_ok = 0;
        exit_base = data->base;
 
-       http = http_setup(&port, data->base, 0);
-
        evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
        tt_assert(evcon);
        evhttp_connection_set_closecb(evcon, http_request_get_addr_on_close, arg);
@@ -3920,12 +4474,12 @@ http_get_addr_test(void *arg)
 static void
 http_set_family_test(void *arg)
 {
-       http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC);
+       http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC, 0);
 }
 static void
 http_set_family_ipv4_test(void *arg)
 {
-       http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_INET);
+       http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_INET, 0);
 }
 static void
 http_set_family_ipv6_test(void *arg)
@@ -3933,23 +4487,244 @@ http_set_family_ipv6_test(void *arg)
        http_ipv6_for_domain_test_impl(arg, AF_INET6);
 }
 
+static void
+http_write_during_read(evutil_socket_t fd, short what, void *arg)
+{
+       struct bufferevent *bev = arg;
+       struct timeval tv;
+
+       bufferevent_write(bev, "foobar", strlen("foobar"));
+
+       evutil_timerclear(&tv);
+       tv.tv_sec = 1;
+       event_base_loopexit(exit_base, &tv);
+}
+static void
+http_write_during_read_test_impl(void *arg, int ssl)
+{
+       struct basic_test_data *data = arg;
+       ev_uint16_t port = 0;
+       struct bufferevent *bev = NULL;
+       struct timeval tv;
+       evutil_socket_t fd;
+       const char *http_request;
+       struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
+
+       test_ok = 0;
+       exit_base = data->base;
+
+       fd = http_connect("127.0.0.1", port);
+       tt_assert(fd != EVUTIL_INVALID_SOCKET);
+       bev = create_bev(data->base, fd, 0, 0);
+       bufferevent_setcb(bev, NULL, NULL, NULL, data->base);
+       bufferevent_disable(bev, EV_READ);
+
+       http_request =
+           "GET /large HTTP/1.1\r\n"
+           "Host: somehost\r\n"
+           "\r\n";
+
+       bufferevent_write(bev, http_request, strlen(http_request));
+       evutil_timerclear(&tv);
+       tv.tv_usec = 10000;
+       event_base_once(data->base, -1, EV_TIMEOUT, http_write_during_read, bev, &tv);
+
+       event_base_dispatch(data->base);
+
+end:
+       if (bev)
+               bufferevent_free(bev);
+       if (http)
+               evhttp_free(http);
+}
+static void http_write_during_read_test(void *arg)
+{ http_write_during_read_test_impl(arg, 0); }
+
+static void
+http_request_own_test(void *arg)
+{
+       struct basic_test_data *data = arg;
+       ev_uint16_t port = 0;
+       struct evhttp_connection *evcon = NULL;
+       struct evhttp_request *req = NULL;
+       struct evhttp *http = http_setup(&port, data->base, 0);
+
+       test_ok = 0;
+       exit_base = data->base;
+
+       evhttp_free(http);
+
+       evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
+       tt_assert(evcon);
+
+       req = evhttp_request_new(http_request_no_action_done, NULL);
+
+       if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+               tt_abort_msg("Couldn't make request");
+       }
+       evhttp_request_own(req);
+
+       event_base_dispatch(data->base);
+
+ end:
+       if (evcon)
+               evhttp_connection_free(evcon);
+       if (req)
+               evhttp_request_free(req);
+
+       test_ok = 1;
+}
+
+static void http_run_bev_request(struct event_base *base, int port,
+       const char *fmt, ...)
+{
+       struct bufferevent *bev = NULL;
+       va_list ap;
+       evutil_socket_t fd;
+       struct evbuffer *out;
+
+       fd = http_connect("127.0.0.1", port);
+       tt_assert(fd != EVUTIL_INVALID_SOCKET);
+
+       /* Stupid thing to send a request */
+       bev = create_bev(base, fd, 0, 0);
+       bufferevent_setcb(bev, http_readcb, http_writecb,
+           http_errorcb, base);
+       out = bufferevent_get_output(bev);
+
+       va_start(ap, fmt);
+       evbuffer_add_vprintf(out, fmt, ap);
+       va_end(ap);
+
+       event_base_dispatch(base);
+
+end:
+       if (bev)
+               bufferevent_free(bev);
+}
+static void
+http_request_extra_body_test(void *arg)
+{
+       struct basic_test_data *data = arg;
+       struct bufferevent *bev = NULL;
+       ev_uint16_t port = 0;
+       int i;
+       struct evhttp *http =
+               http_setup_gencb(&port, data->base, 0, http_timeout_cb, NULL);
+       struct evbuffer *body = NULL;
+
+       exit_base = data->base;
+       test_ok = 0;
+
+       body = evbuffer_new();
+       for (i = 0; i < 10000; ++i)
+               evbuffer_add_printf(body, "this is the body that HEAD should not have");
+
+       http_run_bev_request(data->base, port,
+               "HEAD /timeout HTTP/1.1\r\n"
+               "Host: somehost\r\n"
+               "Connection: close\r\n"
+               "Content-Length: %i\r\n"
+               "\r\n%s",
+               (int)evbuffer_get_length(body),
+               evbuffer_pullup(body, -1)
+       );
+       tt_assert(test_ok == -2);
+
+       http_run_bev_request(data->base, port,
+               "HEAD /__gencb__ HTTP/1.1\r\n"
+               "Host: somehost\r\n"
+               "Connection: close\r\n"
+               "Content-Length: %i\r\n"
+               "\r\n%s",
+               (int)evbuffer_get_length(body),
+               evbuffer_pullup(body, -1)
+       );
+       tt_assert(test_ok == -2);
+
+ end:
+       evhttp_free(http);
+       if (bev)
+               bufferevent_free(bev);
+       if (body)
+               evbuffer_free(body);
+}
+
 #define HTTP_LEGACY(name)                                              \
        { #name, run_legacy_test_fn, TT_ISOLATED|TT_LEGACY, &legacy_setup, \
                    http_##name##_test }
 
-#define HTTP(name) \
-       { #name, http_##name##_test, TT_ISOLATED, &basic_setup, NULL }
+#define HTTP_CAST_ARG(a) ((void *)(a))
+#define HTTP_OFF_N(title, name, arg) \
+       { #title, http_##name##_test, TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, HTTP_CAST_ARG(arg) }
+#define HTTP_RET_N(title, name, test_opts, arg) \
+       { #title, http_##name##_test, TT_ISOLATED|TT_RETRIABLE|test_opts, &basic_setup, HTTP_CAST_ARG(arg) }
+#define HTTP_N(title, name, test_opts, arg) \
+       { #title, http_##name##_test, TT_ISOLATED|test_opts, &basic_setup, HTTP_CAST_ARG(arg) }
+#define HTTP(name) HTTP_N(name, name, 0, NULL)
+#define HTTPS(name) \
+       { "https_" #name, https_##name##_test, TT_ISOLATED, &basic_setup, NULL }
+
+#ifdef EVENT__HAVE_OPENSSL
+static void https_basic_test(void *arg)
+{ http_basic_test_impl(arg, 1, "GET /test HTTP/1.1"); }
+static void https_filter_basic_test(void *arg)
+{ http_basic_test_impl(arg, 1 | HTTP_SSL_FILTER, "GET /test HTTP/1.1"); }
+static void https_incomplete_test(void *arg)
+{ http_incomplete_test_(arg, 0, 1); }
+static void https_incomplete_timeout_test(void *arg)
+{ http_incomplete_test_(arg, 1, 1); }
+static void https_simple_test(void *arg)
+{ http_simple_test_impl(arg, 1, 0, "/test"); }
+static void https_simple_dirty_test(void *arg)
+{ http_simple_test_impl(arg, 1, 1, "/test"); }
+static void https_connection_retry_conn_address_test(void *arg)
+{ http_connection_retry_conn_address_test_impl(arg, 1); }
+static void https_connection_retry_test(void *arg)
+{ http_connection_retry_test_impl(arg, 1); }
+static void https_chunk_out_test(void *arg)
+{ http_chunk_out_test_impl(arg, 1); }
+static void https_filter_chunk_out_test(void *arg)
+{ http_chunk_out_test_impl(arg, 1 | HTTP_SSL_FILTER); }
+static void https_stream_out_test(void *arg)
+{ http_stream_out_test_impl(arg, 1); }
+static void https_connection_fail_test(void *arg)
+{ http_connection_fail_test_impl(arg, 1); }
+static void https_write_during_read_test(void *arg)
+{ http_write_during_read_test_impl(arg, 1); }
+static void https_connection_test(void *arg)
+{ http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC, 1); }
+static void https_persist_connection_test(void *arg)
+{ http_connection_test_(arg, 1, "127.0.0.1", NULL, 0, AF_UNSPEC, 1); }
+#endif
 
 struct testcase_t http_testcases[] = {
        { "primitives", http_primitives, 0, NULL, NULL },
        { "base", http_base_test, TT_FORK, NULL, NULL },
        { "bad_headers", http_bad_header_test, 0, NULL, NULL },
        { "parse_query", http_parse_query_test, 0, NULL, NULL },
+       { "parse_query_str", http_parse_query_str_test, 0, NULL, NULL },
        { "parse_uri", http_parse_uri_test, 0, NULL, NULL },
        { "parse_uri_nc", http_parse_uri_test, 0, &basic_setup, (void*)"nc" },
        { "uriencode", http_uriencode_test, 0, NULL, NULL },
        HTTP(basic),
-       HTTP(cancel),
+       HTTP(basic_trailing_space),
+       HTTP(simple),
+       HTTP(simple_nonconformant),
+
+       HTTP_N(cancel, cancel, 0, BASIC),
+       HTTP_RET_N(cancel_by_host, cancel, 0, BY_HOST),
+       HTTP_RET_N(cancel_by_host_inactive_server, cancel, TT_NO_LOGS, BY_HOST | INACTIVE_SERVER),
+       HTTP_RET_N(cancel_by_host_no_ns, cancel, TT_NO_LOGS, BY_HOST | NO_NS),
+       HTTP_N(cancel_inactive_server, cancel, 0, INACTIVE_SERVER),
+       HTTP_N(cancel_by_host_no_ns_inactive_server, cancel, TT_NO_LOGS, BY_HOST | NO_NS | INACTIVE_SERVER),
+       HTTP_OFF_N(cancel_by_host_server_timeout, cancel, BY_HOST | INACTIVE_SERVER | SERVER_TIMEOUT),
+       HTTP_OFF_N(cancel_server_timeout, cancel, INACTIVE_SERVER | SERVER_TIMEOUT),
+       HTTP_OFF_N(cancel_by_host_no_ns_server_timeout, cancel, BY_HOST | NO_NS | INACTIVE_SERVER | SERVER_TIMEOUT),
+       HTTP_OFF_N(cancel_by_host_ns_timeout_server_timeout, cancel, BY_HOST | NO_NS | NS_TIMEOUT | INACTIVE_SERVER | SERVER_TIMEOUT),
+       HTTP_RET_N(cancel_by_host_ns_timeout, cancel, TT_NO_LOGS, BY_HOST | NO_NS | NS_TIMEOUT),
+       HTTP_RET_N(cancel_by_host_ns_timeout_inactive_server, cancel, TT_NO_LOGS, BY_HOST | NO_NS | NS_TIMEOUT | INACTIVE_SERVER),
+
        HTTP(virtual_host),
        HTTP(post),
        HTTP(put),
@@ -3966,6 +4741,7 @@ struct testcase_t http_testcases[] = {
        HTTP(incomplete),
        HTTP(incomplete_timeout),
        HTTP(terminate_chunked),
+       HTTP(terminate_chunked_oneshot),
        HTTP(on_complete),
 
        HTTP(highport),
@@ -3980,8 +4756,13 @@ struct testcase_t http_testcases[] = {
 
        HTTP(connection_fail),
        { "connection_retry", http_connection_retry_test, TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
+       { "connection_retry_conn_address", http_connection_retry_conn_address_test,
+         TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
 
        HTTP(data_length_constraints),
+       HTTP(read_on_write_error),
+       HTTP(non_lingering_close),
+       HTTP(lingering_close),
 
        HTTP(ipv6_for_domain),
        HTTP(get_addr),
@@ -3990,6 +4771,37 @@ struct testcase_t http_testcases[] = {
        HTTP(set_family_ipv4),
        HTTP(set_family_ipv6),
 
+       HTTP(write_during_read),
+       HTTP(request_own),
+
+       HTTP(request_extra_body),
+
+#ifdef EVENT__HAVE_OPENSSL
+       HTTPS(basic),
+       HTTPS(filter_basic),
+       HTTPS(simple),
+       HTTPS(simple_dirty),
+       HTTPS(incomplete),
+       HTTPS(incomplete_timeout),
+       { "https_connection_retry", https_connection_retry_test, TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
+       { "https_connection_retry_conn_address", https_connection_retry_conn_address_test,
+         TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
+       HTTPS(chunk_out),
+       HTTPS(filter_chunk_out),
+       HTTPS(stream_out),
+       HTTPS(connection_fail),
+       HTTPS(write_during_read),
+       HTTPS(connection),
+       HTTPS(persist_connection),
+#endif
+
        END_OF_TESTCASES
 };
 
+struct testcase_t http_iocp_testcases[] = {
+       { "simple", http_simple_test, TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL },
+#ifdef EVENT__HAVE_OPENSSL
+       { "https_simple", https_simple_test, TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL },
+#endif
+       END_OF_TESTCASES
+};
index 4db102df68caca65980858bb12cc5c775b75ef5d..871da4c62ce927e50bbef92e487ca47f2ef3c5dc 100644 (file)
@@ -40,6 +40,9 @@
 # endif
 #include <unistd.h>
 #endif
+#ifdef EVENT__HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
 
 #include <string.h>
 
@@ -77,8 +80,9 @@ regress_pick_a_port(void *arg)
        ev_socklen_t slen1 = sizeof(ss1), slen2 = sizeof(ss2);
        unsigned int flags =
            LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC;
+       evutil_socket_t fd1, fd2, fd3;
 
-       evutil_socket_t fd1 = -1, fd2 = -1, fd3 = -1;
+       fd1 = fd2 = fd3 = EVUTIL_INVALID_SOCKET;
 
        if (data->setup_data && strstr((char*)data->setup_data, "ts")) {
                flags |= LEV_OPT_THREADSAFE;
@@ -96,8 +100,8 @@ regress_pick_a_port(void *arg)
            flags, -1, (struct sockaddr *)&sin, sizeof(sin));
        tt_assert(listener2);
 
-       tt_int_op(evconnlistener_get_fd(listener1), >=, 0);
-       tt_int_op(evconnlistener_get_fd(listener2), >=, 0);
+       tt_assert(evconnlistener_get_fd(listener1) != EVUTIL_INVALID_SOCKET);
+       tt_assert(evconnlistener_get_fd(listener2) != EVUTIL_INVALID_SOCKET);
        tt_assert(getsockname(evconnlistener_get_fd(listener1),
                (struct sockaddr*)&ss1, &slen1) == 0);
        tt_assert(getsockname(evconnlistener_get_fd(listener2),
@@ -114,7 +118,7 @@ regress_pick_a_port(void *arg)
        tt_ptr_op(evconnlistener_get_base(listener1), ==, base);
        tt_ptr_op(evconnlistener_get_base(listener2), ==, base);
 
-       fd1 = fd2 = fd3 = -1;
+       fd1 = fd2 = fd3 = EVUTIL_INVALID_SOCKET;
        evutil_socket_connect_(&fd1, (struct sockaddr*)&ss1, slen1);
        evutil_socket_connect_(&fd2, (struct sockaddr*)&ss1, slen1);
        evutil_socket_connect_(&fd3, (struct sockaddr*)&ss2, slen2);
@@ -182,6 +186,124 @@ end:
                evconnlistener_free(listener);
 }
 
+static void
+acceptcb_free(struct evconnlistener *listener, evutil_socket_t fd,
+    struct sockaddr *addr, int socklen, void *arg)
+{
+       int *ptr = arg;
+       --*ptr;
+       TT_BLATHER(("Got one for %p", ptr));
+       evutil_closesocket(fd);
+
+       if (! *ptr)
+               evconnlistener_free(listener);
+}
+static void
+regress_listener_close_accepted_fd(void *arg)
+{
+       struct basic_test_data *data = arg;
+       struct event_base *base = data->base;
+       struct evconnlistener *listener = NULL;
+       struct sockaddr_in sin;
+       struct sockaddr_storage ss;
+       ev_socklen_t slen = sizeof(ss);
+       int count = 1;
+       unsigned int flags = LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE;
+       evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
+
+       memset(&sin, 0, sizeof(sin));
+       sin.sin_family = AF_INET;
+       sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
+       sin.sin_port = 0; /* "You pick!" */
+
+       /* Start a listener with a bogus socket. */
+       listener = evconnlistener_new_bind(base, acceptcb_free, &count,
+           flags, -1, (struct sockaddr *)&sin, sizeof(sin));
+       tt_assert(listener);
+
+       tt_assert(getsockname(evconnlistener_get_fd(listener),
+               (struct sockaddr*)&ss, &slen) == 0);
+       evutil_socket_connect_(&fd, (struct sockaddr*)&ss, slen);
+
+       event_base_dispatch(base);
+
+end:
+       ;
+}
+
+static void
+regress_listener_immediate_close(void *arg)
+{
+       struct basic_test_data *data = arg;
+       struct event_base *base = data->base;
+       struct evconnlistener *listener = NULL;
+       struct sockaddr_in sin;
+       struct sockaddr_storage ss;
+       ev_socklen_t slen = sizeof(ss);
+       int count = 1;
+       unsigned int flags = LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE;
+       evutil_socket_t fd1 = EVUTIL_INVALID_SOCKET, fd2 = EVUTIL_INVALID_SOCKET;
+
+       memset(&sin, 0, sizeof(sin));
+       sin.sin_family = AF_INET;
+       sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
+       sin.sin_port = 0; /* "You pick!" */
+
+       /* Start a listener with a bogus socket. */
+       listener = evconnlistener_new_bind(base, acceptcb, &count,
+           flags, -1, (struct sockaddr *)&sin, sizeof(sin));
+       tt_assert(listener);
+
+       tt_assert(getsockname(evconnlistener_get_fd(listener),
+               (struct sockaddr*)&ss, &slen) == 0);
+
+       evutil_socket_connect_(&fd1, (struct sockaddr*)&ss, slen);
+       evutil_socket_connect_(&fd2, (struct sockaddr*)&ss, slen);
+
+       event_base_dispatch(base);
+
+       tt_int_op(count, ==, 0);
+
+end:
+       if (listener)
+               evconnlistener_free(listener);
+}
+
+#ifdef EVENT__HAVE_SETRLIMIT
+static void
+regress_listener_error_unlock(void *arg)
+{
+       struct basic_test_data *data = arg;
+       struct event_base *base = data->base;
+       struct evconnlistener *listener = NULL;
+       unsigned int flags =
+               LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|LEV_OPT_THREADSAFE;
+
+       tt_int_op(send(data->pair[1], "hello", 5, 0), >, 0);
+
+       /* Start a listener with a bogus socket. */
+       listener = evconnlistener_new(base, acceptcb, NULL, flags, 0, data->pair[0]);
+       tt_assert(listener);
+
+       /** accept() must errored out with EMFILE */
+       {
+               struct rlimit rl;
+               rl.rlim_cur = rl.rlim_max = data->pair[1];
+               if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
+                       TT_DIE(("Can't change RLIMIT_NOFILE"));
+               }
+       }
+
+       event_base_loop(base, EVLOOP_ONCE);
+
+       /** with lock debugging, can fail on lock->count assertion */
+
+end:
+       if (listener)
+               evconnlistener_free(listener);
+}
+#endif
+
 struct testcase_t listener_testcases[] = {
 
        { "randport", regress_pick_a_port, TT_FORK|TT_NEED_BASE,
@@ -190,6 +312,12 @@ struct testcase_t listener_testcases[] = {
        { "randport_ts", regress_pick_a_port, TT_FORK|TT_NEED_BASE,
          &basic_setup, (char*)"ts"},
 
+#ifdef EVENT__HAVE_SETRLIMIT
+       { "error_unlock", regress_listener_error_unlock,
+         TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR|TT_NO_LOGS,
+         &basic_setup, NULL},
+#endif
+
        { "error", regress_listener_error,
          TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR,
          &basic_setup, NULL},
@@ -198,6 +326,12 @@ struct testcase_t listener_testcases[] = {
          TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR,
          &basic_setup, (char*)"ts"},
 
+       { "close_accepted_fd", regress_listener_close_accepted_fd,
+         TT_FORK|TT_NEED_BASE, &basic_setup, NULL, },
+
+       { "immediate_close", regress_listener_immediate_close,
+         TT_FORK|TT_NEED_BASE, &basic_setup, NULL, },
+
        END_OF_TESTCASES,
 };
 
index 3198ced1da3559bb53832f55ebe91b247ec93238..266561214b8e7b3583401bb5e6ac21b1c5300c5d 100644 (file)
 #include <fcntl.h>
 #endif
 
+/* move_pthread_to_realtime_scheduling_class() */
+#ifdef EVENT__HAVE_MACH_MACH_H
+#include <mach/mach.h>
+#endif
+#ifdef EVENT__HAVE_MACH_MACH_TIME_H
+#include <mach/mach_time.h>
+#endif
+
 #if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
 #if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \
     __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
 
 #include "event2/event-config.h"
 
-#ifdef EVENT____func__
-#define __func__ EVENT____func__
-#endif
-
 #if 0
 #include <sys/types.h>
 #include <sys/stat.h>
 
 #include "event2/event-config.h"
 #include "regress.h"
+#include "regress_thread.h"
 #include "tinytest.h"
 #include "tinytest_macros.h"
 #include "../iocp-internal.h"
 #include "../event-internal.h"
+#include "../evthread-internal.h"
 
 struct evutil_weakrand_state test_weakrand_state;
 
@@ -190,18 +196,65 @@ ignore_log_cb(int s, const char *msg)
 {
 }
 
-static void *
+/**
+ * Put into the real time scheduling class for better timers latency.
+ * https://developer.apple.com/library/archive/technotes/tn2169/_index.html#//apple_ref/doc/uid/DTS40013172-CH1-TNTAG6000
+ */
+#if defined(__APPLE__)
+static void move_pthread_to_realtime_scheduling_class(pthread_t pthread)
+{
+       mach_timebase_info_data_t info;
+       mach_timebase_info(&info);
+
+       const uint64_t NANOS_PER_MSEC = 1000000ULL;
+       double clock2abs =
+               ((double)info.denom / (double)info.numer) * NANOS_PER_MSEC;
+
+       thread_time_constraint_policy_data_t policy;
+       policy.period      = 0;
+       policy.computation = (uint32_t)(5 * clock2abs); // 5 ms of work
+       policy.constraint  = (uint32_t)(10 * clock2abs);
+       policy.preemptible = FALSE;
+
+       int kr = thread_policy_set(pthread_mach_thread_np(pthread),
+               THREAD_TIME_CONSTRAINT_POLICY,
+               (thread_policy_t)&policy,
+               THREAD_TIME_CONSTRAINT_POLICY_COUNT);
+       if (kr != KERN_SUCCESS) {
+               mach_error("thread_policy_set:", kr);
+               exit(1);
+       }
+}
+
+void thread_setup(THREAD_T pthread)
+{
+       move_pthread_to_realtime_scheduling_class(pthread);
+}
+#else /** \__APPLE__ */
+void thread_setup(THREAD_T pthread) {}
+#endif /** \!__APPLE__ */
+
+
+void *
 basic_test_setup(const struct testcase_t *testcase)
 {
        struct event_base *base = NULL;
        evutil_socket_t spair[2] = { -1, -1 };
        struct basic_test_data *data = NULL;
 
+       thread_setup(THREAD_SELF());
+
 #ifndef _WIN32
        if (testcase->flags & TT_ENABLE_IOCP_FLAG)
                return (void*)TT_SKIP;
 #endif
 
+       if (testcase->flags & TT_ENABLE_DEBUG_MODE &&
+               !libevent_tests_running_in_debug_mode) {
+               event_enable_debug_mode();
+               libevent_tests_running_in_debug_mode = 1;
+       }
+
        if (testcase->flags & TT_NEED_THREADS) {
                if (!(testcase->flags & TT_FORK))
                        return NULL;
@@ -266,7 +319,7 @@ basic_test_setup(const struct testcase_t *testcase)
        return data;
 }
 
-static int
+int
 basic_test_cleanup(const struct testcase_t *testcase, void *ptr)
 {
        struct basic_test_data *data = ptr;
@@ -388,6 +441,7 @@ struct testgroup_t testgroups[] = {
        { "iocp/", iocp_testcases },
        { "iocp/bufferevent/", bufferevent_iocp_testcases },
        { "iocp/listener/", listener_iocp_testcases },
+       { "iocp/http/", http_iocp_testcases },
 #endif
 #ifdef EVENT__HAVE_OPENSSL
        { "ssl/", ssl_testcases },
@@ -407,6 +461,7 @@ const char *finetimetests[] = {
        "+util/monotonic_res_fallback",
        "+thread/deferred_cb_skew",
        "+http/connection_retry",
+       "+http/https_connection_retry",
        NULL
 };
 struct testlist_alias_t testaliases[] = {
@@ -437,6 +492,8 @@ main(int argc, const char **argv)
 
 #ifdef _WIN32
        tinytest_skip(testgroups, "http/connection_retry");
+       tinytest_skip(testgroups, "http/https_connection_retry");
+       tinytest_skip(testgroups, "http/read_on_write_error");
 #endif
 
 #ifndef EVENT__DISABLE_THREAD_SUPPORT
@@ -456,6 +513,11 @@ main(int argc, const char **argv)
 
        evutil_weakrand_seed_(&test_weakrand_state, 0);
 
+       if (getenv("EVENT_NO_FILE_BUFFERING")) {
+               setbuf(stdout, NULL);
+               setbuf(stderr, NULL);
+       }
+
        if (tinytest_main(argc,argv,testgroups))
                return 1;
 
index 24ff2933be2c11e0c1c6ff392e013e6b5bb211dc..05db32e26f4de7420ea8d9dd60392e2acc224279 100644 (file)
@@ -63,7 +63,6 @@ test_heap_randomized(void *ptr)
 
        for (i = 0; i < 1024; ++i) {
                inserted[i] = malloc(sizeof(struct event));
-               assert(inserted[i] != NULL);
                set_random_timeout(inserted[i]);
                min_heap_push_(&heap, inserted[i]);
        }
index 01a058cbb2b86facf4196f035bc7257eaac3a4cc..87a7efa12fc3b25e1f99b92f96ae8efc57870bf6 100644 (file)
@@ -61,7 +61,6 @@
 #include "event2/http_compat.h"
 #include "event2/http_struct.h"
 #include "event2/rpc.h"
-#include "event2/rpc.h"
 #include "event2/rpc_struct.h"
 #include "event2/tag.h"
 #include "log-internal.h"
@@ -880,6 +879,53 @@ end:
                evbuffer_free(tmp);
 }
 
+static void
+rpc_invalid_type(void)
+{
+       ev_uint16_t port;
+       struct evhttp *http = NULL;
+       struct evrpc_base *base = NULL;
+       struct evhttp_connection *evcon = NULL;
+       struct evhttp_request *req = NULL;
+
+       rpc_setup(&http, &port, &base);
+
+       evcon = evhttp_connection_new("127.0.0.1", port);
+       tt_assert(evcon);
+
+       /*
+        * At this point, we want to schedule an HTTP POST request
+        * server using our make request method.
+        */
+
+       req = evhttp_request_new(rpc_postrequest_failure, NULL);
+       tt_assert(req);
+
+       /* Add the information that we care about */
+       evhttp_add_header(req->output_headers, "Host", "somehost");
+       evbuffer_add_printf(req->output_buffer, "Some Nonsense");
+
+       if (evhttp_make_request(evcon, req,
+               EVHTTP_REQ_GET,
+               "/.rpc.Message") == -1) {
+               tt_abort();
+       }
+
+       test_ok = 0;
+
+       event_dispatch();
+
+       evhttp_connection_free(evcon);
+
+       rpc_teardown(base);
+
+       tt_assert(test_ok == 1);
+
+end:
+       evhttp_free(http);
+}
+
+
 #define RPC_LEGACY(name)                                               \
        { #name, run_legacy_test_fn, TT_FORK|TT_NEED_BASE|TT_LEGACY,    \
                    &legacy_setup,                                      \
@@ -898,6 +944,7 @@ struct testcase_t rpc_testcases[] = {
        RPC_LEGACY(basic_client),
        RPC_LEGACY(basic_queued_client),
        RPC_LEGACY(basic_client_with_pause),
+       RPC_LEGACY(invalid_type),
        RPC_LEGACY(client_timeout),
        RPC_LEGACY(test),
 
index 226a2a3a7e82956df10032b2c34e2f999629eda3..37dc334dcafa30aae2001440e89b04be8ab306f6 100644 (file)
@@ -34,6 +34,8 @@
 #include <windows.h>
 #endif
 
+#include "util-internal.h"
+
 #ifndef _WIN32
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -43,6 +45,7 @@
 #include "event2/util.h"
 #include "event2/event.h"
 #include "event2/bufferevent_ssl.h"
+#include "event2/bufferevent_struct.h"
 #include "event2/buffer.h"
 #include "event2/listener.h"
 
 #include "tinytest.h"
 #include "tinytest_macros.h"
 
-#include <openssl/asn1.h>
-#include <openssl/ssl.h>
-#include <openssl/bio.h>
-#include <openssl/crypto.h>
 #include <openssl/err.h>
 #include <openssl/pem.h>
-#include <openssl/opensslv.h>
-#include <openssl/x509.h>
+#include "openssl-compat.h"
 
 #include <string.h>
+#ifdef _WIN32
+#include <io.h>
+#define read _read
+#define write _write
+#else
+#include <unistd.h>
+#endif
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-#define OpenSSL_version_num SSLeay
-#endif /* OPENSSL_VERSION_NUMBER */
-
-/* A short pre-generated key, to save the cost of doing an RSA key generation
- * step during the unit tests.  It's only 512 bits long, and it is published
- * in this file, so you would have to be very foolish to consider using it in
- * your own code. */
+/* A pre-generated key, to save the cost of doing an RSA key generation step
+ * during the unit tests. It is published in this file, so you would have to
+ * be very foolish to consider using it in your own code. */
 static const char KEY[] =
     "-----BEGIN RSA PRIVATE KEY-----\n"
-    "MIIBOgIBAAJBAKibTEzXjj+sqpipePX1lEk5BNFuL/dDBbw8QCXgaJWikOiKHeJq\n"
-    "3FQ0OmCnmpkdsPFE4x3ojYmmdgE2i0dJwq0CAwEAAQJAZ08gpUS+qE1IClps/2gG\n"
-    "AAer6Bc31K2AaiIQvCSQcH440cp062QtWMC3V5sEoWmdLsbAHFH26/9ZHn5zAflp\n"
-    "gQIhANWOx/UYeR8HD0WREU5kcuSzgzNLwUErHLzxP7U6aojpAiEAyh2H35CjN/P7\n"
-    "NhcZ4QYw3PeUWpqgJnaE/4i80BSYkSUCIQDLHFhLYLJZ80HwHTADif/ISn9/Ow6b\n"
-    "p6BWh3DbMar/eQIgBPS6azH5vpp983KXkNv9AL4VZi9ac/b+BeINdzC6GP0CIDmB\n"
-    "U6GFEQTZ3IfuiVabG5pummdC4DNbcdI+WKrSFNmQ\n"
+    "MIIEogIBAAKCAQEAtK07Ili0dkJb79m/sFmHoVJTWyLoveXex2yX/BtUzzcvZEOu\n"
+    "QLon/++5YOA48kzZm5K9mIwZkZhui1ZgJ5Bjq0LGAWTZGIn+NXjLFshPYvTKpOCW\n"
+    "uzL0Ir0LXMsBLYJQ5A4FomLNxs4I3H/dhDSGy/rSiJB1B4w2xNiwPK08/VL3zZqk\n"
+    "V+GsSvGIIkzhTMbqPJy9K8pqyjwOU2pgORS794yXciTGxWYjTDzJPgQ35YMDATaG\n"
+    "jr4HHo1zxU/Lj0pndSUK5rKLYxYQ3Uc8B3AVYDl9CP/GbOoQ4LBzS68JjcAUyp6i\n"
+    "6NfXlc2D9S9XgqVqwI+JqgJs0eW/+zPY2UEDWwIDAQABAoIBAD2HzV66FOM9YDAD\n"
+    "2RtGskEHV2nvLpIVadRCsFPkPvK+2X3s6rgSbbLkwh4y3lHuSCGKTNVZyQ9jeSos\n"
+    "xVxT+Q2HFQW+gYyw2gj91TQyDY8mzKhv8AVaqff2p5r3a7RC8CdqexK9UVUGL9Bg\n"
+    "H2F5vfpTtkVZ5PEoGDLblNFlMiMW/t1SobUeBVx+Msco/xqk9lFv1A9nnepGy0Gi\n"
+    "D+i6YNGTBsX22YhoCZl/ICxCL8lgqPei4FvBr9dBVh/jQgjuUBm2jz55p2r7+7Aw\n"
+    "khmXHReejoVokQ2+htgSgZNKlKuDy710ZpBqnDi8ynQi82Y2qCpyg/p/xcER54B6\n"
+    "hSftaiECgYEA2RkSoxU+nWk+BClQEUZRi88QK5W/M8oo1DvUs36hvPFkw3Jk/gz0\n"
+    "fgd5bnA+MXj0Fc0QHvbddPjIkyoI/evq9GPV+JYIuH5zabrlI3Jvya8q9QpAcEDO\n"
+    "KkL/O09qXVEW52S6l05nh4PLejyI7aTyTIN5nbVLac/+M8MY/qOjZksCgYEA1Q1o\n"
+    "L8kjSavU2xhQmSgZb9W62Do60sa3e73ljrDPoiyvbExldpSdziFYxHBD/Rep0ePf\n"
+    "eVSGS3VSwevt9/jSGo2Oa83TYYns9agBm03oR/Go/DukESdI792NsEM+PRFypVNy\n"
+    "AohWRLj0UU6DV+zLKp0VBavtx0ATeLFX0eN17TECgYBI2O/3Bz7uhQ0JSm+SjFz6\n"
+    "o+2SInp5P2G57aWu4VQWWY3tQ2p+EQzNaWam10UXRrXoxtmc+ktPX9e2AgnoYoyB\n"
+    "myqGcpnUhqHlnZAb999o9r1cYidDQ4uqhLauSTSwwXAFDzjJYsa8o03Y440y6QFh\n"
+    "CVD6yYXXqLJs3g96CqDexwKBgAHxq1+0QCQt8zVElYewO/svQhMzBNJjic0RQIT6\n"
+    "zAo4yij80XgxhvcYiszQEW6/xobpw2JCCS+rFGQ8mOFIXfJsFD6blDAxp/3d2JXo\n"
+    "MhRl+hrDGI4ng5zcsqxHEMxR2m/zwPiQ8eiSn3gWdVBaEsiCwmxY00ScKxFQ3PJH\n"
+    "Vw4hAoGAdZLd8KfjjG6lg7hfpVqavstqVi9LOgkHeCfdjn7JP+76kYrgLk/XdkrP\n"
+    "N/BHhtFVFjOi/mTQfQ5YfZImkm/1ePBy7437DT8BDkOxspa50kK4HPggHnU64h1w\n"
+    "lhdEOj7mAgHwGwwVZWOgs9Lq6vfztnSuhqjha1daESY6kDscPIQ=\n"
     "-----END RSA PRIVATE KEY-----\n";
 
-static EVP_PKEY *
-getkey(void)
+EVP_PKEY *
+ssl_getkey(void)
 {
        EVP_PKEY *key;
        BIO *bio;
@@ -99,15 +117,14 @@ end:
        return NULL;
 }
 
-static X509 *
-getcert(void)
+X509 *
+ssl_getcert(EVP_PKEY *key)
 {
        /* Dummy code to make a quick-and-dirty valid certificate with
           OpenSSL.  Don't copy this code into your own program! It does a
           number of things in a stupid and insecure way. */
        X509 *x509 = NULL;
        X509_NAME *name = NULL;
-       EVP_PKEY *key = getkey();
        int nid;
        time_t now = time(NULL);
 
@@ -129,29 +146,25 @@ getcert(void)
 
        X509_set_subject_name(x509, name);
        X509_set_issuer_name(x509, name);
+       X509_NAME_free(name);
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-       X509_time_adj(X509_get_notBefore(x509), 0, &now);
-       now += 3600;
-       X509_time_adj(X509_get_notAfter(x509), 0, &now);
-#else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
        X509_time_adj(X509_getm_notBefore(x509), 0, &now);
        now += 3600;
        X509_time_adj(X509_getm_notAfter(x509), 0, &now);
-#endif /* OPENSSL_VERSION_NUMBER */
        X509_set_pubkey(x509, key);
        tt_assert(0 != X509_sign(x509, key, EVP_sha1()));
 
        return x509;
 end:
        X509_free(x509);
+       X509_NAME_free(name);
        return NULL;
 }
 
 static int disable_tls_11_and_12 = 0;
 static SSL_CTX *the_ssl_ctx = NULL;
 
-static SSL_CTX *
+SSL_CTX *
 get_ssl_ctx(void)
 {
        if (the_ssl_ctx)
@@ -170,31 +183,137 @@ get_ssl_ctx(void)
        return the_ssl_ctx;
 }
 
-static void
+static int test_is_done;
+static int n_connected;
+static int got_close;
+static int got_error;
+static int got_timeout;
+static int renegotiate_at = -1;
+static int stop_when_connected;
+static int pending_connect_events;
+static struct event_base *exit_base;
+static X509 *the_cert;
+EVP_PKEY *the_key;
+
+void
 init_ssl(void)
 {
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+       (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
        SSL_library_init();
        ERR_load_crypto_strings();
        SSL_load_error_strings();
        OpenSSL_add_all_algorithms();
-       if (OpenSSL_version_num() != OPENSSL_VERSION_NUMBER) {
-               TT_DECLARE("WARN", ("Version mismatch for openssl: compiled with %lx but running with %lx", (unsigned long)OPENSSL_VERSION_NUMBER, (unsigned long) OpenSSL_version_num()));
+       if (SSLeay() != OPENSSL_VERSION_NUMBER) {
+               TT_DECLARE("WARN",
+                       ("Version mismatch for openssl: compiled with %lx but running with %lx",
+                       (unsigned long)OPENSSL_VERSION_NUMBER, (unsigned long)SSLeay()));
        }
+#endif
 }
 
+static void *
+ssl_test_setup(const struct testcase_t *testcase)
+{
+       init_ssl();
+
+       the_key = ssl_getkey();
+       EVUTIL_ASSERT(the_key);
+
+       the_cert = ssl_getcert(the_key);
+       EVUTIL_ASSERT(the_cert);
+
+       disable_tls_11_and_12 = 0;
+
+       return basic_test_setup(testcase);
+}
+static int
+ssl_test_cleanup(const struct testcase_t *testcase, void *ptr)
+{
+       int ret = basic_test_cleanup(testcase, ptr);
+       if (!ret) {
+               return ret;
+       }
+
+       test_is_done = 0;
+       n_connected = 0;
+       got_close = 0;
+       got_error = 0;
+       got_timeout = 0;
+       renegotiate_at = -1;
+       stop_when_connected = 0;
+       pending_connect_events = 0;
+       exit_base = NULL;
+
+       X509_free(the_cert);
+       EVP_PKEY_free(the_key);
+
+       SSL_CTX_free(the_ssl_ctx);
+       the_ssl_ctx = NULL;
+
+       return 1;
+}
+const struct testcase_setup_t ssl_setup = {
+       ssl_test_setup, ssl_test_cleanup
+};
+
+
 /* ====================
    Here's a simple test: we read a number from the input, increment it, and
    reply, until we get to 1001.
 */
 
-static int test_is_done = 0;
-static int n_connected = 0;
-static int got_close = 0;
-static int got_error = 0;
-static int renegotiate_at = -1;
-static int stop_when_connected = 0;
-static int pending_connect_events = 0;
-static struct event_base *exit_base = NULL;
+enum regress_openssl_type
+{
+       REGRESS_OPENSSL_SOCKETPAIR = 1,
+       REGRESS_OPENSSL_FILTER = 2,
+       REGRESS_OPENSSL_RENEGOTIATE = 4,
+       REGRESS_OPENSSL_OPEN = 8,
+       REGRESS_OPENSSL_DIRTY_SHUTDOWN = 16,
+       REGRESS_OPENSSL_FD = 32,
+
+       REGRESS_OPENSSL_CLIENT = 64,
+       REGRESS_OPENSSL_SERVER = 128,
+
+       REGRESS_OPENSSL_FREED = 256,
+       REGRESS_OPENSSL_TIMEOUT = 512,
+       REGRESS_OPENSSL_SLEEP = 1024,
+
+       REGRESS_OPENSSL_CLIENT_WRITE = 2048,
+
+       REGRESS_DEFERRED_CALLBACKS = 4096,
+};
+
+static void
+bufferevent_openssl_check_fd(struct bufferevent *bev, int filter)
+{
+       tt_fd_op(bufferevent_getfd(bev), !=, EVUTIL_INVALID_SOCKET);
+       tt_fd_op(bufferevent_setfd(bev, EVUTIL_INVALID_SOCKET), ==, 0);
+       if (filter) {
+               tt_fd_op(bufferevent_getfd(bev), !=, EVUTIL_INVALID_SOCKET);
+       } else {
+               tt_fd_op(bufferevent_getfd(bev), ==, EVUTIL_INVALID_SOCKET);
+       }
+
+end:
+       ;
+}
+static void
+bufferevent_openssl_check_freed(struct bufferevent *bev)
+{
+       tt_int_op(event_pending(&bev->ev_read, EVLIST_ALL, NULL), ==, 0);
+       tt_int_op(event_pending(&bev->ev_write, EVLIST_ALL, NULL), ==, 0);
+
+end:
+       ;
+}
+
+static void
+free_on_cb(struct bufferevent *bev, void *ctx)
+{
+       TT_BLATHER(("free_on_cb: %p", bev));
+       bufferevent_free(bev);
+}
 
 static void
 respond_to_number(struct bufferevent *bev, void *ctx)
@@ -202,6 +321,10 @@ respond_to_number(struct bufferevent *bev, void *ctx)
        struct evbuffer *b = bufferevent_get_input(bev);
        char *line;
        int n;
+
+       enum regress_openssl_type type;
+       type = (enum regress_openssl_type)ctx;
+
        line = evbuffer_readln(b, NULL, EVBUFFER_EOL_LF);
        if (! line)
                return;
@@ -215,7 +338,7 @@ respond_to_number(struct bufferevent *bev, void *ctx)
                bufferevent_free(bev); /* Should trigger close on other side. */
                return;
        }
-       if (!strcmp(ctx, "client") && n == renegotiate_at) {
+       if ((type & REGRESS_OPENSSL_CLIENT) && n == renegotiate_at) {
                SSL_renegotiate(bufferevent_openssl_get_ssl(bev));
        }
        ++n;
@@ -240,15 +363,19 @@ done_writing_cb(struct bufferevent *bev, void *ctx)
 static void
 eventcb(struct bufferevent *bev, short what, void *ctx)
 {
+       X509 *peer_cert = NULL;
+       enum regress_openssl_type type;
+
+       type = (enum regress_openssl_type)ctx;
+
        TT_BLATHER(("Got event %d", (int)what));
        if (what & BEV_EVENT_CONNECTED) {
                SSL *ssl;
-               X509 *peer_cert;
                ++n_connected;
                ssl = bufferevent_openssl_get_ssl(bev);
                tt_assert(ssl);
                peer_cert = SSL_get_peer_certificate(ssl);
-               if (0==strcmp(ctx, "server")) {
+               if (type & REGRESS_OPENSSL_SERVER) {
                        tt_assert(peer_cert == NULL);
                } else {
                        tt_assert(peer_cert != NULL);
@@ -257,26 +384,55 @@ eventcb(struct bufferevent *bev, short what, void *ctx)
                        if (--pending_connect_events == 0)
                                event_base_loopexit(exit_base, NULL);
                }
+
+               if ((type & REGRESS_OPENSSL_CLIENT_WRITE) && (type & REGRESS_OPENSSL_CLIENT))
+                       evbuffer_add_printf(bufferevent_get_output(bev), "1\n");
        } else if (what & BEV_EVENT_EOF) {
                TT_BLATHER(("Got a good EOF"));
                ++got_close;
+               if (type & REGRESS_OPENSSL_FD) {
+                       bufferevent_openssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER);
+               }
+               if (type & REGRESS_OPENSSL_FREED) {
+                       bufferevent_openssl_check_freed(bev);
+               }
                bufferevent_free(bev);
        } else if (what & BEV_EVENT_ERROR) {
                TT_BLATHER(("Got an error."));
                ++got_error;
+               if (type & REGRESS_OPENSSL_FD) {
+                       bufferevent_openssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER);
+               }
+               if (type & REGRESS_OPENSSL_FREED) {
+                       bufferevent_openssl_check_freed(bev);
+               }
+               bufferevent_free(bev);
+       } else if (what & BEV_EVENT_TIMEOUT) {
+               TT_BLATHER(("Got timeout."));
+               ++got_timeout;
+               if (type & REGRESS_OPENSSL_FD) {
+                       bufferevent_openssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER);
+               }
+               if (type & REGRESS_OPENSSL_FREED) {
+                       bufferevent_openssl_check_freed(bev);
+               }
                bufferevent_free(bev);
        }
+
 end:
-       ;
+       if (peer_cert)
+               X509_free(peer_cert);
 }
 
 static void
 open_ssl_bufevs(struct bufferevent **bev1_out, struct bufferevent **bev2_out,
     struct event_base *base, int is_open, int flags, SSL *ssl1, SSL *ssl2,
-    evutil_socket_t *fd_pair, struct bufferevent **underlying_pair)
+    evutil_socket_t *fd_pair, struct bufferevent **underlying_pair,
+    enum regress_openssl_type type)
 {
        int state1 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_CONNECTING;
        int state2 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_ACCEPTING;
+       int dirty_shutdown = type & REGRESS_OPENSSL_DIRTY_SHUTDOWN;
        if (fd_pair) {
                *bev1_out = bufferevent_openssl_socket_new(
                        base, fd_pair[0], ssl1, state1, flags);
@@ -290,9 +446,12 @@ open_ssl_bufevs(struct bufferevent **bev1_out, struct bufferevent **bev2_out,
 
        }
        bufferevent_setcb(*bev1_out, respond_to_number, done_writing_cb,
-           eventcb, (void*)"client");
+           eventcb, (void*)(REGRESS_OPENSSL_CLIENT | (long)type));
        bufferevent_setcb(*bev2_out, respond_to_number, done_writing_cb,
-           eventcb, (void*)"server");
+           eventcb, (void*)(REGRESS_OPENSSL_SERVER | (long)type));
+
+       bufferevent_openssl_set_allow_dirty_shutdown(*bev1_out, dirty_shutdown);
+       bufferevent_openssl_set_allow_dirty_shutdown(*bev2_out, dirty_shutdown);
 }
 
 static void
@@ -302,22 +461,16 @@ regress_bufferevent_openssl(void *arg)
 
        struct bufferevent *bev1, *bev2;
        SSL *ssl1, *ssl2;
-       X509 *cert = getcert();
-       EVP_PKEY *key = getkey();
-       const int start_open = strstr((char*)data->setup_data, "open")!=NULL;
-       const int filter = strstr((char*)data->setup_data, "filter")!=NULL;
        int flags = BEV_OPT_DEFER_CALLBACKS;
        struct bufferevent *bev_ll[2] = { NULL, NULL };
        evutil_socket_t *fd_pair = NULL;
 
-       tt_assert(cert);
-       tt_assert(key);
-
-       init_ssl();
+       enum regress_openssl_type type;
+       type = (enum regress_openssl_type)data->setup_data;
 
-       if (strstr((char*)data->setup_data, "renegotiate")) {
-               if (OpenSSL_version_num() >= 0x10001000 &&
-                   OpenSSL_version_num() <  0x1000104f) {
+       if (type & REGRESS_OPENSSL_RENEGOTIATE) {
+               if (OPENSSL_VERSION_NUMBER >= 0x10001000 &&
+                   OPENSSL_VERSION_NUMBER <  0x1000104f) {
                        /* 1.0.1 up to 1.0.1c has a bug where TLS1.1 and 1.2
                         * can't renegotiate with themselves. Disable. */
                        disable_tls_11_and_12 = 1;
@@ -328,14 +481,14 @@ regress_bufferevent_openssl(void *arg)
        ssl1 = SSL_new(get_ssl_ctx());
        ssl2 = SSL_new(get_ssl_ctx());
 
-       SSL_use_certificate(ssl2, cert);
-       SSL_use_PrivateKey(ssl2, key);
+       SSL_use_certificate(ssl2, the_cert);
+       SSL_use_PrivateKey(ssl2, the_key);
 
-       if (! start_open)
+       if (!(type & REGRESS_OPENSSL_OPEN))
                flags |= BEV_OPT_CLOSE_ON_FREE;
 
-       if (!filter) {
-               tt_assert(strstr((char*)data->setup_data, "socketpair"));
+       if (!(type & REGRESS_OPENSSL_FILTER)) {
+               tt_assert(type & REGRESS_OPENSSL_SOCKETPAIR);
                fd_pair = data->pair;
        } else {
                bev_ll[0] = bufferevent_socket_new(data->base, data->pair[0],
@@ -345,15 +498,15 @@ regress_bufferevent_openssl(void *arg)
        }
 
        open_ssl_bufevs(&bev1, &bev2, data->base, 0, flags, ssl1, ssl2,
-           fd_pair, bev_ll);
+           fd_pair, bev_ll, type);
 
-       if (!filter) {
-               tt_int_op(bufferevent_getfd(bev1), ==, data->pair[0]);
+       if (!(type & REGRESS_OPENSSL_FILTER)) {
+               tt_fd_op(bufferevent_getfd(bev1), ==, data->pair[0]);
        } else {
                tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev_ll[0]);
        }
 
-       if (start_open) {
+       if (type & REGRESS_OPENSSL_OPEN) {
                pending_connect_events = 2;
                stop_when_connected = 1;
                exit_base = data->base;
@@ -365,52 +518,209 @@ regress_bufferevent_openssl(void *arg)
                bufferevent_free(bev2);
                bev1 = bev2 = NULL;
                open_ssl_bufevs(&bev1, &bev2, data->base, 1, flags, ssl1, ssl2,
-                   fd_pair, bev_ll);
+                   fd_pair, bev_ll, type);
        }
 
-       bufferevent_enable(bev1, EV_READ|EV_WRITE);
-       bufferevent_enable(bev2, EV_READ|EV_WRITE);
+       if (!(type & REGRESS_OPENSSL_TIMEOUT)) {
+               bufferevent_enable(bev1, EV_READ|EV_WRITE);
+               bufferevent_enable(bev2, EV_READ|EV_WRITE);
+
+               if (!(type & REGRESS_OPENSSL_CLIENT_WRITE))
+                       evbuffer_add_printf(bufferevent_get_output(bev1), "1\n");
+
+               event_base_dispatch(data->base);
+
+               tt_assert(test_is_done == 1);
+               tt_assert(n_connected == 2);
+
+               /* We don't handle shutdown properly yet */
+               if (type & REGRESS_OPENSSL_DIRTY_SHUTDOWN) {
+                       tt_int_op(got_close, ==, 1);
+                       tt_int_op(got_error, ==, 0);
+               } else {
+                       tt_int_op(got_error, ==, 1);
+               }
+               tt_int_op(got_timeout, ==, 0);
+       } else {
+               struct timeval t = { 2, 0 };
+
+               bufferevent_enable(bev1, EV_READ|EV_WRITE);
+               bufferevent_disable(bev2, EV_READ|EV_WRITE);
 
-       evbuffer_add_printf(bufferevent_get_output(bev1), "1\n");
+               bufferevent_set_timeouts(bev1, &t, &t);
 
-       event_base_dispatch(data->base);
+               if (!(type & REGRESS_OPENSSL_CLIENT_WRITE))
+                       evbuffer_add_printf(bufferevent_get_output(bev1), "1\n");
 
-       tt_assert(test_is_done == 1);
-       tt_assert(n_connected == 2);
+               event_base_dispatch(data->base);
+
+               tt_assert(test_is_done == 0);
+               tt_assert(n_connected == 0);
+
+               tt_int_op(got_close, ==, 0);
+               tt_int_op(got_error, ==, 0);
+               tt_int_op(got_timeout, ==, 1);
+
+               bufferevent_free(bev2);
+       }
 
-       /* We don't handle shutdown properly yet.
-          tt_int_op(got_close, ==, 1);
-          tt_int_op(got_error, ==, 0);
-       */
 end:
        return;
 }
 
+static void
+acceptcb_deferred(evutil_socket_t fd, short events, void *arg)
+{
+       struct bufferevent *bev = arg;
+       bufferevent_enable(bev, EV_READ|EV_WRITE);
+}
 static void
 acceptcb(struct evconnlistener *listener, evutil_socket_t fd,
     struct sockaddr *addr, int socklen, void *arg)
 {
        struct basic_test_data *data = arg;
        struct bufferevent *bev;
+       enum regress_openssl_type type;
        SSL *ssl = SSL_new(get_ssl_ctx());
 
-       SSL_use_certificate(ssl, getcert());
-       SSL_use_PrivateKey(ssl, getkey());
+       type = (enum regress_openssl_type)data->setup_data;
+
+       SSL_use_certificate(ssl, the_cert);
+       SSL_use_PrivateKey(ssl, the_key);
 
        bev = bufferevent_openssl_socket_new(
-               data->base,
-               fd,
-               ssl,
-               BUFFEREVENT_SSL_ACCEPTING,
+               data->base, fd, ssl, BUFFEREVENT_SSL_ACCEPTING,
                BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
+       tt_assert(bev);
 
        bufferevent_setcb(bev, respond_to_number, NULL, eventcb,
-           (void*)"server");
+           (void*)(REGRESS_OPENSSL_SERVER));
 
-       bufferevent_enable(bev, EV_READ|EV_WRITE);
+       if (type & REGRESS_OPENSSL_SLEEP) {
+               struct timeval when = { 1, 0 };
+               event_base_once(data->base, -1, EV_TIMEOUT,
+                   acceptcb_deferred, bev, &when);
+               bufferevent_disable(bev, EV_READ|EV_WRITE);
+       } else {
+               bufferevent_enable(bev, EV_READ|EV_WRITE);
+       }
 
        /* Only accept once, then disable ourself. */
        evconnlistener_disable(listener);
+
+end:
+       ;
+}
+
+struct rwcount
+{
+       evutil_socket_t fd;
+       size_t read;
+       size_t write;
+};
+static int
+bio_rwcount_new(BIO *b)
+{
+       BIO_set_init(b, 0);
+       BIO_set_data(b, NULL);
+       return 1;
+}
+static int
+bio_rwcount_free(BIO *b)
+{
+       TT_BLATHER(("bio_rwcount_free: %p", b));
+       if (!b)
+               return 0;
+       if (BIO_get_shutdown(b)) {
+               BIO_set_init(b, 0);
+               BIO_set_data(b, NULL);
+       }
+       return 1;
+}
+static int
+bio_rwcount_read(BIO *b, char *out, int outlen)
+{
+       struct rwcount *rw = BIO_get_data(b);
+       ev_ssize_t ret = recv(rw->fd, out, outlen, 0);
+       ++rw->read;
+       if (ret == -1 && EVUTIL_ERR_RW_RETRIABLE(EVUTIL_SOCKET_ERROR())) {
+               BIO_set_retry_read(b);
+       }
+       return ret;
+}
+static int
+bio_rwcount_write(BIO *b, const char *in, int inlen)
+{
+       struct rwcount *rw = BIO_get_data(b);
+       ev_ssize_t ret = send(rw->fd, in, inlen, 0);
+       ++rw->write;
+       if (ret == -1 && EVUTIL_ERR_RW_RETRIABLE(EVUTIL_SOCKET_ERROR())) {
+               BIO_set_retry_write(b);
+       }
+       return ret;
+}
+static long
+bio_rwcount_ctrl(BIO *b, int cmd, long num, void *ptr)
+{
+       struct rwcount *rw = BIO_get_data(b);
+       long ret = 0;
+       switch (cmd) {
+       case BIO_C_GET_FD:
+               ret = rw->fd;
+               break;
+       case BIO_CTRL_GET_CLOSE:
+               ret = BIO_get_shutdown(b);
+               break;
+       case BIO_CTRL_SET_CLOSE:
+               BIO_set_shutdown(b, (int)num);
+               break;
+       case BIO_CTRL_PENDING:
+               ret = 0;
+               break;
+       case BIO_CTRL_WPENDING:
+               ret = 0;
+               break;
+       case BIO_CTRL_DUP:
+       case BIO_CTRL_FLUSH:
+               ret = 1;
+               break;
+       }
+       return ret;
+}
+static int
+bio_rwcount_puts(BIO *b, const char *s)
+{
+       return bio_rwcount_write(b, s, strlen(s));
+}
+#define BIO_TYPE_LIBEVENT_RWCOUNT 0xff1
+static BIO_METHOD *methods_rwcount;
+
+static BIO_METHOD *
+BIO_s_rwcount(void)
+{
+       if (methods_rwcount == NULL) {
+               methods_rwcount = BIO_meth_new(BIO_TYPE_LIBEVENT_RWCOUNT, "rwcount");
+               if (methods_rwcount == NULL)
+                       return NULL;
+               BIO_meth_set_write(methods_rwcount, bio_rwcount_write);
+               BIO_meth_set_read(methods_rwcount, bio_rwcount_read);
+               BIO_meth_set_puts(methods_rwcount, bio_rwcount_puts);
+               BIO_meth_set_ctrl(methods_rwcount, bio_rwcount_ctrl);
+               BIO_meth_set_create(methods_rwcount, bio_rwcount_new);
+               BIO_meth_set_destroy(methods_rwcount, bio_rwcount_free);
+       }
+       return methods_rwcount;
+}
+static BIO *
+BIO_new_rwcount(int close_flag)
+{
+       BIO *result;
+       if (!(result = BIO_new(BIO_s_rwcount())))
+               return NULL;
+       BIO_set_init(result, 1);
+       BIO_set_data(result,  NULL);
+       BIO_set_shutdown(result, !!close_flag);
+       return result;
 }
 
 static void
@@ -425,8 +735,11 @@ regress_bufferevent_openssl_connect(void *arg)
        struct sockaddr_in sin;
        struct sockaddr_storage ss;
        ev_socklen_t slen;
+       SSL *ssl;
+       struct rwcount rw = { -1, 0, 0 };
+       enum regress_openssl_type type;
 
-       init_ssl();
+       type = (enum regress_openssl_type)data->setup_data;
 
        memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
@@ -442,51 +755,324 @@ regress_bufferevent_openssl_connect(void *arg)
        tt_assert(listener);
        tt_assert(evconnlistener_get_fd(listener) >= 0);
 
+       ssl = SSL_new(get_ssl_ctx());
+       tt_assert(ssl);
+
        bev = bufferevent_openssl_socket_new(
-               data->base, -1, SSL_new(get_ssl_ctx()),
+               data->base, -1, ssl,
                BUFFEREVENT_SSL_CONNECTING,
                BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
        tt_assert(bev);
 
-       bufferevent_setcb(bev, respond_to_number, NULL, eventcb,
-           (void*)"client");
+       bufferevent_setcb(bev, respond_to_number, free_on_cb, eventcb,
+           (void*)(REGRESS_OPENSSL_CLIENT));
 
        tt_assert(getsockname(evconnlistener_get_fd(listener),
                (struct sockaddr*)&ss, &slen) == 0);
        tt_assert(slen == sizeof(struct sockaddr_in));
        tt_int_op(((struct sockaddr*)&ss)->sa_family, ==, AF_INET);
-       tt_int_op(((struct sockaddr*)&ss)->sa_family, ==, AF_INET);
 
        tt_assert(0 ==
            bufferevent_socket_connect(bev, (struct sockaddr*)&ss, slen));
+       /* Possible only when we have fd, since be_openssl can and will overwrite
+        * bio otherwise before */
+       if (type & REGRESS_OPENSSL_SLEEP) {
+               BIO *bio;
+
+               rw.fd = bufferevent_getfd(bev);
+               bio = BIO_new_rwcount(0);
+               tt_assert(bio);
+               BIO_set_data(bio, &rw);
+               SSL_set_bio(ssl, bio, bio);
+       }
        evbuffer_add_printf(bufferevent_get_output(bev), "1\n");
        bufferevent_enable(bev, EV_READ|EV_WRITE);
 
        event_base_dispatch(base);
+
+       tt_int_op(rw.read, <=, 100);
+       tt_int_op(rw.write, <=, 100);
 end:
-       ;
+       evconnlistener_free(listener);
 }
 
-struct testcase_t ssl_testcases[] = {
+struct wm_context
+{
+       int server;
+       int flags;
+       struct evbuffer *data;
+       size_t to_read;
+       size_t wm_high;
+       size_t limit;
+       size_t get;
+       struct bufferevent *bev;
+       struct wm_context *neighbour;
+};
+static void
+wm_transfer(struct bufferevent *bev, void *arg)
+{
+       struct wm_context *ctx = arg;
+       struct evbuffer *in  = bufferevent_get_input(bev);
+       struct evbuffer *out = bufferevent_get_output(bev);
+       size_t len = evbuffer_get_length(in);
+       size_t drain = len < ctx->to_read ? len : ctx->to_read;
+
+       if (ctx->get >= ctx->limit) {
+               TT_BLATHER(("wm_transfer-%s(%p): break",
+                       ctx->server ? "server" : "client", bev));
+               bufferevent_setcb(bev, NULL, NULL, NULL, NULL);
+               bufferevent_disable(bev, EV_READ);
+               if (ctx->neighbour->get >= ctx->neighbour->limit) {
+                       event_base_loopbreak(bufferevent_get_base(bev));
+               }
+       } else {
+               ctx->get += drain;
+               evbuffer_drain(in, drain);
+       }
+
+       TT_BLATHER(("wm_transfer-%s(%p): "
+               "in: " EV_SIZE_FMT ", "
+               "out: " EV_SIZE_FMT ", "
+               "got: " EV_SIZE_FMT "",
+               ctx->server ? "server" : "client", bev,
+               evbuffer_get_length(in),
+               evbuffer_get_length(out),
+               ctx->get));
+
+       evbuffer_add_buffer_reference(out, ctx->data);
+}
+static void
+wm_eventcb(struct bufferevent *bev, short what, void *arg)
+{
+       struct wm_context *ctx = arg;
+       TT_BLATHER(("wm_eventcb-%s(%p): %i",
+               ctx->server ? "server" : "client", bev, what));
+       if (what & BEV_EVENT_CONNECTED) {
+       } else {
+               ctx->get = 0;
+       }
+}
+static void
+wm_acceptcb(struct evconnlistener *listener, evutil_socket_t fd,
+    struct sockaddr *addr, int socklen, void *arg)
+{
+       struct wm_context *ctx = arg;
+       struct bufferevent *bev;
+       struct event_base *base = evconnlistener_get_base(listener);
+       SSL *ssl = SSL_new(get_ssl_ctx());
+
+       SSL_use_certificate(ssl, the_cert);
+       SSL_use_PrivateKey(ssl, the_key);
+
+       bev = bufferevent_openssl_socket_new(
+               base, fd, ssl, BUFFEREVENT_SSL_ACCEPTING, ctx->flags);
+
+       TT_BLATHER(("wm_transfer-%s(%p): accept",
+               ctx->server ? "server" : "client", bev));
 
-       { "bufferevent_socketpair", regress_bufferevent_openssl, TT_ISOLATED,
-         &basic_setup, (void*)"socketpair" },
+       bufferevent_setwatermark(bev, EV_READ, 0, ctx->wm_high);
+       bufferevent_setcb(bev, wm_transfer, NULL, wm_eventcb, ctx);
+       bufferevent_enable(bev, EV_READ|EV_WRITE);
+       ctx->bev = bev;
+
+       /* Only accept once, then disable ourself. */
+       evconnlistener_disable(listener);
+}
+static void
+regress_bufferevent_openssl_wm(void *arg)
+{
+       struct basic_test_data *data = arg;
+       struct event_base *base = data->base;
+
+       struct evconnlistener *listener;
+       struct bufferevent *bev;
+       struct sockaddr_in sin;
+       struct sockaddr_storage ss;
+       enum regress_openssl_type type =
+               (enum regress_openssl_type)data->setup_data;
+       int bev_flags = BEV_OPT_CLOSE_ON_FREE;
+       ev_socklen_t slen;
+       SSL *ssl;
+       struct wm_context client, server;
+       char *payload;
+       size_t payload_len = 1<<10;
+       size_t wm_high = 5<<10;
+
+       memset(&sin, 0, sizeof(sin));
+       sin.sin_family = AF_INET;
+       sin.sin_addr.s_addr = htonl(0x7f000001);
+
+       memset(&ss, 0, sizeof(ss));
+       slen = sizeof(ss);
+
+       if (type & REGRESS_DEFERRED_CALLBACKS)
+               bev_flags |= BEV_OPT_DEFER_CALLBACKS;
+
+       memset(&client, 0, sizeof(client));
+       memset(&server, 0, sizeof(server));
+       client.server = 0;
+       server.server = 1;
+       client.flags = server.flags = bev_flags;
+       client.data = evbuffer_new();
+       server.data = evbuffer_new();
+       payload = calloc(1, payload_len);
+       memset(payload, 'A', payload_len);
+       evbuffer_add(server.data, payload, payload_len);
+       evbuffer_add(client.data, payload, payload_len);
+       client.wm_high = server.wm_high = wm_high;
+       client.limit = server.limit = wm_high<<3;
+       client.to_read = server.to_read = payload_len>>1;
+
+       TT_BLATHER(("openssl_wm: "
+               "payload_len = " EV_SIZE_FMT ", "
+               "wm_high = " EV_SIZE_FMT ", "
+               "limit = " EV_SIZE_FMT ", "
+               "to_read: " EV_SIZE_FMT "",
+               payload_len,
+               wm_high,
+               server.limit,
+               server.to_read));
+
+       listener = evconnlistener_new_bind(base, wm_acceptcb, &server,
+           LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
+           -1, (struct sockaddr *)&sin, sizeof(sin));
+
+       tt_assert(listener);
+       tt_assert(evconnlistener_get_fd(listener) >= 0);
+
+       ssl = SSL_new(get_ssl_ctx());
+       tt_assert(ssl);
+
+       if (type & REGRESS_OPENSSL_FILTER) {
+               bev = bufferevent_socket_new(data->base, -1, client.flags);
+               tt_assert(bev);
+               bev = bufferevent_openssl_filter_new(
+                       base, bev, ssl, BUFFEREVENT_SSL_CONNECTING, client.flags);
+       } else {
+               bev = bufferevent_openssl_socket_new(
+                       data->base, -1, ssl,
+                       BUFFEREVENT_SSL_CONNECTING,
+                       client.flags);
+       }
+       tt_assert(bev);
+       client.bev = bev;
+
+       server.neighbour = &client;
+       client.neighbour = &server;
+
+       bufferevent_setwatermark(bev, EV_READ, 0, client.wm_high);
+       bufferevent_setcb(bev, wm_transfer, NULL, wm_eventcb, &client);
+
+       tt_assert(getsockname(evconnlistener_get_fd(listener),
+               (struct sockaddr*)&ss, &slen) == 0);
+
+       tt_assert(!bufferevent_socket_connect(bev, (struct sockaddr*)&ss, slen));
+       tt_assert(!evbuffer_add_buffer_reference(bufferevent_get_output(bev), client.data));
+       tt_assert(!bufferevent_enable(bev, EV_READ|EV_WRITE));
+
+       event_base_dispatch(base);
+
+       tt_int_op(client.get, ==, client.limit);
+       tt_int_op(server.get, ==, server.limit);
+
+end:
+       free(payload);
+       evbuffer_free(client.data);
+       evbuffer_free(server.data);
+       evconnlistener_free(listener);
+       bufferevent_free(client.bev);
+       bufferevent_free(server.bev);
+
+       /* XXX: by some reason otherise there is a leak */
+       if (!(type & REGRESS_OPENSSL_FILTER))
+               event_base_loop(base, EVLOOP_ONCE);
+}
+
+struct testcase_t ssl_testcases[] = {
+#define T(a) ((void *)(a))
+       { "bufferevent_socketpair", regress_bufferevent_openssl,
+         TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_SOCKETPAIR) },
+       { "bufferevent_socketpair_write_after_connect", regress_bufferevent_openssl,
+         TT_ISOLATED, &ssl_setup,
+         T(REGRESS_OPENSSL_SOCKETPAIR|REGRESS_OPENSSL_CLIENT_WRITE) },
        { "bufferevent_filter", regress_bufferevent_openssl,
-         TT_ISOLATED,
-         &basic_setup, (void*)"filter" },
+         TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_FILTER) },
+       { "bufferevent_filter_write_after_connect", regress_bufferevent_openssl,
+         TT_ISOLATED, &ssl_setup,
+         T(REGRESS_OPENSSL_FILTER|REGRESS_OPENSSL_CLIENT_WRITE) },
        { "bufferevent_renegotiate_socketpair", regress_bufferevent_openssl,
-         TT_ISOLATED,
-         &basic_setup, (void*)"socketpair renegotiate" },
+         TT_ISOLATED, &ssl_setup,
+         T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_RENEGOTIATE) },
        { "bufferevent_renegotiate_filter", regress_bufferevent_openssl,
-         TT_ISOLATED,
-         &basic_setup, (void*)"filter renegotiate" },
+         TT_ISOLATED, &ssl_setup,
+         T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_RENEGOTIATE) },
        { "bufferevent_socketpair_startopen", regress_bufferevent_openssl,
-         TT_ISOLATED, &basic_setup, (void*)"socketpair open" },
+         TT_ISOLATED, &ssl_setup,
+         T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_OPEN) },
        { "bufferevent_filter_startopen", regress_bufferevent_openssl,
-         TT_ISOLATED, &basic_setup, (void*)"filter open" },
+         TT_ISOLATED, &ssl_setup,
+         T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_OPEN) },
+
+       { "bufferevent_socketpair_dirty_shutdown", regress_bufferevent_openssl,
+         TT_ISOLATED, &ssl_setup,
+         T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
+       { "bufferevent_filter_dirty_shutdown", regress_bufferevent_openssl,
+         TT_ISOLATED, &ssl_setup,
+         T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
+       { "bufferevent_renegotiate_socketpair_dirty_shutdown",
+         regress_bufferevent_openssl,
+         TT_ISOLATED,
+         &ssl_setup,
+         T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_RENEGOTIATE | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
+       { "bufferevent_renegotiate_filter_dirty_shutdown",
+         regress_bufferevent_openssl,
+         TT_ISOLATED,
+         &ssl_setup,
+         T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_RENEGOTIATE | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
+       { "bufferevent_socketpair_startopen_dirty_shutdown",
+         regress_bufferevent_openssl,
+         TT_ISOLATED, &ssl_setup,
+         T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_OPEN | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
+       { "bufferevent_filter_startopen_dirty_shutdown",
+         regress_bufferevent_openssl,
+         TT_ISOLATED, &ssl_setup,
+         T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_OPEN | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
+
+       { "bufferevent_socketpair_fd", regress_bufferevent_openssl,
+         TT_ISOLATED, &ssl_setup,
+         T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_FD) },
+       { "bufferevent_socketpair_freed", regress_bufferevent_openssl,
+         TT_ISOLATED, &ssl_setup,
+         T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_FREED) },
+       { "bufferevent_socketpair_freed_fd", regress_bufferevent_openssl,
+         TT_ISOLATED, &ssl_setup,
+         T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_FREED | REGRESS_OPENSSL_FD) },
+       { "bufferevent_filter_freed_fd", regress_bufferevent_openssl,
+         TT_ISOLATED, &ssl_setup,
+         T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_FREED | REGRESS_OPENSSL_FD) },
+
+       { "bufferevent_socketpair_timeout", regress_bufferevent_openssl,
+         TT_ISOLATED, &ssl_setup,
+         T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_TIMEOUT) },
+       { "bufferevent_socketpair_timeout_freed_fd", regress_bufferevent_openssl,
+         TT_ISOLATED, &ssl_setup,
+         T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_TIMEOUT | REGRESS_OPENSSL_FREED | REGRESS_OPENSSL_FD) },
 
        { "bufferevent_connect", regress_bufferevent_openssl_connect,
-         TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
+         TT_FORK|TT_NEED_BASE, &ssl_setup, NULL },
+       { "bufferevent_connect_sleep", regress_bufferevent_openssl_connect,
+         TT_FORK|TT_NEED_BASE, &ssl_setup, T(REGRESS_OPENSSL_SLEEP) },
+
+       { "bufferevent_wm", regress_bufferevent_openssl_wm,
+         TT_FORK|TT_NEED_BASE, &ssl_setup, NULL },
+       { "bufferevent_wm_filter", regress_bufferevent_openssl_wm,
+         TT_FORK|TT_NEED_BASE, &ssl_setup, T(REGRESS_OPENSSL_FILTER) },
+       { "bufferevent_wm_defer", regress_bufferevent_openssl_wm,
+         TT_FORK|TT_NEED_BASE, &ssl_setup, T(REGRESS_DEFERRED_CALLBACKS) },
+       { "bufferevent_wm_filter_defer", regress_bufferevent_openssl_wm,
+         TT_FORK|TT_NEED_BASE, &ssl_setup, T(REGRESS_OPENSSL_FILTER|REGRESS_DEFERRED_CALLBACKS) },
+
+#undef T
 
        END_OF_TESTCASES,
 };
index 1f0046031fd40d0e5b704a732b2f949d10bae875..b0ce7dbba2a6369a6a6062857ed7bbd5a282f8cd 100644 (file)
@@ -110,7 +110,7 @@ regress_get_dnsserver(struct event_base *base,
        memset(&my_addr, 0, sizeof(my_addr));
        my_addr.sin_family = AF_INET;
        my_addr.sin_port = htons(*portnum);
-       my_addr.sin_addr.s_addr = htonl(0x7f000001UL);
+       my_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
        if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) {
                evutil_closesocket(sock);
                tt_abort_perror("bind");
@@ -129,17 +129,28 @@ end:
 void
 regress_clean_dnsserver(void)
 {
-       if (dns_port)
+       if (dns_port) {
                evdns_close_server_port(dns_port);
-       if (dns_sock >= 0)
+               dns_port = NULL;
+       }
+       if (dns_sock >= 0) {
                evutil_closesocket(dns_sock);
+               dns_sock = -1;
+       }
 }
 
+static void strtolower(char *s)
+{
+       while (*s) {
+               *s = EVUTIL_TOLOWER_(*s);
+               ++s;
+       }
+}
 void
 regress_dns_server_cb(struct evdns_server_request *req, void *data)
 {
        struct regress_dns_server_table *tab = data;
-       const char *question;
+       char *question;
 
        if (req->nquestions != 1)
                TT_DIE(("Only handling one question at a time; got %d",
@@ -155,6 +166,9 @@ regress_dns_server_cb(struct evdns_server_request *req, void *data)
 
        ++tab->seen;
 
+       if (tab->lower)
+               strtolower(question);
+
        if (!strcmp(tab->anstype, "err")) {
                int err = atoi(tab->ans);
                tt_assert(! evdns_server_request_respond(req, err));
index f90b9c997ab5e523a91313e3e6213aee02005890..040516a5858ef2bef29f6d34e3bcd217041f4ce7 100644 (file)
@@ -34,6 +34,7 @@ struct regress_dns_server_table {
        const char *anstype;
        const char *ans;
        int seen;
+       int lower;
 };
 
 struct evdns_server_port *
index c42668ea8839c150c3d0253e07ab02625c64b802..1e0ce41ff95e3afc40fb99eb1a2732816caa2cf1 100644 (file)
@@ -376,7 +376,7 @@ thread_conditions_simple(void *arg)
                }
                evutil_timeradd(target_delay, &launched_at, &target_time);
                test_timeval_diff_leq(&target_time, &alerted[i].alerted_at,
-                   0, 50);
+                   0, 200);
        }
        tt_int_op(n_broadcast + n_signal + n_timed_out, ==, NUM_THREADS);
        tt_int_op(n_signal, ==, 1);
@@ -564,8 +564,8 @@ end:
        ;
 }
 
-#define TEST(name)                                                     \
-       { #name, thread_##name, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE,   \
+#define TEST(name, f)                                                  \
+       { #name, thread_##name, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE|(f),       \
          &basic_setup, NULL }
 
 struct testcase_t thread_testcases[] = {
@@ -575,11 +575,16 @@ struct testcase_t thread_testcases[] = {
        { "forking", thread_basic, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE,
          &basic_setup, (char*)"forking" },
 #endif
-       TEST(conditions_simple),
+       TEST(conditions_simple, TT_RETRIABLE),
        { "deferred_cb_skew", thread_deferred_cb_skew,
          TT_FORK|TT_NEED_THREADS|TT_OFF_BY_DEFAULT,
          &basic_setup, NULL },
-       TEST(no_events),
+#ifndef _WIN32
+       /****** XXX TODO FIXME windows seems to be having some timing trouble,
+        * looking into it now. / ellzey
+        ******/
+       TEST(no_events, TT_RETRIABLE),
+#endif
        END_OF_TESTCASES
 };
 
index 831b51e50739783986714eb475540bc9ec909dcc..a954fefa5611a87a90b0899f2a72f6be9f33528a 100644 (file)
 #ifndef REGRESS_THREAD_H_INCLUDED_
 #define REGRESS_THREAD_H_INCLUDED_
 
-#ifdef EVENT__HAVE_PTHREADS
+#if defined(_WIN32) /** _WIN32 */
+#define THREAD_T void * /* HANDLE */
+#define THREAD_FN unsigned __stdcall
+#define THREAD_RETURN() return (0)
+#define THREAD_SELF() GetCurrentThreadId()
+#define THREAD_START(threadvar, fn, arg) do {                         \
+       uintptr_t threadhandle = _beginthreadex(NULL,0,fn,(arg),0,NULL);  \
+       (threadvar) = (THREAD_T)threadhandle;                             \
+       thread_setup(threadvar);                                          \
+} while (0)
+#define THREAD_JOIN(th) WaitForSingleObject(th, INFINITE)
+#else /* !_WIN32 */
+#include <pthread.h>
 #define THREAD_T pthread_t
 #define THREAD_FN void *
 #define THREAD_RETURN() return (NULL)
-#define THREAD_START(threadvar, fn, arg) \
-       pthread_create(&(threadvar), NULL, fn, arg)
+#define THREAD_SELF() pthread_self()
+#define THREAD_START(threadvar, fn, arg) do {          \
+       if (!pthread_create(&(threadvar), NULL, fn, arg))  \
+               thread_setup(threadvar);                       \
+} while (0)
 #define THREAD_JOIN(th) pthread_join(th, NULL)
-#else
-#define THREAD_T HANDLE
-#define THREAD_FN unsigned __stdcall
-#define THREAD_RETURN() return (0)
-#define THREAD_START(threadvar, fn, arg) do {          \
-       uintptr_t threadhandle = _beginthreadex(NULL,0,fn,(arg),0,NULL); \
-       (threadvar) = (HANDLE) threadhandle; \
-       } while (0)
-#define THREAD_JOIN(th) WaitForSingleObject(th, INFINITE)
-#endif
+#endif /* \!_WIN32 */
+
+void thread_setup(THREAD_T pthread);
 
 #endif
index 60f085bf1db3f85d3cf0738f00e146cc3d7418b7..45caa2700a4037194f36e0819e0b4449399fa400 100644 (file)
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
+/** For event_debug() usage/coverage */
+#define EVENT_VISIBILITY_WANT_DLLIMPORT
+
 #include "../util-internal.h"
 
 #ifdef _WIN32
@@ -207,6 +211,65 @@ regress_ipv6_parse(void *ptr)
 #endif
 }
 
+static struct ipv6_entry_scope {
+       const char *addr;
+       ev_uint32_t res[4];
+       unsigned scope;
+       enum entry_status status;
+} ipv6_entries_scope[] = {
+       { "2001:DB8::", { 0x20010db8, 0, 0 }, 0, NORMAL },
+       { "2001:DB8::%0", { 0x20010db8, 0, 0, 0 }, 0, NORMAL },
+       { "2001:DB8::%1", { 0x20010db8, 0, 0, 0 }, 1, NORMAL },
+       { "foobar.", { 0, 0, 0, 0 }, 0, BAD },
+       { "2001:DB8::%does-not-exist", { 0, 0, 0, 0 }, 0, BAD },
+       { NULL, { 0, 0, 0, 0,  }, 0, BAD },
+};
+static void
+regress_ipv6_parse_scope(void *ptr)
+{
+#ifdef AF_INET6
+       int i, j;
+       unsigned if_scope;
+
+       for (i = 0; ipv6_entries_scope[i].addr; ++i) {
+               struct ipv6_entry_scope *ent = &ipv6_entries_scope[i];
+               struct in6_addr in6;
+               int r;
+               r = evutil_inet_pton_scope(AF_INET6, ent->addr, &in6,
+                       &if_scope);
+               if (r == 0) {
+                       if (ent->status != BAD)
+                               TT_FAIL(("%s did not parse, but it's a good address!",
+                                       ent->addr));
+                       continue;
+               }
+               if (ent->status == BAD) {
+                       TT_FAIL(("%s parsed, but we expected an error", ent->addr));
+                       continue;
+               }
+               for (j = 0; j < 4; ++j) {
+                       /* Can't use s6_addr32 here; some don't have it. */
+                       ev_uint32_t u =
+                           ((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;
+                       }
+               }
+               if (if_scope != ent->scope) {
+                       TT_FAIL(("%s did not parse as expected.", ent->addr));
+                       continue;
+               }
+       }
+#else
+       TT_BLATHER(("Skipping IPv6 address parsing."));
+#endif
+}
+
+
 static struct sa_port_ent {
        const char *parse;
        int safamily;
@@ -921,6 +984,16 @@ end:
        ;
 }
 
+static void
+test_EVUTIL_IS_(void *arg)
+{
+       tt_int_op(EVUTIL_ISDIGIT_('0'), ==, 1);
+       tt_int_op(EVUTIL_ISDIGIT_('a'), ==, 0);
+       tt_int_op(EVUTIL_ISDIGIT_('\xff'), ==, 0);
+end:
+       ;
+}
+
 static void
 test_evutil_getaddrinfo(void *arg)
 {
@@ -1117,6 +1190,41 @@ end:
                evutil_freeaddrinfo(ai);
 }
 
+static void
+test_evutil_getaddrinfo_AI_ADDRCONFIG(void *arg)
+{
+       struct evutil_addrinfo *ai = NULL;
+       struct evutil_addrinfo hints;
+       int r;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = AF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_flags = EVUTIL_AI_PASSIVE|EVUTIL_AI_ADDRCONFIG;
+
+       /* IPv4 */
+       r = evutil_getaddrinfo("127.0.0.1", "80", &hints, &ai);
+       tt_int_op(r, ==, 0);
+       tt_assert(ai);
+       tt_ptr_op(ai->ai_next, ==, NULL);
+       test_ai_eq(ai, "127.0.0.1:80", SOCK_STREAM, IPPROTO_TCP);
+       evutil_freeaddrinfo(ai);
+       ai = NULL;
+
+       /* IPv6 */
+       r = evutil_getaddrinfo("::1", "80", &hints, &ai);
+       tt_int_op(r, ==, 0);
+       tt_assert(ai);
+       tt_ptr_op(ai->ai_next, ==, NULL);
+       test_ai_eq(ai, "[::1]:80", SOCK_STREAM, IPPROTO_TCP);
+       evutil_freeaddrinfo(ai);
+       ai = NULL;
+
+end:
+       if (ai)
+               evutil_freeaddrinfo(ai);
+}
+
 #ifdef _WIN32
 static void
 test_evutil_loadsyslib(void *arg)
@@ -1378,9 +1486,164 @@ end:
        ;
 }
 
+static void
+create_tm_from_unix_epoch(struct tm *cur_p, const time_t t)
+{
+#ifdef _WIN32
+       struct tm *tmp = gmtime(&t);
+       if (!tmp) {
+               fprintf(stderr, "gmtime: %s (%i)", strerror(errno), (int)t);
+               exit(1);
+       }
+       *cur_p = *tmp;
+#else
+       gmtime_r(&t, cur_p);
+#endif
+}
+
+static struct date_rfc1123_case {
+       time_t t;
+       char date[30];
+} date_rfc1123_cases[] = {
+       {           0, "Thu, 01 Jan 1970 00:00:00 GMT"} /* UNIX time of zero */,
+       {   946684799, "Fri, 31 Dec 1999 23:59:59 GMT"} /* the last moment of the 20th century */,
+       {   946684800, "Sat, 01 Jan 2000 00:00:00 GMT"} /* the first moment of the 21st century */,
+       {   981072000, "Fri, 02 Feb 2001 00:00:00 GMT"},
+       {  1015113600, "Sun, 03 Mar 2002 00:00:00 GMT"},
+       {  1049414400, "Fri, 04 Apr 2003 00:00:00 GMT"},
+       {  1083715200, "Wed, 05 May 2004 00:00:00 GMT"},
+       {  1118016000, "Mon, 06 Jun 2005 00:00:00 GMT"},
+       {  1152230400, "Fri, 07 Jul 2006 00:00:00 GMT"},
+       {  1186531200, "Wed, 08 Aug 2007 00:00:00 GMT"},
+       {  1220918400, "Tue, 09 Sep 2008 00:00:00 GMT"},
+       {  1255132800, "Sat, 10 Oct 2009 00:00:00 GMT"},
+       {  1289433600, "Thu, 11 Nov 2010 00:00:00 GMT"},
+       {  1323648000, "Mon, 12 Dec 2011 00:00:00 GMT"},
+#ifndef _WIN32
+#if EVENT__SIZEOF_TIME_T > 4
+       /** In win32 case we have max   "23:59:59 January 18, 2038, UTC" for time32 */
+       {  4294967296, "Sun, 07 Feb 2106 06:28:16 GMT"} /* 2^32 */,
+       /** In win32 case we have max "23:59:59, December 31, 3000, UTC" for time64 */
+       {253402300799, "Fri, 31 Dec 9999 23:59:59 GMT"} /* long long future no one can imagine */,
+#endif /* time_t != 32bit */
+       {  1456704000, "Mon, 29 Feb 2016 00:00:00 GMT"} /* leap year */,
+#endif
+       {  1435708800, "Wed, 01 Jul 2015 00:00:00 GMT"} /* leap second */,
+       {  1481866376, "Fri, 16 Dec 2016 05:32:56 GMT"} /* the time this test case is generated */,
+       {0, ""} /* end of test cases. */
+};
+
+static void
+test_evutil_date_rfc1123(void *arg)
+{
+       struct tm query;
+       char result[30];
+       size_t i = 0;
+
+       /* Checks if too small buffers are safely accepted. */
+       {
+               create_tm_from_unix_epoch(&query, 0);
+               evutil_date_rfc1123(result, 8, &query);
+               tt_str_op(result, ==, "Thu, 01");
+       }
+
+       /* Checks for testcases. */
+       for (i = 0; ; i++) {
+               struct date_rfc1123_case c = date_rfc1123_cases[i];
+
+               if (strlen(c.date) == 0)
+                       break;
+
+               create_tm_from_unix_epoch(&query, c.t);
+               evutil_date_rfc1123(result, sizeof(result), &query);
+               tt_str_op(result, ==, c.date);
+       }
+
+end:
+       ;
+}
+
+static void
+test_evutil_v4addr_is_local(void *arg)
+{
+       struct sockaddr_in sin;
+       sin.sin_family = AF_INET;
+
+       /* we use evutil_inet_pton() here to fill in network-byte order */
+#define LOCAL(str, yes) do {                                              \
+       tt_int_op(evutil_inet_pton(AF_INET, str, &sin.sin_addr), ==, 1);  \
+       tt_int_op(evutil_v4addr_is_local_(&sin.sin_addr), ==, yes);       \
+} while (0)
+
+       /** any */
+       sin.sin_addr.s_addr = INADDR_ANY;
+       tt_int_op(evutil_v4addr_is_local_(&sin.sin_addr), ==, 1);
+
+       /** loopback */
+       sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+       tt_int_op(evutil_v4addr_is_local_(&sin.sin_addr), ==, 1);
+       LOCAL("127.0.0.1", 1);
+       LOCAL("127.255.255.255", 1);
+       LOCAL("121.0.0.1", 0);
+
+       /** link-local */
+       LOCAL("169.254.0.1", 1);
+       LOCAL("169.254.255.255", 1);
+       LOCAL("170.0.0.0", 0);
+
+       /** Multicast */
+       LOCAL("224.0.0.0", 1);
+       LOCAL("239.255.255.255", 1);
+       LOCAL("240.0.0.0", 0);
+end:
+       ;
+}
+
+static void
+test_evutil_v6addr_is_local(void *arg)
+{
+       struct sockaddr_in6 sin6;
+       struct in6_addr anyaddr = IN6ADDR_ANY_INIT;
+       struct in6_addr loopback = IN6ADDR_LOOPBACK_INIT;
+
+       sin6.sin6_family = AF_INET6;
+#define LOCAL6(str, yes) do {                                              \
+       tt_int_op(evutil_inet_pton(AF_INET6, str, &sin6.sin6_addr), ==, 1);\
+       tt_int_op(evutil_v6addr_is_local_(&sin6.sin6_addr), ==, yes);      \
+} while (0)
+
+       /** any */
+       tt_int_op(evutil_v6addr_is_local_(&anyaddr), ==, 1);
+       LOCAL6("::0", 1);
+
+       /** loopback */
+       tt_int_op(evutil_v6addr_is_local_(&loopback), ==, 1);
+       LOCAL6("::1", 1);
+
+       /** IPV4 mapped */
+       LOCAL6("::ffff:0:0", 1);
+       /** IPv4 translated */
+       LOCAL6("::ffff:0:0:0", 1);
+       /** IPv4/IPv6 translation */
+       LOCAL6("64:ff9b::", 0);
+       /** Link-local */
+       LOCAL6("fe80::", 1);
+       /** Multicast */
+       LOCAL6("ff00::", 1);
+       /** Unspecified */
+       LOCAL6("::", 1);
+
+       /** Global Internet */
+       LOCAL6("2001::", 0);
+       LOCAL6("2001:4860:4802:32::1b", 0);
+end:
+       ;
+}
+
 struct testcase_t util_testcases[] = {
        { "ipv4_parse", regress_ipv4_parse, 0, NULL, NULL },
        { "ipv6_parse", regress_ipv6_parse, 0, NULL, NULL },
+       { "ipv6_parse_scope", regress_ipv6_parse_scope, 0, NULL, NULL },
        { "sockaddr_port_parse", regress_sockaddr_port_parse, 0, NULL, NULL },
        { "sockaddr_port_format", regress_sockaddr_port_format, 0, NULL, NULL },
        { "sockaddr_predicates", test_evutil_sockaddr_predicates, 0,NULL,NULL },
@@ -1393,21 +1656,26 @@ struct testcase_t util_testcases[] = {
        { "upcast", test_evutil_upcast, 0, NULL, NULL },
        { "integers", test_evutil_integers, 0, NULL, NULL },
        { "rand", test_evutil_rand, TT_FORK, NULL, NULL },
+       { "EVUTIL_IS_", test_EVUTIL_IS_, 0, NULL, NULL },
        { "getaddrinfo", test_evutil_getaddrinfo, TT_FORK, NULL, NULL },
        { "getaddrinfo_live", test_evutil_getaddrinfo_live, TT_FORK|TT_OFF_BY_DEFAULT, NULL, NULL },
+       { "getaddrinfo_AI_ADDRCONFIG", test_evutil_getaddrinfo_AI_ADDRCONFIG, TT_FORK|TT_OFF_BY_DEFAULT, NULL, NULL },
 #ifdef _WIN32
        { "loadsyslib", test_evutil_loadsyslib, TT_FORK, NULL, NULL },
 #endif
        { "mm_malloc", test_event_malloc, 0, NULL, NULL },
        { "mm_calloc", test_event_calloc, 0, NULL, NULL },
        { "mm_strdup", test_event_strdup, 0, NULL, NULL },
-       { "usleep", test_evutil_usleep, 0, NULL, NULL },
+       { "usleep", test_evutil_usleep, TT_RETRIABLE, NULL, NULL },
        { "monotonic_res", test_evutil_monotonic_res, 0, &basic_setup, (void*)"" },
        { "monotonic_res_precise", test_evutil_monotonic_res, TT_OFF_BY_DEFAULT, &basic_setup, (void*)"precise" },
        { "monotonic_res_fallback", test_evutil_monotonic_res, TT_OFF_BY_DEFAULT, &basic_setup, (void*)"fallback" },
        { "monotonic_prc", test_evutil_monotonic_prc, 0, &basic_setup, (void*)"" },
-       { "monotonic_prc_precise", test_evutil_monotonic_prc, 0, &basic_setup, (void*)"precise" },
+       { "monotonic_prc_precise", test_evutil_monotonic_prc, TT_RETRIABLE, &basic_setup, (void*)"precise" },
        { "monotonic_prc_fallback", test_evutil_monotonic_prc, 0, &basic_setup, (void*)"fallback" },
+       { "date_rfc1123", test_evutil_date_rfc1123, 0, NULL, NULL },
+       { "evutil_v4addr_is_local", test_evutil_v4addr_is_local, 0, NULL, NULL },
+       { "evutil_v6addr_is_local", test_evutil_v6addr_is_local, 0, NULL, NULL },
        END_OF_TESTCASES,
 };
 
index 8406676932ed337f6b3c55b7f94fc3e4065658ad..5fe774913e26159cb06201c27c82fcd66681f87c 100644 (file)
@@ -143,14 +143,14 @@ zlib_input_filter(struct evbuffer *src, struct evbuffer *dst,
                n = evbuffer_peek(src, -1, NULL, v_in, 1);
                if (n) {
                        p->avail_in = v_in[0].iov_len;
-                       p->next_in = v_in[0].iov_base;
+                       p->next_in = (unsigned char *)v_in[0].iov_base;
                } else {
                        p->avail_in = 0;
                        p->next_in = 0;
                }
 
                evbuffer_reserve_space(dst, 4096, v_out, 1);
-               p->next_out = v_out[0].iov_base;
+               p->next_out = (unsigned char *)v_out[0].iov_base;
                p->avail_out = v_out[0].iov_len;
 
                /* we need to flush zlib if we got a flush */
@@ -197,14 +197,14 @@ zlib_output_filter(struct evbuffer *src, struct evbuffer *dst,
                n = evbuffer_peek(src, -1, NULL, v_in, 1);
                if (n) {
                        p->avail_in = v_in[0].iov_len;
-                       p->next_in = v_in[0].iov_base;
+                       p->next_in = (unsigned char *)v_in[0].iov_base;
                } else {
                        p->avail_in = 0;
                        p->next_in = 0;
                }
 
                evbuffer_reserve_space(dst, 4096, v_out, 1);
-               p->next_out = v_out[0].iov_base;
+               p->next_out = (unsigned char *)v_out[0].iov_base;
                p->avail_out = v_out[0].iov_len;
 
                /* we need to flush zlib if we got a flush */
index aaa03031a1f693f52ea7929f91f7765da36673c6..fe582d57bd33ef1ae8431409882a4422d35830fc 100755 (executable)
@@ -25,19 +25,10 @@ exit_failed() {
     echo "Could not generate regress.gen.\[ch\] using event_rpcgen.sh" >&2
     exit 1
 }
-
-if [ -x /usr/bin/python2 ] ; then
-  PYTHON2=/usr/bin/python2
-elif [ "x`which python2`" != x ] ; then
-  PYTHON2=python2
-else
-  PYTHON2=python
-fi
-
 srcdir=$1
 srcdir=${srcdir:-.}
 
-${PYTHON2} ${srcdir}/../event_rpcgen.py --quiet ${srcdir}/regress.rpc \
+${srcdir}/../event_rpcgen.py --quiet ${srcdir}/regress.rpc \
                test/regress.gen.h test/regress.gen.c
 
 case "$?" in
index 6e2466d5a55c009827630bac9e68b0af4b392538..fd1a17f5bd592feaf0b5d68bd42fc9fbe0b62889 100644 (file)
@@ -182,11 +182,11 @@ main(int argc, char **argv)
        if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
                return (1);
 
-       /* Initalize the event library */
+       /* Initialize the event library */
        if (!(base = event_base_new()))
                return (1);
 
-       /* Initalize a timeout to terminate the test */
+       /* Initialize a timeout to terminate the test */
        timeout = evtimer_new(base,timeout_cb,&timeout);
        /* and watch for writability on one end of the pipe */
        ev = event_new(base,pair[1],EV_WRITE | EV_PERSIST, write_cb, &ev);
index 5b04f354acc90e08f94a6d2d3ac4d57365a4d851..9e6050408d6411b4bde563f28ed7dd6d4935732e 100644 (file)
@@ -24,6 +24,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+#include "../util-internal.h"
 #include "event2/event-config.h"
 
 #ifdef _WIN32
 #include <event.h>
 #include <evutil.h>
 
-#ifdef EVENT____func__
-#define __func__ EVENT____func__
-#endif
-
 struct timeval timeout = {3, 0};
 
 static void
@@ -71,10 +68,6 @@ closed_cb(evutil_socket_t fd, short event, void *arg)
        exit(1);
 }
 
-#ifndef SHUT_WR
-#define SHUT_WR 1
-#endif
-
 int
 main(int argc, char **argv)
 {
@@ -103,7 +96,7 @@ main(int argc, char **argv)
        /* 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);
+       shutdown(pair[0], EVUTIL_SHUT_WR);
 
        /* Dispatch */
        ev = event_new(base, pair[1], EV_CLOSED | EV_TIMEOUT, closed_cb, event_self_cbarg());
@@ -111,6 +104,7 @@ main(int argc, char **argv)
        event_base_dispatch(base);
 
        /* Finalize library */
+       event_free(ev);
        event_base_free(base);
        return 0;
 }
index a9ca5343a2cef093b9bbf4bb611ddefe1d9e8cf1..de2fd88b991eed7f05305f44104440568355e366 100644 (file)
@@ -24,6 +24,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+#include "../util-internal.h"
 #include "event2/event-config.h"
 
 #ifdef _WIN32
 #include <event.h>
 #include <evutil.h>
 
-#ifdef EVENT____func__
-#define __func__ EVENT____func__
-#endif
-
 int test_okay = 1;
 int called = 0;
 struct timeval timeout = {60, 0};
@@ -81,10 +78,6 @@ read_cb(evutil_socket_t fd, short event, void *arg)
        called++;
 }
 
-#ifndef SHUT_WR
-#define SHUT_WR 1
-#endif
-
 int
 main(int argc, char **argv)
 {
@@ -107,12 +100,12 @@ main(int argc, char **argv)
 
        if (send(pair[0], test, (int)strlen(test)+1, 0) < 0)
                return (1);
-       shutdown(pair[0], SHUT_WR);
+       shutdown(pair[0], EVUTIL_SHUT_WR);
 
-       /* Initalize the event library */
+       /* Initialize the event library */
        event_init();
 
-       /* Initalize one event */
+       /* Initialize one event */
        event_set(&ev, pair[1], EV_READ | EV_TIMEOUT, read_cb, &ev);
 
        event_add(&ev, &timeout);
index 4c4eba25e70e5b60afddf3234538cf056c49ec2e..a1fb4ed13bd28e34cf3fb3703f01febc194a6813 100644 (file)
@@ -95,8 +95,11 @@ server_event_cb(struct bufferevent *bev, short events, void *ctx)
        if (events & BEV_EVENT_ERROR) {
                my_perror("Error from bufferevent");
                exit(1);
-       } else if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
+       } else if (events & BEV_EVENT_EOF) {
                bufferevent_free(bev);
+               if (num_requests == MAX_REQUESTS) {
+                       event_base_loopbreak(bufferevent_get_base(bev));
+               }
        }
 }
 
@@ -107,8 +110,7 @@ listener_accept_cb(struct evconnlistener *listener, evutil_socket_t sock,
 {
        struct event_base *base = evconnlistener_get_base(listener);
        struct bufferevent *bev = bufferevent_socket_new(base, sock,
-                                                         BEV_OPT_CLOSE_ON_FREE);
-
+               BEV_OPT_CLOSE_ON_FREE);
        bufferevent_setcb(bev, server_read_cb, NULL, server_event_cb, NULL);
        bufferevent_enable(bev, EV_READ|EV_WRITE);
 }
@@ -154,6 +156,9 @@ start_loop(void)
        start_client(base);
 
        event_base_dispatch(base);
+
+       evconnlistener_free(listener);
+       event_base_free(base);
 }
 
 /*
@@ -178,9 +183,7 @@ client_read_cb(struct bufferevent *bev, void *ctx)
        bufferevent_free(bev);
 
        num_requests++;
-       if (num_requests == MAX_REQUESTS) {
-               event_base_loopbreak(base);
-       } else {
+       if (++num_requests < MAX_REQUESTS) {
                start_client(base);
        }
 }
index 92fbc6b1465947bbb76649ff64288f1108408913..aea49ee9428843a8ca28004c83d08a36a99b8c2c 100644 (file)
@@ -57,7 +57,7 @@ main(int argc, char **argv)
        (void) WSAStartup(wVersionRequested, &wsaData);
 #endif
 
-       /* Initalize the event library */
+       /* Initialize the event library */
        event_init();
 
        return (0);
index 40a1b95984ef1f4803ed668b8b5648f886a40b96..34112e39e14d16b3d08e62e07baea754e3bb7099 100644 (file)
 #include "event2/listener.h"
 #include "event2/thread.h"
 
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
 static struct evutil_weakrand_state weakrand_state;
 
 static int cfg_verbose = 0;
@@ -85,6 +89,18 @@ struct client_state {
 };
 static const struct timeval *ms100_common=NULL;
 
+/* Timers bias for slow CPUs, affects:
+ * - cfg_connlimit_tolerance  (--check-connlimit)
+ * - cfg_grouplimit_tolerance (--check-grouplimit)
+ * - cfg_stddev_tolerance     (--check-stddev)
+ */
+static int timer_bias_events;
+static struct timeval timer_bias_start;
+double timer_bias_spend;
+/* Real cost is less (approximately ~5 usec),
+ * this macros adjusted to make the bias less */
+#define TIMER_MAX_COST_USEC 10
+
 /* info from check_bucket_levels_cb */
 static int total_n_bev_checks = 0;
 static ev_int64_t total_rbucket_level=0;
@@ -244,6 +260,64 @@ group_drain_cb(evutil_socket_t fd, short events, void *arg)
        bufferevent_rate_limit_group_decrement_write(ratelim_group, cfg_group_drain);
 }
 
+static void
+timer_bias_cb(evutil_socket_t fd, short events, void *arg)
+{
+       struct event *event = arg;
+       struct timeval end;
+       struct timeval diff;
+
+       /** XXX: use rdtsc? (portability issues?) */
+       evutil_gettimeofday(&end, NULL);
+       evutil_timersub(&end, &timer_bias_start, &diff);
+       timer_bias_spend += diff.tv_sec + diff.tv_usec * 1e6;
+       timer_bias_start = end;
+
+       if (++timer_bias_events == 100)
+               event_del(event);
+}
+static double
+timer_bias_calculate(void)
+{
+       struct event_config *cfg = NULL;
+       struct event_base *base = NULL;
+       struct event *timer = NULL;
+       struct timeval tv = { 0, 1 };
+       int done = 0;
+
+       cfg = event_config_new();
+       if (!cfg)
+               goto err;
+       if (event_config_set_flag(cfg, EVENT_BASE_FLAG_PRECISE_TIMER))
+               goto err;
+       base = event_base_new_with_config(cfg);
+       if (!base)
+               goto err;
+
+       timer = event_new(base, -1, EV_PERSIST, timer_bias_cb, event_self_cbarg());
+       if (!timer || event_add(timer, &tv)) {
+               goto err;
+       }
+
+       evutil_gettimeofday(&timer_bias_start, NULL);
+       event_base_dispatch(base);
+       done = 1;
+
+err:
+       if (cfg)
+               event_config_free(cfg);
+       if (timer)
+               event_free(timer);
+       if (base)
+               event_base_free(base);
+
+       if (done)
+               return MIN(timer_bias_spend / 1e6 / timer_bias_events / TIMER_MAX_COST_USEC, 5);
+
+       fprintf(stderr, "Couldn't create event for CPU cycle counter bias\n");
+       return -1;
+}
+
 static int
 test_ratelimiting(void)
 {
@@ -266,6 +340,7 @@ test_ratelimiting(void)
        struct event_config *base_cfg;
        struct event *periodic_level_check;
        struct event *group_drain_event=NULL;
+       double timer_bias;
 
        memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
@@ -275,11 +350,23 @@ test_ratelimiting(void)
        if (0)
                event_enable_debug_mode();
 
+       timer_bias = timer_bias_calculate();
+       if (timer_bias > 1) {
+               fprintf(stderr, "CPU is slow, timers bias is %f\n", timer_bias);
+               cfg_connlimit_tolerance  *= timer_bias;
+               cfg_grouplimit_tolerance *= timer_bias;
+               cfg_stddev_tolerance     *= timer_bias;
+       } else {
+               printf("CPU is fast enough, timers bias is %f\n", timer_bias);
+       }
+
        base_cfg = event_config_new();
 
 #ifdef _WIN32
        if (cfg_enable_iocp) {
+#ifdef EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
                evthread_use_windows_threads();
+#endif
                event_config_set_flag(base_cfg, EVENT_BASE_FLAG_STARTUP_IOCP);
        }
 #endif
@@ -340,10 +427,6 @@ test_ratelimiting(void)
 
        bevs = calloc(cfg_n_connections, sizeof(struct bufferevent *));
        states = calloc(cfg_n_connections, sizeof(struct client_state));
-       if (bevs == NULL || states == NULL) {
-               printf("Unable to allocate memory...\n");
-               return 1;
-       }
 
        for (i = 0; i < cfg_n_connections; ++i) {
                bevs[i] = bufferevent_socket_new(base, -1,
@@ -378,7 +461,7 @@ test_ratelimiting(void)
        ratelim_group = NULL; /* So no more responders get added */
        event_free(periodic_level_check);
        if (group_drain_event)
-               event_del(group_drain_event);
+               event_free(group_drain_event);
 
        for (i = 0; i < cfg_n_connections; ++i) {
                bufferevent_free(bevs[i]);
index e7dff7d7265a7f617f0d4626b12404858184e57b..a8b384626385444f7c8bafa31c9fc723028b0eb3 100644 (file)
@@ -25,6 +25,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "event2/event-config.h"
+#include "util-internal.h"
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -41,7 +42,6 @@
 #include "event2/event.h"
 #include "event2/event_compat.h"
 #include "event2/event_struct.h"
-#include "util-internal.h"
 
 int called = 0;
 
@@ -81,8 +81,10 @@ time_cb(evutil_socket_t fd, short event, void *arg)
 int
 main(int argc, char **argv)
 {
+       struct event_base *base;
        struct timeval tv;
        int i;
+
 #ifdef _WIN32
        WORD wVersionRequested;
        WSADATA wsaData;
@@ -94,24 +96,28 @@ main(int argc, char **argv)
 
        evutil_weakrand_seed_(&weakrand_state, 0);
 
-       /* Initalize the event library */
-       event_init();
+       if (getenv("EVENT_DEBUG_LOGGING_ALL")) {
+               event_enable_debug_logging(EVENT_DBG_ALL);
+       }
 
-       for (i = 0; i < NEVENT; i++) {
-               ev[i] = malloc(sizeof(struct event));
-               assert(ev[i] != NULL);
+       base = event_base_new();
 
-               /* Initalize one event */
-               evtimer_set(ev[i], time_cb, ev[i]);
+       for (i = 0; i < NEVENT; i++) {
+               ev[i] = evtimer_new(base, time_cb, event_self_cbarg());
                tv.tv_sec = 0;
                tv.tv_usec = rand_int(50000);
                evtimer_add(ev[i], &tv);
        }
 
-       event_dispatch();
+       i = event_base_dispatch(base);
 
+       printf("event_base_dispatch=%d, called=%d, EVENT=%d\n",
+               i, called, NEVENT);
 
-       printf("%d, %d\n", called, NEVENT);
-       return (called < NEVENT);
+       if (i == 1 && called >= NEVENT) {
+               return EXIT_SUCCESS;
+       } else {
+               return EXIT_FAILURE;
+       }
 }
 
index c379f287cb503d862e3f8f67103b2508bf163872..68e7cd45792dcc87a83f9a6a0f3769ae58e23212 100644 (file)
@@ -24,6 +24,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+#include "../util-internal.h"
 #include "event2/event-config.h"
 
 #ifdef _WIN32
 #include "event2/event_compat.h"
 #include "event2/util.h"
 
-#ifdef EVENT____func__
-#define __func__ EVENT____func__
-#endif
-
 evutil_socket_t pair[2];
 int test_okay = 1;
 int called = 0;
@@ -102,10 +99,10 @@ main(int argc, char **argv)
        if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
                return (1);
 
-       /* Initalize the event library */
+       /* Initialize the event library */
        event_init();
 
-       /* Initalize one event */
+       /* Initialize one event */
        event_set(&ev, pair[1], EV_WRITE, write_cb, &ev);
 
        event_add(&ev, NULL);
index 2b083ac7f3c9ce16d7bab7d0c1ade43015a6415a..f91a8b0445985f461315aa14a74605ccf835207f 100755 (executable)
@@ -28,7 +28,7 @@ fi
 TEST_DIR=.
 TEST_SRC_DIR=.
 
-T=`echo "$0" | sed -e 's/test.sh$//' | sed -e 's/test-script.sh//' `
+T=`echo "$0" | sed -e 's/test.sh$//'`
 if test -x "$T/test-init"
 then
        TEST_DIR="$T"
@@ -82,8 +82,8 @@ run_tests () {
                fi
        done
        announce_n " test-dumpevents: "
-       if python2 -c 'import sys; assert(sys.version_info >= (2, 4))' 2>/dev/null && test -f $TEST_SRC_DIR/check-dumpevents.py; then
-           if $TEST_DIR/test-dumpevents | python2 $TEST_SRC_DIR/check-dumpevents.py >> "$TEST_OUTPUT_FILE" ;
+       if python -c 'import sys; assert(sys.version_info >= (2, 4))' 2>/dev/null && test -f $TEST_SRC_DIR/check-dumpevents.py; then
+           if $TEST_DIR/test-dumpevents | $TEST_SRC_DIR/check-dumpevents.py >> "$TEST_OUTPUT_FILE" ;
            then
                announce OKAY ;
            else
@@ -97,6 +97,7 @@ run_tests () {
                announce "FAILED (output not checked)" ;
            fi
        fi
+
        test -x $TEST_DIR/regress || return
        announce_n " regress: "
        if test "$TEST_OUTPUT_FILE" = "/dev/null" ;
@@ -112,6 +113,21 @@ run_tests () {
                announce FAILED ;
                FAILED=yes
        fi
+
+       announce_n " regress_debug: "
+       if test "$TEST_OUTPUT_FILE" = "/dev/null" ;
+       then
+               EVENT_DEBUG_MODE=1 $TEST_DIR/regress --quiet $REGRESS_ARGS
+       else
+               EVENT_DEBUG_MODE=1 $TEST_DIR/regress $REGRESS_ARGS >>"$TEST_OUTPUT_FILE"
+       fi
+       if test "$?" = "0" ;
+       then
+               announce OKAY ;
+       else
+               announce FAILED ;
+               FAILED=yes
+       fi
 }
 
 do_test() {
@@ -130,15 +146,43 @@ do_test() {
        run_tests
 }
 
-announce "Running tests:"
+usage()
+{
+       cat <<EOL
+  -b   - specify backends
+  -t   - run timerfd test
+  -c   - run changelist test
+  -T   - run timerfd+changelist test
+EOL
+}
+main()
+{
+       backends=$BACKENDS
+       timerfd=0
+       changelist=0
+       timerfd_changelist=0
 
-do_test EPOLL "(timerfd)"
-do_test EPOLL "(changelist)"
-do_test EPOLL "(timerfd+changelist)"
-for i in $BACKENDS; do
-       do_test $i
-done
+       while getopts "b:tcT" c; do
+               case "$c" in
+                       b) backends="$OPTARG";;
+                       t) timerfd=1;;
+                       c) changelist=1;;
+                       T) timerfd_changelist=1;;
+                       ?*) usage && exit 1;;
+               esac
+       done
 
-if test "$FAILED" = "yes"; then
-       exit 1
-fi
+       announce "Running tests:"
+
+       [ $timerfd -eq 0 ] || do_test EPOLL "(timerfd)"
+       [ $changelist -eq 0 ] || do_test EPOLL "(changelist)"
+       [ $timerfd_changelist -eq 0 ] || do_test EPOLL "(timerfd+changelist)"
+       for i in $backends; do
+               do_test $i
+       done
+
+       if test "$FAILED" = "yes"; then
+               exit 1
+       fi
+}
+main "$@"
index 3a8e331055015365f72c861157becfc6ae5ceb47..85dfe74a720e676c80b590cb75d7aa5aced81d97 100644 (file)
@@ -60,6 +60,8 @@
 #include "tinytest_macros.h"
 
 #define LONGEST_TEST_NAME 16384
+#define DEFAULT_TESTCASE_TIMEOUT 30U
+#define MAGIC_EXITCODE 42
 
 static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
 static int n_ok = 0; /**< Number of tests that have passed */
@@ -69,6 +71,7 @@ static int n_skipped = 0; /**< Number of tests that have been skipped. */
 static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
 static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
 static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
+static unsigned int opt_timeout = DEFAULT_TESTCASE_TIMEOUT; /**< Timeout for every test (using alarm()) */
 const char *verbosity_flag = "";
 
 const struct testlist_alias_t *cfg_aliases=NULL;
@@ -79,14 +82,73 @@ const char *cur_test_prefix = NULL; /**< prefix of the current test group */
 /** Name of the current test, if we haven't logged is yet. Used for --quiet */
 const char *cur_test_name = NULL;
 
+static void usage(struct testgroup_t *groups, int list_groups)
+       __attribute__((noreturn));
+static int process_test_option(struct testgroup_t *groups, const char *test);
+
 #ifdef _WIN32
 /* Copy of argv[0] for win32. */
 static char commandname[MAX_PATH+1];
-#endif
 
-static void usage(struct testgroup_t *groups, int list_groups)
-  __attribute__((noreturn));
-static int process_test_option(struct testgroup_t *groups, const char *test);
+struct timeout_thread_args {
+       const testcase_fn *fn;
+       void *env;
+};
+
+static DWORD WINAPI
+timeout_thread_proc_(LPVOID arg)
+{
+       struct timeout_thread_args *args = arg;
+       (*(args->fn))(args->env);
+       ExitThread(cur_test_outcome == FAIL ? 1 : 0);
+}
+
+static enum outcome
+testcase_run_in_thread_(const struct testcase_t *testcase, void *env)
+{
+       /* We will never run testcase in a new thread when the
+       timeout is set to zero */
+       assert(opt_timeout);
+       DWORD ret, tid;
+       HANDLE handle;
+       struct timeout_thread_args args = {
+               &(testcase->fn),
+               env
+       };
+
+       handle =CreateThread(NULL, 0, timeout_thread_proc_,
+               (LPVOID)&args, 0, &tid);
+       ret = WaitForSingleObject(handle, opt_timeout * 1000U);
+       if (ret == WAIT_OBJECT_0) {
+               ret = 0;
+               if (!GetExitCodeThread(handle, &ret)) {
+                       printf("GetExitCodeThread failed\n");
+                       ret = 1;
+               }
+       } else if (ret == WAIT_TIMEOUT) {
+               printf("timeout\n");
+       } else {
+               printf("Wait failed\n");
+       }
+       CloseHandle(handle);
+       if (ret == 0)
+               return OK;
+       else if (ret == MAGIC_EXITCODE)
+               return SKIP;
+       else
+               return FAIL;
+}
+#else
+static unsigned int testcase_set_timeout_(void)
+{
+       return alarm(opt_timeout);
+}
+
+static unsigned int testcase_reset_timeout_(void)
+{
+       return alarm(0);
+}
+#endif
 
 static enum outcome
 testcase_run_bare_(const struct testcase_t *testcase)
@@ -102,7 +164,19 @@ testcase_run_bare_(const struct testcase_t *testcase)
        }
 
        cur_test_outcome = OK;
-       testcase->fn(env);
+       {
+               if (opt_timeout) {
+#ifdef _WIN32
+                       cur_test_outcome = testcase_run_in_thread_(testcase, env);
+#else
+                       testcase_set_timeout_();
+                       testcase->fn(env);
+                       testcase_reset_timeout_();
+#endif
+               } else {
+                       testcase->fn(env);
+               }
+       }
        outcome = cur_test_outcome;
 
        if (testcase->setup) {
@@ -113,7 +187,6 @@ testcase_run_bare_(const struct testcase_t *testcase)
        return outcome;
 }
 
-#define MAGIC_EXITCODE 42
 
 #ifndef NO_FORKING
 
@@ -134,7 +207,7 @@ testcase_run_forked_(const struct testgroup_t *group,
        char buffer[LONGEST_TEST_NAME+256];
        STARTUPINFOA si;
        PROCESS_INFORMATION info;
-       DWORD exitcode;
+       DWORD ret;
 
        if (!in_tinytest_main) {
                printf("\nERROR.  On Windows, testcase_run_forked_ must be"
@@ -144,7 +217,7 @@ testcase_run_forked_(const struct testgroup_t *group,
        if (opt_verbosity>0)
                printf("[forking] ");
 
-       snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s",
+       snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s --timeout 0 %s%s",
                 commandname, verbosity_flag, group->prefix, testcase->name);
 
        memset(&si, 0, sizeof(si));
@@ -155,15 +228,23 @@ testcase_run_forked_(const struct testgroup_t *group,
                           0, NULL, NULL, &si, &info);
        if (!ok) {
                printf("CreateProcess failed!\n");
-               return 0;
+               return FAIL;
+       }
+       ret = WaitForSingleObject(info.hProcess,
+               (opt_timeout ? opt_timeout * 1000U : INFINITE));
+
+       if (ret == WAIT_OBJECT_0) {
+               GetExitCodeProcess(info.hProcess, &ret);
+       } else if (ret == WAIT_TIMEOUT) {
+               printf("timeout\n");
+       } else {
+               printf("Wait failed\n");
        }
-       WaitForSingleObject(info.hProcess, INFINITE);
-       GetExitCodeProcess(info.hProcess, &exitcode);
        CloseHandle(info.hProcess);
        CloseHandle(info.hThread);
-       if (exitcode == 0)
+       if (ret == 0)
                return OK;
-       else if (exitcode == MAGIC_EXITCODE)
+       else if (ret == MAGIC_EXITCODE)
                return SKIP;
        else
                return FAIL;
@@ -198,7 +279,7 @@ testcase_run_forked_(const struct testgroup_t *group,
                return FAIL; /* unreachable */
        } else {
                /* parent */
-               int status, r;
+               int status, r, exitcode;
                char b[1];
                /* Close this now, so that if the other side closes it,
                 * our read fails. */
@@ -206,12 +287,20 @@ testcase_run_forked_(const struct testgroup_t *group,
                r = (int)read(outcome_pipe[0], b, 1);
                if (r == 0) {
                        printf("[Lost connection!] ");
-                       return 0;
+                       return FAIL;
                } else if (r != 1) {
                        perror("read outcome from pipe");
                }
                waitpid(pid, &status, 0);
+               exitcode = WEXITSTATUS(status);
                close(outcome_pipe[0]);
+               if (opt_verbosity>1)
+                       printf("%s%s: exited with %i (%i)\n", group->prefix, testcase->name, exitcode, status);
+               if (exitcode != 0)
+               {
+                       printf("[atexit failure!] ");
+                       return FAIL;
+               }
                return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
        }
 #endif
@@ -253,15 +342,12 @@ testcase_run_one(const struct testgroup_t *group,
        }
 
        if (outcome == OK) {
-               ++n_ok;
                if (opt_verbosity>0 && !opt_forked)
                        puts(opt_verbosity==1?"OK":"");
        } else if (outcome == SKIP) {
-               ++n_skipped;
                if (opt_verbosity>0 && !opt_forked)
                        puts("SKIPPED");
        } else {
-               ++n_bad;
                if (!opt_forked)
                        printf("\n  [%s FAILED]\n", testcase->name);
        }
@@ -312,7 +398,7 @@ tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigne
 static void
 usage(struct testgroup_t *groups, int list_groups)
 {
-       puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
+       puts("Options are: [--verbose|--quiet|--terse] [--no-fork] [--timeout <sec>]");
        puts("  Specify tests by name, or using a prefix ending with '..'");
        puts("  To skip a test, prefix its name with a colon.");
        puts("  To enable a disabled test, prefix its name with a plus.");
@@ -409,8 +495,15 @@ tinytest_main(int c, const char **v, struct testgroup_t *groups)
                                usage(groups, 0);
                        } else if (!strcmp(v[i], "--list-tests")) {
                                usage(groups, 1);
+                       } else if (!strcmp(v[i], "--timeout")) {
+                               ++i;
+                               if (i >= c) {
+                                       fprintf(stderr, "--timeout requires argument\n");
+                                       return -1;
+                               }
+                               opt_timeout = (unsigned)atoi(v[i]);
                        } else {
-                               printf("Unknown option %s.  Try --help\n",v[i]);
+                               fprintf(stderr, "Unknown option %s. Try --help\n", v[i]);
                                return -1;
                        }
                } else {
@@ -428,11 +521,35 @@ tinytest_main(int c, const char **v, struct testgroup_t *groups)
 #endif
 
        ++in_tinytest_main;
-       for (i=0; groups[i].prefix; ++i)
-               for (j=0; groups[i].cases[j].name; ++j)
-                       if (groups[i].cases[j].flags & TT_ENABLED_)
-                               testcase_run_one(&groups[i],
-                                                &groups[i].cases[j]);
+       for (i = 0; groups[i].prefix; ++i) {
+               struct testgroup_t *group = &groups[i];
+               for (j = 0; group->cases[j].name; ++j) {
+                       struct testcase_t *testcase = &group->cases[j];
+                       int test_attempts = 3;
+                       int test_ret_err;
+
+                       if (!(testcase->flags & TT_ENABLED_))
+                               continue;
+
+                       for (;;) {
+                               test_ret_err = testcase_run_one(group, testcase);
+
+                               if (test_ret_err == OK)
+                                       break;
+                               if (!(testcase->flags & TT_RETRIABLE))
+                                       break;
+                               printf("\n  [RETRYING %s (%i)]\n", testcase->name, test_attempts);
+                               if (!test_attempts--)
+                                       break;
+                       }
+
+                       switch (test_ret_err) {
+                               case OK:   ++n_ok;      break;
+                               case SKIP: ++n_skipped; break;
+                               default:   ++n_bad;     break;
+                       }
+               }
+       }
 
        --in_tinytest_main;
 
@@ -462,7 +579,7 @@ tinytest_set_test_failed_(void)
                printf("%s%s: ", cur_test_prefix, cur_test_name);
                cur_test_name = NULL;
        }
-       cur_test_outcome = 0;
+       cur_test_outcome = FAIL;
 }
 
 void
index ed07b26bc006bd6f3c00ced89c0ba90198203466..d321dd4675423a778f2e3d836f95dd70bd8d9804 100644 (file)
 #define TT_ENABLED_  (1<<2)
 /** Flag for a test that's off by default. */
 #define TT_OFF_BY_DEFAULT  (1<<3)
+/** Flag for a test that should be runned again in case of failure (but not
+ * more then 3 times). */
+#define TT_RETRIABLE   (1<<4)
 /** If you add your own flags, make them start at this point. */
-#define TT_FIRST_USER_FLAG (1<<4)
+#define TT_FIRST_USER_FLAG (1<<5)
 
 typedef void (*testcase_fn)(void *);
 
index bdd0e600897b91e448ba3e2517d5bd5799cabe50..f6bfd66a1a1f13d623bb57344a14ad301d9e6bf5 100644 (file)
@@ -36,7 +36,9 @@
 #include <string.h>
 #include <errno.h>
 #include <time.h>
-#ifndef _WIN32
+#ifdef _WIN32
+#include <windows.h>
+#else
 #include <unistd.h>
 #endif
 
index c3728d1fdd61daeb016970abb45c5b0b056c0e7c..e01f5d56cb3370e6c9616983eb477edd18e121e9 100644 (file)
 #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_ = (a);                                               \
-       type val2_ = (b);                                               \
+       type val1_ = (type)(a);                                         \
+       type val2_ = (type)(b);                                         \
        int tt_status_ = (test);                                        \
        if (!tt_status_ || tinytest_get_verbosity_()>1) {               \
                printf_type print_;                                     \
        tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_), \
            "%ld",TT_EXIT_TEST_FUNCTION)
 
+/** To compare SOCKET(windows)/fd */
+#define tt_fd_op(a,op,b) do {                                          \
+       int _a = (int)(a);                                             \
+       int _b = (int)(b);                                             \
+       tt_assert_test_type(_a,_b,#a" "#op" "#b,long,(val1_ op val2_), \
+           "%ld",TT_EXIT_TEST_FUNCTION);                              \
+} while (0)
+
 #define tt_uint_op(a,op,b)                                             \
        tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long,            \
            (val1_ op val2_),"%lu",TT_EXIT_TEST_FUNCTION)
        tt_assert_test_type(a,b,#a" "#op" "#b,const void*,              \
            (val1_ op val2_),"%p",TT_EXIT_TEST_FUNCTION)
 
+/** XXX: have some issues with printing this non-NUL terminated strings */
+#define tt_nstr_op(n,a,op,b)                                           \
+       tt_assert_test_type_opt(a,b,#a" "#op" "#b,const char *,         \
+           (val1_ && val2_ && strncmp(val1_,val2_,(n)) op 0),"<%s>",   \
+           TT_EXIT_TEST_FUNCTION)
+
 #define tt_str_op(a,op,b)                                              \
        tt_assert_test_type_opt(a,b,#a" "#op" "#b,const char *,         \
            (val1_ && val2_ && strcmp(val1_,val2_) op 0),"<%s>",        \
index 2c584fa75263641057a92a659ff305941ca70c57..e79e6a528dee950accdf71ed432175a59fdc72d9 100644 (file)
@@ -54,6 +54,7 @@ extern "C" {
 #endif
 
 long evutil_tv_to_msec_(const struct timeval *tv);
+EVENT2_EXPORT_SYMBOL
 void evutil_usleep_(const struct timeval *tv);
 
 #ifdef _WIN32
@@ -86,8 +87,10 @@ struct evutil_monotonic_timer {
        struct timeval last_time;
 };
 
+EVENT2_EXPORT_SYMBOL
 int evutil_configure_monotonic_time_(struct evutil_monotonic_timer *mt,
     int flags);
+EVENT2_EXPORT_SYMBOL
 int evutil_gettime_monotonic_(struct evutil_monotonic_timer *mt, struct timeval *tv);
 
 
index 4fdedeaf93c575ac4dae47f4ba34775314513261..39576c71ca22f96a5432ce1555f9c6b8534d6bc8 100644 (file)
 extern "C" {
 #endif
 
+/* __has_attribute() wrapper */
+#ifdef __has_attribute
+# define EVUTIL_HAS_ATTRIBUTE __has_attribute
+#endif
+/** clang 3 __has_attribute misbehaves in some versions */
+#if defined(__clang__) && __clang__ == 1
+# if defined(__apple_build_version__)
+#  if __clang_major__ <= 6
+#   undef EVUTIL_HAS_ATTRIBUTE
+#  endif
+# else /* !__apple_build_version__ */
+#  if __clang_major__ == 3 && __clang_minor__ >= 2 && __clang_minor__ <= 5
+#   undef EVUTIL_HAS_ATTRIBUTE
+#  endif
+# endif /* __apple_build_version__ */
+#endif /*\ defined(__clang__) && __clang__ == 1 */
+#ifndef EVUTIL_HAS_ATTRIBUTE
+# define EVUTIL_HAS_ATTRIBUTE(x) 0
+#endif
+
 /* If we need magic to say "inline", get it for free internally. */
 #ifdef EVENT__inline
 #define inline EVENT__inline
 #endif
-#ifdef EVENT____func__
-#define __func__ EVENT____func__
+
+/* Define to appropriate substitute if compiler doesnt have __func__ */
+#if defined(EVENT__HAVE___func__)
+# ifndef __func__
+#  define __func__ __func__
+# endif
+#elif defined(EVENT__HAVE___FUNCTION__)
+# define __func__ __FUNCTION__
+#else
+# define __func__ __FILE__
 #endif
 
 /* A good no-op to use in macro definitions. */
@@ -134,7 +162,7 @@ extern "C" {
 #ifdef SHUT_WR
 #define EVUTIL_SHUT_WR SHUT_WR
 #else
-#define EVUTIL_SHUT_WR 1
+#define EVUTIL_SHUT_WR 1 /* SD_SEND */
 #endif
 #ifdef SHUT_BOTH
 #define EVUTIL_SHUT_BOTH SHUT_BOTH
@@ -219,19 +247,26 @@ extern "C" {
  * when you care about ASCII's notion of character types, because you are about
  * to send those types onto the wire.
  */
+EVENT2_EXPORT_SYMBOL
 int EVUTIL_ISALPHA_(char c);
+EVENT2_EXPORT_SYMBOL
 int EVUTIL_ISALNUM_(char c);
 int EVUTIL_ISSPACE_(char c);
+EVENT2_EXPORT_SYMBOL
 int EVUTIL_ISDIGIT_(char c);
+EVENT2_EXPORT_SYMBOL
 int EVUTIL_ISXDIGIT_(char c);
 int EVUTIL_ISPRINT_(char c);
 int EVUTIL_ISLOWER_(char c);
 int EVUTIL_ISUPPER_(char c);
+EVENT2_EXPORT_SYMBOL
 char EVUTIL_TOUPPER_(char c);
+EVENT2_EXPORT_SYMBOL
 char EVUTIL_TOLOWER_(char c);
 
 /** Remove all trailing horizontal whitespace (space or tab) from the end of a
  * string */
+EVENT2_EXPORT_SYMBOL
 void evutil_rtrim_lws_(char *);
 
 
@@ -258,13 +293,16 @@ void evutil_rtrim_lws_(char *);
  */
 int evutil_open_closeonexec_(const char *pathname, int flags, unsigned mode);
 
+EVENT2_EXPORT_SYMBOL
 int evutil_read_file_(const char *filename, char **content_out, size_t *len_out,
     int is_binary);
 
-int evutil_socket_connect_(evutil_socket_t *fd_ptr, struct sockaddr *sa, int socklen);
+EVENT2_EXPORT_SYMBOL
+int evutil_socket_connect_(evutil_socket_t *fd_ptr, const struct sockaddr *sa, int socklen);
 
 int evutil_socket_finished_connecting_(evutil_socket_t fd);
 
+EVENT2_EXPORT_SYMBOL
 int evutil_ersatz_socketpair_(int, int , int, evutil_socket_t[]);
 
 int evutil_resolve_(int family, const char *hostname, struct sockaddr *sa,
@@ -289,15 +327,18 @@ struct evutil_weakrand_state {
  * attacker can't predict, or which passes strong statistical tests, use the
  * evutil_secure_rng* functions instead.
  */
+EVENT2_EXPORT_SYMBOL
 ev_uint32_t evutil_weakrand_seed_(struct evutil_weakrand_state *state, ev_uint32_t seed);
 /* Return a pseudorandom value between 0 and EVUTIL_WEAKRAND_MAX inclusive.
  * Updates the state in 'seed' as needed -- this value must be protected by a
  * lock.
  */
+EVENT2_EXPORT_SYMBOL
 ev_int32_t evutil_weakrand_(struct evutil_weakrand_state *seed);
 /* Return a pseudorandom value x such that 0 <= x < top. top must be no more
  * than EVUTIL_WEAKRAND_MAX. Updates the state in 'seed' as needed -- this
  * value must be proteced by a lock */
+EVENT2_EXPORT_SYMBOL
 ev_int32_t evutil_weakrand_range_(struct evutil_weakrand_state *seed, ev_int32_t top);
 
 /* Evaluates to the same boolean value as 'p', and hints to the compiler that
@@ -308,6 +349,12 @@ ev_int32_t evutil_weakrand_range_(struct evutil_weakrand_state *seed, ev_int32_t
 #define EVUTIL_UNLIKELY(p) (p)
 #endif
 
+#if EVUTIL_HAS_ATTRIBUTE(fallthrough)
+#define EVUTIL_FALLTHROUGH __attribute__((fallthrough))
+#else
+#define EVUTIL_FALLTHROUGH /* fallthrough */
+#endif
+
 /* Replacement for assert() that calls event_errx on failure. */
 #ifdef NDEBUG
 #define EVUTIL_ASSERT(cond) EVUTIL_NIL_CONDITION_(cond)
@@ -357,24 +404,35 @@ typedef struct evdns_getaddrinfo_request* (*evdns_getaddrinfo_fn)(
     const char *nodename, const char *servname,
     const struct evutil_addrinfo *hints_in,
     void (*cb)(int, struct evutil_addrinfo *, void *), void *arg);
-
+EVENT2_EXPORT_SYMBOL
 void evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo_fn fn);
+typedef void (*evdns_getaddrinfo_cancel_fn)(
+    struct evdns_getaddrinfo_request *req);
+EVENT2_EXPORT_SYMBOL
+void evutil_set_evdns_getaddrinfo_cancel_fn_(evdns_getaddrinfo_cancel_fn fn);
 
+EVENT2_EXPORT_SYMBOL
 struct evutil_addrinfo *evutil_new_addrinfo_(struct sockaddr *sa,
     ev_socklen_t socklen, const struct evutil_addrinfo *hints);
+EVENT2_EXPORT_SYMBOL
 struct evutil_addrinfo *evutil_addrinfo_append_(struct evutil_addrinfo *first,
     struct evutil_addrinfo *append);
+EVENT2_EXPORT_SYMBOL
 void evutil_adjust_hints_for_addrconfig_(struct evutil_addrinfo *hints);
+EVENT2_EXPORT_SYMBOL
 int evutil_getaddrinfo_common_(const char *nodename, const char *servname,
     struct evutil_addrinfo *hints, struct evutil_addrinfo **res, int *portnum);
 
-int evutil_getaddrinfo_async_(struct evdns_base *dns_base,
+struct evdns_getaddrinfo_request *evutil_getaddrinfo_async_(
+    struct evdns_base *dns_base,
     const char *nodename, const char *servname,
     const struct evutil_addrinfo *hints_in,
     void (*cb)(int, struct evutil_addrinfo *, void *), void *arg);
+void evutil_getaddrinfo_cancel_async_(struct evdns_getaddrinfo_request *data);
 
 /** Return true iff sa is a looback address. (That is, it is 127.0.0.1/8, or
  * ::1). */
+EVENT2_EXPORT_SYMBOL
 int evutil_sockaddr_is_loopback_(const struct sockaddr *sa);
 
 
@@ -383,6 +441,7 @@ int evutil_sockaddr_is_loopback_(const struct sockaddr *sa);
     Returns a pointer to out.  Always writes something into out, so it's safe
     to use the output of this function without checking it for NULL.
  */
+EVENT2_EXPORT_SYMBOL
 const char *evutil_format_sockaddr_port_(const struct sockaddr *sa, char *out, size_t outlen);
 
 int evutil_hex_char_to_int_(char c);
@@ -392,6 +451,7 @@ void evutil_free_secure_rng_globals_(void);
 void evutil_free_globals_(void);
 
 #ifdef _WIN32
+EVENT2_EXPORT_SYMBOL
 HMODULE evutil_load_windows_system_library_(const TCHAR *library_name);
 #endif
 
@@ -417,7 +477,7 @@ HMODULE evutil_load_windows_system_library_(const TCHAR *library_name);
 #define EV_SOCK_ARG(x) (x)
 #endif
 
-#if defined(__STDC__) && defined(__STDC_VERSION__)
+#if defined(__STDC__) && defined(__STDC_VERSION__) && !defined(__MINGW64_VERSION_MAJOR)
 #if (__STDC_VERSION__ >= 199901L)
 #define EV_SIZE_FMT "%zu"
 #define EV_SSIZE_FMT "%zd"
@@ -440,6 +500,7 @@ HMODULE evutil_load_windows_system_library_(const TCHAR *library_name);
 #endif
 #endif
 
+EVENT2_EXPORT_SYMBOL
 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);
@@ -472,6 +533,17 @@ evutil_socket_t evutil_eventfd_(unsigned initval, int flags);
 
 void evutil_memclear_(void *mem, size_t len);
 
+struct in_addr;
+struct in6_addr;
+
+/* This is a any, loopback, link-local, multicast */
+EVENT2_EXPORT_SYMBOL
+int evutil_v4addr_is_local_(const struct in_addr *in);
+/* This is a reserved, ipv4compat, ipv4map, loopback,
+ * link-local, multicast, or unspecified address. */
+EVENT2_EXPORT_SYMBOL
+int evutil_v6addr_is_local_(const struct in6_addr *in);
+
 #ifdef __cplusplus
 }
 #endif
index 0be54ae11b50d3d3af99f6d7090bf167949adfe9..c1f4df8f7878052812f457a9492310302e691ac5 100644 (file)
 
 1.3. Event finalization
 
-  [NOTE: This is an experimental feature in Libevent 2.1.3-alpha. Though
-  it seems solid so far, its API might change between now and the first
-  release candidate for Libevent 2.1.]
-
 1.3.1. Why event finalization?
 
   Libevent 2.1 now supports an API for safely "finalizing" events that
   evbuffer_readln() now supports an EVBUFFER_EOL_NUL argument to fetch
   NUL-terminated strings from buffers.
 
+  There's a new evbuffer_set_flags()/evbuffer_clear_flags() that you can use to
+  set EVBUFFER_FLAG_DRAINS_TO_FD.
+
 1.6. New functions and features: bufferevents
 
   You can now use the bufferevent_getcb() function to find out a
   You can manually trigger a bufferevent's callbacks via
   bufferevent_trigger() and bufferevent_trigger_event().
 
+  Also you can manually increment/decrement reference for bufferevent with
+  bufferevent_incref()/bufferevent_decref(), it is useful in situations where a
+  user may reference the bufferevent somewhere else.
+
+  Now bufferevent_openssl supports "dirty" shutdown (when the peer closes the
+  TCP connection before closing the SSL channel), see
+  bufferevent_openssl_get_allow_dirty_shutdown() and
+  bufferevent_openssl_set_allow_dirty_shutdown().
+
+  And also libevent supports openssl 1.1.
+
 1.7. New functions and features: evdns
 
   The previous evdns interface used an "open a test UDP socket" trick in
   There is a new evdns_base_clear_host_addresses() function to remove
   all the /etc/hosts addresses registered with an evdns instance.
 
+  Also there is evdns_base_get_nameserver_addr() for retrieve the address of
+  the 'idx'th configured nameserver.
+
 1.8. New functions and features: evconnlistener
 
   Libevent 2.1 adds the following evconnlistener flags:
     HTTP where the client always speaks first.  On operating systems
     that don't support this functionality, this option has no effect.
 
+    LEV_OPT_REUSEABLE_PORT -- Indicates that we ask to allow multiple servers
+    to bind to the same port if they each set the option Ionly on Linux and
+    >=3.9)
+
     LEV_OPT_DISABLED -- Creates an evconnlistener in the disabled (not
     listening) state.
 
   evhttp_connection_set_timeout_tv() to configure
   microsecond-granularity timeouts.
 
+  Also there is evhttp_connection_set_initial_retry_tv() to change initial
+  retry timeout.
+
   There are a new pair of functions: evhttp_set_bevcb() and
   evhttp_connection_base_bufferevent_new(), that you can use to
   configure which bufferevents will be used for incoming and outgoing
   The evhttp_request_set_on_complete_cb() facility adds a callback to be
   invoked on request completion.
 
+  You can add linger-close for http server by passing
+  EVHTTP_SERVER_LINGERING_CLOSE to evhttp_set_flags(), with this flag server
+  read all the clients body, and only after this respond with an error if the
+  clients body exceed max_body_size (since some clients cannot read response
+  otherwise).
+
+  The evhttp_connection_set_family() can bypass family hint to evdns.
+
+  There are some flags available for connections, which can be installed with
+  evhttp_connection_set_flags():
+  - EVHTTP_CON_REUSE_CONNECTED_ADDR -- reuse connection address on retry (avoid
+    extra DNS request).
+  - EVHTTP_CON_READ_ON_WRITE_ERROR - try read error, since server may already
+    close the connection.
+
+  The evhttp_connection_free_on_completion() can be used to tell libevent to
+  free the connection object after the last request has completed or failed.
+
+  There is evhttp_request_get_response_code_line() if
+  evhttp_request_get_response_code() is not enough for you.
+
+  There are *evhttp_uri_parse_with_flags() that accepts
+  EVHTTP_URI_NONCONFORMANT to tolerate URIs that do not conform to RFC3986.
+  The evhttp_uri_set_flags() can changes the flags on URI.
+
 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.
 
+  The evutil_date_rfc1123() returns date in RFC1123
+
+  There are new API to work with monotonic timer -- monotonic time is
+  guaranteed never to run in reverse, but is not necessarily epoch-based. Use
+  it to make reliable measurements of elapsed time between events even when the
+  system time may be changed:
+  - evutil_monotonic_timer_new()/evutil_monotonic_timer_free()
+  - evutil_configure_monotonic_time()
+  - evutil_gettime_monotonic()
+
+  Use evutil_make_listen_socket_reuseable_port() to set SO_REUSEPORT (linux >=
+  3.9)
+
+  The evutil_make_tcp_listen_socket_deferred() can make a tcp listener socket
+  defer accept()s until there is data to read (TCP_DEFER_ACCEPT).
+
 2. Cross-platform performance improvements
 
 2.1. Better data structures
 5. Testing
 
   Libevent's test coverage level is more or less unchanged since before:
-  we still have over 80% line coverage in our tests on Linux and OSX.
+  we still have over 80% line coverage in our tests on Linux, FreeBSD, NetBSD,
+  Windows, OSX.
   There are some under-tested modules, though: we need to fix those.
+
+  And now we have CI:
+  - https://travis-ci.org/libevent/libevent
+  - https://ci.appveyor.com/project/nmathewson/libevent
+
+  And code coverage:
+  - https://coveralls.io/github/libevent/libevent
+
+  Plus there is vagrant boxes if you what to test it on more OS'es then
+  travis-ci allows, and there is a wrapper (in python) that will parse logs and
+  provide report:
+  - https://github.com/libevent/libevent-extras/blob/master/tools/vagrant-tests.py
+
+6. Contributing
+
+  From now we have contributing guide and checkpatch.sh.
index a50a2df7b4e7bf5a9c95b1e62bf853f2fc80d606..d005b587d4512bae351cc0f05c58826d360c89b0 100644 (file)
@@ -57,7 +57,7 @@ extern struct event_list timequeue;
 extern struct event_list addqueue;
 
 struct win_fd_set {
-       u_int fd_count;
+       unsigned int fd_count;
        SOCKET fd_array[1];
 };
 
@@ -326,6 +326,8 @@ win32_dispatch(struct event_base *base, struct timeval *tv)
        event_debug(("%s: select returned %d", __func__, res));
 
        if (res <= 0) {
+               event_debug(("%s: %s", __func__,
+                   evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())));
                return res;
        }
 
@@ -350,7 +352,6 @@ win32_dispatch(struct event_base *base, struct timeval *tv)
                }
        }
        if (win32op->writeset_out->fd_count) {
-               SOCKET s;
                i = evutil_weakrand_range_(&base->weakrand_seed,
                    win32op->writeset_out->fd_count);
                for (j=0; j<win32op->writeset_out->fd_count; ++j) {