1
1

Remove the sample and test code from the libevent distro - don't need to include them in ompi

This commit was SVN r23931.
Этот коммит содержится в:
Ralph Castain 2010-10-25 14:53:33 +00:00
родитель bab990d812
Коммит a04da165bc
46 изменённых файлов: 2 добавлений и 18712 удалений

Просмотреть файл

@ -85,7 +85,7 @@ EXTRA_DIST = \
libevent.pc.in \
Doxyfile \
whatsnew-2.0.txt \
Makefile.nmake test/Makefile.nmake \
Makefile.nmake \
$(PLATFORM_DEPENDENT_SRC)
# OMPI: Changed to noinst and libevent.la

Просмотреть файл

@ -838,4 +838,4 @@ if test x$enable_gcc_warnings = xyes; then
fi
AC_CONFIG_FILES( [libevent.pc libevent_openssl.pc libevent_pthreads.pc] )
AC_OUTPUT(Makefile include/Makefile test/Makefile sample/Makefile)
AC_OUTPUT(Makefile include/Makefile)

Просмотреть файл

@ -1,22 +0,0 @@
AUTOMAKE_OPTIONS = foreign no-dependencies
LDADD = ../libevent.la
AM_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat -I$(top_srcdir)/include -I../include
noinst_PROGRAMS = event-test time-test signal-test dns-example hello-world
event_test_sources = event-test.c
time_test_sources = time-test.c
signal_test_sources = signal-test.c
dns_example_sources = dns-example.c
hello_world_sources = hello-world.c
if OPENSSL
noinst_PROGRAMS += le-proxy
le_proxy_sources = le-proxy.c
le_proxy_LDADD = $(LDADD) ../libevent_openssl.la -lcrypto -lssl
endif
verify:
DISTCLEANFILES = *~

Просмотреть файл

@ -1,221 +0,0 @@
/*
This example code shows how to use the high-level, low-level, and
server-level interfaces of evdns.
XXX It's pretty ugly and should probably be cleaned up.
*/
#include <event2/event-config.h>
#include <sys/types.h>
#ifdef WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include <event2/event.h>
#include <event2/dns.h>
#include <event2/dns_struct.h>
#include <event2/util.h>
#ifdef _EVENT_HAVE_NETINET_IN6_H
#include <netinet/in6.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define u32 ev_uint32_t
#define u8 ev_uint8_t
static const char *
debug_ntoa(u32 address)
{
static char buf[32];
u32 a = ntohl(address);
evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d",
(int)(u8)((a>>24)&0xff),
(int)(u8)((a>>16)&0xff),
(int)(u8)((a>>8 )&0xff),
(int)(u8)((a )&0xff));
return buf;
}
static void
main_callback(int result, char type, int count, int ttl,
void *addrs, void *orig) {
char *n = (char*)orig;
int i;
for (i = 0; i < count; ++i) {
if (type == DNS_IPv4_A) {
printf("%s: %s\n", n, debug_ntoa(((u32*)addrs)[i]));
} else if (type == DNS_PTR) {
printf("%s: %s\n", n, ((char**)addrs)[i]);
}
}
if (!count) {
printf("%s: No answer (%d)\n", n, result);
}
fflush(stdout);
}
static void
gai_callback(int err, struct evutil_addrinfo *ai, void *arg)
{
const char *name = arg;
struct evutil_addrinfo *ai_first = NULL;
int i;
if (err) {
printf("%s: %s\n", name, evutil_gai_strerror(err));
}
if (ai && ai->ai_canonname)
printf(" %s ==> %s\n", name, ai->ai_canonname);
for (i=0; ai; ai = ai->ai_next, ++i) {
char buf[128];
if (ai->ai_family == PF_INET) {
struct sockaddr_in *sin =
(struct sockaddr_in*)ai->ai_addr;
evutil_inet_ntop(AF_INET, &sin->sin_addr, buf,
sizeof(buf));
printf("[%d] %s: %s\n",i,name,buf);
} else {
struct sockaddr_in6 *sin6 =
(struct sockaddr_in6*)ai->ai_addr;
evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf,
sizeof(buf));
printf("[%d] %s: %s\n",i,name,buf);
}
}
if (ai_first)
evutil_freeaddrinfo(ai_first);
}
static void
evdns_server_callback(struct evdns_server_request *req, void *data)
{
int i, r;
(void)data;
/* dummy; give 192.168.11.11 as an answer for all A questions,
* give foo.bar.example.com as an answer for all PTR questions. */
for (i = 0; i < req->nquestions; ++i) {
u32 ans = htonl(0xc0a80b0bUL);
if (req->questions[i]->type == EVDNS_TYPE_A &&
req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
printf(" -- replying for %s (A)\n", req->questions[i]->name);
r = evdns_server_request_add_a_reply(req, req->questions[i]->name,
1, &ans, 10);
if (r<0)
printf("eeep, didn't work.\n");
} else if (req->questions[i]->type == EVDNS_TYPE_PTR &&
req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
printf(" -- replying for %s (PTR)\n", req->questions[i]->name);
r = evdns_server_request_add_ptr_reply(req, NULL, req->questions[i]->name,
"foo.bar.example.com", 10);
} else {
printf(" -- skipping %s [%d %d]\n", req->questions[i]->name,
req->questions[i]->type, req->questions[i]->dns_question_class);
}
}
r = evdns_server_request_respond(req, 0);
if (r<0)
printf("eeek, couldn't send reply.\n");
}
static int verbose = 0;
static void
logfn(int is_warn, const char *msg) {
if (!is_warn && !verbose)
return;
fprintf(stderr, "%s: %s\n", is_warn?"WARN":"INFO", msg);
}
int
main(int c, char **v) {
int idx;
int reverse = 0, servertest = 0, use_getaddrinfo = 0;
struct event_base *event_base = NULL;
struct evdns_base *evdns_base = NULL;
if (c<2) {
fprintf(stderr, "syntax: %s [-x] [-v] hostname\n", v[0]);
fprintf(stderr, "syntax: %s [-servertest]\n", v[0]);
return 1;
}
idx = 1;
while (idx < c && v[idx][0] == '-') {
if (!strcmp(v[idx], "-x"))
reverse = 1;
else if (!strcmp(v[idx], "-v"))
verbose = 1;
else if (!strcmp(v[idx], "-g"))
use_getaddrinfo = 1;
else if (!strcmp(v[idx], "-servertest"))
servertest = 1;
else
fprintf(stderr, "Unknown option %s\n", v[idx]);
++idx;
}
event_base = event_base_new();
evdns_base = evdns_base_new(event_base, 0);
evdns_set_log_fn(logfn);
if (servertest) {
evutil_socket_t sock;
struct sockaddr_in my_addr;
sock = socket(PF_INET, SOCK_DGRAM, 0);
evutil_make_socket_nonblocking(sock);
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(10053);
my_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr))<0) {
perror("bind");
exit(1);
}
evdns_add_server_port_with_base(event_base, sock, 0, evdns_server_callback, NULL);
}
if (idx < c) {
#ifdef WIN32
evdns_base_config_windows_nameservers(evdns_base);
#else
evdns_base_resolv_conf_parse(evdns_base, DNS_OPTION_NAMESERVERS,
"/etc/resolv.conf");
#endif
}
printf("EVUTIL_AI_CANONNAME in example = %d\n", EVUTIL_AI_CANONNAME);
for (; idx < c; ++idx) {
if (reverse) {
struct in_addr addr;
if (evutil_inet_pton(AF_INET, v[idx], &addr)!=1) {
fprintf(stderr, "Skipping non-IP %s\n", v[idx]);
continue;
}
fprintf(stderr, "resolving %s...\n",v[idx]);
evdns_base_resolve_reverse(evdns_base, &addr, 0, main_callback, v[idx]);
} else if (use_getaddrinfo) {
struct evutil_addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = EVUTIL_AI_CANONNAME;
fprintf(stderr, "resolving (fwd) %s...\n",v[idx]);
evdns_getaddrinfo(evdns_base, v[idx], NULL, &hints,
gai_callback, v[idx]);
} else {
fprintf(stderr, "resolving (fwd) %s...\n",v[idx]);
evdns_base_resolve_ipv4(evdns_base, v[idx], 0, main_callback, v[idx]);
}
}
fflush(stdout);
event_base_dispatch(event_base);
return 0;
}

Просмотреть файл

@ -1,143 +0,0 @@
/*
* XXX This sample code was once meant to show how to use the basic Libevent
* interfaces, but it never worked on non-Unix platforms, and some of the
* interfaces have changed since it was first written. It should probably
* be removed or replaced with something better.
*
* Compile with:
* cc -I/usr/local/include -o event-test event-test.c -L/usr/local/lib -levent
*/
#include <event2/event-config.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef WIN32
#include <sys/queue.h>
#include <unistd.h>
#include <sys/time.h>
#else
#include <winsock2.h>
#include <windows.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <event.h>
static void
fifo_read(int fd, short event, void *arg)
{
char buf[255];
int len;
struct event *ev = arg;
#ifdef WIN32
DWORD dwBytesRead;
#endif
/* Reschedule this event */
event_add(ev, NULL);
fprintf(stderr, "fifo_read called with fd: %d, event: %d, arg: %p\n",
fd, event, arg);
#ifdef WIN32
len = ReadFile((HANDLE)fd, buf, sizeof(buf) - 1, &dwBytesRead, NULL);
/* Check for end of file. */
if (len && dwBytesRead == 0) {
fprintf(stderr, "End Of File");
event_del(ev);
return;
}
buf[dwBytesRead] = '\0';
#else
len = read(fd, buf, sizeof(buf) - 1);
if (len == -1) {
perror("read");
return;
} else if (len == 0) {
fprintf(stderr, "Connection closed\n");
return;
}
buf[len] = '\0';
#endif
fprintf(stdout, "Read: %s\n", buf);
}
int
main(int argc, char **argv)
{
struct event evfifo;
#ifdef WIN32
HANDLE socket;
/* Open a file. */
socket = CreateFileA("test.txt", /* open File */
GENERIC_READ, /* open for reading */
0, /* do not share */
NULL, /* no security */
OPEN_EXISTING, /* existing file only */
FILE_ATTRIBUTE_NORMAL, /* normal file */
NULL); /* no attr. template */
if (socket == INVALID_HANDLE_VALUE)
return 1;
#else
struct stat st;
const char *fifo = "event.fifo";
int socket;
if (lstat(fifo, &st) == 0) {
if ((st.st_mode & S_IFMT) == S_IFREG) {
errno = EEXIST;
perror("lstat");
exit(1);
}
}
unlink(fifo);
if (mkfifo(fifo, 0600) == -1) {
perror("mkfifo");
exit(1);
}
/* Linux pipes are broken, we need O_RDWR instead of O_RDONLY */
#ifdef __linux
socket = open(fifo, O_RDWR | O_NONBLOCK, 0);
#else
socket = open(fifo, O_RDONLY | O_NONBLOCK, 0);
#endif
if (socket == -1) {
perror("open");
exit(1);
}
fprintf(stderr, "Write data to %s\n", fifo);
#endif
/* Initalize the event library */
event_init();
/* Initalize one event */
#ifdef WIN32
event_set(&evfifo, (int)socket, EV_READ, fifo_read, &evfifo);
#else
event_set(&evfifo, socket, EV_READ, fifo_read, &evfifo);
#endif
/* Add it to the active events, without a timeout */
event_add(&evfifo, NULL);
event_dispatch();
#ifdef WIN32
CloseHandle(socket);
#endif
return (0);
}

Просмотреть файл

@ -1,138 +0,0 @@
/*
This exmple program provides a trivial server program that listens for TCP
connections on port 9995. When they arrive, it writes a short message to
each client connection, and closes each connection once it is flushed.
Where possible, it exits cleanly in response to a SIGINT (ctrl-c).
*/
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#ifndef WIN32
#include <netinet/in.h>
#include <sys/socket.h>
#endif
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>
static const char MESSAGE[] = "Hello, World!\n";
static const int PORT = 9995;
static void listener_cb(struct evconnlistener *, evutil_socket_t,
struct sockaddr *, int socklen, void *);
static void conn_writecb(struct bufferevent *, void *);
static void conn_eventcb(struct bufferevent *, short, void *);
static void signal_cb(evutil_socket_t, short, void *);
int
main(int argc, char **argv)
{
struct event_base *base;
struct evconnlistener *listener;
struct event *signal_event;
struct sockaddr_in sin;
#ifdef WIN32
WSADATA wsa_data;
WSAStartup(0x0201, &wsa_data);
#endif
base = event_base_new();
if (!base) {
fprintf(stderr, "Could not initialize libevent!\n");
return 1;
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
listener = evconnlistener_new_bind(base, listener_cb, (void *)base,
LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1,
(struct sockaddr*)&sin,
sizeof(sin));
if (!listener) {
fprintf(stderr, "Could not create a listener!\n");
return 1;
}
signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);
if (!signal_event || event_add(signal_event, NULL)<0) {
fprintf(stderr, "Could not create/add a signal event!\n");
return 1;
}
event_base_dispatch(base);
evconnlistener_free(listener);
event_free(signal_event);
event_base_free(base);
printf("done\n");
return 0;
}
static void
listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
struct sockaddr *sa, int socklen, void *user_data)
{
struct event_base *base = user_data;
struct bufferevent *bev;
bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
if (!bev) {
fprintf(stderr, "Error constructing bufferevent!");
event_base_loopbreak(base);
return;
}
bufferevent_setcb(bev, NULL, conn_writecb, conn_eventcb, NULL);
bufferevent_enable(bev, EV_WRITE);
bufferevent_disable(bev, EV_READ);
bufferevent_write(bev, MESSAGE, strlen(MESSAGE));
}
static void
conn_writecb(struct bufferevent *bev, void *user_data)
{
struct evbuffer *output = bufferevent_get_output(bev);
if (evbuffer_get_length(output) == 0) {
printf("flushed answer\n");
bufferevent_free(bev);
}
}
static void
conn_eventcb(struct bufferevent *bev, short events, void *user_data)
{
if (events & BEV_EVENT_EOF) {
printf("Connection closed.\n");
} else if (events & BEV_EVENT_ERROR) {
printf("Got an error on the connection: %s\n",
strerror(errno));/*XXX win32*/
}
/* None of the other events can happen here, since we haven't enabled
* timeouts */
bufferevent_free(bev);
}
static void
signal_cb(evutil_socket_t sig, short events, void *user_data)
{
struct event_base *base = user_data;
struct timeval delay = { 2, 0 };
printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");
event_base_loopexit(base, &delay);
}

Просмотреть файл

@ -1,275 +0,0 @@
/*
This example code shows how to write an (optionally encrypting) SSL proxy
with Libevent's bufferevent layer.
XXX It's a little ugly and should probably be cleaned up.
*/
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#include <event2/bufferevent_ssl.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
static struct event_base *base;
static struct sockaddr_storage listen_on_addr;
static struct sockaddr_storage connect_to_addr;
static int connect_to_addrlen;
static int use_wrapper = 1;
static SSL_CTX *ssl_ctx = NULL;
#define MAX_OUTPUT (512*1024)
static void drained_writecb(struct bufferevent *bev, void *ctx);
static void eventcb(struct bufferevent *bev, short what, void *ctx);
static void
readcb(struct bufferevent *bev, void *ctx)
{
struct bufferevent *partner = ctx;
struct evbuffer *src, *dst;
size_t len;
src = bufferevent_get_input(bev);
len = evbuffer_get_length(src);
if (!partner) {
evbuffer_drain(src, len);
return;
}
dst = bufferevent_get_output(partner);
evbuffer_add_buffer(dst, src);
if (evbuffer_get_length(dst) >= MAX_OUTPUT) {
/* We're giving the other side data faster than it can
* pass it on. Stop reading here until we have drained the
* other side to MAX_OUTPUT/2 bytes. */
bufferevent_setcb(partner, readcb, drained_writecb,
eventcb, bev);
bufferevent_setwatermark(partner, EV_WRITE, MAX_OUTPUT/2,
MAX_OUTPUT);
bufferevent_disable(bev, EV_READ);
}
}
static void
drained_writecb(struct bufferevent *bev, void *ctx)
{
struct bufferevent *partner = ctx;
/* We were choking the other side until we drained our outbuf a bit.
* Now it seems drained. */
bufferevent_setcb(bev, readcb, NULL, eventcb, partner);
bufferevent_setwatermark(bev, EV_WRITE, 0, 0);
if (partner)
bufferevent_enable(partner, EV_READ);
}
static void
close_on_finished_writecb(struct bufferevent *bev, void *ctx)
{
struct evbuffer *b = bufferevent_get_output(bev);
if (evbuffer_get_length(b) == 0) {
bufferevent_free(bev);
}
}
static void
eventcb(struct bufferevent *bev, short what, void *ctx)
{
struct bufferevent *partner = ctx;
if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
if (what & BEV_EVENT_ERROR) {
unsigned long err;
while ((err = (bufferevent_get_openssl_error(bev)))) {
const char *msg = (const char*)
ERR_reason_error_string(err);
const char *lib = (const char*)
ERR_lib_error_string(err);
const char *func = (const char*)
ERR_func_error_string(err);
fprintf(stderr,
"%s in %s %s\n", msg, lib, func);
}
if (errno)
perror("connection error");
}
if (partner) {
/* Flush all pending data */
readcb(bev, ctx);
if (evbuffer_get_length(
bufferevent_get_output(partner))) {
/* We still have to flush data from the other
* side, but when that's done, close the other
* side. */
bufferevent_setcb(partner,
NULL, close_on_finished_writecb,
eventcb, NULL);
bufferevent_disable(partner, EV_READ);
} else {
/* We have nothing left to say to the other
* side; close it. */
bufferevent_free(partner);
}
}
bufferevent_free(bev);
}
}
static void
syntax(void)
{
fputs("Syntax:\n", stderr);
fputs(" le-proxy [-s] [-W] <listen-on-addr> <connect-to-addr>\n", stderr);
fputs("Example:\n", stderr);
fputs(" le-proxy 127.0.0.1:8888 1.2.3.4:80\n", stderr);
exit(1);
}
static void
accept_cb(struct evconnlistener *listener, evutil_socket_t fd,
struct sockaddr *a, int slen, void *p)
{
struct bufferevent *b_out, *b_in;
/* Create two linked bufferevent objects: one to connect, one for the
* new connection */
b_in = bufferevent_socket_new(base, fd,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
if (!ssl_ctx || use_wrapper)
b_out = bufferevent_socket_new(base, -1,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
else {
SSL *ssl = SSL_new(ssl_ctx);
b_out = bufferevent_openssl_socket_new(base, -1, ssl,
BUFFEREVENT_SSL_CONNECTING,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
}
assert(b_in && b_out);
if (bufferevent_socket_connect(b_out,
(struct sockaddr*)&connect_to_addr, connect_to_addrlen)<0) {
perror("bufferevent_socket_connect");
bufferevent_free(b_out);
bufferevent_free(b_in);
return;
}
if (ssl_ctx && use_wrapper) {
struct bufferevent *b_ssl;
SSL *ssl = SSL_new(ssl_ctx);
b_ssl = bufferevent_openssl_filter_new(base,
b_out, ssl, BUFFEREVENT_SSL_CONNECTING,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
if (!b_ssl) {
perror("Bufferevent_openssl_new");
bufferevent_free(b_out);
bufferevent_free(b_in);
}
b_out = b_ssl;
}
bufferevent_setcb(b_in, readcb, NULL, eventcb, b_out);
bufferevent_setcb(b_out, readcb, NULL, eventcb, b_in);
bufferevent_enable(b_in, EV_READ|EV_WRITE);
bufferevent_enable(b_out, EV_READ|EV_WRITE);
}
int
main(int argc, char **argv)
{
int i;
int socklen;
int use_ssl = 0;
struct evconnlistener *listener;
if (argc < 3)
syntax();
for (i=1; i < argc; ++i) {
if (!strcmp(argv[i], "-s")) {
use_ssl = 1;
} else if (!strcmp(argv[i], "-W")) {
use_wrapper = 0;
} else if (argv[i][0] == '-') {
syntax();
} else
break;
}
if (i+2 != argc)
syntax();
memset(&listen_on_addr, 0, sizeof(listen_on_addr));
socklen = sizeof(listen_on_addr);
if (evutil_parse_sockaddr_port(argv[i],
(struct sockaddr*)&listen_on_addr, &socklen)<0) {
int p = atoi(argv[i]);
struct sockaddr_in *sin = (struct sockaddr_in*)&listen_on_addr;
if (p < 1 || p > 65535)
syntax();
sin->sin_port = htons(p);
sin->sin_addr.s_addr = htonl(0x7f000001);
sin->sin_family = AF_INET;
socklen = sizeof(struct sockaddr_in);
}
memset(&connect_to_addr, 0, sizeof(connect_to_addr));
connect_to_addrlen = sizeof(connect_to_addr);
if (evutil_parse_sockaddr_port(argv[i+1],
(struct sockaddr*)&connect_to_addr, &connect_to_addrlen)<0)
syntax();
base = event_base_new();
if (!base) {
perror("event_base_new()");
return 1;
}
if (use_ssl) {
int r;
SSL_library_init();
ERR_load_crypto_strings();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
r = RAND_poll();
if (r == 0) {
fprintf(stderr, "RAND_poll() failed.\n");
return 1;
}
ssl_ctx = SSL_CTX_new(SSLv23_method());
}
listener = evconnlistener_new_bind(base, accept_cb, NULL,
LEV_OPT_CLOSE_ON_FREE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_REUSEABLE,
-1, (struct sockaddr*)&listen_on_addr, socklen);
event_base_dispatch(base);
return 0;
}

Просмотреть файл

@ -1,77 +0,0 @@
/*
* Compile with:
* cc -I/usr/local/include -o signal-test \
* signal-test.c -L/usr/local/lib -levent
*/
#include <sys/types.h>
#include <event2/event-config.h>
#include <sys/stat.h>
#ifndef WIN32
#include <sys/queue.h>
#include <unistd.h>
#include <sys/time.h>
#else
#include <winsock2.h>
#include <windows.h>
#endif
#include <signal.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <event.h>
#ifdef _EVENT___func__
#define __func__ _EVENT___func__
#endif
int called = 0;
static void
signal_cb(evutil_socket_t fd, short event, void *arg)
{
struct event *signal = arg;
printf("%s: got signal %d\n", __func__, EVENT_SIGNAL(signal));
if (called >= 2)
event_del(signal);
called++;
}
int
main(int argc, char **argv)
{
struct event signal_int;
struct event_base* base;
#ifdef WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
#endif
/* Initalize the event library */
base = event_base_new();
/* Initalize one event */
event_assign(&signal_int, base, SIGINT, EV_SIGNAL|EV_PERSIST, signal_cb,
&signal_int);
event_add(&signal_int, NULL);
event_base_dispatch(base);
event_base_free(base);
return (0);
}

Просмотреть файл

@ -1,108 +0,0 @@
/*
* XXX This sample code was once meant to show how to use the basic Libevent
* interfaces, but it never worked on non-Unix platforms, and some of the
* interfaces have changed since it was first written. It should probably
* be removed or replaced with something better.
*
* Compile with:
* cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
*/
#include <sys/types.h>
#include <event2/event-config.h>
#include <sys/stat.h>
#ifndef WIN32
#include <sys/queue.h>
#include <unistd.h>
#endif
#include <time.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <event2/event.h>
#include <event2/event_struct.h>
#include <event2/util.h>
#ifdef WIN32
#include <winsock2.h>
#endif
struct timeval lasttime;
int event_is_persistent;
static void
timeout_cb(evutil_socket_t fd, short event, void *arg)
{
struct timeval newtime, difference;
struct event *timeout = arg;
double elapsed;
evutil_gettimeofday(&newtime, NULL);
evutil_timersub(&newtime, &lasttime, &difference);
elapsed = difference.tv_sec +
(difference.tv_usec / 1.0e6);
printf("timeout_cb called at %d: %.3f seconds elapsed.\n",
(int)newtime.tv_sec, elapsed);
lasttime = newtime;
if (! event_is_persistent) {
struct timeval tv;
evutil_timerclear(&tv);
tv.tv_sec = 2;
event_add(timeout, &tv);
}
}
int
main(int argc, char **argv)
{
struct event timeout;
struct timeval tv;
struct event_base *base;
int flags;
#ifdef WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
#endif
if (argc == 2 && !strcmp(argv[1], "-p")) {
event_is_persistent = 1;
flags = EV_PERSIST;
} else {
event_is_persistent = 0;
flags = 0;
}
/* Initalize the event library */
base = event_base_new();
/* Initalize one event */
event_assign(&timeout, base, -1, flags, timeout_cb, (void*) &timeout);
evutil_timerclear(&tv);
tv.tv_sec = 2;
event_add(&timeout, &tv);
evutil_gettimeofday(&lasttime, NULL);
event_base_dispatch(base);
return (0);
}

Просмотреть файл

@ -1,74 +0,0 @@
AUTOMAKE_OPTIONS = foreign
AM_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat -I$(top_srcdir)/include -I../include
EXTRA_DIST = regress.rpc regress.gen.h regress.gen.c test.sh
noinst_PROGRAMS = test-init test-eof test-weof test-time regress \
bench bench_cascade bench_http bench_httpclient test-ratelim \
test-changelist
noinst_HEADERS = tinytest.h tinytest_macros.h regress.h
TESTS = $(top_srcdir)/test/test.sh
BUILT_SOURCES = regress.gen.c regress.gen.h
test_init_SOURCES = test-init.c
test_init_LDADD = ../../../libopen-pal.la
test_eof_SOURCES = test-eof.c
test_eof_LDADD = ../../../libopen-pal.la
test_changelist_SOURCES = test-changelist.c
test_changelist_LDADD = ../../../libopen-pal.la
test_weof_SOURCES = test-weof.c
test_weof_LDADD = ../../../libopen-pal.la
test_time_SOURCES = test-time.c
test_time_LDADD = ../../../libopen-pal.la
test_ratelim_SOURCES = test-ratelim.c
test_ratelim_LDADD = ../../../libopen-pal.la
regress_SOURCES = regress.c regress_buffer.c regress_http.c regress_dns.c \
regress_testutils.c regress_testutils.h \
regress_rpc.c regress.gen.c regress.gen.h regress_et.c \
regress_bufferevent.c regress_listener.c \
regress_util.c tinytest.c regress_main.c regress_minheap.c \
$(regress_thread_SOURCES) $(regress_zlib_SOURCES)
if PTHREADS
regress_thread_SOURCES = regress_thread.c
PTHREAD_LIBS += ../libevent_pthreads.la
endif
if BUILD_WIN32
regress_thread_SOURCES = regress_thread.c
endif
if ZLIB_REGRESS
regress_zlib_SOURCES = regress_zlib.c
endif
if BUILD_WIN32
regress_SOURCES += regress_iocp.c
endif
regress_LDADD = ../libevent.la $(PTHREAD_LIBS) $(ZLIB_LIBS)
regress_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat \
-I$(top_srcdir)/include -I../include $(PTHREAD_CFLAGS) $(ZLIB_CFLAGS)
regress_LDFLAGS = $(PTHREAD_CFLAGS)
if OPENSSL
regress_SOURCES += regress_ssl.c
regress_LDADD += ../libevent_openssl.la -lcrypto -lssl
endif
bench_SOURCES = bench.c
bench_LDADD = ../libevent.la
bench_cascade_SOURCES = bench_cascade.c
bench_cascade_LDADD = ../libevent.la
bench_http_SOURCES = bench_http.c
bench_http_LDADD = ../libevent.la
bench_httpclient_SOURCES = bench_httpclient.c
bench_httpclient_LDADD = ../libevent_core.la
regress.gen.c regress.gen.h: regress.rpc $(top_srcdir)/event_rpcgen.py
$(top_srcdir)/event_rpcgen.py $(srcdir)/regress.rpc || echo "No Python installed"
DISTCLEANFILES = *~
verify: check
bench test-init test-eof test-weof test-time test-changelist: ../libevent.la

Просмотреть файл

@ -1,56 +0,0 @@
CFLAGS=/I.. /I../WIN32-Code /I../include /I../compat /DWIN32 /DHAVE_CONFIG_H
CFLAGS=$(CFLAGS) /Ox /W3 /wd4996 /nologo
REGRESS_OBJS=regress.obj regress_buffer.obj regress_http.obj regress_dns.obj \
regress_testutils.obj \
regress_rpc.obj regress.gen.obj \
regress_et.obj regress_bufferevent.obj \
regress_listener.obj regress_util.obj tinytest.obj \
regress_main.obj regress_minheap.obj regress_iocp.obj \
regress_thread.obj
OTHER_OBJS=test-init.obj test-eof.obj test-weof.obj test-time.obj \
bench.obj bench_cascade.obj bench_http.obj bench_httpclient.obj \
test-changelist.obj
PROGRAMS=regress.exe \
test-init.exe test-eof.exe test-weof.exe test-time.exe \
test-changelist.exe
# Disabled for now:
# bench.exe bench_cascade.exe bench_http.exe bench_httpclient.exe
LIBS=..\libevent.lib ws2_32.lib shell32.lib advapi32.lib
all: $(PROGRAMS)
regress.exe: $(REGRESS_OBJS)
$(CC) $(CFLAGS) $(LIBS) $(REGRESS_OBJS)
test-init.exe: test-init.obj
$(CC) $(CFLAGS) $(LIBS) test-init.obj
test-eof.exe: test-eof.obj
$(CC) $(CFLAGS) $(LIBS) test-eof.obj
test-changelist.exe: test-changelist.obj
$(CC) $(CFLAGS) $(LIBS) test-changelist.obj
test-weof.exe: test-weof.obj
$(CC) $(CFLAGS) $(LIBS) test-weof.obj
test-time.exe: test-time.obj
$(CC) $(CFLAGS) $(LIBS) test-time.obj
bench.exe: bench.obj
$(CC) $(CFLAGS) $(LIBS) bench.obj
bench_cascade.exe: bench_cascade.obj
$(CC) $(CFLAGS) $(LIBS) bench_cascade.obj
bench_http.exe: bench_http.obj
$(CC) $(CFLAGS) $(LIBS) bench_http.obj
bench_httpclient.exe: bench_httpclient.obj
$(CC) $(CFLAGS) $(LIBS) bench_httpclient.obj
clean:
-del $(REGRESS_OBJS)
-del $(OTHER_OBJS)
-del regress.exe

Просмотреть файл

@ -1,191 +0,0 @@
/*
* Copyright 2003-2007 Niels Provos <provos@citi.umich.edu>
* Copyright 2007-2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Mon 03/10/2003 - Modified by Davide Libenzi <davidel@xmailserver.org>
*
* Added chain event propagation to improve the sensitivity of
* the measure respect to the event loop efficency.
*
*
*/
#include "event2/event-config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#ifdef WIN32
#include <windows.h>
#else
#include <sys/socket.h>
#include <signal.h>
#include <sys/resource.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <event.h>
#include <evutil.h>
static int count, writes, fired;
static int *pipes;
static int num_pipes, num_active, num_writes;
static struct event *events;
static void
read_cb(evutil_socket_t fd, short which, void *arg)
{
long idx = (long) arg, widx = idx + 1;
u_char ch;
count += recv(fd, &ch, sizeof(ch), 0);
if (writes) {
if (widx >= num_pipes)
widx -= num_pipes;
send(pipes[2 * widx + 1], "e", 1, 0);
writes--;
fired++;
}
}
static struct timeval *
run_once(void)
{
int *cp, space;
long i;
static struct timeval ts, te;
for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
if (event_initialized(&events[i]))
event_del(&events[i]);
event_set(&events[i], cp[0], EV_READ | EV_PERSIST, read_cb, (void *) i);
event_add(&events[i], NULL);
}
event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK);
fired = 0;
space = num_pipes / num_active;
space = space * 2;
for (i = 0; i < num_active; i++, fired++)
send(pipes[i * space + 1], "e", 1, 0);
count = 0;
writes = num_writes;
{ int xcount = 0;
gettimeofday(&ts, NULL);
do {
event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK);
xcount++;
} while (count != fired);
gettimeofday(&te, NULL);
if (xcount != count) fprintf(stderr, "Xcount: %d, Rcount: %d\n", xcount, count);
}
evutil_timersub(&te, &ts, &te);
return (&te);
}
int
main(int argc, char **argv)
{
#ifndef WIN32
struct rlimit rl;
#endif
int i, c;
struct timeval *tv;
int *cp;
#ifdef WIN32
WSADATA WSAData;
WSAStartup(0x101, &WSAData);
#endif
num_pipes = 100;
num_active = 1;
num_writes = num_pipes;
while ((c = getopt(argc, argv, "n:a:w:")) != -1) {
switch (c) {
case 'n':
num_pipes = atoi(optarg);
break;
case 'a':
num_active = atoi(optarg);
break;
case 'w':
num_writes = atoi(optarg);
break;
default:
fprintf(stderr, "Illegal argument \"%c\"\n", c);
exit(1);
}
}
#ifndef WIN32
rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50;
if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
perror("setrlimit");
exit(1);
}
#endif
events = calloc(num_pipes, sizeof(struct event));
pipes = calloc(num_pipes * 2, sizeof(int));
if (events == NULL || pipes == NULL) {
perror("malloc");
exit(1);
}
event_init();
for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
#ifdef USE_PIPES
if (pipe(cp) == -1) {
#else
if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) {
#endif
perror("pipe");
exit(1);
}
}
for (i = 0; i < 25; i++) {
tv = run_once();
if (tv == NULL)
exit(1);
fprintf(stdout, "%ld\n",
tv->tv_sec * 1000000L + tv->tv_usec);
}
exit(0);
}

