Merge pull request #125 from libevent/master

update upstream
This commit is contained in:
Mark Ellzey 2015-12-21 15:33:50 -08:00
commit 01c7b45111
56 changed files with 2821 additions and 968 deletions

6
.gitignore vendored
View File

@ -23,6 +23,9 @@
*.gcov
*.gcda
# gdb stuff
.gdb_history
# Autotools stuff
.deps
.dirstamp
@ -36,6 +39,7 @@ Makefile.in
# ctags stuff
TAGS
tags
# Stuff made by our makefiles
libevent.pc
@ -80,10 +84,12 @@ libevent_openssl.pc
/sample/event-read-fifo
/sample/hello-world
/sample/http-server
/sample/http-connect
/sample/le-proxy
/sample/https-client
/sample/signal-test
/sample/time-test
/sample/event-test
/test-driver
/test/bench

View File

@ -3,7 +3,9 @@ env:
- EVENT_BUILD_METHOD=cmake EVENT_CMAKE_OPTIONS=""
- EVENT_BUILD_METHOD=cmake EVENT_CMAKE_OPTIONS="-DEVENT__DISABLE_OPENSSL=ON"
- EVENT_BUILD_METHOD=cmake EVENT_CMAKE_OPTIONS="-DEVENT__DISABLE_THREAD_SUPPORT=ON"
- EVENT_BUILD_METHOD=autotools
- EVENT_BUILD_METHOD=cmake EVENT_CMAKE_OPTIONS="-DEVENT__DISABLE_DEBUG_MODE=ON"
- EVENT_BUILD_METHOD=autotools EVENT_CONFIGURE_OPTIONS=""
- EVENT_BUILD_METHOD=autotools EVENT_CONFIGURE_OPTIONS="--disable-debug-mode"
language: c
compiler:
- gcc
@ -12,5 +14,8 @@ install:
- sudo apt-get update -qq
- sudo apt-get install -y -qq zlib1g-dev libssl-dev build-essential automake autoconf cmake
script:
- if [ "$EVENT_BUILD_METHOD" = "autotools" ]; then ./autogen.sh && ./configure && make && make verify; fi
- if [ "$EVENT_BUILD_METHOD" = "autotools" ]; then ./autogen.sh && ./configure $EVENT_CONFIGURE_OPTIONS && make && make verify; fi
- if [ "$EVENT_BUILD_METHOD" = "cmake" ]; then mkdir build && cd build && cmake .. $EVENT_CMAKE_OPTIONS && cmake --build . && CTEST_OUTPUT_ON_FAILURE=1 cmake --build . --target verify; fi
notifications:
irc: "irc.oftc.net#libevent"

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,14 @@
<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/github/libevent/libevent?branch=master&svg=true)](https://ci.appveyor.com/project/nmathewson/libevent)
[![Travis Build Status](https://travis-ci.org/libevent/libevent.svg?branch=master)](https://travis-ci.org/libevent/libevent)
# 0. BUILDING AND INSTALLATION (Briefly)
## Autoconf
@ -7,6 +18,72 @@
$ make verify # (optional)
$ sudo make install
## Cmake (General)
The following Libevent specific Cmake variables ar as follows (the values being
the default).
```
# Installation directory for executables
EVENT_INSTALL_BIN_DIR:PATH=bin
# Installation directory for CMake files
EVENT_INSTALL_CMAKE_DIR:PATH=lib/cmake/libevent
## Installation directory for header files
EVENT_INSTALL_INCLUDE_DIR:PATH=include
## Installation directory for libraries
EVENT_INSTALL_LIB_DIR:PATH=lib
## Define if libevent should be built with shared libraries instead of archives
EVENT__BUILD_SHARED_LIBRARIES:BOOL=OFF
# 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 exectuables
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 encrpytion
EVENT__DISABLE_OPENSSL:BOOL=ON
# 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 crosscompiling forces running a test program that verifies that Kqueue
# works with pipes. Note that this requires you to manually run the test program
# on the the cross compilation target to verify that it works. See cmake
# documentation for try_run for more details
EVENT__FORCE_KQUEUE_CHECK:BOOL=OFF
# set EVENT_STAGE_VERSION
EVENT__STAGE_VERSION:STRING=beta
```
__More variables can be found by running `cmake -LAH <sourcedir_path>`__
## CMake (Windows)
Install CMake: <http://www.cmake.org>

View File

@ -1,11 +1,45 @@
version: 2.1.5.{build}
shallow_clone: true
os: Visual Studio 2015 RC
build:
verbosity: detailed
environment:
global:
CYG_ROOT: C:/MinGW/msys/1.0
init:
- 'echo Building libevent %version% for Windows'
- 'echo System architecture: %PLATFORM%'
- 'echo Repo build branch is: %APPVEYOR_REPO_BRANCH%'
- 'echo Build folder is: %APPVEYOR_BUILD_FOLDER%'
install:
- appveyor DownloadFile http://slproweb.com/download/Win32OpenSSL-1_0_1L.exe
- Win32OpenSSL-1_0_1L.exe /silent /verysilent /sp- /suppressmsgboxes
- set PATH=%PATH%;C:\MinGW\msys\1.0\bin;C:\MinGW\bin
- appveyor DownloadFile https://strcpy.net/packages/Win32OpenSSL-1_0_2a.exe
- Win32OpenSSL-1_0_2a.exe /silent /verysilent /sp- /suppressmsgboxes
build_script:
- md build
- cd build
- cmake ..
- cmake --build .
- ctest --output-on-failure
- cmd: 'echo Cygwin root is: %CYG_ROOT%'
- cmd: 'echo Build folder is: %APPVEYOR_BUILD_FOLDER%'
- cmd: 'echo Repo build branch is: %APPVEYOR_REPO_BRANCH%'
- cmd: 'echo Repo build commit is: %APPVEYOR_REPO_COMMIT%'
- cmd: "echo installing stuff"
- cmd: 'echo "C:\MinGW /mingw" >%CYG_ROOT%/etc/fstab'
- cmd: 'C:\MinGW\bin\mingw-get install autotools autoconf automake python'
- cmd: 'echo Autogen running...'
- cmd: '%CYG_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null;mount C:/MinGW /mingw; bash -x ./autogen.sh; ./configure; make; make verify"'
#install:
# - appveyor DownloadFile https://strcpy.net/packages/Win32OpenSSL-1_0_2a.exe
# - Win32OpenSSL-1_0_2a.exe /silent /verysilent /sp- /suppressmsgboxes
#build_script:
# - md build
# - cd build
# - cmake ..
# - cmake --build .
# - ctest --output-on-failure
cache:
- C:\OpenSSL-Win32

View File

@ -184,7 +184,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;
@ -2909,7 +2909,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;

View 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,18 @@ 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;
};
/** Possible operations for a control callback. */
@ -327,14 +350,17 @@ int bufferevent_disable_hard_(struct bufferevent *bufev, short event);
/** Internal: Set up locking on a bufferevent. If lock is set, use it.
* Otherwise, use a new lock. */
int bufferevent_enable_locking_(struct bufferevent *bufev, void *lock);
/** 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. */
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. */
int bufferevent_decref_and_unlock_(struct bufferevent *bufev);
@ -386,9 +412,13 @@ void bufferevent_init_generic_timeout_cbs_(struct bufferevent *bev);
* 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. */
int bufferevent_generic_adj_timeouts_(struct bufferevent *bev);
int bufferevent_generic_adj_existing_timeouts_(struct bufferevent *bev);
enum bufferevent_options bufferevent_get_options_(struct bufferevent *bev);
const struct sockaddr*
bufferevent_socket_get_conn_address_(struct bufferevent *bev);
/** 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) \

View File

@ -777,7 +777,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 +793,15 @@ 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);
/* 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);
@ -965,10 +969,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);

View File

@ -536,10 +536,20 @@ 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:
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);
}
case BEV_CTRL_GET_FD:
case BEV_CTRL_CANCEL_ALL:
default:
return -1;
}
return -1;
}

View File

@ -320,8 +320,6 @@ 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;
@ -957,6 +955,18 @@ be_openssl_writeeventcb(evutil_socket_t fd, short what, void *ptr)
bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
}
static int
be_openssl_auto_fd(struct bufferevent_openssl *bev_ssl, int 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,30 +978,36 @@ 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;
}
}
static int
set_open_callbacks_auto(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
{
fd = be_openssl_auto_fd(bev_ssl, fd);
return set_open_callbacks(bev_ssl, fd);
}
static int
do_handshake(struct bufferevent_openssl *bev_ssl)
@ -1011,9 +1027,10 @@ do_handshake(struct bufferevent_openssl *bev_ssl)
decrement_buckets(bev_ssl);
if (r==1) {
int 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,
@ -1073,28 +1090,31 @@ set_handshake_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
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;
}
}
static int
set_handshake_callbacks_auto(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
{
fd = be_openssl_auto_fd(bev_ssl, fd);
return set_handshake_callbacks(bev_ssl, fd);
}
int
bufferevent_ssl_renegotiate(struct bufferevent *bev)
{
@ -1104,7 +1124,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_auto(bev_ssl, -1) < 0)
return -1;
if (!bev_ssl->underlying)
return do_handshake(bev_ssl);
@ -1119,14 +1139,13 @@ be_openssl_outbuf_cb(struct evbuffer *buf,
int r = 0;
/* XXX need to hold a reference here. */
if (cbinfo->n_added && bev_ssl->state == BUFFEREVENT_SSL_OPEN) {
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 (cbinfo->n_added && bev_ssl->state == BUFFEREVENT_SSL_OPEN &&
cbinfo->orig_size == 0) {
r = bufferevent_add_event_(&bev_ssl->bev.bev.ev_write,
&bev_ssl->bev.bev.timeout_write);
}
/* XXX Handle r < 0 */
(void)r;
(void)r;
}
@ -1136,9 +1155,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 +1178,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);
@ -1233,23 +1247,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);
}
}
@ -1274,25 +1272,16 @@ be_openssl_ctrl(struct bufferevent *bev,
BIO *bio;
bio = BIO_new_socket(data->fd, 0);
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)
if (bev_ssl->state == BUFFEREVENT_SSL_OPEN && data->fd >= 0)
return set_open_callbacks(bev_ssl, data->fd);
else {
return set_handshake_callbacks(bev_ssl, 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);
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:
@ -1360,16 +1349,16 @@ bufferevent_openssl_new_impl(struct event_base *base,
switch (state) {
case BUFFEREVENT_SSL_ACCEPTING:
SSL_set_accept_state(bev_ssl->ssl);
if (set_handshake_callbacks(bev_ssl, fd) < 0)
if (set_handshake_callbacks_auto(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)
if (set_handshake_callbacks_auto(bev_ssl, fd) < 0)
goto err;
break;
case BUFFEREVENT_SSL_OPEN:
if (set_open_callbacks(bev_ssl, fd) < 0)
if (set_open_callbacks_auto(bev_ssl, fd) < 0)
goto err;
break;
default:
@ -1382,15 +1371,6 @@ 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;

View File

@ -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);

View 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,35 @@ 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 =
EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
return (struct sockaddr *)&bev_p->conn_address;
}
static void
bufferevent_socket_set_conn_address_fd(struct bufferevent_private *bev_p, int fd)
{
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);
}
static void
bufferevent_socket_set_conn_address(struct bufferevent_private *bev_p,
struct sockaddr *addr, size_t addrlen)
{
EVUTIL_ASSERT(addrlen <= sizeof(bev_p->conn_address));
memcpy(&bev_p->conn_address, addr, addrlen);
}
static void
bufferevent_socket_outbuf_cb(struct evbuffer *buf,
@ -115,7 +136,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? */
}
}
@ -239,6 +260,7 @@ bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
goto done;
} else {
connected = 1;
bufferevent_socket_set_conn_address_fd(bufev_p, fd);
#ifdef _WIN32
if (BEV_IS_ASYNC(bufev)) {
event_del(&bufev->ev_write);
@ -351,7 +373,7 @@ 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);
@ -457,6 +479,7 @@ 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_p, ai->ai_addr, (int)ai->ai_addrlen);
r = bufferevent_socket_connect(bev, ai->ai_addr, (int)ai->ai_addrlen);
(void)r;
bufferevent_decref_and_unlock_(bev);
@ -478,23 +501,23 @@ bufferevent_socket_connect_hostname(struct bufferevent *bev,
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_UNLOCK(bev);
if (err == 0) {
return 0;
@ -550,14 +573,12 @@ 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;
}
@ -592,29 +613,6 @@ be_socket_destruct(struct bufferevent *bufev)
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;
}
static int
be_socket_flush(struct bufferevent *bev, short iotype,
enum bufferevent_flush_mode mode)

