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

View File

@ -3,7 +3,9 @@ env:
- EVENT_BUILD_METHOD=cmake EVENT_CMAKE_OPTIONS="" - 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_OPENSSL=ON"
- EVENT_BUILD_METHOD=cmake EVENT_CMAKE_OPTIONS="-DEVENT__DISABLE_THREAD_SUPPORT=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 language: c
compiler: compiler:
- gcc - gcc
@ -12,5 +14,8 @@ install:
- sudo apt-get update -qq - sudo apt-get update -qq
- sudo apt-get install -y -qq zlib1g-dev libssl-dev build-essential automake autoconf cmake - sudo apt-get install -y -qq zlib1g-dev libssl-dev build-essential automake autoconf cmake
script: 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 - 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) # 0. BUILDING AND INSTALLATION (Briefly)
## Autoconf ## Autoconf
@ -7,6 +18,72 @@
$ make verify # (optional) $ make verify # (optional)
$ sudo make install $ 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) ## CMake (Windows)
Install CMake: <http://www.cmake.org> 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: install:
- appveyor DownloadFile http://slproweb.com/download/Win32OpenSSL-1_0_1L.exe - set PATH=%PATH%;C:\MinGW\msys\1.0\bin;C:\MinGW\bin
- Win32OpenSSL-1_0_1L.exe /silent /verysilent /sp- /suppressmsgboxes - appveyor DownloadFile https://strcpy.net/packages/Win32OpenSSL-1_0_2a.exe
- Win32OpenSSL-1_0_2a.exe /silent /verysilent /sp- /suppressmsgboxes
build_script: build_script:
- md build - cmd: 'echo Cygwin root is: %CYG_ROOT%'
- cd build - cmd: 'echo Build folder is: %APPVEYOR_BUILD_FOLDER%'
- cmake .. - cmd: 'echo Repo build branch is: %APPVEYOR_REPO_BRANCH%'
- cmake --build . - cmd: 'echo Repo build commit is: %APPVEYOR_REPO_COMMIT%'
- ctest --output-on-failure - 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: cache:
- C:\OpenSSL-Win32 - 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, /* this way we can manipulate the buffer to different addresses,
* which is required for mmap for example. * 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; chain->refcnt = 1;
@ -2909,7 +2909,7 @@ evbuffer_add_reference(struct evbuffer *outbuf,
if (!chain) if (!chain)
return (-1); return (-1);
chain->flags |= EVBUFFER_REFERENCE | EVBUFFER_IMMUTABLE; chain->flags |= EVBUFFER_REFERENCE | EVBUFFER_IMMUTABLE;
chain->buffer = (u_char *)data; chain->buffer = (unsigned char *)data;
chain->buffer_len = datlen; chain->buffer_len = datlen;
chain->off = datlen; chain->off = datlen;

View File

@ -40,6 +40,17 @@ extern "C" {
#include "ratelim-internal.h" #include "ratelim-internal.h"
#include "event2/bufferevent_struct.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 /* These flags are reasons that we might be declining to actually enable
reading or writing on a bufferevent. reading or writing on a bufferevent.
*/ */
@ -205,6 +216,18 @@ struct bufferevent_private {
/** Rate-limiting information for this bufferevent */ /** Rate-limiting information for this bufferevent */
struct bufferevent_rate_limit *rate_limiting; 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. */ /** 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. /** Internal: Set up locking on a bufferevent. If lock is set, use it.
* Otherwise, use a new lock. */ * Otherwise, use a new lock. */
int bufferevent_enable_locking_(struct bufferevent *bufev, void *lock); int bufferevent_enable_locking_(struct bufferevent *bufev, void *lock);
/** Internal: Increment the reference count on bufev. */ /** Internal: backwards compat macro for the now public function
void bufferevent_incref_(struct bufferevent *bufev); * Increment the reference count on bufev. */
#define bufferevent_incref_(bufev) bufferevent_incref(bufev)
/** Internal: Lock bufev and increase its reference count. /** Internal: Lock bufev and increase its reference count.
* unlocking it otherwise. */ * unlocking it otherwise. */
void bufferevent_incref_and_lock_(struct bufferevent *bufev); 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.*/ * 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 /** Internal: Drop the reference count on bufev, freeing as necessary, and
* unlocking it otherwise. Returns 1 if it freed the bufferevent. */ * unlocking it otherwise. Returns 1 if it freed the bufferevent. */
int bufferevent_decref_and_unlock_(struct bufferevent *bufev); 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, * 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. */ * 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_timeouts_(struct bufferevent *bev);
int bufferevent_generic_adj_existing_timeouts_(struct bufferevent *bev);
enum bufferevent_options bufferevent_get_options_(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 /** Internal use: We have just successfully read data into an inbuf, so
* reset the read timeout (if any). */ * reset the read timeout (if any). */
#define BEV_RESET_GENERIC_READ_TIMEOUT(bev) \ #define BEV_RESET_GENERIC_READ_TIMEOUT(bev) \

View File

@ -777,7 +777,7 @@ bufferevent_finalize_cb_(struct event_callback *evcb, void *arg_)
} }
int int
bufferevent_decref_(struct bufferevent *bufev) bufferevent_decref(struct bufferevent *bufev)
{ {
BEV_LOCK(bufev); BEV_LOCK(bufev);
return bufferevent_decref_and_unlock_(bufev); return bufferevent_decref_and_unlock_(bufev);
@ -793,11 +793,15 @@ bufferevent_free(struct bufferevent *bufev)
} }
void void
bufferevent_incref_(struct bufferevent *bufev) bufferevent_incref(struct bufferevent *bufev)
{ {
struct bufferevent_private *bufev_private = struct bufferevent_private *bufev_private =
EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); 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); BEV_LOCK(bufev);
++bufev_private->refcnt; ++bufev_private->refcnt;
BEV_UNLOCK(bufev); BEV_UNLOCK(bufev);
@ -965,10 +969,33 @@ bufferevent_generic_adj_timeouts_(struct bufferevent *bev)
return 0; 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 int
bufferevent_add_event_(struct event *ev, const struct timeval *tv) 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); return event_add(ev, NULL);
else else
return event_add(ev, tv); 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); bevf = upcast(bev);
data->ptr = bevf->underlying; data->ptr = bevf->underlying;
return 0; return 0;
case BEV_CTRL_GET_FD:
case BEV_CTRL_SET_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: case BEV_CTRL_CANCEL_ALL:
default: default:
return -1; return -1;
} }
return -1;
} }

View File

