Remove the sample and test code from the libevent distro - don't need to include them in ompi
This commit was SVN r23931.
Этот коммит содержится в:
родитель
bab990d812
Коммит
a04da165bc
@ -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, ¬e_one) == -1 ||
|
||||
EVTAG_ARRAY_GET(run, notes, 1, ¬e_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
|
Загрузка…
x
Ссылка в новой задаче
Block a user