View File

@ -0,0 +1,15 @@
include(CheckCCompilerFlag)
macro(add_compiler_flags _flags)
foreach(flag ${_flags})
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()

View File

@ -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)

45
cmake/FindGit.cmake Normal file
View File

@ -0,0 +1,45 @@
# The module defines the following variables:
# GIT_EXECUTABLE - path to git command line client
# GIT_FOUND - true if the command line client was found
# Example usage:
# find_package(Git)
# if(GIT_FOUND)
# message("git found: ${GIT_EXECUTABLE}")
# endif()
#=============================================================================
# Copyright 2010 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distributed this file outside of CMake, substitute the full
# License text for the above reference.)
# Look for 'git' or 'eg' (easy git)
set(git_names git eg)
# Prefer .cmd variants on Windows unless running in a Makefile
# in the MSYS shell.
if(WIN32)
if(NOT CMAKE_GENERATOR MATCHES "MSYS")
set(git_names git.cmd git eg.cmd eg)
endif()
endif()
find_program(GIT_EXECUTABLE
NAMES ${git_names}
DOC "git command line client")
mark_as_advanced(GIT_EXECUTABLE)
# Handle the QUIETLY and REQUIRED arguments and set GIT_FOUND to TRUE if
# all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Git DEFAULT_MSG GIT_EXECUTABLE)

53
cmake/VersionViaGit.cmake Normal file
View File

@ -0,0 +1,53 @@
# 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
#
# Usful for auto-versionin in ou CMakeLists
#
# EVENT_GIT___VERSION_FOUND - Version variables foud
# 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()
# if (EVENT_GIT___VERSION_FOUND)
# 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(EVENT_GIT___VERSION_FOUND FALSE)
# set our defaults.
set(EVENT_GIT___VERSION_MAJOR 2)
set(EVENT_GIT___VERSION_MINOR 1)
set(EVENT_GIT___VERSION_PATCH 5)
set(EVENT_GIT___VERSION_STAGE "beta")
find_package(Git)
if (GIT_FOUND)
execute_process(
COMMAND
${GIT_EXECUTABLE} describe --abbrev=0
WORKING_DIRECTORY
${PROJECT_SOURCE_DIR}
RESULT_VARIABLE
GITRET
OUTPUT_VARIABLE
GITVERSION)
if (GITRET EQUAL 0)
string(REGEX REPLACE "^release-([0-9]+)\\.([0-9]+)\\.([0-9]+)-(.*)" "\\1" EVENT_GIT___VERSION_MAJOR ${GITVERSION})
string(REGEX REPLACE "^release-([0-9]+)\\.([0-9]+)\\.([0-9]+)-(.*)" "\\2" EVENT_GIT___VERSION_MINOR ${GITVERSION})
string(REGEX REPLACE "^release-([0-9]+)\\.([0-9]+)\\.([0-9]+)-(.*)" "\\3" EVENT_GIT___VERSION_PATCH ${GITVERSION})
string(REGEX REPLACE "^release-([0-9]+)\\.([0-9]+)\\.([0-9]+)-([aA-zZ]+)" "\\4" EVENT_GIT___VERSION_STAGE ${GITVERSION})
endif()
endif()
endmacro()

View File

@ -369,6 +369,7 @@ AC_CHECK_FUNCS([ \
unsetenv \
usleep \
vasprintf \
getservbyname \
])
AM_CONDITIONAL(STRLCPY_IMPL, [test x"$ac_cv_func_strlcpy" = xno])
@ -394,7 +395,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.)
@ -763,6 +763,10 @@ fi
# check if we have and should use openssl
AM_CONDITIONAL(OPENSSL, [test "$enable_openssl" != "no" && test "$have_openssl" = "yes"])
if test "x$enable_openssl" = "xyes"; then
AC_SEARCH_LIBS([ERR_remove_thread_state], [crypto],
[AC_DEFINE(HAVE_ERR_REMOVE_THREAD_STATE, 1, [Define to 1 if you have ERR_remove_thread_stat().])])
fi
# Add some more warnings which we use in development but not in the
# released versions. (Some relevant gcc versions can't handle these.)