@ -320,8 +320,6 @@ struct bufferevent_openssl {
unsigned write_blocked_on_read : 1; unsigned write_blocked_on_read : 1;
/* Treat TCP close before SSL close on SSL >= v3 as clean EOF. */ /* Treat TCP close before SSL close on SSL >= v3 as clean EOF. */
unsigned allow_dirty_shutdown : 1; unsigned allow_dirty_shutdown : 1;
/* XXXX */
unsigned fd_is_set : 1;
/* XXX */ /* XXX */
unsigned n_errors : 2; 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); 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 static int
set_open_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd) 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 { } else {
struct bufferevent *bev = &bev_ssl->bev.bev; struct bufferevent *bev = &bev_ssl->bev.bev;
int rpending=0, wpending=0, r1=0, r2=0; 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 (event_initialized(&bev->ev_read)) {
if (bev_ssl->fd_is_set) {
rpending = event_pending(&bev->ev_read, EV_READ, NULL); rpending = event_pending(&bev->ev_read, EV_READ, NULL);
wpending = event_pending(&bev->ev_write, EV_WRITE, NULL); wpending = event_pending(&bev->ev_write, EV_WRITE, NULL);
event_del(&bev->ev_read); event_del(&bev->ev_read);
event_del(&bev->ev_write); event_del(&bev->ev_write);
} }
event_assign(&bev->ev_read, bev->ev_base, fd, event_assign(&bev->ev_read, bev->ev_base, fd,
EV_READ|EV_PERSIST|EV_FINALIZE, EV_READ|EV_PERSIST|EV_FINALIZE,
be_openssl_readeventcb, bev_ssl); be_openssl_readeventcb, bev_ssl);
event_assign(&bev->ev_write, bev->ev_base, fd, event_assign(&bev->ev_write, bev->ev_base, fd,
EV_WRITE|EV_PERSIST|EV_FINALIZE, EV_WRITE|EV_PERSIST|EV_FINALIZE,
be_openssl_writeeventcb, bev_ssl); be_openssl_writeeventcb, bev_ssl);
if (rpending) if (rpending)
r1 = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read); r1 = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read);
if (wpending) if (wpending)
r2 = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write); 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; 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 static int
do_handshake(struct bufferevent_openssl *bev_ssl) do_handshake(struct bufferevent_openssl *bev_ssl)
@ -1011,9 +1027,10 @@ do_handshake(struct bufferevent_openssl *bev_ssl)
decrement_buckets(bev_ssl); decrement_buckets(bev_ssl);
if (r==1) { if (r==1) {
int fd = event_get_fd(&bev_ssl->bev.bev.ev_read);
/* We're done! */ /* We're done! */
bev_ssl->state = BUFFEREVENT_SSL_OPEN; 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 */ /* Call do_read and do_write as needed */
bufferevent_enable(&bev_ssl->bev.bev, bev_ssl->bev.bev.enabled); bufferevent_enable(&bev_ssl->bev.bev, bev_ssl->bev.bev.enabled);
bufferevent_run_eventcb_(&bev_ssl->bev.bev, 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); return do_handshake(bev_ssl);
} else { } else {
struct bufferevent *bev = &bev_ssl->bev.bev; struct bufferevent *bev = &bev_ssl->bev.bev;
int r1=0, r2=0;
if (fd < 0 && bev_ssl->fd_is_set) if (event_initialized(&bev->ev_read)) {
fd = event_get_fd(&bev->ev_read);
if (bev_ssl->fd_is_set) {
event_del(&bev->ev_read); event_del(&bev->ev_read);
event_del(&bev->ev_write); event_del(&bev->ev_write);
} }
event_assign(&bev->ev_read, bev->ev_base, fd, event_assign(&bev->ev_read, bev->ev_base, fd,
EV_READ|EV_PERSIST|EV_FINALIZE, EV_READ|EV_PERSIST|EV_FINALIZE,
be_openssl_handshakeeventcb, bev_ssl); be_openssl_handshakeeventcb, bev_ssl);
event_assign(&bev->ev_write, bev->ev_base, fd, event_assign(&bev->ev_write, bev->ev_base, fd,
EV_WRITE|EV_PERSIST|EV_FINALIZE, EV_WRITE|EV_PERSIST|EV_FINALIZE,
be_openssl_handshakeeventcb, bev_ssl); be_openssl_handshakeeventcb, bev_ssl);
if (fd >= 0) { if (fd >= 0)
r1 = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read); bufferevent_enable(bev, bev->enabled);
r2 = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write); return 0;
bev_ssl->fd_is_set = 1;
}
return (r1<0 || r2<0) ? -1 : 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 int
bufferevent_ssl_renegotiate(struct bufferevent *bev) bufferevent_ssl_renegotiate(struct bufferevent *bev)
{ {
@ -1104,7 +1124,7 @@ bufferevent_ssl_renegotiate(struct bufferevent *bev)
if (SSL_renegotiate(bev_ssl->ssl) < 0) if (SSL_renegotiate(bev_ssl->ssl) < 0)
return -1; return -1;
bev_ssl->state = BUFFEREVENT_SSL_CONNECTING; 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; return -1;
if (!bev_ssl->underlying) if (!bev_ssl->underlying)
return do_handshake(bev_ssl); return do_handshake(bev_ssl);
@ -1119,14 +1139,13 @@ be_openssl_outbuf_cb(struct evbuffer *buf,
int r = 0; int r = 0;
/* XXX need to hold a reference here. */ /* XXX need to hold a reference here. */
if (cbinfo->n_added && bev_ssl->state == BUFFEREVENT_SSL_OPEN) { if (cbinfo->n_added && bev_ssl->state == BUFFEREVENT_SSL_OPEN &&
if (cbinfo->orig_size == 0) cbinfo->orig_size == 0) {
r = bufferevent_add_event_(&bev_ssl->bev.bev.ev_write, r = bufferevent_add_event_(&bev_ssl->bev.bev.ev_write,
&bev_ssl->bev.bev.timeout_write); &bev_ssl->bev.bev.timeout_write);
consider_writing(bev_ssl);
} }
/* XXX Handle r < 0 */ /* 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); struct bufferevent_openssl *bev_ssl = upcast(bev);
int r1 = 0, r2 = 0; int r1 = 0, r2 = 0;
if (bev_ssl->state != BUFFEREVENT_SSL_OPEN)
return 0;
if (events & EV_READ) if (events & EV_READ)
r1 = start_reading(bev_ssl); r1 = start_reading(bev_ssl);
if (events & EV_WRITE) if (events & EV_WRITE)
@ -1162,8 +1178,6 @@ static int
be_openssl_disable(struct bufferevent *bev, short events) be_openssl_disable(struct bufferevent *bev, short events)
{ {
struct bufferevent_openssl *bev_ssl = upcast(bev); struct bufferevent_openssl *bev_ssl = upcast(bev);
if (bev_ssl->state != BUFFEREVENT_SSL_OPEN)
return 0;
if (events & EV_READ) if (events & EV_READ)
stop_reading(bev_ssl); stop_reading(bev_ssl);
@ -1233,23 +1247,7 @@ be_openssl_adj_timeouts(struct bufferevent *bev)
if (bev_ssl->underlying) { if (bev_ssl->underlying) {
return bufferevent_generic_adj_timeouts_(bev); return bufferevent_generic_adj_timeouts_(bev);
} else { } else {
int r1=0, r2=0; return bufferevent_generic_adj_existing_timeouts_(bev);
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;
} }
} }
@ -1274,25 +1272,16 @@ be_openssl_ctrl(struct bufferevent *bev,
BIO *bio; BIO *bio;
bio = BIO_new_socket(data->fd, 0); bio = BIO_new_socket(data->fd, 0);
SSL_set_bio(bev_ssl->ssl, bio, bio); SSL_set_bio(bev_ssl->ssl, bio, bio);
bev_ssl->fd_is_set = 1;
} }
if (data->fd == -1) if (bev_ssl->state == BUFFEREVENT_SSL_OPEN && data->fd >= 0)
bev_ssl->fd_is_set = 0;
if (bev_ssl->state == BUFFEREVENT_SSL_OPEN)
return set_open_callbacks(bev_ssl, data->fd); return set_open_callbacks(bev_ssl, data->fd);
else { else {
return set_handshake_callbacks(bev_ssl, data->fd); return set_handshake_callbacks(bev_ssl, data->fd);
} }
case BEV_CTRL_GET_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); data->fd = event_get_fd(&bev->ev_read);
return 0; return 0;
case BEV_CTRL_GET_UNDERLYING: case BEV_CTRL_GET_UNDERLYING:
if (!bev_ssl->underlying)
return -1;
data->ptr = bev_ssl->underlying; data->ptr = bev_ssl->underlying;
return 0; return 0;
case BEV_CTRL_CANCEL_ALL: case BEV_CTRL_CANCEL_ALL:
@ -1360,16 +1349,16 @@ bufferevent_openssl_new_impl(struct event_base *base,
switch (state) { switch (state) {
case BUFFEREVENT_SSL_ACCEPTING: case BUFFEREVENT_SSL_ACCEPTING:
SSL_set_accept_state(bev_ssl->ssl); 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; goto err;
break; break;
case BUFFEREVENT_SSL_CONNECTING: case BUFFEREVENT_SSL_CONNECTING:
SSL_set_connect_state(bev_ssl->ssl); 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; goto err;
break; break;
case BUFFEREVENT_SSL_OPEN: case BUFFEREVENT_SSL_OPEN:
if (set_open_callbacks(bev_ssl, fd) < 0) if (set_open_callbacks_auto(bev_ssl, fd) < 0)
goto err; goto err;
break; break;
default: default:
@ -1382,15 +1371,6 @@ bufferevent_openssl_new_impl(struct event_base *base,
if (state == BUFFEREVENT_SSL_OPEN) if (state == BUFFEREVENT_SSL_OPEN)
bufferevent_suspend_read_(underlying, bufferevent_suspend_read_(underlying,
BEV_SUSPEND_FILT_READ); 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; 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_pair *bev_p = upcast(bev);
struct bufferevent *partner; struct bufferevent *partner;
incref_and_lock(bev);
if (!bev_p->partner) if (!bev_p->partner)
return -1; return -1;
partner = downcast(bev_p->partner);
if (mode == BEV_NORMAL) if (mode == BEV_NORMAL)
return 0; return 0;
incref_and_lock(bev);
partner = downcast(bev_p->partner);
if ((iotype & EV_READ) != 0) if ((iotype & EV_READ) != 0)
be_pair_transfer(partner, bev, 1); be_pair_transfer(partner, bev, 1);

View File

@ -79,7 +79,6 @@
static int be_socket_enable(struct bufferevent *, short); static int be_socket_enable(struct bufferevent *, short);
static int be_socket_disable(struct bufferevent *, short); static int be_socket_disable(struct bufferevent *, short);
static void be_socket_destruct(struct bufferevent *); 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_flush(struct bufferevent *, short, enum bufferevent_flush_mode);
static int be_socket_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *); 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, be_socket_disable,
NULL, /* unlink */ NULL, /* unlink */
be_socket_destruct, be_socket_destruct,
be_socket_adj_timeouts, bufferevent_generic_adj_existing_timeouts_,
be_socket_flush, be_socket_flush,
be_socket_ctrl, be_socket_ctrl,
}; };
#define be_socket_add(ev, t) \ const struct sockaddr*
bufferevent_add_event_((ev), (t)) 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 static void
bufferevent_socket_outbuf_cb(struct evbuffer *buf, bufferevent_socket_outbuf_cb(struct evbuffer *buf,
@ -115,7 +136,7 @@ bufferevent_socket_outbuf_cb(struct evbuffer *buf,
!bufev_p->write_suspended) { !bufev_p->write_suspended) {
/* Somebody added data to the buffer, and we would like to /* Somebody added data to the buffer, and we would like to
* write, and we were not writing. So, start writing. */ * 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? */ /* Should we log this? */
} }
} }
@ -239,6 +260,7 @@ bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
goto done; goto done;
} else { } else {
connected = 1; connected = 1;
bufferevent_socket_set_conn_address_fd(bufev_p, fd);
#ifdef _WIN32 #ifdef _WIN32
if (BEV_IS_ASYNC(bufev)) { if (BEV_IS_ASYNC(bufev)) {
event_del(&bufev->ev_write); event_del(&bufev->ev_write);
@ -351,7 +373,7 @@ bufferevent_socket_new(struct event_base *base, evutil_socket_t fd,
int int
bufferevent_socket_connect(struct bufferevent *bev, bufferevent_socket_connect(struct bufferevent *bev,
struct sockaddr *sa, int socklen) const struct sockaddr *sa, int socklen)
{ {
struct bufferevent_private *bufev_p = struct bufferevent_private *bufev_p =
EVUTIL_UPCAST(bev, struct bufferevent_private, bev); 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 the other addrinfos? */
/* XXX use this return value */ /* 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); r = bufferevent_socket_connect(bev, ai->ai_addr, (int)ai->ai_addrlen);
(void)r; (void)r;
bufferevent_decref_and_unlock_(bev); bufferevent_decref_and_unlock_(bev);
@ -478,23 +501,23 @@ bufferevent_socket_connect_hostname(struct bufferevent *bev,
if (port < 1 || port > 65535) if (port < 1 || port > 65535)
return -1; 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)); memset(&hint, 0, sizeof(hint));
hint.ai_family = family; hint.ai_family = family;
hint.ai_protocol = IPPROTO_TCP; hint.ai_protocol = IPPROTO_TCP;
hint.ai_socktype = SOCK_STREAM; 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_write_(bev, BEV_SUSPEND_LOOKUP);
bufferevent_suspend_read_(bev, BEV_SUSPEND_LOOKUP); bufferevent_suspend_read_(bev, BEV_SUSPEND_LOOKUP);
bufferevent_incref_(bev); bufferevent_incref_(bev);
err = evutil_getaddrinfo_async_(evdns_base, hostname, portbuf, err = evutil_getaddrinfo_async_(evdns_base, hostname, portbuf,
&hint, bufferevent_connect_getaddrinfo_cb, bev); &hint, bufferevent_connect_getaddrinfo_cb, bev);
BEV_UNLOCK(bev);
if (err == 0) { if (err == 0) {
return 0; return 0;
@ -550,14 +573,12 @@ bufferevent_new(evutil_socket_t fd,
static int static int
be_socket_enable(struct bufferevent *bufev, short event) be_socket_enable(struct bufferevent *bufev, short event)
{ {
if (event & EV_READ) { if (event & EV_READ &&
if (be_socket_add(&bufev->ev_read,&bufev->timeout_read) == -1) bufferevent_add_event_(&bufev->ev_read, &bufev->timeout_read) == -1)
return -1; return -1;
} if (event & EV_WRITE &&
if (event & EV_WRITE) { bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1)
if (be_socket_add(&bufev->ev_write,&bufev->timeout_write) == -1)
return -1; return -1;
}
return 0; return 0;
} }
@ -592,29 +613,6 @@ be_socket_destruct(struct bufferevent *bufev)
EVUTIL_CLOSESOCKET(fd); 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 static int
be_socket_flush(struct bufferevent *bev, short iotype, be_socket_flush(struct bufferevent *bev, short iotype,
enum bufferevent_flush_mode mode) 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 \ unsetenv \
usleep \ usleep \
vasprintf \ vasprintf \
getservbyname \
]) ])
AM_CONDITIONAL(STRLCPY_IMPL, [test x"$ac_cv_func_strlcpy" = xno]) 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()?]) AC_DEFINE([HAVE_GETADDRINFO], [1], [Do we have getaddrinfo()?])
else else
AC_CHECK_FUNCS([getservbyname])
# Check for gethostbyname_r in all its glorious incompatible versions. # Check for gethostbyname_r in all its glorious incompatible versions.
# (This is cut-and-pasted from Tor, which based its logic on # (This is cut-and-pasted from Tor, which based its logic on
# Python's configure.in.) # Python's configure.in.)
@ -763,6 +763,10 @@ fi
# check if we have and should use openssl # check if we have and should use openssl
AM_CONDITIONAL(OPENSSL, [test "$enable_openssl" != "no" && test "$have_openssl" = "yes"]) 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 # Add some more warnings which we use in development but not in the
# released versions. (Some relevant gcc versions can't handle these.) # 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 static int
epoll_apply_one_change(struct event_base *base, epoll_apply_one_change(struct event_base *base,
struct epollop *epollop, struct epollop *epollop,
@ -271,14 +288,7 @@ epoll_apply_one_change(struct event_base *base,
epev.data.fd = ch->fd; epev.data.fd = ch->fd;
epev.events = events; epev.events = events;
if (epoll_ctl(epollop->epfd, op, ch->fd, &epev) == 0) { 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]", event_debug((PRINT_CHANGES(op, epev.events, ch, "okay")));
epoll_op_to_string(op),
(int)epev.events,
(int)ch->fd,
ch->old_events,
ch->read_change,
ch->write_change,
ch->close_change));
return 0; return 0;
} }
@ -338,18 +348,7 @@ epoll_apply_one_change(struct event_base *base,
break; 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)", event_warn(PRINT_CHANGES(op, epev.events, ch, "failed"));
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));
return -1; 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) \ sizeof(tmp_name))<0) \
goto err; \ goto err; \
} while (0) } 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; reply.type = req->request_type;
@ -1086,9 +1068,25 @@ reply_parse(struct evdns_base *base, u8 *packet, int length) {
/* the question looks like /* the question looks like
* <label:name><u16:type><u16:class> * <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; j += 4;
if (j > length) goto err; if (j > length)
goto err;
} }
if (!name_matches) 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. */ /* 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) { for (i = 0; i < base->n_req_heads; ++i) {
while (base->req_heads[i]) { while (base->req_heads[i]) {
if (fail_requests) 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; 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) { if (base->global_search_state) {
for (dom = base->global_search_state->head; dom; dom = dom_next) { 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; other_req = &data->ipv4_request;
} }
EVDNS_LOCK(data->evdns_base); /** Called from evdns_base_free() with @fail_requests == 1 */
if (evdns_result_is_answer(result)) { if (result != DNS_ERR_SHUTDOWN) {
if (req->type == DNS_IPv4_A) EVDNS_LOCK(data->evdns_base);
++data->evdns_base->getaddrinfo_ipv4_answered; if (evdns_result_is_answer(result)) {
else if (req->type == DNS_IPv4_A)
++data->evdns_base->getaddrinfo_ipv6_answered; ++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; 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 /* The other request is still working; maybe it will
* succeed. */ * succeed. */
/* XXXX handle failure from set_timeout */ /* 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; data->pending_error = err;
return; return;
} }

View File

@ -11,8 +11,11 @@
/* Numeric representation of the version */ /* Numeric representation of the version */
#define EVENT__NUMERIC_VERSION @EVENT_NUMERIC_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 */ /* Version number of package */
#define EVENT__VERSION "@EVENT_VERSION@" #define EVENT__VERSION "@EVENT_VERSION@"
@ -33,467 +36,499 @@
#define EVENT__PACKAGE_TARNAME "" #define EVENT__PACKAGE_TARNAME ""
/* Define if libevent should build without support for a debug mode */ /* 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 */ /* 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 */ /* 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. */ /* 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. */ /* 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. */ /* 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 */ /* 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 */ /* Define is no secure id variant is available */
#cmakedefine EVENT__DNS_USE_GETTIMEOFDAY_FOR_ID 1 #cmakedefine EVENT__DNS_USE_GETTIMEOFDAY_FOR_ID
#cmakedefine EVENT__DNS_USE_FTIME_FOR_ID 1 #cmakedefine EVENT__DNS_USE_FTIME_FOR_ID
/* Define to 1 if you have the <arpa/inet.h> header file. */ /* 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. */ /* 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'. */ /* 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'. */ /* 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'. */ /* 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 */ /* 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. */ /* 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 */ /* 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. */ /* 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. */ /* 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 */ /* 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. */ /* 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. */ /* 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. */ /* 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 */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* TODO: Check for different gethostname argument counts. CheckPrototypeDefinition.cmake can be used. */
/* Define this if you have any gethostbyname_r() */ /* 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 */ /* 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 */ /* 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 */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* Define to 1 if you have the `kqueue' function. */
#cmakedefine EVENT__HAVE_KQUEUE 1 #cmakedefine EVENT__HAVE_KQUEUE
/* Define if the system has zlib */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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 */ /* Define if the system has openssl */
#cmakedefine EVENT__HAVE_OPENSSL 1 #cmakedefine EVENT__HAVE_OPENSSL
/* Defines if the system has zlib */ /* Defines if the system has zlib */
#cmakedefine EVENT__HAVE_ZLIB 1 #cmakedefine EVENT__HAVE_ZLIB
/* Define to 1 if you have the `pipe' function. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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 */ /* 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. */ /* 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'. */ /* 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. */ /* 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. */ /* 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> */ /* 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. */ /* 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. */ /* 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> */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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'. */ /* 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'. */ /* 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'. */ /* 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'. */ /* 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'. */ /* 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'. */ /* 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'. */ /* 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'. */ /* 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'. */ /* 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'. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* Define to 1 if you have the <sys/timerfd.h> header file. */
#cmakedefine EVENT__HAVE_SYS_TIMERFD_H */ #cmakedefine EVENT__HAVE_SYS_TIMERFD_H */
/* Define to 1 if you have the <sys/time.h> header file. */ /* 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. */ /* 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. */ /* 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. */ /* 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> */ /* 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> */ /* 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> */ /* 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> */ /* 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. */ /* 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> */ /* 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'. */ /* 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'. */ /* 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'. */ /* 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'. */ /* 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'. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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 */ /* 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 #ifdef __USE_UNUSED_DEFINITIONS__
your system. */ /* Define to necessary symbol if this constant uses a non-standard name on your system. */
#cmakedefine EVENT__PTHREAD_CREATE_JOINABLE ${EVENT__PTHREAD_CREATE_JOINABLE} /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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. */ /* 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>. */ /* 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. */ /* 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 */ /* 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__ */ /* set an alias for whatever __func__ __FUNCTION__ is, what sillyness */
#cmakedefine EVENT____func__ ${EVENT____func__} #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. */ /* 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. */ /* 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. */ /* 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 /* 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. */ calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus #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 #endif
/* Define to `int' if <sys/types.h> does not define. */ /* Define to `int' if <sys/tyes.h> does not define. */
#cmakedefine EVENT__pid_t ${EVENT__pid_t} #define EVENT__pid_t @EVENT__pid_t@
/* Define to `unsigned' if <sys/types.h> does not define. */ /* 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 */ /* 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. */ /* 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 #endif

View File

@ -368,7 +368,6 @@ struct event_config {
}; };
/* Internal use only: Functions that might be missing from <sys/queue.h> */ /* 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 #ifndef TAILQ_FIRST
#define TAILQ_FIRST(head) ((head)->tqh_first) #define TAILQ_FIRST(head) ((head)->tqh_first)
#endif #endif
@ -394,7 +393,6 @@ struct event_config {
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
} while (0) } while (0)
#endif #endif
#endif /* TAILQ_FOREACH */
#define N_ACTIVE_CALLBACKS(base) \ #define N_ACTIVE_CALLBACKS(base) \
((base)->event_count_active) ((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, int event_base_foreach_event_nolock_(struct event_base *base,
event_base_foreach_event_cb cb, void *arg); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -183,14 +183,14 @@
.Fn "evbuffer_write" "struct evbuffer *buf" "int fd" .Fn "evbuffer_write" "struct evbuffer *buf" "int fd"
.Ft int .Ft int
.Fn "evbuffer_read" "struct evbuffer *buf" "int fd" "int size" .Fn "evbuffer_read" "struct evbuffer *buf" "int fd" "int size"
.Ft "u_char *" .Ft "unsigned char *"
.Fn "evbuffer_find" "struct evbuffer *buf" "const u_char *data" "size_t size" .Fn "evbuffer_find" "struct evbuffer *buf" "const unsigned char *data" "size_t size"
.Ft "char *" .Ft "char *"
.Fn "evbuffer_readline" "struct evbuffer *buf" .Fn "evbuffer_readline" "struct evbuffer *buf"
.Ft "struct evhttp *" .Ft "struct evhttp *"
.Fn "evhttp_new" "struct event_base *base" .Fn "evhttp_new" "struct event_base *base"
.Ft int .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" .Ft "void"
.Fn "evhttp_free" "struct evhttp *http" .Fn "evhttp_free" "struct evhttp *http"
.Ft int .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; 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. */ /* Set if it's too late to enable event_debug_mode. */
static int event_debug_mode_too_late = 0; static int event_debug_mode_too_late = 0;
#ifndef EVENT__DISABLE_THREAD_SUPPORT #ifndef EVENT__DISABLE_THREAD_SUPPORT
@ -655,6 +671,10 @@ event_base_new_with_config(const struct event_config *cfg)
/* prepare for threading */ /* 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 #ifndef EVENT__DISABLE_THREAD_SUPPORT
if (EVTHREAD_LOCKING_ENABLED() && if (EVTHREAD_LOCKING_ENABLED() &&
(!cfg || !(cfg->flags & EVENT_BASE_FLAG_NOLOCK))) { (!cfg || !(cfg->flags & EVENT_BASE_FLAG_NOLOCK))) {
@ -749,6 +769,29 @@ event_base_cancel_single_callback_(struct event_base *base,
return result; 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 static void
event_base_free_(struct event_base *base, int run_finalizers) 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) if (base->common_timeout_queues)
mm_free(base->common_timeout_queues); mm_free(base->common_timeout_queues);
for (i = 0; i < base->nactivequeues; ++i) { for (;;) {
struct event_callback *evcb, *next; /* For finalizers we can register yet another finalizer out from
for (evcb = TAILQ_FIRST(&base->activequeues[i]); evcb; ) { * finalizer, and iff finalizer will be in active_later_queue we can
next = TAILQ_NEXT(evcb, evcb_active_next); * add finalizer to activequeues, and we will have events in
n_deleted += event_base_cancel_single_callback_(base, evcb, run_finalizers); * activequeues after this function returns, which is not what we want
evcb = next; * (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) if (n_deleted)
event_debug(("%s: %d events were still set in base", event_debug(("%s: %d events were still set in base",

View File

@ -40,10 +40,11 @@
#include <winsock2.h> #include <winsock2.h>
#include <windows.h> #include <windows.h>
#undef WIN32_LEAN_AND_MEAN #undef WIN32_LEAN_AND_MEAN
#else
#include <sys/ioctl.h>
#endif #endif
#ifdef EVENT__HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#include <sys/queue.h> #include <sys/queue.h>
#ifdef EVENT__HAVE_SYS_TIME_H #ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h> #include <sys/time.h>

View File

@ -45,6 +45,11 @@
#define GLOBAL static #define GLOBAL static
#endif #endif
#ifndef EVENT__DISABLE_DEBUG_MODE
extern int event_debug_created_threadable_ctx_;
extern int event_debug_mode_on_;
#endif
/* globals */ /* globals */
GLOBAL int evthread_lock_debugging_enabled_ = 0; GLOBAL int evthread_lock_debugging_enabled_ = 0;
GLOBAL struct evthread_lock_callbacks evthread_lock_fns_ = { 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(); 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 (!cbs) {
if (target->alloc) if (target->alloc)
event_warnx("Trying to disable lock functions after " 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(); 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 (!cbs) {
if (target->alloc_condition) if (target->alloc_condition)
event_warnx("Trying to disable condition functions " 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); return evthread_lock_fns_.alloc(locktype);
} else { } else {
/* Case 4: Fill in a debug lock with a real lock */ /* 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 && EVUTIL_ASSERT(enable_locks &&
evthread_lock_debugging_enabled_); evthread_lock_debugging_enabled_);
EVUTIL_ASSERT(lock->locktype == locktype); EVUTIL_ASSERT(lock->locktype == locktype);
EVUTIL_ASSERT(lock->lock == NULL);
lock->lock = original_lock_fns_.alloc(
locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
if (!lock->lock) { if (!lock->lock) {
lock->count = -200; lock->lock = original_lock_fns_.alloc(
mm_free(lock); locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
return NULL; if (!lock->lock) {
lock->count = -200;
mm_free(lock);
return NULL;
}
} }
return lock; return lock;
} }
@ -406,6 +428,12 @@ evthreadimpl_get_id_()
void * void *
evthreadimpl_lock_alloc_(unsigned locktype) 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 ? return evthread_lock_fns_.alloc ?
evthread_lock_fns_.alloc(locktype) : NULL; evthread_lock_fns_.alloc(locktype) : NULL;
} }
@ -434,6 +462,12 @@ evthreadimpl_lock_unlock_(unsigned mode, void *lock)
void * void *
evthreadimpl_cond_alloc_(unsigned condtype) 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 ? return evthread_cond_fns_.alloc_condition ?
evthread_cond_fns_.alloc_condition(condtype) : NULL; 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; struct sockaddr_in connect_addr;
ev_socklen_t size; ev_socklen_t size;
int saved_errno = -1; int saved_errno = -1;
int family_test;
if (protocol
|| (family != AF_INET family_test = family != AF_INET;
#ifdef AF_UNIX #ifdef AF_UNIX
&& family != AF_UNIX family_test = family_test && (family != AF_UNIX);
#endif #endif
)) { if (protocol || family_test) {
EVUTIL_SET_SOCKET_ERROR(ERR(EAFNOSUPPORT)); EVUTIL_SET_SOCKET_ERROR(ERR(EAFNOSUPPORT));
return -1; return -1;
} }
if (!fd) { if (!fd) {
EVUTIL_SET_SOCKET_ERROR(ERR(EINVAL)); EVUTIL_SET_SOCKET_ERROR(ERR(EINVAL));
return -1; return -1;
@ -257,6 +258,9 @@ evutil_ersatz_socketpair_(int family, int type, int protocol,
connector = socket(AF_INET, type, 0); connector = socket(AF_INET, type, 0);
if (connector < 0) if (connector < 0)
goto tidy_up_and_fail; goto tidy_up_and_fail;
memset(&connect_addr, 0, sizeof(connect_addr));
/* We want to find out the port number to connect to. */ /* We want to find out the port number to connect to. */
size = sizeof(connect_addr); size = sizeof(connect_addr);
if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1) if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1)
@ -310,7 +314,7 @@ evutil_make_socket_nonblocking(evutil_socket_t fd)
{ {
#ifdef _WIN32 #ifdef _WIN32
{ {
u_long nonblocking = 1; unsigned long nonblocking = 1;
if (ioctlsocket(fd, FIONBIO, &nonblocking) == SOCKET_ERROR) { if (ioctlsocket(fd, FIONBIO, &nonblocking) == SOCKET_ERROR) {
event_sock_warn(fd, "fcntl(%d, F_GETFL)", (int)fd); event_sock_warn(fd, "fcntl(%d, F_GETFL)", (int)fd);
return -1; return -1;
@ -355,7 +359,7 @@ evutil_fast_socket_nonblocking(evutil_socket_t fd)
int int
evutil_make_listen_socket_reuseable(evutil_socket_t sock) evutil_make_listen_socket_reuseable(evutil_socket_t sock)
{ {
#ifndef _WIN32 #if defined(SO_REUSEADDR) && !defined(_WIN32)
int one = 1; int one = 1;
/* REUSEADDR on Unix means, "don't hang on to this address after the /* 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 * 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. */ /* XXX we should use an enum here. */
/* 2 for connection refused, 1 for connected, 0 for not yet, -1 for error. */ /* 2 for connection refused, 1 for connected, 0 for not yet, -1 for error. */
int 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; int made_fd = 0;
@ -1159,7 +1163,7 @@ addrinfo_from_hostent(const struct hostent *ent,
sin6.sin6_family = AF_INET6; sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(port); sin6.sin6_port = htons(port);
sa = (struct sockaddr *)&sin6; sa = (struct sockaddr *)&sin6;
socklen = sizeof(struct sockaddr_in); socklen = sizeof(struct sockaddr_in6);
addrp = &sin6.sin6_addr; addrp = &sin6.sin6_addr;
if (ent->h_length != sizeof(sin6.sin6_addr)) { if (ent->h_length != sizeof(sin6.sin6_addr)) {
event_warnx("Weird h_length from gethostbyname"); event_warnx("Weird h_length from gethostbyname");
@ -1705,10 +1709,10 @@ evutil_socket_error_to_string(int errcode)
goto done; goto done;
} }
if (0 != FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | if (0 != FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_ALLOCATE_BUFFER, 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 */ chomp (msg); /* because message has trailing newline */
else { else {
size_t len = 50; size_t len = 50;

View File

@ -62,10 +62,10 @@ struct evhttp_connection {
struct event retry_ev; /* for retrying connects */ struct event retry_ev; /* for retrying connects */
char *bind_address; /* address to use for binding the src */ 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 */ char *address; /* address to connect to */
u_short port; unsigned short port;
size_t max_headers_size; size_t max_headers_size;
ev_uint64_t max_body_size; ev_uint64_t max_body_size;
@ -101,13 +101,6 @@ struct evhttp_connection {
struct event_base *base; struct event_base *base;
struct evdns_base *dns_base; struct evdns_base *dns_base;
int ai_family; 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 */ /* A callback for an http server */

139
http.c
View File

@ -35,18 +35,22 @@
#include <sys/types.h> #include <sys/types.h>
#endif #endif
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_IOCCOM_H #ifdef HAVE_SYS_IOCCOM_H
#include <sys/ioccom.h> #include <sys/ioccom.h>
#endif #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 #ifndef _WIN32
#include <sys/resource.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h>
#else #else
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.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); 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' */ /* Return true iff 'headers' contains 'Connection: keep-alive' */
static int static int
@ -674,6 +685,23 @@ evhttp_connection_incoming_fail(struct evhttp_request *req,
return (0); 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 /* Called when evcon has experienced a (non-recoverable? -NM) error, as
* given in error. If it's an outgoing connection, reset the connection, * given in error. If it's an outgoing connection, reset the connection,
* retry any pending requests, and inform the user. If it's incoming, * 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, * send over a new connection. when a user cancels a request,
* all other pending requests should be processed as normal * all other pending requests should be processed as normal
*/ */
TAILQ_REMOVE(&evcon->requests, req, next); evhttp_request_free_(evcon, req);
evhttp_request_free(req);
/* reset the connection */ /* reset the connection */
evhttp_connection_reset_(evcon); evhttp_connection_reset_(evcon);
@ -773,16 +800,12 @@ evhttp_connection_done(struct evhttp_connection *evcon)
if (con_outgoing) { if (con_outgoing) {
/* idle or close the connection */ /* idle or close the connection */
int need_close; int need_close = evhttp_is_request_connection_close(req);
TAILQ_REMOVE(&evcon->requests, req, next); TAILQ_REMOVE(&evcon->requests, req, next);
req->evcon = NULL; req->evcon = NULL;
evcon->state = EVCON_IDLE; 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 */ /* check if we got asked to close the connection */
if (need_close) if (need_close)
evhttp_connection_reset_(evcon); evhttp_connection_reset_(evcon);
@ -820,11 +843,9 @@ evhttp_connection_done(struct evhttp_connection *evcon)
/* notify the user of the request */ /* notify the user of the request */
(*req->cb)(req, req->cb_arg); (*req->cb)(req, req->cb_arg);
/* if this was an outgoing request, we own and it's done. so free it. /* 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) {
*/ evhttp_request_free_auto(req);
if (con_outgoing && ((req->flags & EVHTTP_USER_OWNED) == 0)) {
evhttp_request_free(req);
} }
/* If this was the last request of an outgoing connection and we're /* 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 MORE_DATA_EXPECTED:
case REQUEST_CANCELED: /* ??? */ case REQUEST_CANCELED: /* ??? */
default: default:
bufferevent_enable(evcon->bufev, EV_READ);
break; break;
} }
} }
@ -985,7 +1005,7 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
return; return;
case REQUEST_CANCELED: case REQUEST_CANCELED:
/* request canceled */ /* request canceled */
evhttp_request_free(req); evhttp_request_free_auto(req);
return; return;
case MORE_DATA_EXPECTED: case MORE_DATA_EXPECTED:
default: default:
@ -1031,7 +1051,7 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
evbuffer_drain(req->input_buffer, evbuffer_drain(req->input_buffer,
evbuffer_get_length(req->input_buffer)); evbuffer_get_length(req->input_buffer));
if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) { if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) {
evhttp_request_free(req); evhttp_request_free_auto(req);
return; return;
} }
} }
@ -1042,9 +1062,6 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
evhttp_connection_done(evcon); evhttp_connection_done(evcon);
return; return;
} }
/* Read more! */
bufferevent_enable(evcon->bufev, EV_READ);
} }
#define get_deferred_queue(evcon) \ #define get_deferred_queue(evcon) \
@ -1125,6 +1142,9 @@ evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg)
EVUTIL_ASSERT(evcon->state == EVCON_WRITING); 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 */ /* We are done writing our header and are now expecting the response */
req->kind = EVHTTP_RESPONSE; req->kind = EVHTTP_RESPONSE;
@ -1152,8 +1172,7 @@ evhttp_connection_free(struct evhttp_connection *evcon)
* evhttp_connection_fail_. * evhttp_connection_fail_.
*/ */
while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) { while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) {
TAILQ_REMOVE(&evcon->requests, req, next); evhttp_request_free_(evcon, req);
evhttp_request_free(req);
} }
if (evcon->http_server != NULL) { if (evcon->http_server != NULL) {
@ -1173,6 +1192,7 @@ evhttp_connection_free(struct evhttp_connection *evcon)
&evcon->read_more_deferred_cb); &evcon->read_more_deferred_cb);
if (evcon->fd != -1) { if (evcon->fd != -1) {
bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE);
shutdown(evcon->fd, EVUTIL_SHUT_WR); shutdown(evcon->fd, EVUTIL_SHUT_WR);
if (!(bufferevent_get_options_(evcon->bufev) & BEV_OPT_CLOSE_ON_FREE)) { if (!(bufferevent_get_options_(evcon->bufev) & BEV_OPT_CLOSE_ON_FREE)) {
evutil_closesocket(evcon->fd); evutil_closesocket(evcon->fd);
@ -1185,9 +1205,6 @@ evhttp_connection_free(struct evhttp_connection *evcon)
if (evcon->address != NULL) if (evcon->address != NULL)
mm_free(evcon->address); mm_free(evcon->address);
if (evcon->conn_address != NULL)
mm_free(evcon->conn_address);
mm_free(evcon); mm_free(evcon);
} }
@ -1352,7 +1369,7 @@ evhttp_connection_cb_cleanup(struct evhttp_connection *evcon)
/* we might want to set an error here */ /* we might want to set an error here */
request->cb(request, request->cb_arg); 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; struct evhttp_connection *evcon = arg;
int error; int error;
ev_socklen_t errsz = sizeof(error); ev_socklen_t errsz = sizeof(error);
socklen_t conn_address_len = sizeof(*evcon->conn_address);
if (evcon->fd == -1) if (evcon->fd == -1)
evcon->fd = bufferevent_getfd(bufev); evcon->fd = bufferevent_getfd(bufev);
@ -1492,14 +1508,6 @@ evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg)
evcon->retry_cnt = 0; evcon->retry_cnt = 0;
evcon->state = EVCON_IDLE; 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 */ /* reset the bufferevent cbs */
bufferevent_setcb(evcon->bufev, bufferevent_setcb(evcon->bufev,
evhttp_read_cb, evhttp_read_cb,
@ -2181,9 +2189,6 @@ evhttp_read_header(struct evhttp_connection *evcon,
return; return;
} }
/* Disable reading for now */
bufferevent_disable(evcon->bufev, EV_READ);
/* Callback can shut down connection with negative return value */ /* Callback can shut down connection with negative return value */
if (req->header_cb != NULL) { if (req->header_cb != NULL) {
if ((*req->header_cb)(req, req->cb_arg) < 0) { 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; 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 void
evhttp_connection_set_base(struct evhttp_connection *evcon, evhttp_connection_set_base(struct evhttp_connection *evcon,
struct event_base *base) struct event_base *base)
@ -2412,13 +2431,16 @@ evhttp_connection_get_peer(struct evhttp_connection *evcon,
const struct sockaddr* const struct sockaddr*
evhttp_connection_get_addr(struct evhttp_connection *evcon) evhttp_connection_get_addr(struct evhttp_connection *evcon)
{ {
return (struct sockaddr *)evcon->conn_address; return bufferevent_socket_get_conn_address_(evcon->bufev);
} }
int int
evhttp_connection_connect_(struct evhttp_connection *evcon) evhttp_connection_connect_(struct evhttp_connection *evcon)
{ {
int old_state = evcon->state; 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) if (evcon->state == EVCON_CONNECTING)
return (0); return (0);
@ -2450,17 +2472,29 @@ evhttp_connection_connect_(struct evhttp_connection *evcon)
evcon); evcon);
if (!evutil_timerisset(&evcon->timeout)) { if (!evutil_timerisset(&evcon->timeout)) {
const struct timeval conn_tv = { HTTP_CONNECT_TIMEOUT, 0 }; 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 { } 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 */ /* make sure that we get a write callback */
bufferevent_enable(evcon->bufev, EV_WRITE); bufferevent_enable(evcon->bufev, EV_WRITE);
evcon->state = EVCON_CONNECTING; evcon->state = EVCON_CONNECTING;
if (bufferevent_socket_connect_hostname(evcon->bufev, evcon->dns_base, if (evcon->flags & EVHTTP_CON_REUSE_CONNECTED_ADDR &&
evcon->ai_family, evcon->address, evcon->port) < 0) { 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; evcon->state = old_state;
event_sock_warn(evcon->fd, "%s: connection to \"%s\" failed", event_sock_warn(evcon->fd, "%s: connection to \"%s\" failed",
__func__, evcon->address); __func__, evcon->address);
@ -2493,7 +2527,7 @@ evhttp_make_request(struct evhttp_connection *evcon,
mm_free(req->uri); mm_free(req->uri);
if ((req->uri = mm_strdup(uri)) == NULL) { if ((req->uri = mm_strdup(uri)) == NULL) {
event_warn("%s: strdup", __func__); event_warn("%s: strdup", __func__);
evhttp_request_free(req); evhttp_request_free_auto(req);
return (-1); 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 void
evhttp_start_read_(struct evhttp_connection *evcon) evhttp_start_read_(struct evhttp_connection *evcon)
{ {
/* Set up an event to read the headers */
bufferevent_disable(evcon->bufev, EV_WRITE); bufferevent_disable(evcon->bufev, EV_WRITE);
bufferevent_enable(evcon->bufev, EV_READ); bufferevent_enable(evcon->bufev, EV_READ);
evcon->state = EVCON_READING_FIRSTLINE; evcon->state = EVCON_READING_FIRSTLINE;
/* Reset the bufferevent callbacks */ /* Reset the bufferevent callbacks */
bufferevent_setcb(evcon->bufev, bufferevent_setcb(evcon->bufev,
@ -2599,9 +2633,8 @@ evhttp_send_done(struct evhttp_connection *evcon, void *arg)
need_close = need_close =
(REQ_VERSION_BEFORE(req, 1, 1) && (REQ_VERSION_BEFORE(req, 1, 1) &&
!evhttp_is_connection_keepalive(req->input_headers))|| !evhttp_is_connection_keepalive(req->input_headers)) ||
evhttp_is_connection_close(req->flags, req->input_headers) || evhttp_is_request_connection_close(req);
evhttp_is_connection_close(req->flags, req->output_headers);
EVUTIL_ASSERT(req->flags & EVHTTP_REQ_OWN_CONNECTION); EVUTIL_ASSERT(req->flags & EVHTTP_REQ_OWN_CONNECTION);
evhttp_request_free(req); evhttp_request_free(req);
@ -4035,6 +4068,8 @@ evhttp_get_request_connection(
evcon->fd = fd; evcon->fd = fd;
bufferevent_enable(evcon->bufev, EV_READ);
bufferevent_disable(evcon->bufev, EV_WRITE);
bufferevent_setfd(evcon->bufev, fd); bufferevent_setfd(evcon->bufev, fd);
return (evcon); return (evcon);

View File

@ -63,8 +63,6 @@ extern "C" {
#include <winsock2.h> #include <winsock2.h>
#include <windows.h> #include <windows.h>
#undef WIN32_LEAN_AND_MEAN #undef WIN32_LEAN_AND_MEAN
typedef unsigned char u_char;
typedef unsigned short u_short;
#endif #endif
#include <event2/event_struct.h> #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 @deprecated This function is deprecated because its behavior is not correct
for almost any protocol, and also because it's wholly subsumed by 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. @return 0 on success, -1 on failure.
*/ */
EVENT2_EXPORT_SYMBOL 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; struct evdns_base;
/** /**
@ -562,6 +562,32 @@ void bufferevent_lock(struct bufferevent *bufev);
EVENT2_EXPORT_SYMBOL EVENT2_EXPORT_SYMBOL
void bufferevent_unlock(struct bufferevent *bufev); 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 Flags that can be passed into filters to let them know how to
deal with the incoming data. deal with the incoming data.

View File

@ -633,9 +633,22 @@ struct evhttp_connection *evhttp_connection_base_new(
/** /**
* Set family hint for DNS requests. * Set family hint for DNS requests.
*/ */
EVENT2_EXPORT_SYMBOL
void evhttp_connection_set_family(struct evhttp_connection *evcon, void evhttp_connection_set_family(struct evhttp_connection *evcon,
int family); 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 /** Takes ownership of the request object
* *
* Can be used in a request callback to keep onto the request until * 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); char **address, ev_uint16_t *port);
/** Get the remote address associated with this connection. /** Get the remote address associated with this connection.
* extracted from getpeername(). * extracted from getpeername() OR from nameserver.
* *
* @return NULL if getpeername() return non success, * @return NULL if getpeername() return non success,
* or connection is not connected, * 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_UINT64_MAX ((((ev_uint64_t)0xffffffffUL) << 32) | 0xffffffffUL)
#define EV_INT64_MAX ((((ev_int64_t) 0x7fffffffL) << 32) | 0xffffffffL) #define EV_INT64_MAX ((((ev_int64_t) 0x7fffffffL) << 32) | 0xffffffffL)
#define EV_INT64_MIN ((-EV_INT64_MAX) - 1) #define EV_INT64_MIN ((-EV_INT64_MAX) - 1)
@ -245,7 +246,21 @@ extern "C" {
#define EV_UINT8_MAX 255 #define EV_UINT8_MAX 255
#define EV_INT8_MAX 127 #define EV_INT8_MAX 127
#define EV_INT8_MIN ((-EV_INT8_MAX) - 1) #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 @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 /* 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 * 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. */ * 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 PTR_TO_UDATA(x) ((intptr_t)(x))
#define INT_TO_UDATA(x) ((intptr_t)(x)) #define INT_TO_UDATA(x) ((intptr_t)(x))
#else #else
@ -260,7 +260,8 @@ kq_dispatch(struct event_base *base, struct timeval *tv)
int i, n_changes, res; int i, n_changes, res;
if (tv != NULL) { if (tv != NULL) {
TIMEVAL_TO_TIMESPEC(tv, &ts); ts.tv_sec = tv->tv_sec;
ts.tv_nsec = tv->tv_usec * 1000;
ts_p = &ts; ts_p = &ts;
} }

View File

@ -421,6 +421,8 @@ listener_read_cb(evutil_socket_t fd, short what, void *p)
if (lev->refcnt == 1) { if (lev->refcnt == 1) {
int freed = listener_decref_and_unlock(lev); int freed = listener_decref_and_unlock(lev);
EVUTIL_ASSERT(freed); EVUTIL_ASSERT(freed);
evutil_closesocket(new_fd);
return; return;
} }
--lev->refcnt; --lev->refcnt;

View File

@ -12,9 +12,14 @@
#include <sys/types.h> #include <sys/types.h>
#ifdef EVENT__HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include <getopt.h>
#else #else
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
@ -141,34 +146,36 @@ logfn(int is_warn, const char *msg) {
int int
main(int c, char **v) { main(int c, char **v) {
int idx; struct options {
int reverse = 0, servertest = 0, use_getaddrinfo = 0; 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 event_base *event_base = NULL;
struct evdns_base *evdns_base = NULL; struct evdns_base *evdns_base = NULL;
const char *resolv_conf = NULL;
if (c<2) { memset(&o, 0, sizeof(o));
fprintf(stderr, "syntax: %s [-x] [-v] [-c resolv.conf] hostname\n", v[0]);
fprintf(stderr, "syntax: %s [-servertest]\n", v[0]); 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; return 1;
} }
idx = 1;
while (idx < c && v[idx][0] == '-') { while ((opt = getopt(c, v, "xvc:Ts:")) != -1) {
if (!strcmp(v[idx], "-x")) switch (opt) {
reverse = 1; case 'x': o.reverse = 1; break;
else if (!strcmp(v[idx], "-v")) case 'v': ++verbose; break;
verbose = 1; case 'g': o.use_getaddrinfo = 1; break;
else if (!strcmp(v[idx], "-g")) case 'T': o.servertest = 1; break;
use_getaddrinfo = 1; case 'c': o.resolv_conf = optarg; break;
else if (!strcmp(v[idx], "-servertest")) case 's': o.ns = optarg; break;
servertest = 1; default : fprintf(stderr, "Unknown option %c\n", opt); break;
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;
} }
#ifdef _WIN32 #ifdef _WIN32
@ -182,7 +189,7 @@ main(int c, char **v) {
evdns_base = evdns_base_new(event_base, EVDNS_BASE_DISABLE_WHEN_INACTIVE); evdns_base = evdns_base_new(event_base, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
evdns_set_log_fn(logfn); evdns_set_log_fn(logfn);
if (servertest) { if (o.servertest) {
evutil_socket_t sock; evutil_socket_t sock;
struct sockaddr_in my_addr; struct sockaddr_in my_addr;
sock = socket(PF_INET, SOCK_DGRAM, 0); 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); evdns_add_server_port_with_base(event_base, sock, 0, evdns_server_callback, NULL);
} }
if (idx < c) { if (optind < c) {
int res; int res;
#ifdef _WIN32 #ifdef _WIN32
if (resolv_conf == NULL) if (o.resolv_conf == NULL && !o.ns)
res = evdns_base_config_windows_nameservers(evdns_base); res = evdns_base_config_windows_nameservers(evdns_base);
else else
#endif #endif
if (o.ns)
res = evdns_base_nameserver_ip_add(evdns_base, o.ns);
else
res = evdns_base_resolv_conf_parse(evdns_base, res = evdns_base_resolv_conf_parse(evdns_base,
DNS_OPTION_NAMESERVERS, DNS_OPTION_NAMESERVERS, o.resolv_conf);
resolv_conf ? resolv_conf : "/etc/resolv.conf");
if (res < 0) { if (res < 0) {
fprintf(stderr, "Couldn't configure nameservers"); 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); printf("EVUTIL_AI_CANONNAME in example = %d\n", EVUTIL_AI_CANONNAME);
for (; idx < c; ++idx) { for (; optind < c; ++optind) {
if (reverse) { if (o.reverse) {
struct in_addr addr; struct in_addr addr;
if (evutil_inet_pton(AF_INET, v[idx], &addr)!=1) { if (evutil_inet_pton(AF_INET, v[optind], &addr)!=1) {
fprintf(stderr, "Skipping non-IP %s\n", v[idx]); fprintf(stderr, "Skipping non-IP %s\n", v[optind]);
continue; continue;
} }
fprintf(stderr, "resolving %s...\n",v[idx]); fprintf(stderr, "resolving %s...\n",v[optind]);
evdns_base_resolve_reverse(evdns_base, &addr, 0, main_callback, v[idx]); evdns_base_resolve_reverse(evdns_base, &addr, 0, main_callback, v[optind]);
} else if (use_getaddrinfo) { } else if (o.use_getaddrinfo) {
struct evutil_addrinfo hints; struct evutil_addrinfo hints;
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC; hints.ai_family = PF_UNSPEC;
hints.ai_protocol = IPPROTO_TCP; hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = EVUTIL_AI_CANONNAME; hints.ai_flags = EVUTIL_AI_CANONNAME;
fprintf(stderr, "resolving (fwd) %s...\n",v[idx]); fprintf(stderr, "resolving (fwd) %s...\n",v[optind]);
evdns_getaddrinfo(evdns_base, v[idx], NULL, &hints, evdns_getaddrinfo(evdns_base, v[optind], NULL, &hints,
gai_callback, v[idx]); gai_callback, v[optind]);
} else { } else {
fprintf(stderr, "resolving (fwd) %s...\n",v[idx]); fprintf(stderr, "resolving (fwd) %s...\n",v[optind]);
evdns_base_resolve_ipv4(evdns_base, v[idx], 0, main_callback, v[idx]); evdns_base_resolve_ipv4(evdns_base, v[optind], 0, main_callback, v[optind]);
} }
} }
fflush(stdout); 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) syntax(void)
{ {
fputs("Syntax:\n", stderr); 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("Example:\n", stderr);
fputs(" https-client -url https://ip.appspot.com/\n", stderr); fputs(" https-client -url https://ip.appspot.com/\n", stderr);
exit(1);
} }
static void static void
die(const char *msg) err(const char *msg)
{ {
fputs(msg, stderr); fputs(msg, stderr);
exit(1);
} }
static void static void
die_openssl(const char *func) err_openssl(const char *func)
{ {
fprintf (stderr, "%s failed:\n", func); fprintf (stderr, "%s failed:\n", func);
@ -190,22 +187,26 @@ main(int argc, char **argv)
{ {
int r; int r;
struct evhttp_uri *http_uri; struct evhttp_uri *http_uri = NULL;
const char *url = NULL, *data_file = NULL; const char *url = NULL, *data_file = NULL;
const char *crt = "/etc/ssl/certs/ca-certificates.crt";
const char *scheme, *host, *path, *query; const char *scheme, *host, *path, *query;
char uri[256]; char uri[256];
int port; int port;
int retries = 0; int retries = 0;
int timeout = -1;
SSL_CTX *ssl_ctx; SSL_CTX *ssl_ctx = NULL;
SSL *ssl; SSL *ssl = NULL;
struct bufferevent *bev; struct bufferevent *bev;
struct evhttp_connection *evcon; struct evhttp_connection *evcon = NULL;
struct evhttp_request *req; struct evhttp_request *req;
struct evkeyvalq *output_headers; struct evkeyvalq *output_headers;
struct evbuffer * output_buffer; struct evbuffer *output_buffer;
int i; int i;
int ret = 0;
enum { HTTP, HTTPS } type = HTTP;
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
if (!strcmp("-url", argv[i])) { if (!strcmp("-url", argv[i])) {
@ -213,6 +214,14 @@ main(int argc, char **argv)
url = argv[i + 1]; url = argv[i + 1];
} else { } else {
syntax(); 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])) { } else if (!strcmp("-ignore-cert", argv[i])) {
ignore_cert = 1; ignore_cert = 1;
@ -221,20 +230,31 @@ main(int argc, char **argv)
data_file = argv[i + 1]; data_file = argv[i + 1];
} else { } else {
syntax(); syntax();
goto error;
} }
} else if (!strcmp("-retries", argv[i])) { } else if (!strcmp("-retries", argv[i])) {
if (i < argc - 1) { if (i < argc - 1) {
retries = atoi(argv[i + 1]); retries = atoi(argv[i + 1]);
} else { } else {
syntax(); 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])) { } else if (!strcmp("-help", argv[i])) {
syntax(); syntax();
goto error;
} }
} }
if (!url) { if (!url) {
syntax(); syntax();
goto error;
} }
#ifdef _WIN32 #ifdef _WIN32
@ -248,25 +268,28 @@ main(int argc, char **argv)
err = WSAStartup(wVersionRequested, &wsaData); err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) { if (err != 0) {
printf("WSAStartup failed with error: %d\n", err); printf("WSAStartup failed with error: %d\n", err);
return 1; goto error;
} }
} }
#endif // _WIN32 #endif // _WIN32
http_uri = evhttp_uri_parse(url); http_uri = evhttp_uri_parse(url);
if (http_uri == NULL) { if (http_uri == NULL) {
die("malformed url"); err("malformed url");
goto error;
} }
scheme = evhttp_uri_get_scheme(http_uri); scheme = evhttp_uri_get_scheme(http_uri);
if (scheme == NULL || (strcasecmp(scheme, "https") != 0 && if (scheme == NULL || (strcasecmp(scheme, "https") != 0 &&
strcasecmp(scheme, "http") != 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); host = evhttp_uri_get_host(http_uri);
if (host == NULL) { if (host == NULL) {
die("url must have a host"); err("url must have a host");
goto error;
} }
port = evhttp_uri_get_port(http_uri); port = evhttp_uri_get_port(http_uri);
@ -275,7 +298,7 @@ main(int argc, char **argv)
} }
path = evhttp_uri_get_path(http_uri); path = evhttp_uri_get_path(http_uri);
if (path == NULL) { if (strlen(path) == 0) {
path = "/"; path = "/";
} }
@ -297,23 +320,26 @@ main(int argc, char **argv)
* automatically on first use of random number generator. */ * automatically on first use of random number generator. */
r = RAND_poll(); r = RAND_poll();
if (r == 0) { if (r == 0) {
die_openssl("RAND_poll"); err_openssl("RAND_poll");
goto error;
} }
/* Create a new OpenSSL context */ /* Create a new OpenSSL context */
ssl_ctx = SSL_CTX_new(SSLv23_method()); ssl_ctx = SSL_CTX_new(SSLv23_method());
if (!ssl_ctx) if (!ssl_ctx) {
die_openssl("SSL_CTX_new"); err_openssl("SSL_CTX_new");
goto error;
}
#ifndef _WIN32 #ifndef _WIN32
/* TODO: Add certificate loading on Windows as well */ /* TODO: Add certificate loading on Windows as well */
/* Attempt to use the system's trusted root certificates. /* Attempt to use the system's trusted root certificates.
* (This path is only valid for Debian-based systems.) */ * (This path is only valid for Debian-based systems.) */
if (1 != SSL_CTX_load_verify_locations(ssl_ctx, if (1 != SSL_CTX_load_verify_locations(ssl_ctx, crt, NULL)) {
"/etc/ssl/certs/ca-certificates.crt", err_openssl("SSL_CTX_load_verify_locations");
NULL)) goto error;
die_openssl("SSL_CTX_load_verify_locations"); }
/* Ask OpenSSL to verify the server certificate. Note that this /* Ask OpenSSL to verify the server certificate. Note that this
* does NOT include verifying that the hostname is correct. * does NOT include verifying that the hostname is correct.
* So, by itself, this means anyone with any legitimate * 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 * OpenSSL's built-in routine which would have been called if
* we hadn't set the callback. Therefore, we're just * we hadn't set the callback. Therefore, we're just
* "wrapping" OpenSSL's routine, not replacing it. */ * "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); (void *) host);
#endif // not _WIN32 #endif // not _WIN32
// Create event base // Create event base
base = event_base_new(); base = event_base_new();
if (!base) { if (!base) {
perror("event_base_new()"); perror("event_base_new()");
return 1; goto error;
} }
// Create OpenSSL bufferevent and stack evhttp on top of it // Create OpenSSL bufferevent and stack evhttp on top of it
ssl = SSL_new(ssl_ctx); ssl = SSL_new(ssl_ctx);
if (ssl == NULL) { if (ssl == NULL) {
die_openssl("SSL_new()"); err_openssl("SSL_new()");
goto error;
} }
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
@ -361,6 +388,7 @@ main(int argc, char **argv)
if (strcasecmp(scheme, "http") == 0) { if (strcasecmp(scheme, "http") == 0) {
bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE); bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
} else { } else {
type = HTTPS;
bev = bufferevent_openssl_socket_new(base, -1, ssl, bev = bufferevent_openssl_socket_new(base, -1, ssl,
BUFFEREVENT_SSL_CONNECTING, BUFFEREVENT_SSL_CONNECTING,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
@ -368,7 +396,7 @@ main(int argc, char **argv)
if (bev == NULL) { if (bev == NULL) {
fprintf(stderr, "bufferevent_openssl_socket_new() failed\n"); fprintf(stderr, "bufferevent_openssl_socket_new() failed\n");
return 1; goto error;
} }
bufferevent_openssl_set_allow_dirty_shutdown(bev, 1); bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
@ -379,18 +407,21 @@ main(int argc, char **argv)
host, port); host, port);
if (evcon == NULL) { if (evcon == NULL) {
fprintf(stderr, "evhttp_connection_base_bufferevent_new() failed\n"); fprintf(stderr, "evhttp_connection_base_bufferevent_new() failed\n");
return 1; goto error;
} }
if (retries > 0) { if (retries > 0) {
evhttp_connection_set_retries(evcon, retries); evhttp_connection_set_retries(evcon, retries);
} }
if (timeout >= 0) {
evhttp_connection_set_timeout(evcon, timeout);
}
// Fire off the request // Fire off the request
req = evhttp_request_new(http_request_done, bev); req = evhttp_request_new(http_request_done, bev);
if (req == NULL) { if (req == NULL) {
fprintf(stderr, "evhttp_request_new() failed\n"); fprintf(stderr, "evhttp_request_new() failed\n");
return 1; goto error;
} }
output_headers = evhttp_request_get_output_headers(req); output_headers = evhttp_request_get_output_headers(req);
@ -408,6 +439,7 @@ main(int argc, char **argv)
if (!f) { if (!f) {
syntax(); syntax();
goto error;
} }
output_buffer = evhttp_request_get_output_buffer(req); 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); r = evhttp_make_request(evcon, req, data_file ? EVHTTP_REQ_POST : EVHTTP_REQ_GET, uri);
if (r != 0) { if (r != 0) {
fprintf(stderr, "evhttp_make_request() failed\n"); fprintf(stderr, "evhttp_make_request() failed\n");
return 1; goto error;
} }
event_base_dispatch(base); 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); 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 #ifdef _WIN32
WSACleanup(); WSACleanup();
#endif #endif
return 0; return ret;
} }

View File

@ -9,6 +9,7 @@ SAMPLES = \
sample/event-read-fifo \ sample/event-read-fifo \
sample/hello-world \ sample/hello-world \
sample/http-server \ sample/http-server \
sample/http-connect \
sample/signal-test \ sample/signal-test \
sample/time-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_hello_world_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la
sample_http_server_SOURCES = sample/http-server.c sample_http_server_SOURCES = sample/http-server.c
sample_http_server_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la 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/x509v3.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <string.h>
#include "openssl_hostname_validation.h" #include "openssl_hostname_validation.h"
#include "hostcheck.h" #include "hostcheck.h"

View File

@ -74,7 +74,7 @@ static void
read_cb(evutil_socket_t fd, short which, void *arg) read_cb(evutil_socket_t fd, short which, void *arg)
{ {
ev_intptr_t idx = (ev_intptr_t) arg, widx = idx + 1; ev_intptr_t idx = (ev_intptr_t) arg, widx = idx + 1;
u_char ch; unsigned char ch;
ev_ssize_t n; ev_ssize_t n;
n = recv(fd, (char*)&ch, sizeof(ch), 0); n = recv(fd, (char*)&ch, sizeof(ch), 0);

View File

@ -151,7 +151,7 @@ launch_request(void)
} }
frob_socket(sock); frob_socket(sock);
if (connect(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0) { if (connect(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
int e = errno; int e = evutil_socket_geterror(sock);
if (! EVUTIL_ERR_CONNECT_RETRIABLE(e)) { if (! EVUTIL_ERR_CONNECT_RETRIABLE(e)) {
evutil_closesocket(sock); evutil_closesocket(sock);
return -1; return -1;
@ -183,6 +183,11 @@ main(int argc, char **argv)
double throughput; double throughput;
resource = "/ref"; resource = "/ref";
#ifdef _WIN32
WSADATA WSAData;
WSAStartup(0x101, &WSAData);
#endif
setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0);
base = event_base_new(); base = event_base_new();
@ -226,5 +231,9 @@ main(int argc, char **argv)
(double)(usec/1000) / total_n_handled, (double)(usec/1000) / total_n_handled,
(I64_TYP)total_n_bytes, n_errors); (I64_TYP)total_n_bytes, n_errors);
#ifdef _WIN32
WSACleanup();
#endif
return 0; return 0;
} }

View File

@ -2290,7 +2290,7 @@ end:
static void static void
evtag_fuzz(void *ptr) evtag_fuzz(void *ptr)
{ {
u_char buffer[4096]; unsigned char buffer[4096];
struct evbuffer *tmp = evbuffer_new(); struct evbuffer *tmp = evbuffer_new();
struct timeval tv; struct timeval tv;
int i, j; 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); pid_t regress_fork(void);
#endif #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 #ifdef __cplusplus
} }
#endif #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_two) == 0);
tt_assert(evbuffer_get_length(evb) == 7); 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)); memset(buffer, 0, sizeof(buffer));
evbuffer_add(evb, buffer, sizeof(buffer)); evbuffer_add(evb, buffer, sizeof(buffer));
@ -1292,7 +1292,7 @@ test_evbuffer_iterative(void *ptr)
static void static void
test_evbuffer_find(void *ptr) test_evbuffer_find(void *ptr)
{ {
u_char* p; unsigned char* p;
const char* test1 = "1234567890\r\n"; const char* test1 = "1234567890\r\n";
const char* test2 = "1234567890\r"; const char* test2 = "1234567890\r";
#define EVBUFFER_INITIAL_LENGTH 256 #define EVBUFFER_INITIAL_LENGTH 256
@ -1303,13 +1303,13 @@ test_evbuffer_find(void *ptr)
tt_assert(buf); tt_assert(buf);
/* make sure evbuffer_find doesn't match past the end of the buffer */ /* 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_validate(buf);
evbuffer_drain(buf, strlen(test1)); evbuffer_drain(buf, strlen(test1));
evbuffer_validate(buf); evbuffer_validate(buf);
evbuffer_add(buf, (u_char*)test2, strlen(test2)); evbuffer_add(buf, (unsigned char*)test2, strlen(test2));
evbuffer_validate(buf); 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); tt_want(p == NULL);
/* /*
@ -1321,13 +1321,13 @@ test_evbuffer_find(void *ptr)
for (i = 0; i < EVBUFFER_INITIAL_LENGTH; ++i) for (i = 0; i < EVBUFFER_INITIAL_LENGTH; ++i)
test3[i] = 'a'; test3[i] = 'a';
test3[EVBUFFER_INITIAL_LENGTH - 1] = 'x'; 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); evbuffer_validate(buf);
p = evbuffer_find(buf, (u_char *)"xy", 2); p = evbuffer_find(buf, (unsigned char *)"xy", 2);
tt_want(p == NULL); tt_want(p == NULL);
/* simple test for match at end of allocated buffer */ /* 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_assert(p != NULL);
tt_want(strncmp((char*)p, "ax", 2) == 0); tt_want(strncmp((char*)p, "ax", 2) == 0);

View File

@ -123,11 +123,12 @@ errorcb(struct bufferevent *bev, short what, void *arg)
} }
static void static void
test_bufferevent_impl(int use_pair) test_bufferevent_impl(int use_pair, int flush)
{ {
struct bufferevent *bev1 = NULL, *bev2 = NULL; struct bufferevent *bev1 = NULL, *bev2 = NULL;
char buffer[8333]; char buffer[8333];
int i; int i;
int expected = 2;
if (use_pair) { if (use_pair) {
struct bufferevent *pair[2]; struct bufferevent *pair[2];
@ -171,6 +172,9 @@ test_bufferevent_impl(int use_pair)
buffer[i] = i; buffer[i] = i;
bufferevent_write(bev1, buffer, sizeof(buffer)); bufferevent_write(bev1, buffer, sizeof(buffer));
if (flush >= 0) {
tt_int_op(bufferevent_flush(bev1, EV_WRITE, flush), >=, 0);
}
event_dispatch(); event_dispatch();
@ -178,23 +182,26 @@ test_bufferevent_impl(int use_pair)
tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL); tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL);
bufferevent_free(bev1); 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; test_ok = 0;
end: end:
; ;
} }
static void static void test_bufferevent(void) { test_bufferevent_impl(0, -1); }
test_bufferevent(void) static void test_bufferevent_pair(void) { test_bufferevent_impl(1, -1); }
{
test_bufferevent_impl(0);
}
static void static void test_bufferevent_flush_normal(void) { test_bufferevent_impl(0, BEV_NORMAL); }
test_bufferevent_pair(void) 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); }
test_bufferevent_impl(1);
} static void test_bufferevent_pair_flush_normal(void) { test_bufferevent_impl(1, BEV_NORMAL); }
static void test_bufferevent_pair_flush_flush(void) { test_bufferevent_impl(1, BEV_FLUSH); }
static void test_bufferevent_pair_flush_finished(void) { test_bufferevent_impl(1, BEV_FINISHED); }
#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED) #if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
/** /**
@ -245,7 +252,6 @@ static void trace_lock_free(void *lock_, unsigned locktype)
{ {
lock_wrapper *lock = lu_find(lock_); lock_wrapper *lock = lu_find(lock_);
if (!lock || lock->status == FREE || lock->locked) { if (!lock || lock->status == FREE || lock->locked) {
__asm__("int3");
TT_FAIL(("lock: free error")); TT_FAIL(("lock: free error"));
} else { } else {
lock->status = FREE; lock->status = FREE;
@ -278,6 +284,9 @@ static void lock_unlock_free_thread_cbs(void)
{ {
event_base_free(NULL); event_base_free(NULL);
if (libevent_tests_running_in_debug_mode)
libevent_global_shutdown();
/** drop immutable flag */ /** drop immutable flag */
evthread_set_lock_callbacks(NULL); evthread_set_lock_callbacks(NULL);
/** avoid calling of event_global_setup_locks_() for new cbs */ /** 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) 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(); lock_unlock_free_thread_cbs();
free(lu_base.locks); free(lu_base.locks);
data->base = NULL; data->base = NULL;
@ -594,6 +606,7 @@ static int bufferevent_connect_test_flags = 0;
static int bufferevent_trigger_test_flags = 0; static int bufferevent_trigger_test_flags = 0;
static int n_strings_read = 0; static int n_strings_read = 0;
static int n_reads_invoked = 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 " \ #define TEST_STR "Now is the time for all good events to signal for " \
"the good of their protocol" "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 static void
reader_eventcb(struct bufferevent *bev, short what, void *ctx) 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 static void
reader_readcb(struct bufferevent *bev, void *ctx) reader_readcb(struct bufferevent *bev, void *ctx)
{ {
@ -727,6 +773,45 @@ end:
bufferevent_free(bev2); 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 static void
want_fail_eventcb(struct bufferevent *bev, short what, void *ctx) 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 basic_test_data *data = (struct basic_test_data *)arg;
struct bufferevent *bev=NULL; 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; struct event close_listener_event;
int close_listener_event_added = 0; int close_listener_event_added = 0;
struct timeval one_second = { 1, 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; int r;
test_ok = 0; test_ok = 0;
memset(&localhost, 0, sizeof(localhost)); fake_listener = fake_listener_create(&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);
bev = bufferevent_socket_new(data->base, -1, bev = bufferevent_socket_new(data->base, -1,
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS); BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
tt_assert(bev); tt_assert(bev);
bufferevent_setcb(bev, NULL, NULL, want_fail_eventcb, data->base); 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 /* XXXX we'd like to test the '0' case everywhere, but FreeBSD tells
* detects the error immediately, which is not really wrong of it. */ * detects the error immediately, which is not really wrong of it. */
tt_want(r == 0 || r == -1); tt_want(r == 0 || r == -1);
@ -1084,10 +1158,35 @@ end:
bufferevent_free(bev); 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[] = { struct testcase_t bufferevent_testcases[] = {
LEGACY(bufferevent, TT_ISOLATED), LEGACY(bufferevent, TT_ISOLATED),
LEGACY(bufferevent_pair, 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) #if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
{ "bufferevent_pair_release_lock", test_bufferevent_pair_release_lock, { "bufferevent_pair_release_lock", test_bufferevent_pair_release_lock,
TT_FORK|TT_ISOLATED|TT_NEED_THREADS|TT_NEED_BASE|TT_LEGACY, TT_FORK|TT_ISOLATED|TT_NEED_THREADS|TT_NEED_BASE|TT_LEGACY,
@ -1135,12 +1234,26 @@ struct testcase_t bufferevent_testcases[] = {
{ "bufferevent_zlib", NULL, TT_SKIP, NULL, NULL }, { "bufferevent_zlib", NULL, TT_SKIP, NULL, NULL },
#endif #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, END_OF_TESTCASES,
}; };
struct testcase_t bufferevent_iocp_testcases[] = { struct testcase_t bufferevent_iocp_testcases[] = {
LEGACY(bufferevent, TT_ISOLATED|TT_ENABLE_IOCP), 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_watermarks, TT_ISOLATED|TT_ENABLE_IOCP),
LEGACY(bufferevent_filters, TT_ISOLATED|TT_ENABLE_IOCP), LEGACY(bufferevent_filters, TT_ISOLATED|TT_ENABLE_IOCP),
{ "bufferevent_connect", test_bufferevent_connect, { "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, TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup,
(void*)"unset_connectex" }, (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, END_OF_TESTCASES,
}; };

View File

@ -72,6 +72,8 @@
#include "regress.h" #include "regress.h"
#include "regress_testutils.h" #include "regress_testutils.h"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
static int dns_ok = 0; static int dns_ok = 0;
static int dns_got_cancel = 0; static int dns_got_cancel = 0;
static int dns_err = 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[] = { static struct regress_dns_server_table search_table[] = {
{ "host.a.example.com", "err", "3", 0 }, { "host.a.example.com", "err", "3", 0, 0 },
{ "host.b.example.com", "err", "3", 0 }, { "host.b.example.com", "err", "3", 0, 0 },
{ "host.c.example.com", "A", "11.22.33.44", 0 }, { "host.c.example.com", "A", "11.22.33.44", 0, 0 },
{ "host2.a.example.com", "err", "3", 0 }, { "host2.a.example.com", "err", "3", 0, 0 },
{ "host2.b.example.com", "A", "200.100.0.100", 0 }, { "host2.b.example.com", "A", "200.100.0.100", 0, 0 },
{ "host2.c.example.com", "err", "3", 0 }, { "host2.c.example.com", "err", "3", 0, 0 },
{ "hostn.a.example.com", "errsoa", "0", 0 }, { "hostn.a.example.com", "errsoa", "0", 0, 0 },
{ "hostn.b.example.com", "errsoa", "3", 0 }, { "hostn.b.example.com", "errsoa", "3", 0, 0 },
{ "hostn.c.example.com", "err", "0", 0 }, { "hostn.c.example.com", "err", "0", 0, 0 },
{ "host", "err", "3", 0 }, { "host", "err", "3", 0, 0 },
{ "host2", "err", "3", 0 }, { "host2", "err", "3", 0, 0 },
{ "*", "err", "3", 0 }, { "*", "err", "3", 0, 0 },
{ NULL, NULL, NULL, 0 } { NULL, NULL, NULL, 0, 0 }
}; };
static void 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 basic_test_data *data = arg;
struct event_base *base = data->base; struct event_base *base = data->base;
struct evdns_base *dns = NULL; struct evdns_base *dns = NULL;
@ -537,8 +539,14 @@ dns_search_test(void *arg)
char buf[64]; char buf[64];
struct generic_dns_callback_result r[8]; 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); evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
dns = evdns_base_new(base, 0); 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, "b.example.com");
evdns_base_search_add(dns, "c.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; exit_base = base;
evdns_base_resolve_ipv4(dns, "host", 0, generic_dns_callback, &r[0]); evdns_base_resolve_ipv4(dns, "host", 0, generic_dns_callback, &r[0]);
@ -584,6 +592,16 @@ end:
regress_clean_dnsserver(); 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 int request_count = 0;
static struct evdns_request *current_req = NULL; 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! XXXX we should reissue under a much wider set of circumstances!
*/ */
{ "foof.example.com", "err", "4", 0 }, { "foof.example.com", "err", "4", 0, 0 },
{ NULL, NULL, NULL, 0 } { NULL, NULL, NULL, 0, 0 }
}; };
static struct regress_dns_server_table reissue_table[] = { static struct regress_dns_server_table reissue_table[] = {
{ "foof.example.com", "A", "240.15.240.15", 0 }, { "foof.example.com", "A", "240.15.240.15", 0, 0 },
{ NULL, NULL, NULL, 0 } { NULL, NULL, NULL, 0, 0 }
}; };
static void static void
@ -1672,7 +1690,6 @@ test_getaddrinfo_async(void *arg)
end: end:
if (local_outcome.ai) if (local_outcome.ai)
evutil_freeaddrinfo(local_outcome.ai); evutil_freeaddrinfo(local_outcome.ai);
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
for (i=0;i<(int)ARRAY_SIZE(a_out);++i) { for (i=0;i<(int)ARRAY_SIZE(a_out);++i) {
if (a_out[i].ai) if (a_out[i].ai)
evutil_freeaddrinfo(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)); tt_assert(!evdns_base_resume(env->dns_base));
} }
event_base_loop(env->base, EVLOOP_NONBLOCK);
/** /**
* Because we don't cancel request, * Because we don't cancel request, and want our callback to recieve
* and want our callback to recieve DNS_ERR_SHUTDOWN, * DNS_ERR_SHUTDOWN, we use deferred callback, and there was:
* we use deferred callback, and there was
* - one extra malloc(), * - one extra malloc(),
* @see reply_schedule_callback() * @see reply_schedule_callback()
* - and one missing free * - and one missing free
* @see request_finished() (req->handle->pending_cb = 1) * @see request_finished() (req->handle->pending_cb = 1)
* than we don't need to count in testleak_cleanup() * 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.
* So just decrement allocated_chunks to 2,
* like we already take care about it.
*/ */
if (!cancel && send_err_shutdown) { evdns_base_free(env->dns_base, send_err_shutdown);
allocated_chunks -= 2; env->dns_base = 0;
}
event_base_loop(env->base, EVLOOP_NONBLOCK); event_base_loop(env->base, EVLOOP_NONBLOCK);
end: end:
evdns_base_free(env->dns_base, send_err_shutdown);
env->dns_base = 0;
event_base_free(env->base); event_base_free(env->base);
env->base = 0; env->base = 0;
} }
@ -1998,6 +2008,91 @@ end:
evutil_closesocket(fd); 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) \ #define DNS_LEGACY(name, flags) \
{ #name, run_legacy_test_fn, flags|TT_LEGACY, &legacy_setup, \ { #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), 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 }, { "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", 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, { "search_cancel", dns_search_cancel_test,
TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
{ "retry", dns_retry_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &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 }, TT_FORK, &testleak_funcs, NULL },
#endif #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 END_OF_TESTCASES
}; };

View File

@ -58,7 +58,9 @@
#include "event2/http.h" #include "event2/http.h"
#include "event2/buffer.h" #include "event2/buffer.h"
#include "event2/bufferevent.h" #include "event2/bufferevent.h"
#include "event2/bufferevent_ssl.h"
#include "event2/util.h" #include "event2/util.h"
#include "event2/listener.h"
#include "log-internal.h" #include "log-internal.h"
#include "http-internal.h" #include "http-internal.h"
#include "regress.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) IMPL_HTTP_REQUEST_ERROR_CB(cancel, EVREQ_HTTP_REQUEST_CANCEL)
static void http_basic_cb(struct evhttp_request *req, void *arg); 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_chunked_cb(struct evhttp_request *req, void *arg);
static void http_post_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); 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_dispatcher_cb(struct evhttp_request *req, void *arg);
static void http_on_complete_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 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; int port;
struct evhttp_bound_socket *sock; struct evhttp_bound_socket *sock;
int ipv6 = mask & HTTP_BIND_IPV6;
if (ipv6) if (ipv6)
sock = evhttp_bind_socket_with_handle(myhttp, "::1", *pport); 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; 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 * 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; struct evhttp *myhttp;
/* Try a few different ports */ /* Try a few different ports */
myhttp = evhttp_new(base); myhttp = evhttp_new(base);
if (http_bind(myhttp, pport, ipv6) < 0) if (http_bind(myhttp, pport, mask) < 0)
return NULL; 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 */ /* Register a callback for certain types of requests */
evhttp_set_cb(myhttp, "/test", http_basic_cb, base); evhttp_set_cb(myhttp, "/test", http_basic_cb, base);
evhttp_set_cb(myhttp, "/large", http_large_cb, base);
evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, base); evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, base);
evhttp_set_cb(myhttp, "/streamed", http_chunked_cb, base); evhttp_set_cb(myhttp, "/streamed", http_chunked_cb, base);
evhttp_set_cb(myhttp, "/postit", http_post_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 #endif
static evutil_socket_t static evutil_socket_t
http_connect(const char *address, u_short port) http_connect(const char *address, unsigned short port)
{ {
/* Stupid code for connecting */ /* Stupid code for connecting */
struct evutil_addrinfo ai, *aitop; struct evutil_addrinfo ai, *aitop;
@ -276,6 +303,9 @@ http_writecb(struct bufferevent *bev, void *arg)
static void static void
http_errorcb(struct bufferevent *bev, short what, void *arg) http_errorcb(struct bufferevent *bev, short what, void *arg)
{ {
/** For ssl */
if (what & BEV_EVENT_CONNECTED)
return;
test_ok = -2; test_ok = -2;
event_base_loopexit(arg, NULL); event_base_loopexit(arg, NULL);
} }
@ -329,6 +359,19 @@ end:
evbuffer_free(evb); 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[] = { static char const* const CHUNKS[] = {
"This is funny", "This is funny",
"but not hilarious.", "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)); 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 static void
http_basic_test(void *arg) http_basic_test_impl(void *arg, int ssl)
{ {
struct basic_test_data *data = arg; struct basic_test_data *data = arg;
struct timeval tv; struct timeval tv;
@ -403,13 +466,14 @@ http_basic_test(void *arg)
evutil_socket_t fd; evutil_socket_t fd;
const char *http_request; const char *http_request;
ev_uint16_t port = 0, port2 = 0; ev_uint16_t port = 0, port2 = 0;
int server_flags = ssl ? HTTP_BIND_SSL : 0;
test_ok = 0; test_ok = 0;
http = http_setup(&port, data->base, 0); http = http_setup(&port, data->base, server_flags);
/* bind to a second socket */ /* 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"); fprintf(stdout, "FAILED (bind)\n");
exit(1); exit(1);
} }
@ -417,7 +481,7 @@ http_basic_test(void *arg)
fd = http_connect("127.0.0.1", port); fd = http_connect("127.0.0.1", port);
/* Stupid thing to send a request */ /* 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, bufferevent_setcb(bev, http_readcb, http_writecb,
http_errorcb, data->base); http_errorcb, data->base);
@ -443,7 +507,7 @@ http_basic_test(void *arg)
fd = http_connect("127.0.0.1", port2); fd = http_connect("127.0.0.1", port2);
/* Stupid thing to send a request */ /* 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, bufferevent_setcb(bev, http_readcb, http_writecb,
http_errorcb, data->base); http_errorcb, data->base);
@ -466,7 +530,7 @@ http_basic_test(void *arg)
fd = http_connect("127.0.0.1", port2); fd = http_connect("127.0.0.1", port2);
/* Stupid thing to send a request */ /* 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, bufferevent_setcb(bev, http_readcb, http_writecb,
http_errorcb, data->base); http_errorcb, data->base);
@ -487,6 +551,8 @@ http_basic_test(void *arg)
if (bev) if (bev)
bufferevent_free(bev); bufferevent_free(bev);
} }
static void http_basic_test(void *arg)
{ return http_basic_test_impl(arg, 0); }
static void static void
@ -956,6 +1022,7 @@ http_allowed_methods_test(void *arg)
evutil_closesocket(fd3); 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_done(struct evhttp_request *, void *);
static void http_request_empty_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[] = { static struct regress_dns_server_table search_table[] = {
{ "localhost", "A", "127.0.0.1", 0 }, { "localhost", "A", "127.0.0.1", 0, 0 },
{ NULL, NULL, NULL, 0 } { NULL, NULL, NULL, 0, 0 }
}; };
static void static void
@ -1319,6 +1386,13 @@ http_cancel_test(void *arg)
evhttp_free(http); 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 static void
http_request_done(struct evhttp_request *req, void *arg) 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; struct event_base *base = arg;
const char *what = "DISPATCHER_TEST"; const char *what = "DISPATCHER_TEST";
if (!req) {
fprintf(stderr, "FAILED\n");
exit(1);
}
if (evhttp_request_get_response_code(req) != HTTP_OK) { if (evhttp_request_get_response_code(req) != HTTP_OK) {
fprintf(stderr, "FAILED\n"); fprintf(stderr, "FAILED\n");
exit(1); exit(1);
@ -2750,6 +2829,10 @@ http_incomplete_readcb(struct bufferevent *bev, void *arg)
static void static void
http_incomplete_errorcb(struct bufferevent *bev, short what, void *arg) 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)) if (what == (BEV_EVENT_READING|BEV_EVENT_EOF))
test_ok++; test_ok++;
else else
@ -2773,7 +2856,7 @@ http_incomplete_writecb(struct bufferevent *bev, void *arg)
} }
static void 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; struct bufferevent *bev;
evutil_socket_t fd; evutil_socket_t fd;
@ -2785,14 +2868,14 @@ http_incomplete_test_(struct basic_test_data *data, int use_timeout)
test_ok = 0; 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); evhttp_set_timeout(http, 1);
fd = http_connect("127.0.0.1", port); fd = http_connect("127.0.0.1", port);
tt_int_op(fd, >=, 0); tt_int_op(fd, >=, 0);
/* Stupid thing to send a request */ /* Stupid thing to send a request */
bev = bufferevent_socket_new(data->base, fd, 0); bev = create_bev(data->base, fd, ssl);
bufferevent_setcb(bev, bufferevent_setcb(bev,
http_incomplete_readcb, http_incomplete_writecb, http_incomplete_readcb, http_incomplete_writecb,
http_incomplete_errorcb, use_timeout ? NULL : &fd); 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) if (fd >= 0)
evutil_closesocket(fd); evutil_closesocket(fd);
} }
static void static void http_incomplete_test(void *arg)
http_incomplete_test(void *arg) { http_incomplete_test_(arg, 0, 0); }
{ static void http_incomplete_timeout_test(void *arg)
http_incomplete_test_(arg, 0); { http_incomplete_test_(arg, 1, 0); }
}
static void
http_incomplete_timeout_test(void *arg)
{
http_incomplete_test_(arg, 1);
}
/* /*
* the server is going to reply with chunked data. * 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; struct evhttp_request *req = NULL;
/** SSL */
if (what & BEV_EVENT_CONNECTED)
return;
if (!test_ok) if (!test_ok)
goto out; goto out;
@ -2990,7 +3072,7 @@ http_chunked_request_done(struct evhttp_request *req, void *arg)
} }
static void static void
http_chunk_out_test(void *arg) http_chunk_out_test_impl(void *arg, int ssl)
{ {
struct basic_test_data *data = arg; struct basic_test_data *data = arg;
struct bufferevent *bev; struct bufferevent *bev;
@ -3005,12 +3087,12 @@ http_chunk_out_test(void *arg)
exit_base = data->base; exit_base = data->base;
test_ok = 0; 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); fd = http_connect("127.0.0.1", port);
/* Stupid thing to send a request */ /* Stupid thing to send a request */
bev = bufferevent_socket_new(data->base, fd, 0); bev = create_bev(data->base, fd, ssl);
bufferevent_setcb(bev, bufferevent_setcb(bev,
http_chunked_readcb, http_chunked_writecb, http_chunked_readcb, http_chunked_writecb,
http_chunked_errorcb, data->base); http_chunked_errorcb, data->base);
@ -3037,7 +3119,9 @@ http_chunk_out_test(void *arg)
tt_int_op(test_ok, ==, 2); tt_int_op(test_ok, ==, 2);
/* now try again with the regular connection object */ /* 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); tt_assert(evcon);
/* make two requests to check the keepalive behavior */ /* make two requests to check the keepalive behavior */
@ -3065,21 +3149,26 @@ http_chunk_out_test(void *arg)
if (http) if (http)
evhttp_free(http); evhttp_free(http);
} }
static void http_chunk_out_test(void *arg)
{ return http_chunk_out_test_impl(arg, 0); }
static void static void
http_stream_out_test(void *arg) http_stream_out_test_impl(void *arg, int ssl)
{ {
struct basic_test_data *data = arg; struct basic_test_data *data = arg;
ev_uint16_t port = 0; ev_uint16_t port = 0;
struct evhttp_connection *evcon = NULL; struct evhttp_connection *evcon = NULL;
struct evhttp_request *req = NULL; struct evhttp_request *req = NULL;
struct bufferevent *bev;
test_ok = 0; test_ok = 0;
exit_base = data->base; 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); tt_assert(evcon);
/* /*
@ -3107,6 +3196,8 @@ http_stream_out_test(void *arg)
if (http) if (http)
evhttp_free(http); evhttp_free(http);
} }
static void http_stream_out_test(void *arg)
{ return http_stream_out_test_impl(arg, 0); }
static void static void
http_stream_in_chunk(struct evhttp_request *req, void *arg) http_stream_in_chunk(struct evhttp_request *req, void *arg)
@ -3241,65 +3332,70 @@ http_stream_in_cancel_test(void *arg)
static void static void
http_connection_fail_done(struct evhttp_request *req, void *arg) http_connection_fail_done(struct evhttp_request *req, void *arg)
{ {
struct evhttp_connection *evcon = arg; struct evhttp_connection *evcon = arg;
struct event_base *base = evhttp_connection_get_base(evcon); struct event_base *base = evhttp_connection_get_base(evcon);
/* An ENETUNREACH error results in an unrecoverable /* An ENETUNREACH error results in an unrecoverable
* evhttp_connection error (see evhttp_connection_fail_()). The * evhttp_connection error (see evhttp_connection_fail_()). The
* connection will be reset, and the user will be notified with a NULL * connection will be reset, and the user will be notified with a NULL
* req parameter. */ * req parameter. */
tt_assert(!req); tt_assert(!req);
evhttp_connection_free(evcon); evhttp_connection_free(evcon);
test_ok = 1; test_ok = 1;
end: end:
event_base_loopexit(base, NULL); event_base_loopexit(base, NULL);
} }
/* Test unrecoverable evhttp_connection errors by generating an ENETUNREACH /* Test unrecoverable evhttp_connection errors by generating an ENETUNREACH
* error on connection. */ * error on connection. */
static void static void
http_connection_fail_test(void *arg) http_connection_fail_test_impl(void *arg, int ssl)
{ {
struct basic_test_data *data = arg; struct basic_test_data *data = arg;
ev_uint16_t port = 0; ev_uint16_t port = 0;
struct evhttp_connection *evcon = NULL; struct evhttp_connection *evcon = NULL;
struct evhttp_request *req = NULL; struct evhttp_request *req = NULL;
struct bufferevent *bev;
exit_base = data->base; exit_base = data->base;
test_ok = 0; test_ok = 0;
/* auto detect a port */ /* auto detect a port */
http = http_setup(&port, data->base, 0); http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
evhttp_free(http); evhttp_free(http);
http = NULL; http = NULL;
/* Pick an unroutable address. This administratively scoped multicast bev = create_bev(data->base, -1, ssl);
* address should do when working with TCP. */ /* Pick an unroutable address. This administratively scoped multicast
evcon = evhttp_connection_base_new(data->base, NULL, "239.10.20.30", 80); * address should do when working with TCP. */
tt_assert(evcon); 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 * At this point, we want to schedule an HTTP GET request
* server using our make request method. * server using our make request method.
*/ */
req = evhttp_request_new(http_connection_fail_done, evcon); req = evhttp_request_new(http_connection_fail_done, evcon);
tt_assert(req); tt_assert(req);
if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/") == -1) { if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/") == -1) {
tt_abort_msg("Couldn't make request"); 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: end:
; ;
} }
static void http_connection_fail_test(void *arg)
{ return http_connection_fail_test_impl(arg, 0); }
static void static void
http_connection_retry_done(struct evhttp_request *req, void *arg) 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); 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 struct event_base *http_make_web_server_base=NULL;
static void static void
http_make_web_server(evutil_socket_t fd, short what, void *arg) http_make_web_server(evutil_socket_t fd, short what, void *arg)
{ {
ev_uint16_t port = *(ev_uint16_t*)arg; struct http_server *hs = (struct http_server *)arg;
http = http_setup(&port, http_make_web_server_base, 0); http = http_setup(&hs->port, http_make_web_server_base, hs->ssl ? HTTP_BIND_SSL : 0);
} }
static void 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; struct basic_test_data *data = arg;
ev_uint16_t port = 0;
struct evhttp_connection *evcon = NULL; struct evhttp_connection *evcon = NULL;
struct evhttp_request *req = NULL; struct evhttp_request *req = NULL;
struct timeval tv, tv_start, tv_end; struct timeval tv, tv_start, tv_end;
struct bufferevent *bev;
struct http_server hs = { .port = 0, .ssl = ssl, };
exit_base = data->base; exit_base = data->base;
test_ok = 0; test_ok = 0;
/* auto detect a port */ /* 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); evhttp_free(http);
http = NULL; 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); tt_assert(evcon);
if (dns_base)
tt_assert(!evhttp_connection_set_flags(evcon, EVHTTP_CON_REUSE_CONNECTED_ADDR));
evhttp_connection_set_timeout(evcon, 1); evhttp_connection_set_timeout(evcon, 1);
/* also bind to local host */ /* also bind to local host */
@ -3377,6 +3521,9 @@ http_connection_retry_test(void *arg)
* now test the same but with retries * now test the same but with retries
*/ */
test_ok = 0; test_ok = 0;
/** Shutdown dns server, to test conn_address reusing */
if (dns_base)
regress_clean_dnsserver();
{ {
const struct timeval tv_timeout = { 0, 500000 }; const struct timeval tv_timeout = { 0, 500000 };
@ -3432,7 +3579,7 @@ http_connection_retry_test(void *arg)
evutil_timerclear(&tv); evutil_timerclear(&tv);
tv.tv_usec = 200000; tv.tv_usec = 200000;
http_make_web_server_base = data->base; 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); evutil_gettimeofday(&tv_start, NULL);
event_base_dispatch(data->base); event_base_dispatch(data->base);
@ -3449,6 +3596,42 @@ http_connection_retry_test(void *arg)
evhttp_free(http); 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 static void
http_primitives(void *ptr) http_primitives(void *ptr)
{ {
@ -3688,6 +3871,7 @@ struct terminate_state {
struct bufferevent *bev; struct bufferevent *bev;
evutil_socket_t fd; evutil_socket_t fd;
int gotclosecb: 1; int gotclosecb: 1;
int oneshot: 1;
}; };
static void static void
@ -3695,7 +3879,10 @@ terminate_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
{ {
struct terminate_state *state = arg; struct terminate_state *state = arg;
struct evbuffer *evb; struct evbuffer *evb;
struct timeval tv;
if (!state->req) {
return;
}
if (evhttp_request_get_connection(state->req) == NULL) { if (evhttp_request_get_connection(state->req) == NULL) {
test_ok = 1; 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); evhttp_send_reply_chunk(state->req, evb);
evbuffer_free(evb); evbuffer_free(evb);
tv.tv_sec = 0; if (!state->oneshot) {
tv.tv_usec = 3000; struct timeval tv;
EVUTIL_ASSERT(state); tv.tv_sec = 0;
EVUTIL_ASSERT(state->base); tv.tv_usec = 3000;
event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv); EVUTIL_ASSERT(state);
EVUTIL_ASSERT(state->base);
event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
}
} }
static void static void
@ -3721,6 +3911,13 @@ terminate_chunked_close_cb(struct evhttp_connection *evcon, void *arg)
{ {
struct terminate_state *state = arg; struct terminate_state *state = arg;
state->gotclosecb = 1; 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 static void
@ -3760,7 +3957,7 @@ terminate_readcb(struct bufferevent *bev, void *arg)
static void static void
http_terminate_chunked_test(void *arg) http_terminate_chunked_test_impl(void *arg, int oneshot)
{ {
struct basic_test_data *data = arg; struct basic_test_data *data = arg;
struct bufferevent *bev = NULL; struct bufferevent *bev = NULL;
@ -3789,6 +3986,7 @@ http_terminate_chunked_test(void *arg)
terminate_state.fd = fd; terminate_state.fd = fd;
terminate_state.bev = bev; terminate_state.bev = bev;
terminate_state.gotclosecb = 0; terminate_state.gotclosecb = 0;
terminate_state.oneshot = oneshot;
/* first half of the http request */ /* first half of the http request */
http_request = http_request =
@ -3812,10 +4010,20 @@ http_terminate_chunked_test(void *arg)
if (http) if (http)
evhttp_free(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[] = { static struct regress_dns_server_table ipv6_search_table[] = {
{ "localhost", "AAAA", "::1", 0 }, { "localhost", "AAAA", "::1", 0, 0 },
{ NULL, NULL, NULL, 0 } { NULL, NULL, NULL, 0, 0 }
}; };
static void static void
@ -3929,12 +4137,126 @@ http_set_family_ipv6_test(void *arg)
http_ipv6_for_domain_test_impl(arg, AF_INET6); 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) \ #define HTTP_LEGACY(name) \
{ #name, run_legacy_test_fn, TT_ISOLATED|TT_LEGACY, &legacy_setup, \ { #name, run_legacy_test_fn, TT_ISOLATED|TT_LEGACY, &legacy_setup, \
http_##name##_test } http_##name##_test }
#define HTTP(name) \ #define HTTP(name) \
{ #name, http_##name##_test, TT_ISOLATED, &basic_setup, NULL } { #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[] = { struct testcase_t http_testcases[] = {
{ "primitives", http_primitives, 0, NULL, NULL }, { "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" }, { "parse_uri_nc", http_parse_uri_test, 0, &basic_setup, (void*)"nc" },
{ "uriencode", http_uriencode_test, 0, NULL, NULL }, { "uriencode", http_uriencode_test, 0, NULL, NULL },
HTTP(basic), HTTP(basic),
HTTP(simple),
HTTP(cancel), HTTP(cancel),
HTTP(virtual_host), HTTP(virtual_host),
HTTP(post), HTTP(post),
@ -3962,6 +4285,7 @@ struct testcase_t http_testcases[] = {
HTTP(incomplete), HTTP(incomplete),
HTTP(incomplete_timeout), HTTP(incomplete_timeout),
HTTP(terminate_chunked), HTTP(terminate_chunked),
HTTP(terminate_chunked_oneshot),
HTTP(on_complete), HTTP(on_complete),
HTTP(highport), HTTP(highport),
@ -3976,6 +4300,8 @@ struct testcase_t http_testcases[] = {
HTTP(connection_fail), HTTP(connection_fail),
{ "connection_retry", http_connection_retry_test, TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL }, { "connection_retry", http_connection_retry_test, TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
{ "connection_retry_conn_address", http_connection_retry_conn_address_test,
TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
HTTP(data_length_constraints), HTTP(data_length_constraints),
@ -3986,6 +4312,24 @@ struct testcase_t http_testcases[] = {
HTTP(set_family_ipv4), HTTP(set_family_ipv4),
HTTP(set_family_ipv6), 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 END_OF_TESTCASES
}; };

View File

@ -407,6 +407,7 @@ const char *finetimetests[] = {
"+util/monotonic_res_fallback", "+util/monotonic_res_fallback",
"+thread/deferred_cb_skew", "+thread/deferred_cb_skew",
"+http/connection_retry", "+http/connection_retry",
"+http/https_connection_retry",
NULL NULL
}; };
struct testlist_alias_t testaliases[] = { struct testlist_alias_t testaliases[] = {
@ -437,6 +438,7 @@ main(int argc, const char **argv)
#ifdef _WIN32 #ifdef _WIN32
tinytest_skip(testgroups, "http/connection_retry"); tinytest_skip(testgroups, "http/connection_retry");
tinytest_skip(testgroups, "http/https_connection_retry");
#endif #endif
#ifndef EVENT__DISABLE_THREAD_SUPPORT #ifndef EVENT__DISABLE_THREAD_SUPPORT

View File

@ -43,6 +43,7 @@
#include "event2/util.h" #include "event2/util.h"
#include "event2/event.h" #include "event2/event.h"
#include "event2/bufferevent_ssl.h" #include "event2/bufferevent_ssl.h"
#include "event2/bufferevent_struct.h"
#include "event2/buffer.h" #include "event2/buffer.h"
#include "event2/listener.h" #include "event2/listener.h"
@ -50,12 +51,12 @@
#include "tinytest.h" #include "tinytest.h"
#include "tinytest_macros.h" #include "tinytest_macros.h"
#include <openssl/ssl.h>
#include <openssl/bio.h> #include <openssl/bio.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/pem.h> #include <openssl/pem.h>
#include <string.h> #include <string.h>
#include <unistd.h>
/* A short pre-generated key, to save the cost of doing an RSA key generation /* 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 * 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" "U6GFEQTZ3IfuiVabG5pummdC4DNbcdI+WKrSFNmQ\n"
"-----END RSA PRIVATE KEY-----\n"; "-----END RSA PRIVATE KEY-----\n";
static EVP_PKEY * EVP_PKEY *
getkey(void) ssl_getkey(void)
{ {
EVP_PKEY *key; EVP_PKEY *key;
BIO *bio; BIO *bio;
@ -91,15 +92,15 @@ end:
return NULL; return NULL;
} }
static X509 * X509 *
getcert(void) ssl_getcert(void)
{ {
/* Dummy code to make a quick-and-dirty valid certificate with /* Dummy code to make a quick-and-dirty valid certificate with
OpenSSL. Don't copy this code into your own program! It does a OpenSSL. Don't copy this code into your own program! It does a
number of things in a stupid and insecure way. */ number of things in a stupid and insecure way. */
X509 *x509 = NULL; X509 *x509 = NULL;
X509_NAME *name = NULL; X509_NAME *name = NULL;
EVP_PKEY *key = getkey(); EVP_PKEY *key = ssl_getkey();
int nid; int nid;
time_t now = time(NULL); time_t now = time(NULL);
@ -137,7 +138,7 @@ end:
static int disable_tls_11_and_12 = 0; static int disable_tls_11_and_12 = 0;
static SSL_CTX *the_ssl_ctx = NULL; static SSL_CTX *the_ssl_ctx = NULL;
static SSL_CTX * SSL_CTX *
get_ssl_ctx(void) get_ssl_ctx(void)
{ {
if (the_ssl_ctx) if (the_ssl_ctx)
@ -156,7 +157,7 @@ get_ssl_ctx(void)
return the_ssl_ctx; return the_ssl_ctx;
} }
static void void
init_ssl(void) init_ssl(void)
{ {
SSL_library_init(); SSL_library_init();
@ -177,17 +178,64 @@ static int test_is_done = 0;
static int n_connected = 0; static int n_connected = 0;
static int got_close = 0; static int got_close = 0;
static int got_error = 0; static int got_error = 0;
static int got_timeout = 0;
static int renegotiate_at = -1; static int renegotiate_at = -1;
static int stop_when_connected = 0; static int stop_when_connected = 0;
static int pending_connect_events = 0; static int pending_connect_events = 0;
static struct event_base *exit_base = NULL; 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 static void
respond_to_number(struct bufferevent *bev, void *ctx) respond_to_number(struct bufferevent *bev, void *ctx)
{ {
struct evbuffer *b = bufferevent_get_input(bev); struct evbuffer *b = bufferevent_get_input(bev);
char *line; char *line;
int n; int n;
enum regress_openssl_type type;
type = (enum regress_openssl_type)ctx;
line = evbuffer_readln(b, NULL, EVBUFFER_EOL_LF); line = evbuffer_readln(b, NULL, EVBUFFER_EOL_LF);
if (! line) if (! line)
return; return;
@ -201,7 +249,7 @@ respond_to_number(struct bufferevent *bev, void *ctx)
bufferevent_free(bev); /* Should trigger close on other side. */ bufferevent_free(bev); /* Should trigger close on other side. */
return; return;
} }
if (!strcmp(ctx, "client") && n == renegotiate_at) { if ((type & REGRESS_OPENSSL_CLIENT) && n == renegotiate_at) {
SSL_renegotiate(bufferevent_openssl_get_ssl(bev)); SSL_renegotiate(bufferevent_openssl_get_ssl(bev));
} }
++n; ++n;
@ -226,6 +274,9 @@ done_writing_cb(struct bufferevent *bev, void *ctx)
static void static void
eventcb(struct bufferevent *bev, short what, void *ctx) 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)); TT_BLATHER(("Got event %d", (int)what));
if (what & BEV_EVENT_CONNECTED) { if (what & BEV_EVENT_CONNECTED) {
SSL *ssl; SSL *ssl;
@ -234,7 +285,7 @@ eventcb(struct bufferevent *bev, short what, void *ctx)
ssl = bufferevent_openssl_get_ssl(bev); ssl = bufferevent_openssl_get_ssl(bev);
tt_assert(ssl); tt_assert(ssl);
peer_cert = SSL_get_peer_certificate(ssl); peer_cert = SSL_get_peer_certificate(ssl);
if (0==strcmp(ctx, "server")) { if (type & REGRESS_OPENSSL_SERVER) {
tt_assert(peer_cert == NULL); tt_assert(peer_cert == NULL);
} else { } else {
tt_assert(peer_cert != NULL); tt_assert(peer_cert != NULL);
@ -246,10 +297,32 @@ eventcb(struct bufferevent *bev, short what, void *ctx)
} else if (what & BEV_EVENT_EOF) { } else if (what & BEV_EVENT_EOF) {
TT_BLATHER(("Got a good EOF")); TT_BLATHER(("Got a good EOF"));
++got_close; ++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); bufferevent_free(bev);
} else if (what & BEV_EVENT_ERROR) { } else if (what & BEV_EVENT_ERROR) {
TT_BLATHER(("Got an error.")); TT_BLATHER(("Got an error."));
++got_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); bufferevent_free(bev);
} }
end: end:
@ -259,10 +332,12 @@ end:
static void static void
open_ssl_bufevs(struct bufferevent **bev1_out, struct bufferevent **bev2_out, open_ssl_bufevs(struct bufferevent **bev1_out, struct bufferevent **bev2_out,
struct event_base *base, int is_open, int flags, SSL *ssl1, SSL *ssl2, 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 state1 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_CONNECTING;
int state2 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_ACCEPTING; int state2 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_ACCEPTING;
int dirty_shutdown = type & REGRESS_OPENSSL_DIRTY_SHUTDOWN;
if (fd_pair) { if (fd_pair) {
*bev1_out = bufferevent_openssl_socket_new( *bev1_out = bufferevent_openssl_socket_new(
base, fd_pair[0], ssl1, state1, flags); 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, 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, 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 static void
@ -288,20 +366,21 @@ regress_bufferevent_openssl(void *arg)
struct bufferevent *bev1, *bev2; struct bufferevent *bev1, *bev2;
SSL *ssl1, *ssl2; SSL *ssl1, *ssl2;
X509 *cert = getcert(); X509 *cert = ssl_getcert();
EVP_PKEY *key = getkey(); EVP_PKEY *key = ssl_getkey();
const int start_open = strstr((char*)data->setup_data, "open")!=NULL;
const int filter = strstr((char*)data->setup_data, "filter")!=NULL;
int flags = BEV_OPT_DEFER_CALLBACKS; int flags = BEV_OPT_DEFER_CALLBACKS;
struct bufferevent *bev_ll[2] = { NULL, NULL }; struct bufferevent *bev_ll[2] = { NULL, NULL };
evutil_socket_t *fd_pair = 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(cert);
tt_assert(key); tt_assert(key);
init_ssl(); init_ssl();
if (strstr((char*)data->setup_data, "renegotiate")) { if (type & REGRESS_OPENSSL_RENEGOTIATE) {
if (SSLeay() >= 0x10001000 && if (SSLeay() >= 0x10001000 &&
SSLeay() < 0x1000104f) { SSLeay() < 0x1000104f) {
/* 1.0.1 up to 1.0.1c has a bug where TLS1.1 and 1.2 /* 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_certificate(ssl2, cert);
SSL_use_PrivateKey(ssl2, key); SSL_use_PrivateKey(ssl2, key);
if (! start_open) if (!(type & REGRESS_OPENSSL_OPEN))
flags |= BEV_OPT_CLOSE_ON_FREE; flags |= BEV_OPT_CLOSE_ON_FREE;
if (!filter) { if (!(type & REGRESS_OPENSSL_FILTER)) {
tt_assert(strstr((char*)data->setup_data, "socketpair")); tt_assert(type & REGRESS_OPENSSL_SOCKETPAIR);
fd_pair = data->pair; fd_pair = data->pair;
} else { } else {
bev_ll[0] = bufferevent_socket_new(data->base, data->pair[0], 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, 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]); tt_int_op(bufferevent_getfd(bev1), ==, data->pair[0]);
} else { } else {
tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev_ll[0]); tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev_ll[0]);
} }
if (start_open) { if (type & REGRESS_OPENSSL_OPEN) {
pending_connect_events = 2; pending_connect_events = 2;
stop_when_connected = 1; stop_when_connected = 1;
exit_base = data->base; exit_base = data->base;
@ -351,37 +430,70 @@ regress_bufferevent_openssl(void *arg)
bufferevent_free(bev2); bufferevent_free(bev2);
bev1 = bev2 = NULL; bev1 = bev2 = NULL;
open_ssl_bufevs(&bev1, &bev2, data->base, 1, flags, ssl1, ssl2, 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); if (!(type & REGRESS_OPENSSL_TIMEOUT)) {
bufferevent_enable(bev2, EV_READ|EV_WRITE); 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(test_is_done == 1);
tt_assert(n_connected == 2); tt_assert(n_connected == 2);
/* We don't handle shutdown properly yet. /* We don't handle shutdown properly yet */
tt_int_op(got_close, ==, 1); if (type & REGRESS_OPENSSL_DIRTY_SHUTDOWN) {
tt_int_op(got_error, ==, 0); 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: end:
return; 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 static void
acceptcb(struct evconnlistener *listener, evutil_socket_t fd, acceptcb(struct evconnlistener *listener, evutil_socket_t fd,
struct sockaddr *addr, int socklen, void *arg) struct sockaddr *addr, int socklen, void *arg)
{ {
struct basic_test_data *data = arg; struct basic_test_data *data = arg;
struct bufferevent *bev; struct bufferevent *bev;
enum regress_openssl_type type;
SSL *ssl = SSL_new(get_ssl_ctx()); SSL *ssl = SSL_new(get_ssl_ctx());
SSL_use_certificate(ssl, getcert()); type = (enum regress_openssl_type)data->setup_data;
SSL_use_PrivateKey(ssl, getkey());
SSL_use_certificate(ssl, ssl_getcert());
SSL_use_PrivateKey(ssl, ssl_getkey());
bev = bufferevent_openssl_socket_new( bev = bufferevent_openssl_socket_new(
data->base, data->base,
@ -391,14 +503,129 @@ acceptcb(struct evconnlistener *listener, evutil_socket_t fd,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
bufferevent_setcb(bev, respond_to_number, NULL, eventcb, 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. */ /* Only accept once, then disable ourself. */
evconnlistener_disable(listener); 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 static void
regress_bufferevent_openssl_connect(void *arg) regress_bufferevent_openssl_connect(void *arg)
{ {
@ -411,6 +638,12 @@ regress_bufferevent_openssl_connect(void *arg)
struct sockaddr_in sin; struct sockaddr_in sin;
struct sockaddr_storage ss; struct sockaddr_storage ss;
ev_socklen_t slen; 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(); init_ssl();
@ -428,51 +661,115 @@ regress_bufferevent_openssl_connect(void *arg)
tt_assert(listener); tt_assert(listener);
tt_assert(evconnlistener_get_fd(listener) >= 0); tt_assert(evconnlistener_get_fd(listener) >= 0);
ssl = SSL_new(get_ssl_ctx());
tt_assert(ssl);
bev = bufferevent_openssl_socket_new( bev = bufferevent_openssl_socket_new(
data->base, -1, SSL_new(get_ssl_ctx()), data->base, -1, ssl,
BUFFEREVENT_SSL_CONNECTING, BUFFEREVENT_SSL_CONNECTING,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
tt_assert(bev); tt_assert(bev);
bufferevent_setcb(bev, respond_to_number, NULL, eventcb, bufferevent_setcb(bev, respond_to_number, NULL, eventcb,
(void*)"client"); (void*)(REGRESS_OPENSSL_CLIENT));
tt_assert(getsockname(evconnlistener_get_fd(listener), tt_assert(getsockname(evconnlistener_get_fd(listener),
(struct sockaddr*)&ss, &slen) == 0); (struct sockaddr*)&ss, &slen) == 0);
tt_assert(slen == sizeof(struct sockaddr_in)); 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_int_op(((struct sockaddr*)&ss)->sa_family, ==, AF_INET);
tt_assert(0 == tt_assert(0 ==
bufferevent_socket_connect(bev, (struct sockaddr*)&ss, slen)); 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"); evbuffer_add_printf(bufferevent_get_output(bev), "1\n");
bufferevent_enable(bev, EV_READ|EV_WRITE); bufferevent_enable(bev, EV_READ|EV_WRITE);
event_base_dispatch(base); event_base_dispatch(base);
tt_int_op(rw.read, <=, 100);
tt_int_op(rw.write, <=, 100);
end: end:
; ;
} }
struct testcase_t ssl_testcases[] = { struct testcase_t ssl_testcases[] = {
#define T(a) ((void *)(a))
{ "bufferevent_socketpair", regress_bufferevent_openssl, TT_ISOLATED, { "bufferevent_socketpair", regress_bufferevent_openssl,
&basic_setup, (void*)"socketpair" }, TT_ISOLATED, &basic_setup, T(REGRESS_OPENSSL_SOCKETPAIR) },
{ "bufferevent_filter", regress_bufferevent_openssl, { "bufferevent_filter", regress_bufferevent_openssl,
TT_ISOLATED, TT_ISOLATED, &basic_setup, T(REGRESS_OPENSSL_FILTER) },
&basic_setup, (void*)"filter" },
{ "bufferevent_renegotiate_socketpair", regress_bufferevent_openssl, { "bufferevent_renegotiate_socketpair", regress_bufferevent_openssl,
TT_ISOLATED, TT_ISOLATED, &basic_setup,
&basic_setup, (void*)"socketpair renegotiate" }, T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_RENEGOTIATE) },
{ "bufferevent_renegotiate_filter", regress_bufferevent_openssl, { "bufferevent_renegotiate_filter", regress_bufferevent_openssl,
TT_ISOLATED, TT_ISOLATED, &basic_setup,
&basic_setup, (void*)"filter renegotiate" }, T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_RENEGOTIATE) },
{ "bufferevent_socketpair_startopen", regress_bufferevent_openssl, { "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, { "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, { "bufferevent_connect", regress_bufferevent_openssl_connect,
TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, 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, END_OF_TESTCASES,
}; };

View File

@ -135,11 +135,18 @@ regress_clean_dnsserver(void)
evutil_closesocket(dns_sock); evutil_closesocket(dns_sock);
} }
static void strtolower(char *s)
{
while (*s) {
*s = EVUTIL_TOLOWER_(*s);
++s;
}
}
void void
regress_dns_server_cb(struct evdns_server_request *req, void *data) regress_dns_server_cb(struct evdns_server_request *req, void *data)
{ {
struct regress_dns_server_table *tab = data; struct regress_dns_server_table *tab = data;
const char *question; char *question;
if (req->nquestions != 1) if (req->nquestions != 1)
TT_DIE(("Only handling one question at a time; got %d", 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; ++tab->seen;
if (tab->lower)
strtolower(question);
if (!strcmp(tab->anstype, "err")) { if (!strcmp(tab->anstype, "err")) {
int err = atoi(tab->ans); int err = atoi(tab->ans);
tt_assert(! evdns_server_request_respond(req, err)); tt_assert(! evdns_server_request_respond(req, err));

View File

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

View File

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

View File

@ -97,6 +97,7 @@ run_tests () {
announce "FAILED (output not checked)" ; announce "FAILED (output not checked)" ;
fi fi
fi fi
test -x $TEST_DIR/regress || return test -x $TEST_DIR/regress || return
announce_n " regress: " announce_n " regress: "
if test "$TEST_OUTPUT_FILE" = "/dev/null" ; if test "$TEST_OUTPUT_FILE" = "/dev/null" ;
@ -112,6 +113,21 @@ run_tests () {
announce FAILED ; announce FAILED ;
FAILED=yes FAILED=yes
fi 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() { 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 evutil_read_file_(const char *filename, char **content_out, size_t *len_out,
int is_binary); 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); 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; extern struct event_list addqueue;
struct win_fd_set { struct win_fd_set {
u_int fd_count; unsigned int fd_count;
SOCKET fd_array[1]; SOCKET fd_array[1];
}; };