Просмотреть файл

@ -1,169 +0,0 @@
/*
* Copyright 2007-2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "event2/event-config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#ifdef WIN32
#include <windows.h>
#else
#include <sys/socket.h>
#include <sys/resource.h>
#endif
#include <signal.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <event.h>
#include <evutil.h>
/*
* This benchmark tests how quickly we can propagate a write down a chain
* of socket pairs. We start by writing to the first socket pair and all
* events will fire subsequently until the last socket pair has been reached
* and the benchmark terminates.
*/
static int fired;
static int *pipes;
static struct event *events;
static void
read_cb(evutil_socket_t fd, short which, void *arg)
{
char ch;
long idx = (long) arg;
recv(fd, &ch, sizeof(ch), 0);
if (idx >= 0)
send(idx, "e", 1, 0);
fired++;
}
static struct timeval *
run_once(int num_pipes)
{
int *cp, i;
static struct timeval ts, te, tv_timeout;
events = calloc(num_pipes, sizeof(struct event));
pipes = calloc(num_pipes * 2, sizeof(int));
if (events == NULL || pipes == NULL) {
perror("malloc");
exit(1);
}
for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) {
perror("socketpair");
exit(1);
}
}
/* measurements includes event setup */
gettimeofday(&ts, NULL);
/* provide a default timeout for events */
evutil_timerclear(&tv_timeout);
tv_timeout.tv_sec = 60;
for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
long fd = i < num_pipes - 1 ? cp[3] : -1;
event_set(&events[i], cp[0], EV_READ, read_cb, (void *) fd);
event_add(&events[i], &tv_timeout);
}
fired = 0;
/* kick everything off with a single write */
send(pipes[1], "e", 1, 0);
event_dispatch();
gettimeofday(&te, NULL);
evutil_timersub(&te, &ts, &te);
for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
event_del(&events[i]);
close(cp[0]);
close(cp[1]);
}
free(pipes);
free(events);
return (&te);
}
int
main(int argc, char **argv)
{
#ifndef WIN32
struct rlimit rl;
#endif
int i, c;
struct timeval *tv;
int num_pipes = 100;
while ((c = getopt(argc, argv, "n:")) != -1) {
switch (c) {
case 'n':
num_pipes = atoi(optarg);
break;
default:
fprintf(stderr, "Illegal argument \"%c\"\n", c);
exit(1);
}
}
#ifndef WIN32
rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50;
if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
perror("setrlimit");
exit(1);
}
#endif
event_init();
for (i = 0; i < 25; i++) {
tv = run_once(num_pipes);
if (tv == NULL)
exit(1);
fprintf(stdout, "%ld\n",
tv->tv_sec * 1000000L + tv->tv_usec);
}
exit(0);
}

Просмотреть файл

@ -1,179 +0,0 @@
/*
* Copyright 2008-2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "event2/event-config.h"
#include <sys/types.h>
#include <sys/stat.h>
#ifdef WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <unistd.h>
#endif
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <event.h>
#include <evutil.h>
#include <evhttp.h>
#include <event2/thread.h>
#ifdef WIN32
#include "iocp-internal.h"
#endif
static void http_basic_cb(struct evhttp_request *req, void *arg);
static char *content;
static size_t content_len = 0;
static void
http_basic_cb(struct evhttp_request *req, void *arg)
{
struct evbuffer *evb = evbuffer_new();
evbuffer_add(evb, content, content_len);
/* allow sending of an empty reply */
evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
evbuffer_free(evb);
}
/* cheasy way of detecting evbuffer_add_reference */
#ifdef _EVENT2_EVENT_H_
static void
http_ref_cb(struct evhttp_request *req, void *arg)
{
struct evbuffer *evb = evbuffer_new();
evbuffer_add_reference(evb, content, content_len, NULL, NULL);
/* allow sending of an empty reply */
evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
evbuffer_free(evb);
}
#endif
int
main(int argc, char **argv)
{
struct event_base *base;
struct evhttp *http;
int i;
int c;
int use_iocp = 0;
unsigned short port = 8080;
#ifdef WIN32
WSADATA WSAData;
WSAStartup(0x101, &WSAData);
#else
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
return (1);
#endif
base = event_base_new();
for (i = 1; i < argc; ++i) {
if (*argv[i] != '-')
continue;
c = argv[i][1];
if ((c == 'p' || c == 'l') && i + 1 >= argc) {
fprintf(stderr, "-%c requires argument.\n", c);
exit(1);
}
switch (c) {
case 'p':
port = atoi(argv[i+1]);
break;
case 'l':
content_len = atol(argv[i+1]);
if (content_len == 0) {
fprintf(stderr, "Bad content length\n");
exit(1);
}
break;
#ifdef WIN32
case 'i':
use_iocp = 1;
evthread_use_windows_threads();
event_base_start_iocp(base, 0);
break;
#endif
default:
fprintf(stderr, "Illegal argument \"%c\"\n", c);
exit(1);
}
}
http = evhttp_new(base);
content = malloc(content_len);
if (content == NULL) {
fprintf(stderr, "Cannot allocate content\n");
exit(1);
} else {
int i = 0;
for (i = 0; i < content_len; ++i)
content[i] = (i & 255);
}
evhttp_set_cb(http, "/ind", http_basic_cb, NULL);
fprintf(stderr, "/ind - basic content (memory copy)\n");
#ifdef _EVENT2_EVENT_H_
evhttp_set_cb(http, "/ref", http_ref_cb, NULL);
fprintf(stderr, "/ref - basic content (reference)\n");
#endif
fprintf(stderr, "Serving %d bytes on port %d using %s\n",
(int)content_len, port,
use_iocp? "IOCP" : event_base_get_method(base));
evhttp_bind_socket(http, "0.0.0.0", port);
if (use_iocp) {
struct timeval tv={99999999,0};
event_base_loopexit(base, &tv);
}
event_base_dispatch(base);
/* NOTREACHED */
return (0);
}

Просмотреть файл