39
epoll.c
View 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,
@ -271,14 +288,7 @@ epoll_apply_one_change(struct event_base *base,
epev.data.fd = ch->fd;
epev.events = events;
if (epoll_ctl(epollop->epfd, op, ch->fd, &epev) == 0) {
event_debug(("Epoll %s(%d) on fd %d okay. [old events were %d; read change was %d; write change was %d; 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;
}

85
evdns.c
View File

@ -1060,24 +1060,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 +1068,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)
@ -4034,15 +4032,6 @@ evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests)
/* TODO(nickm) we might need to refcount here. */
for (server = base->server_head; server; server = server_next) {
server_next = server->next;
evdns_nameserver_free(server);
if (server_next == base->server_head)
break;
}
base->server_head = NULL;
base->global_good_nameservers = 0;
for (i = 0; i < base->n_req_heads; ++i) {
while (base->req_heads[i]) {
if (fail_requests)
@ -4057,6 +4046,14 @@ evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests)
}
base->global_requests_inflight = base->global_requests_waiting = 0;
for (server = base->server_head; server; server = server_next) {
server_next = server->next;
evdns_nameserver_free(server);
if (server_next == base->server_head)
break;
}
base->server_head = NULL;
base->global_good_nameservers = 0;
if (base->global_search_state) {
for (dom = base->global_search_state->head; dom; dom = dom_next) {
@ -4406,17 +4403,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;
@ -4450,7 +4453,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;
}

View File

@ -11,8 +11,11 @@
/* Numeric representation of the version */
#define EVENT__NUMERIC_VERSION @EVENT_NUMERIC_VERSION@
#define EVENT__PACKAGE_VERSION "@EVENT_PACKAGE_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@"
@ -33,467 +36,499 @@
#define EVENT__PACKAGE_TARNAME ""
/* Define if libevent should build without support for a debug mode */
#cmakedefine EVENT__DISABLE_DEBUG_MODE 0
#cmakedefine EVENT__DISABLE_DEBUG_MODE
/* Define if libevent should not allow replacing the mm functions */
#cmakedefine EVENT__DISABLE_MM_REPLACEMENT 0
#cmakedefine EVENT__DISABLE_MM_REPLACEMENT
/* Define if libevent should not be compiled with thread support */
#cmakedefine EVENT__DISABLE_THREAD_SUPPORT 0
#cmakedefine EVENT__DISABLE_THREAD_SUPPORT
/* Define to 1 if you have the `accept4' function. */
#cmakedefine EVENT__HAVE_ACCEPT4 1
#cmakedefine EVENT__HAVE_ACCEPT4
/* Define to 1 if you have the `arc4random' function. */
#cmakedefine EVENT__HAVE_ARC4RANDOM 1
#cmakedefine EVENT__HAVE_ARC4RANDOM
/* Define to 1 if you have the `arc4random_buf' function. */
#cmakedefine EVENT__HAVE_ARC4RANDOM_BUF 1
#cmakedefine EVENT__HAVE_ARC4RANDOM_BUF
/* Define if clock_gettime is available in libc */
#cmakedefine EVENT__DNS_USE_CPU_CLOCK_FOR_ID 1
#cmakedefine EVENT__DNS_USE_CPU_CLOCK_FOR_ID
/* Define is no secure id variant is available */
#cmakedefine EVENT__DNS_USE_GETTIMEOFDAY_FOR_ID 1
#cmakedefine EVENT__DNS_USE_FTIME_FOR_ID 1
#cmakedefine EVENT__DNS_USE_GETTIMEOFDAY_FOR_ID
#cmakedefine EVENT__DNS_USE_FTIME_FOR_ID
/* Define to 1 if you have the <arpa/inet.h> header file. */
#cmakedefine EVENT__HAVE_ARPA_INET_H 1
#cmakedefine EVENT__HAVE_ARPA_INET_H
/* Define to 1 if you have the `clock_gettime' function. */
#cmakedefine EVENT__HAVE_CLOCK_GETTIME 1
#cmakedefine EVENT__HAVE_CLOCK_GETTIME
/* Define to 1 if you have the declaration of `CTL_KERN'. */
#cmakedefine EVENT__HAVE_DECL_CTL_KERN 1
#cmakedefine EVENT__HAVE_DECL_CTL_KERN
/* Define to 1 if you have the declaration of `KERN_ARND'. */
#cmakedefine EVENT__HAVE_DECL_KERN_ARND 0
#cmakedefine EVENT__HAVE_DECL_KERN_ARND
/* Define to 1 if you have the declaration of `KERN_RANDOM'. */
#cmakedefine EVENT__HAVE_DECL_KERN_RANDOM 1
#cmakedefine EVENT__HAVE_DECL_KERN_RANDOM
/* Define if /dev/poll is available */
#cmakedefine EVENT__HAVE_DEVPOLL 1
#cmakedefine EVENT__HAVE_DEVPOLL
/* Define to 1 if you have the <netdb.h> header file. */
#cmakedefine EVENT__HAVE_NETDB_H 1
#cmakedefine EVENT__HAVE_NETDB_H
/* Define to 1 if fd_mask type is defined */
#cmakedefine EVENT__HAVE_FD_MASK 1
#cmakedefine EVENT__HAVE_FD_MASK
/* Define to 1 if the <sys/queue.h> header file defines TAILQ_FOREACH. */
#cmakedefine EVENT__HAVE_TAILQFOREACH 1
#cmakedefine EVENT__HAVE_TAILQFOREACH
/* Define to 1 if you have the <dlfcn.h> header file. */
#cmakedefine EVENT__HAVE_DLFCN_H 1
#cmakedefine EVENT__HAVE_DLFCN_H
/* Define if your system supports the epoll system calls */
#cmakedefine EVENT__HAVE_EPOLL 1
#cmakedefine EVENT__HAVE_EPOLL
/* Define to 1 if you have the `epoll_create1' function. */
#cmakedefine EVENT__HAVE_EPOLL_CREATE1 1
#cmakedefine EVENT__HAVE_EPOLL_CREATE1
/* Define to 1 if you have the `epoll_ctl' function. */
#cmakedefine EVENT__HAVE_EPOLL_CTL 1
#cmakedefine EVENT__HAVE_EPOLL_CTL
/* Define to 1 if you have the `eventfd' function. */
#cmakedefine EVENT__HAVE_EVENTFD 1
#cmakedefine EVENT__HAVE_EVENTFD
/* Define if your system supports event ports */
#cmakedefine EVENT__HAVE_EVENT_PORTS 1
#cmakedefine EVENT__HAVE_EVENT_PORTS
/* Define to 1 if you have the `fcntl' function. */
#cmakedefine EVENT__HAVE_FCNTL 1
#cmakedefine EVENT__HAVE_FCNTL
/* Define to 1 if you have the <fcntl.h> header file. */
#cmakedefine EVENT__HAVE_FCNTL_H 1
#cmakedefine EVENT__HAVE_FCNTL_H
/* Define to 1 if you have the `getaddrinfo' function. */
#cmakedefine EVENT__HAVE_GETADDRINFO 1
#cmakedefine EVENT__HAVE_GETADDRINFO
/* Define to 1 if you have the `getegid' function. */
#cmakedefine EVENT__HAVE_GETEGID 1
#cmakedefine EVENT__HAVE_GETEGID
/* Define to 1 if you have the `geteuid' function. */
#cmakedefine EVENT__HAVE_GETEUID 1
#cmakedefine EVENT__HAVE_GETEUID
/* 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
#cmakedefine EVENT__HAVE_GETHOSTBYNAME_R
/* Define this if gethostbyname_r takes 3 arguments */
#cmakedefine EVENT__HAVE_GETHOSTBYNAME_R_3_ARG 1
#cmakedefine EVENT__HAVE_GETHOSTBYNAME_R_3_ARG
/* Define this if gethostbyname_r takes 5 arguments */
#cmakedefine EVENT__HAVE_GETHOSTBYNAME_R_5_ARG 1
#cmakedefine EVENT__HAVE_GETHOSTBYNAME_R_5_ARG
/* Define this if gethostbyname_r takes 6 arguments */
#cmakedefine EVENT__HAVE_GETHOSTBYNAME_R_6_ARG 1
#cmakedefine EVENT__HAVE_GETHOSTBYNAME_R_6_ARG
/* Define to 1 if you have the `getifaddrs' function. */
#cmakedefine EVENT__HAVE_GETIFADDRS 1
#cmakedefine EVENT__HAVE_GETIFADDRS
/* Define to 1 if you have the `getnameinfo' function. */
#cmakedefine EVENT__HAVE_GETNAMEINFO 1
#cmakedefine EVENT__HAVE_GETNAMEINFO
/* Define to 1 if you have the `getprotobynumber' function. */
#cmakedefine EVENT__HAVE_GETPROTOBYNUMBER 1
#cmakedefine EVENT__HAVE_GETPROTOBYNUMBER
/* Define to 1 if you have the `getservbyname' function. */
#cmakedefine EVENT__HAVE_GETSERVBYNAME 1
#cmakedefine EVENT__HAVE_GETSERVBYNAME
/* Define to 1 if you have the `gettimeofday' function. */
#cmakedefine EVENT__HAVE_GETTIMEOFDAY 1
#cmakedefine EVENT__HAVE_GETTIMEOFDAY
/* Define to 1 if you have the <ifaddrs.h> header file. */
#cmakedefine EVENT__HAVE_IFADDRS_H 1
#cmakedefine EVENT__HAVE_IFADDRS_H
/* Define to 1 if you have the `inet_ntop' function. */
#cmakedefine EVENT__HAVE_INET_NTOP 1
#cmakedefine EVENT__HAVE_INET_NTOP
/* Define to 1 if you have the `inet_pton' function. */
#cmakedefine EVENT__HAVE_INET_PTON 1
#cmakedefine EVENT__HAVE_INET_PTON
/* Define to 1 if you have the <inttypes.h> header file. */
#cmakedefine EVENT__HAVE_INTTYPES_H 1
#cmakedefine EVENT__HAVE_INTTYPES_H
/* Define to 1 if you have the `issetugid' function. */
#cmakedefine EVENT__HAVE_ISSETUGID 1
#cmakedefine EVENT__HAVE_ISSETUGID
/* Define to 1 if you have the `kqueue' function. */
#cmakedefine EVENT__HAVE_KQUEUE 1
#cmakedefine EVENT__HAVE_KQUEUE
/* Define if the system has zlib */
#cmakedefine EVENT__HAVE_LIBZ 1
#cmakedefine EVENT__HAVE_LIBZ
/* Define to 1 if you have the `mach_absolute_time' function. */
#cmakedefine EVENT__HAVE_MACH_ABSOLUTE_TIME 1
#cmakedefine EVENT__HAVE_MACH_ABSOLUTE_TIME
/* Define to 1 if you have the <mach/mach_time.h> header file. */
#cmakedefine EVENT__HAVE_MACH_MACH_TIME_H 1
#cmakedefine EVENT__HAVE_MACH_MACH_TIME_H
/* Define to 1 if you have the <memory.h> header file. */
#cmakedefine EVENT__HAVE_MEMORY_H 1
#cmakedefine EVENT__HAVE_MEMORY_H
/* Define to 1 if you have the `mmap' function. */
#cmakedefine EVENT__HAVE_MMAP 1
#cmakedefine EVENT__HAVE_MMAP
/* Define to 1 if you have the `nanosleep' function. */
#cmakedefine EVENT__HAVE_NANOSLEEP 1
#cmakedefine EVENT__HAVE_NANOSLEEP
/* Define to 1 if you have the `usleep' function. */
#cmakedefine EVENT__HAVE_USLEEP 1
#cmakedefine EVENT__HAVE_USLEEP
/* Define to 1 if you have the <netdb.h> header file. */
#cmakedefine EVENT__HAVE_NETDB_H 1
#cmakedefine EVENT__HAVE_NETDB_H
/* Define to 1 if you have the <netinet/in6.h> header file. */
#cmakedefine EVENT__HAVE_NETINET_IN6_H 1
#cmakedefine EVENT__HAVE_NETINET_IN6_H
/* Define to 1 if you have the <netinet/in.h> header file. */
#cmakedefine EVENT__HAVE_NETINET_IN_H 1
#cmakedefine EVENT__HAVE_NETINET_IN_H
/* Define to 1 if you have the <netinet/tcp.h> header file. */
#cmakedefine EVENT__HAVE_NETINET_TCP_H 1
#cmakedefine EVENT__HAVE_NETINET_TCP_H
/* Define if the system has openssl */
#cmakedefine EVENT__HAVE_OPENSSL 1
#cmakedefine EVENT__HAVE_OPENSSL
/* Defines if the system has zlib */
#cmakedefine EVENT__HAVE_ZLIB 1
#cmakedefine EVENT__HAVE_ZLIB
/* Define to 1 if you have the `pipe' function. */
#cmakedefine EVENT__HAVE_PIPE 1
#cmakedefine EVENT__HAVE_PIPE
/* Define to 1 if you have the `pipe2' function. */
#cmakedefine EVENT__HAVE_PIPE2 1
#cmakedefine EVENT__HAVE_PIPE2
/* Define to 1 if you have the `poll' function. */
#cmakedefine EVENT__HAVE_POLL 1
#cmakedefine EVENT__HAVE_POLL
/* Define to 1 if you have the <poll.h> header file. */
#cmakedefine EVENT__HAVE_POLL_H 1
#cmakedefine EVENT__HAVE_POLL_H
/* Define to 1 if you have the `port_create' function. */
#cmakedefine EVENT__HAVE_PORT_CREATE 1
#cmakedefine EVENT__HAVE_PORT_CREATE
/* Define to 1 if you have the <port.h> header file. */
#cmakedefine EVENT__HAVE_PORT_H 1
#cmakedefine EVENT__HAVE_PORT_H
/* Define if you have POSIX threads libraries and header files. */
#cmakedefine EVENT__HAVE_PTHREAD 1
#cmakedefine EVENT__HAVE_PTHREAD
/* Define if we have pthreads on this system */
#cmakedefine EVENT__HAVE_PTHREADS 1
#cmakedefine EVENT__HAVE_PTHREADS
/* Define to 1 if you have the `putenv' function. */
#cmakedefine EVENT__HAVE_PUTENV 1
#cmakedefine EVENT__HAVE_PUTENV
/* Define to 1 if the system has the type `sa_family_t'. */
#cmakedefine EVENT__HAVE_SA_FAMILY_T 1
#cmakedefine EVENT__HAVE_SA_FAMILY_T
/* Define to 1 if you have the `select' function. */
#cmakedefine EVENT__HAVE_SELECT 1
#cmakedefine EVENT__HAVE_SELECT
/* Define to 1 if you have the `setenv' function. */
#cmakedefine EVENT__HAVE_SETENV 1
#cmakedefine EVENT__HAVE_SETENV
/* Define if F_SETFD is defined in <fcntl.h> */
#cmakedefine EVENT__HAVE_SETFD 1
#cmakedefine EVENT__HAVE_SETFD
/* Define to 1 if you have the `setrlimit' function. */
#cmakedefine EVENT__HAVE_SETRLIMIT 1
#cmakedefine EVENT__HAVE_SETRLIMIT
/* Define to 1 if you have the `sendfile' function. */
#cmakedefine EVENT__HAVE_SENDFILE 1
#cmakedefine EVENT__HAVE_SENDFILE
/* Define if F_SETFD is defined in <fcntl.h> */
#cmakedefine EVENT__HAVE_SETFD 1
#cmakedefine EVENT__HAVE_SETFD
/* Define to 1 if you have the `sigaction' function. */
#cmakedefine EVENT__HAVE_SIGACTION 1
#cmakedefine EVENT__HAVE_SIGACTION
/* Define to 1 if you have the `signal' function. */
#cmakedefine EVENT__HAVE_SIGNAL 1
#cmakedefine EVENT__HAVE_SIGNAL
/* Define to 1 if you have the `splice' function. */
#cmakedefine EVENT__HAVE_SPLICE 1
#cmakedefine EVENT__HAVE_SPLICE
/* Define to 1 if you have the <stdarg.h> header file. */
#cmakedefine EVENT__HAVE_STDARG_H 1
#cmakedefine EVENT__HAVE_STDARG_H
/* Define to 1 if you have the <stddef.h> header file. */
#cmakedefine EVENT__HAVE_STDDEF_H 1
#cmakedefine EVENT__HAVE_STDDEF_H
/* Define to 1 if you have the <stdint.h> header file. */
#cmakedefine EVENT__HAVE_STDINT_H 1
#cmakedefine EVENT__HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#cmakedefine EVENT__HAVE_STDLIB_H 1
#cmakedefine EVENT__HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#cmakedefine EVENT__HAVE_STRINGS_H 1
#cmakedefine EVENT__HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#cmakedefine EVENT__HAVE_STRING_H 1
#cmakedefine EVENT__HAVE_STRING_H
/* Define to 1 if you have the `strlcpy' function. */
#cmakedefine EVENT__HAVE_STRLCPY 1
#cmakedefine EVENT__HAVE_STRLCPY
/* Define to 1 if you have the `strsep' function. */
#cmakedefine EVENT__HAVE_STRSEP 1
#cmakedefine EVENT__HAVE_STRSEP
/* Define to 1 if you have the `strtok_r' function. */
#cmakedefine EVENT__HAVE_STRTOK_R 1
#cmakedefine EVENT__HAVE_STRTOK_R
/* Define to 1 if you have the `strtoll' function. */
#cmakedefine EVENT__HAVE_STRTOLL 1
#cmakedefine EVENT__HAVE_STRTOLL
/* Define to 1 if the system has the type `struct addrinfo'. */
#cmakedefine EVENT__HAVE_STRUCT_ADDRINFO 1
#cmakedefine EVENT__HAVE_STRUCT_ADDRINFO
/* Define to 1 if the system has the type `struct in6_addr'. */
#cmakedefine EVENT__HAVE_STRUCT_IN6_ADDR 1
#cmakedefine EVENT__HAVE_STRUCT_IN6_ADDR
/* Define to 1 if `s6_addr16' is member of `struct in6_addr'. */
#cmakedefine EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR16 1
#cmakedefine EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR16
/* Define to 1 if `s6_addr32' is member of `struct in6_addr'. */
#cmakedefine EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR32 1
#cmakedefine EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR32
/* Define to 1 if the system has the type `struct sockaddr_in6'. */
#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_IN6 1
#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_IN6
/* Define to 1 if `sin6_len' is member of `struct sockaddr_in6'. */
#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN 1
#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
/* Define to 1 if `sin_len' is member of `struct sockaddr_in'. */
#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 1
#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
/* Define to 1 if the system has the type `struct sockaddr_storage'. */
#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_STORAGE 1
#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_STORAGE
/* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */
#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1
#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
/* Define to 1 if `__ss_family' is a member of `struct sockaddr_storage'. */
#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY 1
#cmakedefine EVENT__HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY
/* Define to 1 if you have the `sysctl' function. */
#cmakedefine EVENT__HAVE_SYSCTL 1
#cmakedefine EVENT__HAVE_SYSCTL
/* Define to 1 if you have the <sys/devpoll.h> header file. */
#cmakedefine EVENT__HAVE_SYS_DEVPOLL_H 1
#cmakedefine EVENT__HAVE_SYS_DEVPOLL_H
/* Define to 1 if you have the <sys/epoll.h> header file. */
#cmakedefine EVENT__HAVE_SYS_EPOLL_H 1
#cmakedefine EVENT__HAVE_SYS_EPOLL_H
/* Define to 1 if you have the <sys/eventfd.h> header file. */
#cmakedefine EVENT__HAVE_SYS_EVENTFD_H 1
#cmakedefine EVENT__HAVE_SYS_EVENTFD_H
/* Define to 1 if you have the <sys/event.h> header file. */
#cmakedefine EVENT__HAVE_SYS_EVENT_H 1
#cmakedefine EVENT__HAVE_SYS_EVENT_H
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#cmakedefine EVENT__HAVE_SYS_IOCTL_H 1
#cmakedefine EVENT__HAVE_SYS_IOCTL_H
/* Define to 1 if you have the <sys/mman.h> header file. */
#cmakedefine EVENT__HAVE_SYS_MMAN_H 1
#cmakedefine EVENT__HAVE_SYS_MMAN_H
/* Define to 1 if you have the <sys/param.h> header file. */
#cmakedefine EVENT__HAVE_SYS_PARAM_H 1
#cmakedefine EVENT__HAVE_SYS_PARAM_H
/* Define to 1 if you have the <sys/queue.h> header file. */
#cmakedefine EVENT__HAVE_SYS_QUEUE_H 1
#cmakedefine EVENT__HAVE_SYS_QUEUE_H
/* Define to 1 if you have the <sys/resource.h> header file. */
#cmakedefine EVENT__HAVE_SYS_RESOURCE_H 1
#cmakedefine EVENT__HAVE_SYS_RESOURCE_H
/* Define to 1 if you have the <sys/select.h> header file. */
#cmakedefine EVENT__HAVE_SYS_SELECT_H 1
#cmakedefine EVENT__HAVE_SYS_SELECT_H
/* Define to 1 if you have the <sys/sendfile.h> header file. */
#cmakedefine EVENT__HAVE_SYS_SENDFILE_H 1
#cmakedefine EVENT__HAVE_SYS_SENDFILE_H
/* Define to 1 if you have the <sys/socket.h> header file. */
#cmakedefine EVENT__HAVE_SYS_SOCKET_H 1
#cmakedefine EVENT__HAVE_SYS_SOCKET_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#cmakedefine EVENT__HAVE_SYS_STAT_H 1
#cmakedefine EVENT__HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/sysctl.h> header file. */
#cmakedefine EVENT__HAVE_SYS_SYSCTL_H 1
#cmakedefine EVENT__HAVE_SYS_SYSCTL_H
/* Define to 1 if you have the <sys/timerfd.h> header file. */
#cmakedefine EVENT__HAVE_SYS_TIMERFD_H */
/* Define to 1 if you have the <sys/time.h> header file. */
#cmakedefine EVENT__HAVE_SYS_TIME_H 1
#cmakedefine EVENT__HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#cmakedefine EVENT__HAVE_SYS_TYPES_H 1
#cmakedefine EVENT__HAVE_SYS_TYPES_H
/* Define to 1 if you have the <sys/uio.h> header file. */
#cmakedefine EVENT__HAVE_SYS_UIO_H 1
#cmakedefine EVENT__HAVE_SYS_UIO_H
/* Define to 1 if you have the <sys/wait.h> header file. */
#cmakedefine EVENT__HAVE_SYS_WAIT_H 1
#cmakedefine EVENT__HAVE_SYS_WAIT_H
/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
#cmakedefine EVENT__HAVE_TAILQFOREACH 1
#cmakedefine EVENT__HAVE_TAILQFOREACH
/* Define if timeradd is defined in <sys/time.h> */
#cmakedefine EVENT__HAVE_TIMERADD 1
#cmakedefine EVENT__HAVE_TIMERADD
/* Define if timerclear is defined in <sys/time.h> */
#cmakedefine EVENT__HAVE_TIMERCLEAR 1
#cmakedefine EVENT__HAVE_TIMERCLEAR
/* Define if timercmp is defined in <sys/time.h> */
#cmakedefine EVENT__HAVE_TIMERCMP 1
#cmakedefine EVENT__HAVE_TIMERCMP
/* Define to 1 if you have the `timerfd_create' function. */
#cmakedefine EVENT__HAVE_TIMERFD_CREATE 1
#cmakedefine EVENT__HAVE_TIMERFD_CREATE
/* Define if timerisset is defined in <sys/time.h> */
#cmakedefine EVENT__HAVE_TIMERISSET 1
#cmakedefine EVENT__HAVE_TIMERISSET
/* Define to 1 if the system has the type `uint8_t'. */
#cmakedefine EVENT__HAVE_UINT8_T 1
#cmakedefine EVENT__HAVE_UINT8_T
/* Define to 1 if the system has the type `uint16_t'. */
#cmakedefine EVENT__HAVE_UINT16_T 1
#cmakedefine EVENT__HAVE_UINT16_T
/* Define to 1 if the system has the type `uint32_t'. */
#cmakedefine EVENT__HAVE_UINT32_T 1
#cmakedefine EVENT__HAVE_UINT32_T
/* Define to 1 if the system has the type `uint64_t'. */
#cmakedefine EVENT__HAVE_UINT64_T 1
#cmakedefine EVENT__HAVE_UINT64_T
/* Define to 1 if the system has the type `uintptr_t'. */
#cmakedefine EVENT__HAVE_UINTPTR_T 1
#cmakedefine EVENT__HAVE_UINTPTR_T
/* Define to 1 if you have the `umask' function. */
#cmakedefine EVENT__HAVE_UMASK 1
#cmakedefine EVENT__HAVE_UMASK
/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine EVENT__HAVE_UNISTD_H 1
#cmakedefine EVENT__HAVE_UNISTD_H
/* Define to 1 if you have the `unsetenv' function. */
#cmakedefine EVENT__HAVE_UNSETENV 1
#cmakedefine EVENT__HAVE_UNSETENV
/* Define to 1 if you have the `vasprintf' function. */
#cmakedefine EVENT__HAVE_VASPRINTF 1
#cmakedefine EVENT__HAVE_VASPRINTF
/* Define if kqueue works correctly with pipes */
#cmakedefine EVENT__HAVE_WORKING_KQUEUE 1
#cmakedefine EVENT__HAVE_WORKING_KQUEUE
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#cmakedefine EVENT__PTHREAD_CREATE_JOINABLE ${EVENT__PTHREAD_CREATE_JOINABLE}
#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. */
#cmakedefine EVENT__SIZEOF_PTHREAD_T ${EVENT__SIZEOF_PTHREAD_T}
#define EVENT__SIZEOF_PTHREAD_T @EVENT__SIZEOF_PTHREAD_T@
/* The size of a `int', as computed by sizeof. */
#cmakedefine EVENT__SIZEOF_INT ${EVENT__SIZEOF_INT}
#define EVENT__SIZEOF_INT @EVENT__SIZEOF_INT@
/* The size of a `long', as computed by sizeof. */
#cmakedefine EVENT__SIZEOF_LONG ${EVENT__SIZEOF_LONG}
#define EVENT__SIZEOF_LONG @EVENT__SIZEOF_LONG@
/* The size of a `long long', as computed by sizeof. */
#cmakedefine EVENT__SIZEOF_LONG_LONG ${EVENT__SIZEOF_LONG_LONG}
#define EVENT__SIZEOF_LONG_LONG @EVENT__SIZEOF_LONG_LONG@
/* The size of `off_t', as computed by sizeof. */
#cmakedefine EVENT__SIZEOF_OFF_T ${EVENT__SIZEOF_OFF_T}
#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. */
#cmakedefine EVENT__SIZEOF_SHORT ${EVENT__SIZEOF_SHORT}
#define EVENT__SIZEOF_SHORT @EVENT__SIZEOF_SHORT@
/* The size of `size_t', as computed by sizeof. */
#cmakedefine EVENT__SIZEOF_SIZE_T ${EVENT__SIZEOF_SIZE_T}
#define EVENT__SIZEOF_SIZE_T @EVENT__SIZEOF_SIZE_T@
/* Define to 1 if you have the ANSI C header files. */
#cmakedefine EVENT__STDC_HEADERS ${EVENT__STDC_HEADERS}
#cmakedefine EVENT__STDC_HEADERS
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#cmakedefine EVENT__TIME_WITH_SYS_TIME ${EVENT__TIME_WITH_SYS_TIME}
#cmakedefine EVENT__TIME_WITH_SYS_TIME
/* The size of `socklen_t', as computed by sizeof. */
#cmakedefine EVENT__SIZEOF_SOCKLEN_T ${EVENT__SIZEOF_SOCKLEN_T}
#define EVENT__SIZEOF_SOCKLEN_T @EVENT__SIZEOF_SOCKLEN_T@
/* The size of 'void *', as computer by sizeof */
#cmakedefine EVENT__SIZEOF_VOID_P ${EVENT__SIZEOF_VOID_P}
#define EVENT__SIZEOF_VOID_P @EVENT__SIZEOF_VOID_P@
/* Define to appropriate substitute if compiler doesnt have __func__ */
#cmakedefine EVENT____func__ ${EVENT____func__}
/* set an alias for whatever __func__ __FUNCTION__ is, what sillyness */
#if defined (__func__)
#define EVENT____func__ __func__
#elif defined(__FUNCTION__)
#define EVENT____func__ __FUNCTION__
#else
#define EVENT____func__ __FILE__
#endif
#ifdef __THESE_ARE_NOT_CONFIG_H_THINGS_THEY_ARE_DASH_D_THINGS__
/* Number of bits in a file offset, on hosts where this is settable. */
#cmakedefine EVENT___FILE_OFFSET_BITS ${EVENT___FILE_OFFSET_BITS}
/* Ellzey is not satisfied */
#define EVENT___FILE_OFFSET_BITS @EVENT___FILE_OFFSET_BITS@
/* Define for large files, on AIX-style hosts. */
/* #undef _LARGE_FILES */
#define @_LARGE_FILES@
#endif
#ifdef _WhAT_DOES_THIS_EVEN_DO_
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef EVENT__const */
/* lolwut? - ellzey */
#undef EVENT__const
#endif
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
#cmakedefine EVENT__inline ${EVENT__inline}
/* 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
/* Define to `int' if <sys/types.h> does not define. */
#cmakedefine EVENT__pid_t ${EVENT__pid_t}
/* Define to `int' if <sys/tyes.h> does not define. */
#define EVENT__pid_t @EVENT__pid_t@
/* Define to `unsigned' if <sys/types.h> does not define. */
#cmakedefine EVENT__size_t ${EVENT__size_t}
#define EVENT__size_t @EVENT__size_t@
/* Define to unsigned int if you dont have it */
#cmakedefine EVENT__socklen_t ${EVENT__socklen_t}
#define EVENT__socklen_t @EVENT__socklen_t@
/* Define to `int' if <sys/types.h> does not define. */
#cmakedefine EVENT__ssize_t ${EVENT__ssize_t}
#define EVENT__ssize_t @EVENT__ssize_t@
#cmakedefine EVENT__NEED_DLLIMPORT ${EVENT__NEED_DLLIMPORT}
#define EVENT__NEED_DLLIMPORT @EVENT__NEED_DLLIMPORT@
/* Define to 1 if you have ERR_remove_thread_stat(). */
#cmakedefine EVENT__HAVE_ERR_REMOVE_THREAD_STATE
#endif

View File

@ -368,7 +368,6 @@ 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 TAILQ_FIRST
#define TAILQ_FIRST(head) ((head)->tqh_first)
#endif
@ -394,7 +393,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)
@ -467,6 +465,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

View File

@ -183,14 +183,14 @@
.Fn "evbuffer_write" "struct evbuffer *buf" "int fd"
.Ft int
.Fn "evbuffer_read" "struct evbuffer *buf" "int fd" "int size"
.Ft "u_char *"
.Fn "evbuffer_find" "struct evbuffer *buf" "const u_char *data" "size_t size"
.Ft "unsigned char *"
.Fn "evbuffer_find" "struct evbuffer *buf" "const unsigned char *data" "size_t size"
.Ft "char *"
.Fn "evbuffer_readline" "struct evbuffer *buf"
.Ft "struct evhttp *"
.Fn "evhttp_new" "struct event_base *base"
.Ft int
.Fn "evhttp_bind_socket" "struct evhttp *http" "const char *address" "u_short port"
.Fn "evhttp_bind_socket" "struct evhttp *http" "const char *address" "unsigned short port"
.Ft "void"
.Fn "evhttp_free" "struct evhttp *http"
.Ft int

69
event.c
View File

@ -199,6 +199,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
@ -655,6 +671,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 +769,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,21 +852,21 @@ 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;
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);
if (!i) {
break;
}
n_deleted += i;
}
{
struct event_callback *evcb;
while ((evcb = TAILQ_FIRST(&base->active_later_queue))) {
n_deleted += event_base_cancel_single_callback_(base, evcb, run_finalizers);
}
}
if (n_deleted)
event_debug(("%s: %d events were still set in base",

View File

@ -40,10 +40,11 @@
#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>

View File

@ -45,6 +45,11 @@
#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;
}

View File

@ -226,16 +226,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 +258,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 +314,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 +359,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
@ -520,7 +524,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;
@ -1159,7 +1163,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");
@ -1705,10 +1709,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;

View File

@ -62,10 +62,10 @@ 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 */
unsigned short bind_port; /* local port for binding the src */
char *address; /* address to connect to */
u_short port;
unsigned short port;
size_t max_headers_size;
ev_uint64_t max_body_size;
@ -101,13 +101,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 */

139
http.c
View File

@ -35,18 +35,22 @@
#include <sys/types.h>
#endif
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.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 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
#include <winsock2.h>
#include <ws2tcpip.h>
@ -461,6 +465,13 @@ 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)
{
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
@ -674,6 +685,23 @@ 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 +750,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);
@ -773,16 +800,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 +843,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,7 +981,6 @@ 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;
}
}
@ -985,7 +1005,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:
@ -1031,7 +1051,7 @@ 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;
}
}
@ -1042,9 +1062,6 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
evhttp_connection_done(evcon);
return;
}
/* Read more! */
bufferevent_enable(evcon->bufev, EV_READ);
}
#define get_deferred_queue(evcon) \
@ -1125,6 +1142,9 @@ evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg)
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(bufferevent_get_output(evcon->bufev)) > 0) { return; }
/* We are done writing our header and are now expecting the response */
req->kind = EVHTTP_RESPONSE;
@ -1152,8 +1172,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) {
@ -1173,6 +1192,7 @@ evhttp_connection_free(struct evhttp_connection *evcon)
&evcon->read_more_deferred_cb);
if (evcon->fd != -1) {
bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE);
shutdown(evcon->fd, EVUTIL_SHUT_WR);
if (!(bufferevent_get_options_(evcon->bufev) & BEV_OPT_CLOSE_ON_FREE)) {
evutil_closesocket(evcon->fd);
@ -1185,9 +1205,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);
}
@ -1352,7 +1369,7 @@ 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);
}
}
@ -1441,7 +1458,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 +1508,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,
@ -2181,9 +2189,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) {
@ -2335,6 +2340,20 @@ void evhttp_connection_set_family(struct evhttp_connection *evcon,
evcon->ai_family = family;
}
int evhttp_connection_set_flags(struct evhttp_connection *evcon,
int flags)
{
if (flags & ~(EVHTTP_CON_REUSE_CONNECTED_ADDR)) {
return 1;
}
evcon->flags &= ~(EVHTTP_CON_REUSE_CONNECTED_ADDR);
evcon->flags |= EVHTTP_CON_REUSE_CONNECTED_ADDR;
return 0;
}
void
evhttp_connection_set_base(struct evhttp_connection *evcon,
struct event_base *base)
@ -2412,13 +2431,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);
@ -2450,17 +2472,29 @@ 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);
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 +2527,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);
}
@ -2556,7 +2590,7 @@ evhttp_cancel_request(struct evhttp_request *req)
}
}
evhttp_request_free(req);
evhttp_request_free_auto(req);
}
/*
@ -2567,9 +2601,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,
@ -2599,9 +2633,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);
@ -4035,6 +4068,8 @@ evhttp_get_request_connection(
evcon->fd = fd;
bufferevent_enable(evcon->bufev, EV_READ);
bufferevent_disable(evcon->bufev, EV_WRITE);
bufferevent_setfd(evcon->bufev, fd);
return (evcon);

View 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>

View 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

View 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;
/**
@ -562,6 +562,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 eles (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.

View File

@ -633,9 +633,22 @@ struct evhttp_connection *evhttp_connection_base_new(
/**
* Set family hint for DNS requests.
*/
EVENT2_EXPORT_SYMBOL
void evhttp_connection_set_family(struct evhttp_connection *evcon,
int family);
#define EVHTTP_CON_REUSE_CONNECTED_ADDR 0x0008 /* reuse connection address on retry */
/**
* 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 +741,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,

View File

@ -233,6 +233,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 +246,21 @@ 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_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

View File

@ -50,7 +50,7 @@
/* 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(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
@ -260,7 +260,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;
}

View File

@ -421,6 +421,8 @@ 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;

View File

@ -12,9 +12,14 @@
#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>
@ -141,34 +146,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;
char 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:")) != -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 +189,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,16 +207,18 @@ 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");
@ -218,27 +227,27 @@ main(int c, char **v) {
}
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);

109
sample/http-connect.c Normal file
View File

@ -0,0 +1,109 @@
#include <event2/event.h>
#include <event2/http.h>
#include <event2/http_struct.h>
#include <event2/buffer.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#define VERIFY(cond) do { \
if (!(cond)) { \
fprintf(stderr, "[error] %s\n", #cond); \
} \
} while (0); \
struct connect_base
{
struct evhttp_connection *evcon;
struct evhttp_uri *location;
};
static void get_cb(struct evhttp_request *req, void *arg)
{
VERIFY(req);
evbuffer_write(req->input_buffer, STDOUT_FILENO);
}
static void connect_cb(struct evhttp_request *proxy_req, void *arg)
{
char buffer[PATH_MAX];
struct connect_base *base = arg;
struct evhttp_connection *evcon = base->evcon;
struct evhttp_uri *location = base->location;
VERIFY(proxy_req);
if (evcon) {
struct evhttp_request *req = evhttp_request_new(get_cb, NULL);
evhttp_add_header(req->output_headers, "Connection", "close");
VERIFY(!evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
evhttp_uri_join(location, buffer, PATH_MAX)));
}
}
int main(int argc, const char **argv)
{
char buffer[PATH_MAX];
struct evhttp_uri *host_port;
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 = evhttp_uri_parse(argv[1]);
VERIFY(evhttp_uri_get_host(proxy));
VERIFY(evhttp_uri_get_port(proxy) > 0);
}
{
host_port = evhttp_uri_parse(argv[2]);
evhttp_uri_set_scheme(host_port, NULL);
evhttp_uri_set_userinfo(host_port, NULL);
evhttp_uri_set_path(host_port, NULL);
evhttp_uri_set_query(host_port, NULL);
evhttp_uri_set_fragment(host_port, NULL);
VERIFY(evhttp_uri_get_host(host_port));
VERIFY(evhttp_uri_get_port(host_port) > 0);
}
{
location = evhttp_uri_parse(argv[2]);
evhttp_uri_set_scheme(location, NULL);
evhttp_uri_set_userinfo(location, 0);
evhttp_uri_set_host(location, NULL);
evhttp_uri_set_port(location, -1);
}
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 = (struct connect_base){
.evcon = evcon,
.location = location,
};
VERIFY(req = evhttp_request_new(connect_cb, &connect_base));
evhttp_add_header(req->output_headers, "Connection", "keep-alive");
evhttp_add_header(req->output_headers, "Proxy-Connection", "keep-alive");
evutil_snprintf(buffer, PATH_MAX, "%s:%d",
evhttp_uri_get_host(host_port), evhttp_uri_get_port(host_port));
evhttp_make_request(evcon, req, EVHTTP_REQ_CONNECT, buffer);
event_base_dispatch(base);
evhttp_connection_free(evcon);
event_base_free(base);
evhttp_uri_free(proxy);
evhttp_uri_free(host_port);
evhttp_uri_free(location);
return 0;
}

View File

@ -96,22 +96,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);
@ -190,22 +187,26 @@ main(int argc, char **argv)
{
int r;
struct evhttp_uri *http_uri;
struct evhttp_uri *http_uri = NULL;
const char *url = NULL, *data_file = NULL;
const char *crt = "/etc/ssl/certs/ca-certificates.crt";
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 +214,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 +230,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 +268,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 +298,7 @@ main(int argc, char **argv)
}
path = evhttp_uri_get_path(http_uri);
if (path == NULL) {
if (strlen(path) == 0) {
path = "/";
}
@ -297,23 +320,26 @@ main(int argc, char **argv)
* 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");
if (!ssl_ctx) {
err_openssl("SSL_CTX_new");
goto error;
}
#ifndef _WIN32
#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 (1 != SSL_CTX_load_verify_locations(ssl_ctx, crt, NULL)) {
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 +362,22 @@ 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
#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 +388,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 +396,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 +407,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 +439,7 @@ main(int argc, char **argv)
if (!f) {
syntax();
goto error;
}
output_buffer = evhttp_request_get_output_buffer(req);
@ -423,17 +455,40 @@ 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;
evhttp_connection_free(evcon);
error:
ret = 1;
cleanup:
if (evcon)
evhttp_connection_free(evcon);
if (http_uri)
evhttp_uri_free(http_uri);
event_base_free(base);
if (ssl_ctx)
SSL_CTX_free(ssl_ctx);
if (type == HTTP && ssl)
SSL_free(ssl);
EVP_cleanup();
ERR_free_strings();
#ifdef EVENT__HAVE_ERR_REMOVE_THREAD_STATE
ERR_remove_thread_state(NULL);
#else
ERR_remove_state(0);
#endif
CRYPTO_cleanup_all_ex_data();
sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
#ifdef _WIN32
WSACleanup();
#endif
return 0;
return ret;
}

View File

@ -9,6 +9,7 @@ SAMPLES = \
sample/event-read-fifo \
sample/hello-world \
sample/http-server \
sample/http-connect \
sample/signal-test \
sample/time-test
@ -48,6 +49,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

View File

@ -41,6 +41,7 @@ SOFTWARE.
#include <openssl/x509v3.h>
#include <openssl/ssl.h>
#include <string.h>
#include "openssl_hostname_validation.h"
#include "hostcheck.h"

View File

@ -74,7 +74,7 @@ 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);

View File

@ -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;
@ -183,6 +183,11 @@ main(int argc, char **argv)
double throughput;
resource = "/ref";
#ifdef _WIN32
WSADATA WSAData;
WSAStartup(0x101, &WSAData);
#endif
setvbuf(stdout, NULL, _IONBF, 0);
base = event_base_new();
@ -226,5 +231,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;
}

View File

@ -2290,7 +2290,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;

View File

@ -129,6 +129,14 @@ 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(void);
SSL_CTX *get_ssl_ctx(void);
void init_ssl(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -198,7 +198,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));
@ -1292,7 +1292,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 +1303,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 +1321,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);

View File

@ -123,11 +123,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];
@ -171,6 +172,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,23 +182,26 @@ 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)
/**
@ -245,7 +252,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;
@ -278,6 +284,9 @@ 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 */
@ -311,6 +320,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;
@ -594,6 +606,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"
@ -613,6 +626,31 @@ end:
;
}
static int
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)
{
@ -642,6 +680,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)
{
@ -727,6 +773,45 @@ end:
bufferevent_free(bev2);
}
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 bufferevent *bev = NULL;
struct evconnlistener *lev = NULL;
struct sockaddr_in localhost;
ev_socklen_t slen = sizeof(localhost);
evutil_socket_t fake_listener = -1;
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() */
bufferevent_socket_connect(bev, (struct sockaddr *)&localhost, slen);
tt_int_op(n_events_invoked, ==, 0);
tt_int_op(n_reads_invoked, ==, 0);
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)
{
@ -762,34 +847,23 @@ 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 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);
@ -1084,10 +1158,35 @@ 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);
}
struct testcase_t bufferevent_testcases[] = {
LEGACY(bufferevent, TT_ISOLATED),
LEGACY(bufferevent_pair, TT_ISOLATED),
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)
{ "bufferevent_pair_release_lock", test_bufferevent_pair_release_lock,
TT_FORK|TT_ISOLATED|TT_NEED_THREADS|TT_NEED_BASE|TT_LEGACY,
@ -1135,12 +1234,26 @@ 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 },
END_OF_TESTCASES,
};
struct testcase_t bufferevent_iocp_testcases[] = {
LEGACY(bufferevent, TT_ISOLATED|TT_ENABLE_IOCP),
LEGACY(bufferevent_flush_normal, TT_ISOLATED),
LEGACY(bufferevent_flush_flush, TT_ISOLATED),
LEGACY(bufferevent_flush_finished, TT_ISOLATED),
LEGACY(bufferevent_watermarks, TT_ISOLATED|TT_ENABLE_IOCP),
LEGACY(bufferevent_filters, TT_ISOLATED|TT_ENABLE_IOCP),
{ "bufferevent_connect", test_bufferevent_connect,
@ -1159,5 +1272,13 @@ struct testcase_t bufferevent_iocp_testcases[] = {
TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup,
(void*)"unset_connectex" },
{ "bufferevent_connect_fail_eventcb_defer",
test_bufferevent_connect_fail_eventcb,
TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup,
(void*)BEV_OPT_DEFER_CALLBACKS },
{ "bufferevent_connect_fail",
test_bufferevent_connect_fail_eventcb,
TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL },
END_OF_TESTCASES,
};

View File

@ -72,6 +72,8 @@
#include "regress.h"
#include "regress_testutils.h"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
static int dns_ok = 0;
static int dns_got_cancel = 0;
static int dns_err = 0;
@ -511,25 +513,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.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 },
{ "host2", "err", "3", 0 },
{ "*", "err", "3", 0 },
{ NULL, NULL, NULL, 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 +539,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 +556,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 +592,16 @@ end:
regress_clean_dnsserver();
}
static void
dns_search_test(void *arg)
{
return dns_search_test_impl(arg, 0);
}
static void
dns_search_lower_test(void *arg)
{
return dns_search_test_impl(arg, 1);
}
static int request_count = 0;
static struct evdns_request *current_req = NULL;
@ -776,13 +794,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
@ -1672,7 +1690,6 @@ 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) {
if (a_out[i].ai)
evutil_freeaddrinfo(a_out[i].ai);
@ -1885,29 +1902,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;
}
evdns_base_free(env->dns_base, send_err_shutdown);
env->dns_base = 0;
event_base_loop(env->base, EVLOOP_NONBLOCK);
end:
evdns_base_free(env->dns_base, send_err_shutdown);
env->dns_base = 0;
event_base_free(env->base);
env->base = 0;
}
@ -1998,6 +2008,91 @@ 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;
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)
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", "http", 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);
}
#define DNS_LEGACY(name, flags) \
{ #name, run_legacy_test_fn, flags|TT_LEGACY, &legacy_setup, \
@ -2010,6 +2105,7 @@ struct testcase_t dns_testcases[] = {
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", 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 },
@ -2044,6 +2140,12 @@ struct testcase_t dns_testcases[] = {
TT_FORK, &testleak_funcs, NULL },
#endif
{ "client_fail_requests", dns_client_fail_requests_test,
TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
{ "client_fail_requests_getaddrinfo",
dns_client_fail_requests_getaddrinfo_test,
TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
END_OF_TESTCASES
};

View File

@ -58,7 +58,9 @@
#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"
@ -84,6 +86,7 @@ static char const BASIC_REQUEST_BODY[] = "This is funny";
IMPL_HTTP_REQUEST_ERROR_CB(cancel, EVREQ_HTTP_REQUEST_CANCEL)
static void http_basic_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 +97,14 @@ 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
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 +126,40 @@ 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_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(ev_uint16_t *pport, struct event_base *base, int mask)
{
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
/* Register a callback for certain types of requests */
evhttp_set_cb(myhttp, "/test", http_basic_cb, base);
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);
@ -151,7 +178,7 @@ http_setup(ev_uint16_t *pport, struct event_base *base, int ipv6)
#endif
static evutil_socket_t
http_connect(const char *address, u_short port)
http_connect(const char *address, unsigned short port)
{
/* Stupid code for connecting */
struct evutil_addrinfo ai, *aitop;
@ -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);
}
@ -329,6 +359,19 @@ end:
evbuffer_free(evb);
}
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.",
@ -394,8 +437,28 @@ http_complete_write(evutil_socket_t fd, short what, void *arg)
bufferevent_write(bev, http_request, strlen(http_request));
}
static struct bufferevent *
create_bev(struct event_base *base, int fd, int ssl)
{
int flags = BEV_OPT_DEFER_CALLBACKS;
struct bufferevent *bev = NULL;
if (!ssl) {
bev = bufferevent_socket_new(base, fd, flags);
} else {
#ifdef EVENT__HAVE_OPENSSL
SSL *ssl = SSL_new(get_ssl_ctx());
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_basic_test(void *arg)
http_basic_test_impl(void *arg, int ssl)
{
struct basic_test_data *data = arg;
struct timeval tv;
@ -403,13 +466,14 @@ http_basic_test(void *arg)
evutil_socket_t fd;
const char *http_request;
ev_uint16_t port = 0, port2 = 0;
int server_flags = ssl ? HTTP_BIND_SSL : 0;
test_ok = 0;
http = http_setup(&port, data->base, 0);
http = http_setup(&port, data->base, server_flags);
/* 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);
}
@ -417,7 +481,7 @@ 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);
bev = create_bev(data->base, fd, ssl);
bufferevent_setcb(bev, http_readcb, http_writecb,
http_errorcb, data->base);
@ -443,7 +507,7 @@ http_basic_test(void *arg)
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);
bufferevent_setcb(bev, http_readcb, http_writecb,
http_errorcb, data->base);
@ -466,7 +530,7 @@ http_basic_test(void *arg)
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);
bufferevent_setcb(bev, http_readcb, http_writecb,
http_errorcb, data->base);
@ -487,6 +551,8 @@ http_basic_test(void *arg)
if (bev)
bufferevent_free(bev);
}
static void http_basic_test(void *arg)
{ return http_basic_test_impl(arg, 0); }
static void
@ -956,6 +1022,7 @@ 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 *);
@ -1060,8 +1127,8 @@ http_persist_connection_test(void *arg)
}
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
@ -1319,6 +1386,13 @@ http_cancel_test(void *arg)
evhttp_free(http);
}
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
http_request_done(struct evhttp_request *req, void *arg)
{
@ -1583,6 +1657,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);
@ -2750,6 +2829,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
@ -2773,7 +2856,7 @@ 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;
@ -2785,14 +2868,14 @@ http_incomplete_test_(struct basic_test_data *data, int use_timeout)
test_ok = 0;
http = http_setup(&port, data->base, 0);
http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
evhttp_set_timeout(http, 1);
fd = http_connect("127.0.0.1", port);
tt_int_op(fd, >=, 0);
/* Stupid thing to send a request */
bev = bufferevent_socket_new(data->base, fd, 0);
bev = create_bev(data->base, fd, ssl);
bufferevent_setcb(bev,
http_incomplete_readcb, http_incomplete_writecb,
http_incomplete_errorcb, use_timeout ? NULL : &fd);
@ -2830,16 +2913,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.
@ -2856,6 +2934,10 @@ http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
{
struct evhttp_request *req = NULL;
/** SSL */
if (what & BEV_EVENT_CONNECTED)
return;
if (!test_ok)
goto out;
@ -2990,7 +3072,7 @@ 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;
@ -3005,12 +3087,12 @@ http_chunk_out_test(void *arg)
exit_base = data->base;
test_ok = 0;
http = http_setup(&port, data->base, 0);
http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
fd = http_connect("127.0.0.1", port);
/* Stupid thing to send a request */
bev = bufferevent_socket_new(data->base, fd, 0);
bev = create_bev(data->base, fd, ssl);
bufferevent_setcb(bev,
http_chunked_readcb, http_chunked_writecb,
http_chunked_errorcb, data->base);
@ -3037,7 +3119,9 @@ 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);
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 */
@ -3065,21 +3149,26 @@ http_chunk_out_test(void *arg)
if (http)
evhttp_free(http);
}
static void http_chunk_out_test(void *arg)
{ return 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;
test_ok = 0;
exit_base = data->base;
http = http_setup(&port, data->base, 0);
http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
bev = create_bev(data->base, -1, ssl);
evcon = evhttp_connection_base_bufferevent_new(
data->base, NULL, bev, "127.0.0.1", port);
tt_assert(evcon);
/*
@ -3107,6 +3196,8 @@ http_stream_out_test(void *arg)
if (http)
evhttp_free(http);
}
static void http_stream_out_test(void *arg)
{ return http_stream_out_test_impl(arg, 0); }
static void
http_stream_in_chunk(struct evhttp_request *req, void *arg)
@ -3241,65 +3332,70 @@ 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;
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 */
http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
evhttp_free(http);
http = NULL;
/* Pick an unroutable address. This administratively scoped multicast
* address should do when working with TCP. */
evcon = evhttp_connection_base_new(data->base, NULL, "239.10.20.30", 80);
tt_assert(evcon);
bev = create_bev(data->base, -1, ssl);
/* 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)
{ return http_connection_fail_test_impl(arg, 0); }
static void
http_connection_retry_done(struct evhttp_request *req, void *arg)
@ -3317,33 +3413,81 @@ http_connection_retry_done(struct evhttp_request *req, void *arg)
event_base_loopexit(arg,NULL);
}
struct http_server
{
ev_uint16_t port;
int ssl;
};
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;
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)
{
struct basic_test_data *data = arg;
struct evhttp_connection *evcon = NULL;
struct evhttp_request *req = NULL;
struct bufferevent *bev;
struct http_server hs = { .port = 0, .ssl = ssl, };
exit_base = data->base;
test_ok = 0;
http = http_setup(&hs.port, data->base, ssl ? HTTP_BIND_SSL : 0);
bev = create_bev(data->base, -1, ssl);
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, "/test") == -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)
{ return http_simple_test_impl(arg, 0, 0); }
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 = { .port = 0, .ssl = ssl, };
exit_base = data->base;
test_ok = 0;
/* auto detect a port */
http = http_setup(&port, data->base, 0);
http = http_setup(&hs.port, data->base, ssl ? HTTP_BIND_SSL : 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);
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 */
@ -3377,6 +3521,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 };
@ -3432,7 +3579,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);
@ -3449,6 +3596,42 @@ http_connection_retry_test(void *arg)
evhttp_free(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)
{ return http_connection_retry_conn_address_test_impl(arg, 0); }
static void
http_connection_retry_test_impl(void *arg, int ssl)
{
return http_connection_retry_test_basic(arg, "127.0.0.1", NULL, ssl);
}
static void
http_connection_retry_test(void *arg)
{ return http_connection_retry_test_impl(arg, 0); }
static void
http_primitives(void *ptr)
{
@ -3688,6 +3871,7 @@ struct terminate_state {
struct bufferevent *bev;
evutil_socket_t fd;
int gotclosecb: 1;
int oneshot: 1;
};
static void
@ -3695,7 +3879,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;
@ -3709,11 +3896,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
@ -3721,6 +3911,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
@ -3760,7 +3957,7 @@ 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;
@ -3789,6 +3986,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 =
@ -3812,10 +4010,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
@ -3929,12 +4137,126 @@ 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;
int fd;
const char *http_request;
test_ok = 0;
exit_base = data->base;
http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
fd = http_connect("127.0.0.1", port);
bev = create_bev(data->base, fd, 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);
if (bev)
bufferevent_free(bev);
if (http)
evhttp_free(http);
}
static void http_write_during_read_test(void *arg)
{ return 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;
test_ok = 0;
exit_base = data->base;
http = http_setup(&port, data->base, 0);
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;
}
#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 HTTPS(name) \
{ "https_" #name, https_##name##_test, TT_ISOLATED, &basic_setup, NULL }
#ifdef EVENT__HAVE_OPENSSL
static void https_basic_test(void *arg)
{ return http_basic_test_impl(arg, 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)
{ return http_simple_test_impl(arg, 1, 0); }
static void https_simple_dirty_test(void *arg)
{ return http_simple_test_impl(arg, 1, 1); }
static void https_connection_retry_conn_address_test(void *arg)
{ return http_connection_retry_conn_address_test_impl(arg, 1); }
static void https_connection_retry_test(void *arg)
{ return http_connection_retry_test_impl(arg, 1); }
static void https_chunk_out_test(void *arg)
{ return http_chunk_out_test_impl(arg, 1); }
static void https_stream_out_test(void *arg)
{ return http_stream_out_test_impl(arg, 1); }
static void https_connection_fail_test(void *arg)
{ return http_connection_fail_test_impl(arg, 1); }
static void https_write_during_read_test(void *arg)
{ return http_write_during_read_test_impl(arg, 1); }
#endif
struct testcase_t http_testcases[] = {
{ "primitives", http_primitives, 0, NULL, NULL },
@ -3945,6 +4267,7 @@ struct testcase_t http_testcases[] = {
{ "parse_uri_nc", http_parse_uri_test, 0, &basic_setup, (void*)"nc" },
{ "uriencode", http_uriencode_test, 0, NULL, NULL },
HTTP(basic),
HTTP(simple),
HTTP(cancel),
HTTP(virtual_host),
HTTP(post),
@ -3962,6 +4285,7 @@ struct testcase_t http_testcases[] = {
HTTP(incomplete),
HTTP(incomplete_timeout),
HTTP(terminate_chunked),
HTTP(terminate_chunked_oneshot),
HTTP(on_complete),
HTTP(highport),
@ -3976,6 +4300,8 @@ 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),
@ -3986,6 +4312,24 @@ struct testcase_t http_testcases[] = {
HTTP(set_family_ipv4),
HTTP(set_family_ipv6),
HTTP(write_during_read),
HTTP(request_own),
#ifdef EVENT__HAVE_OPENSSL
HTTPS(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(stream_out),
HTTPS(connection_fail),
HTTPS(write_during_read),
#endif
END_OF_TESTCASES
};

View File

@ -407,6 +407,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 +438,7 @@ main(int argc, const char **argv)
#ifdef _WIN32
tinytest_skip(testgroups, "http/connection_retry");
tinytest_skip(testgroups, "http/https_connection_retry");
#endif
#ifndef EVENT__DISABLE_THREAD_SUPPORT

View File

@ -43,6 +43,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"
@ -50,12 +51,12 @@
#include "tinytest.h"
#include "tinytest_macros.h"
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <string.h>
#include <unistd.h>
/* A short pre-generated key, to save the cost of doing an RSA key generation
* step during the unit tests. It's only 512 bits long, and it is published
@ -72,8 +73,8 @@ static const char KEY[] =
"U6GFEQTZ3IfuiVabG5pummdC4DNbcdI+WKrSFNmQ\n"
"-----END RSA PRIVATE KEY-----\n";
static EVP_PKEY *
getkey(void)
EVP_PKEY *
ssl_getkey(void)
{
EVP_PKEY *key;
BIO *bio;
@ -91,15 +92,15 @@ end:
return NULL;
}
static X509 *
getcert(void)
X509 *
ssl_getcert(void)
{
/* Dummy code to make a quick-and-dirty valid certificate with
OpenSSL. Don't copy this code into your own program! It does a
number of things in a stupid and insecure way. */
X509 *x509 = NULL;
X509_NAME *name = NULL;
EVP_PKEY *key = getkey();
EVP_PKEY *key = ssl_getkey();
int nid;
time_t now = time(NULL);
@ -137,7 +138,7 @@ end:
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)
@ -156,7 +157,7 @@ get_ssl_ctx(void)
return the_ssl_ctx;
}
static void
void
init_ssl(void)
{
SSL_library_init();
@ -177,17 +178,64 @@ static int test_is_done = 0;
static int n_connected = 0;
static int got_close = 0;
static int got_error = 0;
static int got_timeout = 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,
};
static void
bufferevent_openssl_check_fd(struct bufferevent *bev, int filter)
{
if (filter) {
tt_int_op(bufferevent_getfd(bev), ==, -1);
tt_int_op(bufferevent_setfd(bev, -1), ==, -1);
} else {
tt_int_op(bufferevent_getfd(bev), !=, -1);
tt_int_op(bufferevent_setfd(bev, -1), ==, 0);
}
tt_int_op(bufferevent_getfd(bev), ==, -1);
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
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;
@ -201,7 +249,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;
@ -226,6 +274,9 @@ done_writing_cb(struct bufferevent *bev, void *ctx)
static void
eventcb(struct bufferevent *bev, short what, void *ctx)
{
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;
@ -234,7 +285,7 @@ eventcb(struct bufferevent *bev, short what, void *ctx)
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);
@ -246,10 +297,32 @@ eventcb(struct bufferevent *bev, short what, void *ctx)
} 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:
@ -259,10 +332,12 @@ end:
static void
open_ssl_bufevs(struct bufferevent **bev1_out, struct bufferevent **bev2_out,
struct event_base *base, int is_open, int flags, SSL *ssl1, SSL *ssl2,
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);
@ -276,9 +351,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
@ -288,20 +366,21 @@ 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;
X509 *cert = ssl_getcert();
EVP_PKEY *key = ssl_getkey();
int flags = BEV_OPT_DEFER_CALLBACKS;
struct bufferevent *bev_ll[2] = { NULL, NULL };
evutil_socket_t *fd_pair = NULL;
enum regress_openssl_type type;
type = (enum regress_openssl_type)data->setup_data;
tt_assert(cert);
tt_assert(key);
init_ssl();
if (strstr((char*)data->setup_data, "renegotiate")) {
if (type & REGRESS_OPENSSL_RENEGOTIATE) {
if (SSLeay() >= 0x10001000 &&
SSLeay() < 0x1000104f) {
/* 1.0.1 up to 1.0.1c has a bug where TLS1.1 and 1.2
@ -317,11 +396,11 @@ regress_bufferevent_openssl(void *arg)
SSL_use_certificate(ssl2, cert);
SSL_use_PrivateKey(ssl2, 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],
@ -331,15 +410,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) {
if (!(type & REGRESS_OPENSSL_FILTER)) {
tt_int_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;
@ -351,37 +430,70 @@ 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);
evbuffer_add_printf(bufferevent_get_output(bev1), "1\n");
evbuffer_add_printf(bufferevent_get_output(bev1), "1\n");
event_base_dispatch(data->base);
event_base_dispatch(data->base);
tt_assert(test_is_done == 1);
tt_assert(n_connected == 2);
tt_assert(test_is_done == 1);
tt_assert(n_connected == 2);
/* We don't handle shutdown properly yet.
tt_int_op(got_close, ==, 1);
tt_int_op(got_error, ==, 0);
*/
/* 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);
bufferevent_set_timeouts(bev1, &t, &t);
evbuffer_add_printf(bufferevent_get_output(bev1), "1\n");
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);
}
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, ssl_getcert());
SSL_use_PrivateKey(ssl, ssl_getkey());
bev = bufferevent_openssl_socket_new(
data->base,
@ -391,14 +503,129 @@ acceptcb(struct evconnlistener *listener, evutil_socket_t fd,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
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);
}
struct rwcount
{
int fd;
size_t read;
size_t write;
};
static int
bio_rwcount_new(BIO *b)
{
b->init = 0;
b->num = -1;
b->ptr = NULL;
b->flags = 0;
return 1;
}
static int
bio_rwcount_free(BIO *b)
{
if (!b)
return 0;
if (b->shutdown) {
b->init = 0;
b->flags = 0;
b->ptr = NULL;
}
return 1;
}
static int
bio_rwcount_read(BIO *b, char *out, int outlen)
{
struct rwcount *rw = b->ptr;
ssize_t ret = read(rw->fd, out, outlen);
++rw->read;
if (ret == -1 && errno == EAGAIN) {
BIO_set_retry_read(b);
}
return ret;
}
static int
bio_rwcount_write(BIO *b, const char *in, int inlen)
{
struct rwcount *rw = b->ptr;
ssize_t ret = write(rw->fd, in, inlen);
++rw->write;
if (ret == -1 && errno == EAGAIN) {
BIO_set_retry_write(b);
}
return ret;
}
static long
bio_rwcount_ctrl(BIO *b, int cmd, long num, void *ptr)
{
long ret = 0;
switch (cmd) {
case BIO_CTRL_GET_CLOSE:
ret = b->shutdown;
break;
case BIO_CTRL_SET_CLOSE:
b->shutdown = (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 = {
BIO_TYPE_LIBEVENT_RWCOUNT, "rwcount",
bio_rwcount_write,
bio_rwcount_read,
bio_rwcount_puts,
NULL /* bio_rwcount_gets */,
bio_rwcount_ctrl,
bio_rwcount_new,
bio_rwcount_free,
NULL /* callback_ctrl */,
};
static BIO_METHOD *
BIO_s_rwcount(void)
{
return &methods_rwcount;
}
static BIO *
BIO_new_rwcount(int close_flag)
{
BIO *result;
if (!(result = BIO_new(BIO_s_rwcount())))
return NULL;
result->init = 1;
result->ptr = NULL;
result->shutdown = !!close_flag;
return result;
}
static void
regress_bufferevent_openssl_connect(void *arg)
{
@ -411,6 +638,12 @@ regress_bufferevent_openssl_connect(void *arg)
struct sockaddr_in sin;
struct sockaddr_storage ss;
ev_socklen_t slen;
SSL *ssl;
BIO *bio;
struct rwcount rw = { -1, 0, 0 };
enum regress_openssl_type type;
type = (enum regress_openssl_type)data->setup_data;
init_ssl();
@ -428,51 +661,115 @@ 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");
(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) {
rw.fd = bufferevent_getfd(bev);
bio = BIO_new_rwcount(0);
tt_assert(bio);
bio->ptr = &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:
;
}
struct testcase_t ssl_testcases[] = {
{ "bufferevent_socketpair", regress_bufferevent_openssl, TT_ISOLATED,
&basic_setup, (void*)"socketpair" },
#define T(a) ((void *)(a))
{ "bufferevent_socketpair", regress_bufferevent_openssl,
TT_ISOLATED, &basic_setup, T(REGRESS_OPENSSL_SOCKETPAIR) },
{ "bufferevent_filter", regress_bufferevent_openssl,
TT_ISOLATED,
&basic_setup, (void*)"filter" },
TT_ISOLATED, &basic_setup, T(REGRESS_OPENSSL_FILTER) },
{ "bufferevent_renegotiate_socketpair", regress_bufferevent_openssl,
TT_ISOLATED,
&basic_setup, (void*)"socketpair renegotiate" },
TT_ISOLATED, &basic_setup,
T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_RENEGOTIATE) },
{ "bufferevent_renegotiate_filter", regress_bufferevent_openssl,
TT_ISOLATED,
&basic_setup, (void*)"filter renegotiate" },
TT_ISOLATED, &basic_setup,
T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_RENEGOTIATE) },
{ "bufferevent_socketpair_startopen", regress_bufferevent_openssl,
TT_ISOLATED, &basic_setup, (void*)"socketpair open" },
TT_ISOLATED, &basic_setup,
T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_OPEN) },
{ "bufferevent_filter_startopen", regress_bufferevent_openssl,
TT_ISOLATED, &basic_setup, (void*)"filter open" },
TT_ISOLATED, &basic_setup,
T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_OPEN) },
{ "bufferevent_socketpair_dirty_shutdown", regress_bufferevent_openssl,
TT_ISOLATED, &basic_setup,
T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
{ "bufferevent_filter_dirty_shutdown", regress_bufferevent_openssl,
TT_ISOLATED, &basic_setup,
T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
{ "bufferevent_renegotiate_socketpair_dirty_shutdown",
regress_bufferevent_openssl,
TT_ISOLATED,
&basic_setup,
T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_RENEGOTIATE | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
{ "bufferevent_renegotiate_filter_dirty_shutdown",
regress_bufferevent_openssl,
TT_ISOLATED,
&basic_setup,
T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_RENEGOTIATE | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
{ "bufferevent_socketpair_startopen_dirty_shutdown",
regress_bufferevent_openssl,
TT_ISOLATED, &basic_setup,
T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_OPEN | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
{ "bufferevent_filter_startopen_dirty_shutdown",
regress_bufferevent_openssl,
TT_ISOLATED, &basic_setup,
T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_OPEN | REGRESS_OPENSSL_DIRTY_SHUTDOWN) },
{ "bufferevent_socketpair_fd", regress_bufferevent_openssl,
TT_ISOLATED, &basic_setup,
T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_FD) },
{ "bufferevent_socketpair_freed", regress_bufferevent_openssl,
TT_ISOLATED, &basic_setup,
T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_FREED) },
{ "bufferevent_socketpair_freed_fd", regress_bufferevent_openssl,
TT_ISOLATED, &basic_setup,
T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_FREED | REGRESS_OPENSSL_FD) },
{ "bufferevent_filter_freed_fd", regress_bufferevent_openssl,
TT_ISOLATED, &basic_setup,
T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_FREED | REGRESS_OPENSSL_FD) },
{ "bufferevent_socketpair_timeout", regress_bufferevent_openssl,
TT_ISOLATED, &basic_setup,
T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_TIMEOUT) },
{ "bufferevent_socketpair_timeout_freed_fd", regress_bufferevent_openssl,
TT_ISOLATED, &basic_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 },
{ "bufferevent_connect_sleep", regress_bufferevent_openssl_connect,
TT_FORK|TT_NEED_BASE, &basic_setup, T(REGRESS_OPENSSL_SLEEP) },
#undef T
END_OF_TESTCASES,
};

View File

@ -135,11 +135,18 @@ regress_clean_dnsserver(void)
evutil_closesocket(dns_sock);
}
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 +162,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));

View File

@ -34,6 +34,7 @@ struct regress_dns_server_table {
const char *anstype;
const char *ans;
int seen;
int lower;
};
struct evdns_server_port *

View File

@ -579,7 +579,12 @@ struct testcase_t thread_testcases[] = {
{ "deferred_cb_skew", thread_deferred_cb_skew,
TT_FORK|TT_NEED_THREADS|TT_OFF_BY_DEFAULT,
&basic_setup, NULL },
#ifndef _WIN32
/****** XXX TODO FIXME windows seems to be having some timing trouble,
* looking into it now. / ellzey
******/
TEST(no_events),
#endif
END_OF_TESTCASES
};

View File

@ -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() {

View File

@ -261,7 +261,7 @@ int evutil_open_closeonexec_(const char *pathname, int flags, unsigned mode);
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);
int evutil_socket_connect_(evutil_socket_t *fd_ptr, const struct sockaddr *sa, int socklen);
int evutil_socket_finished_connecting_(evutil_socket_t fd);

View 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];
};