@ -1,208 +0,0 @@
/*
* Copyright 2009-2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/types.h>
#ifdef WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#include <stdlib.h>
#include <errno.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/util.h>
/* for EVUTIL_ERR_CONNECT_RETRIABLE macro */
#include "util-internal.h"
const char *resource = NULL;
struct event_base *base = NULL;
int total_n_handled = 0;
int total_n_errors = 0;
int total_n_launched = 0;
size_t total_n_bytes = 0;
struct timeval total_time = {0,0};
int n_errors = 0;
const int PARALLELISM = 200;
const int N_REQUESTS = 20000;
struct request_info {
size_t n_read;
struct timeval started;
};
static int launch_request(void);
static void readcb(struct bufferevent *b, void *arg);
static void errorcb(struct bufferevent *b, short what, void *arg);
static void
readcb(struct bufferevent *b, void *arg)
{
struct request_info *ri = arg;
struct evbuffer *input = bufferevent_get_input(b);
size_t n = evbuffer_get_length(input);
ri->n_read += n;
evbuffer_drain(input, n);
}
static void
errorcb(struct bufferevent *b, short what, void *arg)
{
struct request_info *ri = arg;
struct timeval now, diff;
if (what & BEV_EVENT_EOF) {
++total_n_handled;
total_n_bytes += ri->n_read;
gettimeofday(&now, NULL);
evutil_timersub(&now, &ri->started, &diff);
evutil_timeradd(&diff, &total_time, &total_time);
if (total_n_handled && (total_n_handled%1000)==0)
printf("%d requests done\n",total_n_handled);
if (total_n_launched < N_REQUESTS) {
if (launch_request() < 0)
perror("Can't launch");
}
} else {
++total_n_errors;
perror("Unexpected error");
}
bufferevent_setcb(b, NULL, NULL, NULL, NULL);
free(ri);
bufferevent_disable(b, EV_READ|EV_WRITE);
bufferevent_free(b);
}
static void
frob_socket(evutil_socket_t sock)
{
struct linger l;
int one = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&one, sizeof(one));
l.l_onoff = 1;
l.l_linger = 0;
if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&l, sizeof(l))<0)
perror("setsockopt");
}
static int
launch_request(void)
{
evutil_socket_t sock;
struct sockaddr_in sin;
struct bufferevent *b;
struct request_info *ri;
++total_n_launched;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(0x7f000001);
sin.sin_port = htons(8080);
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return -1;
if (evutil_make_socket_nonblocking(sock) < 0)
return -1;
frob_socket(sock);
if (connect(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
int e = errno;
if (! EVUTIL_ERR_CONNECT_RETRIABLE(e)) {
return -1;
}
}
ri = malloc(sizeof(*ri));
ri->n_read = 0;
gettimeofday(&ri->started, NULL);
b = bufferevent_socket_new(base, sock, BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(b, readcb, NULL, errorcb, ri);
bufferevent_enable(b, EV_READ|EV_WRITE);
evbuffer_add_printf(bufferevent_get_output(b),
"GET %s HTTP/1.0\r\n\r\n", resource);
return 0;
}
int
main(int argc, char **argv)
{
int i;
struct timeval start, end, total;
long long usec;
double throughput;
resource = "/ref";
setvbuf(stdout, NULL, _IONBF, 0);
base = event_base_new();
for (i=0; i < PARALLELISM; ++i) {
if (launch_request() < 0)
perror("launch");
}
gettimeofday(&start, NULL);
event_base_dispatch(base);
gettimeofday(&end, NULL);
evutil_timersub(&end, &start, &total);
usec = total_time.tv_sec * 1000000 + total_time.tv_usec;
if (!total_n_handled) {
puts("Nothing worked. You probably did something dumb.");
return 0;
}
throughput = total_n_handled /
(total.tv_sec+ ((double)total.tv_usec)/1000000.0);
printf("\n%d requests in %d.%06d sec. (%.2f throughput)\n"
"Each took about %.02f msec latency\n"
"%lld bytes read. %d errors.\n",
total_n_handled,
(int)total.tv_sec, (int)total.tv_usec,
throughput,
(double)(usec/1000) / total_n_handled,
(long long)total_n_bytes, n_errors);
return 0;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,207 +0,0 @@
/*
* Automatically generated from ./regress.rpc
*/
#ifndef ___REGRESS_RPC_
#define ___REGRESS_RPC_
#include <event2/util.h> /* for ev_uint*_t */
#include <event2/rpc.h>
struct msg;
struct kill;
struct run;
/* Tag definition for msg */
enum msg_ {
MSG_FROM_NAME=1,
MSG_TO_NAME=2,
MSG_ATTACK=3,
MSG_RUN=4,
MSG_MAX_TAGS
};
/* Structure declaration for msg */
struct msg_access_ {
int (*from_name_assign)(struct msg *, const char *);
int (*from_name_get)(struct msg *, char * *);
int (*to_name_assign)(struct msg *, const char *);
int (*to_name_get)(struct msg *, char * *);
int (*attack_assign)(struct msg *, const struct kill*);
int (*attack_get)(struct msg *, struct kill* *);
int (*run_assign)(struct msg *, int, const struct run*);
int (*run_get)(struct msg *, int, struct run* *);
struct run* (*run_add)(struct msg *msg);
};
struct msg {
struct msg_access_ *base;
char *from_name_data;
char *to_name_data;
struct kill* attack_data;
struct run* *run_data;
int run_length;
int run_num_allocated;
ev_uint8_t from_name_set;
ev_uint8_t to_name_set;
ev_uint8_t attack_set;
ev_uint8_t run_set;
};
struct msg *msg_new(void);
struct msg *msg_new_with_arg(void *);
void msg_free(struct msg *);
void msg_clear(struct msg *);
void msg_marshal(struct evbuffer *, const struct msg *);
int msg_unmarshal(struct msg *, struct evbuffer *);
int msg_complete(struct msg *);
void evtag_marshal_msg(struct evbuffer *, ev_uint32_t,
const struct msg *);
int evtag_unmarshal_msg(struct evbuffer *, ev_uint32_t,
struct msg *);
int msg_from_name_assign(struct msg *, const char *);
int msg_from_name_get(struct msg *, char * *);
int msg_to_name_assign(struct msg *, const char *);
int msg_to_name_get(struct msg *, char * *);
int msg_attack_assign(struct msg *, const struct kill*);
int msg_attack_get(struct msg *, struct kill* *);
int msg_run_assign(struct msg *, int, const struct run*);
int msg_run_get(struct msg *, int, struct run* *);
struct run* msg_run_add(struct msg *msg);
/* --- msg done --- */
/* Tag definition for kill */
enum kill_ {
KILL_WEAPON=65825,
KILL_ACTION=2,
KILL_HOW_OFTEN=3,
KILL_MAX_TAGS
};
/* Structure declaration for kill */
struct kill_access_ {
int (*weapon_assign)(struct kill *, const char *);
int (*weapon_get)(struct kill *, char * *);
int (*action_assign)(struct kill *, const char *);
int (*action_get)(struct kill *, char * *);
int (*how_often_assign)(struct kill *, int, const ev_uint32_t);
int (*how_often_get)(struct kill *, int, ev_uint32_t *);
ev_uint32_t * (*how_often_add)(struct kill *msg, const ev_uint32_t value);
};
struct kill {
struct kill_access_ *base;
char *weapon_data;
char *action_data;
ev_uint32_t *how_often_data;
int how_often_length;
int how_often_num_allocated;
ev_uint8_t weapon_set;
ev_uint8_t action_set;
ev_uint8_t how_often_set;
};
struct kill *kill_new(void);
struct kill *kill_new_with_arg(void *);
void kill_free(struct kill *);
void kill_clear(struct kill *);
void kill_marshal(struct evbuffer *, const struct kill *);
int kill_unmarshal(struct kill *, struct evbuffer *);
int kill_complete(struct kill *);
void evtag_marshal_kill(struct evbuffer *, ev_uint32_t,
const struct kill *);
int evtag_unmarshal_kill(struct evbuffer *, ev_uint32_t,
struct kill *);
int kill_weapon_assign(struct kill *, const char *);
int kill_weapon_get(struct kill *, char * *);
int kill_action_assign(struct kill *, const char *);
int kill_action_get(struct kill *, char * *);
int kill_how_often_assign(struct kill *, int, const ev_uint32_t);
int kill_how_often_get(struct kill *, int, ev_uint32_t *);
ev_uint32_t * kill_how_often_add(struct kill *msg, const ev_uint32_t value);
/* --- kill done --- */
/* Tag definition for run */
enum run_ {
RUN_HOW=1,
RUN_SOME_BYTES=2,
RUN_FIXED_BYTES=3,
RUN_NOTES=4,
RUN_LARGE_NUMBER=5,
RUN_OTHER_NUMBERS=6,
RUN_MAX_TAGS
};
/* Structure declaration for run */
struct run_access_ {
int (*how_assign)(struct run *, const char *);
int (*how_get)(struct run *, char * *);
int (*some_bytes_assign)(struct run *, const ev_uint8_t *, ev_uint32_t);
int (*some_bytes_get)(struct run *, ev_uint8_t * *, ev_uint32_t *);
int (*fixed_bytes_assign)(struct run *, const ev_uint8_t *);
int (*fixed_bytes_get)(struct run *, ev_uint8_t **);
int (*notes_assign)(struct run *, int, const char *);
int (*notes_get)(struct run *, int, char * *);
char * * (*notes_add)(struct run *msg, const char * value);
int (*large_number_assign)(struct run *, const ev_uint64_t);
int (*large_number_get)(struct run *, ev_uint64_t *);
int (*other_numbers_assign)(struct run *, int, const ev_uint32_t);
int (*other_numbers_get)(struct run *, int, ev_uint32_t *);
ev_uint32_t * (*other_numbers_add)(struct run *msg, const ev_uint32_t value);
};
struct run {
struct run_access_ *base;
char *how_data;
ev_uint8_t *some_bytes_data;
ev_uint32_t some_bytes_length;
ev_uint8_t fixed_bytes_data[24];
char * *notes_data;
int notes_length;
int notes_num_allocated;
ev_uint64_t large_number_data;
ev_uint32_t *other_numbers_data;
int other_numbers_length;
int other_numbers_num_allocated;
ev_uint8_t how_set;
ev_uint8_t some_bytes_set;
ev_uint8_t fixed_bytes_set;
ev_uint8_t notes_set;
ev_uint8_t large_number_set;
ev_uint8_t other_numbers_set;
};
struct run *run_new(void);
struct run *run_new_with_arg(void *);
void run_free(struct run *);
void run_clear(struct run *);
void run_marshal(struct evbuffer *, const struct run *);
int run_unmarshal(struct run *, struct evbuffer *);
int run_complete(struct run *);
void evtag_marshal_run(struct evbuffer *, ev_uint32_t,
const struct run *);
int evtag_unmarshal_run(struct evbuffer *, ev_uint32_t,
struct run *);
int run_how_assign(struct run *, const char *);
int run_how_get(struct run *, char * *);
int run_some_bytes_assign(struct run *, const ev_uint8_t *, ev_uint32_t);
int run_some_bytes_get(struct run *, ev_uint8_t * *, ev_uint32_t *);
int run_fixed_bytes_assign(struct run *, const ev_uint8_t *);
int run_fixed_bytes_get(struct run *, ev_uint8_t **);
int run_notes_assign(struct run *, int, const char *);
int run_notes_get(struct run *, int, char * *);
char * * run_notes_add(struct run *msg, const char * value);
int run_large_number_assign(struct run *, const ev_uint64_t);
int run_large_number_get(struct run *, ev_uint64_t *);
int run_other_numbers_assign(struct run *, int, const ev_uint32_t);
int run_other_numbers_get(struct run *, int, ev_uint32_t *);
ev_uint32_t * run_other_numbers_add(struct run *msg, const ev_uint32_t value);
/* --- run done --- */
#endif /* ___REGRESS_RPC_ */

Просмотреть файл

@ -1,125 +0,0 @@
/*
* Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
* Copyright (c) 2007-2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _REGRESS_H_
#define _REGRESS_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "tinytest.h"
#include "tinytest_macros.h"
extern struct testcase_t main_testcases[];
extern struct testcase_t evtag_testcases[];
extern struct testcase_t evbuffer_testcases[];
extern struct testcase_t bufferevent_testcases[];
extern struct testcase_t bufferevent_iocp_testcases[];
extern struct testcase_t util_testcases[];
extern struct testcase_t signal_testcases[];
extern struct testcase_t http_testcases[];
extern struct testcase_t dns_testcases[];
extern struct testcase_t rpc_testcases[];
extern struct testcase_t edgetriggered_testcases[];
extern struct testcase_t minheap_testcases[];
extern struct testcase_t iocp_testcases[];
extern struct testcase_t ssl_testcases[];
extern struct testcase_t listener_testcases[];
extern struct testcase_t listener_iocp_testcases[];
extern struct testcase_t thread_testcases[];
void regress_threads(void *);
void test_bufferevent_zlib(void *);
/* Helpers to wrap old testcases */
extern int pair[2];
extern int test_ok;
extern int called;
extern struct event_base *global_base;
extern int in_legacy_test_wrapper;
evutil_socket_t regress_make_tmpfile(const void *data, size_t datalen);
struct basic_test_data {
struct event_base *base;
int pair[2];
void (*legacy_test_fn)(void);
void *setup_data;
};
extern const struct testcase_setup_t basic_setup;
extern const struct testcase_setup_t legacy_setup;
void run_legacy_test_fn(void *ptr);
/* A couple of flags that basic/legacy_setup can support. */
#define TT_NEED_SOCKETPAIR TT_FIRST_USER_FLAG
#define TT_NEED_BASE (TT_FIRST_USER_FLAG<<1)
#define TT_NEED_DNS (TT_FIRST_USER_FLAG<<2)
#define TT_LEGACY (TT_FIRST_USER_FLAG<<3)
#define TT_NEED_THREADS (TT_FIRST_USER_FLAG<<4)
#define TT_NO_LOGS (TT_FIRST_USER_FLAG<<5)
#define TT_ENABLE_IOCP_FLAG (TT_FIRST_USER_FLAG<<6)
#define TT_ENABLE_IOCP (TT_ENABLE_IOCP_FLAG|TT_NEED_THREADS)
/* All the flags that a legacy test needs. */
#define TT_ISOLATED TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE
#define BASIC(name,flags) \
{ #name, test_## name, flags, &basic_setup, NULL }
#define LEGACY(name,flags) \
{ #name, run_legacy_test_fn, flags|TT_LEGACY, &legacy_setup, \
test_## name }
struct evutil_addrinfo;
struct evutil_addrinfo *ai_find_by_family(struct evutil_addrinfo *ai, int f);
struct evutil_addrinfo *ai_find_by_protocol(struct evutil_addrinfo *ai, int p);
int _test_ai_eq(const struct evutil_addrinfo *ai, const char *sockaddr_port,
int socktype, int protocol, int line);
#define test_ai_eq(ai, str, s, p) do { \
if (_test_ai_eq((ai), (str), (s), (p), __LINE__)<0) \
goto end; \
} while (0)
#define test_timeval_diff_leq(tv1, tv2, diff, tolerance) \
tt_int_op(abs(timeval_msec_diff((tv1), (tv2)) - diff), <=, tolerance)
#define test_timeval_diff_eq(tv1, tv2, diff) \
test_timeval_diff_leq((tv1), (tv2), (diff), 50)
long timeval_msec_diff(const struct timeval *start, const struct timeval *end);
#ifdef __cplusplus
}
#endif
#endif /* _REGRESS_H_ */

Просмотреть файл

@ -1,25 +0,0 @@
/* tests data packing and unpacking */
struct msg {
string /* sender */ from_name = 1; /* be verbose */
string to_name = 2;
optional struct[kill] attack = 3;
array struct[run] run = 4;
}
struct kill {
string weapon = 0x10121;
string action = 2;
array int how_often = 3;
}
struct run {
string how = 1;
optional bytes some_bytes = 2;
bytes fixed_bytes[24] = 3;
array string notes = 4;
optional int64 large_number = 5;
array int other_numbers = 6;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,835 +0,0 @@
/*
* Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
* Copyright (c) 2007-2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* The old tests here need assertions to work. */
#undef NDEBUG
#ifdef WIN32
#include <winsock2.h>
#include <windows.h>
#endif
#include "event2/event-config.h"
#include <sys/types.h>
#include <sys/stat.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <sys/queue.h>
#ifndef WIN32
#include <sys/socket.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#endif
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#ifdef _EVENT_HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include "event2/event-config.h"
#include "event2/event.h"
#include "event2/event_struct.h"
#include "event2/event_compat.h"
#include "event2/tag.h"
#include "event2/buffer.h"
#include "event2/bufferevent.h"
#include "event2/bufferevent_compat.h"
#include "event2/bufferevent_struct.h"
#include "event2/listener.h"
#include "event2/util.h"
#include "bufferevent-internal.h"
#ifdef WIN32
#include "iocp-internal.h"
#endif
#include "regress.h"
#include "regress_testutils.h"
/*
* simple bufferevent test
*/
static void
readcb(struct bufferevent *bev, void *arg)
{
if (evbuffer_get_length(bev->input) == 8333) {
struct evbuffer *evbuf = evbuffer_new();
assert(evbuf != NULL);
/* gratuitous test of bufferevent_read_buffer */
bufferevent_read_buffer(bev, evbuf);
bufferevent_disable(bev, EV_READ);
if (evbuffer_get_length(evbuf) == 8333) {
test_ok++;
}
evbuffer_free(evbuf);
}
}
static void
writecb(struct bufferevent *bev, void *arg)
{
if (evbuffer_get_length(bev->output) == 0) {
test_ok++;
}
}
static void
errorcb(struct bufferevent *bev, short what, void *arg)
{
test_ok = -2;
}
static void
test_bufferevent_impl(int use_pair)
{
struct bufferevent *bev1 = NULL, *bev2 = NULL;
char buffer[8333];
int i;
if (use_pair) {
struct bufferevent *pair[2];
tt_assert(0 == bufferevent_pair_new(NULL, 0, pair));
bev1 = pair[0];
bev2 = pair[1];
bufferevent_setcb(bev1, readcb, writecb, errorcb, NULL);
bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL);
tt_int_op(bufferevent_getfd(bev1), ==, -1);
tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL);
tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, bev2);
tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, bev1);
} else {
bev1 = bufferevent_new(pair[0], readcb, writecb, errorcb, NULL);
bev2 = bufferevent_new(pair[1], readcb, writecb, errorcb, NULL);
tt_int_op(bufferevent_getfd(bev1), ==, pair[0]);
tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL);
tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL);
tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, NULL);
}
bufferevent_disable(bev1, EV_READ);
bufferevent_enable(bev2, EV_READ);
tt_int_op(bufferevent_get_enabled(bev1), ==, EV_WRITE);
tt_int_op(bufferevent_get_enabled(bev2), ==, EV_WRITE|EV_READ);
for (i = 0; i < sizeof(buffer); i++)
buffer[i] = i;
bufferevent_write(bev1, buffer, sizeof(buffer));
event_dispatch();
bufferevent_free(bev1);
tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, NULL);
bufferevent_free(bev2);
if (test_ok != 2)
test_ok = 0;
end:
;
}
static void
test_bufferevent(void)
{
test_bufferevent_impl(0);
}
static void
test_bufferevent_pair(void)
{
test_bufferevent_impl(1);
}
/*
* test watermarks and bufferevent
*/
static void
wm_readcb(struct bufferevent *bev, void *arg)
{
struct evbuffer *evbuf = evbuffer_new();
int len = evbuffer_get_length(bev->input);
static int nread;
assert(len >= 10 && len <= 20);
assert(evbuf != NULL);
/* gratuitous test of bufferevent_read_buffer */
bufferevent_read_buffer(bev, evbuf);
nread += len;
if (nread == 65000) {
bufferevent_disable(bev, EV_READ);
test_ok++;
}
evbuffer_free(evbuf);
}
static void
wm_writecb(struct bufferevent *bev, void *arg)
{
assert(evbuffer_get_length(bev->output) <= 100);
if (evbuffer_get_length(bev->output) == 0) {
evbuffer_drain(bev->output, evbuffer_get_length(bev->output));
test_ok++;
}
}
static void
wm_errorcb(struct bufferevent *bev, short what, void *arg)
{
test_ok = -2;
}
static void
test_bufferevent_watermarks_impl(int use_pair)
{
struct bufferevent *bev1 = NULL, *bev2 = NULL;
char buffer[65000];
int i;
test_ok = 0;
if (use_pair) {
struct bufferevent *pair[2];
tt_assert(0 == bufferevent_pair_new(NULL, 0, pair));
bev1 = pair[0];
bev2 = pair[1];
bufferevent_setcb(bev1, NULL, wm_writecb, errorcb, NULL);
bufferevent_setcb(bev2, wm_readcb, NULL, errorcb, NULL);
} else {
bev1 = bufferevent_new(pair[0], NULL, wm_writecb, wm_errorcb, NULL);
bev2 = bufferevent_new(pair[1], wm_readcb, NULL, wm_errorcb, NULL);
}
bufferevent_disable(bev1, EV_READ);
bufferevent_enable(bev2, EV_READ);
for (i = 0; i < sizeof(buffer); i++)
buffer[i] = (char)i;
/* limit the reading on the receiving bufferevent */
bufferevent_setwatermark(bev2, EV_READ, 10, 20);
/* Tell the sending bufferevent not to notify us till it's down to
100 bytes. */
bufferevent_setwatermark(bev1, EV_WRITE, 100, 2000);
bufferevent_write(bev1, buffer, sizeof(buffer));
event_dispatch();
tt_int_op(test_ok, ==, 2);
/* The write callback drained all the data from outbuf, so we
* should have removed the write event... */
tt_assert(!event_pending(&bev2->ev_write, EV_WRITE, NULL));
end:
bufferevent_free(bev1);
bufferevent_free(bev2);
}
static void
test_bufferevent_watermarks(void)
{
test_bufferevent_watermarks_impl(0);
}
static void
test_bufferevent_pair_watermarks(void)
{
test_bufferevent_watermarks_impl(1);
}
/*
* Test bufferevent filters
*/
/* strip an 'x' from each byte */
static enum bufferevent_filter_result
bufferevent_input_filter(struct evbuffer *src, struct evbuffer *dst,
ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
{
const unsigned char *buffer;
unsigned i;
buffer = evbuffer_pullup(src, evbuffer_get_length(src));
for (i = 0; i < evbuffer_get_length(src); i += 2) {
assert(buffer[i] == 'x');
evbuffer_add(dst, buffer + i + 1, 1);
if (i + 2 > evbuffer_get_length(src))
break;
}
evbuffer_drain(src, i);
return (BEV_OK);
}
/* add an 'x' before each byte */
static enum bufferevent_filter_result
bufferevent_output_filter(struct evbuffer *src, struct evbuffer *dst,
ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
{
const unsigned char *buffer;
unsigned i;
buffer = evbuffer_pullup(src, evbuffer_get_length(src));
for (i = 0; i < evbuffer_get_length(src); ++i) {
evbuffer_add(dst, "x", 1);
evbuffer_add(dst, buffer + i, 1);
}
evbuffer_drain(src, evbuffer_get_length(src));
return (BEV_OK);
}
static void
test_bufferevent_filters_impl(int use_pair)
{
struct bufferevent *bev1 = NULL, *bev2 = NULL;
struct bufferevent *bev1_base = NULL, *bev2_base = NULL;
char buffer[8333];
int i;
test_ok = 0;
if (use_pair) {
struct bufferevent *pair[2];
tt_assert(0 == bufferevent_pair_new(NULL, 0, pair));
bev1 = pair[0];
bev2 = pair[1];
} else {
bev1 = bufferevent_socket_new(NULL, pair[0], 0);
bev2 = bufferevent_socket_new(NULL, pair[1], 0);
}
bev1_base = bev1;
bev2_base = bev2;
for (i = 0; i < sizeof(buffer); i++)
buffer[i] = i;
bev1 = bufferevent_filter_new(bev1, NULL, bufferevent_output_filter,
BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
bev2 = bufferevent_filter_new(bev2, bufferevent_input_filter,
NULL, BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
bufferevent_setcb(bev1, NULL, writecb, errorcb, NULL);
bufferevent_setcb(bev2, readcb, NULL, errorcb, NULL);
tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev1_base);
tt_ptr_op(bufferevent_get_underlying(bev2), ==, bev2_base);
tt_int_op(bufferevent_getfd(bev1), ==, -1);
tt_int_op(bufferevent_getfd(bev2), ==, -1);
bufferevent_disable(bev1, EV_READ);
bufferevent_enable(bev2, EV_READ);
/* insert some filters */
bufferevent_write(bev1, buffer, sizeof(buffer));
event_dispatch();
if (test_ok != 2)
test_ok = 0;
end:
bufferevent_free(bev1);
bufferevent_free(bev2);
}
static void
test_bufferevent_filters(void)
{
test_bufferevent_filters_impl(0);
}
static void
test_bufferevent_pair_filters(void)
{
test_bufferevent_filters_impl(1);
}
static void
sender_writecb(struct bufferevent *bev, void *ctx)
{
if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
bufferevent_disable(bev,EV_READ|EV_WRITE);
bufferevent_free(bev);
}
}
static void
sender_errorcb(struct bufferevent *bev, short what, void *ctx)
{
TT_FAIL(("Got sender error %d",(int)what));
}
static int bufferevent_connect_test_flags = 0;
static int n_strings_read = 0;
static int n_reads_invoked = 0;
#define TEST_STR "Now is the time for all good events to signal for " \
"the good of their protocol"
static void
listen_cb(struct evconnlistener *listener, evutil_socket_t fd,
struct sockaddr *sa, int socklen, void *arg)
{
struct event_base *base = arg;
struct bufferevent *bev;
const char s[] = TEST_STR;
TT_BLATHER(("Got a request on socket %d", (int)fd ));
bev = bufferevent_socket_new(base, fd, bufferevent_connect_test_flags);
tt_assert(bev);
bufferevent_setcb(bev, NULL, sender_writecb, sender_errorcb, NULL);
bufferevent_write(bev, s, sizeof(s));
end:
;
}
static void
reader_eventcb(struct bufferevent *bev, short what, void *ctx)
{
struct event_base *base = ctx;
if (what & BEV_EVENT_ERROR) {
perror("foobar");
TT_FAIL(("got connector error %d", (int)what));
return;
}
if (what & BEV_EVENT_CONNECTED) {
bufferevent_enable(bev, EV_READ);
}
if (what & BEV_EVENT_EOF) {
char buf[512];
size_t n;
n = bufferevent_read(bev, buf, sizeof(buf)-1);
buf[n] = '\0';
tt_str_op(buf, ==, TEST_STR);
if (++n_strings_read == 2)
event_base_loopexit(base, NULL);
}
end:
;
}
static void
reader_readcb(struct bufferevent *bev, void *ctx)
{
n_reads_invoked++;
}
static void
test_bufferevent_connect(void *arg)
{
struct basic_test_data *data = arg;
struct evconnlistener *lev=NULL;
struct bufferevent *bev1=NULL, *bev2=NULL;
struct sockaddr_in localhost;
struct sockaddr_storage ss;
struct sockaddr *sa;
ev_socklen_t slen;
int be_flags=BEV_OPT_CLOSE_ON_FREE;
if (strstr((char*)data->setup_data, "defer")) {
be_flags |= BEV_OPT_DEFER_CALLBACKS;
}
if (strstr((char*)data->setup_data, "unlocked")) {
be_flags |= BEV_OPT_UNLOCK_CALLBACKS;
}
if (strstr((char*)data->setup_data, "lock")) {
be_flags |= BEV_OPT_THREADSAFE;
}
bufferevent_connect_test_flags = be_flags;
#ifdef WIN32
if (!strcmp((char*)data->setup_data, "unset_connectex")) {
struct win32_extension_fns *ext =
(struct win32_extension_fns *)
event_get_win32_extension_fns();
ext->ConnectEx = NULL;
}
#endif
memset(&localhost, 0, sizeof(localhost));
localhost.sin_port = 0; /* pick-a-port */
localhost.sin_addr.s_addr = htonl(0x7f000001L);
localhost.sin_family = AF_INET;
sa = (struct sockaddr *)&localhost;
lev = evconnlistener_new_bind(data->base, listen_cb, data->base,
LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
16, sa, sizeof(localhost));
tt_assert(lev);
sa = (struct sockaddr *)&ss;
slen = sizeof(ss);
if (regress_get_listener_addr(lev, sa, &slen) < 0) {
tt_abort_perror("getsockname");
}
tt_assert(!evconnlistener_enable(lev));
bev1 = bufferevent_socket_new(data->base, -1, be_flags);
bev2 = bufferevent_socket_new(data->base, -1, be_flags);
tt_assert(bev1);
tt_assert(bev2);
bufferevent_setcb(bev1, reader_readcb,NULL, reader_eventcb, data->base);
bufferevent_setcb(bev2, reader_readcb,NULL, reader_eventcb, data->base);
bufferevent_enable(bev1, EV_READ);
bufferevent_enable(bev2, EV_READ);
tt_want(!bufferevent_socket_connect(bev1, sa, sizeof(localhost)));
tt_want(!bufferevent_socket_connect(bev2, sa, sizeof(localhost)));
event_base_dispatch(data->base);
tt_int_op(n_strings_read, ==, 2);
tt_int_op(n_reads_invoked, >=, 2);
end:
if (lev)
evconnlistener_free(lev);
if (bev1)
bufferevent_free(bev1);
if (bev2)
bufferevent_free(bev2);
}
static void
want_fail_eventcb(struct bufferevent *bev, short what, void *ctx)
{
struct event_base *base = ctx;
const char *err;
evutil_socket_t s;
if (what & BEV_EVENT_ERROR) {
s = bufferevent_getfd(bev);
err = evutil_socket_error_to_string(evutil_socket_geterror(s));
TT_BLATHER(("connection failure %s", err));
test_ok = 1;
} else {
TT_FAIL(("didn't fail? what %hd", what));
}
event_base_loopexit(base, NULL);
}
static void
close_socket_cb(evutil_socket_t fd, short what, void *arg)
{
evutil_socket_t *fdp = arg;
if (*fdp >= 0) {
evutil_closesocket(*fdp);
*fdp = -1;
}
}
static void
test_bufferevent_connect_fail(void *arg)
{
struct basic_test_data *data = arg;
struct bufferevent *bev=NULL;
struct sockaddr_in localhost;
struct sockaddr *sa = (struct sockaddr*)&localhost;
evutil_socket_t fake_listener = -1;
ev_socklen_t slen = sizeof(localhost);
struct event close_listener_event;
int close_listener_event_added = 0;
struct timeval one_second = { 1, 0 };
int r;
test_ok = 0;
memset(&localhost, 0, sizeof(localhost));
localhost.sin_port = 0; /* have the kernel pick a port */
localhost.sin_addr.s_addr = htonl(0x7f000001L);
localhost.sin_family = AF_INET;
/* bind, but don't listen or accept. should trigger
"Connection refused" reliably on most platforms. */
fake_listener = socket(localhost.sin_family, SOCK_STREAM, 0);
tt_assert(fake_listener >= 0);
tt_assert(bind(fake_listener, sa, slen) == 0);
tt_assert(getsockname(fake_listener, sa, &slen) == 0);
bev = bufferevent_socket_new(data->base, -1,
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
tt_assert(bev);
bufferevent_setcb(bev, NULL, NULL, want_fail_eventcb, data->base);
r = bufferevent_socket_connect(bev, sa, slen);
/* XXXX we'd like to test the '0' case everywhere, but FreeBSD tells
* detects the error immediately, which is not really wrong of it. */
tt_want(r == 0 || r == -1);
/* Close the listener socket after a second. This should trigger
"connection refused" on some other platforms, including OSX. */
evtimer_assign(&close_listener_event, data->base, close_socket_cb,
&fake_listener);
event_add(&close_listener_event, &one_second);
close_listener_event_added = 1;
event_base_dispatch(data->base);
tt_int_op(test_ok, ==, 1);
end:
if (fake_listener >= 0)
evutil_closesocket(fake_listener);
if (bev)
bufferevent_free(bev);
if (close_listener_event_added)
event_del(&close_listener_event);
}
struct timeout_cb_result {
struct timeval read_timeout_at;
struct timeval write_timeout_at;
struct timeval last_wrote_at;
int n_read_timeouts;
int n_write_timeouts;
int total_calls;
};
static void
bev_timeout_write_cb(struct bufferevent *bev, void *arg)
{
struct timeout_cb_result *res = arg;
evutil_gettimeofday(&res->last_wrote_at, NULL);
}
static void
bev_timeout_event_cb(struct bufferevent *bev, short what, void *arg)
{
struct timeout_cb_result *res = arg;
++res->total_calls;
if ((what & (BEV_EVENT_READING|BEV_EVENT_TIMEOUT))
== (BEV_EVENT_READING|BEV_EVENT_TIMEOUT)) {
evutil_gettimeofday(&res->read_timeout_at, NULL);
++res->n_read_timeouts;
}
if ((what & (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT))
== (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT)) {
evutil_gettimeofday(&res->write_timeout_at, NULL);
++res->n_write_timeouts;
}
}
static void
test_bufferevent_timeouts(void *arg)
{
/* "arg" is a string containing "pair" and/or "filter". */
struct bufferevent *bev1 = NULL, *bev2 = NULL;
struct basic_test_data *data = arg;
int use_pair = 0, use_filter = 0;
struct timeval tv_w, tv_r, started_at;
struct timeout_cb_result res1, res2;
char buf[1024];
memset(&res1, 0, sizeof(res1));
memset(&res2, 0, sizeof(res2));
if (strstr((char*)data->setup_data, "pair"))
use_pair = 1;
if (strstr((char*)data->setup_data, "filter"))
use_filter = 1;
if (use_pair) {
struct bufferevent *p[2];
tt_int_op(0, ==, bufferevent_pair_new(data->base, 0, p));
bev1 = p[0];
bev2 = p[1];
} else {
bev1 = bufferevent_socket_new(data->base, data->pair[0], 0);
bev2 = bufferevent_socket_new(data->base, data->pair[1], 0);
}
tt_assert(bev1);
tt_assert(bev2);
if (use_filter) {
struct bufferevent *bevf1, *bevf2;
bevf1 = bufferevent_filter_new(bev1, NULL, NULL,
BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
bevf2 = bufferevent_filter_new(bev2, NULL, NULL,
BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
tt_assert(bevf1);
tt_assert(bevf2);
bev1 = bevf1;
bev2 = bevf2;
}
/* Do this nice and early. */
bufferevent_disable(bev2, EV_READ);
/* bev1 will try to write and read. Both will time out. */
evutil_gettimeofday(&started_at, NULL);
tv_w.tv_sec = tv_r.tv_sec = 0;
tv_w.tv_usec = 100*1000;
tv_r.tv_usec = 150*1000;
bufferevent_setcb(bev1, NULL, bev_timeout_write_cb,
bev_timeout_event_cb, &res1);
bufferevent_setwatermark(bev1, EV_WRITE, 1024*1024+10, 0);
bufferevent_set_timeouts(bev1, &tv_r, &tv_w);
if (use_pair) {
/* For a pair, the fact that the other side isn't reading
* makes the writer stall */
bufferevent_write(bev1, "ABCDEFG", 7);
} else {
/* For a real socket, the kernel's TCP buffers can eat a
* fair number of bytes; make sure that at some point we
* have some bytes that will stall. */
struct evbuffer *output = bufferevent_get_output(bev1);
int i;
memset(buf, 0xbb, sizeof(buf));
for (i=0;i<1024;++i) {
evbuffer_add_reference(output, buf, sizeof(buf),
NULL, NULL);
}
}
bufferevent_enable(bev1, EV_READ|EV_WRITE);
/* bev2 has nothing to say, and isn't listening. */
bufferevent_setcb(bev2, NULL, bev_timeout_write_cb,
bev_timeout_event_cb, &res2);
tv_w.tv_sec = tv_r.tv_sec = 0;
tv_w.tv_usec = 200*1000;
tv_r.tv_usec = 100*1000;
bufferevent_set_timeouts(bev2, &tv_r, &tv_w);
bufferevent_enable(bev2, EV_WRITE);
tv_r.tv_sec = 1;
tv_r.tv_usec = 0;
event_base_loopexit(data->base, &tv_r);
event_base_dispatch(data->base);
/* XXXX Test that actually reading or writing a little resets the
* timeouts. */
/* Each buf1 timeout happens, and happens only once. */
tt_want(res1.n_read_timeouts);
tt_want(res1.n_write_timeouts);
tt_want(res1.n_read_timeouts == 1);
tt_want(res1.n_write_timeouts == 1);
test_timeval_diff_eq(&started_at, &res1.read_timeout_at, 150);
test_timeval_diff_eq(&started_at, &res1.write_timeout_at, 100);
end:
if (bev1)
bufferevent_free(bev1);
if (bev2)
bufferevent_free(bev2);
}
struct testcase_t bufferevent_testcases[] = {
LEGACY(bufferevent, TT_ISOLATED),
LEGACY(bufferevent_pair, TT_ISOLATED),
LEGACY(bufferevent_watermarks, TT_ISOLATED),
LEGACY(bufferevent_pair_watermarks, TT_ISOLATED),
LEGACY(bufferevent_filters, TT_ISOLATED),
LEGACY(bufferevent_pair_filters, TT_ISOLATED),
{ "bufferevent_connect", test_bufferevent_connect, TT_FORK|TT_NEED_BASE,
&basic_setup, (void*)"" },
{ "bufferevent_connect_defer", test_bufferevent_connect,
TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"defer" },
{ "bufferevent_connect_lock", test_bufferevent_connect,
TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, (void*)"lock" },
{ "bufferevent_connect_lock_defer", test_bufferevent_connect,
TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup,
(void*)"defer lock" },
{ "bufferevent_connect_unlocked_cbs", test_bufferevent_connect,
TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup,
(void*)"lock defer unlocked" },
{ "bufferevent_connect_fail", test_bufferevent_connect_fail,
TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
{ "bufferevent_timeout", test_bufferevent_timeouts,
TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR, &basic_setup, (void*)"" },
{ "bufferevent_timeout_pair", test_bufferevent_timeouts,
TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"pair" },
{ "bufferevent_timeout_filter", test_bufferevent_timeouts,
TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter" },
{ "bufferevent_timeout_filter_pair", test_bufferevent_timeouts,
TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter pair" },
#ifdef _EVENT_HAVE_LIBZ
LEGACY(bufferevent_zlib, TT_ISOLATED),
#else
{ "bufferevent_zlib", NULL, TT_SKIP, NULL, NULL },
#endif
END_OF_TESTCASES,
};
struct testcase_t bufferevent_iocp_testcases[] = {
LEGACY(bufferevent, TT_ISOLATED|TT_ENABLE_IOCP),
LEGACY(bufferevent_watermarks, TT_ISOLATED|TT_ENABLE_IOCP),
LEGACY(bufferevent_filters, TT_ISOLATED|TT_ENABLE_IOCP),
{ "bufferevent_connect", test_bufferevent_connect,
TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, (void*)"" },
{ "bufferevent_connect_defer", test_bufferevent_connect,
TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, (void*)"defer" },
{ "bufferevent_connect_lock", test_bufferevent_connect,
TT_FORK|TT_NEED_BASE|TT_NEED_THREADS|TT_ENABLE_IOCP, &basic_setup,
(void*)"lock" },
{ "bufferevent_connect_lock_defer", test_bufferevent_connect,
TT_FORK|TT_NEED_BASE|TT_NEED_THREADS|TT_ENABLE_IOCP, &basic_setup,
(void*)"defer lock" },
{ "bufferevent_connect_fail", test_bufferevent_connect_fail,
TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL },
{ "bufferevent_connect_nonblocking", test_bufferevent_connect,
TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup,
(void*)"unset_connectex" },
END_OF_TESTCASES,
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,199 +0,0 @@
/*
* Copyright (c) 2009-2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <event2/event-config.h>
#ifdef WIN32
#include <winsock2.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef _EVENT_HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef WIN32
#include <sys/time.h>
#include <unistd.h>
#endif
#include <errno.h>
#include <event2/event.h>
#include <event2/util.h>
#include "regress.h"
static int was_et = 0;
static void
read_cb(evutil_socket_t fd, short event, void *arg)
{
char buf;
int len;
len = recv(fd, &buf, sizeof(buf), 0);
/*printf("%s: %s %d%s\n", __func__, event & EV_ET ? "etread" : "read",
len, len ? "" : " - means EOF");
*/
called++;
if (event & EV_ET)
was_et = 1;
if (!len)
event_del(arg);
}
#ifndef SHUT_WR
#define SHUT_WR 1
#endif
#ifdef WIN32
#define LOCAL_SOCKETPAIR_AF AF_INET
#else
#define LOCAL_SOCKETPAIR_AF AF_UNIX
#endif
static void
test_edgetriggered(void *et)
{
struct event *ev = NULL;
struct event_base *base = NULL;
const char *test = "test string";
evutil_socket_t pair[2] = {-1,-1};
int supports_et;
int success;
if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair) == -1) {
tt_abort_perror("socketpair");
}
called = was_et = 0;
send(pair[0], test, strlen(test)+1, 0);
shutdown(pair[0], SHUT_WR);
/* Initalize the event library */
base = event_base_new();
if (!strcmp(event_base_get_method(base), "epoll") ||
!strcmp(event_base_get_method(base), "kqueue"))
supports_et = 1;
else
supports_et = 0;
TT_BLATHER(("Checking for edge-triggered events with %s, which should %s"
"support edge-triggering", event_base_get_method(base),
supports_et?"":"not "));
/* Initalize one event */
ev = event_new(base, pair[1], EV_READ|EV_ET|EV_PERSIST, read_cb, &ev);
event_add(ev, NULL);
/* We're going to call the dispatch function twice. The first invocation
* will read a single byte from pair[1] in either case. If we're edge
* triggered, we'll only see the event once (since we only see transitions
* from no data to data), so the second invocation of event_base_loop will
* do nothing. If we're level triggered, the second invocation of
* event_base_loop will also activate the event (because there's still
* data to read). */
event_base_loop(base,EVLOOP_NONBLOCK|EVLOOP_ONCE);
event_base_loop(base,EVLOOP_NONBLOCK|EVLOOP_ONCE);
if (supports_et) {
tt_int_op(called, ==, 1);
tt_assert(was_et);
} else {
tt_int_op(called, ==, 2);
tt_assert(!was_et);
success = (called == 2) && !was_et;
}
end:
if (ev) {
event_del(ev);
event_free(ev);
}
if (base)
event_base_free(base);
evutil_closesocket(pair[0]);
evutil_closesocket(pair[1]);
}
static void
test_edgetriggered_mix_error(void *data_)
{
struct basic_test_data *data = data_;
struct event_base *base = NULL;
struct event *ev_et=NULL, *ev_lt=NULL;
#ifdef _EVENT_DISABLE_DEBUG_MODE
if (1)
tt_skip();
#endif
event_enable_debug_mode();
base = event_base_new();
/* try mixing edge-triggered and level-triggered to make sure it fails*/
ev_et = event_new(base, data->pair[0], EV_READ|EV_ET, read_cb, ev_et);
ev_lt = event_new(base, data->pair[0], EV_READ, read_cb, ev_lt);
/* Add edge-triggered, then level-triggered. Get an error. */
tt_int_op(0, ==, event_add(ev_et, NULL));
tt_int_op(-1, ==, event_add(ev_lt, NULL));
tt_int_op(EV_READ, ==, event_pending(ev_et, EV_READ, NULL));
tt_int_op(0, ==, event_pending(ev_lt, EV_READ, NULL));
tt_int_op(0, ==, event_del(ev_et));
/* Add level-triggered, then edge-triggered. Get an error. */
tt_int_op(0, ==, event_add(ev_lt, NULL));
tt_int_op(-1, ==, event_add(ev_et, NULL));
tt_int_op(EV_READ, ==, event_pending(ev_lt, EV_READ, NULL));
tt_int_op(0, ==, event_pending(ev_et, EV_READ, NULL));
end:
if (ev_et)
event_free(ev_et);
if (ev_lt)
event_free(ev_lt);
if (base)
event_base_free(base);
}
struct testcase_t edgetriggered_testcases[] = {
{ "et", test_edgetriggered, TT_FORK, NULL, NULL },
{ "et_mix_error", test_edgetriggered_mix_error,
TT_FORK|TT_NEED_SOCKETPAIR|TT_NO_LOGS, &basic_setup, NULL },
END_OF_TESTCASES
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,352 +0,0 @@
/*
* Copyright (c) 2009-2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <string.h>
#include <event2/event.h>
#include <event2/thread.h>
#include <event2/buffer.h>
#include <event2/buffer_compat.h>
#include <event2/bufferevent.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include "regress.h"
#include "tinytest.h"
#include "tinytest_macros.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#undef WIN32_LEAN_AND_MEAN
#include "iocp-internal.h"
#include "evbuffer-internal.h"
#include "evthread-internal.h"
/* FIXME remove these ones */
#include <sys/queue.h>
#include "event2/event_struct.h"
#include "event-internal.h"
#define MAX_CALLS 16
static void *count_lock = NULL, *count_cond = NULL;
static int count = 0;
static void
count_init(void)
{
EVTHREAD_ALLOC_LOCK(count_lock, 0);
EVTHREAD_ALLOC_COND(count_cond);
tt_assert(count_lock);
tt_assert(count_cond);
end:
;
}
static void
count_free(void)
{
EVTHREAD_FREE_LOCK(count_lock, 0);
EVTHREAD_FREE_COND(count_cond);
}
static void
count_incr(void)
{
EVLOCK_LOCK(count_lock, 0);
count++;
EVTHREAD_COND_BROADCAST(count_cond);
EVLOCK_UNLOCK(count_lock, 0);
}
static int
count_wait_for(int i, int ms)
{
struct timeval tv;
DWORD elapsed;
int rv = -1;
EVLOCK_LOCK(count_lock, 0);
while (ms > 0 && count != i) {
tv.tv_sec = 0;
tv.tv_usec = ms * 1000;
elapsed = GetTickCount();
EVTHREAD_COND_WAIT_TIMED(count_cond, count_lock, &tv);
elapsed = GetTickCount() - elapsed;
ms -= elapsed;
}
if (count == i)
rv = 0;
EVLOCK_UNLOCK(count_lock, 0);
return rv;
}
struct dummy_overlapped {
struct event_overlapped eo;
void *lock;
int call_count;
uintptr_t keys[MAX_CALLS];
ev_ssize_t sizes[MAX_CALLS];
};
static void
dummy_cb(struct event_overlapped *o, uintptr_t key, ev_ssize_t n, int ok)
{
struct dummy_overlapped *d_o =
EVUTIL_UPCAST(o, struct dummy_overlapped, eo);
EVLOCK_LOCK(d_o->lock, 0);
if (d_o->call_count < MAX_CALLS) {
d_o->keys[d_o->call_count] = key;
d_o->sizes[d_o->call_count] = n;
}
d_o->call_count++;
EVLOCK_UNLOCK(d_o->lock, 0);
count_incr();
}
static int
pair_is_in(struct dummy_overlapped *o, uintptr_t key, ev_ssize_t n)
{
int i;
int result = 0;
EVLOCK_LOCK(o->lock, 0);
for (i=0; i < o->call_count; ++i) {
if (o->keys[i] == key && o->sizes[i] == n) {
result = 1;
break;
}
}
EVLOCK_UNLOCK(o->lock, 0);
return result;
}
static void
test_iocp_port(void *ptr)
{
struct event_iocp_port *port = NULL;
struct dummy_overlapped o1, o2;
memset(&o1, 0, sizeof(o1));
memset(&o2, 0, sizeof(o2));
count_init();
EVTHREAD_ALLOC_LOCK(o1.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
EVTHREAD_ALLOC_LOCK(o2.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
tt_assert(o1.lock);
tt_assert(o2.lock);
event_overlapped_init(&o1.eo, dummy_cb);
event_overlapped_init(&o2.eo, dummy_cb);
port = event_iocp_port_launch(0);
tt_assert(port);
tt_assert(!event_iocp_activate_overlapped(port, &o1.eo, 10, 100));
tt_assert(!event_iocp_activate_overlapped(port, &o2.eo, 20, 200));
tt_assert(!event_iocp_activate_overlapped(port, &o1.eo, 11, 101));
tt_assert(!event_iocp_activate_overlapped(port, &o2.eo, 21, 201));
tt_assert(!event_iocp_activate_overlapped(port, &o1.eo, 12, 102));
tt_assert(!event_iocp_activate_overlapped(port, &o2.eo, 22, 202));
tt_assert(!event_iocp_activate_overlapped(port, &o1.eo, 13, 103));
tt_assert(!event_iocp_activate_overlapped(port, &o2.eo, 23, 203));
tt_int_op(count_wait_for(8, 2000), ==, 0);
tt_want(!event_iocp_shutdown(port, 2000));
tt_int_op(o1.call_count, ==, 4);
tt_int_op(o2.call_count, ==, 4);
tt_want(pair_is_in(&o1, 10, 100));
tt_want(pair_is_in(&o1, 11, 101));
tt_want(pair_is_in(&o1, 12, 102));
tt_want(pair_is_in(&o1, 13, 103));
tt_want(pair_is_in(&o2, 20, 200));
tt_want(pair_is_in(&o2, 21, 201));
tt_want(pair_is_in(&o2, 22, 202));
tt_want(pair_is_in(&o2, 23, 203));
end:
EVTHREAD_FREE_LOCK(o1.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
EVTHREAD_FREE_LOCK(o2.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
count_free();
}
static struct evbuffer *rbuf = NULL, *wbuf = NULL;
static void
read_complete(struct event_overlapped *eo, uintptr_t key,
ev_ssize_t nbytes, int ok)
{
tt_assert(ok);
evbuffer_commit_read(rbuf, nbytes);
count_incr();
end:
;
}
static void
write_complete(struct event_overlapped *eo, uintptr_t key,
ev_ssize_t nbytes, int ok)
{
tt_assert(ok);
evbuffer_commit_write(wbuf, nbytes);
count_incr();
end:
;
}
static void
test_iocp_evbuffer(void *ptr)
{
struct event_overlapped rol, wol;
struct basic_test_data *data = ptr;
struct event_iocp_port *port = NULL;
struct evbuffer *buf=NULL;
struct evbuffer_chain *chain;
char junk[1024];
int i;
count_init();
event_overlapped_init(&rol, read_complete);
event_overlapped_init(&wol, write_complete);
for (i = 0; i < sizeof(junk); ++i)
junk[i] = (char)(i);
rbuf = evbuffer_overlapped_new(data->pair[0]);
wbuf = evbuffer_overlapped_new(data->pair[1]);
evbuffer_enable_locking(rbuf, NULL);
evbuffer_enable_locking(wbuf, NULL);
port = event_iocp_port_launch(0);
tt_assert(port);
tt_assert(rbuf);
tt_assert(wbuf);
tt_assert(!event_iocp_port_associate(port, data->pair[0], 100));
tt_assert(!event_iocp_port_associate(port, data->pair[1], 100));
for (i=0;i<10;++i)
evbuffer_add(wbuf, junk, sizeof(junk));
buf = evbuffer_new();
tt_assert(buf != NULL);
evbuffer_add(rbuf, junk, sizeof(junk));
tt_assert(!evbuffer_launch_read(rbuf, 2048, &rol));
evbuffer_add_buffer(buf, rbuf);
tt_int_op(evbuffer_get_length(buf), ==, sizeof(junk));
for (chain = buf->first; chain; chain = chain->next)
tt_int_op(chain->flags & EVBUFFER_MEM_PINNED_ANY, ==, 0);
tt_assert(!evbuffer_get_length(rbuf));
tt_assert(!evbuffer_launch_write(wbuf, 512, &wol));
tt_int_op(count_wait_for(2, 2000), ==, 0);
tt_int_op(evbuffer_get_length(rbuf),==,512);
/* FIXME Actually test some stuff here. */
tt_want(!event_iocp_shutdown(port, 2000));
end:
count_free();
evbuffer_free(rbuf);
evbuffer_free(wbuf);
if (buf) evbuffer_free(buf);
}
static int got_readcb = 0;
static void
async_readcb(struct bufferevent *bev, void *arg)
{
/* Disabling read should cause the loop to quit */
bufferevent_disable(bev, EV_READ);
got_readcb++;
}
static void
test_iocp_bufferevent_async(void *ptr)
{
struct basic_test_data *data = ptr;
struct event_iocp_port *port = NULL;
struct bufferevent *bea1=NULL, *bea2=NULL;
char buf[128];
size_t n;
event_base_start_iocp(data->base, 0);
port = event_base_get_iocp(data->base);
tt_assert(port);
bea1 = bufferevent_async_new(data->base, data->pair[0],
BEV_OPT_DEFER_CALLBACKS);
bea2 = bufferevent_async_new(data->base, data->pair[1],
BEV_OPT_DEFER_CALLBACKS);
tt_assert(bea1);
tt_assert(bea2);
bufferevent_setcb(bea2, async_readcb, NULL, NULL, NULL);
bufferevent_enable(bea1, EV_WRITE);
bufferevent_enable(bea2, EV_READ);
bufferevent_write(bea1, "Hello world", strlen("Hello world")+1);
event_base_dispatch(data->base);
tt_int_op(got_readcb, ==, 1);
n = bufferevent_read(bea2, buf, sizeof(buf)-1);
buf[n]='\0';
tt_str_op(buf, ==, "Hello world");
end:
bufferevent_free(bea1);
bufferevent_free(bea2);
}
struct testcase_t iocp_testcases[] = {
{ "port", test_iocp_port, TT_FORK|TT_NEED_THREADS, &basic_setup, NULL },
{ "evbuffer", test_iocp_evbuffer,
TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_THREADS,
&basic_setup, NULL },
{ "bufferevent_async", test_iocp_bufferevent_async,
TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_THREADS|TT_NEED_BASE,
&basic_setup, NULL },
END_OF_TESTCASES
};

Просмотреть файл

@ -1,151 +0,0 @@
/*
* Copyright (c) 2009-2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef WIN32
#include <winsock2.h>
#include <windows.h>
#endif
#include <sys/types.h>
#ifndef WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#endif
#include <string.h>
#include <event2/listener.h>
#include <event2/event.h>
#include <event2/util.h>
#include "regress.h"
#include "tinytest.h"
#include "tinytest_macros.h"
#include "util-internal.h"
static void
acceptcb(struct evconnlistener *listener, evutil_socket_t fd,
struct sockaddr *addr, int socklen, void *arg)
{
int *ptr = arg;
--*ptr;
TT_BLATHER(("Got one for %p", ptr));
evutil_closesocket(fd);
if (! *ptr)
evconnlistener_disable(listener);
}
static void
regress_pick_a_port(void *arg)
{
struct basic_test_data *data = arg;
struct event_base *base = data->base;
struct evconnlistener *listener1 = NULL, *listener2 = NULL;
struct sockaddr_in sin;
int count1 = 2, count2 = 1;
struct sockaddr_storage ss1, ss2;
struct sockaddr_in *sin1, *sin2;
ev_socklen_t slen1 = sizeof(ss1), slen2 = sizeof(ss2);
unsigned int flags =
LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC;
evutil_socket_t fd1 = -1, fd2 = -1, fd3 = -1;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
sin.sin_port = 0; /* "You pick!" */
listener1 = evconnlistener_new_bind(base, acceptcb, &count1,
flags, -1, (struct sockaddr *)&sin, sizeof(sin));
tt_assert(listener1);
listener2 = evconnlistener_new_bind(base, acceptcb, &count2,
flags, -1, (struct sockaddr *)&sin, sizeof(sin));
tt_assert(listener2);
tt_int_op(evconnlistener_get_fd(listener1), >=, 0);
tt_int_op(evconnlistener_get_fd(listener2), >=, 0);
tt_assert(getsockname(evconnlistener_get_fd(listener1),
(struct sockaddr*)&ss1, &slen1) == 0);
tt_assert(getsockname(evconnlistener_get_fd(listener2),
(struct sockaddr*)&ss2, &slen2) == 0);
tt_int_op(ss1.ss_family, ==, AF_INET);
tt_int_op(ss2.ss_family, ==, AF_INET);
sin1 = (struct sockaddr_in*)&ss1;
sin2 = (struct sockaddr_in*)&ss2;
tt_int_op(ntohl(sin1->sin_addr.s_addr), ==, 0x7f000001);
tt_int_op(ntohl(sin2->sin_addr.s_addr), ==, 0x7f000001);
tt_int_op(sin1->sin_port, !=, sin2->sin_port);
tt_ptr_op(evconnlistener_get_base(listener1), ==, base);
tt_ptr_op(evconnlistener_get_base(listener2), ==, base);
fd1 = fd2 = fd3 = -1;
evutil_socket_connect(&fd1, (struct sockaddr*)&ss1, slen1);
evutil_socket_connect(&fd2, (struct sockaddr*)&ss1, slen1);
evutil_socket_connect(&fd3, (struct sockaddr*)&ss2, slen2);
#ifdef WIN32
Sleep(100); /* XXXX this is a stupid stopgap. */
#endif
event_base_dispatch(base);
tt_int_op(count1, ==, 0);
tt_int_op(count2, ==, 0);
end:
if (fd1>=0)
EVUTIL_CLOSESOCKET(fd1);
if (fd2>=0)
EVUTIL_CLOSESOCKET(fd2);
if (fd3>=0)
EVUTIL_CLOSESOCKET(fd3);
if (listener1)
evconnlistener_free(listener1);
if (listener2)
evconnlistener_free(listener2);
}
struct testcase_t listener_testcases[] = {
{ "randport", regress_pick_a_port, TT_FORK|TT_NEED_BASE,
&basic_setup, NULL},
END_OF_TESTCASES,
};
struct testcase_t listener_iocp_testcases[] = {
{ "randport", regress_pick_a_port,
TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP,
&basic_setup, NULL},
END_OF_TESTCASES,
};

Просмотреть файл

@ -1,392 +0,0 @@
/*
* Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
* Copyright (c) 2007-2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef WIN32
#include <winsock2.h>
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#endif
#include "event2/event-config.h"
#ifdef _EVENT___func__
#define __func__ _EVENT___func__
#endif
#if 0
#include <sys/types.h>
#include <sys/stat.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <sys/queue.h>
#include <signal.h>
#include <errno.h>
#endif
#include <sys/types.h>
#ifndef WIN32
#include <sys/socket.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include <netdb.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <event2/util.h>
#include <event2/event.h>
#include <event2/event_compat.h>
#include <event2/dns.h>
#include <event2/dns_compat.h>
#include <event2/thread.h>
#include "event2/event-config.h"
#include "regress.h"
#include "tinytest.h"
#include "tinytest_macros.h"
#include "../iocp-internal.h"
long
timeval_msec_diff(const struct timeval *start, const struct timeval *end)
{
long ms = end->tv_sec - start->tv_sec;
ms *= 1000;
ms += ((end->tv_usec - start->tv_usec)+500) / 1000;
return ms;
}
/* ============================================================ */
/* Code to wrap up old legacy test cases that used setup() and cleanup().
*
* Not all of the tests designated "legacy" are ones that used setup() and
* cleanup(), of course. A test is legacy it it uses setup()/cleanup(), OR
* if it wants to find its event base/socketpair in global variables (ugh),
* OR if it wants to communicate success/failure through test_ok.
*/
/* This is set to true if we're inside a legacy test wrapper. It lets the
setup() and cleanup() functions in regress.c know they're not needed.
*/
int in_legacy_test_wrapper = 0;
static void dnslogcb(int w, const char *m)
{
TT_BLATHER(("%s", m));
}
/* creates a temporary file with the data in it */
evutil_socket_t
regress_make_tmpfile(const void *data, size_t datalen)
{
#ifndef WIN32
char tmpfilename[32];
int fd;
strcpy(tmpfilename, "/tmp/eventtmp.XXXXXX");
fd = mkstemp(tmpfilename);
if (fd == -1)
return (-1);
if (write(fd, data, datalen) != datalen) {
close(fd);
return (-1);
}
lseek(fd, 0, SEEK_SET);
/* remove it from the file system */
unlink(tmpfilename);
return (fd);
#else
/* XXXX actually delete the file later */
char tmpfilepath[MAX_PATH];
char tmpfilename[MAX_PATH];
DWORD r, written;
int tries = 16;
HANDLE h;
r = GetTempPathA(MAX_PATH, tmpfilepath);
if (r > MAX_PATH || r == 0)
return (-1);
for (; tries > 0; --tries) {
r = GetTempFileNameA(tmpfilepath, "LIBEVENT", 0, tmpfilename);
if (r == 0)
return (-1);
h = CreateFileA(tmpfilename, GENERIC_READ|GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (h != INVALID_HANDLE_VALUE)
break;
}
if (tries == 0)
return (-1);
written = 0;
WriteFile(h, data, datalen, &written, NULL);
/* Closing the fd returned by this function will indeed close h. */
return _open_osfhandle((intptr_t)h,_O_RDONLY);
#endif
}
static void
ignore_log_cb(int s, const char *msg)
{
}
static void *
basic_test_setup(const struct testcase_t *testcase)
{
struct event_base *base = NULL;
int spair[2] = { -1, -1 };
struct basic_test_data *data = NULL;
#ifndef WIN32
if (testcase->flags & TT_ENABLE_IOCP_FLAG)
return (void*)TT_SKIP;
#endif
if (testcase->flags & TT_NEED_THREADS) {
if (!(testcase->flags & TT_FORK))
return NULL;
#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
if (evthread_use_pthreads())
exit(1);
#elif defined(EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED)
if (evthread_use_windows_threads())
exit(1);
#else
return (void*)TT_SKIP;
#endif
}
if (testcase->flags & TT_NEED_SOCKETPAIR) {
if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, spair) == -1) {
fprintf(stderr, "%s: socketpair\n", __func__);
exit(1);
}
if (evutil_make_socket_nonblocking(spair[0]) == -1) {
fprintf(stderr, "fcntl(O_NONBLOCK)");
exit(1);
}
if (evutil_make_socket_nonblocking(spair[1]) == -1) {
fprintf(stderr, "fcntl(O_NONBLOCK)");
exit(1);
}
}
if (testcase->flags & TT_NEED_BASE) {
if (testcase->flags & TT_LEGACY)
base = event_init();
else
base = event_base_new();
if (!base)
exit(1);
}
if (testcase->flags & TT_ENABLE_IOCP_FLAG) {
if (event_base_start_iocp(base, 0)<0) {
event_base_free(base);
return (void*)TT_SKIP;
}
}
if (testcase->flags & TT_NEED_DNS) {
evdns_set_log_fn(dnslogcb);
if (evdns_init())
return NULL; /* fast failure */ /*XXX asserts. */
}
if (testcase->flags & TT_NO_LOGS)
event_set_log_callback(ignore_log_cb);
data = calloc(1, sizeof(*data));
if (!data)
exit(1);
data->base = base;
data->pair[0] = spair[0];
data->pair[1] = spair[1];
data->setup_data = testcase->setup_data;
return data;
}
static int
basic_test_cleanup(const struct testcase_t *testcase, void *ptr)
{
struct basic_test_data *data = ptr;
if (testcase->flags & TT_NO_LOGS)
event_set_log_callback(NULL);
if (testcase->flags & TT_NEED_SOCKETPAIR) {
if (data->pair[0] != -1)
evutil_closesocket(data->pair[0]);
if (data->pair[1] != -1)
evutil_closesocket(data->pair[1]);
}
if (testcase->flags & TT_NEED_DNS) {
evdns_shutdown(0);
}
if (testcase->flags & TT_NEED_BASE) {
if (data->base)
event_base_free(data->base);
}
free(data);
return 1;
}
const struct testcase_setup_t basic_setup = {
basic_test_setup, basic_test_cleanup
};
/* The "data" for a legacy test is just a pointer to the void fn(void)
function implementing the test case. We need to set up some globals,
though, since that's where legacy tests expect to find a socketpair
(sometimes) and a global event_base (sometimes).
*/
static void *
legacy_test_setup(const struct testcase_t *testcase)
{
struct basic_test_data *data = basic_test_setup(testcase);
if (data == (void*)TT_SKIP)
return data;
global_base = data->base;
pair[0] = data->pair[0];
pair[1] = data->pair[1];
data->legacy_test_fn = testcase->setup_data;
return data;
}
/* This function is the implementation of every legacy test case. It
sets test_ok to 0, invokes the test function, and tells tinytest that
the test failed if the test didn't set test_ok to 1.
*/
void
run_legacy_test_fn(void *ptr)
{
struct basic_test_data *data = ptr;
test_ok = called = 0;
in_legacy_test_wrapper = 1;
data->legacy_test_fn(); /* This part actually calls the test */
in_legacy_test_wrapper = 0;
if (!test_ok)
tt_abort_msg("Legacy unit test failed");
end:
test_ok = 0;
}
/* This function doesn't have to clean up ptr (which is just a pointer
to the test function), but it may need to close the socketpair or
free the event_base.
*/
static int
legacy_test_cleanup(const struct testcase_t *testcase, void *ptr)
{
int r = basic_test_cleanup(testcase, ptr);
pair[0] = pair[1] = -1;
global_base = NULL;
return r;
}
const struct testcase_setup_t legacy_setup = {
legacy_test_setup, legacy_test_cleanup
};
/* ============================================================ */
#if (!defined(_EVENT_HAVE_PTHREADS) && !defined(WIN32)) || defined(_EVENT_DISABLE_THREAD_SUPPORT)
struct testcase_t thread_testcases[] = {
{ "basic", NULL, TT_SKIP, NULL, NULL },
END_OF_TESTCASES
};
#endif
struct testgroup_t testgroups[] = {
{ "main/", main_testcases },
{ "heap/", minheap_testcases },
{ "et/", edgetriggered_testcases },
{ "evbuffer/", evbuffer_testcases },
{ "signal/", signal_testcases },
{ "util/", util_testcases },
{ "bufferevent/", bufferevent_testcases },
{ "http/", http_testcases },
{ "dns/", dns_testcases },
{ "evtag/", evtag_testcases },
{ "rpc/", rpc_testcases },
{ "thread/", thread_testcases },
{ "listener/", listener_testcases },
#ifdef WIN32
{ "iocp/", iocp_testcases },
{ "iocp/bufferevent/", bufferevent_iocp_testcases },
{ "iocp/listener/", listener_iocp_testcases },
#endif
#ifdef _EVENT_HAVE_OPENSSL
{ "ssl/", ssl_testcases },
#endif
END_OF_GROUPS
};
int
main(int argc, const char **argv)
{
#ifdef WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
#endif
#ifndef WIN32
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
return 1;
#endif
#ifdef WIN32
tinytest_skip(testgroups, "http/connection_retry");
#endif
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
if (!getenv("EVENT_NO_DEBUG_LOCKS"))
evthread_enable_lock_debuging();
#endif
if (tinytest_main(argc,argv,testgroups))
return 1;
return 0;
}

Просмотреть файл

@ -1,98 +0,0 @@
/*
* Copyright (c) 2009-2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <event2/event_struct.h>
#include "tinytest.h"
#include "tinytest_macros.h"
#include "../minheap-internal.h"
static void
set_random_timeout(struct event *ev)
{
ev->ev_timeout.tv_sec = rand();
ev->ev_timeout.tv_usec = rand() & 0xfffff;
ev->ev_timeout_pos.min_heap_idx = -1;
}
static void
check_heap(struct min_heap *heap)
{
unsigned i;
for (i = 1; i < heap->n; ++i) {
unsigned parent_idx = (i-1)/2;
tt_want(evutil_timercmp(&heap->p[i]->ev_timeout,
&heap->p[parent_idx]->ev_timeout, >=));
}
}
static void
test_heap_randomized(void *ptr)
{
struct min_heap heap;
struct event *inserted[1024];
struct event *e, *last_e;
int i;
min_heap_ctor(&heap);
for (i = 0; i < 1024; ++i) {
inserted[i] = malloc(sizeof(struct event));
set_random_timeout(inserted[i]);
min_heap_push(&heap, inserted[i]);
}
check_heap(&heap);
tt_assert(min_heap_size(&heap) == 1024);
for (i = 0; i < 512; ++i) {
min_heap_erase(&heap, inserted[i]);
if (0 == (i % 32))
check_heap(&heap);
}
tt_assert(min_heap_size(&heap) == 512);
last_e = min_heap_pop(&heap);
while (1) {
e = min_heap_pop(&heap);
if (!e)
break;
tt_want(evutil_timercmp(&last_e->ev_timeout,
&e->ev_timeout, <=));
}
tt_assert(min_heap_size(&heap) == 0);
end:
for (i = 0; i < 1024; ++i)
free(inserted[i]);
min_heap_dtor(&heap);
}
struct testcase_t minheap_testcases[] = {
{ "randomized", test_heap_randomized, 0, NULL, NULL },
END_OF_TESTCASES
};

Просмотреть файл

@ -1,878 +0,0 @@
/*
* Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
* Copyright (c) 2007-2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* The old tests here need assertions to work. */
#undef NDEBUG
#ifdef WIN32
#include <winsock2.h>
#include <windows.h>
#endif
#include "event2/event-config.h"
#include <sys/types.h>
#include <sys/stat.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <sys/queue.h>
#ifndef WIN32
#include <sys/socket.h>
#include <signal.h>
#include <unistd.h>
#include <netdb.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "event2/event.h"
#include "evhttp.h"
#include "log-internal.h"
#include "event2/rpc.h"
#include "event2/rpc_struct.h"
#include "regress.gen.h"
#include "regress.h"
#include "regress_testutils.h"
static struct evhttp *
http_setup(ev_uint16_t *pport)
{
struct evhttp *myhttp;
ev_uint16_t port;
struct evhttp_bound_socket *sock;
myhttp = evhttp_new(NULL);
if (!myhttp)
event_errx(1, "Could not start web server");
/* Try a few different ports */
sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", 0);
if (!sock)
event_errx(1, "Couldn't open web port");
port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock));
*pport = port;
return (myhttp);
}
EVRPC_HEADER(Message, msg, kill)
EVRPC_HEADER(NeverReply, msg, kill)
EVRPC_GENERATE(Message, msg, kill)
EVRPC_GENERATE(NeverReply, msg, kill)
static int need_input_hook = 0;
static int need_output_hook = 0;
static void
MessageCb(EVRPC_STRUCT(Message)* rpc, void *arg)
{
struct kill* kill_reply = rpc->reply;
if (need_input_hook) {
struct evhttp_request* req = EVRPC_REQUEST_HTTP(rpc);
const char *header = evhttp_find_header(
req->input_headers, "X-Hook");
assert(strcmp(header, "input") == 0);
}
/* we just want to fill in some non-sense */
EVTAG_ASSIGN(kill_reply, weapon, "dagger");
EVTAG_ASSIGN(kill_reply, action, "wave around like an idiot");
/* no reply to the RPC */
EVRPC_REQUEST_DONE(rpc);
}
static EVRPC_STRUCT(NeverReply) *saved_rpc;
static void
NeverReplyCb(EVRPC_STRUCT(NeverReply)* rpc, void *arg)
{
test_ok += 1;
saved_rpc = rpc;
}
static void
rpc_setup(struct evhttp **phttp, ev_uint16_t *pport, struct evrpc_base **pbase)
{
ev_uint16_t port;
struct evhttp *http = NULL;
struct evrpc_base *base = NULL;
http = http_setup(&port);
base = evrpc_init(http);
EVRPC_REGISTER(base, Message, msg, kill, MessageCb, NULL);
EVRPC_REGISTER(base, NeverReply, msg, kill, NeverReplyCb, NULL);
*phttp = http;
*pport = port;
*pbase = base;
need_input_hook = 0;
need_output_hook = 0;
}
static void
rpc_teardown(struct evrpc_base *base)
{
assert(EVRPC_UNREGISTER(base, Message) == 0);
assert(EVRPC_UNREGISTER(base, NeverReply) == 0);
evrpc_free(base);
}
static void
rpc_postrequest_failure(struct evhttp_request *req, void *arg)
{
if (req->response_code != HTTP_SERVUNAVAIL) {
fprintf(stderr, "FAILED (response code)\n");
exit(1);
}
test_ok = 1;
event_loopexit(NULL);
}
/*
* Test a malformed payload submitted as an RPC
*/
static void
rpc_basic_test(void)
{
ev_uint16_t port;
struct evhttp *http = NULL;
struct evrpc_base *base = NULL;
struct evhttp_connection *evcon = NULL;
struct evhttp_request *req = NULL;
rpc_setup(&http, &port, &base);
evcon = evhttp_connection_new("127.0.0.1", port);
tt_assert(evcon);
/*
* At this point, we want to schedule an HTTP POST request
* server using our make request method.
*/
req = evhttp_request_new(rpc_postrequest_failure, NULL);
tt_assert(req);
/* Add the information that we care about */
evhttp_add_header(req->output_headers, "Host", "somehost");
evbuffer_add_printf(req->output_buffer, "Some Nonsense");
if (evhttp_make_request(evcon, req,
EVHTTP_REQ_POST,
"/.rpc.Message") == -1) {
tt_abort();
}
test_ok = 0;
event_dispatch();
evhttp_connection_free(evcon);
rpc_teardown(base);
tt_assert(test_ok == 1);
end:
evhttp_free(http);
}
static void
rpc_postrequest_done(struct evhttp_request *req, void *arg)
{
struct kill* kill_reply = NULL;
if (req->response_code != HTTP_OK) {
fprintf(stderr, "FAILED (response code)\n");
exit(1);
}
kill_reply = kill_new();
if ((kill_unmarshal(kill_reply, req->input_buffer)) == -1) {
fprintf(stderr, "FAILED (unmarshal)\n");
exit(1);
}
kill_free(kill_reply);
test_ok = 1;
event_loopexit(NULL);
}
static void
rpc_basic_message(void)
{
ev_uint16_t port;
struct evhttp *http = NULL;
struct evrpc_base *base = NULL;
struct evhttp_connection *evcon = NULL;
struct evhttp_request *req = NULL;
struct msg *msg;
rpc_setup(&http, &port, &base);
evcon = evhttp_connection_new("127.0.0.1", port);
tt_assert(evcon);
/*
* At this point, we want to schedule an HTTP POST request
* server using our make request method.
*/
req = evhttp_request_new(rpc_postrequest_done, NULL);
if (req == NULL) {
fprintf(stdout, "FAILED\n");
exit(1);
}
/* Add the information that we care about */
evhttp_add_header(req->output_headers, "Host", "somehost");
/* set up the basic message */
msg = msg_new();
EVTAG_ASSIGN(msg, from_name, "niels");
EVTAG_ASSIGN(msg, to_name, "tester");
msg_marshal(req->output_buffer, msg);
msg_free(msg);
if (evhttp_make_request(evcon, req,
EVHTTP_REQ_POST,
"/.rpc.Message") == -1) {
fprintf(stdout, "FAILED\n");
exit(1);
}
test_ok = 0;
event_dispatch();
evhttp_connection_free(evcon);
rpc_teardown(base);
end:
evhttp_free(http);
}
static struct evrpc_pool *
rpc_pool_with_connection(ev_uint16_t port)
{
struct evhttp_connection *evcon;
struct evrpc_pool *pool;
pool = evrpc_pool_new(NULL);
assert(pool != NULL);
evcon = evhttp_connection_new("127.0.0.1", port);
assert(evcon != NULL);
evrpc_pool_add_connection(pool, evcon);
return (pool);
}
static void
GotKillCb(struct evrpc_status *status,
struct msg *msg, struct kill *kill, void *arg)
{
char *weapon;
char *action;
if (need_output_hook) {
struct evhttp_request *req = status->http_req;
const char *header = evhttp_find_header(
req->input_headers, "X-Pool-Hook");
assert(strcmp(header, "ran") == 0);
}
if (status->error != EVRPC_STATUS_ERR_NONE)
goto done;
if (EVTAG_GET(kill, weapon, &weapon) == -1) {
fprintf(stderr, "get weapon\n");
goto done;
}
if (EVTAG_GET(kill, action, &action) == -1) {
fprintf(stderr, "get action\n");
goto done;
}
if (strcmp(weapon, "dagger"))
goto done;
if (strcmp(action, "wave around like an idiot"))
goto done;
test_ok += 1;
done:
event_loopexit(NULL);
}
static void
GotKillCbTwo(struct evrpc_status *status,
struct msg *msg, struct kill *kill, void *arg)
{
char *weapon;
char *action;
if (status->error != EVRPC_STATUS_ERR_NONE)
goto done;
if (EVTAG_GET(kill, weapon, &weapon) == -1) {
fprintf(stderr, "get weapon\n");
goto done;
}
if (EVTAG_GET(kill, action, &action) == -1) {
fprintf(stderr, "get action\n");
goto done;
}
if (strcmp(weapon, "dagger"))
goto done;
if (strcmp(action, "wave around like an idiot"))
goto done;
test_ok += 1;
done:
if (test_ok == 2)
event_loopexit(NULL);
}
static int
rpc_hook_add_header(void *ctx, struct evhttp_request *req,
struct evbuffer *evbuf, void *arg)
{
const char *hook_type = arg;
if (strcmp("input", hook_type) == 0)
evhttp_add_header(req->input_headers, "X-Hook", hook_type);
else
evhttp_add_header(req->output_headers, "X-Hook", hook_type);
assert(evrpc_hook_get_connection(ctx) != NULL);
return (EVRPC_CONTINUE);
}
static int
rpc_hook_add_meta(void *ctx, struct evhttp_request *req,
struct evbuffer *evbuf, void *arg)
{
evrpc_hook_add_meta(ctx, "meta", "test", 5);
assert(evrpc_hook_get_connection(ctx) != NULL);
return (EVRPC_CONTINUE);
}
static int
rpc_hook_remove_header(void *ctx, struct evhttp_request *req,
struct evbuffer *evbuf, void *arg)
{
const char *header = evhttp_find_header(req->input_headers, "X-Hook");
void *data = NULL;
size_t data_len = 0;
assert(header != NULL);
assert(strcmp(header, arg) == 0);
evhttp_remove_header(req->input_headers, "X-Hook");
evhttp_add_header(req->input_headers, "X-Pool-Hook", "ran");
assert(evrpc_hook_find_meta(ctx, "meta", &data, &data_len) == 0);
assert(data != NULL);
assert(data_len == 5);
assert(evrpc_hook_get_connection(ctx) != NULL);
return (EVRPC_CONTINUE);
}
static void
rpc_basic_client(void)
{
ev_uint16_t port;
struct evhttp *http = NULL;
struct evrpc_base *base = NULL;
struct evrpc_pool *pool = NULL;
struct msg *msg = NULL;
struct kill *kill = NULL;
rpc_setup(&http, &port, &base);
need_input_hook = 1;
need_output_hook = 1;
assert(evrpc_add_hook(base, EVRPC_INPUT, rpc_hook_add_header, (void*)"input")
!= NULL);
assert(evrpc_add_hook(base, EVRPC_OUTPUT, rpc_hook_add_header, (void*)"output")
!= NULL);
pool = rpc_pool_with_connection(port);
assert(evrpc_add_hook(pool, EVRPC_OUTPUT, rpc_hook_add_meta, NULL));
assert(evrpc_add_hook(pool, EVRPC_INPUT, rpc_hook_remove_header, (void*)"output"));
/* set up the basic message */
msg = msg_new();
EVTAG_ASSIGN(msg, from_name, "niels");
EVTAG_ASSIGN(msg, to_name, "tester");
kill = kill_new();
EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
test_ok = 0;
event_dispatch();
tt_assert(test_ok == 1);
/* we do it twice to make sure that reuse works correctly */
kill_clear(kill);
EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
event_dispatch();
tt_assert(test_ok == 2);
/* we do it trice to make sure other stuff works, too */
kill_clear(kill);
{
struct evrpc_request_wrapper *ctx =
EVRPC_MAKE_CTX(Message, msg, kill,
pool, msg, kill, GotKillCb, NULL);
evrpc_make_request(ctx);
}
event_dispatch();
rpc_teardown(base);
tt_assert(test_ok == 3);
end:
if (msg)
msg_free(msg);
if (kill)
kill_free(kill);
if (pool)
evrpc_pool_free(pool);
if (http)
evhttp_free(http);
need_input_hook = 0;
need_output_hook = 0;
}
/*
* We are testing that the second requests gets send over the same
* connection after the first RPCs completes.
*/
static void
rpc_basic_queued_client(void)
{
ev_uint16_t port;
struct evhttp *http = NULL;
struct evrpc_base *base = NULL;
struct evrpc_pool *pool = NULL;
struct msg *msg=NULL;
struct kill *kill_one=NULL, *kill_two=NULL;
rpc_setup(&http, &port, &base);
pool = rpc_pool_with_connection(port);
/* set up the basic message */
msg = msg_new();
EVTAG_ASSIGN(msg, from_name, "niels");
EVTAG_ASSIGN(msg, to_name, "tester");
kill_one = kill_new();
kill_two = kill_new();
EVRPC_MAKE_REQUEST(Message, pool, msg, kill_one, GotKillCbTwo, NULL);
EVRPC_MAKE_REQUEST(Message, pool, msg, kill_two, GotKillCb, NULL);
test_ok = 0;
event_dispatch();
rpc_teardown(base);
tt_assert(test_ok == 2);
end:
if (msg)
msg_free(msg);
if (kill_one)
kill_free(kill_one);
if (kill_two)
kill_free(kill_two);
if (pool)
evrpc_pool_free(pool);
if (http)
evhttp_free(http);
}
static void
GotErrorCb(struct evrpc_status *status,
struct msg *msg, struct kill *kill, void *arg)
{
if (status->error != EVRPC_STATUS_ERR_TIMEOUT)
goto done;
/* should never be complete but just to check */
if (kill_complete(kill) == 0)
goto done;
test_ok += 1;
done:
event_loopexit(NULL);
}
/* we just pause the rpc and continue it in the next callback */
struct _rpc_hook_ctx {
void *vbase;
void *ctx;
};
static int hook_pause_cb_called=0;
static void
rpc_hook_pause_cb(evutil_socket_t fd, short what, void *arg)
{
struct _rpc_hook_ctx *ctx = arg;
++hook_pause_cb_called;
evrpc_resume_request(ctx->vbase, ctx->ctx, EVRPC_CONTINUE);
free(arg);
}
static int
rpc_hook_pause(void *ctx, struct evhttp_request *req, struct evbuffer *evbuf,
void *arg)
{
struct _rpc_hook_ctx *tmp = malloc(sizeof(*tmp));
struct timeval tv;
assert(tmp != NULL);
tmp->vbase = arg;
tmp->ctx = ctx;
memset(&tv, 0, sizeof(tv));
event_once(-1, EV_TIMEOUT, rpc_hook_pause_cb, tmp, &tv);
return EVRPC_PAUSE;
}
static void
rpc_basic_client_with_pause(void)
{
ev_uint16_t port;
struct evhttp *http = NULL;
struct evrpc_base *base = NULL;
struct evrpc_pool *pool = NULL;
struct msg *msg = NULL;
struct kill *kill= NULL;
rpc_setup(&http, &port, &base);
assert(evrpc_add_hook(base, EVRPC_INPUT, rpc_hook_pause, base));
assert(evrpc_add_hook(base, EVRPC_OUTPUT, rpc_hook_pause, base));
pool = rpc_pool_with_connection(port);
assert(evrpc_add_hook(pool, EVRPC_INPUT, rpc_hook_pause, pool));
assert(evrpc_add_hook(pool, EVRPC_OUTPUT, rpc_hook_pause, pool));
/* set up the basic message */
msg = msg_new();
EVTAG_ASSIGN(msg, from_name, "niels");
EVTAG_ASSIGN(msg, to_name, "tester");
kill = kill_new();
EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
test_ok = 0;
event_dispatch();
tt_int_op(test_ok, ==, 1);
tt_int_op(hook_pause_cb_called, ==, 4);
end:
if (base)
rpc_teardown(base);
if (msg)
msg_free(msg);
if (kill)
kill_free(kill);
if (pool)
evrpc_pool_free(pool);
if (http)
evhttp_free(http);
}
static void
rpc_client_timeout(void)
{
ev_uint16_t port;
struct evhttp *http = NULL;
struct evrpc_base *base = NULL;
struct evrpc_pool *pool = NULL;
struct msg *msg = NULL;
struct kill *kill = NULL;
rpc_setup(&http, &port, &base);
pool = rpc_pool_with_connection(port);
/* set the timeout to 5 seconds */
evrpc_pool_set_timeout(pool, 5);
/* set up the basic message */
msg = msg_new();
EVTAG_ASSIGN(msg, from_name, "niels");
EVTAG_ASSIGN(msg, to_name, "tester");
kill = kill_new();
EVRPC_MAKE_REQUEST(NeverReply, pool, msg, kill, GotErrorCb, NULL);
test_ok = 0;
event_dispatch();
/* free the saved RPC structure up */
EVRPC_REQUEST_DONE(saved_rpc);
rpc_teardown(base);
tt_assert(test_ok == 2);
end:
if (msg)
msg_free(msg);
if (kill)
kill_free(kill);
if (pool)
evrpc_pool_free(pool);
if (http)
evhttp_free(http);
}
static void
rpc_test(void)
{
struct msg *msg = NULL, *msg2 = NULL;
struct kill *attack = NULL;
struct run *run = NULL;
struct evbuffer *tmp = evbuffer_new();
struct timeval tv_start, tv_end;
ev_uint32_t tag;
int i;
msg = msg_new();
EVTAG_ASSIGN(msg, from_name, "niels");
EVTAG_ASSIGN(msg, to_name, "phoenix");
if (EVTAG_GET(msg, attack, &attack) == -1) {
tt_abort_msg("Failed to set kill message.");
}
EVTAG_ASSIGN(attack, weapon, "feather");
EVTAG_ASSIGN(attack, action, "tickle");
for (i = 0; i < 3; ++i) {
if (EVTAG_ARRAY_ADD_VALUE(attack, how_often, i) == NULL) {
tt_abort_msg("Failed to add how_often.");
}
}
evutil_gettimeofday(&tv_start, NULL);
for (i = 0; i < 1000; ++i) {
run = EVTAG_ARRAY_ADD(msg, run);
if (run == NULL) {
tt_abort_msg("Failed to add run message.");
}
EVTAG_ASSIGN(run, how, "very fast but with some data in it");
EVTAG_ASSIGN(run, fixed_bytes,
(ev_uint8_t*)"012345678901234567890123");
if (EVTAG_ARRAY_ADD_VALUE(
run, notes, "this is my note") == NULL) {
tt_abort_msg("Failed to add note.");
}
if (EVTAG_ARRAY_ADD_VALUE(run, notes, "pps") == NULL) {
tt_abort_msg("Failed to add note");
}
EVTAG_ASSIGN(run, large_number, 0xdead0a0bcafebeefLL);
EVTAG_ARRAY_ADD_VALUE(run, other_numbers, 0xdead0a0b);
EVTAG_ARRAY_ADD_VALUE(run, other_numbers, 0xbeefcafe);
}
if (msg_complete(msg) == -1)
tt_abort_msg("Failed to make complete message.");
evtag_marshal_msg(tmp, 0xdeaf, msg);
if (evtag_peek(tmp, &tag) == -1)
tt_abort_msg("Failed to peak tag.");
if (tag != 0xdeaf)
TT_DIE(("Got incorrect tag: %0x.", (unsigned)tag));
msg2 = msg_new();
if (evtag_unmarshal_msg(tmp, 0xdeaf, msg2) == -1)
tt_abort_msg("Failed to unmarshal message.");
evutil_gettimeofday(&tv_end, NULL);
evutil_timersub(&tv_end, &tv_start, &tv_end);
TT_BLATHER(("(%.1f us/add) ",
(float)tv_end.tv_sec/(float)i * 1000000.0 +
tv_end.tv_usec / (float)i));
if (!EVTAG_HAS(msg2, from_name) ||
!EVTAG_HAS(msg2, to_name) ||
!EVTAG_HAS(msg2, attack)) {
tt_abort_msg("Missing data structures.");
}
if (EVTAG_GET(msg2, attack, &attack) == -1) {
tt_abort_msg("Could not get attack.");
}
if (EVTAG_ARRAY_LEN(msg2, run) != i) {
tt_abort_msg("Wrong number of run messages.");
}
/* get the very first run message */
if (EVTAG_ARRAY_GET(msg2, run, 0, &run) == -1) {
tt_abort_msg("Failed to get run msg.");
} else {
/* verify the notes */
char *note_one, *note_two;
ev_uint64_t large_number;
ev_uint32_t short_number;
if (EVTAG_ARRAY_LEN(run, notes) != 2) {
tt_abort_msg("Wrong number of note strings.");
}
if (EVTAG_ARRAY_GET(run, notes, 0, &note_one) == -1 ||
EVTAG_ARRAY_GET(run, notes, 1, &note_two) == -1) {
tt_abort_msg("Could not get note strings.");
}
if (strcmp(note_one, "this is my note") ||
strcmp(note_two, "pps")) {
tt_abort_msg("Incorrect note strings encoded.");
}
if (EVTAG_GET(run, large_number, &large_number) == -1 ||
large_number != 0xdead0a0bcafebeefLL) {
tt_abort_msg("Incorrrect large_number.");
}
if (EVTAG_ARRAY_LEN(run, other_numbers) != 2) {
tt_abort_msg("Wrong number of other_numbers.");
}
if (EVTAG_ARRAY_GET(
run, other_numbers, 0, &short_number) == -1) {
tt_abort_msg("Could not get short number.");
}
tt_uint_op(short_number, ==, 0xdead0a0b);
}
tt_int_op(EVTAG_ARRAY_LEN(attack, how_often), ==, 3);
for (i = 0; i < 3; ++i) {
ev_uint32_t res;
if (EVTAG_ARRAY_GET(attack, how_often, i, &res) == -1) {
TT_DIE(("Cannot get %dth how_often msg.", i));
}
if (res != i) {
TT_DIE(("Wrong message encoded %d != %d", i, res));
}
}
test_ok = 1;
end:
if (msg)
msg_free(msg);
if (msg2)
msg_free(msg2);
if (tmp)
evbuffer_free(tmp);
}
#define RPC_LEGACY(name) \
{ #name, run_legacy_test_fn, TT_FORK|TT_NEED_BASE|TT_LEGACY, \
&legacy_setup, \
rpc_##name }
struct testcase_t rpc_testcases[] = {
RPC_LEGACY(basic_test),
RPC_LEGACY(basic_message),
RPC_LEGACY(basic_client),
RPC_LEGACY(basic_queued_client),
RPC_LEGACY(basic_client_with_pause),
RPC_LEGACY(client_timeout),
RPC_LEGACY(test),
END_OF_TESTCASES,
};

Просмотреть файл

@ -1,400 +0,0 @@
/*
* Copyright (c) 2009-2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef WIN32
#include <winsock2.h>
#include <windows.h>
#endif
#ifndef WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#include <event2/util.h>
#include <event2/event.h>
#include <event2/bufferevent_ssl.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include "regress.h"
#include "tinytest.h"
#include "tinytest_macros.h"
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <string.h>
/* A short pre-generated key, to save the cost of doing an RSA key generation
* step during the unit tests. It's only 512 bits long, and it is published
* in this file, so you would have to be very foolish to consider using it in
* your own code. */
static const char KEY[] =
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIIBOgIBAAJBAKibTEzXjj+sqpipePX1lEk5BNFuL/dDBbw8QCXgaJWikOiKHeJq\n"
"3FQ0OmCnmpkdsPFE4x3ojYmmdgE2i0dJwq0CAwEAAQJAZ08gpUS+qE1IClps/2gG\n"
"AAer6Bc31K2AaiIQvCSQcH440cp062QtWMC3V5sEoWmdLsbAHFH26/9ZHn5zAflp\n"
"gQIhANWOx/UYeR8HD0WREU5kcuSzgzNLwUErHLzxP7U6aojpAiEAyh2H35CjN/P7\n"
"NhcZ4QYw3PeUWpqgJnaE/4i80BSYkSUCIQDLHFhLYLJZ80HwHTADif/ISn9/Ow6b\n"
"p6BWh3DbMar/eQIgBPS6azH5vpp983KXkNv9AL4VZi9ac/b+BeINdzC6GP0CIDmB\n"
"U6GFEQTZ3IfuiVabG5pummdC4DNbcdI+WKrSFNmQ\n"
"-----END RSA PRIVATE KEY-----\n";
static EVP_PKEY *
getkey(void)
{
EVP_PKEY *key;
BIO *bio;
/* new read-only BIO backed by KEY. */
bio = BIO_new_mem_buf((char*)KEY, -1);
tt_assert(bio);
key = PEM_read_bio_PrivateKey(bio,NULL,NULL,NULL);
BIO_free(bio);
tt_assert(key);
return key;
end:
return NULL;
}
static X509 *
getcert(void)
{
/* Dummy code to make a quick-and-dirty valid certificate with
OpenSSL. Don't copy this code into your own program! It does a
number of things in a stupid and insecure way. */
X509 *x509 = NULL;
X509_NAME *name = NULL;
EVP_PKEY *key = getkey();
int nid;
time_t now = time(NULL);
tt_assert(key);
x509 = X509_new();
tt_assert(x509);
tt_assert(0 != X509_set_version(x509, 2));
tt_assert(0 != ASN1_INTEGER_set(X509_get_serialNumber(x509),
(long)now));
name = X509_NAME_new();
tt_assert(name);
tt_assert(NID_undef != (nid = OBJ_txt2nid("commonName")));
tt_assert(0 != X509_NAME_add_entry_by_NID(
name, nid, MBSTRING_ASC, (unsigned char*)"example.com",
-1, -1, 0));
X509_set_subject_name(x509, name);
X509_set_issuer_name(x509, name);
X509_time_adj(X509_get_notBefore(x509), 0, &now);
now += 3600;
X509_time_adj(X509_get_notAfter(x509), 0, &now);
X509_set_pubkey(x509, key);
tt_assert(0 != X509_sign(x509, key, EVP_sha1()));
return x509;
end:
X509_free(x509);
return NULL;
}
static SSL_CTX *the_ssl_ctx = NULL;
static SSL_CTX *
get_ssl_ctx(void)
{
if (the_ssl_ctx)
return the_ssl_ctx;
return (the_ssl_ctx = SSL_CTX_new(SSLv23_method()));
}
static void
init_ssl(void)
{
SSL_library_init();
ERR_load_crypto_strings();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
}
/* ====================
Here's a simple test: we read a number from the input, increment it, and
reply, until we get to 1001.
*/
static int test_is_done = 0;
static int n_connected = 0;
static int got_close = 0;
static int got_error = 0;
static int renegotiate_at = -1;
static void
respond_to_number(struct bufferevent *bev, void *ctx)
{
struct evbuffer *b = bufferevent_get_input(bev);
char *line;
int n;
line = evbuffer_readln(b, NULL, EVBUFFER_EOL_LF);
if (! line)
return;
n = atoi(line);
if (n <= 0)
TT_FAIL(("Bad number: %s", line));
TT_BLATHER(("The number was %d", n));
if (n == 1001) {
++test_is_done;
bufferevent_free(bev); /* Should trigger close on other side. */
return;
}
if (!strcmp(ctx, "client") && n == renegotiate_at) {
SSL_renegotiate(bufferevent_openssl_get_ssl(bev));
}
++n;
evbuffer_add_printf(bufferevent_get_output(bev),
"%d\n", n);
}
static void
eventcb(struct bufferevent *bev, short what, void *ctx)
{
TT_BLATHER(("Got event %d", (int)what));
if (what & BEV_EVENT_CONNECTED) {
SSL *ssl;
X509 *peer_cert;
++n_connected;
ssl = bufferevent_openssl_get_ssl(bev);
tt_assert(ssl);
peer_cert = SSL_get_peer_certificate(ssl);
if (0==strcmp(ctx, "server")) {
tt_assert(peer_cert == NULL);
} else {
tt_assert(peer_cert != NULL);
}
} else if (what & BEV_EVENT_EOF) {
TT_BLATHER(("Got a good EOF"));
++got_close;
bufferevent_free(bev);
} else if (what & BEV_EVENT_ERROR) {
TT_BLATHER(("Got an error."));
++got_error;
bufferevent_free(bev);
}
end:
;
}
static void
regress_bufferevent_openssl(void *arg)
{
struct basic_test_data *data = arg;
struct bufferevent *bev1, *bev2;
SSL *ssl1, *ssl2;
X509 *cert = getcert();
EVP_PKEY *key = getkey();
tt_assert(cert);
tt_assert(key);
init_ssl();
ssl1 = SSL_new(get_ssl_ctx());
ssl2 = SSL_new(get_ssl_ctx());
SSL_use_certificate(ssl2, cert);
SSL_use_PrivateKey(ssl2, key);
if (strstr((char*)data->setup_data, "renegotiate"))
renegotiate_at = 600;
if (strstr((char*)data->setup_data, "socketpair")) {
bev1 = bufferevent_openssl_socket_new(
data->base,
data->pair[0],
ssl1,
BUFFEREVENT_SSL_CONNECTING,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
bev2 = bufferevent_openssl_socket_new(
data->base,
data->pair[1],
ssl2,
BUFFEREVENT_SSL_ACCEPTING,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
tt_int_op(bufferevent_getfd(bev1), ==, data->pair[0]);
} else if (strstr((char*)data->setup_data, "filter")) {
struct bufferevent *bev_ll1, *bev_ll2;
bev_ll1 = bufferevent_socket_new(data->base, data->pair[0],
BEV_OPT_CLOSE_ON_FREE);
bev_ll2 = bufferevent_socket_new(data->base, data->pair[1],
BEV_OPT_CLOSE_ON_FREE);
tt_assert(bev_ll1);
tt_assert(bev_ll2);
bev1 = bufferevent_openssl_filter_new(
data->base,
bev_ll1,
ssl1,
BUFFEREVENT_SSL_CONNECTING,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
bev2 = bufferevent_openssl_filter_new(
data->base,
bev_ll2,
ssl2,
BUFFEREVENT_SSL_ACCEPTING,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev_ll1);
} else {
TT_DIE(("Bad setup data %s", (char*)data->setup_data));
}
bufferevent_enable(bev1, EV_READ|EV_WRITE);
bufferevent_enable(bev2, EV_READ|EV_WRITE);
bufferevent_setcb(bev1, respond_to_number, NULL, eventcb,
(void*)"client");
bufferevent_setcb(bev2, respond_to_number, NULL, eventcb,
(void*)"server");
evbuffer_add_printf(bufferevent_get_output(bev1), "1\n");
event_base_dispatch(data->base);
tt_assert(test_is_done == 1);
tt_assert(n_connected == 2);
/* We don't handle shutdown properly yet.
tt_int_op(got_close, ==, 1);
tt_int_op(got_error, ==, 0);
*/
end:
return;
}
static void
acceptcb(struct evconnlistener *listener, evutil_socket_t fd,
struct sockaddr *addr, int socklen, void *arg)
{
struct basic_test_data *data = arg;
struct bufferevent *bev;
SSL *ssl = SSL_new(get_ssl_ctx());
SSL_use_certificate(ssl, getcert());
SSL_use_PrivateKey(ssl, getkey());
bev = bufferevent_openssl_socket_new(
data->base,
fd,
ssl,
BUFFEREVENT_SSL_ACCEPTING,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
bufferevent_setcb(bev, respond_to_number, NULL, eventcb,
(void*)"server");
bufferevent_enable(bev, EV_READ|EV_WRITE);
/* Only accept once, then disable ourself. */
evconnlistener_disable(listener);
}
static void
regress_bufferevent_openssl_connect(void *arg)
{
struct basic_test_data *data = arg;
struct event_base *base = data->base;
struct evconnlistener *listener;
struct bufferevent *bev;
struct sockaddr_in sin;
struct sockaddr_storage ss;
ev_socklen_t slen;
init_ssl();
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(0x7f000001);
memset(&ss, 0, sizeof(ss));
slen = sizeof(ss);
listener = evconnlistener_new_bind(base, acceptcb, data,
LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
-1, (struct sockaddr *)&sin, sizeof(sin));
tt_assert(listener);
tt_assert(evconnlistener_get_fd(listener) >= 0);
bev = bufferevent_openssl_socket_new(
data->base, -1, SSL_new(get_ssl_ctx()),
BUFFEREVENT_SSL_CONNECTING,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
tt_assert(bev);
bufferevent_setcb(bev, respond_to_number, NULL, eventcb,
(void*)"client");
tt_assert(getsockname(evconnlistener_get_fd(listener),
(struct sockaddr*)&ss, &slen) == 0);
tt_assert(slen == sizeof(struct sockaddr_in));
tt_int_op(((struct sockaddr*)&ss)->sa_family, ==, AF_INET);
tt_int_op(((struct sockaddr*)&ss)->sa_family, ==, AF_INET);
tt_assert(0 ==
bufferevent_socket_connect(bev, (struct sockaddr*)&ss, slen));
evbuffer_add_printf(bufferevent_get_output(bev), "1\n");
bufferevent_enable(bev, EV_READ|EV_WRITE);
event_base_dispatch(base);
end:
;
}
struct testcase_t ssl_testcases[] = {
{ "bufferevent_socketpair", regress_bufferevent_openssl, TT_ISOLATED,
&basic_setup, (void*)"socketpair" },
{ "bufferevent_filter", regress_bufferevent_openssl,
TT_ISOLATED,
&basic_setup, (void*)"filter" },
{ "bufferevent_renegotiate_socketpair", regress_bufferevent_openssl,
TT_ISOLATED,
&basic_setup, (void*)"socketpair renegotiate" },
{ "bufferevent_renegotiate_filter", regress_bufferevent_openssl,
TT_ISOLATED,
&basic_setup, (void*)"filter renegotiate" },
{ "bufferevent_connect", regress_bufferevent_openssl_connect,
TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
END_OF_TESTCASES,
};

Просмотреть файл

@ -1,195 +0,0 @@
/*
* Copyright (c) 2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef WIN32
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#endif
#include "event2/event-config.h"
#include <sys/types.h>
#include <sys/stat.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <sys/queue.h>
#ifndef WIN32
#include <sys/socket.h>
#include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#ifdef _EVENT_HAVE_NETINET_IN6_H
#include <netinet/in6.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "event2/event.h"
#include "event2/event_compat.h"
#include <event2/util.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>
#include "evdns.h"
#include "log-internal.h"
#include "regress.h"
#include "regress_testutils.h"
/* globals */
static struct evdns_server_port *dns_port;
evutil_socket_t dns_sock = -1;
/* Helper: return the port that a socket is bound on, in host order. */
int
regress_get_socket_port(evutil_socket_t fd)
{
struct sockaddr_storage ss;
ev_socklen_t socklen = sizeof(ss);
if (getsockname(fd, (struct sockaddr*)&ss, &socklen) != 0)
return -1;
if (ss.ss_family == AF_INET)
return ntohs( ((struct sockaddr_in*)&ss)->sin_port);
else if (ss.ss_family == AF_INET6)
return ntohs( ((struct sockaddr_in6*)&ss)->sin6_port);
else
return -1;
}
struct evdns_server_port *
regress_get_dnsserver(struct event_base *base,
ev_uint16_t *portnum,
evutil_socket_t *psock,
evdns_request_callback_fn_type cb,
void *arg)
{
struct evdns_server_port *port = NULL;
evutil_socket_t sock;
struct sockaddr_in my_addr;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock <= 0) {
tt_abort_perror("socket");
}
evutil_make_socket_nonblocking(sock);
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(*portnum);
my_addr.sin_addr.s_addr = htonl(0x7f000001UL);
if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) {
tt_abort_perror("bind");
}
port = evdns_add_server_port_with_base(base, sock, 0, cb, arg);
if (!*portnum)
*portnum = regress_get_socket_port(sock);
if (psock)
*psock = sock;
return port;
end:
return NULL;
}
void
regress_clean_dnsserver(void)
{
if (dns_port)
evdns_close_server_port(dns_port);
if (dns_sock >= 0)
evutil_closesocket(dns_sock);
}
void
regress_dns_server_cb(struct evdns_server_request *req, void *data)
{
struct regress_dns_server_table *tab = data;
const char *question;
if (req->nquestions != 1)
TT_DIE(("Only handling one question at a time; got %d",
req->nquestions));
question = req->questions[0]->name;
while (tab->q && evutil_ascii_strcasecmp(question, tab->q) &&
strcmp("*", tab->q))
++tab;
if (tab->q == NULL)
TT_DIE(("Unexpected question: '%s'", question));
++tab->seen;
if (!strcmp(tab->anstype, "err")) {
int err = atoi(tab->ans);
tt_assert(! evdns_server_request_respond(req, err));
return;
} else if (!strcmp(tab->anstype, "A")) {
struct in_addr in;
evutil_inet_pton(AF_INET, tab->ans, &in);
evdns_server_request_add_a_reply(req, question, 1, &in.s_addr,
100);
} else if (!strcmp(tab->anstype, "AAAA")) {
struct in6_addr in6;
evutil_inet_pton(AF_INET6, tab->ans, &in6);
evdns_server_request_add_aaaa_reply(req,
question, 1, &in6.s6_addr, 100);
} else {
TT_DIE(("Weird table entry with type '%s'", tab->anstype));
}
tt_assert(! evdns_server_request_respond(req, 0))
return;
end:
tt_want(! evdns_server_request_drop(req));
}
int
regress_dnsserver(struct event_base *base, ev_uint16_t *port,
struct regress_dns_server_table *search_table)
{
dns_port = regress_get_dnsserver(base, port, &dns_sock,
regress_dns_server_cb, search_table);
return dns_port != NULL;
}
int
regress_get_listener_addr(struct evconnlistener *lev,
struct sockaddr *sa, ev_socklen_t *socklen)
{
evutil_socket_t s = evconnlistener_get_fd(lev);
if (s <= 0)
return -1;
return getsockname(s, sa, socklen);
}

Просмотреть файл

@ -1,66 +0,0 @@
/*
* Copyright (c) 2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TESTUTILS_H
#define _TESTUTILS_H
#include <event2/dns.h>
struct regress_dns_server_table {
const char *q;
const char *anstype;
const char *ans;
int seen;
};
struct evdns_server_port *
regress_get_dnsserver(struct event_base *base,
ev_uint16_t *portnum,
evutil_socket_t *psock,
evdns_request_callback_fn_type cb,
void *arg);
/* Helper: return the port that a socket is bound on, in host order. */
int regress_get_socket_port(evutil_socket_t fd);
/* used to look up pre-canned responses in a search table */
void regress_dns_server_cb(
struct evdns_server_request *req, void *data);
/* globally allocates a dns server that serves from a search table */
int regress_dnsserver(struct event_base *base, ev_uint16_t *port,
struct regress_dns_server_table *seach_table);
/* clean up the global dns server resources */
void regress_clean_dnsserver(void);
struct evconnlistener;
struct sockaddr;
int regress_get_listener_addr(struct evconnlistener *lev,
struct sockaddr *sa, ev_socklen_t *socklen);
#endif /* _TESTUTILS_H */

Просмотреть файл

@ -1,501 +0,0 @@
/*
* Copyright (c) 2007-2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* The old tests here need assertions to work. */
#undef NDEBUG
#include "event2/event-config.h"
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _EVENT_HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef _EVENT_HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#ifdef _EVENT_HAVE_PTHREADS
#include <pthread.h>
#elif defined(WIN32)
#include <process.h>
#endif
#include <assert.h>
#ifdef _EVENT_HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <time.h>
#include "sys/queue.h"
#include "event2/util.h"
#include "event2/event.h"
#include "event2/event_struct.h"
#include "event2/thread.h"
#include "evthread-internal.h"
#include "event-internal.h"
#include "defer-internal.h"
#include "regress.h"
#include "tinytest_macros.h"
#ifdef _EVENT_HAVE_PTHREADS
#define THREAD_T pthread_t
#define THREAD_FN void *
#define THREAD_RETURN() return (NULL)
#define THREAD_START(threadvar, fn, arg) \
pthread_create(&(threadvar), NULL, fn, arg)
#define THREAD_JOIN(th) pthread_join(th, NULL)
#else
#define THREAD_T HANDLE
#define THREAD_FN unsigned __stdcall
#define THREAD_RETURN() return (0)
#define THREAD_START(threadvar, fn, arg) do { \
uintptr_t threadhandle = _beginthreadex(NULL,0,fn,(arg),0,NULL); \
(threadvar) = (HANDLE) threadhandle; \
} while (0)
#define THREAD_JOIN(th) WaitForSingleObject(th, INFINITE)
#endif
struct cond_wait {
void *lock;
void *cond;
};
static void
wake_all_timeout(evutil_socket_t fd, short what, void *arg)
{
struct cond_wait *cw = arg;
EVLOCK_LOCK(cw->lock, 0);
EVTHREAD_COND_BROADCAST(cw->cond);
EVLOCK_UNLOCK(cw->lock, 0);
}
static void
wake_one_timeout(evutil_socket_t fd, short what, void *arg)
{
struct cond_wait *cw = arg;
EVLOCK_LOCK(cw->lock, 0);
EVTHREAD_COND_SIGNAL(cw->cond);
EVLOCK_UNLOCK(cw->lock, 0);
}
#define NUM_THREADS 100
#define NUM_ITERATIONS 100
void *count_lock;
static int count;
static THREAD_FN
basic_thread(void *arg)
{
struct cond_wait cw;
struct event_base *base = arg;
struct event ev;
int i = 0;
EVTHREAD_ALLOC_LOCK(cw.lock, 0);
EVTHREAD_ALLOC_COND(cw.cond);
assert(cw.lock);
assert(cw.cond);
evtimer_assign(&ev, base, wake_all_timeout, &cw);
for (i = 0; i < NUM_ITERATIONS; i++) {
struct timeval tv;
evutil_timerclear(&tv);
tv.tv_sec = 0;
tv.tv_usec = 3000;
EVLOCK_LOCK(cw.lock, 0);
/* we need to make sure that event does not happen before
* we get to wait on the conditional variable */
assert(evtimer_add(&ev, &tv) == 0);
assert(EVTHREAD_COND_WAIT(cw.cond, cw.lock) == 0);
EVLOCK_UNLOCK(cw.lock, 0);
EVLOCK_LOCK(count_lock, 0);
++count;
EVLOCK_UNLOCK(count_lock, 0);
}
/* exit the loop only if all threads fired all timeouts */
EVLOCK_LOCK(count_lock, 0);
if (count >= NUM_THREADS * NUM_ITERATIONS)
event_base_loopexit(base, NULL);
EVLOCK_UNLOCK(count_lock, 0);
EVTHREAD_FREE_LOCK(cw.lock, 0);
EVTHREAD_FREE_COND(cw.cond);
THREAD_RETURN();
}
static int notification_fd_used = 0;
#ifndef WIN32
static int got_sigchld = 0;
static void
sigchld_cb(evutil_socket_t fd, short event, void *arg)
{
struct timeval tv;
struct event_base *base = arg;
got_sigchld++;
tv.tv_usec = 100000;
tv.tv_sec = 0;
event_base_loopexit(base, &tv);
}
static void
notify_fd_cb(evutil_socket_t fd, short event, void *arg)
{
++notification_fd_used;
}
#endif
static void
thread_basic(void *arg)
{
THREAD_T threads[NUM_THREADS];
struct event ev;
struct timeval tv;
int i;
struct basic_test_data *data = arg;
struct event_base *base = data->base;
struct event *notification_event = NULL;
struct event *sigchld_event = NULL;
EVTHREAD_ALLOC_LOCK(count_lock, 0);
tt_assert(count_lock);
tt_assert(base);
if (evthread_make_base_notifiable(base)<0) {
tt_abort_msg("Couldn't make base notifiable!");
}
#ifndef WIN32
if (data->setup_data && !strcmp(data->setup_data, "forking")) {
pid_t pid;
int status;
sigchld_event = evsignal_new(base, SIGCHLD, sigchld_cb, base);
/* This piggybacks on the th_notify_fd weirdly, and looks
* inside libevent internals. Not a good idea in non-testing
* code! */
notification_event = event_new(base,
base->th_notify_fd[0], EV_READ|EV_PERSIST, notify_fd_cb,
NULL);
event_add(sigchld_event, NULL);
event_add(notification_event, NULL);
if ((pid = fork()) == 0) {
if (event_reinit(base) < 0) {
TT_FAIL(("reinit"));
exit(1);
}
goto child;
}
event_base_dispatch(base);
if (waitpid(pid, &status, 0) == -1)
tt_abort_perror("waitpid");
TT_BLATHER(("Waitpid okay\n"));
tt_assert(got_sigchld);
tt_int_op(notification_fd_used, ==, 0);
goto end;
}
child:
#endif
for (i = 0; i < NUM_THREADS; ++i)
THREAD_START(threads[i], basic_thread, base);
evtimer_assign(&ev, base, NULL, NULL);
evutil_timerclear(&tv);
tv.tv_sec = 1000;
event_add(&ev, &tv);
event_base_dispatch(base);
for (i = 0; i < NUM_THREADS; ++i)
THREAD_JOIN(threads[i]);
event_del(&ev);
tt_int_op(count, ==, NUM_THREADS * NUM_ITERATIONS);
EVTHREAD_FREE_LOCK(count_lock, 0);
TT_BLATHER(("notifiations==%d", notification_fd_used));
end:
if (notification_event)
event_free(notification_event);
if (sigchld_event)
event_free(sigchld_event);
}
#undef NUM_THREADS
#define NUM_THREADS 10
struct alerted_record {
struct cond_wait *cond;
struct timeval delay;
struct timeval alerted_at;
int timed_out;
};
static THREAD_FN
wait_for_condition(void *arg)
{
struct alerted_record *rec = arg;
int r;
EVLOCK_LOCK(rec->cond->lock, 0);
if (rec->delay.tv_sec || rec->delay.tv_usec) {
r = EVTHREAD_COND_WAIT_TIMED(rec->cond->cond, rec->cond->lock,
&rec->delay);
} else {
r = EVTHREAD_COND_WAIT(rec->cond->cond, rec->cond->lock);
}
EVLOCK_UNLOCK(rec->cond->lock, 0);
evutil_gettimeofday(&rec->alerted_at, NULL);
if (r == 1)
rec->timed_out = 1;
THREAD_RETURN();
}
static void
thread_conditions_simple(void *arg)
{
struct timeval tv_signal, tv_timeout, tv_broadcast;
struct alerted_record alerted[NUM_THREADS];
THREAD_T threads[NUM_THREADS];
struct cond_wait cond;
int i;
struct timeval launched_at;
struct event wake_one;
struct event wake_all;
struct basic_test_data *data = arg;
struct event_base *base = data->base;
int n_timed_out=0, n_signal=0, n_broadcast=0;
tv_signal.tv_sec = tv_timeout.tv_sec = tv_broadcast.tv_sec = 0;
tv_signal.tv_usec = 30*1000;
tv_timeout.tv_usec = 150*1000;
tv_broadcast.tv_usec = 500*1000;
EVTHREAD_ALLOC_LOCK(cond.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
EVTHREAD_ALLOC_COND(cond.cond);
tt_assert(cond.lock);
tt_assert(cond.cond);
for (i = 0; i < NUM_THREADS; ++i) {
memset(&alerted[i], 0, sizeof(struct alerted_record));
alerted[i].cond = &cond;
}
/* Threads 5 and 6 will be allowed to time out */
memcpy(&alerted[5].delay, &tv_timeout, sizeof(tv_timeout));
memcpy(&alerted[6].delay, &tv_timeout, sizeof(tv_timeout));
evtimer_assign(&wake_one, base, wake_one_timeout, &cond);
evtimer_assign(&wake_all, base, wake_all_timeout, &cond);
evutil_gettimeofday(&launched_at, NULL);
/* Launch the threads... */
for (i = 0; i < NUM_THREADS; ++i) {
THREAD_START(threads[i], wait_for_condition, &alerted[i]);
}
/* Start the timers... */
tt_int_op(event_add(&wake_one, &tv_signal), ==, 0);
tt_int_op(event_add(&wake_all, &tv_broadcast), ==, 0);
/* And run for a bit... */
event_base_dispatch(base);
/* And wait till the threads are done. */
for (i = 0; i < NUM_THREADS; ++i)
THREAD_JOIN(threads[i]);
/* Now, let's see what happened. At least one of 5 or 6 should
* have timed out. */
n_timed_out = alerted[5].timed_out + alerted[6].timed_out;
tt_int_op(n_timed_out, >=, 1);
tt_int_op(n_timed_out, <=, 2);
for (i = 0; i < NUM_THREADS; ++i) {
const struct timeval *target_delay;
struct timeval target_time, actual_delay;
if (alerted[i].timed_out) {
TT_BLATHER(("%d looks like a timeout\n", i));
target_delay = &tv_timeout;
tt_assert(i == 5 || i == 6);
} else if (evutil_timerisset(&alerted[i].alerted_at)) {
long diff1,diff2;
evutil_timersub(&alerted[i].alerted_at,
&launched_at, &actual_delay);
diff1 = timeval_msec_diff(&actual_delay,
&tv_signal);
diff2 = timeval_msec_diff(&actual_delay,
&tv_broadcast);
if (abs(diff1) < abs(diff2)) {
TT_BLATHER(("%d looks like a signal\n", i));
target_delay = &tv_signal;
++n_signal;
} else {
TT_BLATHER(("%d looks like a broadcast\n", i));
target_delay = &tv_broadcast;
++n_broadcast;
}
} else {
TT_FAIL(("Thread %d never got woken", i));
continue;
}
evutil_timeradd(target_delay, &launched_at, &target_time);
test_timeval_diff_leq(&target_time, &alerted[i].alerted_at,
0, 50);
}
tt_int_op(n_broadcast + n_signal + n_timed_out, ==, NUM_THREADS);
tt_int_op(n_signal, ==, 1);
end:
;
}
#define CB_COUNT 128
#define QUEUE_THREAD_COUNT 8
#ifdef WIN32
#define SLEEP_MS(ms) Sleep(ms)
#else
#define SLEEP_MS(ms) usleep((ms) * 1000)
#endif
struct deferred_test_data {
struct deferred_cb cbs[CB_COUNT];
struct deferred_cb_queue *queue;
};
static time_t timer_start = 0;
static time_t timer_end = 0;
static unsigned callback_count = 0;
static THREAD_T load_threads[QUEUE_THREAD_COUNT];
static struct deferred_test_data deferred_data[QUEUE_THREAD_COUNT];
static void
deferred_callback(struct deferred_cb *cb, void *arg)
{
SLEEP_MS(1);
callback_count += 1;
}
static THREAD_FN
load_deferred_queue(void *arg)
{
struct deferred_test_data *data = arg;
size_t i;
for (i = 0; i < CB_COUNT; ++i) {
event_deferred_cb_init(&data->cbs[i], deferred_callback, NULL);
event_deferred_cb_schedule(data->queue, &data->cbs[i]);
SLEEP_MS(1);
}
THREAD_RETURN();
}
static void
timer_callback(evutil_socket_t fd, short what, void *arg)
{
timer_end = time(NULL);
}
static void
start_threads_callback(evutil_socket_t fd, short what, void *arg)
{
int i;
for (i = 0; i < QUEUE_THREAD_COUNT; ++i) {
THREAD_START(load_threads[i], load_deferred_queue,
&deferred_data[i]);
}
}
static void
thread_deferred_cb_skew(void *arg)
{
struct basic_test_data *data = arg;
struct timeval tv_timer = {4, 0};
struct deferred_cb_queue *queue;
int i;
queue = event_base_get_deferred_cb_queue(data->base);
tt_assert(queue);
for (i = 0; i < QUEUE_THREAD_COUNT; ++i)
deferred_data[i].queue = queue;
timer_start = time(NULL);
event_base_once(data->base, -1, EV_TIMEOUT, timer_callback, NULL,
&tv_timer);
event_base_once(data->base, -1, EV_TIMEOUT, start_threads_callback,
NULL, NULL);
event_base_dispatch(data->base);
TT_BLATHER(("callback count, %u", callback_count));
tt_int_op(timer_end - timer_start, ==, 4);
end:
for (i = 0; i < QUEUE_THREAD_COUNT; ++i)
THREAD_JOIN(load_threads[i]);
}
#define TEST(name) \
{ #name, thread_##name, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE, \
&basic_setup, NULL }
struct testcase_t thread_testcases[] = {
{ "basic", thread_basic, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE,
&basic_setup, NULL },
#ifndef WIN32
{ "forking", thread_basic, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE,
&basic_setup, (char*)"forking" },
#endif
TEST(conditions_simple),
TEST(deferred_cb_skew),
END_OF_TESTCASES
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,322 +0,0 @@
/*
* Copyright (c) 2008-2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* The old tests here need assertions to work. */
#undef NDEBUG
#ifdef WIN32
#include <winsock2.h>
#include <windows.h>
#endif
#include "event2/event-config.h"
#include <sys/types.h>
#ifndef WIN32
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <netdb.h>
#endif
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zlib.h>
#include <assert.h>
#include <errno.h>
#include "event2/util.h"
#include "event2/event.h"
#include "event2/event_compat.h"
#include "event2/buffer.h"
#include "event2/bufferevent.h"
#include "regress.h"
static int infilter_calls;
static int outfilter_calls;
static int readcb_finished;
static int writecb_finished;
static int errorcb_invoked;
/*
* Zlib filters
*/
static void
zlib_deflate_free(void *ctx)
{
z_streamp p = ctx;
assert(deflateEnd(p) == Z_OK);
}
static void
zlib_inflate_free(void *ctx)
{
z_streamp p = ctx;
assert(inflateEnd(p) == Z_OK);
}
static int
getstate(enum bufferevent_flush_mode state)
{
switch (state) {
case BEV_FINISHED:
return Z_FINISH;
case BEV_FLUSH:
return Z_SYNC_FLUSH;
case BEV_NORMAL:
default:
return Z_NO_FLUSH;
}
}
/*
* The input filter is triggered only on new input read from the network.
* That means all input data needs to be consumed or the filter needs to
* initiate its own triggering via a timeout.
*/
static enum bufferevent_filter_result
zlib_input_filter(struct evbuffer *src, struct evbuffer *dst,
ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
{
struct evbuffer_iovec v_in[1];
struct evbuffer_iovec v_out[1];
int nread, nwrite;
int res, n;
z_streamp p = ctx;
do {
/* let's do some decompression */
n = evbuffer_peek(src, -1, NULL, v_in, 1);
if (n) {
p->avail_in = v_in[0].iov_len;
p->next_in = v_in[0].iov_base;
} else {
p->avail_in = 0;
p->next_in = 0;
}
evbuffer_reserve_space(dst, 4096, v_out, 1);
p->next_out = v_out[0].iov_base;
p->avail_out = v_out[0].iov_len;
/* we need to flush zlib if we got a flush */
res = inflate(p, getstate(state));
/* let's figure out how much was compressed */
nread = v_in[0].iov_len - p->avail_in;
nwrite = v_out[0].iov_len - p->avail_out;
evbuffer_drain(src, nread);
v_out[0].iov_len = nwrite;
evbuffer_commit_space(dst, v_out, 1);
if (res==Z_BUF_ERROR) {
/* We're out of space, or out of decodeable input.
Only if nwrite == 0 assume the latter.
*/
if (nwrite == 0)
return BEV_NEED_MORE;
} else {
assert(res == Z_OK || res == Z_STREAM_END);
}
} while (evbuffer_get_length(src) > 0);
++infilter_calls;
return (BEV_OK);
}
static enum bufferevent_filter_result
zlib_output_filter(struct evbuffer *src, struct evbuffer *dst,
ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
{
struct evbuffer_iovec v_in[1];
struct evbuffer_iovec v_out[1];
int nread, nwrite;
int res, n;
z_streamp p = ctx;
do {
/* let's do some compression */
n = evbuffer_peek(src, -1, NULL, v_in, 1);
if (n) {
p->avail_in = v_in[0].iov_len;
p->next_in = v_in[0].iov_base;
} else {
p->avail_in = 0;
p->next_in = 0;
}
evbuffer_reserve_space(dst, 4096, v_out, 1);
p->next_out = v_out[0].iov_base;
p->avail_out = v_out[0].iov_len;
/* we need to flush zlib if we got a flush */
res = deflate(p, getstate(state));
/* let's figure out how much was decompressed */
nread = v_in[0].iov_len - p->avail_in;
nwrite = v_out[0].iov_len - p->avail_out;
evbuffer_drain(src, nread);
v_out[0].iov_len = nwrite;
evbuffer_commit_space(dst, v_out, 1);
if (res==Z_BUF_ERROR) {
/* We're out of space, or out of decodeable input.
Only if nwrite == 0 assume the latter.
*/
if (nwrite == 0)
return BEV_NEED_MORE;
} else {
assert(res == Z_OK || res == Z_STREAM_END);
}
} while (evbuffer_get_length(src) > 0);
++outfilter_calls;
return (BEV_OK);
}
/*
* simple bufferevent test (over transparent zlib treatment)
*/
static void
readcb(struct bufferevent *bev, void *arg)
{
if (evbuffer_get_length(bufferevent_get_input(bev)) == 8333) {
struct evbuffer *evbuf = evbuffer_new();
assert(evbuf != NULL);
/* gratuitous test of bufferevent_read_buffer */
bufferevent_read_buffer(bev, evbuf);
bufferevent_disable(bev, EV_READ);
if (evbuffer_get_length(evbuf) == 8333) {
++readcb_finished;
}
evbuffer_free(evbuf);
}
}
static void
writecb(struct bufferevent *bev, void *arg)
{
if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
++writecb_finished;
}
}
static void
errorcb(struct bufferevent *bev, short what, void *arg)
{
errorcb_invoked = 1;
}
void
test_bufferevent_zlib(void *arg)
{
struct bufferevent *bev1=NULL, *bev2=NULL, *bev1_orig, *bev2_orig;
char buffer[8333];
z_stream z_input, z_output;
int i, pair[2]={-1,-1}, r;
(void)arg;
infilter_calls = outfilter_calls = readcb_finished = writecb_finished
= errorcb_invoked = 0;
if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
tt_abort_perror("socketpair");
}
evutil_make_socket_nonblocking(pair[0]);
evutil_make_socket_nonblocking(pair[1]);
bev1_orig = bev1 = bufferevent_socket_new(NULL, pair[0], 0);
bev2_orig = bev2 = bufferevent_socket_new(NULL, pair[1], 0);
memset(&z_output, 0, sizeof(z_output));
r = deflateInit(&z_output, Z_DEFAULT_COMPRESSION);
tt_int_op(r, ==, Z_OK);
memset(&z_input, 0, sizeof(z_input));
r = inflateInit(&z_input);
/* initialize filters */
bev1 = bufferevent_filter_new(bev1, NULL, zlib_output_filter,
BEV_OPT_CLOSE_ON_FREE, zlib_deflate_free, &z_output);
bev2 = bufferevent_filter_new(bev2, zlib_input_filter,
NULL, BEV_OPT_CLOSE_ON_FREE, zlib_inflate_free, &z_input);
bufferevent_setcb(bev1, readcb, writecb, errorcb, NULL);
bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL);
bufferevent_disable(bev1, EV_READ);
bufferevent_enable(bev1, EV_WRITE);
bufferevent_enable(bev2, EV_READ);
for (i = 0; i < sizeof(buffer); i++)
buffer[i] = i;
/* break it up into multiple buffer chains */
bufferevent_write(bev1, buffer, 1800);
bufferevent_write(bev1, buffer + 1800, sizeof(buffer) - 1800);
/* we are done writing - we need to flush everything */
bufferevent_flush(bev1, EV_WRITE, BEV_FINISHED);
event_dispatch();
tt_want(infilter_calls);
tt_want(outfilter_calls);
tt_want(readcb_finished);
tt_want(writecb_finished);
tt_want(!errorcb_invoked);
test_ok = 1;
end:
if (bev1)
bufferevent_free(bev1);
if (bev2)
bufferevent_free(bev2);
if (pair[0] >= 0)
evutil_closesocket(pair[0]);
if (pair[1] >= 0)
evutil_closesocket(pair[1]);
}

Просмотреть файл

@ -1,199 +0,0 @@
/*
* based on test-eof.c
*/
#include "event2/event-config.h"
#ifdef WIN32
#include <winsock2.h>
#include <windows.h>
#else
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef _EVENT_HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <event2/event.h>
#include <event2/util.h>
#include <time.h>
struct cpu_usage_timer {
#ifdef WIN32
HANDLE thread;
FILETIME usertimeBegin;
FILETIME kerneltimeBegin;
#else
clock_t ticksBegin;
#endif
struct timeval timeBegin;
};
static void
start_cpu_usage_timer(struct cpu_usage_timer *timer)
{
#ifdef WIN32
int r;
FILETIME createtime, exittime;
timer->thread = GetCurrentThread();
r = GetThreadTimes(timer->thread, &createtime, &exittime,
&timer->usertimeBegin, &timer->kerneltimeBegin);
if (r==0) printf("GetThreadTimes failed.");
#else
timer->ticksBegin = clock();
#endif
evutil_gettimeofday(&timer->timeBegin, NULL);
}
#ifdef WIN32
static ev_int64_t
filetime_to_100nsec(const FILETIME *ft)
{
/* Number of 100-nanosecond units */
ev_int64_t n = ft->dwHighDateTime;
n <<= 32;
n += ft->dwLowDateTime;
return n;
}
static double
filetime_diff(const FILETIME *ftStart, const FILETIME *ftEnd)
{
ev_int64_t s, e, diff;
double r;
s = filetime_to_100nsec(ftStart);
e = filetime_to_100nsec(ftEnd);
diff = e - s;
r = (double) diff;
return r / 1.0e7;
}
#endif
static void
get_cpu_usage(struct cpu_usage_timer *timer, double *secElapsedOut,
double *secUsedOut, double *usageOut)
{
#ifdef WIN32
double usertime_seconds, kerneltime_seconds;
FILETIME createtime, exittime, usertimeEnd, kerneltimeEnd;
int r;
#else
clock_t ticksEnd;
#endif
struct timeval timeEnd, timeDiff;
double secondsPassed, secondsUsed;
#ifdef WIN32
r = GetThreadTimes(timer->thread, &createtime, &exittime,
&usertimeEnd, &kerneltimeEnd);
if (r==0) printf("GetThreadTimes failed.");
usertime_seconds = filetime_diff(&timer->usertimeBegin, &usertimeEnd);
kerneltime_seconds = filetime_diff(&timer->kerneltimeBegin, &kerneltimeEnd);
secondsUsed = kerneltime_seconds + usertime_seconds;
#else
ticksEnd = clock();
secondsUsed = (ticksEnd - timer->ticksBegin) / (double)CLOCKS_PER_SEC;
#endif
evutil_gettimeofday(&timeEnd, NULL);
evutil_timersub(&timeEnd, &timer->timeBegin, &timeDiff);
secondsPassed = timeDiff.tv_sec + (timeDiff.tv_usec / 1.0e6);
*secElapsedOut = secondsPassed;
*secUsedOut = secondsUsed;
*usageOut = secondsUsed / secondsPassed;
}
static void
write_cb(evutil_socket_t fd, short event, void *arg)
{
printf("write callback. should only see this once\n");
/* got what we want remove the event */
event_del(*(struct event**)arg);
/* opps changed my mind add it back again */
event_add(*(struct event**)arg,NULL);
/* not a good day for decisiveness, I really didn't want it after all */
event_del(*(struct event**)arg);
}
static void
timeout_cb(evutil_socket_t fd, short event, void *arg)
{
printf("timeout fired, time to end test\n");
event_del(*(struct event**)arg);
return;
}
int
main(int argc, char **argv)
{
struct event* ev;
struct event* timeout;
struct event_base* base;
int pair[2];
int res;
struct timeval tv;
struct cpu_usage_timer timer;
double usage, secPassed, secUsed;
#ifdef WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
#endif
if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
return (1);
/* Initalize the event library */
base = event_base_new();
/* Initalize a timeout to terminate the test */
timeout = evtimer_new(base,timeout_cb,&timeout);
/* and watch for writability on one end of the pipe */
ev = event_new(base,pair[1],EV_WRITE | EV_PERSIST, write_cb, &ev);
tv.tv_sec = 5;
tv.tv_usec = 0;
evtimer_add(timeout, &tv);
event_add(ev, NULL);
start_cpu_usage_timer(&timer);
res = event_base_dispatch(base);
get_cpu_usage(&timer, &secPassed, &secUsed, &usage);
/* attempt to calculate our cpu usage over the test should be
virtually nil */
printf("usec used=%d, usec passed=%d, cpu usage=%.2f%%\n",
(int)(secUsed*1e6),
(int)(secPassed*1e6),
usage*100);
if (usage > 50.0) /* way too high */
return 1;
return 0;
}

Просмотреть файл

@ -1,96 +0,0 @@
/*
* Compile with:
* cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
*/
#include "event2/event-config.h"
#ifdef WIN32
#include <winsock2.h>
#else
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef _EVENT_HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <event.h>
#include <evutil.h>
#ifdef _EVENT___func__
#define __func__ _EVENT___func__
#endif
int test_okay = 1;
int called = 0;
static void
read_cb(evutil_socket_t fd, short event, void *arg)
{
char buf[256];
int len;
len = recv(fd, buf, sizeof(buf), 0);
printf("%s: read %d%s\n", __func__,
len, len ? "" : " - means EOF");
if (len) {
if (!called)
event_add(arg, NULL);
} else if (called == 1)
test_okay = 0;
called++;
}
#ifndef SHUT_WR
#define SHUT_WR 1
#endif
int
main(int argc, char **argv)
{
struct event ev;
const char *test = "test string";
int pair[2];
#ifdef WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
#endif
if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
return (1);
send(pair[0], test, strlen(test)+1, 0);
shutdown(pair[0], SHUT_WR);
/* Initalize the event library */
event_init();
/* Initalize one event */
event_set(&ev, pair[1], EV_READ, read_cb, &ev);
event_add(&ev, NULL);
event_dispatch();
return (test_okay);
}

Просмотреть файл

@ -1,44 +0,0 @@
/*
* Compile with:
* cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
*/
#include "event2/event-config.h"
#include <sys/types.h>
#include <sys/stat.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef _EVENT_HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <errno.h>
#include <event.h>
int
main(int argc, char **argv)
{
#ifdef WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
#endif
/* Initalize the event library */
event_init();
return (0);
}

Просмотреть файл

@ -1,456 +0,0 @@
/*
* Copyright (c) 2009-2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#ifdef WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#include <signal.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/event.h>
#include <event2/util.h>
#include <event2/listener.h>
#include <event2/thread.h>
static int cfg_verbose = 0;
static int cfg_help = 0;
static int cfg_n_connections = 30;
static int cfg_duration = 5;
static int cfg_connlimit = 0;
static int cfg_grouplimit = 0;
static int cfg_tick_msec = 1000;
static int cfg_min_share = -1;
static int cfg_connlimit_tolerance = -1;
static int cfg_grouplimit_tolerance = -1;
static int cfg_stddev_tolerance = -1;
static struct timeval cfg_tick = { 0, 500*1000 };
static struct ev_token_bucket_cfg *conn_bucket_cfg = NULL;
static struct ev_token_bucket_cfg *group_bucket_cfg = NULL;
struct bufferevent_rate_limit_group *ratelim_group = NULL;
static double seconds_per_tick = 0.0;
struct client_state {
size_t queued;
ev_uint64_t received;
};
static int n_echo_conns_open = 0;
static void
loud_writecb(struct bufferevent *bev, void *ctx)
{
struct client_state *cs = ctx;
struct evbuffer *output = bufferevent_get_output(bev);
char buf[1024];
#ifdef WIN32
int r = rand() % 256;
#else
int r = random() % 256;
#endif
memset(buf, r, sizeof(buf));
while (evbuffer_get_length(output) < 8192) {
evbuffer_add(output, buf, sizeof(buf));
cs->queued += sizeof(buf);
}
}
static void
discard_readcb(struct bufferevent *bev, void *ctx)
{
struct client_state *cs = ctx;
struct evbuffer *input = bufferevent_get_input(bev);
size_t len = evbuffer_get_length(input);
evbuffer_drain(input, len);
cs->received += len;
}
static void
write_on_connectedcb(struct bufferevent *bev, short what, void *ctx)
{
if (what & BEV_EVENT_CONNECTED) {
loud_writecb(bev, ctx);
/* XXXX this shouldn't be needed. */
bufferevent_enable(bev, EV_READ|EV_WRITE);
}
}
static void
echo_readcb(struct bufferevent *bev, void *ctx)
{
struct evbuffer *input = bufferevent_get_input(bev);
struct evbuffer *output = bufferevent_get_output(bev);
evbuffer_add_buffer(output, input);
if (evbuffer_get_length(output) > 1024000)
bufferevent_disable(bev, EV_READ);
}
static void
echo_writecb(struct bufferevent *bev, void *ctx)
{
struct evbuffer *output = bufferevent_get_output(bev);
if (evbuffer_get_length(output) < 512000)
bufferevent_enable(bev, EV_READ);
}
static void
echo_eventcb(struct bufferevent *bev, short what, void *ctx)
{
if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
--n_echo_conns_open;
bufferevent_free(bev);
}
}
static void
echo_listenercb(struct evconnlistener *listener, evutil_socket_t newsock,
struct sockaddr *sourceaddr, int socklen, void *ctx)
{
struct event_base *base = ctx;
int flags = BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE;
struct bufferevent *bev;
bev = bufferevent_socket_new(base, newsock, flags);
bufferevent_setcb(bev, echo_readcb, echo_writecb, echo_eventcb, NULL);
if (conn_bucket_cfg)
bufferevent_set_rate_limit(bev, conn_bucket_cfg);
if (ratelim_group)
bufferevent_add_to_rate_limit_group(bev, ratelim_group);
++n_echo_conns_open;
bufferevent_enable(bev, EV_READ|EV_WRITE);
}
static int
test_ratelimiting(void)
{
struct event_base *base;
struct sockaddr_in sin;
struct evconnlistener *listener;
struct sockaddr_storage ss;
ev_socklen_t slen;
struct bufferevent **bevs;
struct client_state *states;
struct bufferevent_rate_limit_group *group = NULL;
int i;
struct timeval tv;
ev_uint64_t total_received;
double total_sq_persec, total_persec;
double variance;
double expected_total_persec = -1.0, expected_avg_persec = -1.0;
int ok = 1;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
sin.sin_port = 0; /* unspecified port */
if (0)
event_enable_debug_mode();
base = event_base_new();
listener = evconnlistener_new_bind(base, echo_listenercb, base,
LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1,
(struct sockaddr *)&sin, sizeof(sin));
slen = sizeof(ss);
if (getsockname(evconnlistener_get_fd(listener), (struct sockaddr *)&ss,
&slen) < 0) {
perror("getsockname");
return 1;
}
if (cfg_connlimit > 0) {
conn_bucket_cfg = ev_token_bucket_cfg_new(
cfg_connlimit, cfg_connlimit * 4,
cfg_connlimit, cfg_connlimit * 4,
&cfg_tick);
assert(conn_bucket_cfg);
}
if (cfg_grouplimit > 0) {
group_bucket_cfg = ev_token_bucket_cfg_new(
cfg_grouplimit, cfg_grouplimit * 4,
cfg_grouplimit, cfg_grouplimit * 4,
&cfg_tick);
group = ratelim_group = bufferevent_rate_limit_group_new(
base, group_bucket_cfg);
expected_total_persec = cfg_grouplimit;
expected_avg_persec = cfg_grouplimit / cfg_n_connections;
if (cfg_connlimit > 0 && expected_avg_persec > cfg_connlimit)
expected_avg_persec = cfg_connlimit;
if (cfg_min_share >= 0)
bufferevent_rate_limit_group_set_min_share(
ratelim_group, cfg_min_share);
}
if (expected_avg_persec < 0 && cfg_connlimit > 0)
expected_avg_persec = cfg_connlimit;
if (expected_avg_persec > 0)
expected_avg_persec /= seconds_per_tick;
if (expected_total_persec > 0)
expected_total_persec /= seconds_per_tick;
bevs = calloc(cfg_n_connections, sizeof(struct bufferevent *));
states = calloc(cfg_n_connections, sizeof(struct client_state));
for (i = 0; i < cfg_n_connections; ++i) {
bevs[i] = bufferevent_socket_new(base, -1,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE);
assert(bevs[i]);
bufferevent_setcb(bevs[i], discard_readcb, loud_writecb,
write_on_connectedcb, &states[i]);
bufferevent_enable(bevs[i], EV_READ|EV_WRITE);
bufferevent_socket_connect(bevs[i], (struct sockaddr *)&ss,
slen);
}
tv.tv_sec = cfg_duration - 1;
tv.tv_usec = 995000;
event_base_loopexit(base, &tv);
event_base_dispatch(base);
ratelim_group = NULL; /* So no more responders get added */
for (i = 0; i < cfg_n_connections; ++i) {
bufferevent_free(bevs[i]);
}
evconnlistener_free(listener);
/* Make sure no new echo_conns get added to the group. */
ratelim_group = NULL;
/* This should get _everybody_ freed */
while (n_echo_conns_open) {
printf("waiting for %d conns\n", n_echo_conns_open);
tv.tv_sec = 0;
tv.tv_usec = 300000;
event_base_loopexit(base, &tv);
event_base_dispatch(base);
}
if (group)
bufferevent_rate_limit_group_free(group);
total_received = 0;
total_persec = 0.0;
total_sq_persec = 0.0;
for (i=0; i < cfg_n_connections; ++i) {
double persec = states[i].received;
persec /= cfg_duration;
total_received += states[i].received;
total_persec += persec;
total_sq_persec += persec*persec;
printf("%d: %f per second\n", i+1, persec);
}
printf(" total: %f per second\n",
((double)total_received)/cfg_duration);
if (expected_total_persec > 0) {
double diff = expected_total_persec -
((double)total_received/cfg_duration);
printf(" [Off by %lf]\n", diff);
if (cfg_grouplimit_tolerance > 0 &&
fabs(diff) > cfg_grouplimit_tolerance) {
fprintf(stderr, "Group bandwidth out of bounds\n");
ok = 0;
}
}
printf(" average: %f per second\n",
(((double)total_received)/cfg_duration)/cfg_n_connections);
if (expected_avg_persec > 0) {
double diff = expected_avg_persec - (((double)total_received)/cfg_duration)/cfg_n_connections;
printf(" [Off by %lf]\n", diff);
if (cfg_connlimit_tolerance > 0 &&
fabs(diff) > cfg_connlimit_tolerance) {
fprintf(stderr, "Connection bandwidth out of bounds\n");
ok = 0;
}
}
variance = total_sq_persec/cfg_n_connections - total_persec*total_persec/(cfg_n_connections*cfg_n_connections);
printf(" stddev: %f per second\n", sqrt(variance));
if (cfg_stddev_tolerance > 0 &&
sqrt(variance) > cfg_stddev_tolerance) {
fprintf(stderr, "Connection variance out of bounds\n");
ok = 0;
}
event_base_free(base);
free(bevs);
free(states);
return ok ? 0 : 1;
}
static struct option {
const char *name; int *ptr; int min; int isbool;
} options[] = {
{ "-v", &cfg_verbose, 0, 1 },
{ "-h", &cfg_help, 0, 1 },
{ "-n", &cfg_n_connections, 1, 0 },
{ "-d", &cfg_duration, 1, 0 },
{ "-c", &cfg_connlimit, 0, 0 },
{ "-g", &cfg_grouplimit, 0, 0 },
{ "-t", &cfg_tick_msec, 10, 0 },
{ "--min-share", &cfg_min_share, 0, 0 },
{ "--check-connlimit", &cfg_connlimit_tolerance, 0, 0 },
{ "--check-grouplimit", &cfg_grouplimit_tolerance, 0, 0 },
{ "--check-stddev", &cfg_stddev_tolerance, 0, 0 },
{ NULL, NULL, -1, 0 },
};
static int
handle_option(int argc, char **argv, int *i, const struct option *opt)
{
long val;
char *endptr = NULL;
if (opt->isbool) {
*opt->ptr = 1;
return 0;
}
if (*i + 1 == argc) {
fprintf(stderr, "Too few arguments to '%s'\n",argv[*i]);
return -1;
}
val = strtol(argv[*i+1], &endptr, 10);
if (*argv[*i+1] == '\0' || !endptr || *endptr != '\0') {
fprintf(stderr, "Couldn't parse numeric value '%s'\n",
argv[*i+1]);
return -1;
}
if (val < opt->min || val > 0x7fffffff) {
fprintf(stderr, "Value '%s' is out-of-range'\n",
argv[*i+1]);
return -1;
}
*opt->ptr = (int)val;
++*i;
return 0;
}
static void
usage(void)
{
fprintf(stderr,
"test-ratelim [-v] [-n INT] [-d INT] [-c INT] [-g INT] [-t INT]\n\n"
"Pushes bytes through a number of possibly rate-limited connections, and\n"
"displays average throughput.\n\n"
" -n INT: Number of connections to open (default: 30)\n"
" -d INT: Duration of the test in seconds (default: 5 sec)\n");
fprintf(stderr,
" -c INT: Connection-rate limit applied to each connection in bytes per second\n"
" (default: None.)\n"
" -g INT: Group-rate limit applied to sum of all usage in bytes per second\n"
" (default: None.)\n"
" -t INT: Granularity of timing, in milliseconds (default: 1000 msec)\n");
}
int
main(int argc, char **argv)
{
int i,j;
double ratio;
#ifdef WIN32
WORD wVersionRequested = MAKEWORD(2,2);
WSADATA wsaData;
int err;
err = WSAStartup(wVersionRequested, &wsaData);
#endif
#ifndef WIN32
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
return 1;
#endif
for (i = 1; i < argc; ++i) {
for (j = 0; options[j].name; ++j) {
if (!strcmp(argv[i],options[j].name)) {
if (handle_option(argc,argv,&i,&options[j])<0)
return 1;
goto again;
}
}
fprintf(stderr, "Unknown option '%s'\n", argv[i]);
usage();
return 1;
again:
;
}
if (cfg_help) {
usage();
return 0;
}
cfg_tick.tv_sec = cfg_tick_msec / 1000;
cfg_tick.tv_usec = (cfg_tick_msec % 1000)*1000;
seconds_per_tick = ratio = cfg_tick_msec / 1000.0;
cfg_connlimit *= ratio;
cfg_grouplimit *= ratio;
{
struct timeval tv;
evutil_gettimeofday(&tv, NULL);
#ifdef WIN32
srand(tv.tv_usec);
#else
srandom(tv.tv_usec);
#endif
}
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
evthread_enable_lock_debuging();
#endif
return test_ratelimiting();
}

Просмотреть файл

@ -1,92 +0,0 @@
/*
* Compile with:
* cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
*/
#include "opal_config.h"
#include "event2/event-config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef WIN32
#include <unistd.h>
#include <sys/time.h>
#endif
#include <errno.h>
#include "opal/mca/event/event.h"
int called = 0;
#define NEVENT 10
struct event *ev[NEVENT];
static int
rand_int(int n)
{
#ifdef WIN32
return (int)(rand() % n);
#else
return (int)(random() % n);
#endif
}
static void
time_cb(evutil_socket_t fd, short event, void *arg)
{
struct timeval tv;
int i, j;
called++;
fprintf(stderr, "TIMER FIRED FOR %d TIME\n", called);
if (called < 10*NEVENT) {
for (i = 0; i < 10; i++) {
j = rand_int(NEVENT);
tv.tv_sec = 0;
tv.tv_usec = 0; /* rand_int(50000); */
if (tv.tv_usec % 2)
opal_evtimer_add(ev[j], &tv);
else
opal_evtimer_del(ev[j]);
}
}
}
int
main(int argc, char **argv)
{
struct timeval tv;
int i;
#ifdef WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
#endif
/* Initalize the event library */
opal_event_init();
for (i = 0; i < NEVENT; i++) {
ev[i] = malloc(sizeof(struct event));
/* Initalize one event */
opal_evtimer_set(ev[i], time_cb, ev[i]);
tv.tv_sec = 0;
tv.tv_usec = 0; /* rand_int(50000); */
opal_evtimer_add(ev[i], &tv);
}
opal_event_dispatch();
return (called < NEVENT);
}

Просмотреть файл

@ -1,96 +0,0 @@
/*
* Compile with:
* cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
*/
#include "event2/event-config.h"
#ifdef WIN32
#include <winsock2.h>
#else
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef _EVENT_HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <event2/event.h>
#include <event2/event_struct.h>
#include <event2/event_compat.h>
#include <event2/util.h>
#ifdef _EVENT___func__
#define __func__ _EVENT___func__
#endif
int pair[2];
int test_okay = 1;
int called = 0;
static void
write_cb(evutil_socket_t fd, short event, void *arg)
{
const char *test = "test string";
int len;
len = send(fd, test, strlen(test) + 1, 0);
printf("%s: write %d%s\n", __func__,
len, len ? "" : " - means EOF");
if (len > 0) {
if (!called)
event_add(arg, NULL);
evutil_closesocket(pair[0]);
} else if (called == 1)
test_okay = 0;
called++;
}
int
main(int argc, char **argv)
{
struct event ev;
#ifdef WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
#endif
#ifndef WIN32
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
return (1);
#endif
if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
return (1);
/* Initalize the event library */
event_init();
/* Initalize one event */
event_set(&ev, pair[1], EV_WRITE, write_cb, &ev);
event_add(&ev, NULL);
event_dispatch();
return (test_okay);
}

Просмотреть файл

@ -1,149 +0,0 @@
#!/bin/sh
FAILED=no
if test "x$TEST_OUTPUT_FILE" = "x"
then
TEST_OUTPUT_FILE=/dev/null
fi
# /bin/echo is a little more likely to support -n than sh's builtin echo.
if test -x /bin/echo
then
ECHO=/bin/echo
else
ECHO=echo
fi
if test "$TEST_OUTPUT_FILE" != "/dev/null"
then
touch "$TEST_OUTPUT_FILE" || exit 1
fi
TEST_DIR=.
T=`echo "$0" | sed -e 's/test.sh$//'`
if test -x "$T/test-init"
then
TEST_DIR="$T"
fi
setup () {
EVENT_NOKQUEUE=yes; export EVENT_NOKQUEUE
EVENT_NODEVPOLL=yes; export EVENT_NODEVPOLL
EVENT_NOPOLL=yes; export EVENT_NOPOLL
EVENT_NOSELECT=yes; export EVENT_NOSELECT
EVENT_NOEPOLL=yes; export EVENT_NOEPOLL
EVENT_NOEVPORT=yes; export EVENT_NOEVPORT
EVENT_NOWIN32=yes; export EVENT_NOWIN32
}
announce () {
echo $@
echo $@ >>"$TEST_OUTPUT_FILE"
}
announce_n () {
$ECHO -n $@
echo $@ >>"$TEST_OUTPUT_FILE"
}
run_tests () {
if $TEST_DIR/test-init 2>>"$TEST_OUTPUT_FILE" ;
then
true
else
announce Skipping test
return
fi
announce_n " test-eof: "
if $TEST_DIR/test-eof >>"$TEST_OUTPUT_FILE" ;
then
announce OKAY ;
else
announce FAILED ;
FAILED=yes
fi
announce_n " test-weof: "
if $TEST_DIR/test-weof >>"$TEST_OUTPUT_FILE" ;
then
announce OKAY ;
else
announce FAILED ;
FAILED=yes
fi
announce_n " test-time: "
if $TEST_DIR/test-time >>"$TEST_OUTPUT_FILE" ;
then
announce OKAY ;
else
announce FAILED ;
FAILED=yes
fi
announce_n " test-changelist: "
if $TEST_DIR/test-changelist >>"$TEST_OUTPUT_FILE" ;
then
announce OKAY ;
else
announce FAILED ;
FAILED=yes
fi
announce_n " regress: "
if test "$TEST_OUTPUT_FILE" = "/dev/null" ;
then
$TEST_DIR/regress --quiet
else
$TEST_DIR/regress >>"$TEST_OUTPUT_FILE"
fi
if test "$?" = "0" ;
then
announce OKAY ;
else
announce FAILED ;
FAILED=yes
fi
}
announce "Running tests:"
# Need to do this by hand?
setup
unset EVENT_NOKQUEUE
announce "KQUEUE"
run_tests
setup
unset EVENT_NODEVPOLL
announce "DEVPOLL"
run_tests
setup
unset EVENT_NOPOLL
announce "POLL"
run_tests
setup
unset EVENT_NOSELECT
announce "SELECT"
run_tests
setup
unset EVENT_NOEPOLL
announce "EPOLL"
run_tests
setup
unset EVENT_NOEVPORT
announce "EVPORT"
run_tests
setup
unset EVENT_NOWIN32
announce "WIN32"
run_tests
if test "$FAILED" = "yes"; then
exit 1
fi

Просмотреть файл

@ -1,365 +0,0 @@
/* tinytest.c -- Copyright 2009-2010 Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifdef WIN32
#include <winsock2.h>
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#endif
#include <event2/util.h>
#include "tinytest.h"
#include "tinytest_macros.h"
#define LONGEST_TEST_NAME 16384
static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
static int n_ok = 0; /**< Number of tests that have passed */
static int n_bad = 0; /**< Number of tests that have failed. */
static int n_skipped = 0; /**< Number of tests that have been skipped. */
static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
const char *verbosity_flag = "";
enum outcome { SKIP=2, OK=1, FAIL=0 };
static enum outcome cur_test_outcome = 0;
const char *cur_test_prefix = NULL; /**< prefix of the current test group */
/** Name of the current test, if we haven't logged is yet. Used for --quiet */
const char *cur_test_name = NULL;
#ifdef WIN32
/** Pointer to argv[0] for win32. */
static const char *commandname = NULL;
#endif
static enum outcome
_testcase_run_bare(const struct testcase_t *testcase)
{
void *env = NULL;
int outcome;
if (testcase->setup) {
env = testcase->setup->setup_fn(testcase);
if (!env)
return FAIL;
else if (env == (void*)TT_SKIP)
return SKIP;
}
cur_test_outcome = OK;
testcase->fn(env);
outcome = cur_test_outcome;
if (testcase->setup) {
if (testcase->setup->cleanup_fn(testcase, env) == 0)
outcome = FAIL;
}
return outcome;
}
#define MAGIC_EXITCODE 42
static enum outcome
_testcase_run_forked(const struct testgroup_t *group,
const struct testcase_t *testcase)
{
#ifdef WIN32
/* Fork? On Win32? How primitive! We'll do what the smart kids do:
we'll invoke our own exe (whose name we recall from the command
line) with a command line that tells it to run just the test we
want, and this time without forking.
(No, threads aren't an option. The whole point of forking is to
share no state between tests.)
*/
int ok;
char buffer[LONGEST_TEST_NAME+256];
STARTUPINFOA si;
PROCESS_INFORMATION info;
DWORD exitcode;
if (!in_tinytest_main) {
printf("\nERROR. On Windows, _testcase_run_forked must be"
" called from within tinytest_main.\n");
abort();
}
if (opt_verbosity>0)
printf("[forking] ");
evutil_snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s",
commandname, verbosity_flag, group->prefix, testcase->name);
memset(&si, 0, sizeof(si));
memset(&info, 0, sizeof(info));
si.cb = sizeof(si);
ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
0, NULL, NULL, &si, &info);
if (!ok) {
printf("CreateProcess failed!\n");
return 0;
}
WaitForSingleObject(info.hProcess, INFINITE);
GetExitCodeProcess(info.hProcess, &exitcode);
CloseHandle(info.hProcess);
CloseHandle(info.hThread);
if (exitcode == 0)
return OK;
else if (exitcode == MAGIC_EXITCODE)
return SKIP;
else
return FAIL;
#else
int outcome_pipe[2];
pid_t pid;
(void)group;
if (pipe(outcome_pipe))
perror("opening pipe");
if (opt_verbosity>0)
printf("[forking] ");
pid = fork();
if (!pid) {
/* child. */
int test_r, write_r;
char b[1];
close(outcome_pipe[0]);
test_r = _testcase_run_bare(testcase);
assert(0<=(int)test_r && (int)test_r<=2);
b[0] = "NYS"[test_r];
write_r = write(outcome_pipe[1], b, 1);
if (write_r != 1) {
perror("write outcome to pipe");
exit(1);
}
exit(0);
} else {
/* parent */
int status, r;
char b[1];
/* Close this now, so that if the other side closes it,
* our read fails. */
close(outcome_pipe[1]);
r = read(outcome_pipe[0], b, 1);
if (r == 0) {
printf("[Lost connection!] ");
return 0;
} else if (r != 1) {
perror("read outcome from pipe");
}
waitpid(pid, &status, 0);
close(outcome_pipe[0]);
return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
}
#endif
}
int
testcase_run_one(const struct testgroup_t *group,
const struct testcase_t *testcase)
{
enum outcome outcome;
if (testcase->flags & TT_SKIP) {
if (opt_verbosity>0)
printf("%s%s: SKIPPED\n",
group->prefix, testcase->name);
++n_skipped;
return SKIP;
}
if (opt_verbosity>0 && !opt_forked) {
printf("%s%s: ", group->prefix, testcase->name);
} else {
if (opt_verbosity==0) printf(".");
cur_test_prefix = group->prefix;
cur_test_name = testcase->name;
}
if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
outcome = _testcase_run_forked(group, testcase);
} else {
outcome = _testcase_run_bare(testcase);
}
if (outcome == OK) {
++n_ok;
if (opt_verbosity>0 && !opt_forked)
puts(opt_verbosity==1?"OK":"");
} else if (outcome == SKIP) {
++n_skipped;
if (opt_verbosity>0 && !opt_forked)
puts("SKIPPED");
} else {
++n_bad;
if (!opt_forked)
printf("\n [%s FAILED]\n", testcase->name);
}
if (opt_forked) {
exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
} else {
return (int)outcome;
}
}
int
_tinytest_set_flag(struct testgroup_t *groups, const char *arg, unsigned long flag)
{
int i, j;
int length = LONGEST_TEST_NAME;
char fullname[LONGEST_TEST_NAME];
int found=0;
if (strstr(arg, ".."))
length = strstr(arg,"..")-arg;
for (i=0; groups[i].prefix; ++i) {
for (j=0; groups[i].cases[j].name; ++j) {
evutil_snprintf(fullname, sizeof(fullname), "%s%s",
groups[i].prefix, groups[i].cases[j].name);
if (!flag) /* Hack! */
printf(" %s\n", fullname);
if (!strncmp(fullname, arg, length)) {
groups[i].cases[j].flags |= flag;
++found;
}
}
}
return found;
}
static void
usage(struct testgroup_t *groups, int list_groups)
{
puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
puts(" Specify tests by name, or using a prefix ending with '..'");
puts(" Use --list-tests for a list of tests.");
if (list_groups) {
puts("Known tests are:");
_tinytest_set_flag(groups, "..", 0);
}
exit(0);
}
int
tinytest_main(int c, const char **v, struct testgroup_t *groups)
{
int i, j, n=0;
#ifdef WIN32
commandname = v[0];
#endif
for (i=1; i<c; ++i) {
if (v[i][0] == '-') {
if (!strcmp(v[i], "--RUNNING-FORKED")) {
opt_forked = 1;
} else if (!strcmp(v[i], "--no-fork")) {
opt_nofork = 1;
} else if (!strcmp(v[i], "--quiet")) {
opt_verbosity = -1;
verbosity_flag = "--quiet";
} else if (!strcmp(v[i], "--verbose")) {
opt_verbosity = 2;
verbosity_flag = "--verbose";
} else if (!strcmp(v[i], "--terse")) {
opt_verbosity = 0;
verbosity_flag = "--terse";
} else if (!strcmp(v[i], "--help")) {
usage(groups, 0);
} else if (!strcmp(v[i], "--list-tests")) {
usage(groups, 1);
} else {
printf("Unknown option %s. Try --help\n",v[i]);
return -1;
}
} else {
++n;
if (!_tinytest_set_flag(groups, v[i], _TT_ENABLED)) {
printf("No such test as %s!\n", v[i]);
return -1;
}
}
}
if (!n)
_tinytest_set_flag(groups, "..", _TT_ENABLED);
setvbuf(stdout, NULL, _IONBF, 0);
++in_tinytest_main;
for (i=0; groups[i].prefix; ++i)
for (j=0; groups[i].cases[j].name; ++j)
if (groups[i].cases[j].flags & _TT_ENABLED)
testcase_run_one(&groups[i],
&groups[i].cases[j]);
--in_tinytest_main;
if (opt_verbosity==0)
puts("");
if (n_bad)
printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
n_bad+n_ok,n_skipped);
else if (opt_verbosity >= 1)
printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped);
return (n_bad == 0) ? 0 : 1;
}
int
_tinytest_get_verbosity(void)
{
return opt_verbosity;
}
void
_tinytest_set_test_failed(void)
{
if (opt_verbosity <= 0 && cur_test_name) {
if (opt_verbosity==0) puts("");
printf("%s%s: ", cur_test_prefix, cur_test_name);
cur_test_name = NULL;
}
cur_test_outcome = 0;
}
void
_tinytest_set_test_skipped(void)
{
if (cur_test_outcome==OK)
cur_test_outcome = SKIP;
}

Просмотреть файл

@ -1,87 +0,0 @@
/* tinytest.h -- Copyright 2009-2010 Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TINYTEST_H
#define _TINYTEST_H
/** Flag for a test that needs to run in a subprocess. */
#define TT_FORK (1<<0)
/** Runtime flag for a test we've decided to skip. */
#define TT_SKIP (1<<1)
/** Internal runtime flag for a test we've decided to run. */
#define _TT_ENABLED (1<<2)
/** If you add your own flags, make them start at this point. */
#define TT_FIRST_USER_FLAG (1<<3)
typedef void (*testcase_fn)(void *);
struct testcase_t;
/** Functions to initialize/teardown a structure for a testcase. */
struct testcase_setup_t {
/** Return a new structure for use by a given testcase. */
void *(*setup_fn)(const struct testcase_t *);
/** Clean/free a structure from setup_fn. Return 1 if ok, 0 on err. */
int (*cleanup_fn)(const struct testcase_t *, void *);
};
/** A single test-case that you can run. */
struct testcase_t {
const char *name; /**< An identifier for this case. */
testcase_fn fn; /**< The function to run to implement this case. */
unsigned long flags; /**< Bitfield of TT_* flags. */
const struct testcase_setup_t *setup; /**< Optional setup/cleanup fns*/
void *setup_data; /**< Extra data usable by setup function */
};
#define END_OF_TESTCASES { NULL, NULL, 0, NULL, NULL }
/** A group of tests that are selectable together. */
struct testgroup_t {
const char *prefix; /**< Prefix to prepend to testnames. */
struct testcase_t *cases; /** Array, ending with END_OF_TESTCASES */
};
#define END_OF_GROUPS { NULL, NULL}
/** Implementation: called from a test to indicate failure, before logging. */
void _tinytest_set_test_failed(void);
/** Implementation: called from a test to indicate that we're skipping. */
void _tinytest_set_test_skipped(void);
/** Implementation: return 0 for quiet, 1 for normal, 2 for loud. */
int _tinytest_get_verbosity(void);
/** Implementation: Set a flag on tests matching a name; returns number
* of tests that matched. */
int _tinytest_set_flag(struct testgroup_t *, const char *, unsigned long);
/** Set all tests in 'groups' matching the name 'named' to be skipped. */
#define tinytest_skip(groups, named) \
_tinytest_set_flag(groups, named, TT_SKIP)
/** Run a single testcase in a single group. */
int testcase_run_one(const struct testgroup_t *,const struct testcase_t *);
/** Run a set of testcases from an END_OF_GROUPS-terminated array of groups,
as selected from the command line. */
int tinytest_main(int argc, const char **argv, struct testgroup_t *groups);
#endif

Просмотреть файл

@ -1,145 +0,0 @@
/* tinytest_macros.h -- Copyright 2009-2010 Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TINYTEST_MACROS_H
#define _TINYTEST_MACROS_H
/* Helpers for defining statement-like macros */
#define TT_STMT_BEGIN do {
#define TT_STMT_END } while (0)
/* Redefine this if your test functions want to abort with something besides
* "goto end;" */
#ifndef TT_EXIT_TEST_FUNCTION
#define TT_EXIT_TEST_FUNCTION TT_STMT_BEGIN goto end; TT_STMT_END
#endif
/* Redefine this if you want to note success/failure in some different way. */
#ifndef TT_DECLARE
#define TT_DECLARE(prefix, args) \
TT_STMT_BEGIN \
printf("\n %s %s:%d: ",prefix,__FILE__,__LINE__); \
printf args ; \
TT_STMT_END
#endif
/* Announce a failure. Args are parenthesized printf args. */
#define TT_GRIPE(args) TT_DECLARE("FAIL", args)
/* Announce a non-failure if we're verbose. */
#define TT_BLATHER(args) \
TT_STMT_BEGIN \
if (_tinytest_get_verbosity()>1) TT_DECLARE(" OK", args); \
TT_STMT_END
#define TT_DIE(args) \
TT_STMT_BEGIN \
_tinytest_set_test_failed(); \
TT_GRIPE(args); \
TT_EXIT_TEST_FUNCTION; \
TT_STMT_END
#define TT_FAIL(args) \
TT_STMT_BEGIN \
_tinytest_set_test_failed(); \
TT_GRIPE(args); \
TT_STMT_END
/* Fail and abort the current test for the reason in msg */
#define tt_abort_printf(msg) TT_DIE(msg)
#define tt_abort_perror(op) TT_DIE(("%s: %s [%d]",(op),strerror(errno), errno))
#define tt_abort_msg(msg) TT_DIE(("%s", msg))
#define tt_abort() TT_DIE(("%s", "(Failed.)"))
/* Fail but do not abort the current test for the reason in msg. */
#define tt_fail_printf(msg) TT_FAIL(msg)
#define tt_fail_perror(op) TT_FAIL(("%s: %s [%d]",(op),strerror(errno), errno))
#define tt_fail_msg(msg) TT_FAIL(("%s", msg))
#define tt_fail() TT_FAIL(("%s", "(Failed.)"))
/* End the current test, and indicate we are skipping it. */
#define tt_skip() \
TT_STMT_BEGIN \
_tinytest_set_test_skipped(); \
TT_EXIT_TEST_FUNCTION; \
TT_STMT_END
#define _tt_want(b, msg, fail) \
TT_STMT_BEGIN \
if (!(b)) { \
_tinytest_set_test_failed(); \
TT_GRIPE((msg)); \
fail; \
} else { \
TT_BLATHER((msg)); \
} \
TT_STMT_END
/* Assert b, but do not stop the test if b fails. Log msg on failure. */
#define tt_want_msg(b, msg) \
_tt_want(b, msg, );
/* Assert b and stop the test if b fails. Log msg on failure. */
#define tt_assert_msg(b, msg) \
_tt_want(b, msg, TT_EXIT_TEST_FUNCTION);
/* Assert b, but do not stop the test if b fails. */
#define tt_want(b) tt_want_msg( (b), "want("#b")")
/* Assert b, and stop the test if b fails. */
#define tt_assert(b) tt_assert_msg((b), "assert("#b")")
#define tt_assert_test_type(a,b,str_test,type,test,fmt) \
TT_STMT_BEGIN \
type _val1 = (type)(a); \
type _val2 = (type)(b); \
if (!(test)) { \
TT_DIE(("assert(%s): "fmt" vs "fmt, \
str_test, _val1, _val2)); \
} else { \
TT_BLATHER(("assert(%s): "fmt" vs "fmt, \
str_test, _val1, _val2)); \
} \
TT_STMT_END
/* Helper: assert that a op b, when cast to type. Format the values with
* printf format fmt on failure. */
#define tt_assert_op_type(a,op,b,type,fmt) \
tt_assert_test_type(a,b,#a" "#op" "#b,type,(_val1 op _val2),fmt)
#define tt_int_op(a,op,b) \
tt_assert_test_type(a,b,#a" "#op" "#b,long,(_val1 op _val2),"%ld")
#define tt_uint_op(a,op,b) \
tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \
(_val1 op _val2),"%lu")
#define tt_ptr_op(a,op,b) \
tt_assert_test_type(a,b,#a" "#op" "#b,void*, \
(_val1 op _val2),"%p")
#define tt_str_op(a,op,b) \
tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \
(strcmp(_val1,_val2) op 0),"<%s>")
#endif