From 89f3cf8bbb9dc1fa0fe72f6af6638ac086c7e011 Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Wed, 29 Nov 2017 09:33:41 +0300 Subject: libevent, telegram, whatsapp moved to deprecated coz doesn't work --- libs/libevent/docs/test/Makefile.nmake | 79 - libs/libevent/docs/test/bench.c | 207 -- libs/libevent/docs/test/bench_cascade.c | 188 - libs/libevent/docs/test/bench_http.c | 195 -- libs/libevent/docs/test/bench_httpclient.c | 239 -- libs/libevent/docs/test/check-dumpevents.py | 54 - libs/libevent/docs/test/include.am | 146 - libs/libevent/docs/test/print-winsock-errors.c | 84 - libs/libevent/docs/test/regress.c | 3401 ------------------- libs/libevent/docs/test/regress.h | 144 - libs/libevent/docs/test/regress.rpc | 25 - libs/libevent/docs/test/regress_buffer.c | 2281 ------------- libs/libevent/docs/test/regress_bufferevent.c | 1284 ------- libs/libevent/docs/test/regress_dns.c | 2151 ------------ libs/libevent/docs/test/regress_et.c | 208 -- libs/libevent/docs/test/regress_finalize.c | 347 -- libs/libevent/docs/test/regress_http.c | 4335 ------------------------ libs/libevent/docs/test/regress_iocp.c | 352 -- libs/libevent/docs/test/regress_listener.c | 214 -- libs/libevent/docs/test/regress_main.c | 468 --- libs/libevent/docs/test/regress_minheap.c | 99 - libs/libevent/docs/test/regress_rpc.c | 905 ----- libs/libevent/docs/test/regress_ssl.c | 781 ----- libs/libevent/docs/test/regress_testutils.c | 229 -- libs/libevent/docs/test/regress_testutils.h | 67 - libs/libevent/docs/test/regress_thread.c | 590 ---- libs/libevent/docs/test/regress_thread.h | 48 - libs/libevent/docs/test/regress_util.c | 1413 -------- libs/libevent/docs/test/regress_zlib.c | 348 -- libs/libevent/docs/test/rpcgen_wrapper.sh | 52 - libs/libevent/docs/test/test-changelist.c | 224 -- libs/libevent/docs/test/test-closed.c | 117 - libs/libevent/docs/test/test-dumpevents.c | 179 - libs/libevent/docs/test/test-eof.c | 124 - libs/libevent/docs/test/test-fdleak.c | 249 -- libs/libevent/docs/test/test-init.c | 65 - libs/libevent/docs/test/test-ratelim.c | 601 ---- libs/libevent/docs/test/test-ratelim.sh | 88 - libs/libevent/docs/test/test-time.c | 116 - libs/libevent/docs/test/test-weof.c | 117 - libs/libevent/docs/test/test.sh | 160 - libs/libevent/docs/test/tinytest.c | 493 --- libs/libevent/docs/test/tinytest.h | 100 - libs/libevent/docs/test/tinytest_demo.c | 262 -- libs/libevent/docs/test/tinytest_local.h | 12 - libs/libevent/docs/test/tinytest_macros.h | 199 -- 46 files changed, 24040 deletions(-) delete mode 100644 libs/libevent/docs/test/Makefile.nmake delete mode 100644 libs/libevent/docs/test/bench.c delete mode 100644 libs/libevent/docs/test/bench_cascade.c delete mode 100644 libs/libevent/docs/test/bench_http.c delete mode 100644 libs/libevent/docs/test/bench_httpclient.c delete mode 100644 libs/libevent/docs/test/check-dumpevents.py delete mode 100644 libs/libevent/docs/test/include.am delete mode 100644 libs/libevent/docs/test/print-winsock-errors.c delete mode 100644 libs/libevent/docs/test/regress.c delete mode 100644 libs/libevent/docs/test/regress.h delete mode 100644 libs/libevent/docs/test/regress.rpc delete mode 100644 libs/libevent/docs/test/regress_buffer.c delete mode 100644 libs/libevent/docs/test/regress_bufferevent.c delete mode 100644 libs/libevent/docs/test/regress_dns.c delete mode 100644 libs/libevent/docs/test/regress_et.c delete mode 100644 libs/libevent/docs/test/regress_finalize.c delete mode 100644 libs/libevent/docs/test/regress_http.c delete mode 100644 libs/libevent/docs/test/regress_iocp.c delete mode 100644 libs/libevent/docs/test/regress_listener.c delete mode 100644 libs/libevent/docs/test/regress_main.c delete mode 100644 libs/libevent/docs/test/regress_minheap.c delete mode 100644 libs/libevent/docs/test/regress_rpc.c delete mode 100644 libs/libevent/docs/test/regress_ssl.c delete mode 100644 libs/libevent/docs/test/regress_testutils.c delete mode 100644 libs/libevent/docs/test/regress_testutils.h delete mode 100644 libs/libevent/docs/test/regress_thread.c delete mode 100644 libs/libevent/docs/test/regress_thread.h delete mode 100644 libs/libevent/docs/test/regress_util.c delete mode 100644 libs/libevent/docs/test/regress_zlib.c delete mode 100644 libs/libevent/docs/test/rpcgen_wrapper.sh delete mode 100644 libs/libevent/docs/test/test-changelist.c delete mode 100644 libs/libevent/docs/test/test-closed.c delete mode 100644 libs/libevent/docs/test/test-dumpevents.c delete mode 100644 libs/libevent/docs/test/test-eof.c delete mode 100644 libs/libevent/docs/test/test-fdleak.c delete mode 100644 libs/libevent/docs/test/test-init.c delete mode 100644 libs/libevent/docs/test/test-ratelim.c delete mode 100644 libs/libevent/docs/test/test-ratelim.sh delete mode 100644 libs/libevent/docs/test/test-time.c delete mode 100644 libs/libevent/docs/test/test-weof.c delete mode 100644 libs/libevent/docs/test/test.sh delete mode 100644 libs/libevent/docs/test/tinytest.c delete mode 100644 libs/libevent/docs/test/tinytest.h delete mode 100644 libs/libevent/docs/test/tinytest_demo.c delete mode 100644 libs/libevent/docs/test/tinytest_local.h delete mode 100644 libs/libevent/docs/test/tinytest_macros.h (limited to 'libs/libevent/docs/test') diff --git a/libs/libevent/docs/test/Makefile.nmake b/libs/libevent/docs/test/Makefile.nmake deleted file mode 100644 index 30c3eb792b..0000000000 --- a/libs/libevent/docs/test/Makefile.nmake +++ /dev/null @@ -1,79 +0,0 @@ -# WATCH OUT! This makefile is a work in progress. -*- makefile -*- - -!IFDEF OPENSSL_DIR -SSL_CFLAGS=/I$(OPENSSL_DIR)\include /DEVENT__HAVE_OPENSSL -SSL_OBJS=regress_ssl.obj -SSL_LIBS=..\libevent_openssl.lib $(OPENSSL_DIR)\lib\libeay32.lib $(OPENSSL_DIR)\lib\ssleay32.lib gdi32.lib User32.lib -!ELSE -SSL_CFLAGS= -SSL_OBJS= -SSL_LIBS= -!ENDIF - -CFLAGS=/I.. /I../WIN32-Code /I../WIN32-Code/nmake /I../include /I../compat /DHAVE_CONFIG_H /DTINYTEST_LOCAL $(SSL_CFLAGS) - -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 regress_finalize.obj $(SSL_OBJS) - -OTHER_OBJS=test-init.obj test-eof.obj test-closed.obj test-weof.obj test-time.obj \ - bench.obj bench_cascade.obj bench_http.obj bench_httpclient.obj \ - test-changelist.obj \ - print-winsock-errors.obj - -PROGRAMS=regress.exe \ - test-init.exe test-eof.exe test-closed.exe test-weof.exe test-time.exe \ - test-changelist.exe \ - print-winsock-errors.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) $(SSL_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-closed.exe: test-closed.obj - $(CC) $(CFLAGS) $(LIBS) test-closed.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 - -print-winsock-errors.exe: print-winsock-errors.obj - $(CC) $(CFLAGS) $(LIBS) print-winsock-errors.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 - -regress.gen.c regress.gen.h: regress.rpc ../event_rpcgen.py - echo // > regress.gen.c - echo #define NO_PYTHON_EXISTS > regress.gen.h - -python ..\event_rpcgen.py regress.rpc - -clean: - -del $(REGRESS_OBJS) - -del $(OTHER_OBJS) - -del $(PROGRAMS) diff --git a/libs/libevent/docs/test/bench.c b/libs/libevent/docs/test/bench.c deleted file mode 100644 index 214479c1ff..0000000000 --- a/libs/libevent/docs/test/bench.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright 2003-2007 Niels Provos - * Copyright 2007-2012 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 - * - * Added chain event propagation to improve the sensitivity of - * the measure respect to the event loop efficency. - * - * - */ - -#include "event2/event-config.h" - -#include -#include -#ifdef EVENT__HAVE_SYS_TIME_H -#include -#endif -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#else -#include -#include -#include -#endif -#include -#include -#include -#include -#ifdef EVENT__HAVE_UNISTD_H -#include -#endif -#include - -#ifdef _WIN32 -#include -#endif - -#include -#include - -static int count, writes, fired, failures; -static evutil_socket_t *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) -{ - ev_intptr_t idx = (ev_intptr_t) arg, widx = idx + 1; - unsigned char ch; - ev_ssize_t n; - - n = recv(fd, (char*)&ch, sizeof(ch), 0); - if (n >= 0) - count += n; - else - failures++; - if (writes) { - if (widx >= num_pipes) - widx -= num_pipes; - n = send(pipes[2 * widx + 1], "e", 1, 0); - if (n != 1) - failures++; - writes--; - fired++; - } -} - -static struct timeval * -run_once(void) -{ - evutil_socket_t *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 *)(ev_intptr_t) 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++) - (void) send(pipes[i * space + 1], "e", 1, 0); - - count = 0; - writes = num_writes; - { int xcount = 0; - evutil_gettimeofday(&ts, NULL); - do { - event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK); - xcount++; - } while (count != fired); - evutil_gettimeofday(&te, NULL); - - if (xcount != count) fprintf(stderr, "Xcount: %d, Rcount: %d\n", xcount, count); - } - - evutil_timersub(&te, &ts, &te); - - return (&te); -} - -int -main(int argc, char **argv) -{ -#ifdef HAVE_SETRLIMIT - struct rlimit rl; -#endif - int i, c; - struct timeval *tv; - evutil_socket_t *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); - } - } - -#ifdef HAVE_SETRLIMIT - 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(evutil_socket_t)); - 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); -} diff --git a/libs/libevent/docs/test/bench_cascade.c b/libs/libevent/docs/test/bench_cascade.c deleted file mode 100644 index 2d85cc1f10..0000000000 --- a/libs/libevent/docs/test/bench_cascade.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright 2007-2012 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 -#include -#ifdef EVENT__HAVE_SYS_TIME_H -#include -#endif -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#else -#include -#include -#endif -#include -#include -#include -#include -#include -#ifdef EVENT__HAVE_UNISTD_H -#include -#endif -#include -#include -#include -#include - -/* - * 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 evutil_socket_t *pipes; -static struct event *events; - -static void -read_cb(evutil_socket_t fd, short which, void *arg) -{ - char ch; - evutil_socket_t sock = (evutil_socket_t)(ev_intptr_t)arg; - - (void) recv(fd, &ch, sizeof(ch), 0); - if (sock >= 0) { - if (send(sock, "e", 1, 0) < 0) - perror("send"); - } - fired++; -} - -static struct timeval * -run_once(int num_pipes) -{ - int i; - evutil_socket_t *cp; - static struct timeval ts, te, tv_timeout; - - events = (struct event *)calloc(num_pipes, sizeof(struct event)); - pipes = (evutil_socket_t *)calloc(num_pipes * 2, sizeof(evutil_socket_t)); - - 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 */ - evutil_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) { - evutil_socket_t fd = i < num_pipes - 1 ? cp[3] : -1; - event_set(&events[i], cp[0], EV_READ, read_cb, - (void *)(ev_intptr_t)fd); - event_add(&events[i], &tv_timeout); - } - - fired = 0; - - /* kick everything off with a single write */ - if (send(pipes[1], "e", 1, 0) < 0) - perror("send"); - - event_dispatch(); - - evutil_gettimeofday(&te, NULL); - evutil_timersub(&te, &ts, &te); - - for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { - event_del(&events[i]); - evutil_closesocket(cp[0]); - evutil_closesocket(cp[1]); - } - - free(pipes); - free(events); - - return (&te); -} - -int -main(int argc, char **argv) -{ -#ifdef HAVE_SETRLIMIT - struct rlimit rl; -#endif - int i, c; - struct timeval *tv; - - int num_pipes = 100; -#ifdef _WIN32 - WSADATA WSAData; - WSAStartup(0x101, &WSAData); -#endif - - 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); - } - } - -#ifdef HAVE_SETRLIMIT - 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); - } - -#ifdef _WIN32 - WSACleanup(); -#endif - - exit(0); -} diff --git a/libs/libevent/docs/test/bench_http.c b/libs/libevent/docs/test/bench_http.c deleted file mode 100644 index 6d0d971799..0000000000 --- a/libs/libevent/docs/test/bench_http.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2008-2012 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 -#include -#ifdef _WIN32 -#include -#else -#include -#include -#include -#include -#endif -#include -#include -#include -#include -#include -#include - -#include "event2/event.h" -#include "event2/buffer.h" -#include "event2/util.h" -#include "event2/http.h" -#include "event2/thread.h" - -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); -} - -#if LIBEVENT_VERSION_NUMBER >= 0x02000200 -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_config *cfg = event_config_new(); - struct event_base *base; - struct evhttp *http; - int i; - int c; - int use_iocp = 0; - unsigned short port = 8080; - char *endptr = NULL; - -#ifdef _WIN32 - WSADATA WSAData; - WSAStartup(0x101, &WSAData); -#else - if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) - return (1); -#endif - - 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': - if (i+1 >= argc || !argv[i+1]) { - fprintf(stderr, "Missing port\n"); - exit(1); - } - port = (int)strtol(argv[i+1], &endptr, 10); - if (*endptr != '\0') { - fprintf(stderr, "Bad port\n"); - exit(1); - } - break; - case 'l': - if (i+1 >= argc || !argv[i+1]) { - fprintf(stderr, "Missing content length\n"); - exit(1); - } - content_len = (size_t)strtol(argv[i+1], &endptr, 10); - if (*endptr != '\0' || content_len == 0) { - fprintf(stderr, "Bad content length\n"); - exit(1); - } - break; -#ifdef _WIN32 - case 'i': - use_iocp = 1; - evthread_use_windows_threads(); - event_config_set_flag(cfg,EVENT_BASE_FLAG_STARTUP_IOCP); - break; -#endif - default: - fprintf(stderr, "Illegal argument \"%c\"\n", c); - exit(1); - } - } - - base = event_base_new_with_config(cfg); - if (!base) { - fprintf(stderr, "creating event_base failed. Exiting.\n"); - return 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 < (int)content_len; ++i) - content[i] = (i & 255); - } - - evhttp_set_cb(http, "/ind", http_basic_cb, NULL); - fprintf(stderr, "/ind - basic content (memory copy)\n"); - - evhttp_set_cb(http, "/ref", http_ref_cb, NULL); - fprintf(stderr, "/ref - basic content (reference)\n"); - - 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); - -#ifdef _WIN32 - if (use_iocp) { - struct timeval tv={99999999,0}; - event_base_loopexit(base, &tv); - } -#endif - event_base_dispatch(base); - -#ifdef _WIN32 - WSACleanup(); -#endif - - /* NOTREACHED */ - return (0); -} diff --git a/libs/libevent/docs/test/bench_httpclient.c b/libs/libevent/docs/test/bench_httpclient.c deleted file mode 100644 index bcddc95f43..0000000000 --- a/libs/libevent/docs/test/bench_httpclient.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2009-2012 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. - * - */ - -/* for EVUTIL_ERR_CONNECT_RETRIABLE macro */ -#include "util-internal.h" - -#include -#ifdef _WIN32 -#include -#else -#include -#include -# ifdef _XOPEN_SOURCE_EXTENDED -# include -# endif -#endif -#include -#include -#include - -#include "event2/event.h" -#include "event2/bufferevent.h" -#include "event2/buffer.h" -#include "event2/util.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; - evutil_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) -{ -#ifdef HAVE_SO_LINGER - struct linger l; -#endif - int one = 1; - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&one, sizeof(one))<0) - perror("setsockopt(SO_REUSEADDR)"); -#ifdef HAVE_SO_LINGER - l.l_onoff = 1; - l.l_linger = 0; - if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&l, sizeof(l))<0) - perror("setsockopt(SO_LINGER)"); -#endif -} - -static int -launch_request(void) -{ - evutil_socket_t sock; - struct sockaddr_in sin; - struct bufferevent *b; - - struct request_info *ri; - - memset(&sin, 0, sizeof(sin)); - - ++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) { - evutil_closesocket(sock); - return -1; - } - frob_socket(sock); - if (connect(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0) { - int e = evutil_socket_geterror(sock); - if (! EVUTIL_ERR_CONNECT_RETRIABLE(e)) { - evutil_closesocket(sock); - return -1; - } - } - - ri = malloc(sizeof(*ri)); - ri->n_read = 0; - evutil_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"; - -#ifdef _WIN32 - WSADATA WSAData; - WSAStartup(0x101, &WSAData); -#endif - - setvbuf(stdout, NULL, _IONBF, 0); - - base = event_base_new(); - - for (i=0; i < PARALLELISM; ++i) { - if (launch_request() < 0) - perror("launch"); - } - - evutil_gettimeofday(&start, NULL); - - event_base_dispatch(base); - - evutil_gettimeofday(&end, NULL); - evutil_timersub(&end, &start, &total); - usec = total_time.tv_sec * (long long)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); - -#ifdef _WIN32 -#define I64_FMT "%I64d" -#define I64_TYP __int64 -#else -#define I64_FMT "%lld" -#define I64_TYP long long int -#endif - - printf("\n%d requests in %d.%06d sec. (%.2f throughput)\n" - "Each took about %.02f msec latency\n" - I64_FMT "bytes read. %d errors.\n", - total_n_handled, - (int)total.tv_sec, (int)total.tv_usec, - throughput, - (double)(usec/1000) / total_n_handled, - (I64_TYP)total_n_bytes, n_errors); - -#ifdef _WIN32 - WSACleanup(); -#endif - - return 0; -} diff --git a/libs/libevent/docs/test/check-dumpevents.py b/libs/libevent/docs/test/check-dumpevents.py deleted file mode 100644 index 16fe9bc92f..0000000000 --- a/libs/libevent/docs/test/check-dumpevents.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/python2 -# -# Post-process the output of test-dumpevents and check it for correctness. -# - -import math -import re -import sys - -text = sys.stdin.readlines() - -try: - expect_inserted_pos = text.index("Inserted:\n") - expect_active_pos = text.index("Active:\n") - got_inserted_pos = text.index("Inserted events:\n") - got_active_pos = text.index("Active events:\n") -except ValueError: - print >>sys.stderr, "Missing expected dividing line in dumpevents output" - sys.exit(1) - -if not (expect_inserted_pos < expect_active_pos < - got_inserted_pos < got_active_pos): - print >>sys.stderr, "Sections out of order in dumpevents output" - sys.exit(1) - -now,T= text[1].split() -T = float(T) - -want_inserted = set(text[expect_inserted_pos+1:expect_active_pos]) -want_active = set(text[expect_active_pos+1:got_inserted_pos-1]) -got_inserted = set(text[got_inserted_pos+1:got_active_pos]) -got_active = set(text[got_active_pos+1:]) - -pat = re.compile(r'Timeout=([0-9\.]+)') -def replace_time(m): - t = float(m.group(1)) - if .9 < abs(t-T) < 1.1: - return "Timeout=T+1" - elif 2.4 < abs(t-T) < 2.6: - return "Timeout=T+2.5" - else: - return m.group(0) - -cleaned_inserted = set( pat.sub(replace_time, s) for s in got_inserted - if "Internal" not in s) - -if cleaned_inserted != want_inserted: - print >>sys.stderr, "Inserted event lists were not as expected!" - sys.exit(1) - -if set(got_active) != set(want_active): - print >>sys.stderr, "Active event lists were not as expected!" - sys.exit(1) - diff --git a/libs/libevent/docs/test/include.am b/libs/libevent/docs/test/include.am deleted file mode 100644 index 4cd49ef630..0000000000 --- a/libs/libevent/docs/test/include.am +++ /dev/null @@ -1,146 +0,0 @@ -# test/Makefile.am for libevent -# Copyright 2000-2007 Niels Provos -# Copyright 2007-2012 Niels Provos and Nick Mathewson -# -# See LICENSE for copying information. - -regress_CPPFLAGS = -DTINYTEST_LOCAL - -EXTRA_DIST+= \ - test/check-dumpevents.py \ - test/regress.gen.c \ - test/regress.gen.h \ - test/regress.rpc \ - test/rpcgen_wrapper.sh \ - test/test.sh - -TESTPROGRAMS = \ - test/bench \ - test/bench_cascade \ - test/bench_http \ - test/bench_httpclient \ - test/test-changelist \ - test/test-dumpevents \ - test/test-eof \ - test/test-closed \ - test/test-fdleak \ - test/test-init \ - test/test-ratelim \ - test/test-time \ - test/test-weof \ - test/regress - -if BUILD_REGRESS -noinst_PROGRAMS += $(TESTPROGRAMS) -EXTRA_PROGRAMS+= test/regress -endif - -noinst_HEADERS+= \ - test/regress.h \ - test/regress_thread.h \ - test/tinytest.h \ - test/tinytest_local.h \ - test/tinytest_macros.h - -# We need to copy this file, since automake doesn't want us to use top_srcdir -# in TESTS. -TESTS = test/test-script.sh - -test/test-script.sh: test/test.sh - cp $(top_srcdir)/test/test.sh $@ - -DISTCLEANFILES += test/test-script.sh -DISTCLEANFILES += test/regress.gen.c test/regress.gen.h - -if BUILD_REGRESS -BUILT_SOURCES += test/regress.gen.c test/regress.gen.h -endif - -test_test_init_SOURCES = test/test-init.c -test_test_init_LDADD = libevent_core.la -test_test_dumpevents_SOURCES = test/test-dumpevents.c -test_test_dumpevents_LDADD = libevent_core.la -test_test_eof_SOURCES = test/test-eof.c -test_test_eof_LDADD = libevent_core.la -test_test_closed_SOURCES = test/test-closed.c -test_test_closed_LDADD = libevent_core.la -test_test_changelist_SOURCES = test/test-changelist.c -test_test_changelist_LDADD = libevent_core.la -test_test_weof_SOURCES = test/test-weof.c -test_test_weof_LDADD = libevent_core.la -test_test_time_SOURCES = test/test-time.c -test_test_time_LDADD = libevent_core.la -test_test_ratelim_SOURCES = test/test-ratelim.c -test_test_ratelim_LDADD = libevent_core.la -lm -test_test_fdleak_SOURCES = test/test-fdleak.c -test_test_fdleak_LDADD = libevent_core.la - -test_regress_SOURCES = \ - test/regress.c \ - test/regress.gen.c \ - test/regress.gen.h \ - test/regress_buffer.c \ - test/regress_bufferevent.c \ - test/regress_dns.c \ - test/regress_et.c \ - test/regress_finalize.c \ - test/regress_http.c \ - test/regress_listener.c \ - test/regress_main.c \ - test/regress_minheap.c \ - test/regress_rpc.c \ - test/regress_testutils.c \ - test/regress_testutils.h \ - test/regress_util.c \ - test/tinytest.c \ - $(regress_thread_SOURCES) \ - $(regress_zlib_SOURCES) - -if PTHREADS -regress_thread_SOURCES = test/regress_thread.c -PTHREAD_LIBS += libevent_pthreads.la -endif -if BUILD_WIN32 -regress_thread_SOURCES = test/regress_thread.c -endif -if ZLIB_REGRESS -regress_zlib_SOURCES = test/regress_zlib.c -endif -if BUILD_WIN32 -test_regress_SOURCES += test/regress_iocp.c -endif - -test_regress_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la $(PTHREAD_LIBS) $(ZLIB_LIBS) -test_regress_CPPFLAGS = $(AM_CPPFLAGS) $(PTHREAD_CFLAGS) $(ZLIB_CFLAGS) -Itest -test_regress_LDFLAGS = $(PTHREAD_CFLAGS) - -if OPENSSL -test_regress_SOURCES += test/regress_ssl.c -test_regress_CPPFLAGS += $(OPENSSL_INCS) -test_regress_LDADD += libevent_openssl.la $(OPENSSL_LIBS) ${OPENSSL_LIBADD} -endif - -test_bench_SOURCES = test/bench.c -test_bench_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la -test_bench_cascade_SOURCES = test/bench_cascade.c -test_bench_cascade_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la -test_bench_http_SOURCES = test/bench_http.c -test_bench_http_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la -test_bench_httpclient_SOURCES = test/bench_httpclient.c -test_bench_httpclient_LDADD = $(LIBEVENT_GC_SECTIONS) libevent_core.la - -test/regress.gen.c test/regress.gen.h: test/rpcgen-attempted - -test/rpcgen-attempted: test/regress.rpc event_rpcgen.py test/rpcgen_wrapper.sh - $(AM_V_GEN)date -u > $@ - $(AM_V_at)if $(srcdir)/test/rpcgen_wrapper.sh $(srcdir)/test; then \ - true; \ - else \ - echo "No Python installed; stubbing out RPC test." >&2; \ - echo " "> test/regress.gen.c; \ - echo "#define NO_PYTHON_EXISTS" > test/regress.gen.h; \ - fi - -CLEANFILES += test/rpcgen-attempted - -$(TESTPROGRAMS) : libevent.la diff --git a/libs/libevent/docs/test/print-winsock-errors.c b/libs/libevent/docs/test/print-winsock-errors.c deleted file mode 100644 index ab6e610e84..0000000000 --- a/libs/libevent/docs/test/print-winsock-errors.c +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include - -#include -#include - -#include "event2/event.h" -#include "event2/util.h" -#include "event2/thread.h" - -#define E(x) printf (#x " -> \"%s\"\n", evutil_socket_error_to_string (x)); - -int main (int argc, char **argv) -{ - int i, j; - const char *s1, *s2; - - evthread_use_windows_threads (); - - s1 = evutil_socket_error_to_string (WSAEINTR); - - for (i = 0; i < 3; i++) { - printf ("\niteration %d:\n\n", i); - E(WSAEINTR); - E(WSAEACCES); - E(WSAEFAULT); - E(WSAEINVAL); - E(WSAEMFILE); - E(WSAEWOULDBLOCK); - E(WSAEINPROGRESS); - E(WSAEALREADY); - E(WSAENOTSOCK); - E(WSAEDESTADDRREQ); - E(WSAEMSGSIZE); - E(WSAEPROTOTYPE); - E(WSAENOPROTOOPT); - E(WSAEPROTONOSUPPORT); - E(WSAESOCKTNOSUPPORT); - E(WSAEOPNOTSUPP); - E(WSAEPFNOSUPPORT); - E(WSAEAFNOSUPPORT); - E(WSAEADDRINUSE); - E(WSAEADDRNOTAVAIL); - E(WSAENETDOWN); - E(WSAENETUNREACH); - E(WSAENETRESET); - E(WSAECONNABORTED); - E(WSAECONNRESET); - E(WSAENOBUFS); - E(WSAEISCONN); - E(WSAENOTCONN); - E(WSAESHUTDOWN); - E(WSAETIMEDOUT); - E(WSAECONNREFUSED); - E(WSAEHOSTDOWN); - E(WSAEHOSTUNREACH); - E(WSAEPROCLIM); - E(WSASYSNOTREADY); - E(WSAVERNOTSUPPORTED); - E(WSANOTINITIALISED); - E(WSAEDISCON); - E(WSATYPE_NOT_FOUND); - E(WSAHOST_NOT_FOUND); - E(WSATRY_AGAIN); - E(WSANO_RECOVERY); - E(WSANO_DATA); - E(0xdeadbeef); /* test the case where no message is available */ - - /* fill up the hash table a bit to make sure it grows properly */ - for (j = 0; j < 50; j++) { - int err; - evutil_secure_rng_get_bytes(&err, sizeof(err)); - evutil_socket_error_to_string(err); - } - } - - s2 = evutil_socket_error_to_string (WSAEINTR); - if (s1 != s2) - printf ("caching failed!\n"); - - libevent_global_shutdown (); - - return EXIT_SUCCESS; -} diff --git a/libs/libevent/docs/test/regress.c b/libs/libevent/docs/test/regress.c deleted file mode 100644 index b12c66dfa0..0000000000 --- a/libs/libevent/docs/test/regress.c +++ /dev/null @@ -1,3401 +0,0 @@ -/* - * Copyright (c) 2003-2007 Niels Provos - * Copyright (c) 2007-2012 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 "util-internal.h" - -#ifdef _WIN32 -#include -#include -#endif - -#ifdef EVENT__HAVE_PTHREADS -#include -#endif - -#include "event2/event-config.h" - -#include -#include -#ifdef EVENT__HAVE_SYS_TIME_H -#include -#endif -#include -#ifndef _WIN32 -#include -#include -#include -#include -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -#include "event2/event.h" -#include "event2/event_struct.h" -#include "event2/event_compat.h" -#include "event2/tag.h" -#include "event2/buffer.h" -#include "event2/buffer_compat.h" -#include "event2/util.h" -#include "event-internal.h" -#include "evthread-internal.h" -#include "log-internal.h" -#include "time-internal.h" - -#include "regress.h" - -#ifndef _WIN32 -#include "regress.gen.h" -#endif - -evutil_socket_t pair[2]; -int test_ok; -int called; -struct event_base *global_base; - -static char wbuf[4096]; -static char rbuf[4096]; -static int woff; -static int roff; -static int usepersist; -static struct timeval tset; -static struct timeval tcalled; - - -#define TEST1 "this is a test" - -#ifndef SHUT_WR -#define SHUT_WR 1 -#endif - -#ifdef _WIN32 -#define write(fd,buf,len) send((fd),(buf),(int)(len),0) -#define read(fd,buf,len) recv((fd),(buf),(int)(len),0) -#endif - -struct basic_cb_args -{ - struct event_base *eb; - struct event *ev; - unsigned int callcount; -}; - -static void -simple_read_cb(evutil_socket_t fd, short event, void *arg) -{ - char buf[256]; - int len; - - len = read(fd, buf, sizeof(buf)); - - if (len) { - if (!called) { - if (event_add(arg, NULL) == -1) - exit(1); - } - } else if (called == 1) - test_ok = 1; - - called++; -} - -static void -basic_read_cb(evutil_socket_t fd, short event, void *data) -{ - char buf[256]; - int len; - struct basic_cb_args *arg = data; - - len = read(fd, buf, sizeof(buf)); - - if (len < 0) { - tt_fail_perror("read (callback)"); - } else { - switch (arg->callcount++) { - case 0: /* first call: expect to read data; cycle */ - if (len > 0) - return; - - tt_fail_msg("EOF before data read"); - break; - - case 1: /* second call: expect EOF; stop */ - if (len > 0) - tt_fail_msg("not all data read on first cycle"); - break; - - default: /* third call: should not happen */ - tt_fail_msg("too many cycles"); - } - } - - event_del(arg->ev); - event_base_loopexit(arg->eb, NULL); -} - -static void -dummy_read_cb(evutil_socket_t fd, short event, void *arg) -{ -} - -static void -simple_write_cb(evutil_socket_t fd, short event, void *arg) -{ - int len; - - len = write(fd, TEST1, strlen(TEST1) + 1); - if (len == -1) - test_ok = 0; - else - test_ok = 1; -} - -static void -multiple_write_cb(evutil_socket_t fd, short event, void *arg) -{ - struct event *ev = arg; - int len; - - len = 128; - if (woff + len >= (int)sizeof(wbuf)) - len = sizeof(wbuf) - woff; - - len = write(fd, wbuf + woff, len); - if (len == -1) { - fprintf(stderr, "%s: write\n", __func__); - if (usepersist) - event_del(ev); - return; - } - - woff += len; - - if (woff >= (int)sizeof(wbuf)) { - shutdown(fd, SHUT_WR); - if (usepersist) - event_del(ev); - return; - } - - if (!usepersist) { - if (event_add(ev, NULL) == -1) - exit(1); - } -} - -static void -multiple_read_cb(evutil_socket_t fd, short event, void *arg) -{ - struct event *ev = arg; - int len; - - len = read(fd, rbuf + roff, sizeof(rbuf) - roff); - if (len == -1) - fprintf(stderr, "%s: read\n", __func__); - if (len <= 0) { - if (usepersist) - event_del(ev); - return; - } - - roff += len; - if (!usepersist) { - if (event_add(ev, NULL) == -1) - exit(1); - } -} - -static void -timeout_cb(evutil_socket_t fd, short event, void *arg) -{ - evutil_gettimeofday(&tcalled, NULL); -} - -struct both { - struct event ev; - int nread; -}; - -static void -combined_read_cb(evutil_socket_t fd, short event, void *arg) -{ - struct both *both = arg; - char buf[128]; - int len; - - len = read(fd, buf, sizeof(buf)); - if (len == -1) - fprintf(stderr, "%s: read\n", __func__); - if (len <= 0) - return; - - both->nread += len; - if (event_add(&both->ev, NULL) == -1) - exit(1); -} - -static void -combined_write_cb(evutil_socket_t fd, short event, void *arg) -{ - struct both *both = arg; - char buf[128]; - int len; - - len = sizeof(buf); - if (len > both->nread) - len = both->nread; - - memset(buf, 'q', len); - - len = write(fd, buf, len); - if (len == -1) - fprintf(stderr, "%s: write\n", __func__); - if (len <= 0) { - shutdown(fd, SHUT_WR); - return; - } - - both->nread -= len; - if (event_add(&both->ev, NULL) == -1) - exit(1); -} - -/* These macros used to replicate the work of the legacy test wrapper code */ -#define setup_test(x) do { \ - if (!in_legacy_test_wrapper) { \ - TT_FAIL(("Legacy test %s not wrapped properly", x)); \ - return; \ - } \ - } while (0) -#define cleanup_test() setup_test("cleanup") - -static void -test_simpleread(void) -{ - struct event ev; - - /* Very simple read test */ - setup_test("Simple read: "); - - if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { - tt_fail_perror("write"); - } - - shutdown(pair[0], SHUT_WR); - - event_set(&ev, pair[1], EV_READ, simple_read_cb, &ev); - if (event_add(&ev, NULL) == -1) - exit(1); - event_dispatch(); - - cleanup_test(); -} - -static void -test_simplewrite(void) -{ - struct event ev; - - /* Very simple write test */ - setup_test("Simple write: "); - - event_set(&ev, pair[0], EV_WRITE, simple_write_cb, &ev); - if (event_add(&ev, NULL) == -1) - exit(1); - event_dispatch(); - - cleanup_test(); -} - -static void -simpleread_multiple_cb(evutil_socket_t fd, short event, void *arg) -{ - if (++called == 2) - test_ok = 1; -} - -static void -test_simpleread_multiple(void) -{ - struct event one, two; - - /* Very simple read test */ - setup_test("Simple read to multiple evens: "); - - if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { - tt_fail_perror("write"); - } - - shutdown(pair[0], SHUT_WR); - - event_set(&one, pair[1], EV_READ, simpleread_multiple_cb, NULL); - if (event_add(&one, NULL) == -1) - exit(1); - event_set(&two, pair[1], EV_READ, simpleread_multiple_cb, NULL); - if (event_add(&two, NULL) == -1) - exit(1); - event_dispatch(); - - cleanup_test(); -} - -static int have_closed = 0; -static int premature_event = 0; -static void -simpleclose_close_fd_cb(evutil_socket_t s, short what, void *ptr) -{ - evutil_socket_t **fds = ptr; - TT_BLATHER(("Closing")); - evutil_closesocket(*fds[0]); - evutil_closesocket(*fds[1]); - *fds[0] = -1; - *fds[1] = -1; - have_closed = 1; -} - -static void -record_event_cb(evutil_socket_t s, short what, void *ptr) -{ - short *whatp = ptr; - if (!have_closed) - premature_event = 1; - *whatp = what; - TT_BLATHER(("Recorded %d on socket %d", (int)what, (int)s)); -} - -static void -test_simpleclose(void *ptr) -{ - /* Test that a close of FD is detected as a read and as a write. */ - struct event_base *base = event_base_new(); - evutil_socket_t pair1[2]={-1,-1}, pair2[2] = {-1, -1}; - evutil_socket_t *to_close[2]; - struct event *rev=NULL, *wev=NULL, *closeev=NULL; - struct timeval tv; - short got_read_on_close = 0, got_write_on_close = 0; - char buf[1024]; - memset(buf, 99, sizeof(buf)); -#ifdef _WIN32 -#define LOCAL_SOCKETPAIR_AF AF_INET -#else -#define LOCAL_SOCKETPAIR_AF AF_UNIX -#endif - if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair1)<0) - TT_DIE(("socketpair: %s", strerror(errno))); - if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair2)<0) - TT_DIE(("socketpair: %s", strerror(errno))); - if (evutil_make_socket_nonblocking(pair1[1]) < 0) - TT_DIE(("make_socket_nonblocking")); - if (evutil_make_socket_nonblocking(pair2[1]) < 0) - TT_DIE(("make_socket_nonblocking")); - - /** Stuff pair2[1] full of data, until write fails */ - while (1) { - int r = write(pair2[1], buf, sizeof(buf)); - if (r<0) { - int err = evutil_socket_geterror(pair2[1]); - if (! EVUTIL_ERR_RW_RETRIABLE(err)) - TT_DIE(("write failed strangely: %s", - evutil_socket_error_to_string(err))); - break; - } - } - to_close[0] = &pair1[0]; - to_close[1] = &pair2[0]; - - closeev = event_new(base, -1, EV_TIMEOUT, simpleclose_close_fd_cb, - to_close); - rev = event_new(base, pair1[1], EV_READ, record_event_cb, - &got_read_on_close); - TT_BLATHER(("Waiting for read on %d", (int)pair1[1])); - wev = event_new(base, pair2[1], EV_WRITE, record_event_cb, - &got_write_on_close); - TT_BLATHER(("Waiting for write on %d", (int)pair2[1])); - tv.tv_sec = 0; - tv.tv_usec = 100*1000; /* Close pair1[0] after a little while, and make - * sure we get a read event. */ - event_add(closeev, &tv); - event_add(rev, NULL); - event_add(wev, NULL); - /* Don't let the test go on too long. */ - tv.tv_sec = 0; - tv.tv_usec = 200*1000; - event_base_loopexit(base, &tv); - event_base_loop(base, 0); - - tt_int_op(got_read_on_close, ==, EV_READ); - tt_int_op(got_write_on_close, ==, EV_WRITE); - tt_int_op(premature_event, ==, 0); - -end: - if (pair1[0] >= 0) - evutil_closesocket(pair1[0]); - if (pair1[1] >= 0) - evutil_closesocket(pair1[1]); - if (pair2[0] >= 0) - evutil_closesocket(pair2[0]); - if (pair2[1] >= 0) - evutil_closesocket(pair2[1]); - if (rev) - event_free(rev); - if (wev) - event_free(wev); - if (closeev) - event_free(closeev); - if (base) - event_base_free(base); -} - - -static void -test_multiple(void) -{ - struct event ev, ev2; - int i; - - /* Multiple read and write test */ - setup_test("Multiple read/write: "); - memset(rbuf, 0, sizeof(rbuf)); - for (i = 0; i < (int)sizeof(wbuf); i++) - wbuf[i] = i; - - roff = woff = 0; - usepersist = 0; - - event_set(&ev, pair[0], EV_WRITE, multiple_write_cb, &ev); - if (event_add(&ev, NULL) == -1) - exit(1); - event_set(&ev2, pair[1], EV_READ, multiple_read_cb, &ev2); - if (event_add(&ev2, NULL) == -1) - exit(1); - event_dispatch(); - - if (roff == woff) - test_ok = memcmp(rbuf, wbuf, sizeof(wbuf)) == 0; - - cleanup_test(); -} - -static void -test_persistent(void) -{ - struct event ev, ev2; - int i; - - /* Multiple read and write test with persist */ - setup_test("Persist read/write: "); - memset(rbuf, 0, sizeof(rbuf)); - for (i = 0; i < (int)sizeof(wbuf); i++) - wbuf[i] = i; - - roff = woff = 0; - usepersist = 1; - - event_set(&ev, pair[0], EV_WRITE|EV_PERSIST, multiple_write_cb, &ev); - if (event_add(&ev, NULL) == -1) - exit(1); - event_set(&ev2, pair[1], EV_READ|EV_PERSIST, multiple_read_cb, &ev2); - if (event_add(&ev2, NULL) == -1) - exit(1); - event_dispatch(); - - if (roff == woff) - test_ok = memcmp(rbuf, wbuf, sizeof(wbuf)) == 0; - - cleanup_test(); -} - -static void -test_combined(void) -{ - struct both r1, r2, w1, w2; - - setup_test("Combined read/write: "); - memset(&r1, 0, sizeof(r1)); - memset(&r2, 0, sizeof(r2)); - memset(&w1, 0, sizeof(w1)); - memset(&w2, 0, sizeof(w2)); - - w1.nread = 4096; - w2.nread = 8192; - - event_set(&r1.ev, pair[0], EV_READ, combined_read_cb, &r1); - event_set(&w1.ev, pair[0], EV_WRITE, combined_write_cb, &w1); - event_set(&r2.ev, pair[1], EV_READ, combined_read_cb, &r2); - event_set(&w2.ev, pair[1], EV_WRITE, combined_write_cb, &w2); - tt_assert(event_add(&r1.ev, NULL) != -1); - tt_assert(!event_add(&w1.ev, NULL)); - tt_assert(!event_add(&r2.ev, NULL)); - tt_assert(!event_add(&w2.ev, NULL)); - event_dispatch(); - - if (r1.nread == 8192 && r2.nread == 4096) - test_ok = 1; - -end: - cleanup_test(); -} - -static void -test_simpletimeout(void) -{ - struct timeval tv; - struct event ev; - - setup_test("Simple timeout: "); - - tv.tv_usec = 200*1000; - tv.tv_sec = 0; - evutil_timerclear(&tcalled); - evtimer_set(&ev, timeout_cb, NULL); - evtimer_add(&ev, &tv); - - evutil_gettimeofday(&tset, NULL); - event_dispatch(); - test_timeval_diff_eq(&tset, &tcalled, 200); - - test_ok = 1; -end: - cleanup_test(); -} - -static void -periodic_timeout_cb(evutil_socket_t fd, short event, void *arg) -{ - int *count = arg; - - (*count)++; - if (*count == 6) { - /* call loopexit only once - on slow machines(?), it is - * apparently possible for this to get called twice. */ - test_ok = 1; - event_base_loopexit(global_base, NULL); - } -} - -static void -test_persistent_timeout(void) -{ - struct timeval tv; - struct event ev; - int count = 0; - - evutil_timerclear(&tv); - tv.tv_usec = 10000; - - event_assign(&ev, global_base, -1, EV_TIMEOUT|EV_PERSIST, - periodic_timeout_cb, &count); - event_add(&ev, &tv); - - event_dispatch(); - - event_del(&ev); -} - -static void -test_persistent_timeout_jump(void *ptr) -{ - struct basic_test_data *data = ptr; - struct event ev; - int count = 0; - struct timeval msec100 = { 0, 100 * 1000 }; - struct timeval msec50 = { 0, 50 * 1000 }; - struct timeval msec300 = { 0, 300 * 1000 }; - - event_assign(&ev, data->base, -1, EV_PERSIST, periodic_timeout_cb, &count); - event_add(&ev, &msec100); - /* Wait for a bit */ - evutil_usleep_(&msec300); - event_base_loopexit(data->base, &msec50); - event_base_dispatch(data->base); - tt_int_op(count, ==, 1); - -end: - event_del(&ev); -} - -struct persist_active_timeout_called { - int n; - short events[16]; - struct timeval tvs[16]; -}; - -static void -activate_cb(evutil_socket_t fd, short event, void *arg) -{ - struct event *ev = arg; - event_active(ev, EV_READ, 1); -} - -static void -persist_active_timeout_cb(evutil_socket_t fd, short event, void *arg) -{ - struct persist_active_timeout_called *c = arg; - if (c->n < 15) { - c->events[c->n] = event; - evutil_gettimeofday(&c->tvs[c->n], NULL); - ++c->n; - } -} - -static void -test_persistent_active_timeout(void *ptr) -{ - struct timeval tv, tv2, tv_exit, start; - struct event ev; - struct persist_active_timeout_called res; - - struct basic_test_data *data = ptr; - struct event_base *base = data->base; - - memset(&res, 0, sizeof(res)); - - tv.tv_sec = 0; - tv.tv_usec = 200 * 1000; - event_assign(&ev, base, -1, EV_TIMEOUT|EV_PERSIST, - persist_active_timeout_cb, &res); - event_add(&ev, &tv); - - tv2.tv_sec = 0; - tv2.tv_usec = 100 * 1000; - event_base_once(base, -1, EV_TIMEOUT, activate_cb, &ev, &tv2); - - tv_exit.tv_sec = 0; - tv_exit.tv_usec = 600 * 1000; - event_base_loopexit(base, &tv_exit); - - event_base_assert_ok_(base); - evutil_gettimeofday(&start, NULL); - - event_base_dispatch(base); - event_base_assert_ok_(base); - - tt_int_op(res.n, ==, 3); - tt_int_op(res.events[0], ==, EV_READ); - tt_int_op(res.events[1], ==, EV_TIMEOUT); - tt_int_op(res.events[2], ==, EV_TIMEOUT); - test_timeval_diff_eq(&start, &res.tvs[0], 100); - test_timeval_diff_eq(&start, &res.tvs[1], 300); - test_timeval_diff_eq(&start, &res.tvs[2], 500); -end: - event_del(&ev); -} - -struct common_timeout_info { - struct event ev; - struct timeval called_at; - int which; - int count; -}; - -static void -common_timeout_cb(evutil_socket_t fd, short event, void *arg) -{ - struct common_timeout_info *ti = arg; - ++ti->count; - evutil_gettimeofday(&ti->called_at, NULL); - if (ti->count >= 4) - event_del(&ti->ev); -} - -static void -test_common_timeout(void *ptr) -{ - struct basic_test_data *data = ptr; - - struct event_base *base = data->base; - int i; - struct common_timeout_info info[100]; - - struct timeval start; - struct timeval tmp_100_ms = { 0, 100*1000 }; - struct timeval tmp_200_ms = { 0, 200*1000 }; - struct timeval tmp_5_sec = { 5, 0 }; - struct timeval tmp_5M_usec = { 0, 5*1000*1000 }; - - const struct timeval *ms_100, *ms_200, *sec_5; - - ms_100 = event_base_init_common_timeout(base, &tmp_100_ms); - ms_200 = event_base_init_common_timeout(base, &tmp_200_ms); - sec_5 = event_base_init_common_timeout(base, &tmp_5_sec); - tt_assert(ms_100); - tt_assert(ms_200); - tt_assert(sec_5); - tt_ptr_op(event_base_init_common_timeout(base, &tmp_200_ms), - ==, ms_200); - tt_ptr_op(event_base_init_common_timeout(base, ms_200), ==, ms_200); - tt_ptr_op(event_base_init_common_timeout(base, &tmp_5M_usec), ==, sec_5); - tt_int_op(ms_100->tv_sec, ==, 0); - tt_int_op(ms_200->tv_sec, ==, 0); - tt_int_op(sec_5->tv_sec, ==, 5); - tt_int_op(ms_100->tv_usec, ==, 100000|0x50000000); - tt_int_op(ms_200->tv_usec, ==, 200000|0x50100000); - tt_int_op(sec_5->tv_usec, ==, 0|0x50200000); - - memset(info, 0, sizeof(info)); - - for (i=0; i<100; ++i) { - info[i].which = i; - event_assign(&info[i].ev, base, -1, EV_TIMEOUT|EV_PERSIST, - common_timeout_cb, &info[i]); - if (i % 2) { - if ((i%20)==1) { - /* Glass-box test: Make sure we survive the - * transition to non-common timeouts. It's - * a little tricky. */ - event_add(&info[i].ev, ms_200); - event_add(&info[i].ev, &tmp_100_ms); - } else if ((i%20)==3) { - /* Check heap-to-common too. */ - event_add(&info[i].ev, &tmp_200_ms); - event_add(&info[i].ev, ms_100); - } else if ((i%20)==5) { - /* Also check common-to-common. */ - event_add(&info[i].ev, ms_200); - event_add(&info[i].ev, ms_100); - } else { - event_add(&info[i].ev, ms_100); - } - } else { - event_add(&info[i].ev, ms_200); - } - } - - event_base_assert_ok_(base); - evutil_gettimeofday(&start, NULL); - event_base_dispatch(base); - - event_base_assert_ok_(base); - - for (i=0; i<10; ++i) { - tt_int_op(info[i].count, ==, 4); - if (i % 2) { - test_timeval_diff_eq(&start, &info[i].called_at, 400); - } else { - test_timeval_diff_eq(&start, &info[i].called_at, 800); - } - } - - /* Make sure we can free the base with some events in. */ - for (i=0; i<100; ++i) { - if (i % 2) { - event_add(&info[i].ev, ms_100); - } else { - event_add(&info[i].ev, ms_200); - } - } - -end: - event_base_free(data->base); /* need to do this here before info is - * out-of-scope */ - data->base = NULL; -} - -#ifndef _WIN32 - -#define current_base event_global_current_base_ -extern struct event_base *current_base; - -static void -fork_signal_cb(evutil_socket_t fd, short events, void *arg) -{ - event_del(arg); -} - - -static void -test_fork(void) -{ - int status; - struct event ev, sig_ev, usr_ev, existing_ev; - pid_t pid; - - setup_test("After fork: "); - - tt_assert(current_base); - evthread_make_base_notifiable(current_base); - - if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { - tt_fail_perror("write"); - } - - event_set(&ev, pair[1], EV_READ, simple_read_cb, &ev); - if (event_add(&ev, NULL) == -1) - exit(1); - - evsignal_set(&sig_ev, SIGCHLD, fork_signal_cb, &sig_ev); - evsignal_add(&sig_ev, NULL); - - evsignal_set(&existing_ev, SIGUSR2, fork_signal_cb, &existing_ev); - evsignal_add(&existing_ev, NULL); - - event_base_assert_ok_(current_base); - TT_BLATHER(("Before fork")); - if ((pid = regress_fork()) == 0) { - /* in the child */ - TT_BLATHER(("In child, before reinit")); - event_base_assert_ok_(current_base); - if (event_reinit(current_base) == -1) { - fprintf(stdout, "FAILED (reinit)\n"); - exit(1); - } - TT_BLATHER(("After reinit")); - event_base_assert_ok_(current_base); - TT_BLATHER(("After assert-ok")); - - evsignal_del(&sig_ev); - - evsignal_set(&usr_ev, SIGUSR1, fork_signal_cb, &usr_ev); - evsignal_add(&usr_ev, NULL); - raise(SIGUSR1); - raise(SIGUSR2); - - called = 0; - - event_dispatch(); - - event_base_free(current_base); - - /* we do not send an EOF; simple_read_cb requires an EOF - * to set test_ok. we just verify that the callback was - * called. */ - exit(test_ok != 0 || called != 2 ? -2 : 76); - } - - /* wait for the child to read the data */ - { - const struct timeval tv = { 0, 100000 }; - evutil_usleep_(&tv); - } - - if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { - tt_fail_perror("write"); - } - - TT_BLATHER(("Before waitpid")); - if (waitpid(pid, &status, 0) == -1) { - fprintf(stdout, "FAILED (fork)\n"); - exit(1); - } - TT_BLATHER(("After waitpid")); - - if (WEXITSTATUS(status) != 76) { - fprintf(stdout, "FAILED (exit): %d\n", WEXITSTATUS(status)); - exit(1); - } - - /* test that the current event loop still works */ - if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { - fprintf(stderr, "%s: write\n", __func__); - } - - shutdown(pair[0], SHUT_WR); - - evsignal_set(&usr_ev, SIGUSR1, fork_signal_cb, &usr_ev); - evsignal_add(&usr_ev, NULL); - raise(SIGUSR1); - raise(SIGUSR2); - - event_dispatch(); - - evsignal_del(&sig_ev); - - end: - cleanup_test(); -} - -#ifdef EVENT__HAVE_PTHREADS -static void* del_wait_thread(void *arg) -{ - struct timeval tv_start, tv_end; - - evutil_gettimeofday(&tv_start, NULL); - event_dispatch(); - evutil_gettimeofday(&tv_end, NULL); - - test_timeval_diff_eq(&tv_start, &tv_end, 300); - - end: - return NULL; -} - -static void -del_wait_cb(evutil_socket_t fd, short event, void *arg) -{ - struct timeval delay = { 0, 300*1000 }; - TT_BLATHER(("Sleeping")); - evutil_usleep_(&delay); - test_ok = 1; -} - -static void -test_del_wait(void) -{ - struct event ev; - pthread_t thread; - - setup_test("event_del will wait: "); - - event_set(&ev, pair[1], EV_READ, del_wait_cb, &ev); - event_add(&ev, NULL); - - pthread_create(&thread, NULL, del_wait_thread, NULL); - - if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { - tt_fail_perror("write"); - } - - { - struct timeval delay = { 0, 30*1000 }; - evutil_usleep_(&delay); - } - - { - struct timeval tv_start, tv_end; - evutil_gettimeofday(&tv_start, NULL); - event_del(&ev); - evutil_gettimeofday(&tv_end, NULL); - test_timeval_diff_eq(&tv_start, &tv_end, 270); - } - - pthread_join(thread, NULL); - - end: - ; -} -#endif - -static void -signal_cb_sa(int sig) -{ - test_ok = 2; -} - -static void -signal_cb(evutil_socket_t fd, short event, void *arg) -{ - struct event *ev = arg; - - evsignal_del(ev); - test_ok = 1; -} - -static void -test_simplesignal_impl(int find_reorder) -{ - struct event ev; - struct itimerval itv; - - evsignal_set(&ev, SIGALRM, signal_cb, &ev); - evsignal_add(&ev, NULL); - /* find bugs in which operations are re-ordered */ - if (find_reorder) { - evsignal_del(&ev); - evsignal_add(&ev, NULL); - } - - memset(&itv, 0, sizeof(itv)); - itv.it_value.tv_sec = 0; - itv.it_value.tv_usec = 100000; - if (setitimer(ITIMER_REAL, &itv, NULL) == -1) - goto skip_simplesignal; - - event_dispatch(); - skip_simplesignal: - if (evsignal_del(&ev) == -1) - test_ok = 0; - - cleanup_test(); -} - -static void -test_simplestsignal(void) -{ - setup_test("Simplest one signal: "); - test_simplesignal_impl(0); -} - -static void -test_simplesignal(void) -{ - setup_test("Simple signal: "); - test_simplesignal_impl(1); -} - -static void -test_multiplesignal(void) -{ - struct event ev_one, ev_two; - struct itimerval itv; - - setup_test("Multiple signal: "); - - evsignal_set(&ev_one, SIGALRM, signal_cb, &ev_one); - evsignal_add(&ev_one, NULL); - - evsignal_set(&ev_two, SIGALRM, signal_cb, &ev_two); - evsignal_add(&ev_two, NULL); - - memset(&itv, 0, sizeof(itv)); - itv.it_value.tv_sec = 0; - itv.it_value.tv_usec = 100000; - if (setitimer(ITIMER_REAL, &itv, NULL) == -1) - goto skip_simplesignal; - - event_dispatch(); - - skip_simplesignal: - if (evsignal_del(&ev_one) == -1) - test_ok = 0; - if (evsignal_del(&ev_two) == -1) - test_ok = 0; - - cleanup_test(); -} - -static void -test_immediatesignal(void) -{ - struct event ev; - - test_ok = 0; - evsignal_set(&ev, SIGUSR1, signal_cb, &ev); - evsignal_add(&ev, NULL); - raise(SIGUSR1); - event_loop(EVLOOP_NONBLOCK); - evsignal_del(&ev); - cleanup_test(); -} - -static void -test_signal_dealloc(void) -{ - /* make sure that evsignal_event is event_del'ed and pipe closed */ - struct event ev; - struct event_base *base = event_init(); - evsignal_set(&ev, SIGUSR1, signal_cb, &ev); - evsignal_add(&ev, NULL); - evsignal_del(&ev); - event_base_free(base); - /* If we got here without asserting, we're fine. */ - test_ok = 1; - cleanup_test(); -} - -static void -test_signal_pipeloss(void) -{ - /* make sure that the base1 pipe is closed correctly. */ - struct event_base *base1, *base2; - int pipe1; - test_ok = 0; - base1 = event_init(); - pipe1 = base1->sig.ev_signal_pair[0]; - base2 = event_init(); - event_base_free(base2); - event_base_free(base1); - if (close(pipe1) != -1 || errno!=EBADF) { - /* fd must be closed, so second close gives -1, EBADF */ - printf("signal pipe not closed. "); - test_ok = 0; - } else { - test_ok = 1; - } - cleanup_test(); -} - -/* - * make two bases to catch signals, use both of them. this only works - * for event mechanisms that use our signal pipe trick. kqueue handles - * signals internally, and all interested kqueues get all the signals. - */ -static void -test_signal_switchbase(void) -{ - struct event ev1, ev2; - struct event_base *base1, *base2; - int is_kqueue; - test_ok = 0; - base1 = event_init(); - base2 = event_init(); - is_kqueue = !strcmp(event_get_method(),"kqueue"); - evsignal_set(&ev1, SIGUSR1, signal_cb, &ev1); - evsignal_set(&ev2, SIGUSR1, signal_cb, &ev2); - if (event_base_set(base1, &ev1) || - event_base_set(base2, &ev2) || - event_add(&ev1, NULL) || - event_add(&ev2, NULL)) { - fprintf(stderr, "%s: cannot set base, add\n", __func__); - exit(1); - } - - tt_ptr_op(event_get_base(&ev1), ==, base1); - tt_ptr_op(event_get_base(&ev2), ==, base2); - - test_ok = 0; - /* can handle signal before loop is called */ - raise(SIGUSR1); - event_base_loop(base2, EVLOOP_NONBLOCK); - if (is_kqueue) { - if (!test_ok) - goto end; - test_ok = 0; - } - event_base_loop(base1, EVLOOP_NONBLOCK); - if (test_ok && !is_kqueue) { - test_ok = 0; - - /* set base1 to handle signals */ - event_base_loop(base1, EVLOOP_NONBLOCK); - raise(SIGUSR1); - event_base_loop(base1, EVLOOP_NONBLOCK); - event_base_loop(base2, EVLOOP_NONBLOCK); - } -end: - event_base_free(base1); - event_base_free(base2); - cleanup_test(); -} - -/* - * assert that a signal event removed from the event queue really is - * removed - with no possibility of it's parent handler being fired. - */ -static void -test_signal_assert(void) -{ - struct event ev; - struct event_base *base = event_init(); - test_ok = 0; - /* use SIGCONT so we don't kill ourselves when we signal to nowhere */ - evsignal_set(&ev, SIGCONT, signal_cb, &ev); - evsignal_add(&ev, NULL); - /* - * if evsignal_del() fails to reset the handler, it's current handler - * will still point to evsig_handler(). - */ - evsignal_del(&ev); - - raise(SIGCONT); -#if 0 - /* only way to verify we were in evsig_handler() */ - /* XXXX Now there's no longer a good way. */ - if (base->sig.evsig_caught) - test_ok = 0; - else - test_ok = 1; -#else - test_ok = 1; -#endif - - event_base_free(base); - cleanup_test(); - return; -} - -/* - * assert that we restore our previous signal handler properly. - */ -static void -test_signal_restore(void) -{ - struct event ev; - struct event_base *base = event_init(); -#ifdef EVENT__HAVE_SIGACTION - struct sigaction sa; -#endif - - test_ok = 0; -#ifdef EVENT__HAVE_SIGACTION - sa.sa_handler = signal_cb_sa; - sa.sa_flags = 0x0; - sigemptyset(&sa.sa_mask); - if (sigaction(SIGUSR1, &sa, NULL) == -1) - goto out; -#else - if (signal(SIGUSR1, signal_cb_sa) == SIG_ERR) - goto out; -#endif - evsignal_set(&ev, SIGUSR1, signal_cb, &ev); - evsignal_add(&ev, NULL); - evsignal_del(&ev); - - raise(SIGUSR1); - /* 1 == signal_cb, 2 == signal_cb_sa, we want our previous handler */ - if (test_ok != 2) - test_ok = 0; -out: - event_base_free(base); - cleanup_test(); - return; -} - -static void -signal_cb_swp(int sig, short event, void *arg) -{ - called++; - if (called < 5) - raise(sig); - else - event_loopexit(NULL); -} -static void -timeout_cb_swp(evutil_socket_t fd, short event, void *arg) -{ - if (called == -1) { - struct timeval tv = {5, 0}; - - called = 0; - evtimer_add((struct event *)arg, &tv); - raise(SIGUSR1); - return; - } - test_ok = 0; - event_loopexit(NULL); -} - -static void -test_signal_while_processing(void) -{ - struct event_base *base = event_init(); - struct event ev, ev_timer; - struct timeval tv = {0, 0}; - - setup_test("Receiving a signal while processing other signal: "); - - called = -1; - test_ok = 1; - signal_set(&ev, SIGUSR1, signal_cb_swp, NULL); - signal_add(&ev, NULL); - evtimer_set(&ev_timer, timeout_cb_swp, &ev_timer); - evtimer_add(&ev_timer, &tv); - event_dispatch(); - - event_base_free(base); - cleanup_test(); - return; -} -#endif - -static void -test_free_active_base(void *ptr) -{ - struct basic_test_data *data = ptr; - struct event_base *base1; - struct event ev1; - - base1 = event_init(); - if (base1) { - event_assign(&ev1, base1, data->pair[1], EV_READ, - dummy_read_cb, NULL); - event_add(&ev1, NULL); - event_base_free(base1); /* should not crash */ - } else { - tt_fail_msg("failed to create event_base for test"); - } - - base1 = event_init(); - tt_assert(base1); - event_assign(&ev1, base1, 0, 0, dummy_read_cb, NULL); - event_active(&ev1, EV_READ, 1); - event_base_free(base1); -end: - ; -} - -static void -test_manipulate_active_events(void *ptr) -{ - struct basic_test_data *data = ptr; - struct event_base *base = data->base; - struct event ev1; - - event_assign(&ev1, base, -1, EV_TIMEOUT, dummy_read_cb, NULL); - - /* Make sure an active event is pending. */ - event_active(&ev1, EV_READ, 1); - tt_int_op(event_pending(&ev1, EV_READ|EV_TIMEOUT|EV_WRITE, NULL), - ==, EV_READ); - - /* Make sure that activating an event twice works. */ - event_active(&ev1, EV_WRITE, 1); - tt_int_op(event_pending(&ev1, EV_READ|EV_TIMEOUT|EV_WRITE, NULL), - ==, EV_READ|EV_WRITE); - -end: - event_del(&ev1); -} - -static void -event_selfarg_cb(evutil_socket_t fd, short event, void *arg) -{ - struct event *ev = arg; - struct event_base *base = event_get_base(ev); - event_base_assert_ok_(base); - event_base_loopexit(base, NULL); - tt_want(ev == event_base_get_running_event(base)); -} - -static void -test_event_new_selfarg(void *ptr) -{ - struct basic_test_data *data = ptr; - struct event_base *base = data->base; - struct event *ev = event_new(base, -1, EV_READ, event_selfarg_cb, - event_self_cbarg()); - - event_active(ev, EV_READ, 1); - event_base_dispatch(base); - - event_free(ev); -} - -static void -test_event_assign_selfarg(void *ptr) -{ - struct basic_test_data *data = ptr; - struct event_base *base = data->base; - struct event ev; - - event_assign(&ev, base, -1, EV_READ, event_selfarg_cb, - event_self_cbarg()); - event_active(&ev, EV_READ, 1); - event_base_dispatch(base); -} - -static void -test_event_base_get_num_events(void *ptr) -{ - struct basic_test_data *data = ptr; - struct event_base *base = data->base; - struct event ev; - int event_count_active; - int event_count_virtual; - int event_count_added; - int event_count_active_virtual; - int event_count_active_added; - int event_count_virtual_added; - int event_count_active_added_virtual; - - struct timeval qsec = {0, 100000}; - - event_assign(&ev, base, -1, EV_READ, event_selfarg_cb, - event_self_cbarg()); - - event_add(&ev, &qsec); - event_count_active = event_base_get_num_events(base, - EVENT_BASE_COUNT_ACTIVE); - event_count_virtual = event_base_get_num_events(base, - EVENT_BASE_COUNT_VIRTUAL); - event_count_added = event_base_get_num_events(base, - EVENT_BASE_COUNT_ADDED); - event_count_active_virtual = event_base_get_num_events(base, - EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_VIRTUAL); - event_count_active_added = event_base_get_num_events(base, - EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_ADDED); - event_count_virtual_added = event_base_get_num_events(base, - EVENT_BASE_COUNT_VIRTUAL|EVENT_BASE_COUNT_ADDED); - event_count_active_added_virtual = event_base_get_num_events(base, - EVENT_BASE_COUNT_ACTIVE| - EVENT_BASE_COUNT_ADDED| - EVENT_BASE_COUNT_VIRTUAL); - tt_int_op(event_count_active, ==, 0); - tt_int_op(event_count_virtual, ==, 0); - /* libevent itself adds a timeout event, so the event_count is 2 here */ - tt_int_op(event_count_added, ==, 2); - tt_int_op(event_count_active_virtual, ==, 0); - tt_int_op(event_count_active_added, ==, 2); - tt_int_op(event_count_virtual_added, ==, 2); - tt_int_op(event_count_active_added_virtual, ==, 2); - - event_active(&ev, EV_READ, 1); - event_count_active = event_base_get_num_events(base, - EVENT_BASE_COUNT_ACTIVE); - event_count_virtual = event_base_get_num_events(base, - EVENT_BASE_COUNT_VIRTUAL); - event_count_added = event_base_get_num_events(base, - EVENT_BASE_COUNT_ADDED); - event_count_active_virtual = event_base_get_num_events(base, - EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_VIRTUAL); - event_count_active_added = event_base_get_num_events(base, - EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_ADDED); - event_count_virtual_added = event_base_get_num_events(base, - EVENT_BASE_COUNT_VIRTUAL|EVENT_BASE_COUNT_ADDED); - event_count_active_added_virtual = event_base_get_num_events(base, - EVENT_BASE_COUNT_ACTIVE| - EVENT_BASE_COUNT_ADDED| - EVENT_BASE_COUNT_VIRTUAL); - tt_int_op(event_count_active, ==, 1); - tt_int_op(event_count_virtual, ==, 0); - tt_int_op(event_count_added, ==, 3); - tt_int_op(event_count_active_virtual, ==, 1); - tt_int_op(event_count_active_added, ==, 4); - tt_int_op(event_count_virtual_added, ==, 3); - tt_int_op(event_count_active_added_virtual, ==, 4); - - event_base_loop(base, 0); - event_count_active = event_base_get_num_events(base, - EVENT_BASE_COUNT_ACTIVE); - event_count_virtual = event_base_get_num_events(base, - EVENT_BASE_COUNT_VIRTUAL); - event_count_added = event_base_get_num_events(base, - EVENT_BASE_COUNT_ADDED); - event_count_active_virtual = event_base_get_num_events(base, - EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_VIRTUAL); - event_count_active_added = event_base_get_num_events(base, - EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_ADDED); - event_count_virtual_added = event_base_get_num_events(base, - EVENT_BASE_COUNT_VIRTUAL|EVENT_BASE_COUNT_ADDED); - event_count_active_added_virtual = event_base_get_num_events(base, - EVENT_BASE_COUNT_ACTIVE| - EVENT_BASE_COUNT_ADDED| - EVENT_BASE_COUNT_VIRTUAL); - tt_int_op(event_count_active, ==, 0); - tt_int_op(event_count_virtual, ==, 0); - tt_int_op(event_count_added, ==, 0); - tt_int_op(event_count_active_virtual, ==, 0); - tt_int_op(event_count_active_added, ==, 0); - tt_int_op(event_count_virtual_added, ==, 0); - tt_int_op(event_count_active_added_virtual, ==, 0); - - event_base_add_virtual_(base); - event_count_active = event_base_get_num_events(base, - EVENT_BASE_COUNT_ACTIVE); - event_count_virtual = event_base_get_num_events(base, - EVENT_BASE_COUNT_VIRTUAL); - event_count_added = event_base_get_num_events(base, - EVENT_BASE_COUNT_ADDED); - event_count_active_virtual = event_base_get_num_events(base, - EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_VIRTUAL); - event_count_active_added = event_base_get_num_events(base, - EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_ADDED); - event_count_virtual_added = event_base_get_num_events(base, - EVENT_BASE_COUNT_VIRTUAL|EVENT_BASE_COUNT_ADDED); - event_count_active_added_virtual = event_base_get_num_events(base, - EVENT_BASE_COUNT_ACTIVE| - EVENT_BASE_COUNT_ADDED| - EVENT_BASE_COUNT_VIRTUAL); - tt_int_op(event_count_active, ==, 0); - tt_int_op(event_count_virtual, ==, 1); - tt_int_op(event_count_added, ==, 0); - tt_int_op(event_count_active_virtual, ==, 1); - tt_int_op(event_count_active_added, ==, 0); - tt_int_op(event_count_virtual_added, ==, 1); - tt_int_op(event_count_active_added_virtual, ==, 1); - -end: - ; -} - -static void -test_event_base_get_max_events(void *ptr) -{ - struct basic_test_data *data = ptr; - struct event_base *base = data->base; - struct event ev; - struct event ev2; - int event_count_active; - int event_count_virtual; - int event_count_added; - int event_count_active_virtual; - int event_count_active_added; - int event_count_virtual_added; - int event_count_active_added_virtual; - - struct timeval qsec = {0, 100000}; - - event_assign(&ev, base, -1, EV_READ, event_selfarg_cb, - event_self_cbarg()); - event_assign(&ev2, base, -1, EV_READ, event_selfarg_cb, - event_self_cbarg()); - - event_add(&ev, &qsec); - event_add(&ev2, &qsec); - event_del(&ev2); - - event_count_active = event_base_get_max_events(base, - EVENT_BASE_COUNT_ACTIVE, 0); - event_count_virtual = event_base_get_max_events(base, - EVENT_BASE_COUNT_VIRTUAL, 0); - event_count_added = event_base_get_max_events(base, - EVENT_BASE_COUNT_ADDED, 0); - event_count_active_virtual = event_base_get_max_events(base, - EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_VIRTUAL, 0); - event_count_active_added = event_base_get_max_events(base, - EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED, 0); - event_count_virtual_added = event_base_get_max_events(base, - EVENT_BASE_COUNT_VIRTUAL | EVENT_BASE_COUNT_ADDED, 0); - event_count_active_added_virtual = event_base_get_max_events(base, - EVENT_BASE_COUNT_ACTIVE | - EVENT_BASE_COUNT_ADDED | - EVENT_BASE_COUNT_VIRTUAL, 0); - - tt_int_op(event_count_active, ==, 0); - tt_int_op(event_count_virtual, ==, 0); - /* libevent itself adds a timeout event, so the event_count is 4 here */ - tt_int_op(event_count_added, ==, 4); - tt_int_op(event_count_active_virtual, ==, 0); - tt_int_op(event_count_active_added, ==, 4); - tt_int_op(event_count_virtual_added, ==, 4); - tt_int_op(event_count_active_added_virtual, ==, 4); - - event_active(&ev, EV_READ, 1); - event_count_active = event_base_get_max_events(base, - EVENT_BASE_COUNT_ACTIVE, 0); - event_count_virtual = event_base_get_max_events(base, - EVENT_BASE_COUNT_VIRTUAL, 0); - event_count_added = event_base_get_max_events(base, - EVENT_BASE_COUNT_ADDED, 0); - event_count_active_virtual = event_base_get_max_events(base, - EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_VIRTUAL, 0); - event_count_active_added = event_base_get_max_events(base, - EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED, 0); - event_count_virtual_added = event_base_get_max_events(base, - EVENT_BASE_COUNT_VIRTUAL | EVENT_BASE_COUNT_ADDED, 0); - event_count_active_added_virtual = event_base_get_max_events(base, - EVENT_BASE_COUNT_ACTIVE | - EVENT_BASE_COUNT_ADDED | - EVENT_BASE_COUNT_VIRTUAL, 0); - - tt_int_op(event_count_active, ==, 1); - tt_int_op(event_count_virtual, ==, 0); - tt_int_op(event_count_added, ==, 4); - tt_int_op(event_count_active_virtual, ==, 1); - tt_int_op(event_count_active_added, ==, 5); - tt_int_op(event_count_virtual_added, ==, 4); - tt_int_op(event_count_active_added_virtual, ==, 5); - - event_base_loop(base, 0); - event_count_active = event_base_get_max_events(base, - EVENT_BASE_COUNT_ACTIVE, 1); - event_count_virtual = event_base_get_max_events(base, - EVENT_BASE_COUNT_VIRTUAL, 1); - event_count_added = event_base_get_max_events(base, - EVENT_BASE_COUNT_ADDED, 1); - event_count_active_virtual = event_base_get_max_events(base, - EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_VIRTUAL, 0); - event_count_active_added = event_base_get_max_events(base, - EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED, 0); - event_count_virtual_added = event_base_get_max_events(base, - EVENT_BASE_COUNT_VIRTUAL | EVENT_BASE_COUNT_ADDED, 0); - event_count_active_added_virtual = event_base_get_max_events(base, - EVENT_BASE_COUNT_ACTIVE | - EVENT_BASE_COUNT_ADDED | - EVENT_BASE_COUNT_VIRTUAL, 1); - - tt_int_op(event_count_active, ==, 1); - tt_int_op(event_count_virtual, ==, 0); - tt_int_op(event_count_added, ==, 4); - tt_int_op(event_count_active_virtual, ==, 0); - tt_int_op(event_count_active_added, ==, 0); - tt_int_op(event_count_virtual_added, ==, 0); - tt_int_op(event_count_active_added_virtual, ==, 0); - - event_count_active = event_base_get_max_events(base, - EVENT_BASE_COUNT_ACTIVE, 0); - event_count_virtual = event_base_get_max_events(base, - EVENT_BASE_COUNT_VIRTUAL, 0); - event_count_added = event_base_get_max_events(base, - EVENT_BASE_COUNT_ADDED, 0); - tt_int_op(event_count_active, ==, 0); - tt_int_op(event_count_virtual, ==, 0); - tt_int_op(event_count_added, ==, 0); - - event_base_add_virtual_(base); - event_count_active = event_base_get_max_events(base, - EVENT_BASE_COUNT_ACTIVE, 0); - event_count_virtual = event_base_get_max_events(base, - EVENT_BASE_COUNT_VIRTUAL, 0); - event_count_added = event_base_get_max_events(base, - EVENT_BASE_COUNT_ADDED, 0); - event_count_active_virtual = event_base_get_max_events(base, - EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_VIRTUAL, 0); - event_count_active_added = event_base_get_max_events(base, - EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED, 0); - event_count_virtual_added = event_base_get_max_events(base, - EVENT_BASE_COUNT_VIRTUAL | EVENT_BASE_COUNT_ADDED, 0); - event_count_active_added_virtual = event_base_get_max_events(base, - EVENT_BASE_COUNT_ACTIVE | - EVENT_BASE_COUNT_ADDED | - EVENT_BASE_COUNT_VIRTUAL, 0); - - tt_int_op(event_count_active, ==, 0); - tt_int_op(event_count_virtual, ==, 1); - tt_int_op(event_count_added, ==, 0); - tt_int_op(event_count_active_virtual, ==, 1); - tt_int_op(event_count_active_added, ==, 0); - tt_int_op(event_count_virtual_added, ==, 1); - tt_int_op(event_count_active_added_virtual, ==, 1); - -end: - ; -} - -static void -test_bad_assign(void *ptr) -{ - struct event ev; - int r; - /* READ|SIGNAL is not allowed */ - r = event_assign(&ev, NULL, -1, EV_SIGNAL|EV_READ, dummy_read_cb, NULL); - tt_int_op(r,==,-1); - -end: - ; -} - -static int reentrant_cb_run = 0; - -static void -bad_reentrant_run_loop_cb(evutil_socket_t fd, short what, void *ptr) -{ - struct event_base *base = ptr; - int r; - reentrant_cb_run = 1; - /* This reentrant call to event_base_loop should be detected and - * should fail */ - r = event_base_loop(base, 0); - tt_int_op(r, ==, -1); -end: - ; -} - -static void -test_bad_reentrant(void *ptr) -{ - struct basic_test_data *data = ptr; - struct event_base *base = data->base; - struct event ev; - int r; - event_assign(&ev, base, -1, - 0, bad_reentrant_run_loop_cb, base); - - event_active(&ev, EV_WRITE, 1); - r = event_base_loop(base, 0); - tt_int_op(r, ==, 1); - tt_int_op(reentrant_cb_run, ==, 1); -end: - ; -} - -static int n_write_a_byte_cb=0; -static int n_read_and_drain_cb=0; -static int n_activate_other_event_cb=0; -static void -write_a_byte_cb(evutil_socket_t fd, short what, void *arg) -{ - char buf[] = "x"; - if (write(fd, buf, 1) == 1) - ++n_write_a_byte_cb; -} -static void -read_and_drain_cb(evutil_socket_t fd, short what, void *arg) -{ - char buf[128]; - int n; - ++n_read_and_drain_cb; - while ((n = read(fd, buf, sizeof(buf))) > 0) - ; -} - -static void -activate_other_event_cb(evutil_socket_t fd, short what, void *other_) -{ - struct event *ev_activate = other_; - ++n_activate_other_event_cb; - event_active_later_(ev_activate, EV_READ); -} - -static void -test_active_later(void *ptr) -{ - struct basic_test_data *data = ptr; - struct event *ev1 = NULL, *ev2 = NULL; - struct event ev3, ev4; - struct timeval qsec = {0, 100000}; - ev1 = event_new(data->base, data->pair[0], EV_READ|EV_PERSIST, read_and_drain_cb, NULL); - ev2 = event_new(data->base, data->pair[1], EV_WRITE|EV_PERSIST, write_a_byte_cb, NULL); - event_assign(&ev3, data->base, -1, 0, activate_other_event_cb, &ev4); - event_assign(&ev4, data->base, -1, 0, activate_other_event_cb, &ev3); - event_add(ev1, NULL); - event_add(ev2, NULL); - event_active_later_(&ev3, EV_READ); - - event_base_loopexit(data->base, &qsec); - - event_base_loop(data->base, 0); - - TT_BLATHER(("%d write calls, %d read calls, %d activate-other calls.", - n_write_a_byte_cb, n_read_and_drain_cb, n_activate_other_event_cb)); - event_del(&ev3); - event_del(&ev4); - - tt_int_op(n_write_a_byte_cb, ==, n_activate_other_event_cb); - tt_int_op(n_write_a_byte_cb, >, 100); - tt_int_op(n_read_and_drain_cb, >, 100); - tt_int_op(n_activate_other_event_cb, >, 100); - - event_active_later_(&ev4, EV_READ); - event_active(&ev4, EV_READ, 1); /* This should make the event - active immediately. */ - tt_assert((ev4.ev_flags & EVLIST_ACTIVE) != 0); - tt_assert((ev4.ev_flags & EVLIST_ACTIVE_LATER) == 0); - - /* Now leave this one around, so that event_free sees it and removes - * it. */ - event_active_later_(&ev3, EV_READ); - event_base_assert_ok_(data->base); - -end: - if (ev1) - event_free(ev1); - if (ev2) - event_free(ev2); - - event_base_free(data->base); - data->base = NULL; -} - - -static void incr_arg_cb(evutil_socket_t fd, short what, void *arg) -{ - int *intptr = arg; - (void) fd; (void) what; - ++*intptr; -} -static void remove_timers_cb(evutil_socket_t fd, short what, void *arg) -{ - struct event **ep = arg; - (void) fd; (void) what; - event_remove_timer(ep[0]); - event_remove_timer(ep[1]); -} -static void send_a_byte_cb(evutil_socket_t fd, short what, void *arg) -{ - evutil_socket_t *sockp = arg; - (void) fd; (void) what; - (void) write(*sockp, "A", 1); -} -struct read_not_timeout_param -{ - struct event **ev; - int events; - int count; -}; -static void read_not_timeout_cb(evutil_socket_t fd, short what, void *arg) -{ - struct read_not_timeout_param *rntp = arg; - char c; - ev_ssize_t n; - (void) fd; (void) what; - n = read(fd, &c, 1); - tt_int_op(n, ==, 1); - rntp->events |= what; - ++rntp->count; - if(2 == rntp->count) event_del(rntp->ev[0]); -end: - ; -} - -static void -test_event_remove_timeout(void *ptr) -{ - struct basic_test_data *data = ptr; - struct event_base *base = data->base; - struct event *ev[5]; - int ev1_fired=0; - struct timeval ms25 = { 0, 25*1000 }, - ms40 = { 0, 40*1000 }, - ms75 = { 0, 75*1000 }, - ms125 = { 0, 125*1000 }; - struct read_not_timeout_param rntp = { ev, 0, 0 }; - - event_base_assert_ok_(base); - - ev[0] = event_new(base, data->pair[0], EV_READ|EV_PERSIST, - read_not_timeout_cb, &rntp); - ev[1] = evtimer_new(base, incr_arg_cb, &ev1_fired); - ev[2] = evtimer_new(base, remove_timers_cb, ev); - ev[3] = evtimer_new(base, send_a_byte_cb, &data->pair[1]); - ev[4] = evtimer_new(base, send_a_byte_cb, &data->pair[1]); - tt_assert(base); - event_add(ev[2], &ms25); /* remove timers */ - event_add(ev[4], &ms40); /* write to test if timer re-activates */ - event_add(ev[0], &ms75); /* read */ - event_add(ev[1], &ms75); /* timer */ - event_add(ev[3], &ms125); /* timeout. */ - event_base_assert_ok_(base); - - event_base_dispatch(base); - - tt_int_op(ev1_fired, ==, 0); - tt_int_op(rntp.events, ==, EV_READ); - - event_base_assert_ok_(base); -end: - event_free(ev[0]); - event_free(ev[1]); - event_free(ev[2]); - event_free(ev[3]); - event_free(ev[4]); -} - -static void -test_event_base_new(void *ptr) -{ - struct basic_test_data *data = ptr; - struct event_base *base = 0; - struct event ev1; - struct basic_cb_args args; - - int towrite = (int)strlen(TEST1)+1; - int len = write(data->pair[0], TEST1, towrite); - - if (len < 0) - tt_abort_perror("initial write"); - else if (len != towrite) - tt_abort_printf(("initial write fell short (%d of %d bytes)", - len, towrite)); - - if (shutdown(data->pair[0], SHUT_WR)) - tt_abort_perror("initial write shutdown"); - - base = event_base_new(); - if (!base) - tt_abort_msg("failed to create event base"); - - args.eb = base; - args.ev = &ev1; - args.callcount = 0; - event_assign(&ev1, base, data->pair[1], - EV_READ|EV_PERSIST, basic_read_cb, &args); - - if (event_add(&ev1, NULL)) - tt_abort_perror("initial event_add"); - - if (event_base_loop(base, 0)) - tt_abort_msg("unsuccessful exit from event loop"); - -end: - if (base) - event_base_free(base); -} - -static void -test_loopexit(void) -{ - struct timeval tv, tv_start, tv_end; - struct event ev; - - setup_test("Loop exit: "); - - tv.tv_usec = 0; - tv.tv_sec = 60*60*24; - evtimer_set(&ev, timeout_cb, NULL); - evtimer_add(&ev, &tv); - - tv.tv_usec = 300*1000; - tv.tv_sec = 0; - event_loopexit(&tv); - - evutil_gettimeofday(&tv_start, NULL); - event_dispatch(); - evutil_gettimeofday(&tv_end, NULL); - - evtimer_del(&ev); - - tt_assert(event_base_got_exit(global_base)); - tt_assert(!event_base_got_break(global_base)); - - test_timeval_diff_eq(&tv_start, &tv_end, 300); - - test_ok = 1; -end: - cleanup_test(); -} - -static void -test_loopexit_multiple(void) -{ - struct timeval tv, tv_start, tv_end; - struct event_base *base; - - setup_test("Loop Multiple exit: "); - - base = event_base_new(); - - tv.tv_usec = 200*1000; - tv.tv_sec = 0; - event_base_loopexit(base, &tv); - - tv.tv_usec = 0; - tv.tv_sec = 3; - event_base_loopexit(base, &tv); - - evutil_gettimeofday(&tv_start, NULL); - event_base_dispatch(base); - evutil_gettimeofday(&tv_end, NULL); - - tt_assert(event_base_got_exit(base)); - tt_assert(!event_base_got_break(base)); - - event_base_free(base); - - test_timeval_diff_eq(&tv_start, &tv_end, 200); - - test_ok = 1; - -end: - cleanup_test(); -} - -static void -break_cb(evutil_socket_t fd, short events, void *arg) -{ - test_ok = 1; - event_loopbreak(); -} - -static void -fail_cb(evutil_socket_t fd, short events, void *arg) -{ - test_ok = 0; -} - -static void -test_loopbreak(void) -{ - struct event ev1, ev2; - struct timeval tv; - - setup_test("Loop break: "); - - tv.tv_sec = 0; - tv.tv_usec = 0; - evtimer_set(&ev1, break_cb, NULL); - evtimer_add(&ev1, &tv); - evtimer_set(&ev2, fail_cb, NULL); - evtimer_add(&ev2, &tv); - - event_dispatch(); - - tt_assert(!event_base_got_exit(global_base)); - tt_assert(event_base_got_break(global_base)); - - evtimer_del(&ev1); - evtimer_del(&ev2); - -end: - cleanup_test(); -} - -static struct event *readd_test_event_last_added = NULL; -static void -re_add_read_cb(evutil_socket_t fd, short event, void *arg) -{ - char buf[256]; - struct event *ev_other = arg; - ev_ssize_t n_read; - - readd_test_event_last_added = ev_other; - - n_read = read(fd, buf, sizeof(buf)); - - if (n_read < 0) { - tt_fail_perror("read"); - event_base_loopbreak(event_get_base(ev_other)); - return; - } else { - event_add(ev_other, NULL); - ++test_ok; - } -} - -static void -test_nonpersist_readd(void) -{ - struct event ev1, ev2; - - setup_test("Re-add nonpersistent events: "); - event_set(&ev1, pair[0], EV_READ, re_add_read_cb, &ev2); - event_set(&ev2, pair[1], EV_READ, re_add_read_cb, &ev1); - - if (write(pair[0], "Hello", 5) < 0) { - tt_fail_perror("write(pair[0])"); - } - - if (write(pair[1], "Hello", 5) < 0) { - tt_fail_perror("write(pair[1])\n"); - } - - if (event_add(&ev1, NULL) == -1 || - event_add(&ev2, NULL) == -1) { - test_ok = 0; - } - if (test_ok != 0) - exit(1); - event_loop(EVLOOP_ONCE); - if (test_ok != 2) - exit(1); - /* At this point, we executed both callbacks. Whichever one got - * called first added the second, but the second then immediately got - * deleted before its callback was called. At this point, though, it - * re-added the first. - */ - if (!readd_test_event_last_added) { - test_ok = 0; - } else if (readd_test_event_last_added == &ev1) { - if (!event_pending(&ev1, EV_READ, NULL) || - event_pending(&ev2, EV_READ, NULL)) - test_ok = 0; - } else { - if (event_pending(&ev1, EV_READ, NULL) || - !event_pending(&ev2, EV_READ, NULL)) - test_ok = 0; - } - - event_del(&ev1); - event_del(&ev2); - - cleanup_test(); -} - -struct test_pri_event { - struct event ev; - int count; -}; - -static void -test_priorities_cb(evutil_socket_t fd, short what, void *arg) -{ - struct test_pri_event *pri = arg; - struct timeval tv; - - if (pri->count == 3) { - event_loopexit(NULL); - return; - } - - pri->count++; - - evutil_timerclear(&tv); - event_add(&pri->ev, &tv); -} - -static void -test_priorities_impl(int npriorities) -{ - struct test_pri_event one, two; - struct timeval tv; - - TT_BLATHER(("Testing Priorities %d: ", npriorities)); - - event_base_priority_init(global_base, npriorities); - - memset(&one, 0, sizeof(one)); - memset(&two, 0, sizeof(two)); - - timeout_set(&one.ev, test_priorities_cb, &one); - if (event_priority_set(&one.ev, 0) == -1) { - fprintf(stderr, "%s: failed to set priority", __func__); - exit(1); - } - - timeout_set(&two.ev, test_priorities_cb, &two); - if (event_priority_set(&two.ev, npriorities - 1) == -1) { - fprintf(stderr, "%s: failed to set priority", __func__); - exit(1); - } - - evutil_timerclear(&tv); - - if (event_add(&one.ev, &tv) == -1) - exit(1); - if (event_add(&two.ev, &tv) == -1) - exit(1); - - event_dispatch(); - - event_del(&one.ev); - event_del(&two.ev); - - if (npriorities == 1) { - if (one.count == 3 && two.count == 3) - test_ok = 1; - } else if (npriorities == 2) { - /* Two is called once because event_loopexit is priority 1 */ - if (one.count == 3 && two.count == 1) - test_ok = 1; - } else { - if (one.count == 3 && two.count == 0) - test_ok = 1; - } -} - -static void -test_priorities(void) -{ - test_priorities_impl(1); - if (test_ok) - test_priorities_impl(2); - if (test_ok) - test_priorities_impl(3); -} - -/* priority-active-inversion: activate a higher-priority event, and make sure - * it keeps us from running a lower-priority event first. */ -static int n_pai_calls = 0; -static struct event pai_events[3]; - -static void -prio_active_inversion_cb(evutil_socket_t fd, short what, void *arg) -{ - int *call_order = arg; - *call_order = n_pai_calls++; - if (n_pai_calls == 1) { - /* This should activate later, even though it shares a - priority with us. */ - event_active(&pai_events[1], EV_READ, 1); - /* This should activate next, since its priority is higher, - even though we activated it second. */ - event_active(&pai_events[2], EV_TIMEOUT, 1); - } -} - -static void -test_priority_active_inversion(void *data_) -{ - struct basic_test_data *data = data_; - struct event_base *base = data->base; - int call_order[3]; - int i; - tt_int_op(event_base_priority_init(base, 8), ==, 0); - - n_pai_calls = 0; - memset(call_order, 0, sizeof(call_order)); - - for (i=0;i<3;++i) { - event_assign(&pai_events[i], data->base, -1, 0, - prio_active_inversion_cb, &call_order[i]); - } - - event_priority_set(&pai_events[0], 4); - event_priority_set(&pai_events[1], 4); - event_priority_set(&pai_events[2], 0); - - event_active(&pai_events[0], EV_WRITE, 1); - - event_base_dispatch(base); - tt_int_op(n_pai_calls, ==, 3); - tt_int_op(call_order[0], ==, 0); - tt_int_op(call_order[1], ==, 2); - tt_int_op(call_order[2], ==, 1); -end: - ; -} - - -static void -test_multiple_cb(evutil_socket_t fd, short event, void *arg) -{ - if (event & EV_READ) - test_ok |= 1; - else if (event & EV_WRITE) - test_ok |= 2; -} - -static void -test_multiple_events_for_same_fd(void) -{ - struct event e1, e2; - - setup_test("Multiple events for same fd: "); - - event_set(&e1, pair[0], EV_READ, test_multiple_cb, NULL); - event_add(&e1, NULL); - event_set(&e2, pair[0], EV_WRITE, test_multiple_cb, NULL); - event_add(&e2, NULL); - event_loop(EVLOOP_ONCE); - event_del(&e2); - - if (write(pair[1], TEST1, strlen(TEST1)+1) < 0) { - tt_fail_perror("write"); - } - - event_loop(EVLOOP_ONCE); - event_del(&e1); - - if (test_ok != 3) - test_ok = 0; - - cleanup_test(); -} - -int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf); -int evtag_decode_int64(ev_uint64_t *pnumber, struct evbuffer *evbuf); -int evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t number); -int evtag_decode_tag(ev_uint32_t *pnumber, struct evbuffer *evbuf); - -static void -read_once_cb(evutil_socket_t fd, short event, void *arg) -{ - char buf[256]; - int len; - - len = read(fd, buf, sizeof(buf)); - - if (called) { - test_ok = 0; - } else if (len) { - /* Assumes global pair[0] can be used for writing */ - if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { - tt_fail_perror("write"); - test_ok = 0; - } else { - test_ok = 1; - } - } - - called++; -} - -static void -test_want_only_once(void) -{ - struct event ev; - struct timeval tv; - - /* Very simple read test */ - setup_test("Want read only once: "); - - if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { - tt_fail_perror("write"); - } - - /* Setup the loop termination */ - evutil_timerclear(&tv); - tv.tv_usec = 300*1000; - event_loopexit(&tv); - - event_set(&ev, pair[1], EV_READ, read_once_cb, &ev); - if (event_add(&ev, NULL) == -1) - exit(1); - event_dispatch(); - - cleanup_test(); -} - -#define TEST_MAX_INT 6 - -static void -evtag_int_test(void *ptr) -{ - struct evbuffer *tmp = evbuffer_new(); - ev_uint32_t integers[TEST_MAX_INT] = { - 0xaf0, 0x1000, 0x1, 0xdeadbeef, 0x00, 0xbef000 - }; - ev_uint32_t integer; - ev_uint64_t big_int; - int i; - - evtag_init(); - - for (i = 0; i < TEST_MAX_INT; i++) { - int oldlen, newlen; - oldlen = (int)EVBUFFER_LENGTH(tmp); - evtag_encode_int(tmp, integers[i]); - newlen = (int)EVBUFFER_LENGTH(tmp); - TT_BLATHER(("encoded 0x%08x with %d bytes", - (unsigned)integers[i], newlen - oldlen)); - big_int = integers[i]; - big_int *= 1000000000; /* 1 billion */ - evtag_encode_int64(tmp, big_int); - } - - for (i = 0; i < TEST_MAX_INT; i++) { - tt_int_op(evtag_decode_int(&integer, tmp), !=, -1); - tt_uint_op(integer, ==, integers[i]); - tt_int_op(evtag_decode_int64(&big_int, tmp), !=, -1); - tt_assert((big_int / 1000000000) == integers[i]); - } - - tt_uint_op(EVBUFFER_LENGTH(tmp), ==, 0); -end: - evbuffer_free(tmp); -} - -static void -evtag_fuzz(void *ptr) -{ - unsigned char buffer[4096]; - struct evbuffer *tmp = evbuffer_new(); - struct timeval tv; - int i, j; - - int not_failed = 0; - - evtag_init(); - - for (j = 0; j < 100; j++) { - for (i = 0; i < (int)sizeof(buffer); i++) - buffer[i] = test_weakrand(); - evbuffer_drain(tmp, -1); - evbuffer_add(tmp, buffer, sizeof(buffer)); - - if (evtag_unmarshal_timeval(tmp, 0, &tv) != -1) - not_failed++; - } - - /* The majority of decodes should fail */ - tt_int_op(not_failed, <, 10); - - /* Now insert some corruption into the tag length field */ - evbuffer_drain(tmp, -1); - evutil_timerclear(&tv); - tv.tv_sec = 1; - evtag_marshal_timeval(tmp, 0, &tv); - evbuffer_add(tmp, buffer, sizeof(buffer)); - - ((char *)EVBUFFER_DATA(tmp))[1] = '\xff'; - if (evtag_unmarshal_timeval(tmp, 0, &tv) != -1) { - tt_abort_msg("evtag_unmarshal_timeval should have failed"); - } - -end: - evbuffer_free(tmp); -} - -static void -evtag_tag_encoding(void *ptr) -{ - struct evbuffer *tmp = evbuffer_new(); - ev_uint32_t integers[TEST_MAX_INT] = { - 0xaf0, 0x1000, 0x1, 0xdeadbeef, 0x00, 0xbef000 - }; - ev_uint32_t integer; - int i; - - evtag_init(); - - for (i = 0; i < TEST_MAX_INT; i++) { - int oldlen, newlen; - oldlen = (int)EVBUFFER_LENGTH(tmp); - evtag_encode_tag(tmp, integers[i]); - newlen = (int)EVBUFFER_LENGTH(tmp); - TT_BLATHER(("encoded 0x%08x with %d bytes", - (unsigned)integers[i], newlen - oldlen)); - } - - for (i = 0; i < TEST_MAX_INT; i++) { - tt_int_op(evtag_decode_tag(&integer, tmp), !=, -1); - tt_uint_op(integer, ==, integers[i]); - } - - tt_uint_op(EVBUFFER_LENGTH(tmp), ==, 0); - -end: - evbuffer_free(tmp); -} - -static void -evtag_test_peek(void *ptr) -{ - struct evbuffer *tmp = evbuffer_new(); - ev_uint32_t u32; - - evtag_marshal_int(tmp, 30, 0); - evtag_marshal_string(tmp, 40, "Hello world"); - - tt_int_op(evtag_peek(tmp, &u32), ==, 1); - tt_int_op(u32, ==, 30); - tt_int_op(evtag_peek_length(tmp, &u32), ==, 0); - tt_int_op(u32, ==, 1+1+1); - tt_int_op(evtag_consume(tmp), ==, 0); - - tt_int_op(evtag_peek(tmp, &u32), ==, 1); - tt_int_op(u32, ==, 40); - tt_int_op(evtag_peek_length(tmp, &u32), ==, 0); - tt_int_op(u32, ==, 1+1+11); - tt_int_op(evtag_payload_length(tmp, &u32), ==, 0); - tt_int_op(u32, ==, 11); - -end: - evbuffer_free(tmp); -} - - -static void -test_methods(void *ptr) -{ - const char **methods = event_get_supported_methods(); - struct event_config *cfg = NULL; - struct event_base *base = NULL; - const char *backend; - int n_methods = 0; - - tt_assert(methods); - - backend = methods[0]; - while (*methods != NULL) { - TT_BLATHER(("Support method: %s", *methods)); - ++methods; - ++n_methods; - } - - cfg = event_config_new(); - assert(cfg != NULL); - - tt_int_op(event_config_avoid_method(cfg, backend), ==, 0); - event_config_set_flag(cfg, EVENT_BASE_FLAG_IGNORE_ENV); - - base = event_base_new_with_config(cfg); - if (n_methods > 1) { - tt_assert(base); - tt_str_op(backend, !=, event_base_get_method(base)); - } else { - tt_assert(base == NULL); - } - -end: - if (base) - event_base_free(base); - if (cfg) - event_config_free(cfg); -} - -static void -test_version(void *arg) -{ - const char *vstr; - ev_uint32_t vint; - int major, minor, patch, n; - - vstr = event_get_version(); - vint = event_get_version_number(); - - tt_assert(vstr); - tt_assert(vint); - - tt_str_op(vstr, ==, LIBEVENT_VERSION); - tt_int_op(vint, ==, LIBEVENT_VERSION_NUMBER); - - n = sscanf(vstr, "%d.%d.%d", &major, &minor, &patch); - tt_assert(3 == n); - tt_int_op((vint&0xffffff00), ==, ((major<<24)|(minor<<16)|(patch<<8))); -end: - ; -} - -static void -test_base_features(void *arg) -{ - struct event_base *base = NULL; - struct event_config *cfg = NULL; - - cfg = event_config_new(); - - tt_assert(0 == event_config_require_features(cfg, EV_FEATURE_ET)); - - base = event_base_new_with_config(cfg); - if (base) { - tt_int_op(EV_FEATURE_ET, ==, - event_base_get_features(base) & EV_FEATURE_ET); - } else { - base = event_base_new(); - tt_int_op(0, ==, event_base_get_features(base) & EV_FEATURE_ET); - } - -end: - if (base) - event_base_free(base); - if (cfg) - event_config_free(cfg); -} - -#ifdef EVENT__HAVE_SETENV -#define SETENV_OK -#elif !defined(EVENT__HAVE_SETENV) && defined(EVENT__HAVE_PUTENV) -static void setenv(const char *k, const char *v, int o_) -{ - char b[256]; - evutil_snprintf(b, sizeof(b), "%s=%s",k,v); - putenv(b); -} -#define SETENV_OK -#endif - -#ifdef EVENT__HAVE_UNSETENV -#define UNSETENV_OK -#elif !defined(EVENT__HAVE_UNSETENV) && defined(EVENT__HAVE_PUTENV) -static void unsetenv(const char *k) -{ - char b[256]; - evutil_snprintf(b, sizeof(b), "%s=",k); - putenv(b); -} -#define UNSETENV_OK -#endif - -#if defined(SETENV_OK) && defined(UNSETENV_OK) -static void -methodname_to_envvar(const char *mname, char *buf, size_t buflen) -{ - char *cp; - evutil_snprintf(buf, buflen, "EVENT_NO%s", mname); - for (cp = buf; *cp; ++cp) { - *cp = EVUTIL_TOUPPER_(*cp); - } -} -#endif - -static void -test_base_environ(void *arg) -{ - struct event_base *base = NULL; - struct event_config *cfg = NULL; - -#if defined(SETENV_OK) && defined(UNSETENV_OK) - const char **basenames; - int i, n_methods=0; - char varbuf[128]; - const char *defaultname, *ignoreenvname; - - /* See if unsetenv works before we rely on it. */ - setenv("EVENT_NOWAFFLES", "1", 1); - unsetenv("EVENT_NOWAFFLES"); - if (getenv("EVENT_NOWAFFLES") != NULL) { -#ifndef EVENT__HAVE_UNSETENV - TT_DECLARE("NOTE", ("Can't fake unsetenv; skipping test")); -#else - TT_DECLARE("NOTE", ("unsetenv doesn't work; skipping test")); -#endif - tt_skip(); - } - - basenames = event_get_supported_methods(); - for (i = 0; basenames[i]; ++i) { - methodname_to_envvar(basenames[i], varbuf, sizeof(varbuf)); - unsetenv(varbuf); - ++n_methods; - } - - base = event_base_new(); - tt_assert(base); - - defaultname = event_base_get_method(base); - TT_BLATHER(("default is <%s>", defaultname)); - event_base_free(base); - base = NULL; - - /* Can we disable the method with EVENT_NOfoo ? */ - if (!strcmp(defaultname, "epoll (with changelist)")) { - setenv("EVENT_NOEPOLL", "1", 1); - ignoreenvname = "epoll"; - } else { - methodname_to_envvar(defaultname, varbuf, sizeof(varbuf)); - setenv(varbuf, "1", 1); - ignoreenvname = defaultname; - } - - /* Use an empty cfg rather than NULL so a failure doesn't exit() */ - cfg = event_config_new(); - base = event_base_new_with_config(cfg); - event_config_free(cfg); - cfg = NULL; - if (n_methods == 1) { - tt_assert(!base); - } else { - tt_assert(base); - tt_str_op(defaultname, !=, event_base_get_method(base)); - event_base_free(base); - base = NULL; - } - - /* Can we disable looking at the environment with IGNORE_ENV ? */ - cfg = event_config_new(); - event_config_set_flag(cfg, EVENT_BASE_FLAG_IGNORE_ENV); - base = event_base_new_with_config(cfg); - tt_assert(base); - tt_str_op(ignoreenvname, ==, event_base_get_method(base)); -#else - tt_skip(); -#endif - -end: - if (base) - event_base_free(base); - if (cfg) - event_config_free(cfg); -} - -static void -read_called_once_cb(evutil_socket_t fd, short event, void *arg) -{ - tt_int_op(event, ==, EV_READ); - called += 1; -end: - ; -} - -static void -timeout_called_once_cb(evutil_socket_t fd, short event, void *arg) -{ - tt_int_op(event, ==, EV_TIMEOUT); - called += 100; -end: - ; -} - -static void -immediate_called_twice_cb(evutil_socket_t fd, short event, void *arg) -{ - tt_int_op(event, ==, EV_TIMEOUT); - called += 1000; -end: - ; -} - -static void -test_event_once(void *ptr) -{ - struct basic_test_data *data = ptr; - struct timeval tv; - int r; - - tv.tv_sec = 0; - tv.tv_usec = 50*1000; - called = 0; - r = event_base_once(data->base, data->pair[0], EV_READ, - read_called_once_cb, NULL, NULL); - tt_int_op(r, ==, 0); - r = event_base_once(data->base, -1, EV_TIMEOUT, - timeout_called_once_cb, NULL, &tv); - tt_int_op(r, ==, 0); - r = event_base_once(data->base, -1, 0, NULL, NULL, NULL); - tt_int_op(r, <, 0); - r = event_base_once(data->base, -1, EV_TIMEOUT, - immediate_called_twice_cb, NULL, NULL); - tt_int_op(r, ==, 0); - tv.tv_sec = 0; - tv.tv_usec = 0; - r = event_base_once(data->base, -1, EV_TIMEOUT, - immediate_called_twice_cb, NULL, &tv); - tt_int_op(r, ==, 0); - - if (write(data->pair[1], TEST1, strlen(TEST1)+1) < 0) { - tt_fail_perror("write"); - } - - shutdown(data->pair[1], SHUT_WR); - - event_base_dispatch(data->base); - - tt_int_op(called, ==, 2101); -end: - ; -} - -static void -test_event_once_never(void *ptr) -{ - struct basic_test_data *data = ptr; - struct timeval tv; - - /* Have one trigger in 10 seconds (don't worry, because) */ - tv.tv_sec = 10; - tv.tv_usec = 0; - called = 0; - event_base_once(data->base, -1, EV_TIMEOUT, - timeout_called_once_cb, NULL, &tv); - - /* But shut down the base in 75 msec. */ - tv.tv_sec = 0; - tv.tv_usec = 75*1000; - event_base_loopexit(data->base, &tv); - - event_base_dispatch(data->base); - - tt_int_op(called, ==, 0); -end: - ; -} - -static void -test_event_pending(void *ptr) -{ - struct basic_test_data *data = ptr; - struct event *r=NULL, *w=NULL, *t=NULL; - struct timeval tv, now, tv2; - - tv.tv_sec = 0; - tv.tv_usec = 500 * 1000; - r = event_new(data->base, data->pair[0], EV_READ, simple_read_cb, - NULL); - w = event_new(data->base, data->pair[1], EV_WRITE, simple_write_cb, - NULL); - t = evtimer_new(data->base, timeout_cb, NULL); - - tt_assert(r); - tt_assert(w); - tt_assert(t); - - evutil_gettimeofday(&now, NULL); - event_add(r, NULL); - event_add(t, &tv); - - tt_assert( event_pending(r, EV_READ, NULL)); - tt_assert(!event_pending(w, EV_WRITE, NULL)); - tt_assert(!event_pending(r, EV_WRITE, NULL)); - tt_assert( event_pending(r, EV_READ|EV_WRITE, NULL)); - tt_assert(!event_pending(r, EV_TIMEOUT, NULL)); - tt_assert( event_pending(t, EV_TIMEOUT, NULL)); - tt_assert( event_pending(t, EV_TIMEOUT, &tv2)); - - tt_assert(evutil_timercmp(&tv2, &now, >)); - - test_timeval_diff_eq(&now, &tv2, 500); - -end: - if (r) { - event_del(r); - event_free(r); - } - if (w) { - event_del(w); - event_free(w); - } - if (t) { - event_del(t); - event_free(t); - } -} - -#ifndef _WIN32 -/* You can't do this test on windows, since dup2 doesn't work on sockets */ - -static void -dfd_cb(evutil_socket_t fd, short e, void *data) -{ - *(int*)data = (int)e; -} - -/* Regression test for our workaround for a fun epoll/linux related bug - * where fd2 = dup(fd1); add(fd2); close(fd2); dup2(fd1,fd2); add(fd2) - * will get you an EEXIST */ -static void -test_dup_fd(void *arg) -{ - struct basic_test_data *data = arg; - struct event_base *base = data->base; - struct event *ev1=NULL, *ev2=NULL; - int fd, dfd=-1; - int ev1_got, ev2_got; - - tt_int_op(write(data->pair[0], "Hello world", - strlen("Hello world")), >, 0); - fd = data->pair[1]; - - dfd = dup(fd); - tt_int_op(dfd, >=, 0); - - ev1 = event_new(base, fd, EV_READ|EV_PERSIST, dfd_cb, &ev1_got); - ev2 = event_new(base, dfd, EV_READ|EV_PERSIST, dfd_cb, &ev2_got); - ev1_got = ev2_got = 0; - event_add(ev1, NULL); - event_add(ev2, NULL); - event_base_loop(base, EVLOOP_ONCE); - tt_int_op(ev1_got, ==, EV_READ); - tt_int_op(ev2_got, ==, EV_READ); - - /* Now close and delete dfd then dispatch. We need to do the - * dispatch here so that when we add it later, we think there - * was an intermediate delete. */ - close(dfd); - event_del(ev2); - ev1_got = ev2_got = 0; - event_base_loop(base, EVLOOP_ONCE); - tt_want_int_op(ev1_got, ==, EV_READ); - tt_int_op(ev2_got, ==, 0); - - /* Re-duplicate the fd. We need to get the same duplicated - * value that we closed to provoke the epoll quirk. Also, we - * need to change the events to write, or else the old lingering - * read event will make the test pass whether the change was - * successful or not. */ - tt_int_op(dup2(fd, dfd), ==, dfd); - event_free(ev2); - ev2 = event_new(base, dfd, EV_WRITE|EV_PERSIST, dfd_cb, &ev2_got); - event_add(ev2, NULL); - ev1_got = ev2_got = 0; - event_base_loop(base, EVLOOP_ONCE); - tt_want_int_op(ev1_got, ==, EV_READ); - tt_int_op(ev2_got, ==, EV_WRITE); - -end: - if (ev1) - event_free(ev1); - if (ev2) - event_free(ev2); - if (dfd >= 0) - close(dfd); -} -#endif - -#ifdef EVENT__DISABLE_MM_REPLACEMENT -static void -test_mm_functions(void *arg) -{ - tinytest_set_test_skipped_(); -} -#else -static int -check_dummy_mem_ok(void *mem_) -{ - char *mem = mem_; - mem -= 16; - return !memcmp(mem, "{[]}", 16); -} - -static void * -dummy_malloc(size_t len) -{ - char *mem = malloc(len+16); - memcpy(mem, "{[]}", 16); - return mem+16; -} - -static void * -dummy_realloc(void *mem_, size_t len) -{ - char *mem = mem_; - if (!mem) - return dummy_malloc(len); - tt_want(check_dummy_mem_ok(mem_)); - mem -= 16; - mem = realloc(mem, len+16); - return mem+16; -} - -static void -dummy_free(void *mem_) -{ - char *mem = mem_; - tt_want(check_dummy_mem_ok(mem_)); - mem -= 16; - free(mem); -} - -static void -test_mm_functions(void *arg) -{ - struct event_base *b = NULL; - struct event_config *cfg = NULL; - event_set_mem_functions(dummy_malloc, dummy_realloc, dummy_free); - cfg = event_config_new(); - event_config_avoid_method(cfg, "Nonesuch"); - b = event_base_new_with_config(cfg); - tt_assert(b); - tt_assert(check_dummy_mem_ok(b)); -end: - if (cfg) - event_config_free(cfg); - if (b) - event_base_free(b); -} -#endif - -static void -many_event_cb(evutil_socket_t fd, short event, void *arg) -{ - int *calledp = arg; - *calledp += 1; -} - -static void -test_many_events(void *arg) -{ - /* Try 70 events that should all be ready at once. This will - * exercise the "resize" code on most of the backends, and will make - * sure that we can get past the 64-handle limit of some windows - * functions. */ -#define MANY 70 - - struct basic_test_data *data = arg; - struct event_base *base = data->base; - int one_at_a_time = data->setup_data != NULL; - evutil_socket_t sock[MANY]; - struct event *ev[MANY]; - int called[MANY]; - int i; - int loopflags = EVLOOP_NONBLOCK, evflags=0; - if (one_at_a_time) { - loopflags |= EVLOOP_ONCE; - evflags = EV_PERSIST; - } - - memset(sock, 0xff, sizeof(sock)); - memset(ev, 0, sizeof(ev)); - memset(called, 0, sizeof(called)); - - for (i = 0; i < MANY; ++i) { - /* We need an event that will hit the backend, and that will - * be ready immediately. "Send a datagram" is an easy - * instance of that. */ - sock[i] = socket(AF_INET, SOCK_DGRAM, 0); - tt_assert(sock[i] >= 0); - called[i] = 0; - ev[i] = event_new(base, sock[i], EV_WRITE|evflags, - many_event_cb, &called[i]); - event_add(ev[i], NULL); - if (one_at_a_time) - event_base_loop(base, EVLOOP_NONBLOCK|EVLOOP_ONCE); - } - - event_base_loop(base, loopflags); - - for (i = 0; i < MANY; ++i) { - if (one_at_a_time) - tt_int_op(called[i], ==, MANY - i + 1); - else - tt_int_op(called[i], ==, 1); - } - -end: - for (i = 0; i < MANY; ++i) { - if (ev[i]) - event_free(ev[i]); - if (sock[i] >= 0) - evutil_closesocket(sock[i]); - } -#undef MANY -} - -static void -test_struct_event_size(void *arg) -{ - tt_int_op(event_get_struct_event_size(), <=, sizeof(struct event)); -end: - ; -} - -static void -test_get_assignment(void *arg) -{ - struct basic_test_data *data = arg; - struct event_base *base = data->base; - struct event *ev1 = NULL; - const char *str = "foo"; - - struct event_base *b; - evutil_socket_t s; - short what; - event_callback_fn cb; - void *cb_arg; - - ev1 = event_new(base, data->pair[1], EV_READ, dummy_read_cb, (void*)str); - event_get_assignment(ev1, &b, &s, &what, &cb, &cb_arg); - - tt_ptr_op(b, ==, base); - tt_int_op(s, ==, data->pair[1]); - tt_int_op(what, ==, EV_READ); - tt_ptr_op(cb, ==, dummy_read_cb); - tt_ptr_op(cb_arg, ==, str); - - /* Now make sure this doesn't crash. */ - event_get_assignment(ev1, NULL, NULL, NULL, NULL, NULL); - -end: - if (ev1) - event_free(ev1); -} - -struct foreach_helper { - int count; - const struct event *ev; -}; - -static int -foreach_count_cb(const struct event_base *base, const struct event *ev, void *arg) -{ - struct foreach_helper *h = event_get_callback_arg(ev); - struct timeval *tv = arg; - if (event_get_callback(ev) != timeout_cb) - return 0; - tt_ptr_op(event_get_base(ev), ==, base); - tt_int_op(tv->tv_sec, ==, 10); - h->ev = ev; - h->count++; - return 0; -end: - return -1; -} - -static int -foreach_find_cb(const struct event_base *base, const struct event *ev, void *arg) -{ - const struct event **ev_out = arg; - struct foreach_helper *h = event_get_callback_arg(ev); - if (event_get_callback(ev) != timeout_cb) - return 0; - if (h->count == 99) { - *ev_out = ev; - return 101; - } - return 0; -} - -static void -test_event_foreach(void *arg) -{ - struct basic_test_data *data = arg; - struct event_base *base = data->base; - struct event *ev[5]; - struct foreach_helper visited[5]; - int i; - struct timeval ten_sec = {10,0}; - const struct event *ev_found = NULL; - - for (i = 0; i < 5; ++i) { - visited[i].count = 0; - visited[i].ev = NULL; - ev[i] = event_new(base, -1, 0, timeout_cb, &visited[i]); - } - - tt_int_op(-1, ==, event_base_foreach_event(NULL, foreach_count_cb, NULL)); - tt_int_op(-1, ==, event_base_foreach_event(base, NULL, NULL)); - - event_add(ev[0], &ten_sec); - event_add(ev[1], &ten_sec); - event_active(ev[1], EV_TIMEOUT, 1); - event_active(ev[2], EV_TIMEOUT, 1); - event_add(ev[3], &ten_sec); - /* Don't touch ev[4]. */ - - tt_int_op(0, ==, event_base_foreach_event(base, foreach_count_cb, - &ten_sec)); - tt_int_op(1, ==, visited[0].count); - tt_int_op(1, ==, visited[1].count); - tt_int_op(1, ==, visited[2].count); - tt_int_op(1, ==, visited[3].count); - tt_ptr_op(ev[0], ==, visited[0].ev); - tt_ptr_op(ev[1], ==, visited[1].ev); - tt_ptr_op(ev[2], ==, visited[2].ev); - tt_ptr_op(ev[3], ==, visited[3].ev); - - visited[2].count = 99; - tt_int_op(101, ==, event_base_foreach_event(base, foreach_find_cb, - &ev_found)); - tt_ptr_op(ev_found, ==, ev[2]); - -end: - for (i=0; i<5; ++i) { - event_free(ev[i]); - } -} - -static struct event_base *cached_time_base = NULL; -static int cached_time_reset = 0; -static int cached_time_sleep = 0; -static void -cache_time_cb(evutil_socket_t fd, short what, void *arg) -{ - struct timeval *tv = arg; - tt_int_op(0, ==, event_base_gettimeofday_cached(cached_time_base, tv)); - if (cached_time_sleep) { - struct timeval delay = { 0, 30*1000 }; - evutil_usleep_(&delay); - } - if (cached_time_reset) { - event_base_update_cache_time(cached_time_base); - } -end: - ; -} - -static void -test_gettimeofday_cached(void *arg) -{ - struct basic_test_data *data = arg; - struct event_config *cfg = NULL; - struct event_base *base = NULL; - struct timeval tv1, tv2, tv3, now; - struct event *ev1=NULL, *ev2=NULL, *ev3=NULL; - int cached_time_disable = strstr(data->setup_data, "disable") != NULL; - - cfg = event_config_new(); - if (cached_time_disable) { - event_config_set_flag(cfg, EVENT_BASE_FLAG_NO_CACHE_TIME); - } - cached_time_base = base = event_base_new_with_config(cfg); - tt_assert(base); - - /* Try gettimeofday_cached outside of an event loop. */ - evutil_gettimeofday(&now, NULL); - tt_int_op(0, ==, event_base_gettimeofday_cached(NULL, &tv1)); - tt_int_op(0, ==, event_base_gettimeofday_cached(base, &tv2)); - tt_int_op(timeval_msec_diff(&tv1, &tv2), <, 10); - tt_int_op(timeval_msec_diff(&tv1, &now), <, 10); - - cached_time_reset = strstr(data->setup_data, "reset") != NULL; - cached_time_sleep = strstr(data->setup_data, "sleep") != NULL; - - ev1 = event_new(base, -1, 0, cache_time_cb, &tv1); - ev2 = event_new(base, -1, 0, cache_time_cb, &tv2); - ev3 = event_new(base, -1, 0, cache_time_cb, &tv3); - - event_active(ev1, EV_TIMEOUT, 1); - event_active(ev2, EV_TIMEOUT, 1); - event_active(ev3, EV_TIMEOUT, 1); - - event_base_dispatch(base); - - if (cached_time_reset && cached_time_sleep) { - tt_int_op(labs(timeval_msec_diff(&tv1,&tv2)), >, 10); - tt_int_op(labs(timeval_msec_diff(&tv2,&tv3)), >, 10); - } else if (cached_time_disable && cached_time_sleep) { - tt_int_op(labs(timeval_msec_diff(&tv1,&tv2)), >, 10); - tt_int_op(labs(timeval_msec_diff(&tv2,&tv3)), >, 10); - } else if (! cached_time_disable) { - tt_assert(evutil_timercmp(&tv1, &tv2, ==)); - tt_assert(evutil_timercmp(&tv2, &tv3, ==)); - } - -end: - if (ev1) - event_free(ev1); - if (ev2) - event_free(ev2); - if (ev3) - event_free(ev3); - if (base) - event_base_free(base); - if (cfg) - event_config_free(cfg); -} - -static void -tabf_cb(evutil_socket_t fd, short what, void *arg) -{ - int *ptr = arg; - *ptr = what; - *ptr += 0x10000; -} - -static void -test_active_by_fd(void *arg) -{ - struct basic_test_data *data = arg; - struct event_base *base = data->base; - struct event *ev1 = NULL, *ev2 = NULL, *ev3 = NULL, *ev4 = NULL; - int e1,e2,e3,e4; -#ifndef _WIN32 - struct event *evsig = NULL; - int es; -#endif - struct timeval tenmin = { 600, 0 }; - - /* Ensure no crash on nonexistent FD. */ - event_base_active_by_fd(base, 1000, EV_READ); - - /* Ensure no crash on bogus FD. */ - event_base_active_by_fd(base, -1, EV_READ); - - /* Ensure no crash on nonexistent/bogus signal. */ - event_base_active_by_signal(base, 1000); - event_base_active_by_signal(base, -1); - - event_base_assert_ok_(base); - - e1 = e2 = e3 = e4 = 0; - ev1 = event_new(base, data->pair[0], EV_READ, tabf_cb, &e1); - ev2 = event_new(base, data->pair[0], EV_WRITE, tabf_cb, &e2); - ev3 = event_new(base, data->pair[1], EV_READ, tabf_cb, &e3); - ev4 = event_new(base, data->pair[1], EV_READ, tabf_cb, &e4); - tt_assert(ev1); - tt_assert(ev2); - tt_assert(ev3); - tt_assert(ev4); -#ifndef _WIN32 - evsig = event_new(base, SIGHUP, EV_SIGNAL, tabf_cb, &es); - tt_assert(evsig); - event_add(evsig, &tenmin); -#endif - - event_add(ev1, &tenmin); - event_add(ev2, NULL); - event_add(ev3, NULL); - event_add(ev4, &tenmin); - - - event_base_assert_ok_(base); - - /* Trigger 2, 3, 4 */ - event_base_active_by_fd(base, data->pair[0], EV_WRITE); - event_base_active_by_fd(base, data->pair[1], EV_READ); -#ifndef _WIN32 - event_base_active_by_signal(base, SIGHUP); -#endif - - event_base_assert_ok_(base); - - event_base_loop(base, EVLOOP_ONCE); - - tt_int_op(e1, ==, 0); - tt_int_op(e2, ==, EV_WRITE | 0x10000); - tt_int_op(e3, ==, EV_READ | 0x10000); - /* Mask out EV_WRITE here, since it could be genuinely writeable. */ - tt_int_op((e4 & ~EV_WRITE), ==, EV_READ | 0x10000); -#ifndef _WIN32 - tt_int_op(es, ==, EV_SIGNAL | 0x10000); -#endif - -end: - if (ev1) - event_free(ev1); - if (ev2) - event_free(ev2); - if (ev3) - event_free(ev3); - if (ev4) - event_free(ev4); -#ifndef _WIN32 - if (evsig) - event_free(evsig); -#endif -} - -struct testcase_t main_testcases[] = { - /* Some converted-over tests */ - { "methods", test_methods, TT_FORK, NULL, NULL }, - { "version", test_version, 0, NULL, NULL }, - BASIC(base_features, TT_FORK|TT_NO_LOGS), - { "base_environ", test_base_environ, TT_FORK, NULL, NULL }, - - BASIC(event_base_new, TT_FORK|TT_NEED_SOCKETPAIR), - BASIC(free_active_base, TT_FORK|TT_NEED_SOCKETPAIR), - - BASIC(manipulate_active_events, TT_FORK|TT_NEED_BASE), - BASIC(event_new_selfarg, TT_FORK|TT_NEED_BASE), - BASIC(event_assign_selfarg, TT_FORK|TT_NEED_BASE), - BASIC(event_base_get_num_events, TT_FORK|TT_NEED_BASE), - BASIC(event_base_get_max_events, TT_FORK|TT_NEED_BASE), - - BASIC(bad_assign, TT_FORK|TT_NEED_BASE|TT_NO_LOGS), - BASIC(bad_reentrant, TT_FORK|TT_NEED_BASE|TT_NO_LOGS), - BASIC(active_later, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR), - BASIC(event_remove_timeout, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR), - - /* These are still using the old API */ - LEGACY(persistent_timeout, TT_FORK|TT_NEED_BASE), - { "persistent_timeout_jump", test_persistent_timeout_jump, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, - { "persistent_active_timeout", test_persistent_active_timeout, - TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, - LEGACY(priorities, TT_FORK|TT_NEED_BASE), - BASIC(priority_active_inversion, TT_FORK|TT_NEED_BASE), - { "common_timeout", test_common_timeout, TT_FORK|TT_NEED_BASE, - &basic_setup, NULL }, - - /* These legacy tests may not all need all of these flags. */ - LEGACY(simpleread, TT_ISOLATED), - LEGACY(simpleread_multiple, TT_ISOLATED), - LEGACY(simplewrite, TT_ISOLATED), - { "simpleclose", test_simpleclose, TT_FORK, &basic_setup, - NULL }, - LEGACY(multiple, TT_ISOLATED), - LEGACY(persistent, TT_ISOLATED), - LEGACY(combined, TT_ISOLATED), - LEGACY(simpletimeout, TT_ISOLATED), - LEGACY(loopbreak, TT_ISOLATED), - LEGACY(loopexit, TT_ISOLATED), - LEGACY(loopexit_multiple, TT_ISOLATED), - LEGACY(nonpersist_readd, TT_ISOLATED), - LEGACY(multiple_events_for_same_fd, TT_ISOLATED), - LEGACY(want_only_once, TT_ISOLATED), - { "event_once", test_event_once, TT_ISOLATED, &basic_setup, NULL }, - { "event_once_never", test_event_once_never, TT_ISOLATED, &basic_setup, NULL }, - { "event_pending", test_event_pending, TT_ISOLATED, &basic_setup, - NULL }, -#ifndef _WIN32 - { "dup_fd", test_dup_fd, TT_ISOLATED, &basic_setup, NULL }, -#endif - { "mm_functions", test_mm_functions, TT_FORK, NULL, NULL }, - { "many_events", test_many_events, TT_ISOLATED, &basic_setup, NULL }, - { "many_events_slow_add", test_many_events, TT_ISOLATED, &basic_setup, (void*)1 }, - - { "struct_event_size", test_struct_event_size, 0, NULL, NULL }, - BASIC(get_assignment, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR), - - BASIC(event_foreach, TT_FORK|TT_NEED_BASE), - { "gettimeofday_cached", test_gettimeofday_cached, TT_FORK, &basic_setup, (void*)"" }, - { "gettimeofday_cached_sleep", test_gettimeofday_cached, TT_FORK, &basic_setup, (void*)"sleep" }, - { "gettimeofday_cached_reset", test_gettimeofday_cached, TT_FORK, &basic_setup, (void*)"sleep reset" }, - { "gettimeofday_cached_disabled", test_gettimeofday_cached, TT_FORK, &basic_setup, (void*)"sleep disable" }, - { "gettimeofday_cached_disabled_nosleep", test_gettimeofday_cached, TT_FORK, &basic_setup, (void*)"disable" }, - - BASIC(active_by_fd, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR), - -#ifndef _WIN32 - LEGACY(fork, TT_ISOLATED), -#endif -#ifdef EVENT__HAVE_PTHREADS - /** TODO: support win32 */ - LEGACY(del_wait, TT_ISOLATED|TT_NEED_THREADS), -#endif - - END_OF_TESTCASES -}; - -struct testcase_t evtag_testcases[] = { - { "int", evtag_int_test, TT_FORK, NULL, NULL }, - { "fuzz", evtag_fuzz, TT_FORK, NULL, NULL }, - { "encoding", evtag_tag_encoding, TT_FORK, NULL, NULL }, - { "peek", evtag_test_peek, 0, NULL, NULL }, - - END_OF_TESTCASES -}; - -struct testcase_t signal_testcases[] = { -#ifndef _WIN32 - LEGACY(simplestsignal, TT_ISOLATED), - LEGACY(simplesignal, TT_ISOLATED), - LEGACY(multiplesignal, TT_ISOLATED), - LEGACY(immediatesignal, TT_ISOLATED), - LEGACY(signal_dealloc, TT_ISOLATED), - LEGACY(signal_pipeloss, TT_ISOLATED), - LEGACY(signal_switchbase, TT_ISOLATED|TT_NO_LOGS), - LEGACY(signal_restore, TT_ISOLATED), - LEGACY(signal_assert, TT_ISOLATED), - LEGACY(signal_while_processing, TT_ISOLATED), -#endif - END_OF_TESTCASES -}; - diff --git a/libs/libevent/docs/test/regress.h b/libs/libevent/docs/test/regress.h deleted file mode 100644 index de1aed3089..0000000000 --- a/libs/libevent/docs/test/regress.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2000-2007 Niels Provos - * Copyright (c) 2007-2012 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_INCLUDED_ -#define REGRESS_H_INCLUDED_ - -#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 finalize_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[]; - -extern struct evutil_weakrand_state test_weakrand_state; - -#define test_weakrand() (evutil_weakrand_(&test_weakrand_state)) - -void regress_threads(void *); -void test_bufferevent_zlib(void *); - -/* Helpers to wrap old testcases */ -extern evutil_socket_t pair[2]; -extern int test_ok; -extern int called; -extern struct event_base *global_base; -extern int in_legacy_test_wrapper; - -int regress_make_tmpfile(const void *data, size_t datalen, char **filename_out); - -struct basic_test_data { - struct event_base *base; - evutil_socket_t 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); - -extern int libevent_tests_running_in_debug_mode; - -/* 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(labs(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); - -#ifndef _WIN32 -pid_t regress_fork(void); -#endif - -#ifdef EVENT__HAVE_OPENSSL -#include -EVP_PKEY *ssl_getkey(void); -X509 *ssl_getcert(void); -SSL_CTX *get_ssl_ctx(void); -void init_ssl(void); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* REGRESS_H_INCLUDED_ */ diff --git a/libs/libevent/docs/test/regress.rpc b/libs/libevent/docs/test/regress.rpc deleted file mode 100644 index 0ee904e913..0000000000 --- a/libs/libevent/docs/test/regress.rpc +++ /dev/null @@ -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; -} diff --git a/libs/libevent/docs/test/regress_buffer.c b/libs/libevent/docs/test/regress_buffer.c deleted file mode 100644 index 957e59f178..0000000000 --- a/libs/libevent/docs/test/regress_buffer.c +++ /dev/null @@ -1,2281 +0,0 @@ -/* - * Copyright (c) 2003-2007 Niels Provos - * Copyright (c) 2007-2012 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 "util-internal.h" - -#ifdef _WIN32 -#include -#include -#endif - -#include "event2/event-config.h" - -#include -#include -#ifdef EVENT__HAVE_SYS_TIME_H -#include -#endif -#include -#ifndef _WIN32 -#include -#include -#include -#include -#include -#endif -#include -#include -#include -#include -#include - -#include "event2/event.h" -#include "event2/buffer.h" -#include "event2/buffer_compat.h" -#include "event2/util.h" - -#include "defer-internal.h" -#include "evbuffer-internal.h" -#include "log-internal.h" - -#include "regress.h" - -/* Validates that an evbuffer is good. Returns false if it isn't, true if it - * is*/ -static int -evbuffer_validate_(struct evbuffer *buf) -{ - struct evbuffer_chain *chain; - size_t sum = 0; - int found_last_with_datap = 0; - - if (buf->first == NULL) { - tt_assert(buf->last == NULL); - tt_assert(buf->total_len == 0); - } - - chain = buf->first; - - tt_assert(buf->last_with_datap); - if (buf->last_with_datap == &buf->first) - found_last_with_datap = 1; - - while (chain != NULL) { - if (&chain->next == buf->last_with_datap) - found_last_with_datap = 1; - sum += chain->off; - if (chain->next == NULL) { - tt_assert(buf->last == chain); - } - tt_assert(chain->buffer_len >= chain->misalign + chain->off); - chain = chain->next; - } - - if (buf->first) - tt_assert(*buf->last_with_datap); - - if (*buf->last_with_datap) { - chain = *buf->last_with_datap; - if (chain->off == 0 || buf->total_len == 0) { - tt_assert(chain->off == 0) - tt_assert(chain == buf->first); - tt_assert(buf->total_len == 0); - } - chain = chain->next; - while (chain != NULL) { - tt_assert(chain->off == 0); - chain = chain->next; - } - } else { - tt_assert(buf->last_with_datap == &buf->first); - } - tt_assert(found_last_with_datap); - - tt_assert(sum == buf->total_len); - return 1; - end: - return 0; -} - -static void -evbuffer_get_waste(struct evbuffer *buf, size_t *allocatedp, size_t *wastedp, size_t *usedp) -{ - struct evbuffer_chain *chain; - size_t a, w, u; - int n = 0; - u = a = w = 0; - - chain = buf->first; - /* skip empty at start */ - while (chain && chain->off==0) { - ++n; - a += chain->buffer_len; - chain = chain->next; - } - /* first nonempty chain: stuff at the end only is wasted. */ - if (chain) { - ++n; - a += chain->buffer_len; - u += chain->off; - if (chain->next && chain->next->off) - w += (size_t)(chain->buffer_len - (chain->misalign + chain->off)); - chain = chain->next; - } - /* subsequent nonempty chains */ - while (chain && chain->off) { - ++n; - a += chain->buffer_len; - w += (size_t)chain->misalign; - u += chain->off; - if (chain->next && chain->next->off) - w += (size_t) (chain->buffer_len - (chain->misalign + chain->off)); - chain = chain->next; - } - /* subsequent empty chains */ - while (chain) { - ++n; - a += chain->buffer_len; - } - *allocatedp = a; - *wastedp = w; - *usedp = u; -} - -#define evbuffer_validate(buf) \ - TT_STMT_BEGIN if (!evbuffer_validate_(buf)) TT_DIE(("Buffer format invalid")); TT_STMT_END - -static void -test_evbuffer(void *ptr) -{ - static char buffer[512], *tmp; - struct evbuffer *evb = evbuffer_new(); - struct evbuffer *evb_two = evbuffer_new(); - size_t sz_tmp; - int i; - - evbuffer_validate(evb); - evbuffer_add_printf(evb, "%s/%d", "hello", 1); - evbuffer_validate(evb); - - tt_assert(evbuffer_get_length(evb) == 7); - tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "hello/1", 1)); - - evbuffer_add_buffer(evb, evb_two); - evbuffer_validate(evb); - - evbuffer_drain(evb, strlen("hello/")); - evbuffer_validate(evb); - tt_assert(evbuffer_get_length(evb) == 1); - tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1", 1)); - - evbuffer_add_printf(evb_two, "%s", "/hello"); - evbuffer_validate(evb); - evbuffer_add_buffer(evb, evb_two); - evbuffer_validate(evb); - - tt_assert(evbuffer_get_length(evb_two) == 0); - tt_assert(evbuffer_get_length(evb) == 7); - tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1/hello", 7)); - - memset(buffer, 0, sizeof(buffer)); - evbuffer_add(evb, buffer, sizeof(buffer)); - evbuffer_validate(evb); - tt_assert(evbuffer_get_length(evb) == 7 + 512); - - tmp = (char *)evbuffer_pullup(evb, 7 + 512); - tt_assert(tmp); - tt_assert(!strncmp(tmp, "1/hello", 7)); - tt_assert(!memcmp(tmp + 7, buffer, sizeof(buffer))); - evbuffer_validate(evb); - - evbuffer_prepend(evb, "something", 9); - evbuffer_validate(evb); - evbuffer_prepend(evb, "else", 4); - evbuffer_validate(evb); - - tmp = (char *)evbuffer_pullup(evb, 4 + 9 + 7); - tt_assert(!strncmp(tmp, "elsesomething1/hello", 4 + 9 + 7)); - evbuffer_validate(evb); - - evbuffer_drain(evb, -1); - evbuffer_validate(evb); - evbuffer_drain(evb_two, -1); - evbuffer_validate(evb); - - for (i = 0; i < 3; ++i) { - evbuffer_add(evb_two, buffer, sizeof(buffer)); - evbuffer_validate(evb_two); - evbuffer_add_buffer(evb, evb_two); - evbuffer_validate(evb); - evbuffer_validate(evb_two); - } - - tt_assert(evbuffer_get_length(evb_two) == 0); - tt_assert(evbuffer_get_length(evb) == i * sizeof(buffer)); - - /* test remove buffer */ - sz_tmp = (size_t)(sizeof(buffer)*2.5); - evbuffer_remove_buffer(evb, evb_two, sz_tmp); - tt_assert(evbuffer_get_length(evb_two) == sz_tmp); - tt_assert(evbuffer_get_length(evb) == sizeof(buffer) / 2); - evbuffer_validate(evb); - - if (memcmp(evbuffer_pullup( - evb, -1), buffer, sizeof(buffer) / 2) != 0 || - memcmp(evbuffer_pullup( - evb_two, -1), buffer, sizeof(buffer)) != 0) - tt_abort_msg("Pullup did not preserve content"); - - evbuffer_validate(evb); - - - /* testing one-vector reserve and commit */ - { - struct evbuffer_iovec v[1]; - char *buf; - int i, j, r; - - for (i = 0; i < 3; ++i) { - r = evbuffer_reserve_space(evb, 10000, v, 1); - tt_int_op(r, ==, 1); - tt_assert(v[0].iov_len >= 10000); - tt_assert(v[0].iov_base != NULL); - - evbuffer_validate(evb); - buf = v[0].iov_base; - for (j = 0; j < 10000; ++j) { - buf[j] = j; - } - evbuffer_validate(evb); - - tt_int_op(evbuffer_commit_space(evb, v, 1), ==, 0); - evbuffer_validate(evb); - - tt_assert(evbuffer_get_length(evb) >= 10000); - - evbuffer_drain(evb, j * 5000); - evbuffer_validate(evb); - } - } - - end: - evbuffer_free(evb); - evbuffer_free(evb_two); -} - -static void -no_cleanup(const void *data, size_t datalen, void *extra) -{ -} - -static void -test_evbuffer_remove_buffer_with_empty(void *ptr) -{ - struct evbuffer *src = evbuffer_new(); - struct evbuffer *dst = evbuffer_new(); - char buf[2]; - - evbuffer_validate(src); - evbuffer_validate(dst); - - /* setup the buffers */ - /* we need more data in src than we will move later */ - evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL); - evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL); - /* we need one buffer in dst and one empty buffer at the end */ - evbuffer_add(dst, buf, sizeof(buf)); - evbuffer_add_reference(dst, buf, 0, no_cleanup, NULL); - - evbuffer_validate(src); - evbuffer_validate(dst); - - /* move three bytes over */ - evbuffer_remove_buffer(src, dst, 3); - - evbuffer_validate(src); - evbuffer_validate(dst); - -end: - evbuffer_free(src); - evbuffer_free(dst); -} - -static void -test_evbuffer_reserve2(void *ptr) -{ - /* Test the two-vector cases of reserve/commit. */ - struct evbuffer *buf = evbuffer_new(); - int n, i; - struct evbuffer_iovec v[2]; - size_t remaining; - char *cp, *cp2; - - /* First chunk will necessarily be one chunk. Use 512 bytes of it.*/ - n = evbuffer_reserve_space(buf, 1024, v, 2); - tt_int_op(n, ==, 1); - tt_int_op(evbuffer_get_length(buf), ==, 0); - tt_assert(v[0].iov_base != NULL); - tt_int_op(v[0].iov_len, >=, 1024); - memset(v[0].iov_base, 'X', 512); - cp = v[0].iov_base; - remaining = v[0].iov_len - 512; - v[0].iov_len = 512; - evbuffer_validate(buf); - tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1)); - tt_int_op(evbuffer_get_length(buf), ==, 512); - evbuffer_validate(buf); - - /* Ask for another same-chunk request, in an existing chunk. Use 8 - * bytes of it. */ - n = evbuffer_reserve_space(buf, 32, v, 2); - tt_int_op(n, ==, 1); - tt_assert(cp + 512 == v[0].iov_base); - tt_int_op(remaining, ==, v[0].iov_len); - memset(v[0].iov_base, 'Y', 8); - v[0].iov_len = 8; - tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1)); - tt_int_op(evbuffer_get_length(buf), ==, 520); - remaining -= 8; - evbuffer_validate(buf); - - /* Now ask for a request that will be split. Use only one byte of it, - though. */ - n = evbuffer_reserve_space(buf, remaining+64, v, 2); - tt_int_op(n, ==, 2); - tt_assert(cp + 520 == v[0].iov_base); - tt_int_op(remaining, ==, v[0].iov_len); - tt_assert(v[1].iov_base); - tt_assert(v[1].iov_len >= 64); - cp2 = v[1].iov_base; - memset(v[0].iov_base, 'Z', 1); - v[0].iov_len = 1; - tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1)); - tt_int_op(evbuffer_get_length(buf), ==, 521); - remaining -= 1; - evbuffer_validate(buf); - - /* Now ask for a request that will be split. Use some of the first - * part and some of the second. */ - n = evbuffer_reserve_space(buf, remaining+64, v, 2); - evbuffer_validate(buf); - tt_int_op(n, ==, 2); - tt_assert(cp + 521 == v[0].iov_base); - tt_int_op(remaining, ==, v[0].iov_len); - tt_assert(v[1].iov_base == cp2); - tt_assert(v[1].iov_len >= 64); - memset(v[0].iov_base, 'W', 400); - v[0].iov_len = 400; - memset(v[1].iov_base, 'x', 60); - v[1].iov_len = 60; - tt_int_op(0, ==, evbuffer_commit_space(buf, v, 2)); - tt_int_op(evbuffer_get_length(buf), ==, 981); - evbuffer_validate(buf); - - /* Now peek to make sure stuff got made how we like. */ - memset(v,0,sizeof(v)); - n = evbuffer_peek(buf, -1, NULL, v, 2); - tt_int_op(n, ==, 2); - tt_int_op(v[0].iov_len, ==, 921); - tt_int_op(v[1].iov_len, ==, 60); - - cp = v[0].iov_base; - for (i=0; i<512; ++i) - tt_int_op(cp[i], ==, 'X'); - for (i=512; i<520; ++i) - tt_int_op(cp[i], ==, 'Y'); - for (i=520; i<521; ++i) - tt_int_op(cp[i], ==, 'Z'); - for (i=521; i<921; ++i) - tt_int_op(cp[i], ==, 'W'); - - cp = v[1].iov_base; - for (i=0; i<60; ++i) - tt_int_op(cp[i], ==, 'x'); - -end: - evbuffer_free(buf); -} - -static void -test_evbuffer_reserve_many(void *ptr) -{ - /* This is a glass-box test to handle expanding a buffer with more - * chunks and reallocating chunks as needed */ - struct evbuffer *buf = evbuffer_new(); - struct evbuffer_iovec v[8]; - int n; - size_t sz; - int add_data = ptr && !strcmp(ptr, "add"); - int fill_first = ptr && !strcmp(ptr, "fill"); - char *cp1, *cp2; - - /* When reserving the the first chunk, we just allocate it */ - n = evbuffer_reserve_space(buf, 128, v, 2); - evbuffer_validate(buf); - tt_int_op(n, ==, 1); - tt_assert(v[0].iov_len >= 128); - sz = v[0].iov_len; - cp1 = v[0].iov_base; - if (add_data) { - *(char*)v[0].iov_base = 'X'; - v[0].iov_len = 1; - n = evbuffer_commit_space(buf, v, 1); - tt_int_op(n, ==, 0); - } else if (fill_first) { - memset(v[0].iov_base, 'X', v[0].iov_len); - n = evbuffer_commit_space(buf, v, 1); - tt_int_op(n, ==, 0); - n = evbuffer_reserve_space(buf, 128, v, 2); - tt_int_op(n, ==, 1); - sz = v[0].iov_len; - tt_assert(v[0].iov_base != cp1); - cp1 = v[0].iov_base; - } - - /* Make another chunk get added. */ - n = evbuffer_reserve_space(buf, sz+128, v, 2); - evbuffer_validate(buf); - tt_int_op(n, ==, 2); - sz = v[0].iov_len + v[1].iov_len; - tt_int_op(sz, >=, v[0].iov_len+128); - if (add_data) { - tt_assert(v[0].iov_base == cp1 + 1); - } else { - tt_assert(v[0].iov_base == cp1); - } - cp1 = v[0].iov_base; - cp2 = v[1].iov_base; - - /* And a third chunk. */ - n = evbuffer_reserve_space(buf, sz+128, v, 3); - evbuffer_validate(buf); - tt_int_op(n, ==, 3); - tt_assert(cp1 == v[0].iov_base); - tt_assert(cp2 == v[1].iov_base); - sz = v[0].iov_len + v[1].iov_len + v[2].iov_len; - - /* Now force a reallocation by asking for more space in only 2 - * buffers. */ - n = evbuffer_reserve_space(buf, sz+128, v, 2); - evbuffer_validate(buf); - if (add_data) { - tt_int_op(n, ==, 2); - tt_assert(cp1 == v[0].iov_base); - } else { - tt_int_op(n, ==, 1); - } - -end: - evbuffer_free(buf); -} - -static void -test_evbuffer_expand(void *ptr) -{ - char data[4096]; - struct evbuffer *buf; - size_t a,w,u; - void *buffer; - - memset(data, 'X', sizeof(data)); - - /* Make sure that expand() works on an empty buffer */ - buf = evbuffer_new(); - tt_int_op(evbuffer_expand(buf, 20000), ==, 0); - evbuffer_validate(buf); - a=w=u=0; - evbuffer_get_waste(buf, &a,&w,&u); - tt_assert(w == 0); - tt_assert(u == 0); - tt_assert(a >= 20000); - tt_assert(buf->first); - tt_assert(buf->first == buf->last); - tt_assert(buf->first->off == 0); - tt_assert(buf->first->buffer_len >= 20000); - - /* Make sure that expand() works as a no-op when there's enough - * contiguous space already. */ - buffer = buf->first->buffer; - evbuffer_add(buf, data, 1024); - tt_int_op(evbuffer_expand(buf, 1024), ==, 0); - tt_assert(buf->first->buffer == buffer); - evbuffer_validate(buf); - evbuffer_free(buf); - - /* Make sure that expand() can work by moving misaligned data - * when it makes sense to do so. */ - buf = evbuffer_new(); - evbuffer_add(buf, data, 400); - { - int n = (int)(buf->first->buffer_len - buf->first->off - 1); - tt_assert(n < (int)sizeof(data)); - evbuffer_add(buf, data, n); - } - tt_assert(buf->first == buf->last); - tt_assert(buf->first->off == buf->first->buffer_len - 1); - evbuffer_drain(buf, buf->first->off - 1); - tt_assert(1 == evbuffer_get_length(buf)); - tt_assert(buf->first->misalign > 0); - tt_assert(buf->first->off == 1); - buffer = buf->first->buffer; - tt_assert(evbuffer_expand(buf, 40) == 0); - tt_assert(buf->first == buf->last); - tt_assert(buf->first->off == 1); - tt_assert(buf->first->buffer == buffer); - tt_assert(buf->first->misalign == 0); - evbuffer_validate(buf); - evbuffer_free(buf); - - /* add, expand, pull-up: This used to crash libevent. */ - buf = evbuffer_new(); - - evbuffer_add(buf, data, sizeof(data)); - evbuffer_add(buf, data, sizeof(data)); - evbuffer_add(buf, data, sizeof(data)); - - evbuffer_validate(buf); - evbuffer_expand(buf, 1024); - evbuffer_validate(buf); - evbuffer_pullup(buf, -1); - evbuffer_validate(buf); - -end: - evbuffer_free(buf); -} - - -static int reference_cb_called; -static void -reference_cb(const void *data, size_t len, void *extra) -{ - tt_str_op(data, ==, "this is what we add as read-only memory."); - tt_int_op(len, ==, strlen(data)); - tt_want(extra == (void *)0xdeadaffe); - ++reference_cb_called; -end: - ; -} - -static void -test_evbuffer_reference(void *ptr) -{ - struct evbuffer *src = evbuffer_new(); - struct evbuffer *dst = evbuffer_new(); - struct evbuffer_iovec v[1]; - const char *data = "this is what we add as read-only memory."; - reference_cb_called = 0; - - tt_assert(evbuffer_add_reference(src, data, strlen(data), - reference_cb, (void *)0xdeadaffe) != -1); - - evbuffer_reserve_space(dst, strlen(data), v, 1); - tt_assert(evbuffer_remove(src, v[0].iov_base, 10) != -1); - - evbuffer_validate(src); - evbuffer_validate(dst); - - /* make sure that we don't write data at the beginning */ - evbuffer_prepend(src, "aaaaa", 5); - evbuffer_validate(src); - evbuffer_drain(src, 5); - - tt_assert(evbuffer_remove(src, ((char*)(v[0].iov_base)) + 10, - strlen(data) - 10) != -1); - - v[0].iov_len = strlen(data); - - evbuffer_commit_space(dst, v, 1); - evbuffer_validate(src); - evbuffer_validate(dst); - - tt_int_op(reference_cb_called, ==, 1); - - tt_assert(!memcmp(evbuffer_pullup(dst, strlen(data)), - data, strlen(data))); - evbuffer_validate(dst); - - end: - evbuffer_free(dst); - evbuffer_free(src); -} - -static struct event_base *addfile_test_event_base = NULL; -static int addfile_test_done_writing = 0; -static int addfile_test_total_written = 0; -static int addfile_test_total_read = 0; - -static void -addfile_test_writecb(evutil_socket_t fd, short what, void *arg) -{ - struct evbuffer *b = arg; - int r; - evbuffer_validate(b); - while (evbuffer_get_length(b)) { - r = evbuffer_write(b, fd); - if (r > 0) { - addfile_test_total_written += r; - TT_BLATHER(("Wrote %d/%d bytes", r, addfile_test_total_written)); - } else { - int e = evutil_socket_geterror(fd); - if (EVUTIL_ERR_RW_RETRIABLE(e)) - return; - tt_fail_perror("write"); - event_base_loopexit(addfile_test_event_base,NULL); - } - evbuffer_validate(b); - } - addfile_test_done_writing = 1; - return; -end: - event_base_loopexit(addfile_test_event_base,NULL); -} - -static void -addfile_test_readcb(evutil_socket_t fd, short what, void *arg) -{ - struct evbuffer *b = arg; - int e, r = 0; - do { - r = evbuffer_read(b, fd, 1024); - if (r > 0) { - addfile_test_total_read += r; - TT_BLATHER(("Read %d/%d bytes", r, addfile_test_total_read)); - } - } while (r > 0); - if (r < 0) { - e = evutil_socket_geterror(fd); - if (! EVUTIL_ERR_RW_RETRIABLE(e)) { - tt_fail_perror("read"); - event_base_loopexit(addfile_test_event_base,NULL); - } - } - if (addfile_test_done_writing && - addfile_test_total_read >= addfile_test_total_written) { - event_base_loopexit(addfile_test_event_base,NULL); - } -} - -static void -test_evbuffer_add_file(void *ptr) -{ - struct basic_test_data *testdata = ptr; - const char *impl = testdata->setup_data; - struct evbuffer *src = evbuffer_new(), *dest = evbuffer_new(); - char *tmpfilename = NULL; - char *data = NULL; - const char *expect_data; - size_t datalen, expect_len; - const char *compare; - int fd = -1; - int want_ismapping = -1, want_cansendfile = -1; - unsigned flags = 0; - int use_segment = 1, use_bigfile = 0, map_from_offset = 0, - view_from_offset = 0; - struct evbuffer_file_segment *seg = NULL; - ev_off_t starting_offset = 0, mapping_len = -1; - ev_off_t segment_offset = 0, segment_len = -1; - struct event *rev=NULL, *wev=NULL; - struct event_base *base = testdata->base; - evutil_socket_t pair[2] = {-1, -1}; - struct evutil_weakrand_state seed = { 123456789U }; - - /* This test is highly parameterized based on substrings of its - * argument. The strings are: */ - tt_assert(impl); - if (strstr(impl, "nosegment")) { - /* If nosegment is set, use the older evbuffer_add_file - * interface */ - use_segment = 0; - } - if (strstr(impl, "bigfile")) { - /* If bigfile is set, use a 512K file. Else use a smaller - * one. */ - use_bigfile = 1; - } - if (strstr(impl, "map_offset")) { - /* If map_offset is set, we build the file segment starting - * from a point other than byte 0 and ending somewhere other - * than the last byte. Otherwise we map the whole thing */ - map_from_offset = 1; - } - if (strstr(impl, "offset_in_segment")) { - /* If offset_in_segment is set, we add a subsection of the - * file semgment starting from a point other than byte 0 of - * the segment. */ - view_from_offset = 1; - } - if (strstr(impl, "sendfile")) { - /* If sendfile is set, we try to use a sendfile/splice style - * backend. */ - flags = EVBUF_FS_DISABLE_MMAP; - want_cansendfile = 1; - want_ismapping = 0; - } else if (strstr(impl, "mmap")) { - /* If sendfile is set, we try to use a mmap/CreateFileMapping - * style backend. */ - flags = EVBUF_FS_DISABLE_SENDFILE; - want_ismapping = 1; - want_cansendfile = 0; - } else if (strstr(impl, "linear")) { - /* If linear is set, we try to use a read-the-whole-thing - * backend. */ - flags = EVBUF_FS_DISABLE_SENDFILE|EVBUF_FS_DISABLE_MMAP; - want_ismapping = 0; - want_cansendfile = 0; - } else if (strstr(impl, "default")) { - /* The caller doesn't care which backend we use. */ - ; - } else { - /* The caller must choose a backend. */ - TT_DIE(("Didn't recognize the implementation")); - } - - if (use_bigfile) { - unsigned int i; - datalen = 1024*512; - data = malloc(1024*512); - tt_assert(data); - for (i = 0; i < datalen; ++i) - data[i] = (char)evutil_weakrand_(&seed); - } else { - data = strdup("here is a relatively small string."); - tt_assert(data); - datalen = strlen(data); - } - - fd = regress_make_tmpfile(data, datalen, &tmpfilename); - - if (map_from_offset) { - starting_offset = datalen/4 + 1; - mapping_len = datalen / 2 - 1; - expect_data = data + starting_offset; - expect_len = mapping_len; - } else { - expect_data = data; - expect_len = datalen; - } - if (view_from_offset) { - tt_assert(use_segment); /* Can't do this with add_file*/ - segment_offset = expect_len / 3; - segment_len = expect_len / 2; - expect_data = expect_data + segment_offset; - expect_len = segment_len; - } - - if (use_segment) { - seg = evbuffer_file_segment_new(fd, starting_offset, - mapping_len, flags); - tt_assert(seg); - if (want_ismapping >= 0) { - if (seg->is_mapping != (unsigned)want_ismapping) - tt_skip(); - } - if (want_cansendfile >= 0) { - if (seg->can_sendfile != (unsigned)want_cansendfile) - tt_skip(); - } - } - - /* Say that it drains to a fd so that we can use sendfile. */ - evbuffer_set_flags(src, EVBUFFER_FLAG_DRAINS_TO_FD); - -#if defined(EVENT__HAVE_SENDFILE) && defined(__sun__) && defined(__svr4__) - /* We need to use a pair of AF_INET sockets, since Solaris - doesn't support sendfile() over AF_UNIX. */ - if (evutil_ersatz_socketpair_(AF_INET, SOCK_STREAM, 0, pair) == -1) - tt_abort_msg("ersatz_socketpair failed"); -#else - if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) - tt_abort_msg("socketpair failed"); -#endif - evutil_make_socket_nonblocking(pair[0]); - evutil_make_socket_nonblocking(pair[1]); - - tt_assert(fd != -1); - - if (use_segment) { - tt_assert(evbuffer_add_file_segment(src, seg, - segment_offset, segment_len)!=-1); - } else { - tt_assert(evbuffer_add_file(src, fd, starting_offset, - mapping_len) != -1); - } - - evbuffer_validate(src); - - addfile_test_event_base = base; - wev = event_new(base, pair[0], EV_WRITE|EV_PERSIST, - addfile_test_writecb, src); - rev = event_new(base, pair[1], EV_READ|EV_PERSIST, - addfile_test_readcb, dest); - - event_add(wev, NULL); - event_add(rev, NULL); - event_base_dispatch(base); - - evbuffer_validate(src); - evbuffer_validate(dest); - - tt_assert(addfile_test_done_writing); - tt_int_op(addfile_test_total_written, ==, expect_len); - tt_int_op(addfile_test_total_read, ==, expect_len); - - compare = (char *)evbuffer_pullup(dest, expect_len); - tt_assert(compare != NULL); - if (memcmp(compare, expect_data, expect_len)) { - tt_abort_msg("Data from add_file differs."); - } - - evbuffer_validate(dest); - end: - if (data) - free(data); - if (seg) - evbuffer_file_segment_free(seg); - if (src) - evbuffer_free(src); - if (dest) - evbuffer_free(dest); - if (pair[0] >= 0) - evutil_closesocket(pair[0]); - if (pair[1] >= 0) - evutil_closesocket(pair[1]); - if (wev) - event_free(wev); - if (rev) - event_free(rev); - if (tmpfilename) { - unlink(tmpfilename); - free(tmpfilename); - } -} - -static int file_segment_cleanup_cb_called_count = 0; -static struct evbuffer_file_segment const* file_segment_cleanup_cb_called_with = NULL; -static int file_segment_cleanup_cb_called_with_flags = 0; -static void* file_segment_cleanup_cb_called_with_arg = NULL; -static void -file_segment_cleanup_cp(struct evbuffer_file_segment const* seg, int flags, void* arg) -{ - ++file_segment_cleanup_cb_called_count; - file_segment_cleanup_cb_called_with = seg; - file_segment_cleanup_cb_called_with_flags = flags; - file_segment_cleanup_cb_called_with_arg = arg; -} - -static void -test_evbuffer_file_segment_add_cleanup_cb(void* ptr) -{ - char *tmpfilename = NULL; - int fd = -1; - struct evbuffer *evb = NULL; - struct evbuffer_file_segment *seg = NULL, *segptr; - char const* arg = "token"; - - fd = regress_make_tmpfile("file_segment_test_file", 22, &tmpfilename); - tt_int_op(fd, >=, 0); - - evb = evbuffer_new(); - tt_assert(evb); - - segptr = seg = evbuffer_file_segment_new(fd, 0, -1, 0); - tt_assert(seg); - - evbuffer_file_segment_add_cleanup_cb( - seg, &file_segment_cleanup_cp, (void*)arg); - - tt_assert(fd != -1); - - tt_assert(evbuffer_add_file_segment(evb, seg, 0, -1)!=-1); - - evbuffer_validate(evb); - - tt_int_op(file_segment_cleanup_cb_called_count, ==, 0); - evbuffer_file_segment_free(seg); - seg = NULL; /* Prevent double-free. */ - - tt_int_op(file_segment_cleanup_cb_called_count, ==, 0); - evbuffer_free(evb); - evb = NULL; /* pevent double-free */ - - tt_int_op(file_segment_cleanup_cb_called_count, ==, 1); - tt_assert(file_segment_cleanup_cb_called_with == segptr); - tt_assert(file_segment_cleanup_cb_called_with_flags == 0); - tt_assert(file_segment_cleanup_cb_called_with_arg == (void*)arg); - -end: - if (evb) - evbuffer_free(evb); - if (seg) - evbuffer_file_segment_free(seg); - if (tmpfilename) { - unlink(tmpfilename); - free(tmpfilename); - } -} - -#ifndef EVENT__DISABLE_MM_REPLACEMENT -static void * -failing_malloc(size_t how_much) -{ - errno = ENOMEM; - return NULL; -} -#endif - -static void -test_evbuffer_readln(void *ptr) -{ - struct evbuffer *evb = evbuffer_new(); - struct evbuffer *evb_tmp = evbuffer_new(); - const char *s; - char *cp = NULL; - size_t sz; - -#define tt_line_eq(content) \ - TT_STMT_BEGIN \ - if (!cp || sz != strlen(content) || strcmp(cp, content)) { \ - TT_DIE(("Wanted %s; got %s [%d]", content, cp, (int)sz)); \ - } \ - TT_STMT_END - - /* Test EOL_ANY. */ - s = "complex silly newline\r\n\n\r\n\n\rmore\0\n"; - evbuffer_add(evb, s, strlen(s)+2); - evbuffer_validate(evb); - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY); - tt_line_eq("complex silly newline"); - free(cp); - evbuffer_validate(evb); - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY); - if (!cp || sz != 5 || memcmp(cp, "more\0\0", 6)) - tt_abort_msg("Not as expected"); - tt_uint_op(evbuffer_get_length(evb), ==, 0); - evbuffer_validate(evb); - s = "\nno newline"; - evbuffer_add(evb, s, strlen(s)); - free(cp); - evbuffer_validate(evb); - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY); - tt_line_eq(""); - free(cp); - evbuffer_validate(evb); - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY); - tt_assert(!cp); - evbuffer_validate(evb); - evbuffer_drain(evb, evbuffer_get_length(evb)); - tt_assert(evbuffer_get_length(evb) == 0); - evbuffer_validate(evb); - - /* Test EOL_CRLF */ - s = "Line with\rin the middle\nLine with good crlf\r\n\nfinal\n"; - evbuffer_add(evb, s, strlen(s)); - evbuffer_validate(evb); - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF); - tt_line_eq("Line with\rin the middle"); - free(cp); - evbuffer_validate(evb); - - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF); - tt_line_eq("Line with good crlf"); - free(cp); - evbuffer_validate(evb); - - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF); - tt_line_eq(""); - free(cp); - evbuffer_validate(evb); - - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF); - tt_line_eq("final"); - s = "x"; - evbuffer_validate(evb); - evbuffer_add(evb, s, 1); - evbuffer_validate(evb); - free(cp); - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF); - tt_assert(!cp); - evbuffer_validate(evb); - - /* Test CRLF_STRICT */ - s = " and a bad crlf\nand a good one\r\n\r\nMore\r"; - evbuffer_add(evb, s, strlen(s)); - evbuffer_validate(evb); - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); - tt_line_eq("x and a bad crlf\nand a good one"); - free(cp); - evbuffer_validate(evb); - - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); - tt_line_eq(""); - free(cp); - evbuffer_validate(evb); - - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); - tt_assert(!cp); - evbuffer_validate(evb); - evbuffer_add(evb, "\n", 1); - evbuffer_validate(evb); - - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); - tt_line_eq("More"); - free(cp); - tt_assert(evbuffer_get_length(evb) == 0); - evbuffer_validate(evb); - - s = "An internal CR\r is not an eol\r\nNor is a lack of one"; - evbuffer_add(evb, s, strlen(s)); - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); - tt_line_eq("An internal CR\r is not an eol"); - free(cp); - evbuffer_validate(evb); - - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); - tt_assert(!cp); - evbuffer_validate(evb); - - evbuffer_add(evb, "\r\n", 2); - evbuffer_validate(evb); - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); - tt_line_eq("Nor is a lack of one"); - free(cp); - tt_assert(evbuffer_get_length(evb) == 0); - evbuffer_validate(evb); - - /* Test LF */ - s = "An\rand a nl\n\nText"; - evbuffer_add(evb, s, strlen(s)); - evbuffer_validate(evb); - - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); - tt_line_eq("An\rand a nl"); - free(cp); - evbuffer_validate(evb); - - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); - tt_line_eq(""); - free(cp); - evbuffer_validate(evb); - - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); - tt_assert(!cp); - free(cp); - evbuffer_add(evb, "\n", 1); - evbuffer_validate(evb); - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); - tt_line_eq("Text"); - free(cp); - evbuffer_validate(evb); - - /* Test NUL */ - tt_int_op(evbuffer_get_length(evb), ==, 0); - { - char x[] = - "NUL\n\0\0" - "The all-zeros character which may serve\0" - "to accomplish time fill\0and media fill"; - /* Add all but the final NUL of x. */ - evbuffer_add(evb, x, sizeof(x)-1); - } - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL); - tt_line_eq("NUL\n"); - free(cp); - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL); - tt_line_eq(""); - free(cp); - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL); - tt_line_eq("The all-zeros character which may serve"); - free(cp); - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL); - tt_line_eq("to accomplish time fill"); - free(cp); - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL); - tt_ptr_op(cp, ==, NULL); - evbuffer_drain(evb, -1); - - /* Test CRLF_STRICT - across boundaries*/ - s = " and a bad crlf\nand a good one\r"; - evbuffer_add(evb_tmp, s, strlen(s)); - evbuffer_validate(evb); - evbuffer_add_buffer(evb, evb_tmp); - evbuffer_validate(evb); - s = "\n\r"; - evbuffer_add(evb_tmp, s, strlen(s)); - evbuffer_validate(evb); - evbuffer_add_buffer(evb, evb_tmp); - evbuffer_validate(evb); - s = "\nMore\r"; - evbuffer_add(evb_tmp, s, strlen(s)); - evbuffer_validate(evb); - evbuffer_add_buffer(evb, evb_tmp); - evbuffer_validate(evb); - - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); - tt_line_eq(" and a bad crlf\nand a good one"); - free(cp); - evbuffer_validate(evb); - - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); - tt_line_eq(""); - free(cp); - evbuffer_validate(evb); - - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); - tt_assert(!cp); - free(cp); - evbuffer_validate(evb); - evbuffer_add(evb, "\n", 1); - evbuffer_validate(evb); - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); - tt_line_eq("More"); - free(cp); cp = NULL; - evbuffer_validate(evb); - tt_assert(evbuffer_get_length(evb) == 0); - - /* Test memory problem*/ - s = "one line\ntwo line\nblue line"; - evbuffer_add(evb_tmp, s, strlen(s)); - evbuffer_validate(evb); - evbuffer_add_buffer(evb, evb_tmp); - evbuffer_validate(evb); - - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); - tt_line_eq("one line"); - free(cp); cp = NULL; - evbuffer_validate(evb); - - /* the next call to readline should fail */ -#ifndef EVENT__DISABLE_MM_REPLACEMENT - event_set_mem_functions(failing_malloc, realloc, free); - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); - tt_assert(cp == NULL); - evbuffer_validate(evb); - - /* now we should get the next line back */ - event_set_mem_functions(malloc, realloc, free); -#endif - cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); - tt_line_eq("two line"); - free(cp); cp = NULL; - evbuffer_validate(evb); - - end: - evbuffer_free(evb); - evbuffer_free(evb_tmp); - if (cp) free(cp); -} - -static void -test_evbuffer_search_eol(void *ptr) -{ - struct evbuffer *buf = evbuffer_new(); - struct evbuffer_ptr ptr1, ptr2; - const char *s; - size_t eol_len; - - s = "string! \r\n\r\nx\n"; - evbuffer_add(buf, s, strlen(s)); - eol_len = -1; - ptr1 = evbuffer_search_eol(buf, NULL, &eol_len, EVBUFFER_EOL_CRLF); - tt_int_op(ptr1.pos, ==, 8); - tt_int_op(eol_len, ==, 2); - - eol_len = -1; - ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF); - tt_int_op(ptr2.pos, ==, 8); - tt_int_op(eol_len, ==, 2); - - evbuffer_ptr_set(buf, &ptr1, 1, EVBUFFER_PTR_ADD); - eol_len = -1; - ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF); - tt_int_op(ptr2.pos, ==, 9); - tt_int_op(eol_len, ==, 1); - - eol_len = -1; - ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF_STRICT); - tt_int_op(ptr2.pos, ==, 10); - tt_int_op(eol_len, ==, 2); - - eol_len = -1; - ptr1 = evbuffer_search_eol(buf, NULL, &eol_len, EVBUFFER_EOL_LF); - tt_int_op(ptr1.pos, ==, 9); - tt_int_op(eol_len, ==, 1); - - eol_len = -1; - ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF); - tt_int_op(ptr2.pos, ==, 9); - tt_int_op(eol_len, ==, 1); - - evbuffer_ptr_set(buf, &ptr1, 1, EVBUFFER_PTR_ADD); - eol_len = -1; - ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF); - tt_int_op(ptr2.pos, ==, 11); - tt_int_op(eol_len, ==, 1); - - tt_assert(evbuffer_ptr_set(buf, &ptr1, evbuffer_get_length(buf), EVBUFFER_PTR_SET) == 0); - eol_len = -1; - ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF); - tt_int_op(ptr2.pos, ==, -1); - tt_int_op(eol_len, ==, 0); - -end: - evbuffer_free(buf); -} - -static void -test_evbuffer_iterative(void *ptr) -{ - struct evbuffer *buf = evbuffer_new(); - const char *abc = "abcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyz"; - unsigned i, j, sum, n; - - sum = 0; - n = 0; - for (i = 0; i < 1000; ++i) { - for (j = 1; j < strlen(abc); ++j) { - char format[32]; - evutil_snprintf(format, sizeof(format), "%%%u.%us", j, j); - evbuffer_add_printf(buf, format, abc); - - /* Only check for rep violations every so often. - Walking over the whole list of chains can get - pretty expensive as it gets long. - */ - if ((n % 337) == 0) - evbuffer_validate(buf); - - sum += j; - n++; - } - } - evbuffer_validate(buf); - - tt_uint_op(sum, ==, evbuffer_get_length(buf)); - - { - size_t a,w,u; - a=w=u=0; - evbuffer_get_waste(buf, &a, &w, &u); - if (0) - printf("Allocated: %u.\nWasted: %u.\nUsed: %u.", - (unsigned)a, (unsigned)w, (unsigned)u); - tt_assert( ((double)w)/a < .125); - } - end: - evbuffer_free(buf); - -} - -static void -test_evbuffer_find(void *ptr) -{ - unsigned char* p; - const char* test1 = "1234567890\r\n"; - const char* test2 = "1234567890\r"; -#define EVBUFFER_INITIAL_LENGTH 256 - char test3[EVBUFFER_INITIAL_LENGTH]; - unsigned int i; - struct evbuffer * buf = evbuffer_new(); - - tt_assert(buf); - - /* make sure evbuffer_find doesn't match past the end of the buffer */ - evbuffer_add(buf, (unsigned char*)test1, strlen(test1)); - evbuffer_validate(buf); - evbuffer_drain(buf, strlen(test1)); - evbuffer_validate(buf); - evbuffer_add(buf, (unsigned char*)test2, strlen(test2)); - evbuffer_validate(buf); - p = evbuffer_find(buf, (unsigned char*)"\r\n", 2); - tt_want(p == NULL); - - /* - * drain the buffer and do another find; in r309 this would - * read past the allocated buffer causing a valgrind error. - */ - evbuffer_drain(buf, strlen(test2)); - evbuffer_validate(buf); - for (i = 0; i < EVBUFFER_INITIAL_LENGTH; ++i) - test3[i] = 'a'; - test3[EVBUFFER_INITIAL_LENGTH - 1] = 'x'; - evbuffer_add(buf, (unsigned char *)test3, EVBUFFER_INITIAL_LENGTH); - evbuffer_validate(buf); - p = evbuffer_find(buf, (unsigned char *)"xy", 2); - tt_want(p == NULL); - - /* simple test for match at end of allocated buffer */ - p = evbuffer_find(buf, (unsigned char *)"ax", 2); - tt_assert(p != NULL); - tt_want(strncmp((char*)p, "ax", 2) == 0); - -end: - if (buf) - evbuffer_free(buf); -} - -static void -test_evbuffer_ptr_set(void *ptr) -{ - struct evbuffer *buf = evbuffer_new(); - struct evbuffer_ptr pos; - struct evbuffer_iovec v[1]; - - tt_assert(buf); - - tt_int_op(evbuffer_get_length(buf), ==, 0); - - tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); - tt_assert(pos.pos == 0); - tt_assert(evbuffer_ptr_set(buf, &pos, 1, EVBUFFER_PTR_ADD) == -1); - tt_assert(pos.pos == -1); - tt_assert(evbuffer_ptr_set(buf, &pos, 1, EVBUFFER_PTR_SET) == -1); - tt_assert(pos.pos == -1); - - /* create some chains */ - evbuffer_reserve_space(buf, 5000, v, 1); - v[0].iov_len = 5000; - memset(v[0].iov_base, 1, v[0].iov_len); - evbuffer_commit_space(buf, v, 1); - evbuffer_validate(buf); - - evbuffer_reserve_space(buf, 4000, v, 1); - v[0].iov_len = 4000; - memset(v[0].iov_base, 2, v[0].iov_len); - evbuffer_commit_space(buf, v, 1); - - evbuffer_reserve_space(buf, 3000, v, 1); - v[0].iov_len = 3000; - memset(v[0].iov_base, 3, v[0].iov_len); - evbuffer_commit_space(buf, v, 1); - evbuffer_validate(buf); - - tt_int_op(evbuffer_get_length(buf), ==, 12000); - - tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_SET) == -1); - tt_assert(pos.pos == -1); - tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); - tt_assert(pos.pos == 0); - tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_ADD) == -1); - - tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); - tt_assert(pos.pos == 0); - tt_assert(evbuffer_ptr_set(buf, &pos, 10000, EVBUFFER_PTR_ADD) == 0); - tt_assert(pos.pos == 10000); - tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == 0); - tt_assert(pos.pos == 11000); - tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == 0); - tt_assert(pos.pos == 12000); - tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == -1); - tt_assert(pos.pos == -1); - -end: - if (buf) - evbuffer_free(buf); -} - -static void -test_evbuffer_search(void *ptr) -{ - struct evbuffer *buf = evbuffer_new(); - struct evbuffer *tmp = evbuffer_new(); - struct evbuffer_ptr pos, end; - - tt_assert(buf); - tt_assert(tmp); - - pos = evbuffer_search(buf, "x", 1, NULL); - tt_int_op(pos.pos, ==, -1); - tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); - pos = evbuffer_search(buf, "x", 1, &pos); - tt_int_op(pos.pos, ==, -1); - tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); - pos = evbuffer_search_range(buf, "x", 1, &pos, &pos); - tt_int_op(pos.pos, ==, -1); - tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); - pos = evbuffer_search_range(buf, "x", 1, &pos, NULL); - tt_int_op(pos.pos, ==, -1); - - /* set up our chains */ - evbuffer_add_printf(tmp, "hello"); /* 5 chars */ - evbuffer_add_buffer(buf, tmp); - evbuffer_add_printf(tmp, "foo"); /* 3 chars */ - evbuffer_add_buffer(buf, tmp); - evbuffer_add_printf(tmp, "cat"); /* 3 chars */ - evbuffer_add_buffer(buf, tmp); - evbuffer_add_printf(tmp, "attack"); - evbuffer_add_buffer(buf, tmp); - - pos = evbuffer_search(buf, "attack", 6, NULL); - tt_int_op(pos.pos, ==, 11); - pos = evbuffer_search(buf, "attacker", 8, NULL); - tt_int_op(pos.pos, ==, -1); - - /* test continuing search */ - pos = evbuffer_search(buf, "oc", 2, NULL); - tt_int_op(pos.pos, ==, 7); - pos = evbuffer_search(buf, "cat", 3, &pos); - tt_int_op(pos.pos, ==, 8); - pos = evbuffer_search(buf, "tacking", 7, &pos); - tt_int_op(pos.pos, ==, -1); - - evbuffer_ptr_set(buf, &pos, 5, EVBUFFER_PTR_SET); - pos = evbuffer_search(buf, "foo", 3, &pos); - tt_int_op(pos.pos, ==, 5); - - evbuffer_ptr_set(buf, &pos, 2, EVBUFFER_PTR_ADD); - pos = evbuffer_search(buf, "tat", 3, &pos); - tt_int_op(pos.pos, ==, 10); - - /* test bounded search. */ - /* Set "end" to the first t in "attack". */ - evbuffer_ptr_set(buf, &end, 12, EVBUFFER_PTR_SET); - pos = evbuffer_search_range(buf, "foo", 3, NULL, &end); - tt_int_op(pos.pos, ==, 5); - pos = evbuffer_search_range(buf, "foocata", 7, NULL, &end); - tt_int_op(pos.pos, ==, 5); - pos = evbuffer_search_range(buf, "foocatat", 8, NULL, &end); - tt_int_op(pos.pos, ==, -1); - pos = evbuffer_search_range(buf, "ack", 3, NULL, &end); - tt_int_op(pos.pos, ==, -1); - - /* Set "end" after the last byte in the buffer. */ - tt_assert(evbuffer_ptr_set(buf, &end, 17, EVBUFFER_PTR_SET) == 0); - - pos = evbuffer_search_range(buf, "attack", 6, NULL, &end); - tt_int_op(pos.pos, ==, 11); - tt_assert(evbuffer_ptr_set(buf, &pos, 11, EVBUFFER_PTR_SET) == 0); - pos = evbuffer_search_range(buf, "attack", 6, &pos, &end); - tt_int_op(pos.pos, ==, 11); - tt_assert(evbuffer_ptr_set(buf, &pos, 17, EVBUFFER_PTR_SET) == 0); - pos = evbuffer_search_range(buf, "attack", 6, &pos, &end); - tt_int_op(pos.pos, ==, -1); - tt_assert(evbuffer_ptr_set(buf, &pos, 17, EVBUFFER_PTR_SET) == 0); - pos = evbuffer_search_range(buf, "attack", 6, &pos, NULL); - tt_int_op(pos.pos, ==, -1); - -end: - if (buf) - evbuffer_free(buf); - if (tmp) - evbuffer_free(tmp); -} - -static void -log_change_callback(struct evbuffer *buffer, - const struct evbuffer_cb_info *cbinfo, - void *arg) -{ - - size_t old_len = cbinfo->orig_size; - size_t new_len = old_len + cbinfo->n_added - cbinfo->n_deleted; - struct evbuffer *out = arg; - evbuffer_add_printf(out, "%lu->%lu; ", (unsigned long)old_len, - (unsigned long)new_len); -} -static void -self_draining_callback(struct evbuffer *evbuffer, size_t old_len, - size_t new_len, void *arg) -{ - if (new_len > old_len) - evbuffer_drain(evbuffer, new_len); -} - -static void -test_evbuffer_callbacks(void *ptr) -{ - struct evbuffer *buf = evbuffer_new(); - struct evbuffer *buf_out1 = evbuffer_new(); - struct evbuffer *buf_out2 = evbuffer_new(); - struct evbuffer_cb_entry *cb1, *cb2; - - tt_assert(buf); - tt_assert(buf_out1); - tt_assert(buf_out2); - - cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1); - cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2); - - /* Let's run through adding and deleting some stuff from the buffer - * and turning the callbacks on and off and removing them. The callback - * adds a summary of length changes to buf_out1/buf_out2 when called. */ - /* size: 0-> 36. */ - evbuffer_add_printf(buf, "The %d magic words are spotty pudding", 2); - evbuffer_validate(buf); - evbuffer_cb_clear_flags(buf, cb2, EVBUFFER_CB_ENABLED); - evbuffer_drain(buf, 10); /*36->26*/ - evbuffer_validate(buf); - evbuffer_prepend(buf, "Hello", 5);/*26->31*/ - evbuffer_cb_set_flags(buf, cb2, EVBUFFER_CB_ENABLED); - evbuffer_add_reference(buf, "Goodbye", 7, NULL, NULL); /*31->38*/ - evbuffer_remove_cb_entry(buf, cb1); - evbuffer_validate(buf); - evbuffer_drain(buf, evbuffer_get_length(buf)); /*38->0*/; - tt_assert(-1 == evbuffer_remove_cb(buf, log_change_callback, NULL)); - evbuffer_add(buf, "X", 1); /* 0->1 */ - tt_assert(!evbuffer_remove_cb(buf, log_change_callback, buf_out2)); - evbuffer_validate(buf); - - tt_str_op((const char *) evbuffer_pullup(buf_out1, -1), ==, - "0->36; 36->26; 26->31; 31->38; "); - tt_str_op((const char *) evbuffer_pullup(buf_out2, -1), ==, - "0->36; 31->38; 38->0; 0->1; "); - evbuffer_drain(buf_out1, evbuffer_get_length(buf_out1)); - evbuffer_drain(buf_out2, evbuffer_get_length(buf_out2)); - /* Let's test the obsolete buffer_setcb function too. */ - cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1); - tt_assert(cb1 != NULL); - cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2); - tt_assert(cb2 != NULL); - evbuffer_setcb(buf, self_draining_callback, NULL); - evbuffer_add_printf(buf, "This should get drained right away."); - tt_uint_op(evbuffer_get_length(buf), ==, 0); - tt_uint_op(evbuffer_get_length(buf_out1), ==, 0); - tt_uint_op(evbuffer_get_length(buf_out2), ==, 0); - evbuffer_setcb(buf, NULL, NULL); - evbuffer_add_printf(buf, "This will not."); - tt_str_op((const char *) evbuffer_pullup(buf, -1), ==, "This will not."); - evbuffer_validate(buf); - evbuffer_drain(buf, evbuffer_get_length(buf)); - evbuffer_validate(buf); -#if 0 - /* Now let's try a suspended callback. */ - cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1); - cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2); - evbuffer_cb_suspend(buf,cb2); - evbuffer_prepend(buf,"Hello world",11); /*0->11*/ - evbuffer_validate(buf); - evbuffer_cb_suspend(buf,cb1); - evbuffer_add(buf,"more",4); /* 11->15 */ - evbuffer_cb_unsuspend(buf,cb2); - evbuffer_drain(buf, 4); /* 15->11 */ - evbuffer_cb_unsuspend(buf,cb1); - evbuffer_drain(buf, evbuffer_get_length(buf)); /* 11->0 */ - - tt_str_op(evbuffer_pullup(buf_out1, -1), ==, - "0->11; 11->11; 11->0; "); - tt_str_op(evbuffer_pullup(buf_out2, -1), ==, - "0->15; 15->11; 11->0; "); -#endif - - end: - if (buf) - evbuffer_free(buf); - if (buf_out1) - evbuffer_free(buf_out1); - if (buf_out2) - evbuffer_free(buf_out2); -} - -static int ref_done_cb_called_count = 0; -static void *ref_done_cb_called_with = NULL; -static const void *ref_done_cb_called_with_data = NULL; -static size_t ref_done_cb_called_with_len = 0; -static void ref_done_cb(const void *data, size_t len, void *info) -{ - ++ref_done_cb_called_count; - ref_done_cb_called_with = info; - ref_done_cb_called_with_data = data; - ref_done_cb_called_with_len = len; -} - -static void -test_evbuffer_add_reference(void *ptr) -{ - const char chunk1[] = "If you have found the answer to such a problem"; - const char chunk2[] = "you ought to write it up for publication"; - /* -- Knuth's "Notes on the Exercises" from TAOCP */ - char tmp[16]; - size_t len1 = strlen(chunk1), len2=strlen(chunk2); - - struct evbuffer *buf1 = NULL, *buf2 = NULL; - - buf1 = evbuffer_new(); - tt_assert(buf1); - - evbuffer_add_reference(buf1, chunk1, len1, ref_done_cb, (void*)111); - evbuffer_add(buf1, ", ", 2); - evbuffer_add_reference(buf1, chunk2, len2, ref_done_cb, (void*)222); - tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2); - - /* Make sure we can drain a little from a reference. */ - tt_int_op(evbuffer_remove(buf1, tmp, 6), ==, 6); - tt_int_op(memcmp(tmp, "If you", 6), ==, 0); - tt_int_op(evbuffer_remove(buf1, tmp, 5), ==, 5); - tt_int_op(memcmp(tmp, " have", 5), ==, 0); - - /* Make sure that prepending does not meddle with immutable data */ - tt_int_op(evbuffer_prepend(buf1, "I have ", 7), ==, 0); - tt_int_op(memcmp(chunk1, "If you", 6), ==, 0); - evbuffer_validate(buf1); - - /* Make sure that when the chunk is over, the callback is invoked. */ - evbuffer_drain(buf1, 7); /* Remove prepended stuff. */ - evbuffer_drain(buf1, len1-11-1); /* remove all but one byte of chunk1 */ - tt_int_op(ref_done_cb_called_count, ==, 0); - evbuffer_remove(buf1, tmp, 1); - tt_int_op(tmp[0], ==, 'm'); - tt_assert(ref_done_cb_called_with == (void*)111); - tt_assert(ref_done_cb_called_with_data == chunk1); - tt_assert(ref_done_cb_called_with_len == len1); - tt_int_op(ref_done_cb_called_count, ==, 1); - evbuffer_validate(buf1); - - /* Drain some of the remaining chunk, then add it to another buffer */ - evbuffer_drain(buf1, 6); /* Remove the ", you ". */ - buf2 = evbuffer_new(); - tt_assert(buf2); - tt_int_op(ref_done_cb_called_count, ==, 1); - evbuffer_add(buf2, "I ", 2); - - evbuffer_add_buffer(buf2, buf1); - tt_int_op(ref_done_cb_called_count, ==, 1); - evbuffer_remove(buf2, tmp, 16); - tt_int_op(memcmp("I ought to write", tmp, 16), ==, 0); - evbuffer_drain(buf2, evbuffer_get_length(buf2)); - tt_int_op(ref_done_cb_called_count, ==, 2); - tt_assert(ref_done_cb_called_with == (void*)222); - evbuffer_validate(buf2); - - /* Now add more stuff to buf1 and make sure that it gets removed on - * free. */ - evbuffer_add(buf1, "You shake and shake the ", 24); - evbuffer_add_reference(buf1, "ketchup bottle", 14, ref_done_cb, - (void*)3333); - evbuffer_add(buf1, ". Nothing comes and then a lot'll.", 35); - evbuffer_free(buf1); - buf1 = NULL; - tt_int_op(ref_done_cb_called_count, ==, 3); - tt_assert(ref_done_cb_called_with == (void*)3333); - -end: - if (buf1) - evbuffer_free(buf1); - if (buf2) - evbuffer_free(buf2); -} - -static void -test_evbuffer_multicast(void *ptr) -{ - const char chunk1[] = "If you have found the answer to such a problem"; - const char chunk2[] = "you ought to write it up for publication"; - /* -- Knuth's "Notes on the Exercises" from TAOCP */ - char tmp[16]; - size_t len1 = strlen(chunk1), len2=strlen(chunk2); - - struct evbuffer *buf1 = NULL, *buf2 = NULL; - - buf1 = evbuffer_new(); - tt_assert(buf1); - - evbuffer_add(buf1, chunk1, len1); - evbuffer_add(buf1, ", ", 2); - evbuffer_add(buf1, chunk2, len2); - tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2); - - buf2 = evbuffer_new(); - tt_assert(buf2); - - tt_int_op(evbuffer_add_buffer_reference(buf2, buf1), ==, 0); - /* nested references are not allowed */ - tt_int_op(evbuffer_add_buffer_reference(buf2, buf2), ==, -1); - tt_int_op(evbuffer_add_buffer_reference(buf1, buf2), ==, -1); - - /* both buffers contain the same amount of data */ - tt_int_op(evbuffer_get_length(buf1), ==, evbuffer_get_length(buf1)); - - /* Make sure we can drain a little from the first buffer. */ - tt_int_op(evbuffer_remove(buf1, tmp, 6), ==, 6); - tt_int_op(memcmp(tmp, "If you", 6), ==, 0); - tt_int_op(evbuffer_remove(buf1, tmp, 5), ==, 5); - tt_int_op(memcmp(tmp, " have", 5), ==, 0); - - /* Make sure that prepending does not meddle with immutable data */ - tt_int_op(evbuffer_prepend(buf1, "I have ", 7), ==, 0); - tt_int_op(memcmp(chunk1, "If you", 6), ==, 0); - evbuffer_validate(buf1); - - /* Make sure we can drain a little from the second buffer. */ - tt_int_op(evbuffer_remove(buf2, tmp, 6), ==, 6); - tt_int_op(memcmp(tmp, "If you", 6), ==, 0); - tt_int_op(evbuffer_remove(buf2, tmp, 5), ==, 5); - tt_int_op(memcmp(tmp, " have", 5), ==, 0); - - /* Make sure that prepending does not meddle with immutable data */ - tt_int_op(evbuffer_prepend(buf2, "I have ", 7), ==, 0); - tt_int_op(memcmp(chunk1, "If you", 6), ==, 0); - evbuffer_validate(buf2); - - /* Make sure the data can be read from the second buffer when the first is freed */ - evbuffer_free(buf1); - buf1 = NULL; - - tt_int_op(evbuffer_remove(buf2, tmp, 6), ==, 6); - tt_int_op(memcmp(tmp, "I have", 6), ==, 0); - - tt_int_op(evbuffer_remove(buf2, tmp, 6), ==, 6); - tt_int_op(memcmp(tmp, " foun", 6), ==, 0); - -end: - if (buf1) - evbuffer_free(buf1); - if (buf2) - evbuffer_free(buf2); -} - -static void -test_evbuffer_multicast_drain(void *ptr) -{ - const char chunk1[] = "If you have found the answer to such a problem"; - const char chunk2[] = "you ought to write it up for publication"; - /* -- Knuth's "Notes on the Exercises" from TAOCP */ - size_t len1 = strlen(chunk1), len2=strlen(chunk2); - - struct evbuffer *buf1 = NULL, *buf2 = NULL; - - buf1 = evbuffer_new(); - tt_assert(buf1); - - evbuffer_add(buf1, chunk1, len1); - evbuffer_add(buf1, ", ", 2); - evbuffer_add(buf1, chunk2, len2); - tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2); - - buf2 = evbuffer_new(); - tt_assert(buf2); - - tt_int_op(evbuffer_add_buffer_reference(buf2, buf1), ==, 0); - tt_int_op(evbuffer_get_length(buf2), ==, len1+len2+2); - tt_int_op(evbuffer_drain(buf1, evbuffer_get_length(buf1)), ==, 0); - tt_int_op(evbuffer_get_length(buf2), ==, len1+len2+2); - tt_int_op(evbuffer_drain(buf2, evbuffer_get_length(buf2)), ==, 0); - evbuffer_validate(buf1); - evbuffer_validate(buf2); - -end: - if (buf1) - evbuffer_free(buf1); - if (buf2) - evbuffer_free(buf2); -} - -/* Some cases that we didn't get in test_evbuffer() above, for more coverage. */ -static void -test_evbuffer_prepend(void *ptr) -{ - struct evbuffer *buf1 = NULL, *buf2 = NULL; - char tmp[128]; - int n; - - buf1 = evbuffer_new(); - tt_assert(buf1); - - /* Case 0: The evbuffer is entirely empty. */ - evbuffer_prepend(buf1, "This string has 29 characters", 29); - evbuffer_validate(buf1); - - /* Case 1: Prepend goes entirely in new chunk. */ - evbuffer_prepend(buf1, "Short.", 6); - evbuffer_validate(buf1); - - /* Case 2: prepend goes entirely in first chunk. */ - evbuffer_drain(buf1, 6+11); - evbuffer_prepend(buf1, "it", 2); - evbuffer_validate(buf1); - tt_assert(!memcmp(buf1->first->buffer+buf1->first->misalign, - "it has", 6)); - - /* Case 3: prepend is split over multiple chunks. */ - evbuffer_prepend(buf1, "It is no longer true to say ", 28); - evbuffer_validate(buf1); - n = evbuffer_remove(buf1, tmp, sizeof(tmp)-1); - tt_int_op(n, >=, 0); - tmp[n]='\0'; - tt_str_op(tmp,==,"It is no longer true to say it has 29 characters"); - - buf2 = evbuffer_new(); - tt_assert(buf2); - - /* Case 4: prepend a buffer to an empty buffer. */ - n = 999; - evbuffer_add_printf(buf1, "Here is string %d. ", n++); - evbuffer_prepend_buffer(buf2, buf1); - evbuffer_validate(buf2); - - /* Case 5: prepend a buffer to a nonempty buffer. */ - evbuffer_add_printf(buf1, "Here is string %d. ", n++); - evbuffer_prepend_buffer(buf2, buf1); - evbuffer_validate(buf2); - evbuffer_validate(buf1); - n = evbuffer_remove(buf2, tmp, sizeof(tmp)-1); - tt_int_op(n, >=, 0); - tmp[n]='\0'; - tt_str_op(tmp,==,"Here is string 1000. Here is string 999. "); - -end: - if (buf1) - evbuffer_free(buf1); - if (buf2) - evbuffer_free(buf2); - -} - -static void -test_evbuffer_peek_first_gt(void *info) -{ - struct evbuffer *buf = NULL, *tmp_buf = NULL; - struct evbuffer_ptr ptr; - struct evbuffer_iovec v[2]; - - buf = evbuffer_new(); - tmp_buf = evbuffer_new(); - evbuffer_add_printf(tmp_buf, "Contents of chunk 100\n"); - evbuffer_add_buffer(buf, tmp_buf); - evbuffer_add_printf(tmp_buf, "Contents of chunk 1\n"); - evbuffer_add_buffer(buf, tmp_buf); - - evbuffer_ptr_set(buf, &ptr, 0, EVBUFFER_PTR_SET); - - /** The only case that matters*/ - tt_int_op(evbuffer_peek(buf, -1, &ptr, NULL, 0), ==, 2); - /** Just in case */ - tt_int_op(evbuffer_peek(buf, -1, &ptr, v, 2), ==, 2); - - evbuffer_ptr_set(buf, &ptr, 20, EVBUFFER_PTR_ADD); - tt_int_op(evbuffer_peek(buf, -1, &ptr, NULL, 0), ==, 2); - tt_int_op(evbuffer_peek(buf, -1, &ptr, v, 2), ==, 2); - tt_int_op(evbuffer_peek(buf, 2, &ptr, NULL, 0), ==, 1); - tt_int_op(evbuffer_peek(buf, 2, &ptr, v, 2), ==, 1); - tt_int_op(evbuffer_peek(buf, 3, &ptr, NULL, 0), ==, 2); - tt_int_op(evbuffer_peek(buf, 3, &ptr, v, 2), ==, 2); - -end: - if (buf) - evbuffer_free(buf); - if (tmp_buf) - evbuffer_free(tmp_buf); -} - -static void -test_evbuffer_peek(void *info) -{ - struct evbuffer *buf = NULL, *tmp_buf = NULL; - int i; - struct evbuffer_iovec v[20]; - struct evbuffer_ptr ptr; - -#define tt_iov_eq(v, s) \ - tt_int_op((v)->iov_len, ==, strlen(s)); \ - tt_assert(!memcmp((v)->iov_base, (s), strlen(s))) - - /* Let's make a very fragmented buffer. */ - buf = evbuffer_new(); - tmp_buf = evbuffer_new(); - for (i = 0; i < 16; ++i) { - evbuffer_add_printf(tmp_buf, "Contents of chunk [%d]\n", i); - evbuffer_add_buffer(buf, tmp_buf); - } - - /* How many chunks do we need for everything? */ - i = evbuffer_peek(buf, -1, NULL, NULL, 0); - tt_int_op(i, ==, 16); - - /* Simple peek: get everything. */ - i = evbuffer_peek(buf, -1, NULL, v, 20); - tt_int_op(i, ==, 16); /* we used only 16 chunks. */ - tt_iov_eq(&v[0], "Contents of chunk [0]\n"); - tt_iov_eq(&v[3], "Contents of chunk [3]\n"); - tt_iov_eq(&v[12], "Contents of chunk [12]\n"); - tt_iov_eq(&v[15], "Contents of chunk [15]\n"); - - /* Just get one chunk worth. */ - memset(v, 0, sizeof(v)); - i = evbuffer_peek(buf, -1, NULL, v, 1); - tt_int_op(i, ==, 1); - tt_iov_eq(&v[0], "Contents of chunk [0]\n"); - tt_assert(v[1].iov_base == NULL); - - /* Suppose we want at least the first 40 bytes. */ - memset(v, 0, sizeof(v)); - i = evbuffer_peek(buf, 40, NULL, v, 16); - tt_int_op(i, ==, 2); - tt_iov_eq(&v[0], "Contents of chunk [0]\n"); - tt_iov_eq(&v[1], "Contents of chunk [1]\n"); - tt_assert(v[2].iov_base == NULL); - - /* How many chunks do we need for 100 bytes? */ - memset(v, 0, sizeof(v)); - i = evbuffer_peek(buf, 100, NULL, NULL, 0); - tt_int_op(i, ==, 5); - tt_assert(v[0].iov_base == NULL); - - /* Now we ask for more bytes than we provide chunks for */ - memset(v, 0, sizeof(v)); - i = evbuffer_peek(buf, 60, NULL, v, 1); - tt_int_op(i, ==, 3); - tt_iov_eq(&v[0], "Contents of chunk [0]\n"); - tt_assert(v[1].iov_base == NULL); - - /* Now we ask for more bytes than the buffer has. */ - memset(v, 0, sizeof(v)); - i = evbuffer_peek(buf, 65536, NULL, v, 20); - tt_int_op(i, ==, 16); /* we used only 16 chunks. */ - tt_iov_eq(&v[0], "Contents of chunk [0]\n"); - tt_iov_eq(&v[3], "Contents of chunk [3]\n"); - tt_iov_eq(&v[12], "Contents of chunk [12]\n"); - tt_iov_eq(&v[15], "Contents of chunk [15]\n"); - tt_assert(v[16].iov_base == NULL); - - /* What happens if we try an empty buffer? */ - memset(v, 0, sizeof(v)); - i = evbuffer_peek(tmp_buf, -1, NULL, v, 20); - tt_int_op(i, ==, 0); - tt_assert(v[0].iov_base == NULL); - memset(v, 0, sizeof(v)); - i = evbuffer_peek(tmp_buf, 50, NULL, v, 20); - tt_int_op(i, ==, 0); - tt_assert(v[0].iov_base == NULL); - - /* Okay, now time to have fun with pointers. */ - memset(v, 0, sizeof(v)); - evbuffer_ptr_set(buf, &ptr, 30, EVBUFFER_PTR_SET); - i = evbuffer_peek(buf, 50, &ptr, v, 20); - tt_int_op(i, ==, 3); - tt_iov_eq(&v[0], " of chunk [1]\n"); - tt_iov_eq(&v[1], "Contents of chunk [2]\n"); - tt_iov_eq(&v[2], "Contents of chunk [3]\n"); /*more than we asked for*/ - - /* advance to the start of another chain. */ - memset(v, 0, sizeof(v)); - evbuffer_ptr_set(buf, &ptr, 14, EVBUFFER_PTR_ADD); - i = evbuffer_peek(buf, 44, &ptr, v, 20); - tt_int_op(i, ==, 2); - tt_iov_eq(&v[0], "Contents of chunk [2]\n"); - tt_iov_eq(&v[1], "Contents of chunk [3]\n"); /*more than we asked for*/ - - /* peek at the end of the buffer */ - memset(v, 0, sizeof(v)); - tt_assert(evbuffer_ptr_set(buf, &ptr, evbuffer_get_length(buf), EVBUFFER_PTR_SET) == 0); - i = evbuffer_peek(buf, 44, &ptr, v, 20); - tt_int_op(i, ==, 0); - tt_assert(v[0].iov_base == NULL); - -end: - if (buf) - evbuffer_free(buf); - if (tmp_buf) - evbuffer_free(tmp_buf); -} - -/* Check whether evbuffer freezing works right. This is called twice, - once with the argument "start" and once with the argument "end". - When we test "start", we freeze the start of an evbuffer and make sure - that modifying the start of the buffer doesn't work. When we test - "end", we freeze the end of an evbuffer and make sure that modifying - the end of the buffer doesn't work. - */ -static void -test_evbuffer_freeze(void *ptr) -{ - struct evbuffer *buf = NULL, *tmp_buf=NULL; - const char string[] = /* Year's End, Richard Wilbur */ - "I've known the wind by water banks to shake\n" - "The late leaves down, which frozen where they fell\n" - "And held in ice as dancers in a spell\n" - "Fluttered all winter long into a lake..."; - const int start = !strcmp(ptr, "start"); - char *cp; - char charbuf[128]; - int r; - size_t orig_length; - struct evbuffer_iovec v[1]; - - if (!start) - tt_str_op(ptr, ==, "end"); - - buf = evbuffer_new(); - tmp_buf = evbuffer_new(); - tt_assert(tmp_buf); - - evbuffer_add(buf, string, strlen(string)); - evbuffer_freeze(buf, start); /* Freeze the start or the end.*/ - -#define FREEZE_EQ(a, startcase, endcase) \ - do { \ - if (start) { \ - tt_int_op((a), ==, (startcase)); \ - } else { \ - tt_int_op((a), ==, (endcase)); \ - } \ - } while (0) - - - orig_length = evbuffer_get_length(buf); - - /* These functions all manipulate the end of buf. */ - r = evbuffer_add(buf, "abc", 0); - FREEZE_EQ(r, 0, -1); - r = evbuffer_reserve_space(buf, 10, v, 1); - FREEZE_EQ(r, 1, -1); - if (r == 1) { - memset(v[0].iov_base, 'X', 10); - v[0].iov_len = 10; - } - r = evbuffer_commit_space(buf, v, 1); - FREEZE_EQ(r, 0, -1); - r = evbuffer_add_reference(buf, string, 5, NULL, NULL); - FREEZE_EQ(r, 0, -1); - r = evbuffer_add_printf(buf, "Hello %s", "world"); - FREEZE_EQ(r, 11, -1); - /* TODO: test add_buffer, add_file, read */ - - if (!start) - tt_int_op(orig_length, ==, evbuffer_get_length(buf)); - - orig_length = evbuffer_get_length(buf); - - /* These functions all manipulate the start of buf. */ - r = evbuffer_remove(buf, charbuf, 1); - FREEZE_EQ(r, -1, 1); - r = evbuffer_drain(buf, 3); - FREEZE_EQ(r, -1, 0); - r = evbuffer_prepend(buf, "dummy", 5); - FREEZE_EQ(r, -1, 0); - cp = evbuffer_readln(buf, NULL, EVBUFFER_EOL_LF); - FREEZE_EQ(cp==NULL, 1, 0); - if (cp) - free(cp); - /* TODO: Test remove_buffer, add_buffer, write, prepend_buffer */ - - if (start) - tt_int_op(orig_length, ==, evbuffer_get_length(buf)); - -end: - if (buf) - evbuffer_free(buf); - - if (tmp_buf) - evbuffer_free(tmp_buf); -} - -static void -test_evbuffer_add_iovec(void * ptr) -{ - struct evbuffer * buf = NULL; - struct evbuffer_iovec vec[4]; - const char * data[] = { - "Guilt resembles a sword with two edges.", - "On the one hand, it cuts for Justice, imposing practical morality upon those who fear it.", - "Conscience does not always adhere to rational judgment.", - "Guilt is always a self-imposed burden, but it is not always rightly imposed." - /* -- R.A. Salvatore, _Sojurn_ */ - }; - size_t expected_length = 0; - size_t returned_length = 0; - int i; - - buf = evbuffer_new(); - - tt_assert(buf); - - for (i = 0; i < 4; i++) { - vec[i].iov_len = strlen(data[i]); - vec[i].iov_base = (char*) data[i]; - expected_length += vec[i].iov_len; - } - - returned_length = evbuffer_add_iovec(buf, vec, 4); - - tt_int_op(returned_length, ==, evbuffer_get_length(buf)); - tt_int_op(evbuffer_get_length(buf), ==, expected_length); - - for (i = 0; i < 4; i++) { - char charbuf[1024]; - - memset(charbuf, 0, 1024); - evbuffer_remove(buf, charbuf, strlen(data[i])); - tt_assert(strcmp(charbuf, data[i]) == 0); - } - - tt_assert(evbuffer_get_length(buf) == 0); -end: - if (buf) { - evbuffer_free(buf); - } -} - -static void -test_evbuffer_copyout(void *dummy) -{ - const char string[] = - "Still they skirmish to and fro, men my messmates on the snow " - "When we headed off the aurochs turn for turn; " - "When the rich Allobrogenses never kept amanuenses, " - "And our only plots were piled in lakes at Berne."; - /* -- Kipling, "In The Neolithic Age" */ - char tmp[1024]; - struct evbuffer_ptr ptr; - struct evbuffer *buf; - - (void)dummy; - - buf = evbuffer_new(); - tt_assert(buf); - - tt_int_op(strlen(string), ==, 206); - - /* Ensure separate chains */ - evbuffer_add_reference(buf, string, 80, no_cleanup, NULL); - evbuffer_add_reference(buf, string+80, 80, no_cleanup, NULL); - evbuffer_add(buf, string+160, strlen(string)-160); - - tt_int_op(206, ==, evbuffer_get_length(buf)); - - /* First, let's test plain old copyout. */ - - /* Copy a little from the beginning. */ - tt_int_op(10, ==, evbuffer_copyout(buf, tmp, 10)); - tt_int_op(0, ==, memcmp(tmp, "Still they", 10)); - - /* Now copy more than a little from the beginning */ - memset(tmp, 0, sizeof(tmp)); - tt_int_op(100, ==, evbuffer_copyout(buf, tmp, 100)); - tt_int_op(0, ==, memcmp(tmp, string, 100)); - - /* Copy too much; ensure truncation. */ - memset(tmp, 0, sizeof(tmp)); - tt_int_op(206, ==, evbuffer_copyout(buf, tmp, 230)); - tt_int_op(0, ==, memcmp(tmp, string, 206)); - - /* That was supposed to be nondestructive, btw */ - tt_int_op(206, ==, evbuffer_get_length(buf)); - - /* Now it's time to test copyout_from! First, let's start in the - * first chain. */ - evbuffer_ptr_set(buf, &ptr, 15, EVBUFFER_PTR_SET); - memset(tmp, 0, sizeof(tmp)); - tt_int_op(10, ==, evbuffer_copyout_from(buf, &ptr, tmp, 10)); - tt_int_op(0, ==, memcmp(tmp, "mish to an", 10)); - - /* Right up to the end of the first chain */ - memset(tmp, 0, sizeof(tmp)); - tt_int_op(65, ==, evbuffer_copyout_from(buf, &ptr, tmp, 65)); - tt_int_op(0, ==, memcmp(tmp, string+15, 65)); - - /* Span into the second chain */ - memset(tmp, 0, sizeof(tmp)); - tt_int_op(90, ==, evbuffer_copyout_from(buf, &ptr, tmp, 90)); - tt_int_op(0, ==, memcmp(tmp, string+15, 90)); - - /* Span into the third chain */ - memset(tmp, 0, sizeof(tmp)); - tt_int_op(160, ==, evbuffer_copyout_from(buf, &ptr, tmp, 160)); - tt_int_op(0, ==, memcmp(tmp, string+15, 160)); - - /* Overrun */ - memset(tmp, 0, sizeof(tmp)); - tt_int_op(206-15, ==, evbuffer_copyout_from(buf, &ptr, tmp, 999)); - tt_int_op(0, ==, memcmp(tmp, string+15, 206-15)); - - /* That was supposed to be nondestructive, too */ - tt_int_op(206, ==, evbuffer_get_length(buf)); - -end: - if (buf) - evbuffer_free(buf); -} - -static void * -setup_passthrough(const struct testcase_t *testcase) -{ - return testcase->setup_data; -} -static int -cleanup_passthrough(const struct testcase_t *testcase, void *ptr) -{ - (void) ptr; - return 1; -} - -static const struct testcase_setup_t nil_setup = { - setup_passthrough, - cleanup_passthrough -}; - -struct testcase_t evbuffer_testcases[] = { - { "evbuffer", test_evbuffer, 0, NULL, NULL }, - { "remove_buffer_with_empty", test_evbuffer_remove_buffer_with_empty, 0, NULL, NULL }, - { "reserve2", test_evbuffer_reserve2, 0, NULL, NULL }, - { "reserve_many", test_evbuffer_reserve_many, 0, NULL, NULL }, - { "reserve_many2", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"add" }, - { "reserve_many3", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"fill" }, - { "expand", test_evbuffer_expand, 0, NULL, NULL }, - { "reference", test_evbuffer_reference, 0, NULL, NULL }, - { "iterative", test_evbuffer_iterative, 0, NULL, NULL }, - { "readln", test_evbuffer_readln, TT_NO_LOGS, &basic_setup, NULL }, - { "search_eol", test_evbuffer_search_eol, 0, NULL, NULL }, - { "find", test_evbuffer_find, 0, NULL, NULL }, - { "ptr_set", test_evbuffer_ptr_set, 0, NULL, NULL }, - { "search", test_evbuffer_search, 0, NULL, NULL }, - { "callbacks", test_evbuffer_callbacks, 0, NULL, NULL }, - { "add_reference", test_evbuffer_add_reference, 0, NULL, NULL }, - { "multicast", test_evbuffer_multicast, 0, NULL, NULL }, - { "multicast_drain", test_evbuffer_multicast_drain, 0, NULL, NULL }, - { "prepend", test_evbuffer_prepend, TT_FORK, NULL, NULL }, - { "peek", test_evbuffer_peek, 0, NULL, NULL }, - { "peek_first_gt", test_evbuffer_peek_first_gt, 0, NULL, NULL }, - { "freeze_start", test_evbuffer_freeze, 0, &nil_setup, (void*)"start" }, - { "freeze_end", test_evbuffer_freeze, 0, &nil_setup, (void*)"end" }, - { "add_iovec", test_evbuffer_add_iovec, 0, NULL, NULL}, - { "copyout", test_evbuffer_copyout, 0, NULL, NULL}, - { "file_segment_add_cleanup_cb", test_evbuffer_file_segment_add_cleanup_cb, 0, NULL, NULL }, - -#define ADDFILE_TEST(name, parameters) \ - { name, test_evbuffer_add_file, TT_FORK|TT_NEED_BASE, \ - &basic_setup, (void*)(parameters) } - -#define ADDFILE_TEST_GROUP(name, parameters) \ - ADDFILE_TEST(name "_sendfile", "sendfile " parameters), \ - ADDFILE_TEST(name "_mmap", "mmap " parameters), \ - ADDFILE_TEST(name "_linear", "linear " parameters) - - ADDFILE_TEST_GROUP("add_file", ""), - ADDFILE_TEST("add_file_nosegment", "default nosegment"), - - ADDFILE_TEST_GROUP("add_big_file", "bigfile"), - ADDFILE_TEST("add_big_file_nosegment", "default nosegment bigfile"), - - ADDFILE_TEST_GROUP("add_file_offset", "bigfile map_offset"), - ADDFILE_TEST("add_file_offset_nosegment", - "default nosegment bigfile map_offset"), - - ADDFILE_TEST_GROUP("add_file_offset2", "bigfile offset_in_segment"), - - ADDFILE_TEST_GROUP("add_file_offset3", - "bigfile offset_in_segment map_offset"), - - END_OF_TESTCASES -}; diff --git a/libs/libevent/docs/test/regress_bufferevent.c b/libs/libevent/docs/test/regress_bufferevent.c deleted file mode 100644 index 68e6876405..0000000000 --- a/libs/libevent/docs/test/regress_bufferevent.c +++ /dev/null @@ -1,1284 +0,0 @@ -/* - * Copyright (c) 2003-2007 Niels Provos - * Copyright (c) 2007-2012 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 "util-internal.h" - -/* The old tests here need assertions to work. */ -#undef NDEBUG - -#ifdef _WIN32 -#include -#include -#endif - -#include "event2/event-config.h" - -#include -#include -#ifdef EVENT__HAVE_SYS_TIME_H -#include -#endif -#include -#ifndef _WIN32 -#include -#include -#include -#include -#include -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -#ifdef EVENT__HAVE_ARPA_INET_H -#include -#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" -#include "evthread-internal.h" -#include "util-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, int flush) -{ - struct bufferevent *bev1 = NULL, *bev2 = NULL; - char buffer[8333]; - int i; - int expected = 2; - - 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, bev1); - 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); - } - - { - /* Test getcb. */ - bufferevent_data_cb r, w; - bufferevent_event_cb e; - void *a; - bufferevent_getcb(bev1, &r, &w, &e, &a); - tt_ptr_op(r, ==, readcb); - tt_ptr_op(w, ==, writecb); - tt_ptr_op(e, ==, errorcb); - tt_ptr_op(a, ==, use_pair ? bev1 : 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 < (int)sizeof(buffer); i++) - buffer[i] = i; - - bufferevent_write(bev1, buffer, sizeof(buffer)); - if (flush >= 0) { - tt_int_op(bufferevent_flush(bev1, EV_WRITE, flush), >=, 0); - } - - event_dispatch(); - - bufferevent_free(bev2); - tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL); - bufferevent_free(bev1); - - /** Only pair call errorcb for BEV_FINISHED */ - if (use_pair && flush == BEV_FINISHED) { - expected = -1; - } - if (test_ok != expected) - test_ok = 0; -end: - ; -} - -static void test_bufferevent(void) { test_bufferevent_impl(0, -1); } -static void test_bufferevent_pair(void) { test_bufferevent_impl(1, -1); } - -static void test_bufferevent_flush_normal(void) { test_bufferevent_impl(0, BEV_NORMAL); } -static void test_bufferevent_flush_flush(void) { test_bufferevent_impl(0, BEV_FLUSH); } -static void test_bufferevent_flush_finished(void) { test_bufferevent_impl(0, BEV_FINISHED); } - -static void test_bufferevent_pair_flush_normal(void) { test_bufferevent_impl(1, BEV_NORMAL); } -static void test_bufferevent_pair_flush_flush(void) { test_bufferevent_impl(1, BEV_FLUSH); } -static void test_bufferevent_pair_flush_finished(void) { test_bufferevent_impl(1, BEV_FINISHED); } - -#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED) -/** - * Trace lock/unlock/alloc/free for locks. - * (More heavier then evthread_debug*) - */ -typedef struct -{ - void *lock; - enum { - ALLOC, FREE, - } status; - size_t locked /** allow recursive locking */; -} lock_wrapper; -struct lock_unlock_base -{ - /* Original callbacks */ - struct evthread_lock_callbacks cbs; - /* Map of locks */ - lock_wrapper *locks; - size_t nr_locks; -} lu_base = { - .locks = NULL, -}; - -static lock_wrapper *lu_find(void *lock_) -{ - size_t i; - for (i = 0; i < lu_base.nr_locks; ++i) { - lock_wrapper *lock = &lu_base.locks[i]; - if (lock->lock == lock_) - return lock; - } - return NULL; -} - -static void *trace_lock_alloc(unsigned locktype) -{ - void *lock; - ++lu_base.nr_locks; - lu_base.locks = realloc(lu_base.locks, - sizeof(lock_wrapper) * lu_base.nr_locks); - lock = lu_base.cbs.alloc(locktype); - lu_base.locks[lu_base.nr_locks - 1] = (lock_wrapper){ lock, ALLOC, 0 }; - return lock; -} -static void trace_lock_free(void *lock_, unsigned locktype) -{ - lock_wrapper *lock = lu_find(lock_); - if (!lock || lock->status == FREE || lock->locked) { - TT_FAIL(("lock: free error")); - } else { - lock->status = FREE; - lu_base.cbs.free(lock_, locktype); - } -} -static int trace_lock_lock(unsigned mode, void *lock_) -{ - lock_wrapper *lock = lu_find(lock_); - if (!lock || lock->status == FREE) { - TT_FAIL(("lock: lock error")); - return -1; - } else { - ++lock->locked; - return lu_base.cbs.lock(mode, lock_); - } -} -static int trace_lock_unlock(unsigned mode, void *lock_) -{ - lock_wrapper *lock = lu_find(lock_); - if (!lock || lock->status == FREE || !lock->locked) { - TT_FAIL(("lock: unlock error")); - return -1; - } else { - --lock->locked; - return lu_base.cbs.unlock(mode, lock_); - } -} -static void lock_unlock_free_thread_cbs(void) -{ - event_base_free(NULL); - - if (libevent_tests_running_in_debug_mode) - libevent_global_shutdown(); - - /** drop immutable flag */ - evthread_set_lock_callbacks(NULL); - /** avoid calling of event_global_setup_locks_() for new cbs */ - libevent_global_shutdown(); - /** drop immutable flag for non-debug ops (since called after shutdown) */ - evthread_set_lock_callbacks(NULL); -} - -static int use_lock_unlock_profiler(void) -{ - struct evthread_lock_callbacks cbs = { - EVTHREAD_LOCK_API_VERSION, - EVTHREAD_LOCKTYPE_RECURSIVE, - trace_lock_alloc, - trace_lock_free, - trace_lock_lock, - trace_lock_unlock, - }; - memcpy(&lu_base.cbs, evthread_get_lock_callbacks(), - sizeof(lu_base.cbs)); - { - lock_unlock_free_thread_cbs(); - - evthread_set_lock_callbacks(&cbs); - /** re-create debug locks correctly */ - evthread_enable_lock_debugging(); - - event_init(); - } - return 0; -} -static void free_lock_unlock_profiler(struct basic_test_data *data) -{ - /** fix "held_by" for kqueue */ - evthread_set_lock_callbacks(NULL); - - lock_unlock_free_thread_cbs(); - free(lu_base.locks); - data->base = NULL; -} - -static void test_bufferevent_pair_release_lock(void *arg) -{ - struct basic_test_data *data = arg; - use_lock_unlock_profiler(); - { - struct bufferevent *pair[2]; - if (!bufferevent_pair_new(NULL, BEV_OPT_THREADSAFE, pair)) { - bufferevent_free(pair[0]); - bufferevent_free(pair[1]); - } else - tt_abort_perror("bufferevent_pair_new"); - } - free_lock_unlock_profiler(data); -end: - ; -} -#endif - -/* - * test watermarks and bufferevent - */ - -static void -wm_readcb(struct bufferevent *bev, void *arg) -{ - struct evbuffer *evbuf = evbuffer_new(); - int len = (int)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]; - size_t low, high; - 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); - } - tt_assert(bev1); - tt_assert(bev2); - bufferevent_disable(bev1, EV_READ); - bufferevent_enable(bev2, EV_READ); - - /* By default, low watermarks are set to 0 */ - bufferevent_getwatermark(bev1, EV_READ, &low, NULL); - tt_int_op(low, ==, 0); - bufferevent_getwatermark(bev2, EV_WRITE, &low, NULL); - tt_int_op(low, ==, 0); - - for (i = 0; i < (int)sizeof(buffer); i++) - buffer[i] = (char)i; - - /* limit the reading on the receiving bufferevent */ - bufferevent_setwatermark(bev2, EV_READ, 10, 20); - - bufferevent_getwatermark(bev2, EV_READ, &low, &high); - tt_int_op(low, ==, 10); - tt_int_op(high, ==, 20); - - /* Tell the sending bufferevent not to notify us till it's down to - 100 bytes. */ - bufferevent_setwatermark(bev1, EV_WRITE, 100, 2000); - - bufferevent_getwatermark(bev1, EV_WRITE, &low, &high); - tt_int_op(low, ==, 100); - tt_int_op(high, ==, 2000); - - { - int r = bufferevent_getwatermark(bev1, EV_WRITE | EV_READ, &low, &high); - tt_int_op(r, !=, 0); - } - - 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: - if (bev1) - bufferevent_free(bev1); - if (bev2) - 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 < (int)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: - if (bev1) - bufferevent_free(bev1); - if (bev2) - 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); - TT_BLATHER(("Flushed %d: freeing it.", (int)bufferevent_getfd(bev))); - 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 bufferevent_trigger_test_flags = 0; -static int n_strings_read = 0; -static int n_reads_invoked = 0; -static int n_events_invoked = 0; - -#define TEST_STR "Now is the time for all good events to signal for " \ - "the good of their protocol" -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 int -fake_listener_create(struct sockaddr_in *localhost) -{ - struct sockaddr *sa = (struct sockaddr *)localhost; - evutil_socket_t fd = -1; - ev_socklen_t slen = sizeof(*localhost); - - memset(localhost, 0, sizeof(*localhost)); - localhost->sin_port = 0; /* have the kernel pick a port */ - localhost->sin_addr.s_addr = htonl(0x7f000001L); - localhost->sin_family = AF_INET; - - /* bind, but don't listen or accept. should trigger - "Connection refused" reliably on most platforms. */ - fd = socket(localhost->sin_family, SOCK_STREAM, 0); - tt_assert(fd >= 0); - tt_assert(bind(fd, sa, slen) == 0); - tt_assert(getsockname(fd, sa, &slen) == 0); - - return fd; - -end: - return -1; -} - -static void -reader_eventcb(struct bufferevent *bev, short what, void *ctx) -{ - 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) { - TT_BLATHER(("connected on %d", (int)bufferevent_getfd(bev))); - bufferevent_enable(bev, EV_READ); - } - if (what & BEV_EVENT_EOF) { - char buf[512]; - size_t n; - n = bufferevent_read(bev, buf, sizeof(buf)-1); - tt_int_op(n, >=, 0); - buf[n] = '\0'; - tt_str_op(buf, ==, TEST_STR); - if (++n_strings_read == 2) - event_base_loopexit(base, NULL); - TT_BLATHER(("EOF on %d: %d strings read.", - (int)bufferevent_getfd(bev), n_strings_read)); - } -end: - ; -} - -static void -reader_eventcb_simple(struct bufferevent *bev, short what, void *ctx) -{ - TT_BLATHER(("Read eventcb simple invoked on %d.", - (int)bufferevent_getfd(bev))); - n_events_invoked++; -} - -static void -reader_readcb(struct bufferevent *bev, void *ctx) -{ - TT_BLATHER(("Read invoked on %d.", (int)bufferevent_getfd(bev))); - 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 -test_bufferevent_connect_fail_eventcb(void *arg) -{ - struct basic_test_data *data = arg; - int flags = BEV_OPT_CLOSE_ON_FREE | (long)data->setup_data; - struct bufferevent *bev = NULL; - struct evconnlistener *lev = NULL; - struct sockaddr_in localhost; - ev_socklen_t slen = sizeof(localhost); - evutil_socket_t fake_listener = -1; - - fake_listener = fake_listener_create(&localhost); - - tt_int_op(n_events_invoked, ==, 0); - - bev = bufferevent_socket_new(data->base, -1, flags); - tt_assert(bev); - bufferevent_setcb(bev, reader_readcb, reader_readcb, - reader_eventcb_simple, data->base); - bufferevent_enable(bev, EV_READ|EV_WRITE); - tt_int_op(n_events_invoked, ==, 0); - tt_int_op(n_reads_invoked, ==, 0); - /** @see also test_bufferevent_connect_fail() */ - bufferevent_socket_connect(bev, (struct sockaddr *)&localhost, slen); - tt_int_op(n_events_invoked, ==, 0); - tt_int_op(n_reads_invoked, ==, 0); - event_base_dispatch(data->base); - tt_int_op(n_events_invoked, ==, 1); - tt_int_op(n_reads_invoked, ==, 0); - -end: - if (lev) - evconnlistener_free(lev); - if (bev) - bufferevent_free(bev); - if (fake_listener >= 0) - evutil_closesocket(fake_listener); -} - -static void -want_fail_eventcb(struct bufferevent *bev, short what, void *ctx) -{ - 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 on "EV_SOCK_FMT": %s", - EV_SOCK_ARG(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 = (struct basic_test_data *)arg; - struct bufferevent *bev=NULL; - struct event close_listener_event; - int close_listener_event_added = 0; - struct timeval one_second = { 1, 0 }; - struct sockaddr_in localhost; - ev_socklen_t slen = sizeof(localhost); - evutil_socket_t fake_listener = -1; - int r; - - test_ok = 0; - - fake_listener = fake_listener_create(&localhost); - bev = bufferevent_socket_new(data->base, -1, - BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS); - tt_assert(bev); - bufferevent_setcb(bev, NULL, NULL, want_fail_eventcb, data->base); - - r = bufferevent_socket_connect(bev, (struct sockaddr *)&localhost, slen); - /* XXXX we'd like to test the '0' case everywhere, but FreeBSD tells - * detects the error immediately, which is not really wrong of it. */ - tt_want(r == 0 || r == -1); - - /* Close the listener socket after a second. This should trigger - "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 = 0; - tv_r.tv_usec = 350000; - - 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); -} - -static void -trigger_failure_cb(evutil_socket_t fd, short what, void *ctx) -{ - TT_FAIL(("The triggered callback did not fire or the machine is really slow (try increasing timeout).")); -} - -static void -trigger_eventcb(struct bufferevent *bev, short what, void *ctx) -{ - struct event_base *base = ctx; - if (what == ~0) { - TT_BLATHER(("Event successfully triggered.")); - event_base_loopexit(base, NULL); - return; - } - reader_eventcb(bev, what, ctx); -} - -static void -trigger_readcb_triggered(struct bufferevent *bev, void *ctx) -{ - TT_BLATHER(("Read successfully triggered.")); - n_reads_invoked++; - bufferevent_trigger_event(bev, ~0, bufferevent_trigger_test_flags); -} - -static void -trigger_readcb(struct bufferevent *bev, void *ctx) -{ - struct timeval timeout = { 30, 0 }; - struct event_base *base = ctx; - size_t low, high, len; - int expected_reads; - - TT_BLATHER(("Read invoked on %d.", (int)bufferevent_getfd(bev))); - expected_reads = ++n_reads_invoked; - - bufferevent_setcb(bev, trigger_readcb_triggered, NULL, trigger_eventcb, ctx); - - bufferevent_getwatermark(bev, EV_READ, &low, &high); - len = evbuffer_get_length(bufferevent_get_input(bev)); - - bufferevent_setwatermark(bev, EV_READ, len + 1, 0); - bufferevent_trigger(bev, EV_READ, bufferevent_trigger_test_flags); - /* no callback expected */ - tt_int_op(n_reads_invoked, ==, expected_reads); - - if ((bufferevent_trigger_test_flags & BEV_TRIG_DEFER_CALLBACKS) || - (bufferevent_connect_test_flags & BEV_OPT_DEFER_CALLBACKS)) { - /* will be deferred */ - } else { - expected_reads++; - } - - event_base_once(base, -1, EV_TIMEOUT, trigger_failure_cb, NULL, &timeout); - - bufferevent_trigger(bev, EV_READ, - bufferevent_trigger_test_flags | BEV_TRIG_IGNORE_WATERMARKS); - tt_int_op(n_reads_invoked, ==, expected_reads); - - bufferevent_setwatermark(bev, EV_READ, low, high); -end: - ; -} - -static void -test_bufferevent_trigger(void *arg) -{ - struct basic_test_data *data = arg; - struct evconnlistener *lev=NULL; - struct bufferevent *bev=NULL; - struct sockaddr_in localhost; - struct sockaddr_storage ss; - struct sockaddr *sa; - ev_socklen_t slen; - - int be_flags=BEV_OPT_CLOSE_ON_FREE; - int trig_flags=0; - - if (strstr((char*)data->setup_data, "defer")) { - be_flags |= BEV_OPT_DEFER_CALLBACKS; - } - bufferevent_connect_test_flags = be_flags; - - if (strstr((char*)data->setup_data, "postpone")) { - trig_flags |= BEV_TRIG_DEFER_CALLBACKS; - } - bufferevent_trigger_test_flags = trig_flags; - - 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)); - bev = bufferevent_socket_new(data->base, -1, be_flags); - tt_assert(bev); - bufferevent_setcb(bev, trigger_readcb, NULL, trigger_eventcb, data->base); - - bufferevent_enable(bev, EV_READ); - - tt_want(!bufferevent_socket_connect(bev, sa, sizeof(localhost))); - - event_base_dispatch(data->base); - - tt_int_op(n_reads_invoked, ==, 2); -end: - if (lev) - evconnlistener_free(lev); - - if (bev) - bufferevent_free(bev); -} - -static void -test_bufferevent_socket_filter_inactive(void *arg) -{ - struct basic_test_data *data = arg; - struct bufferevent *bev = NULL, *bevf = NULL; - - bev = bufferevent_socket_new(data->base, -1, 0); - tt_assert(bev); - bevf = bufferevent_filter_new(bev, NULL, NULL, 0, NULL, NULL); - tt_assert(bevf); - -end: - if (bevf) - bufferevent_free(bevf); - if (bev) - bufferevent_free(bev); -} - - -struct testcase_t bufferevent_testcases[] = { - - LEGACY(bufferevent, TT_ISOLATED), - LEGACY(bufferevent_pair, TT_ISOLATED), - LEGACY(bufferevent_flush_normal, TT_ISOLATED), - LEGACY(bufferevent_flush_flush, TT_ISOLATED), - LEGACY(bufferevent_flush_finished, TT_ISOLATED), - LEGACY(bufferevent_pair_flush_normal, TT_ISOLATED), - LEGACY(bufferevent_pair_flush_flush, TT_ISOLATED), - LEGACY(bufferevent_pair_flush_finished, TT_ISOLATED), -#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED) - { "bufferevent_pair_release_lock", test_bufferevent_pair_release_lock, - TT_FORK|TT_ISOLATED|TT_NEED_THREADS|TT_NEED_BASE|TT_LEGACY, - &basic_setup, NULL }, -#endif - LEGACY(bufferevent_watermarks, TT_ISOLATED), - LEGACY(bufferevent_pair_watermarks, TT_ISOLATED), - LEGACY(bufferevent_filters, TT_ISOLATED), - LEGACY(bufferevent_pair_filters, TT_ISOLATED), - { "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" }, - { "bufferevent_trigger", test_bufferevent_trigger, TT_FORK|TT_NEED_BASE, - &basic_setup, (void*)"" }, - { "bufferevent_trigger_defer", test_bufferevent_trigger, - TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"defer" }, - { "bufferevent_trigger_postpone", test_bufferevent_trigger, - TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, - (void*)"postpone" }, - { "bufferevent_trigger_defer_postpone", test_bufferevent_trigger, - TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, - (void*)"defer postpone" }, -#ifdef EVENT__HAVE_LIBZ - LEGACY(bufferevent_zlib, TT_ISOLATED), -#else - { "bufferevent_zlib", NULL, TT_SKIP, NULL, NULL }, -#endif - - { "bufferevent_connect_fail_eventcb_defer", - test_bufferevent_connect_fail_eventcb, - TT_FORK|TT_NEED_BASE, &basic_setup, (void*)BEV_OPT_DEFER_CALLBACKS }, - { "bufferevent_connect_fail_eventcb", - test_bufferevent_connect_fail_eventcb, - TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, - - { "bufferevent_socket_filter_inactive", - test_bufferevent_socket_filter_inactive, - TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, - - END_OF_TESTCASES, -}; - -struct testcase_t bufferevent_iocp_testcases[] = { - - LEGACY(bufferevent, TT_ISOLATED|TT_ENABLE_IOCP), - LEGACY(bufferevent_flush_normal, TT_ISOLATED), - LEGACY(bufferevent_flush_flush, TT_ISOLATED), - LEGACY(bufferevent_flush_finished, TT_ISOLATED), - LEGACY(bufferevent_watermarks, TT_ISOLATED|TT_ENABLE_IOCP), - LEGACY(bufferevent_filters, TT_ISOLATED|TT_ENABLE_IOCP), - { "bufferevent_connect", test_bufferevent_connect, - 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" }, - - { "bufferevent_connect_fail_eventcb_defer", - test_bufferevent_connect_fail_eventcb, - TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, - (void*)BEV_OPT_DEFER_CALLBACKS }, - { "bufferevent_connect_fail", - test_bufferevent_connect_fail_eventcb, - TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL }, - - END_OF_TESTCASES, -}; diff --git a/libs/libevent/docs/test/regress_dns.c b/libs/libevent/docs/test/regress_dns.c deleted file mode 100644 index 1873636245..0000000000 --- a/libs/libevent/docs/test/regress_dns.c +++ /dev/null @@ -1,2151 +0,0 @@ -/* - * Copyright (c) 2003-2007 Niels Provos - * Copyright (c) 2007-2012 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 "../util-internal.h" - -#ifdef _WIN32 -#include -#include -#include -#endif - -#include "event2/event-config.h" - -#include -#include -#ifdef EVENT__HAVE_SYS_TIME_H -#include -#endif -#include -#ifndef _WIN32 -#include -#include -#include -#include -#include -#endif -#ifdef EVENT__HAVE_NETINET_IN6_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#include -#include -#include -#include -#include - -#include "event2/dns.h" -#include "event2/dns_compat.h" -#include "event2/dns_struct.h" -#include "event2/event.h" -#include "event2/event_compat.h" -#include "event2/event_struct.h" -#include "event2/util.h" -#include "event2/listener.h" -#include "event2/bufferevent.h" -#include "log-internal.h" -#include "regress.h" -#include "regress_testutils.h" - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) - -static int dns_ok = 0; -static int dns_got_cancel = 0; -static int dns_err = 0; - - -static void -dns_gethostbyname_cb(int result, char type, int count, int ttl, - void *addresses, void *arg) -{ - dns_ok = dns_err = 0; - - if (result == DNS_ERR_TIMEOUT) { - printf("[Timed out] "); - dns_err = result; - goto out; - } - - if (result != DNS_ERR_NONE) { - printf("[Error code %d] ", result); - goto out; - } - - TT_BLATHER(("type: %d, count: %d, ttl: %d: ", type, count, ttl)); - - switch (type) { - case DNS_IPv6_AAAA: { -#if defined(EVENT__HAVE_STRUCT_IN6_ADDR) && defined(EVENT__HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN) - struct in6_addr *in6_addrs = addresses; - char buf[INET6_ADDRSTRLEN+1]; - int i; - /* a resolution that's not valid does not help */ - if (ttl < 0) - goto out; - for (i = 0; i < count; ++i) { - const char *b = evutil_inet_ntop(AF_INET6, &in6_addrs[i], buf,sizeof(buf)); - if (b) - TT_BLATHER(("%s ", b)); - else - TT_BLATHER(("%s ", strerror(errno))); - } -#endif - break; - } - case DNS_IPv4_A: { - struct in_addr *in_addrs = addresses; - int i; - /* a resolution that's not valid does not help */ - if (ttl < 0) - goto out; - for (i = 0; i < count; ++i) - TT_BLATHER(("%s ", inet_ntoa(in_addrs[i]))); - break; - } - case DNS_PTR: - /* may get at most one PTR */ - if (count != 1) - goto out; - - TT_BLATHER(("%s ", *(char **)addresses)); - break; - default: - goto out; - } - - dns_ok = type; - -out: - if (arg == NULL) - event_loopexit(NULL); - else - event_base_loopexit((struct event_base *)arg, NULL); -} - -static void -dns_gethostbyname(void) -{ - dns_ok = 0; - evdns_resolve_ipv4("www.monkey.org", 0, dns_gethostbyname_cb, NULL); - event_dispatch(); - - tt_int_op(dns_ok, ==, DNS_IPv4_A); - test_ok = dns_ok; -end: - ; -} - -static void -dns_gethostbyname6(void) -{ - dns_ok = 0; - evdns_resolve_ipv6("www.ietf.org", 0, dns_gethostbyname_cb, NULL); - event_dispatch(); - - if (!dns_ok && dns_err == DNS_ERR_TIMEOUT) { - tt_skip(); - } - - tt_int_op(dns_ok, ==, DNS_IPv6_AAAA); - test_ok = 1; -end: - ; -} - -static void -dns_gethostbyaddr(void) -{ - struct in_addr in; - in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */ - dns_ok = 0; - evdns_resolve_reverse(&in, 0, dns_gethostbyname_cb, NULL); - event_dispatch(); - - tt_int_op(dns_ok, ==, DNS_PTR); - test_ok = dns_ok; -end: - ; -} - -static void -dns_resolve_reverse(void *ptr) -{ - struct in_addr in; - struct event_base *base = event_base_new(); - struct evdns_base *dns = evdns_base_new(base, 1/* init name servers */); - struct evdns_request *req = NULL; - - tt_assert(base); - tt_assert(dns); - in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */ - dns_ok = 0; - - req = evdns_base_resolve_reverse( - dns, &in, 0, dns_gethostbyname_cb, base); - tt_assert(req); - - event_base_dispatch(base); - - tt_int_op(dns_ok, ==, DNS_PTR); - -end: - if (dns) - evdns_base_free(dns, 0); - if (base) - event_base_free(base); -} - -static int n_server_responses = 0; - -static void -dns_server_request_cb(struct evdns_server_request *req, void *data) -{ - int i, r; - const char TEST_ARPA[] = "11.11.168.192.in-addr.arpa"; - const char TEST_IN6[] = - "f.e.f.e." "0.0.0.0." "0.0.0.0." "1.1.1.1." - "a.a.a.a." "0.0.0.0." "0.0.0.0." "0.f.f.f.ip6.arpa"; - - for (i = 0; i < req->nquestions; ++i) { - const int qtype = req->questions[i]->type; - const int qclass = req->questions[i]->dns_question_class; - const char *qname = req->questions[i]->name; - - struct in_addr ans; - ans.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */ - if (qtype == EVDNS_TYPE_A && - qclass == EVDNS_CLASS_INET && - !evutil_ascii_strcasecmp(qname, "zz.example.com")) { - r = evdns_server_request_add_a_reply(req, qname, - 1, &ans.s_addr, 12345); - if (r<0) - dns_ok = 0; - } else if (qtype == EVDNS_TYPE_AAAA && - qclass == EVDNS_CLASS_INET && - !evutil_ascii_strcasecmp(qname, "zz.example.com")) { - char addr6[17] = "abcdefghijklmnop"; - r = evdns_server_request_add_aaaa_reply(req, - qname, 1, addr6, 123); - if (r<0) - dns_ok = 0; - } else if (qtype == EVDNS_TYPE_PTR && - qclass == EVDNS_CLASS_INET && - !evutil_ascii_strcasecmp(qname, TEST_ARPA)) { - r = evdns_server_request_add_ptr_reply(req, NULL, - qname, "ZZ.EXAMPLE.COM", 54321); - if (r<0) - dns_ok = 0; - } else if (qtype == EVDNS_TYPE_PTR && - qclass == EVDNS_CLASS_INET && - !evutil_ascii_strcasecmp(qname, TEST_IN6)){ - r = evdns_server_request_add_ptr_reply(req, NULL, - qname, - "ZZ-INET6.EXAMPLE.COM", 54322); - if (r<0) - dns_ok = 0; - } else if (qtype == EVDNS_TYPE_A && - qclass == EVDNS_CLASS_INET && - !evutil_ascii_strcasecmp(qname, "drop.example.com")) { - if (evdns_server_request_drop(req)<0) - dns_ok = 0; - return; - } else { - printf("Unexpected question %d %d \"%s\" ", - qtype, qclass, qname); - dns_ok = 0; - } - } - r = evdns_server_request_respond(req, 0); - if (r<0) { - printf("Couldn't send reply. "); - dns_ok = 0; - } -} - -static void -dns_server_gethostbyname_cb(int result, char type, int count, int ttl, - void *addresses, void *arg) -{ - if (result == DNS_ERR_CANCEL) { - if (arg != (void*)(char*)90909) { - printf("Unexpected cancelation"); - dns_ok = 0; - } - dns_got_cancel = 1; - goto out; - } - if (result != DNS_ERR_NONE) { - printf("Unexpected result %d. ", result); - dns_ok = 0; - goto out; - } - if (count != 1) { - printf("Unexpected answer count %d. ", count); - dns_ok = 0; - goto out; - } - switch (type) { - case DNS_IPv4_A: { - struct in_addr *in_addrs = addresses; - if (in_addrs[0].s_addr != htonl(0xc0a80b0bUL) || ttl != 12345) { - printf("Bad IPv4 response \"%s\" %d. ", - inet_ntoa(in_addrs[0]), ttl); - dns_ok = 0; - goto out; - } - break; - } - case DNS_IPv6_AAAA: { -#if defined (EVENT__HAVE_STRUCT_IN6_ADDR) && defined(EVENT__HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN) - struct in6_addr *in6_addrs = addresses; - char buf[INET6_ADDRSTRLEN+1]; - if (memcmp(&in6_addrs[0].s6_addr, "abcdefghijklmnop", 16) - || ttl != 123) { - const char *b = evutil_inet_ntop(AF_INET6, &in6_addrs[0],buf,sizeof(buf)); - printf("Bad IPv6 response \"%s\" %d. ", b, ttl); - dns_ok = 0; - goto out; - } -#endif - break; - } - case DNS_PTR: { - char **addrs = addresses; - if (arg != (void*)6) { - if (strcmp(addrs[0], "ZZ.EXAMPLE.COM") || - ttl != 54321) { - printf("Bad PTR response \"%s\" %d. ", - addrs[0], ttl); - dns_ok = 0; - goto out; - } - } else { - if (strcmp(addrs[0], "ZZ-INET6.EXAMPLE.COM") || - ttl != 54322) { - printf("Bad ipv6 PTR response \"%s\" %d. ", - addrs[0], ttl); - dns_ok = 0; - goto out; - } - } - break; - } - default: - printf("Bad response type %d. ", type); - dns_ok = 0; - } - out: - if (++n_server_responses == 3) { - event_loopexit(NULL); - } -} - -static void -dns_server(void) -{ - evutil_socket_t sock=-1; - struct sockaddr_in my_addr; - struct sockaddr_storage ss; - ev_socklen_t slen; - struct evdns_server_port *port=NULL; - struct in_addr resolve_addr; - struct in6_addr resolve_addr6; - struct evdns_base *base=NULL; - struct evdns_request *req=NULL; - - dns_ok = 1; - - base = evdns_base_new(NULL, 0); - - /* Now configure a nameserver port. */ - 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 = 0; /* kernel picks */ - my_addr.sin_addr.s_addr = htonl(0x7f000001UL); - if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) { - tt_abort_perror("bind"); - } - slen = sizeof(ss); - if (getsockname(sock, (struct sockaddr*)&ss, &slen) < 0) { - tt_abort_perror("getsockname"); - } - - port = evdns_add_server_port(sock, 0, dns_server_request_cb, NULL); - - /* Add ourself as the only nameserver, and make sure we really are - * the only nameserver. */ - evdns_base_nameserver_sockaddr_add(base, (struct sockaddr*)&ss, slen, 0); - tt_int_op(evdns_base_count_nameservers(base), ==, 1); - { - struct sockaddr_storage ss2; - int slen2; - - memset(&ss2, 0, sizeof(ss2)); - - slen2 = evdns_base_get_nameserver_addr(base, 0, (struct sockaddr *)&ss2, 3); - tt_int_op(slen2, ==, slen); - tt_int_op(ss2.ss_family, ==, 0); - slen2 = evdns_base_get_nameserver_addr(base, 0, (struct sockaddr *)&ss2, sizeof(ss2)); - tt_int_op(slen2, ==, slen); - tt_mem_op(&ss2, ==, &ss, slen); - - slen2 = evdns_base_get_nameserver_addr(base, 1, (struct sockaddr *)&ss2, sizeof(ss2)); - tt_int_op(-1, ==, slen2); - } - - /* Send some queries. */ - evdns_base_resolve_ipv4(base, "zz.example.com", DNS_QUERY_NO_SEARCH, - dns_server_gethostbyname_cb, NULL); - evdns_base_resolve_ipv6(base, "zz.example.com", DNS_QUERY_NO_SEARCH, - dns_server_gethostbyname_cb, NULL); - resolve_addr.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */ - evdns_base_resolve_reverse(base, &resolve_addr, 0, - dns_server_gethostbyname_cb, NULL); - memcpy(resolve_addr6.s6_addr, - "\xff\xf0\x00\x00\x00\x00\xaa\xaa" - "\x11\x11\x00\x00\x00\x00\xef\xef", 16); - evdns_base_resolve_reverse_ipv6(base, &resolve_addr6, 0, - dns_server_gethostbyname_cb, (void*)6); - - req = evdns_base_resolve_ipv4(base, - "drop.example.com", DNS_QUERY_NO_SEARCH, - dns_server_gethostbyname_cb, (void*)(char*)90909); - - evdns_cancel_request(base, req); - - event_dispatch(); - - tt_assert(dns_got_cancel); - test_ok = dns_ok; - -end: - if (port) - evdns_close_server_port(port); - if (sock >= 0) - evutil_closesocket(sock); - if (base) - evdns_base_free(base, 0); -} - -static int n_replies_left; -static struct event_base *exit_base; -static struct evdns_server_port *exit_port; - -struct generic_dns_callback_result { - int result; - char type; - int count; - int ttl; - size_t addrs_len; - void *addrs; - char addrs_buf[256]; -}; - -static void -generic_dns_callback(int result, char type, int count, int ttl, void *addresses, - void *arg) -{ - size_t len; - struct generic_dns_callback_result *res = arg; - res->result = result; - res->type = type; - res->count = count; - res->ttl = ttl; - - if (type == DNS_IPv4_A) - len = count * 4; - else if (type == DNS_IPv6_AAAA) - len = count * 16; - else if (type == DNS_PTR) - len = strlen(addresses)+1; - else { - res->addrs_len = len = 0; - res->addrs = NULL; - } - if (len) { - res->addrs_len = len; - if (len > 256) - len = 256; - memcpy(res->addrs_buf, addresses, len); - res->addrs = res->addrs_buf; - } - - --n_replies_left; - if (n_replies_left == 0) { - if (exit_port) { - evdns_close_server_port(exit_port); - exit_port = NULL; - } else - event_base_loopexit(exit_base, NULL); - } -} - -static struct regress_dns_server_table search_table[] = { - { "host.a.example.com", "err", "3", 0, 0 }, - { "host.b.example.com", "err", "3", 0, 0 }, - { "host.c.example.com", "A", "11.22.33.44", 0, 0 }, - { "host2.a.example.com", "err", "3", 0, 0 }, - { "host2.b.example.com", "A", "200.100.0.100", 0, 0 }, - { "host2.c.example.com", "err", "3", 0, 0 }, - { "hostn.a.example.com", "errsoa", "0", 0, 0 }, - { "hostn.b.example.com", "errsoa", "3", 0, 0 }, - { "hostn.c.example.com", "err", "0", 0, 0 }, - - { "host", "err", "3", 0, 0 }, - { "host2", "err", "3", 0, 0 }, - { "*", "err", "3", 0, 0 }, - { NULL, NULL, NULL, 0, 0 } -}; -static void -dns_search_test_impl(void *arg, int lower) -{ - struct regress_dns_server_table table[ARRAY_SIZE(search_table)]; - struct basic_test_data *data = arg; - struct event_base *base = data->base; - struct evdns_base *dns = NULL; - ev_uint16_t portnum = 0; - char buf[64]; - - struct generic_dns_callback_result r[8]; - size_t i; - - for (i = 0; i < ARRAY_SIZE(table); ++i) { - table[i] = search_table[i]; - table[i].lower = lower; - } - - tt_assert(regress_dnsserver(base, &portnum, table)); - evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); - - dns = evdns_base_new(base, 0); - tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); - - evdns_base_search_add(dns, "a.example.com"); - evdns_base_search_add(dns, "b.example.com"); - evdns_base_search_add(dns, "c.example.com"); - - n_replies_left = ARRAY_SIZE(r); - exit_base = base; - - evdns_base_resolve_ipv4(dns, "host", 0, generic_dns_callback, &r[0]); - evdns_base_resolve_ipv4(dns, "host2", 0, generic_dns_callback, &r[1]); - evdns_base_resolve_ipv4(dns, "host", DNS_NO_SEARCH, generic_dns_callback, &r[2]); - evdns_base_resolve_ipv4(dns, "host2", DNS_NO_SEARCH, generic_dns_callback, &r[3]); - evdns_base_resolve_ipv4(dns, "host3", 0, generic_dns_callback, &r[4]); - evdns_base_resolve_ipv4(dns, "hostn.a.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[5]); - evdns_base_resolve_ipv4(dns, "hostn.b.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[6]); - evdns_base_resolve_ipv4(dns, "hostn.c.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[7]); - - event_base_dispatch(base); - - tt_int_op(r[0].type, ==, DNS_IPv4_A); - tt_int_op(r[0].count, ==, 1); - tt_int_op(((ev_uint32_t*)r[0].addrs)[0], ==, htonl(0x0b16212c)); - tt_int_op(r[1].type, ==, DNS_IPv4_A); - tt_int_op(r[1].count, ==, 1); - tt_int_op(((ev_uint32_t*)r[1].addrs)[0], ==, htonl(0xc8640064)); - tt_int_op(r[2].result, ==, DNS_ERR_NOTEXIST); - tt_int_op(r[3].result, ==, DNS_ERR_NOTEXIST); - tt_int_op(r[4].result, ==, DNS_ERR_NOTEXIST); - tt_int_op(r[5].result, ==, DNS_ERR_NODATA); - tt_int_op(r[5].ttl, ==, 42); - tt_int_op(r[6].result, ==, DNS_ERR_NOTEXIST); - tt_int_op(r[6].ttl, ==, 42); - tt_int_op(r[7].result, ==, DNS_ERR_NODATA); - tt_int_op(r[7].ttl, ==, 0); - -end: - if (dns) - evdns_base_free(dns, 0); - - regress_clean_dnsserver(); -} -static void -dns_search_test(void *arg) -{ - return dns_search_test_impl(arg, 0); -} -static void -dns_search_lower_test(void *arg) -{ - return dns_search_test_impl(arg, 1); -} - -static int request_count = 0; -static struct evdns_request *current_req = NULL; - -static void -search_cancel_server_cb(struct evdns_server_request *req, void *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; - - TT_BLATHER(("got question, %s", question)); - - tt_assert(request_count > 0); - tt_assert(!evdns_server_request_respond(req, 3)); - - if (!--request_count) - evdns_cancel_request(NULL, current_req); - -end: - ; -} - -static void -dns_search_cancel_test(void *arg) -{ - struct basic_test_data *data = arg; - struct event_base *base = data->base; - struct evdns_base *dns = NULL; - struct evdns_server_port *port = NULL; - ev_uint16_t portnum = 0; - struct generic_dns_callback_result r1; - char buf[64]; - - port = regress_get_dnsserver(base, &portnum, NULL, - search_cancel_server_cb, NULL); - tt_assert(port); - evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); - - dns = evdns_base_new(base, 0); - tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); - - evdns_base_search_add(dns, "a.example.com"); - evdns_base_search_add(dns, "b.example.com"); - evdns_base_search_add(dns, "c.example.com"); - evdns_base_search_add(dns, "d.example.com"); - - exit_base = base; - request_count = 3; - n_replies_left = 1; - - current_req = evdns_base_resolve_ipv4(dns, "host", 0, - generic_dns_callback, &r1); - event_base_dispatch(base); - - tt_int_op(r1.result, ==, DNS_ERR_CANCEL); - -end: - if (port) - evdns_close_server_port(port); - if (dns) - evdns_base_free(dns, 0); -} - -static void -fail_server_cb(struct evdns_server_request *req, void *data) -{ - const char *question; - int *count = data; - struct in_addr in; - - /* Drop the first N requests that we get. */ - if (*count > 0) { - --*count; - tt_want(! evdns_server_request_drop(req)); - return; - } - - if (req->nquestions != 1) - TT_DIE(("Only handling one question at a time; got %d", - req->nquestions)); - - question = req->questions[0]->name; - - if (!evutil_ascii_strcasecmp(question, "google.com")) { - /* Detect a probe, and get out of the loop. */ - event_base_loopexit(exit_base, NULL); - } - - tt_assert(evutil_inet_pton(AF_INET, "16.32.64.128", &in)); - evdns_server_request_add_a_reply(req, question, 1, &in.s_addr, - 100); - tt_assert(! evdns_server_request_respond(req, 0)) - return; -end: - tt_want(! evdns_server_request_drop(req)); -} - -static void -dns_retry_test_impl(void *arg, int flags) -{ - struct basic_test_data *data = arg; - struct event_base *base = data->base; - struct evdns_server_port *port = NULL; - struct evdns_base *dns = NULL; - int drop_count = 2; - ev_uint16_t portnum = 0; - char buf[64]; - - struct generic_dns_callback_result r1; - - port = regress_get_dnsserver(base, &portnum, NULL, - fail_server_cb, &drop_count); - tt_assert(port); - evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); - - dns = evdns_base_new(base, flags); - tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); - tt_assert(! evdns_base_set_option(dns, "timeout", "0.2")); - tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "10")); - tt_assert(! evdns_base_set_option(dns, "initial-probe-timeout", "0.1")); - - evdns_base_resolve_ipv4(dns, "host.example.com", 0, - generic_dns_callback, &r1); - - n_replies_left = 1; - exit_base = base; - - event_base_dispatch(base); - - tt_int_op(drop_count, ==, 0); - - tt_int_op(r1.type, ==, DNS_IPv4_A); - tt_int_op(r1.count, ==, 1); - tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x10204080)); - - /* Now try again, but this time have the server get treated as - * failed, so we can send it a test probe. */ - drop_count = 4; - tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "2")); - tt_assert(! evdns_base_set_option(dns, "attempts:", "3")); - memset(&r1, 0, sizeof(r1)); - - evdns_base_resolve_ipv4(dns, "host.example.com", 0, - generic_dns_callback, &r1); - - n_replies_left = 2; - - /* This will run until it answers the "google.com" probe request. */ - event_base_dispatch(base); - - /* We'll treat the server as failed here. */ - tt_int_op(r1.result, ==, DNS_ERR_TIMEOUT); - - /* It should work this time. */ - tt_int_op(drop_count, ==, 0); - evdns_base_resolve_ipv4(dns, "host.example.com", 0, - generic_dns_callback, &r1); - - event_base_dispatch(base); - tt_int_op(r1.result, ==, DNS_ERR_NONE); - tt_int_op(r1.type, ==, DNS_IPv4_A); - tt_int_op(r1.count, ==, 1); - tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x10204080)); - -end: - if (dns) - evdns_base_free(dns, 0); - if (port) - evdns_close_server_port(port); -} -static void -dns_retry_test(void *arg) -{ - dns_retry_test_impl(arg, 0); -} -static void -dns_retry_disable_when_inactive_test(void *arg) -{ - dns_retry_test_impl(arg, EVDNS_BASE_DISABLE_WHEN_INACTIVE); -} - -static struct regress_dns_server_table internal_error_table[] = { - /* Error 4 (NOTIMPL) makes us reissue the request to another server - if we can. - - XXXX we should reissue under a much wider set of circumstances! - */ - { "foof.example.com", "err", "4", 0, 0 }, - { NULL, NULL, NULL, 0, 0 } -}; - -static struct regress_dns_server_table reissue_table[] = { - { "foof.example.com", "A", "240.15.240.15", 0, 0 }, - { NULL, NULL, NULL, 0, 0 } -}; - -static void -dns_reissue_test_impl(void *arg, int flags) -{ - struct basic_test_data *data = arg; - struct event_base *base = data->base; - struct evdns_server_port *port1 = NULL, *port2 = NULL; - struct evdns_base *dns = NULL; - struct generic_dns_callback_result r1; - ev_uint16_t portnum1 = 0, portnum2=0; - char buf1[64], buf2[64]; - - port1 = regress_get_dnsserver(base, &portnum1, NULL, - regress_dns_server_cb, internal_error_table); - tt_assert(port1); - port2 = regress_get_dnsserver(base, &portnum2, NULL, - regress_dns_server_cb, reissue_table); - tt_assert(port2); - evutil_snprintf(buf1, sizeof(buf1), "127.0.0.1:%d", (int)portnum1); - evutil_snprintf(buf2, sizeof(buf2), "127.0.0.1:%d", (int)portnum2); - - dns = evdns_base_new(base, flags); - tt_assert(!evdns_base_nameserver_ip_add(dns, buf1)); - tt_assert(! evdns_base_set_option(dns, "timeout:", "0.3")); - tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "2")); - tt_assert(! evdns_base_set_option(dns, "attempts:", "5")); - - memset(&r1, 0, sizeof(r1)); - evdns_base_resolve_ipv4(dns, "foof.example.com", 0, - generic_dns_callback, &r1); - - /* Add this after, so that we are sure to get a reissue. */ - tt_assert(!evdns_base_nameserver_ip_add(dns, buf2)); - - n_replies_left = 1; - exit_base = base; - - event_base_dispatch(base); - tt_int_op(r1.result, ==, DNS_ERR_NONE); - tt_int_op(r1.type, ==, DNS_IPv4_A); - tt_int_op(r1.count, ==, 1); - tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0xf00ff00f)); - - /* Make sure we dropped at least once. */ - tt_int_op(internal_error_table[0].seen, >, 0); - -end: - if (dns) - evdns_base_free(dns, 0); - if (port1) - evdns_close_server_port(port1); - if (port2) - evdns_close_server_port(port2); -} -static void -dns_reissue_test(void *arg) -{ - dns_reissue_test_impl(arg, 0); -} -static void -dns_reissue_disable_when_inactive_test(void *arg) -{ - dns_reissue_test_impl(arg, EVDNS_BASE_DISABLE_WHEN_INACTIVE); -} - -#if 0 -static void -dumb_bytes_fn(char *p, size_t n) -{ - unsigned i; - /* This gets us 6 bits of entropy per transaction ID, which means we - * will have probably have collisions and need to pick again. */ - for (i=0;ibase; - struct evdns_base *dns = NULL; - struct evdns_server_port *dns_port = NULL; - ev_uint16_t portnum = 0; - char buf[64]; - int disable_when_inactive = flags & EVDNS_BASE_DISABLE_WHEN_INACTIVE; - - struct generic_dns_callback_result r[20]; - int i; - - dns_port = regress_get_dnsserver(base, &portnum, NULL, - regress_dns_server_cb, reissue_table); - tt_assert(dns_port); - if (disable_when_inactive) { - exit_port = dns_port; - } - - evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); - - dns = evdns_base_new(base, flags); - tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); - tt_assert(! evdns_base_set_option(dns, "max-inflight:", "3")); - tt_assert(! evdns_base_set_option(dns, "randomize-case:", "0")); - - for (i=0;i<20;++i) - evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r[i]); - - n_replies_left = 20; - exit_base = base; - - event_base_dispatch(base); - - for (i=0;i<20;++i) { - tt_int_op(r[i].type, ==, DNS_IPv4_A); - tt_int_op(r[i].count, ==, 1); - tt_int_op(((ev_uint32_t*)r[i].addrs)[0], ==, htonl(0xf00ff00f)); - } - -end: - if (dns) - evdns_base_free(dns, 0); - if (exit_port) { - evdns_close_server_port(exit_port); - exit_port = NULL; - } else if (! disable_when_inactive) { - evdns_close_server_port(dns_port); - } -} - -static void -dns_inflight_test(void *arg) -{ - dns_inflight_test_impl(arg, 0); -} - -static void -dns_disable_when_inactive_test(void *arg) -{ - dns_inflight_test_impl(arg, EVDNS_BASE_DISABLE_WHEN_INACTIVE); -} - -static void -dns_disable_when_inactive_no_ns_test(void *arg) -{ - struct basic_test_data *data = arg; - struct event_base *base = data->base, *inactive_base; - struct evdns_base *dns = NULL; - ev_uint16_t portnum = 0; - char buf[64]; - struct generic_dns_callback_result r; - - inactive_base = event_base_new(); - tt_assert(inactive_base); - - /** Create dns server with inactive base, to avoid replying to clients */ - tt_assert(regress_dnsserver(inactive_base, &portnum, search_table)); - evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); - - dns = evdns_base_new(base, EVDNS_BASE_DISABLE_WHEN_INACTIVE); - tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); - tt_assert(! evdns_base_set_option(dns, "timeout:", "0.1")); - - evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r); - n_replies_left = 1; - exit_base = base; - - event_base_dispatch(base); - - tt_int_op(n_replies_left, ==, 0); - - tt_int_op(r.result, ==, DNS_ERR_TIMEOUT); - tt_int_op(r.count, ==, 0); - tt_ptr_op(r.addrs, ==, NULL); - -end: - if (dns) - evdns_base_free(dns, 0); - regress_clean_dnsserver(); - if (inactive_base) - event_base_free(inactive_base); -} - -/* === Test for bufferevent_socket_connect_hostname */ - -static int total_connected_or_failed = 0; -static int total_n_accepted = 0; -static struct event_base *be_connect_hostname_base = NULL; - -/* Implements a DNS server for the connect_hostname test and the - * getaddrinfo_async test */ -static void -be_getaddrinfo_server_cb(struct evdns_server_request *req, void *data) -{ - int i; - int *n_got_p=data; - int added_any=0; - ++*n_got_p; - - for (i=0;inquestions;++i) { - const int qtype = req->questions[i]->type; - const int qclass = req->questions[i]->dns_question_class; - const char *qname = req->questions[i]->name; - struct in_addr ans; - struct in6_addr ans6; - memset(&ans6, 0, sizeof(ans6)); - - TT_BLATHER(("Got question about %s, type=%d", qname, qtype)); - - if (qtype == EVDNS_TYPE_A && - qclass == EVDNS_CLASS_INET && - !evutil_ascii_strcasecmp(qname, "nobodaddy.example.com")) { - ans.s_addr = htonl(0x7f000001); - evdns_server_request_add_a_reply(req, qname, - 1, &ans.s_addr, 2000); - added_any = 1; - } else if (!evutil_ascii_strcasecmp(qname, - "nosuchplace.example.com")) { - /* ok, just say notfound. */ - } else if (!evutil_ascii_strcasecmp(qname, - "both.example.com")) { - if (qtype == EVDNS_TYPE_A) { - ans.s_addr = htonl(0x50502020); - evdns_server_request_add_a_reply(req, qname, - 1, &ans.s_addr, 2000); - added_any = 1; - } else if (qtype == EVDNS_TYPE_AAAA) { - ans6.s6_addr[0] = 0x80; - ans6.s6_addr[1] = 0xff; - ans6.s6_addr[14] = 0xbb; - ans6.s6_addr[15] = 0xbb; - evdns_server_request_add_aaaa_reply(req, qname, - 1, &ans6.s6_addr, 2000); - added_any = 1; - } - evdns_server_request_add_cname_reply(req, qname, - "both-canonical.example.com", 1000); - } else if (!evutil_ascii_strcasecmp(qname, - "v4only.example.com") || - !evutil_ascii_strcasecmp(qname, "v4assert.example.com")) { - if (qtype == EVDNS_TYPE_A) { - ans.s_addr = htonl(0x12345678); - evdns_server_request_add_a_reply(req, qname, - 1, &ans.s_addr, 2000); - added_any = 1; - } else if (!evutil_ascii_strcasecmp(qname, - "v4assert.example.com")) { - TT_FAIL(("Got an AAAA request for v4assert")); - } - } else if (!evutil_ascii_strcasecmp(qname, - "v6only.example.com") || - !evutil_ascii_strcasecmp(qname, "v6assert.example.com")) { - if (qtype == EVDNS_TYPE_AAAA) { - ans6.s6_addr[0] = 0x0b; - ans6.s6_addr[1] = 0x0b; - ans6.s6_addr[14] = 0xf0; - ans6.s6_addr[15] = 0x0d; - evdns_server_request_add_aaaa_reply(req, qname, - 1, &ans6.s6_addr, 2000); - added_any = 1; - } else if (!evutil_ascii_strcasecmp(qname, - "v6assert.example.com")) { - TT_FAIL(("Got a A request for v6assert")); - } - } else if (!evutil_ascii_strcasecmp(qname, - "v6timeout.example.com")) { - if (qtype == EVDNS_TYPE_A) { - ans.s_addr = htonl(0xabcdef01); - evdns_server_request_add_a_reply(req, qname, - 1, &ans.s_addr, 2000); - added_any = 1; - } else if (qtype == EVDNS_TYPE_AAAA) { - /* Let the v6 request time out.*/ - evdns_server_request_drop(req); - return; - } - } else if (!evutil_ascii_strcasecmp(qname, - "v4timeout.example.com")) { - if (qtype == EVDNS_TYPE_AAAA) { - ans6.s6_addr[0] = 0x0a; - ans6.s6_addr[1] = 0x0a; - ans6.s6_addr[14] = 0xff; - ans6.s6_addr[15] = 0x01; - evdns_server_request_add_aaaa_reply(req, qname, - 1, &ans6.s6_addr, 2000); - added_any = 1; - } else if (qtype == EVDNS_TYPE_A) { - /* Let the v4 request time out.*/ - evdns_server_request_drop(req); - return; - } - } else if (!evutil_ascii_strcasecmp(qname, - "v6timeout-nonexist.example.com")) { - if (qtype == EVDNS_TYPE_A) { - /* Fall through, give an nexist. */ - } else if (qtype == EVDNS_TYPE_AAAA) { - /* Let the v6 request time out.*/ - evdns_server_request_drop(req); - return; - } - } else if (!evutil_ascii_strcasecmp(qname, - "all-timeout.example.com")) { - /* drop all requests */ - evdns_server_request_drop(req); - return; - } else { - TT_GRIPE(("Got weird request for %s",qname)); - } - } - if (added_any) { - TT_BLATHER(("answering")); - evdns_server_request_respond(req, 0); - } else { - TT_BLATHER(("saying nexist.")); - evdns_server_request_respond(req, 3); - } -} - -/* Implements a listener for connect_hostname test. */ -static void -nil_accept_cb(struct evconnlistener *l, evutil_socket_t fd, struct sockaddr *s, - int socklen, void *arg) -{ - int *p = arg; - (*p)++; - ++total_n_accepted; - /* don't do anything with the socket; let it close when we exit() */ - if (total_n_accepted >= 3 && total_connected_or_failed >= 5) - event_base_loopexit(be_connect_hostname_base, - NULL); -} - -struct be_conn_hostname_result { - int dnserr; - int what; -}; - -/* Bufferevent event callback for the connect_hostname test: remembers what - * event we got. */ -static void -be_connect_hostname_event_cb(struct bufferevent *bev, short what, void *ctx) -{ - struct be_conn_hostname_result *got = ctx; - if (!got->what) { - TT_BLATHER(("Got a bufferevent event %d", what)); - got->what = what; - - if ((what & BEV_EVENT_CONNECTED) || (what & BEV_EVENT_ERROR)) { - int r; - if ((r = bufferevent_socket_get_dns_error(bev))) { - got->dnserr = r; - TT_BLATHER(("DNS error %d: %s", r, - evutil_gai_strerror(r))); - } ++total_connected_or_failed; - TT_BLATHER(("Got %d connections or errors.", total_connected_or_failed)); - - if (total_n_accepted >= 3 && total_connected_or_failed >= 5) - event_base_loopexit(be_connect_hostname_base, - NULL); - } - } else { - TT_FAIL(("Two events on one bufferevent. %d,%d", - got->what, (int)what)); - } -} - -static void -test_bufferevent_connect_hostname(void *arg) -{ - struct basic_test_data *data = arg; - struct evconnlistener *listener = NULL; - struct bufferevent *be1=NULL, *be2=NULL, *be3=NULL, *be4=NULL, *be5=NULL; - struct be_conn_hostname_result be1_outcome={0,0}, be2_outcome={0,0}, - be3_outcome={0,0}, be4_outcome={0,0}, be5_outcome={0,0}; - int expect_err5; - struct evdns_base *dns=NULL; - struct evdns_server_port *port=NULL; - struct sockaddr_in sin; - int listener_port=-1; - ev_uint16_t dns_port=0; - int n_accept=0, n_dns=0; - char buf[128]; - - be_connect_hostname_base = data->base; - - /* Bind an address and figure out what port it's on. */ - 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; - listener = evconnlistener_new_bind(data->base, nil_accept_cb, - &n_accept, - LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC, - -1, (struct sockaddr *)&sin, sizeof(sin)); - tt_assert(listener); - listener_port = regress_get_socket_port( - evconnlistener_get_fd(listener)); - - port = regress_get_dnsserver(data->base, &dns_port, NULL, - be_getaddrinfo_server_cb, &n_dns); - tt_assert(port); - tt_int_op(dns_port, >=, 0); - - /* Start an evdns_base that uses the server as its resolver. */ - dns = evdns_base_new(data->base, 0); - evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)dns_port); - evdns_base_nameserver_ip_add(dns, buf); - - /* Now, finally, at long last, launch the bufferevents. One should do - * a failing lookup IP, one should do a successful lookup by IP, - * and one should do a successful lookup by hostname. */ - be1 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); - be2 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); - be3 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); - be4 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); - be5 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); - - bufferevent_setcb(be1, NULL, NULL, be_connect_hostname_event_cb, - &be1_outcome); - bufferevent_setcb(be2, NULL, NULL, be_connect_hostname_event_cb, - &be2_outcome); - bufferevent_setcb(be3, NULL, NULL, be_connect_hostname_event_cb, - &be3_outcome); - bufferevent_setcb(be4, NULL, NULL, be_connect_hostname_event_cb, - &be4_outcome); - bufferevent_setcb(be5, NULL, NULL, be_connect_hostname_event_cb, - &be5_outcome); - - /* Launch an async resolve that will fail. */ - tt_assert(!bufferevent_socket_connect_hostname(be1, dns, AF_INET, - "nosuchplace.example.com", listener_port)); - /* Connect to the IP without resolving. */ - tt_assert(!bufferevent_socket_connect_hostname(be2, dns, AF_INET, - "127.0.0.1", listener_port)); - /* Launch an async resolve that will succeed. */ - tt_assert(!bufferevent_socket_connect_hostname(be3, dns, AF_INET, - "nobodaddy.example.com", listener_port)); - /* Use the blocking resolver. This one will fail if your resolver - * can't resolve localhost to 127.0.0.1 */ - tt_assert(!bufferevent_socket_connect_hostname(be4, NULL, AF_INET, - "localhost", listener_port)); - /* Use the blocking resolver with a nonexistent hostname. */ - tt_assert(!bufferevent_socket_connect_hostname(be5, NULL, AF_INET, - "nonesuch.nowhere.example.com", 80)); - { - /* The blocking resolver will use the system nameserver, which - * might tell us anything. (Yes, some twits even pretend that - * example.com is real.) Let's see what answer to expect. */ - struct evutil_addrinfo hints, *ai = NULL; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - expect_err5 = evutil_getaddrinfo( - "nonesuch.nowhere.example.com", "80", &hints, &ai); - } - - event_base_dispatch(data->base); - - tt_int_op(be1_outcome.what, ==, BEV_EVENT_ERROR); - tt_int_op(be1_outcome.dnserr, ==, EVUTIL_EAI_NONAME); - tt_int_op(be2_outcome.what, ==, BEV_EVENT_CONNECTED); - tt_int_op(be2_outcome.dnserr, ==, 0); - tt_int_op(be3_outcome.what, ==, BEV_EVENT_CONNECTED); - tt_int_op(be3_outcome.dnserr, ==, 0); - tt_int_op(be4_outcome.what, ==, BEV_EVENT_CONNECTED); - tt_int_op(be4_outcome.dnserr, ==, 0); - if (expect_err5) { - tt_int_op(be5_outcome.what, ==, BEV_EVENT_ERROR); - tt_int_op(be5_outcome.dnserr, ==, expect_err5); - } - - tt_int_op(n_accept, ==, 3); - tt_int_op(n_dns, ==, 2); - -end: - if (listener) - evconnlistener_free(listener); - if (port) - evdns_close_server_port(port); - if (dns) - evdns_base_free(dns, 0); - if (be1) - bufferevent_free(be1); - if (be2) - bufferevent_free(be2); - if (be3) - bufferevent_free(be3); - if (be4) - bufferevent_free(be4); - if (be5) - bufferevent_free(be5); -} - - -struct gai_outcome { - int err; - struct evutil_addrinfo *ai; -}; - -static int n_gai_results_pending = 0; -static struct event_base *exit_base_on_no_pending_results = NULL; - -static void -gai_cb(int err, struct evutil_addrinfo *res, void *ptr) -{ - struct gai_outcome *go = ptr; - go->err = err; - go->ai = res; - if (--n_gai_results_pending <= 0 && exit_base_on_no_pending_results) - event_base_loopexit(exit_base_on_no_pending_results, NULL); - if (n_gai_results_pending < 900) - TT_BLATHER(("Got an answer; expecting %d more.", - n_gai_results_pending)); -} - -static void -cancel_gai_cb(evutil_socket_t fd, short what, void *ptr) -{ - struct evdns_getaddrinfo_request *r = ptr; - evdns_getaddrinfo_cancel(r); -} - -static void -test_getaddrinfo_async(void *arg) -{ - struct basic_test_data *data = arg; - struct evutil_addrinfo hints, *a; - struct gai_outcome local_outcome; - struct gai_outcome a_out[12]; - int i; - struct evdns_getaddrinfo_request *r; - char buf[128]; - struct evdns_server_port *port = NULL; - ev_uint16_t dns_port = 0; - int n_dns_questions = 0; - struct evdns_base *dns_base; - - memset(a_out, 0, sizeof(a_out)); - memset(&local_outcome, 0, sizeof(local_outcome)); - - dns_base = evdns_base_new(data->base, 0); - tt_assert(dns_base); - - /* for localhost */ - evdns_base_load_hosts(dns_base, NULL); - - tt_assert(! evdns_base_set_option(dns_base, "timeout", "0.3")); - tt_assert(! evdns_base_set_option(dns_base, "getaddrinfo-allow-skew", "0.2")); - - n_gai_results_pending = 10000; /* don't think about exiting yet. */ - - /* 1. Try some cases that will never hit the asynchronous resolver. */ - /* 1a. Simple case with a symbolic service name */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - memset(&local_outcome, 0, sizeof(local_outcome)); - r = evdns_getaddrinfo(dns_base, "1.2.3.4", "http", - &hints, gai_cb, &local_outcome); - tt_assert(! r); - if (!local_outcome.err) { - tt_ptr_op(local_outcome.ai,!=,NULL); - test_ai_eq(local_outcome.ai, "1.2.3.4:80", SOCK_STREAM, IPPROTO_TCP); - evutil_freeaddrinfo(local_outcome.ai); - local_outcome.ai = NULL; - } else { - TT_BLATHER(("Apparently we have no getservbyname.")); - } - - /* 1b. EVUTIL_AI_NUMERICHOST is set */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_flags = EVUTIL_AI_NUMERICHOST; - memset(&local_outcome, 0, sizeof(local_outcome)); - r = evdns_getaddrinfo(dns_base, "www.google.com", "80", - &hints, gai_cb, &local_outcome); - tt_ptr_op(r,==,NULL); - tt_int_op(local_outcome.err,==,EVUTIL_EAI_NONAME); - tt_ptr_op(local_outcome.ai,==,NULL); - - /* 1c. We give a numeric address (ipv6) */ - memset(&hints, 0, sizeof(hints)); - memset(&local_outcome, 0, sizeof(local_outcome)); - hints.ai_family = PF_UNSPEC; - hints.ai_protocol = IPPROTO_TCP; - r = evdns_getaddrinfo(dns_base, "f::f", "8008", - &hints, gai_cb, &local_outcome); - tt_assert(!r); - tt_int_op(local_outcome.err,==,0); - tt_assert(local_outcome.ai); - tt_ptr_op(local_outcome.ai->ai_next,==,NULL); - test_ai_eq(local_outcome.ai, "[f::f]:8008", SOCK_STREAM, IPPROTO_TCP); - evutil_freeaddrinfo(local_outcome.ai); - local_outcome.ai = NULL; - - /* 1d. We give a numeric address (ipv4) */ - memset(&hints, 0, sizeof(hints)); - memset(&local_outcome, 0, sizeof(local_outcome)); - hints.ai_family = PF_UNSPEC; - r = evdns_getaddrinfo(dns_base, "5.6.7.8", NULL, - &hints, gai_cb, &local_outcome); - tt_assert(!r); - tt_int_op(local_outcome.err,==,0); - tt_assert(local_outcome.ai); - a = ai_find_by_protocol(local_outcome.ai, IPPROTO_TCP); - tt_assert(a); - test_ai_eq(a, "5.6.7.8", SOCK_STREAM, IPPROTO_TCP); - a = ai_find_by_protocol(local_outcome.ai, IPPROTO_UDP); - tt_assert(a); - test_ai_eq(a, "5.6.7.8", SOCK_DGRAM, IPPROTO_UDP); - evutil_freeaddrinfo(local_outcome.ai); - local_outcome.ai = NULL; - - /* 1e. nodename is NULL (bind) */ - memset(&hints, 0, sizeof(hints)); - memset(&local_outcome, 0, sizeof(local_outcome)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = EVUTIL_AI_PASSIVE; - r = evdns_getaddrinfo(dns_base, NULL, "9090", - &hints, gai_cb, &local_outcome); - tt_assert(!r); - tt_int_op(local_outcome.err,==,0); - tt_assert(local_outcome.ai); - /* we should get a v4 address of 0.0.0.0... */ - a = ai_find_by_family(local_outcome.ai, PF_INET); - tt_assert(a); - test_ai_eq(a, "0.0.0.0:9090", SOCK_DGRAM, IPPROTO_UDP); - /* ... and a v6 address of ::0 */ - a = ai_find_by_family(local_outcome.ai, PF_INET6); - tt_assert(a); - test_ai_eq(a, "[::]:9090", SOCK_DGRAM, IPPROTO_UDP); - evutil_freeaddrinfo(local_outcome.ai); - local_outcome.ai = NULL; - - /* 1f. nodename is NULL (connect) */ - memset(&hints, 0, sizeof(hints)); - memset(&local_outcome, 0, sizeof(local_outcome)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - r = evdns_getaddrinfo(dns_base, NULL, "2", - &hints, gai_cb, &local_outcome); - tt_assert(!r); - tt_int_op(local_outcome.err,==,0); - tt_assert(local_outcome.ai); - /* we should get a v4 address of 127.0.0.1 .... */ - a = ai_find_by_family(local_outcome.ai, PF_INET); - tt_assert(a); - test_ai_eq(a, "127.0.0.1:2", SOCK_STREAM, IPPROTO_TCP); - /* ... and a v6 address of ::1 */ - a = ai_find_by_family(local_outcome.ai, PF_INET6); - tt_assert(a); - test_ai_eq(a, "[::1]:2", SOCK_STREAM, IPPROTO_TCP); - evutil_freeaddrinfo(local_outcome.ai); - local_outcome.ai = NULL; - - /* 1g. We find localhost immediately. (pf_unspec) */ - memset(&hints, 0, sizeof(hints)); - memset(&local_outcome, 0, sizeof(local_outcome)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - r = evdns_getaddrinfo(dns_base, "LOCALHOST", "80", - &hints, gai_cb, &local_outcome); - tt_assert(!r); - tt_int_op(local_outcome.err,==,0); - tt_assert(local_outcome.ai); - /* we should get a v4 address of 127.0.0.1 .... */ - a = ai_find_by_family(local_outcome.ai, PF_INET); - tt_assert(a); - test_ai_eq(a, "127.0.0.1:80", SOCK_STREAM, IPPROTO_TCP); - /* ... and a v6 address of ::1 */ - a = ai_find_by_family(local_outcome.ai, PF_INET6); - tt_assert(a); - test_ai_eq(a, "[::1]:80", SOCK_STREAM, IPPROTO_TCP); - evutil_freeaddrinfo(local_outcome.ai); - local_outcome.ai = NULL; - - /* 1g. We find localhost immediately. (pf_inet6) */ - memset(&hints, 0, sizeof(hints)); - memset(&local_outcome, 0, sizeof(local_outcome)); - hints.ai_family = PF_INET6; - hints.ai_socktype = SOCK_STREAM; - r = evdns_getaddrinfo(dns_base, "LOCALHOST", "9999", - &hints, gai_cb, &local_outcome); - tt_assert(! r); - tt_int_op(local_outcome.err,==,0); - tt_assert(local_outcome.ai); - a = local_outcome.ai; - test_ai_eq(a, "[::1]:9999", SOCK_STREAM, IPPROTO_TCP); - tt_ptr_op(a->ai_next, ==, NULL); - evutil_freeaddrinfo(local_outcome.ai); - local_outcome.ai = NULL; - - /* 2. Okay, now we can actually test the asynchronous resolver. */ - /* Start a dummy local dns server... */ - port = regress_get_dnsserver(data->base, &dns_port, NULL, - be_getaddrinfo_server_cb, &n_dns_questions); - tt_assert(port); - tt_int_op(dns_port, >=, 0); - /* ... and tell the evdns_base about it. */ - evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", dns_port); - evdns_base_nameserver_ip_add(dns_base, buf); - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = EVUTIL_AI_CANONNAME; - /* 0: Request for both.example.com should return both addresses. */ - r = evdns_getaddrinfo(dns_base, "both.example.com", "8000", - &hints, gai_cb, &a_out[0]); - tt_assert(r); - - /* 1: Request for v4only.example.com should return one address. */ - r = evdns_getaddrinfo(dns_base, "v4only.example.com", "8001", - &hints, gai_cb, &a_out[1]); - tt_assert(r); - - /* 2: Request for v6only.example.com should return one address. */ - hints.ai_flags = 0; - r = evdns_getaddrinfo(dns_base, "v6only.example.com", "8002", - &hints, gai_cb, &a_out[2]); - tt_assert(r); - - /* 3: PF_INET request for v4assert.example.com should not generate a - * v6 request. The server will fail the test if it does. */ - hints.ai_family = PF_INET; - r = evdns_getaddrinfo(dns_base, "v4assert.example.com", "8003", - &hints, gai_cb, &a_out[3]); - tt_assert(r); - - /* 4: PF_INET6 request for v6assert.example.com should not generate a - * v4 request. The server will fail the test if it does. */ - hints.ai_family = PF_INET6; - r = evdns_getaddrinfo(dns_base, "v6assert.example.com", "8004", - &hints, gai_cb, &a_out[4]); - tt_assert(r); - - /* 5: PF_INET request for nosuchplace.example.com should give NEXIST. */ - hints.ai_family = PF_INET; - r = evdns_getaddrinfo(dns_base, "nosuchplace.example.com", "8005", - &hints, gai_cb, &a_out[5]); - tt_assert(r); - - /* 6: PF_UNSPEC request for nosuchplace.example.com should give NEXIST. - */ - hints.ai_family = PF_UNSPEC; - r = evdns_getaddrinfo(dns_base, "nosuchplace.example.com", "8006", - &hints, gai_cb, &a_out[6]); - tt_assert(r); - - /* 7: PF_UNSPEC request for v6timeout.example.com should give an ipv4 - * address only. */ - hints.ai_family = PF_UNSPEC; - r = evdns_getaddrinfo(dns_base, "v6timeout.example.com", "8007", - &hints, gai_cb, &a_out[7]); - tt_assert(r); - - /* 8: PF_UNSPEC request for v6timeout-nonexist.example.com should give - * a NEXIST */ - hints.ai_family = PF_UNSPEC; - r = evdns_getaddrinfo(dns_base, "v6timeout-nonexist.example.com", - "8008", &hints, gai_cb, &a_out[8]); - tt_assert(r); - - /* 9: AI_ADDRCONFIG should at least not crash. Can't test it more - * without knowing what kind of internet we have. */ - hints.ai_flags |= EVUTIL_AI_ADDRCONFIG; - r = evdns_getaddrinfo(dns_base, "both.example.com", - "8009", &hints, gai_cb, &a_out[9]); - tt_assert(r); - - /* 10: PF_UNSPEC for v4timeout.example.com should give an ipv6 address - * only. */ - hints.ai_family = PF_UNSPEC; - hints.ai_flags = 0; - r = evdns_getaddrinfo(dns_base, "v4timeout.example.com", "8010", - &hints, gai_cb, &a_out[10]); - tt_assert(r); - - /* 11: timeout.example.com: cancel it after 100 msec. */ - r = evdns_getaddrinfo(dns_base, "all-timeout.example.com", "8011", - &hints, gai_cb, &a_out[11]); - tt_assert(r); - { - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 100*1000; /* 100 msec */ - event_base_once(data->base, -1, EV_TIMEOUT, cancel_gai_cb, - r, &tv); - } - - /* XXXXX There are more tests we could do, including: - - - A test to elicit NODATA. - - */ - - n_gai_results_pending = 12; - exit_base_on_no_pending_results = data->base; - - event_base_dispatch(data->base); - - /* 0: both.example.com */ - tt_int_op(a_out[0].err, ==, 0); - tt_assert(a_out[0].ai); - tt_assert(a_out[0].ai->ai_next); - tt_assert(!a_out[0].ai->ai_next->ai_next); - a = ai_find_by_family(a_out[0].ai, PF_INET); - tt_assert(a); - test_ai_eq(a, "80.80.32.32:8000", SOCK_STREAM, IPPROTO_TCP); - a = ai_find_by_family(a_out[0].ai, PF_INET6); - tt_assert(a); - test_ai_eq(a, "[80ff::bbbb]:8000", SOCK_STREAM, IPPROTO_TCP); - tt_assert(a_out[0].ai->ai_canonname); - tt_str_op(a_out[0].ai->ai_canonname, ==, "both-canonical.example.com"); - - /* 1: v4only.example.com */ - tt_int_op(a_out[1].err, ==, 0); - tt_assert(a_out[1].ai); - tt_assert(! a_out[1].ai->ai_next); - test_ai_eq(a_out[1].ai, "18.52.86.120:8001", SOCK_STREAM, IPPROTO_TCP); - tt_assert(a_out[1].ai->ai_canonname == NULL); - - - /* 2: v6only.example.com */ - tt_int_op(a_out[2].err, ==, 0); - tt_assert(a_out[2].ai); - tt_assert(! a_out[2].ai->ai_next); - test_ai_eq(a_out[2].ai, "[b0b::f00d]:8002", SOCK_STREAM, IPPROTO_TCP); - - /* 3: v4assert.example.com */ - tt_int_op(a_out[3].err, ==, 0); - tt_assert(a_out[3].ai); - tt_assert(! a_out[3].ai->ai_next); - test_ai_eq(a_out[3].ai, "18.52.86.120:8003", SOCK_STREAM, IPPROTO_TCP); - - /* 4: v6assert.example.com */ - tt_int_op(a_out[4].err, ==, 0); - tt_assert(a_out[4].ai); - tt_assert(! a_out[4].ai->ai_next); - test_ai_eq(a_out[4].ai, "[b0b::f00d]:8004", SOCK_STREAM, IPPROTO_TCP); - - /* 5: nosuchplace.example.com (inet) */ - tt_int_op(a_out[5].err, ==, EVUTIL_EAI_NONAME); - tt_assert(! a_out[5].ai); - - /* 6: nosuchplace.example.com (unspec) */ - tt_int_op(a_out[6].err, ==, EVUTIL_EAI_NONAME); - tt_assert(! a_out[6].ai); - - /* 7: v6timeout.example.com */ - tt_int_op(a_out[7].err, ==, 0); - tt_assert(a_out[7].ai); - tt_assert(! a_out[7].ai->ai_next); - test_ai_eq(a_out[7].ai, "171.205.239.1:8007", SOCK_STREAM, IPPROTO_TCP); - - /* 8: v6timeout-nonexist.example.com */ - tt_int_op(a_out[8].err, ==, EVUTIL_EAI_NONAME); - tt_assert(! a_out[8].ai); - - /* 9: both (ADDRCONFIG) */ - tt_int_op(a_out[9].err, ==, 0); - tt_assert(a_out[9].ai); - a = ai_find_by_family(a_out[9].ai, PF_INET); - if (a) - test_ai_eq(a, "80.80.32.32:8009", SOCK_STREAM, IPPROTO_TCP); - else - tt_assert(ai_find_by_family(a_out[9].ai, PF_INET6)); - a = ai_find_by_family(a_out[9].ai, PF_INET6); - if (a) - test_ai_eq(a, "[80ff::bbbb]:8009", SOCK_STREAM, IPPROTO_TCP); - else - tt_assert(ai_find_by_family(a_out[9].ai, PF_INET)); - - /* 10: v4timeout.example.com */ - tt_int_op(a_out[10].err, ==, 0); - tt_assert(a_out[10].ai); - tt_assert(! a_out[10].ai->ai_next); - test_ai_eq(a_out[10].ai, "[a0a::ff01]:8010", SOCK_STREAM, IPPROTO_TCP); - - /* 11: cancelled request. */ - tt_int_op(a_out[11].err, ==, EVUTIL_EAI_CANCEL); - tt_assert(a_out[11].ai == NULL); - -end: - if (local_outcome.ai) - evutil_freeaddrinfo(local_outcome.ai); - for (i=0;i<(int)ARRAY_SIZE(a_out);++i) { - if (a_out[i].ai) - evutil_freeaddrinfo(a_out[i].ai); - } - if (port) - evdns_close_server_port(port); - if (dns_base) - evdns_base_free(dns_base, 0); -} - -struct gaic_request_status { - int magic; - struct event_base *base; - struct evdns_base *dns_base; - struct evdns_getaddrinfo_request *request; - struct event cancel_event; - int canceled; -}; - -#define GAIC_MAGIC 0x1234abcd - -static int pending = 0; - -static void -gaic_cancel_request_cb(evutil_socket_t fd, short what, void *arg) -{ - struct gaic_request_status *status = arg; - - tt_assert(status->magic == GAIC_MAGIC); - status->canceled = 1; - evdns_getaddrinfo_cancel(status->request); - return; -end: - event_base_loopexit(status->base, NULL); -} - -static void -gaic_server_cb(struct evdns_server_request *req, void *arg) -{ - ev_uint32_t answer = 0x7f000001; - tt_assert(req->nquestions); - evdns_server_request_add_a_reply(req, req->questions[0]->name, 1, - &answer, 100); - evdns_server_request_respond(req, 0); - return; -end: - evdns_server_request_respond(req, DNS_ERR_REFUSED); -} - - -static void -gaic_getaddrinfo_cb(int result, struct evutil_addrinfo *res, void *arg) -{ - struct gaic_request_status *status = arg; - struct event_base *base = status->base; - tt_assert(status->magic == GAIC_MAGIC); - - if (result == EVUTIL_EAI_CANCEL) { - tt_assert(status->canceled); - } - event_del(&status->cancel_event); - - memset(status, 0xf0, sizeof(*status)); - free(status); - -end: - if (--pending <= 0) - event_base_loopexit(base, NULL); -} - -static void -gaic_launch(struct event_base *base, struct evdns_base *dns_base) -{ - struct gaic_request_status *status = calloc(1,sizeof(*status)); - struct timeval tv = { 0, 10000 }; - status->magic = GAIC_MAGIC; - status->base = base; - status->dns_base = dns_base; - event_assign(&status->cancel_event, base, -1, 0, gaic_cancel_request_cb, - status); - status->request = evdns_getaddrinfo(dns_base, - "foobar.bazquux.example.com", "80", NULL, gaic_getaddrinfo_cb, - status); - event_add(&status->cancel_event, &tv); - ++pending; -} - -#ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED -/* FIXME: We should move this to regress_main.c if anything else needs it.*/ - -/* Trivial replacements for malloc/free/realloc to check for memory leaks. - * Not threadsafe. */ -static int allocated_chunks = 0; - -static void * -cnt_malloc(size_t sz) -{ - allocated_chunks += 1; - return malloc(sz); -} - -static void * -cnt_realloc(void *old, size_t sz) -{ - if (!old) - allocated_chunks += 1; - if (!sz) - allocated_chunks -= 1; - return realloc(old, sz); -} - -static void -cnt_free(void *ptr) -{ - allocated_chunks -= 1; - free(ptr); -} - -struct testleak_env_t { - struct event_base *base; - struct evdns_base *dns_base; - struct evdns_request *req; - struct generic_dns_callback_result r; -}; - -static void * -testleak_setup(const struct testcase_t *testcase) -{ - struct testleak_env_t *env; - - allocated_chunks = 0; - - /* Reset allocation counter, to start allocations from the very beginning. - * (this will avoid false-positive negative numbers for allocated_chunks) - */ - libevent_global_shutdown(); - - event_set_mem_functions(cnt_malloc, cnt_realloc, cnt_free); - - event_enable_debug_mode(); - - /* not mm_calloc: we don't want to mess with the count. */ - env = calloc(1, sizeof(struct testleak_env_t)); - env->base = event_base_new(); - env->dns_base = evdns_base_new(env->base, 0); - env->req = evdns_base_resolve_ipv4( - env->dns_base, "example.com", DNS_QUERY_NO_SEARCH, - generic_dns_callback, &env->r); - return env; -} - -static int -testleak_cleanup(const struct testcase_t *testcase, void *env_) -{ - int ok = 0; - struct testleak_env_t *env = env_; - tt_assert(env); -#ifdef EVENT__DISABLE_DEBUG_MODE - tt_int_op(allocated_chunks, ==, 0); -#else - libevent_global_shutdown(); - tt_int_op(allocated_chunks, ==, 0); -#endif - ok = 1; -end: - if (env) { - if (env->dns_base) - evdns_base_free(env->dns_base, 0); - if (env->base) - event_base_free(env->base); - free(env); - } - return ok; -} - -static struct testcase_setup_t testleak_funcs = { - testleak_setup, testleak_cleanup -}; - -static void -test_dbg_leak_cancel(void *env_) -{ - /* cancel, loop, free/dns, free/base */ - struct testleak_env_t *env = env_; - int send_err_shutdown = 1; - evdns_cancel_request(env->dns_base, env->req); - env->req = 0; - - /* `req` is freed in callback, that's why one loop is required. */ - event_base_loop(env->base, EVLOOP_NONBLOCK); - - /* send_err_shutdown means nothing as soon as our request is - * already canceled */ - evdns_base_free(env->dns_base, send_err_shutdown); - env->dns_base = 0; - event_base_free(env->base); - env->base = 0; -} - -static void -dbg_leak_resume(void *env_, int cancel, int send_err_shutdown) -{ - /* cancel, loop, free/dns, free/base */ - struct testleak_env_t *env = env_; - if (cancel) { - evdns_cancel_request(env->dns_base, env->req); - tt_assert(!evdns_base_resume(env->dns_base)); - } else { - /* TODO: No nameservers, request can't be processed, must be errored */ - tt_assert(!evdns_base_resume(env->dns_base)); - } - - event_base_loop(env->base, EVLOOP_NONBLOCK); - /** - * Because we don't cancel request, and want our callback to recieve - * DNS_ERR_SHUTDOWN, we use deferred callback, and there was: - * - one extra malloc(), - * @see reply_schedule_callback() - * - and one missing free - * @see request_finished() (req->handle->pending_cb = 1) - * than we don't need to count in testleak_cleanup(), but we can clean them - * if we will run loop once again, but *after* evdns base freed. - */ - evdns_base_free(env->dns_base, send_err_shutdown); - env->dns_base = 0; - event_base_loop(env->base, EVLOOP_NONBLOCK); - -end: - event_base_free(env->base); - env->base = 0; -} - -#define IMPL_DBG_LEAK_RESUME(name, cancel, send_err_shutdown) \ - static void \ - test_dbg_leak_##name##_(void *env_) \ - { \ - dbg_leak_resume(env_, cancel, send_err_shutdown); \ - } -IMPL_DBG_LEAK_RESUME(resume, 0, 0) -IMPL_DBG_LEAK_RESUME(cancel_and_resume, 1, 0) -IMPL_DBG_LEAK_RESUME(resume_send_err, 0, 1) -IMPL_DBG_LEAK_RESUME(cancel_and_resume_send_err, 1, 1) - -static void -test_dbg_leak_shutdown(void *env_) -{ - /* free/dns, loop, free/base */ - struct testleak_env_t *env = env_; - int send_err_shutdown = 1; - - /* `req` is freed both with `send_err_shutdown` and without it, - * the only difference is `evdns_callback` call */ - env->req = 0; - - evdns_base_free(env->dns_base, send_err_shutdown); - env->dns_base = 0; - - /* `req` is freed in callback, that's why one loop is required */ - event_base_loop(env->base, EVLOOP_NONBLOCK); - event_base_free(env->base); - env->base = 0; -} -#endif - -static void -test_getaddrinfo_async_cancel_stress(void *ptr) -{ - struct event_base *base; - struct evdns_base *dns_base = NULL; - struct evdns_server_port *server = NULL; - evutil_socket_t fd = -1; - struct sockaddr_in sin; - struct sockaddr_storage ss; - ev_socklen_t slen; - int i; - - base = event_base_new(); - dns_base = evdns_base_new(base, 0); - - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_port = 0; - sin.sin_addr.s_addr = htonl(0x7f000001); - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - tt_abort_perror("socket"); - } - evutil_make_socket_nonblocking(fd); - if (bind(fd, (struct sockaddr*)&sin, sizeof(sin))<0) { - tt_abort_perror("bind"); - } - server = evdns_add_server_port_with_base(base, fd, 0, gaic_server_cb, - base); - - memset(&ss, 0, sizeof(ss)); - slen = sizeof(ss); - if (getsockname(fd, (struct sockaddr*)&ss, &slen)<0) { - tt_abort_perror("getsockname"); - } - evdns_base_nameserver_sockaddr_add(dns_base, - (struct sockaddr*)&ss, slen, 0); - - for (i = 0; i < 1000; ++i) { - gaic_launch(base, dns_base); - } - - event_base_dispatch(base); - -end: - if (dns_base) - evdns_base_free(dns_base, 1); - if (server) - evdns_close_server_port(server); - if (base) - event_base_free(base); - if (fd >= 0) - evutil_closesocket(fd); -} - -static void -dns_client_fail_requests_test(void *arg) -{ - struct basic_test_data *data = arg; - struct event_base *base = data->base; - struct evdns_base *dns = NULL; - struct evdns_server_port *dns_port = NULL; - ev_uint16_t portnum = 0; - char buf[64]; - - struct generic_dns_callback_result r[20]; - int i; - - dns_port = regress_get_dnsserver(base, &portnum, NULL, - regress_dns_server_cb, reissue_table); - tt_assert(dns_port); - - evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); - - dns = evdns_base_new(base, EVDNS_BASE_DISABLE_WHEN_INACTIVE); - tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); - - for (i = 0; i < 20; ++i) - evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r[i]); - - n_replies_left = 20; - exit_base = base; - - evdns_base_free(dns, 1 /** fail requests */); - /** run defered callbacks, to trigger UAF */ - event_base_dispatch(base); - - tt_int_op(n_replies_left, ==, 0); - for (i = 0; i < 20; ++i) - tt_int_op(r[i].result, ==, DNS_ERR_SHUTDOWN); - -end: - evdns_close_server_port(dns_port); -} - -static void -getaddrinfo_cb(int err, struct evutil_addrinfo *res, void *ptr) -{ - generic_dns_callback(err, 0, 0, 0, NULL, ptr); -} -static void -dns_client_fail_requests_getaddrinfo_test(void *arg) -{ - struct basic_test_data *data = arg; - struct event_base *base = data->base; - struct evdns_base *dns = NULL; - struct evdns_server_port *dns_port = NULL; - ev_uint16_t portnum = 0; - char buf[64]; - - struct generic_dns_callback_result r[20]; - int i; - - dns_port = regress_get_dnsserver(base, &portnum, NULL, - regress_dns_server_cb, reissue_table); - tt_assert(dns_port); - - evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); - - dns = evdns_base_new(base, EVDNS_BASE_DISABLE_WHEN_INACTIVE); - tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); - - for (i = 0; i < 20; ++i) - tt_assert(evdns_getaddrinfo(dns, "foof.example.com", "http", NULL, getaddrinfo_cb, &r[i])); - - n_replies_left = 20; - exit_base = base; - - evdns_base_free(dns, 1 /** fail requests */); - /** run defered callbacks, to trigger UAF */ - event_base_dispatch(base); - - tt_int_op(n_replies_left, ==, 0); - for (i = 0; i < 20; ++i) - tt_int_op(r[i].result, ==, EVUTIL_EAI_FAIL); - -end: - evdns_close_server_port(dns_port); -} - - -#define DNS_LEGACY(name, flags) \ - { #name, run_legacy_test_fn, flags|TT_LEGACY, &legacy_setup, \ - dns_##name } - -struct testcase_t dns_testcases[] = { - DNS_LEGACY(server, TT_FORK|TT_NEED_BASE), - DNS_LEGACY(gethostbyname, TT_FORK|TT_NEED_BASE|TT_NEED_DNS|TT_OFF_BY_DEFAULT), - DNS_LEGACY(gethostbyname6, TT_FORK|TT_NEED_BASE|TT_NEED_DNS|TT_OFF_BY_DEFAULT), - DNS_LEGACY(gethostbyaddr, TT_FORK|TT_NEED_BASE|TT_NEED_DNS|TT_OFF_BY_DEFAULT), - { "resolve_reverse", dns_resolve_reverse, TT_FORK|TT_OFF_BY_DEFAULT, NULL, NULL }, - { "search", dns_search_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, - { "search_lower", dns_search_lower_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, - { "search_cancel", dns_search_cancel_test, - TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, - { "retry", dns_retry_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL }, - { "retry_disable_when_inactive", dns_retry_disable_when_inactive_test, - TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL }, - { "reissue", dns_reissue_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL }, - { "reissue_disable_when_inactive", dns_reissue_disable_when_inactive_test, - TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL }, - { "inflight", dns_inflight_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, - { "bufferevent_connect_hostname", test_bufferevent_connect_hostname, - TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, - { "disable_when_inactive", dns_disable_when_inactive_test, - TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, - { "disable_when_inactive_no_ns", dns_disable_when_inactive_no_ns_test, - TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, - - { "getaddrinfo_async", test_getaddrinfo_async, - TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"" }, - { "getaddrinfo_cancel_stress", test_getaddrinfo_async_cancel_stress, - TT_FORK, NULL, NULL }, - -#ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED - { "leak_shutdown", test_dbg_leak_shutdown, TT_FORK, &testleak_funcs, NULL }, - { "leak_cancel", test_dbg_leak_cancel, TT_FORK, &testleak_funcs, NULL }, - - { "leak_resume", test_dbg_leak_resume_, TT_FORK, &testleak_funcs, NULL }, - { "leak_cancel_and_resume", test_dbg_leak_cancel_and_resume_, - TT_FORK, &testleak_funcs, NULL }, - { "leak_resume_send_err", test_dbg_leak_resume_send_err_, - TT_FORK, &testleak_funcs, NULL }, - { "leak_cancel_and_resume_send_err", test_dbg_leak_cancel_and_resume_send_err_, - TT_FORK, &testleak_funcs, NULL }, -#endif - - { "client_fail_requests", dns_client_fail_requests_test, - TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, - { "client_fail_requests_getaddrinfo", - dns_client_fail_requests_getaddrinfo_test, - TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, - - END_OF_TESTCASES -}; - diff --git a/libs/libevent/docs/test/regress_et.c b/libs/libevent/docs/test/regress_et.c deleted file mode 100644 index 229a78e2d4..0000000000 --- a/libs/libevent/docs/test/regress_et.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2009-2012 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 "../util-internal.h" -#include "event2/event-config.h" - -#ifdef _WIN32 -#include -#endif -#include -#include -#ifdef EVENT__HAVE_SYS_SOCKET_H -#include -#endif -#include -#include -#include -#include -#ifndef _WIN32 -#include -#include -#endif -#include - -#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); - - 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; - - /* On Linux 3.2.1 (at least, as patched by Fedora and tested by Nick), - * doing a "recv" on an AF_UNIX socket resets the readability of the - * socket, even though there is no state change, so we don't actually - * get edge-triggered behavior. Yuck! Linux 3.1.9 didn't have this - * problem. - */ -#ifdef __linux__ - if (evutil_ersatz_socketpair_(AF_INET, SOCK_STREAM, 0, pair) == -1) { - tt_abort_perror("socketpair"); - } -#else - if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair) == -1) { - tt_abort_perror("socketpair"); - } -#endif - - called = was_et = 0; - - tt_int_op(send(pair[0], test, (int)strlen(test)+1, 0), >, 0); - shutdown(pair[0], SHUT_WR); - - /* Initalize the event library */ - base = event_base_new(); - - if (!strcmp(event_base_get_method(base), "epoll") || - !strcmp(event_base_get_method(base), "epoll (with changelist)") || - !strcmp(event_base_get_method(base), "kqueue")) - supports_et = 1; - else - supports_et = 0; - - TT_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); - } - - 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 - - if (!libevent_tests_running_in_debug_mode) - 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); - tt_assert(ev_et); - ev_lt = event_new(base, data->pair[0], EV_READ, read_cb, ev_lt); - tt_assert(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 -}; diff --git a/libs/libevent/docs/test/regress_finalize.c b/libs/libevent/docs/test/regress_finalize.c deleted file mode 100644 index 552210fe9d..0000000000 --- a/libs/libevent/docs/test/regress_finalize.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (c) 2013 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" -#include "evconfig-private.h" -#include "tinytest.h" -#include "tinytest_macros.h" -#include - -#include "event2/event.h" -#include "event2/util.h" -#include "event-internal.h" -#include "defer-internal.h" - -#include "regress.h" -#include "regress_thread.h" - -static void -timer_callback(evutil_socket_t fd, short what, void *arg) -{ - int *int_arg = arg; - *int_arg += 1; - (void)fd; - (void)what; -} -static void -simple_callback(struct event_callback *evcb, void *arg) -{ - int *int_arg = arg; - *int_arg += 1; - (void)evcb; -} -static void -event_finalize_callback_1(struct event *ev, void *arg) -{ - int *int_arg = arg; - *int_arg += 100; - (void)ev; -} -static void -callback_finalize_callback_1(struct event_callback *evcb, void *arg) -{ - int *int_arg = arg; - *int_arg += 100; - (void)evcb; -} - - -static void -test_fin_cb_invoked(void *arg) -{ - struct basic_test_data *data = arg; - struct event_base *base = data->base; - - struct event *ev; - struct event ev2; - struct event_callback evcb; - int cb_called = 0; - int ev_called = 0; - - const struct timeval ten_sec = {10,0}; - - event_deferred_cb_init_(&evcb, 0, simple_callback, &cb_called); - ev = evtimer_new(base, timer_callback, &ev_called); - /* Just finalize them; don't bother adding. */ - event_free_finalize(0, ev, event_finalize_callback_1); - event_callback_finalize_(base, 0, &evcb, callback_finalize_callback_1); - - event_base_dispatch(base); - - tt_int_op(cb_called, ==, 100); - tt_int_op(ev_called, ==, 100); - - ev_called = cb_called = 0; - event_base_assert_ok_(base); - - /* Now try it when they're active. (actually, don't finalize: make - * sure activation can happen! */ - ev = evtimer_new(base, timer_callback, &ev_called); - event_deferred_cb_init_(&evcb, 0, simple_callback, &cb_called); - - event_active(ev, EV_TIMEOUT, 1); - event_callback_activate_(base, &evcb); - - event_base_dispatch(base); - tt_int_op(cb_called, ==, 1); - tt_int_op(ev_called, ==, 1); - - ev_called = cb_called = 0; - event_base_assert_ok_(base); - - /* Great, it worked. Now activate and finalize and make sure only - * finalizing happens. */ - event_active(ev, EV_TIMEOUT, 1); - event_callback_activate_(base, &evcb); - event_free_finalize(0, ev, event_finalize_callback_1); - event_callback_finalize_(base, 0, &evcb, callback_finalize_callback_1); - - event_base_dispatch(base); - tt_int_op(cb_called, ==, 100); - tt_int_op(ev_called, ==, 100); - - ev_called = 0; - - event_base_assert_ok_(base); - - /* Okay, now add but don't have it become active, and make sure *that* - * works. */ - ev = evtimer_new(base, timer_callback, &ev_called); - event_add(ev, &ten_sec); - event_free_finalize(0, ev, event_finalize_callback_1); - - event_base_dispatch(base); - tt_int_op(ev_called, ==, 100); - - ev_called = 0; - event_base_assert_ok_(base); - - /* Now try adding and deleting after finalizing. */ - ev = evtimer_new(base, timer_callback, &ev_called); - evtimer_assign(&ev2, base, timer_callback, &ev_called); - event_add(ev, &ten_sec); - event_free_finalize(0, ev, event_finalize_callback_1); - event_finalize(0, &ev2, event_finalize_callback_1); - - event_add(&ev2, &ten_sec); - event_del(ev); - event_active(&ev2, EV_TIMEOUT, 1); - - event_base_dispatch(base); - tt_int_op(ev_called, ==, 200); - - event_base_assert_ok_(base); - -end: - ; -} - -#ifndef EVENT__DISABLE_MM_REPLACEMENT -static void * -tfff_malloc(size_t n) -{ - return malloc(n); -} -static void *tfff_p1=NULL, *tfff_p2=NULL; -static int tfff_p1_freed=0, tfff_p2_freed=0; -static void -tfff_free(void *p) -{ - if (! p) - return; - if (p == tfff_p1) - ++tfff_p1_freed; - if (p == tfff_p2) - ++tfff_p2_freed; - free(p); -} -static void * -tfff_realloc(void *p, size_t sz) -{ - return realloc(p,sz); -} -#endif - -static void -test_fin_free_finalize(void *arg) -{ -#ifdef EVENT__DISABLE_MM_REPLACEMENT - tinytest_set_test_skipped_(); -#else - struct event_base *base = NULL; - struct event *ev, *ev2; - int ev_called = 0; - int ev2_called = 0; - - (void)arg; - - event_set_mem_functions(tfff_malloc, tfff_realloc, tfff_free); - - base = event_base_new(); - tt_assert(base); - - ev = evtimer_new(base, timer_callback, &ev_called); - ev2 = evtimer_new(base, timer_callback, &ev2_called); - tfff_p1 = ev; - tfff_p2 = ev2; - event_free_finalize(0, ev, event_finalize_callback_1); - event_finalize(0, ev2, event_finalize_callback_1); - - event_base_dispatch(base); - - tt_int_op(ev_called, ==, 100); - tt_int_op(ev2_called, ==, 100); - - event_base_assert_ok_(base); - tt_int_op(tfff_p1_freed, ==, 1); - tt_int_op(tfff_p2_freed, ==, 0); - - event_free(ev2); - -end: - if (base) - event_base_free(base); -#endif -} - -/* For test_fin_within_cb */ -struct event_and_count { - struct event *ev; - struct event *ev2; - int count; -}; -static void -event_finalize_callback_2(struct event *ev, void *arg) -{ - struct event_and_count *evc = arg; - evc->count += 100; - event_free(ev); -} -static void -timer_callback_2(evutil_socket_t fd, short what, void *arg) -{ - struct event_and_count *evc = arg; - event_finalize(0, evc->ev, event_finalize_callback_2); - event_finalize(0, evc->ev2, event_finalize_callback_2); - ++ evc->count; - (void)fd; - (void)what; -} - -static void -test_fin_within_cb(void *arg) -{ - struct basic_test_data *data = arg; - struct event_base *base = data->base; - - struct event_and_count evc1, evc2; - evc1.count = evc2.count = 0; - evc2.ev2 = evc1.ev = evtimer_new(base, timer_callback_2, &evc1); - evc1.ev2 = evc2.ev = evtimer_new(base, timer_callback_2, &evc2); - - /* Activate both. The first one will have its callback run, which - * will finalize both of them, preventing the second one's callback - * from running. */ - event_active(evc1.ev, EV_TIMEOUT, 1); - event_active(evc2.ev, EV_TIMEOUT, 1); - - event_base_dispatch(base); - tt_int_op(evc1.count, ==, 101); - tt_int_op(evc2.count, ==, 100); - - event_base_assert_ok_(base); - /* Now try with EV_PERSIST events. */ - evc1.count = evc2.count = 0; - evc2.ev2 = evc1.ev = event_new(base, -1, EV_PERSIST, timer_callback_2, &evc1); - evc1.ev2 = evc2.ev = event_new(base, -1, EV_PERSIST, timer_callback_2, &evc2); - - event_active(evc1.ev, EV_TIMEOUT, 1); - event_active(evc2.ev, EV_TIMEOUT, 1); - - event_base_dispatch(base); - tt_int_op(evc1.count, ==, 101); - tt_int_op(evc2.count, ==, 100); - - event_base_assert_ok_(base); -end: - ; -} - -#if 0 -static void -timer_callback_3(evutil_socket_t *fd, short what, void *arg) -{ - (void)fd; - (void)what; - -} -static void -test_fin_many(void *arg) -{ - struct basic_test_data *data = arg; - struct event_base *base = data->base; - - struct event *ev1, *ev2; - struct event_callback evcb1, evcb2; - int ev1_count = 0, ev2_count = 0; - int evcb1_count = 0, evcb2_count = 0; - struct event_callback *array[4]; - - int n; - - /* First attempt: call finalize_many with no events running */ - ev1 = evtimer_new(base, timer_callback, &ev1_count); - ev1 = evtimer_new(base, timer_callback, &ev2_count); - event_deferred_cb_init_(&evcb1, 0, simple_callback, &evcb1_called); - event_deferred_cb_init_(&evcb2, 0, simple_callback, &evcb2_called); - array[0] = &ev1->ev_evcallback; - array[1] = &ev2->ev_evcallback; - array[2] = &evcb1; - array[3] = &evcb2; - - - - n = event_callback_finalize_many(base, 4, array, - callback_finalize_callback_1); - -} -#endif - - -#define TEST(name, flags) \ - { #name, test_fin_##name, (flags), &basic_setup, NULL } - -struct testcase_t finalize_testcases[] = { - - TEST(cb_invoked, TT_FORK|TT_NEED_BASE), - TEST(free_finalize, TT_FORK), - TEST(within_cb, TT_FORK|TT_NEED_BASE), -// TEST(many, TT_FORK|TT_NEED_BASE), - - - END_OF_TESTCASES -}; - diff --git a/libs/libevent/docs/test/regress_http.c b/libs/libevent/docs/test/regress_http.c deleted file mode 100644 index cbe7aea34c..0000000000 --- a/libs/libevent/docs/test/regress_http.c +++ /dev/null @@ -1,4335 +0,0 @@ -/* - * Copyright (c) 2003-2007 Niels Provos - * Copyright (c) 2007-2012 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 "util-internal.h" - -#ifdef _WIN32 -#include -#include -#include -#endif - -#include "event2/event-config.h" - -#include -#include -#ifdef EVENT__HAVE_SYS_TIME_H -#include -#endif -#include -#ifndef _WIN32 -#include -#include -#include -#include -#endif -#include -#include -#include -#include -#include - -#include "event2/dns.h" - -#include "event2/event.h" -#include "event2/http.h" -#include "event2/buffer.h" -#include "event2/bufferevent.h" -#include "event2/bufferevent_ssl.h" -#include "event2/util.h" -#include "event2/listener.h" -#include "log-internal.h" -#include "http-internal.h" -#include "regress.h" -#include "regress_testutils.h" - -static struct evhttp *http; -/* set if a test needs to call loopexit on a base */ -static struct event_base *exit_base; - -static char const BASIC_REQUEST_BODY[] = "This is funny"; - -#define IMPL_HTTP_REQUEST_ERROR_CB(name, expecting_error) \ - static void \ - http_request_error_cb_with_##name##_(enum evhttp_request_error error, \ - void *arg) \ - { \ - if (error != expecting_error) { \ - fprintf(stderr, "FAILED\n"); \ - exit(1); \ - } \ - test_ok = 1; \ - } -IMPL_HTTP_REQUEST_ERROR_CB(cancel, EVREQ_HTTP_REQUEST_CANCEL) - -static void http_basic_cb(struct evhttp_request *req, void *arg); -static void http_large_cb(struct evhttp_request *req, void *arg); -static void http_chunked_cb(struct evhttp_request *req, void *arg); -static void http_post_cb(struct evhttp_request *req, void *arg); -static void http_put_cb(struct evhttp_request *req, void *arg); -static void http_delete_cb(struct evhttp_request *req, void *arg); -static void http_delay_cb(struct evhttp_request *req, void *arg); -static void http_large_delay_cb(struct evhttp_request *req, void *arg); -static void http_badreq_cb(struct evhttp_request *req, void *arg); -static void http_dispatcher_cb(struct evhttp_request *req, void *arg); -static void http_on_complete_cb(struct evhttp_request *req, void *arg); - -#define HTTP_BIND_IPV6 1 -#define HTTP_BIND_SSL 2 -static int -http_bind(struct evhttp *myhttp, ev_uint16_t *pport, int mask) -{ - int port; - struct evhttp_bound_socket *sock; - int ipv6 = mask & HTTP_BIND_IPV6; - - if (ipv6) - sock = evhttp_bind_socket_with_handle(myhttp, "::1", *pport); - else - sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", *pport); - - if (sock == NULL) { - if (ipv6) - return -1; - else - event_errx(1, "Could not start web server"); - } - - port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock)); - if (port < 0) - return -1; - *pport = (ev_uint16_t) port; - - return 0; -} - -#ifdef EVENT__HAVE_OPENSSL -static struct bufferevent * -https_bev(struct event_base *base, void *arg) -{ - SSL *ssl = SSL_new(get_ssl_ctx()); - - SSL_use_certificate(ssl, ssl_getcert()); - SSL_use_PrivateKey(ssl, ssl_getkey()); - - return bufferevent_openssl_socket_new( - base, -1, ssl, BUFFEREVENT_SSL_ACCEPTING, - BEV_OPT_CLOSE_ON_FREE); -} -#endif -static struct evhttp * -http_setup(ev_uint16_t *pport, struct event_base *base, int mask) -{ - struct evhttp *myhttp; - - /* Try a few different ports */ - myhttp = evhttp_new(base); - - if (http_bind(myhttp, pport, mask) < 0) - return NULL; -#ifdef EVENT__HAVE_OPENSSL - if (mask & HTTP_BIND_SSL) { - init_ssl(); - evhttp_set_bevcb(myhttp, https_bev, NULL); - } -#endif - - /* Register a callback for certain types of requests */ - evhttp_set_cb(myhttp, "/test", http_basic_cb, base); - evhttp_set_cb(myhttp, "/large", http_large_cb, base); - evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, base); - evhttp_set_cb(myhttp, "/streamed", http_chunked_cb, base); - evhttp_set_cb(myhttp, "/postit", http_post_cb, base); - evhttp_set_cb(myhttp, "/putit", http_put_cb, base); - evhttp_set_cb(myhttp, "/deleteit", http_delete_cb, base); - evhttp_set_cb(myhttp, "/delay", http_delay_cb, base); - evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, base); - evhttp_set_cb(myhttp, "/badrequest", http_badreq_cb, base); - evhttp_set_cb(myhttp, "/oncomplete", http_on_complete_cb, base); - evhttp_set_cb(myhttp, "/", http_dispatcher_cb, base); - return (myhttp); -} - -#ifndef NI_MAXSERV -#define NI_MAXSERV 1024 -#endif - -static evutil_socket_t -http_connect(const char *address, unsigned short port) -{ - /* Stupid code for connecting */ - struct evutil_addrinfo ai, *aitop; - char strport[NI_MAXSERV]; - - struct sockaddr *sa; - int slen; - evutil_socket_t fd; - - memset(&ai, 0, sizeof(ai)); - ai.ai_family = AF_INET; - ai.ai_socktype = SOCK_STREAM; - evutil_snprintf(strport, sizeof(strport), "%d", port); - if (evutil_getaddrinfo(address, strport, &ai, &aitop) != 0) { - event_warn("getaddrinfo"); - return (-1); - } - sa = aitop->ai_addr; - slen = aitop->ai_addrlen; - - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd == -1) - event_err(1, "socket failed"); - - evutil_make_socket_nonblocking(fd); - if (connect(fd, sa, slen) == -1) { -#ifdef _WIN32 - int tmp_err = WSAGetLastError(); - if (tmp_err != WSAEINPROGRESS && tmp_err != WSAEINVAL && - tmp_err != WSAEWOULDBLOCK) - event_err(1, "connect failed"); -#else - if (errno != EINPROGRESS) - event_err(1, "connect failed"); -#endif - } - - evutil_freeaddrinfo(aitop); - - return (fd); -} - -/* Helper: do a strcmp on the contents of buf and the string s. */ -static int -evbuffer_datacmp(struct evbuffer *buf, const char *s) -{ - size_t b_sz = evbuffer_get_length(buf); - size_t s_sz = strlen(s); - unsigned char *d; - int r; - - if (b_sz < s_sz) - return -1; - - d = evbuffer_pullup(buf, s_sz); - if ((r = memcmp(d, s, s_sz))) - return r; - - if (b_sz > s_sz) - return 1; - else - return 0; -} - -/* Helper: Return true iff buf contains s */ -static int -evbuffer_contains(struct evbuffer *buf, const char *s) -{ - struct evbuffer_ptr ptr; - ptr = evbuffer_search(buf, s, strlen(s), NULL); - return ptr.pos != -1; -} - -static void -http_readcb(struct bufferevent *bev, void *arg) -{ - const char *what = BASIC_REQUEST_BODY; - struct event_base *my_base = arg; - - if (evbuffer_contains(bufferevent_get_input(bev), what)) { - struct evhttp_request *req = evhttp_request_new(NULL, NULL); - enum message_read_status done; - - /* req->kind = EVHTTP_RESPONSE; */ - done = evhttp_parse_firstline_(req, bufferevent_get_input(bev)); - if (done != ALL_DATA_READ) - goto out; - - done = evhttp_parse_headers_(req, bufferevent_get_input(bev)); - if (done != ALL_DATA_READ) - goto out; - - if (done == 1 && - evhttp_find_header(evhttp_request_get_input_headers(req), - "Content-Type") != NULL) - test_ok++; - - out: - evhttp_request_free(req); - bufferevent_disable(bev, EV_READ); - if (exit_base) - event_base_loopexit(exit_base, NULL); - else if (my_base) - event_base_loopexit(my_base, NULL); - else { - fprintf(stderr, "No way to exit loop!\n"); - exit(1); - } - } -} - -static void -http_writecb(struct bufferevent *bev, void *arg) -{ - if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) { - /* enable reading of the reply */ - bufferevent_enable(bev, EV_READ); - test_ok++; - } -} - -static void -http_errorcb(struct bufferevent *bev, short what, void *arg) -{ - /** For ssl */ - if (what & BEV_EVENT_CONNECTED) - return; - test_ok = -2; - event_base_loopexit(arg, NULL); -} - -static int found_multi = 0; -static int found_multi2 = 0; - -static void -http_basic_cb(struct evhttp_request *req, void *arg) -{ - struct evbuffer *evb = evbuffer_new(); - struct evhttp_connection *evcon; - int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL; - event_debug(("%s: called\n", __func__)); - evbuffer_add_printf(evb, BASIC_REQUEST_BODY); - - evcon = evhttp_request_get_connection(req); - tt_assert(evhttp_connection_get_server(evcon) == http); - - /* For multi-line headers test */ - { - const char *multi = - evhttp_find_header(evhttp_request_get_input_headers(req),"X-Multi"); - if (multi) { - found_multi = !strcmp(multi,"aaaaaaaa a END"); - if (strcmp("END", multi + strlen(multi) - 3) == 0) - test_ok++; - if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Last")) - test_ok++; - } - } - { - const char *multi2 = - evhttp_find_header(evhttp_request_get_input_headers(req),"X-Multi-Extra-WS"); - if (multi2) { - found_multi2 = !strcmp(multi2,"libevent 2.1"); - } - } - - - /* injecting a bad content-length */ - if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Negative")) - evhttp_add_header(evhttp_request_get_output_headers(req), - "Content-Length", "-100"); - - /* allow sending of an empty reply */ - evhttp_send_reply(req, HTTP_OK, "Everything is fine", - !empty ? evb : NULL); - -end: - evbuffer_free(evb); -} - -static void -http_large_cb(struct evhttp_request *req, void *arg) -{ - struct evbuffer *evb = evbuffer_new(); - int i; - - for (i = 0; i < 1<<20; ++i) { - evbuffer_add_printf(evb, BASIC_REQUEST_BODY); - } - evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb); - evbuffer_free(evb); -} - -static char const* const CHUNKS[] = { - "This is funny", - "but not hilarious.", - "bwv 1052" -}; - -struct chunk_req_state { - struct event_base *base; - struct evhttp_request *req; - int i; -}; - -static void -http_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg) -{ - struct evbuffer *evb = evbuffer_new(); - struct chunk_req_state *state = arg; - struct timeval when = { 0, 0 }; - - evbuffer_add_printf(evb, "%s", CHUNKS[state->i]); - evhttp_send_reply_chunk(state->req, evb); - evbuffer_free(evb); - - if (++state->i < (int) (sizeof(CHUNKS)/sizeof(CHUNKS[0]))) { - event_base_once(state->base, -1, EV_TIMEOUT, - http_chunked_trickle_cb, state, &when); - } else { - evhttp_send_reply_end(state->req); - free(state); - } -} - -static void -http_chunked_cb(struct evhttp_request *req, void *arg) -{ - struct timeval when = { 0, 0 }; - struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state)); - event_debug(("%s: called\n", __func__)); - - memset(state, 0, sizeof(struct chunk_req_state)); - state->req = req; - state->base = arg; - - if (strcmp(evhttp_request_get_uri(req), "/streamed") == 0) { - evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Length", "39"); - } - - /* generate a chunked/streamed reply */ - evhttp_send_reply_start(req, HTTP_OK, "Everything is fine"); - - /* but trickle it across several iterations to ensure we're not - * assuming it comes all at once */ - event_base_once(arg, -1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when); -} - -static void -http_complete_write(evutil_socket_t fd, short what, void *arg) -{ - struct bufferevent *bev = arg; - const char *http_request = "host\r\n" - "Connection: close\r\n" - "\r\n"; - bufferevent_write(bev, http_request, strlen(http_request)); -} - -static struct bufferevent * -create_bev(struct event_base *base, int fd, int ssl) -{ - int flags = BEV_OPT_DEFER_CALLBACKS; - struct bufferevent *bev = NULL; - - if (!ssl) { - bev = bufferevent_socket_new(base, fd, flags); - } else { -#ifdef EVENT__HAVE_OPENSSL - SSL *ssl = SSL_new(get_ssl_ctx()); - bev = bufferevent_openssl_socket_new( - base, fd, ssl, BUFFEREVENT_SSL_CONNECTING, flags); - bufferevent_openssl_set_allow_dirty_shutdown(bev, 1); -#endif - } - - return bev; -} - -static void -http_basic_test_impl(void *arg, int ssl) -{ - struct basic_test_data *data = arg; - struct timeval tv; - struct bufferevent *bev = NULL; - evutil_socket_t fd; - const char *http_request; - ev_uint16_t port = 0, port2 = 0; - int server_flags = ssl ? HTTP_BIND_SSL : 0; - - test_ok = 0; - - http = http_setup(&port, data->base, server_flags); - - /* bind to a second socket */ - if (http_bind(http, &port2, server_flags) == -1) { - fprintf(stdout, "FAILED (bind)\n"); - exit(1); - } - - fd = http_connect("127.0.0.1", port); - - /* Stupid thing to send a request */ - bev = create_bev(data->base, fd, ssl); - bufferevent_setcb(bev, http_readcb, http_writecb, - http_errorcb, data->base); - - /* first half of the http request */ - http_request = - "GET /test HTTP/1.1\r\n" - "Host: some"; - - bufferevent_write(bev, http_request, strlen(http_request)); - evutil_timerclear(&tv); - tv.tv_usec = 10000; - event_base_once(data->base, - -1, EV_TIMEOUT, http_complete_write, bev, &tv); - - event_base_dispatch(data->base); - - tt_assert(test_ok == 3); - - /* connect to the second port */ - bufferevent_free(bev); - evutil_closesocket(fd); - - fd = http_connect("127.0.0.1", port2); - - /* Stupid thing to send a request */ - bev = create_bev(data->base, fd, ssl); - bufferevent_setcb(bev, http_readcb, http_writecb, - http_errorcb, data->base); - - http_request = - "GET /test HTTP/1.1\r\n" - "Host: somehost\r\n" - "Connection: close\r\n" - "\r\n"; - - bufferevent_write(bev, http_request, strlen(http_request)); - - event_base_dispatch(data->base); - - tt_assert(test_ok == 5); - - /* Connect to the second port again. This time, send an absolute uri. */ - bufferevent_free(bev); - evutil_closesocket(fd); - - fd = http_connect("127.0.0.1", port2); - - /* Stupid thing to send a request */ - bev = create_bev(data->base, fd, ssl); - bufferevent_setcb(bev, http_readcb, http_writecb, - http_errorcb, data->base); - - http_request = - "GET http://somehost.net/test HTTP/1.1\r\n" - "Host: somehost\r\n" - "Connection: close\r\n" - "\r\n"; - - bufferevent_write(bev, http_request, strlen(http_request)); - - event_base_dispatch(data->base); - - tt_assert(test_ok == 7); - - evhttp_free(http); - end: - if (bev) - bufferevent_free(bev); -} -static void http_basic_test(void *arg) -{ return http_basic_test_impl(arg, 0); } - - -static void -http_delay_reply(evutil_socket_t fd, short what, void *arg) -{ - struct evhttp_request *req = arg; - - evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL); - - ++test_ok; -} - -static void -http_delay_cb(struct evhttp_request *req, void *arg) -{ - struct timeval tv; - evutil_timerclear(&tv); - tv.tv_sec = 0; - tv.tv_usec = 200 * 1000; - - event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv); -} - -static void -http_badreq_cb(struct evhttp_request *req, void *arg) -{ - struct evbuffer *buf = evbuffer_new(); - - evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/xml; charset=UTF-8"); - evbuffer_add_printf(buf, "Hello, %s!", "127.0.0.1"); - - evhttp_send_reply(req, HTTP_OK, "OK", buf); - evbuffer_free(buf); -} - -static void -http_badreq_errorcb(struct bufferevent *bev, short what, void *arg) -{ - event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg)); - /* ignore */ -} - -#ifndef SHUT_WR -#ifdef _WIN32 -#define SHUT_WR SD_SEND -#else -#define SHUT_WR 1 -#endif -#endif - -static void -http_badreq_readcb(struct bufferevent *bev, void *arg) -{ - const char *what = "Hello, 127.0.0.1"; - const char *bad_request = "400 Bad Request"; - - if (evbuffer_contains(bufferevent_get_input(bev), bad_request)) { - TT_FAIL(("%s:bad request detected", __func__)); - bufferevent_disable(bev, EV_READ); - event_base_loopexit(arg, NULL); - return; - } - - if (evbuffer_contains(bufferevent_get_input(bev), what)) { - struct evhttp_request *req = evhttp_request_new(NULL, NULL); - enum message_read_status done; - - /* req->kind = EVHTTP_RESPONSE; */ - done = evhttp_parse_firstline_(req, bufferevent_get_input(bev)); - if (done != ALL_DATA_READ) - goto out; - - done = evhttp_parse_headers_(req, bufferevent_get_input(bev)); - if (done != ALL_DATA_READ) - goto out; - - if (done == 1 && - evhttp_find_header(evhttp_request_get_input_headers(req), - "Content-Type") != NULL) - test_ok++; - - out: - evhttp_request_free(req); - evbuffer_drain(bufferevent_get_input(bev), evbuffer_get_length(bufferevent_get_input(bev))); - } - - shutdown(bufferevent_getfd(bev), SHUT_WR); -} - -static void -http_badreq_successcb(evutil_socket_t fd, short what, void *arg) -{ - event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg)); - event_base_loopexit(exit_base, NULL); -} - -static void -http_bad_request_test(void *arg) -{ - struct basic_test_data *data = arg; - struct timeval tv; - struct bufferevent *bev = NULL; - evutil_socket_t fd = -1; - const char *http_request; - ev_uint16_t port=0, port2=0; - - test_ok = 0; - exit_base = data->base; - - http = http_setup(&port, data->base, 0); - - /* bind to a second socket */ - if (http_bind(http, &port2, 0) == -1) - TT_DIE(("Bind socket failed")); - - /* NULL request test */ - fd = http_connect("127.0.0.1", port); - tt_int_op(fd, >=, 0); - - /* Stupid thing to send a request */ - bev = bufferevent_socket_new(data->base, fd, 0); - bufferevent_setcb(bev, http_badreq_readcb, http_writecb, - http_badreq_errorcb, data->base); - bufferevent_enable(bev, EV_READ); - - /* real NULL request */ - http_request = ""; - - bufferevent_write(bev, http_request, strlen(http_request)); - - shutdown(fd, SHUT_WR); - timerclear(&tv); - tv.tv_usec = 10000; - event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv); - - event_base_dispatch(data->base); - - bufferevent_free(bev); - evutil_closesocket(fd); - - if (test_ok != 0) { - fprintf(stdout, "FAILED\n"); - exit(1); - } - - /* Second answer (BAD REQUEST) on connection close */ - - /* connect to the second port */ - fd = http_connect("127.0.0.1", port2); - - /* Stupid thing to send a request */ - bev = bufferevent_socket_new(data->base, fd, 0); - bufferevent_setcb(bev, http_badreq_readcb, http_writecb, - http_badreq_errorcb, data->base); - bufferevent_enable(bev, EV_READ); - - /* first half of the http request */ - http_request = - "GET /badrequest HTTP/1.0\r\n" \ - "Connection: Keep-Alive\r\n" \ - "\r\n"; - - bufferevent_write(bev, http_request, strlen(http_request)); - - timerclear(&tv); - tv.tv_usec = 10000; - event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv); - - event_base_dispatch(data->base); - - tt_int_op(test_ok, ==, 2); - -end: - evhttp_free(http); - if (bev) - bufferevent_free(bev); - if (fd >= 0) - evutil_closesocket(fd); -} - -static struct evhttp_connection *delayed_client; - -static void -http_large_delay_cb(struct evhttp_request *req, void *arg) -{ - struct timeval tv; - evutil_timerclear(&tv); - tv.tv_usec = 500000; - - event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv); - evhttp_connection_fail_(delayed_client, EVREQ_HTTP_EOF); -} - -/* - * HTTP DELETE test, just piggyback on the basic test - */ - -static void -http_delete_cb(struct evhttp_request *req, void *arg) -{ - struct evbuffer *evb = evbuffer_new(); - int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL; - - /* Expecting a DELETE request */ - if (evhttp_request_get_command(req) != EVHTTP_REQ_DELETE) { - fprintf(stdout, "FAILED (delete type)\n"); - exit(1); - } - - event_debug(("%s: called\n", __func__)); - evbuffer_add_printf(evb, BASIC_REQUEST_BODY); - - /* allow sending of an empty reply */ - evhttp_send_reply(req, HTTP_OK, "Everything is fine", - !empty ? evb : NULL); - - evbuffer_free(evb); -} - -static void -http_delete_test(void *arg) -{ - struct basic_test_data *data = arg; - struct bufferevent *bev; - evutil_socket_t fd = -1; - const char *http_request; - ev_uint16_t port = 0; - - test_ok = 0; - - http = http_setup(&port, data->base, 0); - - tt_assert(http); - fd = http_connect("127.0.0.1", port); - tt_int_op(fd, >=, 0); - - /* Stupid thing to send a request */ - bev = bufferevent_socket_new(data->base, fd, 0); - bufferevent_setcb(bev, http_readcb, http_writecb, - http_errorcb, data->base); - - http_request = - "DELETE /deleteit HTTP/1.1\r\n" - "Host: somehost\r\n" - "Connection: close\r\n" - "\r\n"; - - bufferevent_write(bev, http_request, strlen(http_request)); - - event_base_dispatch(data->base); - - bufferevent_free(bev); - evutil_closesocket(fd); - fd = -1; - - evhttp_free(http); - - tt_int_op(test_ok, ==, 2); - end: - if (fd >= 0) - evutil_closesocket(fd); -} - -static void -http_sent_cb(struct evhttp_request *req, void *arg) -{ - ev_uintptr_t val = (ev_uintptr_t)arg; - struct evbuffer *b; - - if (val != 0xDEADBEEF) { - fprintf(stdout, "FAILED on_complete_cb argument\n"); - exit(1); - } - - b = evhttp_request_get_output_buffer(req); - if (evbuffer_get_length(b) != 0) { - fprintf(stdout, "FAILED on_complete_cb output buffer not written\n"); - exit(1); - } - - event_debug(("%s: called\n", __func__)); - - ++test_ok; -} - -static void -http_on_complete_cb(struct evhttp_request *req, void *arg) -{ - struct evbuffer *evb = evbuffer_new(); - - evhttp_request_set_on_complete_cb(req, http_sent_cb, (void *)0xDEADBEEF); - - event_debug(("%s: called\n", __func__)); - evbuffer_add_printf(evb, BASIC_REQUEST_BODY); - - /* allow sending of an empty reply */ - evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb); - - evbuffer_free(evb); - - ++test_ok; -} - -static void -http_on_complete_test(void *arg) -{ - struct basic_test_data *data = arg; - struct bufferevent *bev; - evutil_socket_t fd = -1; - const char *http_request; - ev_uint16_t port = 0; - - test_ok = 0; - - http = http_setup(&port, data->base, 0); - - fd = http_connect("127.0.0.1", port); - tt_int_op(fd, >=, 0); - - /* Stupid thing to send a request */ - bev = bufferevent_socket_new(data->base, fd, 0); - bufferevent_setcb(bev, http_readcb, http_writecb, - http_errorcb, data->base); - - http_request = - "GET /oncomplete HTTP/1.1\r\n" - "Host: somehost\r\n" - "Connection: close\r\n" - "\r\n"; - - bufferevent_write(bev, http_request, strlen(http_request)); - - event_base_dispatch(data->base); - - bufferevent_free(bev); - - evhttp_free(http); - - tt_int_op(test_ok, ==, 4); - end: - if (fd >= 0) - evutil_closesocket(fd); -} - -static void -http_allowed_methods_eventcb(struct bufferevent *bev, short what, void *arg) -{ - char **output = arg; - if ((what & (BEV_EVENT_ERROR|BEV_EVENT_EOF))) { - char buf[4096]; - int n; - n = evbuffer_remove(bufferevent_get_input(bev), buf, - sizeof(buf)-1); - if (n >= 0) { - buf[n]='\0'; - if (*output) - free(*output); - *output = strdup(buf); - } - event_base_loopexit(exit_base, NULL); - } -} - -static void -http_allowed_methods_test(void *arg) -{ - struct basic_test_data *data = arg; - struct bufferevent *bev1, *bev2, *bev3; - evutil_socket_t fd1=-1, fd2=-1, fd3=-1; - const char *http_request; - char *result1=NULL, *result2=NULL, *result3=NULL; - ev_uint16_t port = 0; - - exit_base = data->base; - test_ok = 0; - - http = http_setup(&port, data->base, 0); - - fd1 = http_connect("127.0.0.1", port); - tt_int_op(fd1, >=, 0); - - /* GET is out; PATCH is in. */ - evhttp_set_allowed_methods(http, EVHTTP_REQ_PATCH); - - /* Stupid thing to send a request */ - bev1 = bufferevent_socket_new(data->base, fd1, 0); - bufferevent_enable(bev1, EV_READ|EV_WRITE); - bufferevent_setcb(bev1, NULL, NULL, - http_allowed_methods_eventcb, &result1); - - http_request = - "GET /index.html HTTP/1.1\r\n" - "Host: somehost\r\n" - "Connection: close\r\n" - "\r\n"; - - bufferevent_write(bev1, http_request, strlen(http_request)); - - event_base_dispatch(data->base); - - fd2 = http_connect("127.0.0.1", port); - tt_int_op(fd2, >=, 0); - - bev2 = bufferevent_socket_new(data->base, fd2, 0); - bufferevent_enable(bev2, EV_READ|EV_WRITE); - bufferevent_setcb(bev2, NULL, NULL, - http_allowed_methods_eventcb, &result2); - - http_request = - "PATCH /test HTTP/1.1\r\n" - "Host: somehost\r\n" - "Connection: close\r\n" - "\r\n"; - - bufferevent_write(bev2, http_request, strlen(http_request)); - - event_base_dispatch(data->base); - - fd3 = http_connect("127.0.0.1", port); - tt_int_op(fd3, >=, 0); - - bev3 = bufferevent_socket_new(data->base, fd3, 0); - bufferevent_enable(bev3, EV_READ|EV_WRITE); - bufferevent_setcb(bev3, NULL, NULL, - http_allowed_methods_eventcb, &result3); - - http_request = - "FLOOP /test HTTP/1.1\r\n" - "Host: somehost\r\n" - "Connection: close\r\n" - "\r\n"; - - bufferevent_write(bev3, http_request, strlen(http_request)); - - event_base_dispatch(data->base); - - bufferevent_free(bev1); - bufferevent_free(bev2); - bufferevent_free(bev3); - - evhttp_free(http); - - /* Method known but disallowed */ - tt_assert(result1); - tt_assert(!strncmp(result1, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 "))); - - /* Method known and allowed */ - tt_assert(result2); - tt_assert(!strncmp(result2, "HTTP/1.1 200 ", strlen("HTTP/1.1 200 "))); - - /* Method unknown */ - tt_assert(result3); - tt_assert(!strncmp(result3, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 "))); - - end: - if (result1) - free(result1); - if (result2) - free(result2); - if (result3) - free(result3); - if (fd1 >= 0) - evutil_closesocket(fd1); - if (fd2 >= 0) - evutil_closesocket(fd2); - if (fd3 >= 0) - evutil_closesocket(fd3); -} - -static void http_request_no_action_done(struct evhttp_request *, void *); -static void http_request_done(struct evhttp_request *, void *); -static void http_request_empty_done(struct evhttp_request *, void *); - -static void -http_connection_test_(struct basic_test_data *data, int persistent, - const char *address, struct evdns_base *dnsbase, int ipv6, int family) -{ - ev_uint16_t port = 0; - struct evhttp_connection *evcon = NULL; - struct evhttp_request *req = NULL; - - test_ok = 0; - - http = http_setup(&port, data->base, ipv6); - if (!http && ipv6) { - tt_skip(); - } - tt_assert(http); - - evcon = evhttp_connection_base_new(data->base, dnsbase, address, port); - tt_assert(evcon); - evhttp_connection_set_family(evcon, family); - - tt_assert(evhttp_connection_get_base(evcon) == data->base); - - exit_base = data->base; - - tt_assert(evhttp_connection_get_server(evcon) == NULL); - - /* - * At this point, we want to schedule a request to the HTTP - * server using our make request method. - */ - req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { - fprintf(stdout, "FAILED\n"); - exit(1); - } - - event_base_dispatch(data->base); - - tt_assert(test_ok); - - /* try to make another request over the same connection */ - test_ok = 0; - - req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); - - /* - * if our connections are not supposed to be persistent; request - * a close from the server. - */ - if (!persistent) - evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close"); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { - tt_abort_msg("couldn't make request"); - } - - event_base_dispatch(data->base); - - /* make another request: request empty reply */ - test_ok = 0; - - req = evhttp_request_new(http_request_empty_done, data->base); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis"); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { - tt_abort_msg("Couldn't make request"); - } - - event_base_dispatch(data->base); - - end: - if (evcon) - evhttp_connection_free(evcon); - if (http) - evhttp_free(http); -} - -static void -http_connection_test(void *arg) -{ - http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC); -} -static void -http_persist_connection_test(void *arg) -{ - http_connection_test_(arg, 1, "127.0.0.1", NULL, 0, AF_UNSPEC); -} - -static struct regress_dns_server_table search_table[] = { - { "localhost", "A", "127.0.0.1", 0, 0 }, - { NULL, NULL, NULL, 0, 0 } -}; - -static void -http_connection_async_test(void *arg) -{ - struct basic_test_data *data = arg; - ev_uint16_t port = 0; - struct evhttp_connection *evcon = NULL; - struct evhttp_request *req = NULL; - struct evdns_base *dns_base = NULL; - ev_uint16_t portnum = 0; - char address[64]; - - exit_base = data->base; - tt_assert(regress_dnsserver(data->base, &portnum, search_table)); - - dns_base = evdns_base_new(data->base, 0/* init name servers */); - tt_assert(dns_base); - - /* Add ourself as the only nameserver, and make sure we really are - * the only nameserver. */ - evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum); - evdns_base_nameserver_ip_add(dns_base, address); - - test_ok = 0; - - http = http_setup(&port, data->base, 0); - - evcon = evhttp_connection_base_new(data->base, dns_base, "127.0.0.1", port); - tt_assert(evcon); - - /* - * At this point, we want to schedule a request to the HTTP - * server using our make request method. - */ - - req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { - fprintf(stdout, "FAILED\n"); - exit(1); - } - - event_base_dispatch(data->base); - - tt_assert(test_ok); - - /* try to make another request over the same connection */ - test_ok = 0; - - req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); - - /* - * if our connections are not supposed to be persistent; request - * a close from the server. - */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close"); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { - tt_abort_msg("couldn't make request"); - } - - event_base_dispatch(data->base); - - /* make another request: request empty reply */ - test_ok = 0; - - req = evhttp_request_new(http_request_empty_done, data->base); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis"); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { - tt_abort_msg("Couldn't make request"); - } - - event_base_dispatch(data->base); - - end: - if (evcon) - evhttp_connection_free(evcon); - if (http) - evhttp_free(http); - if (dns_base) - evdns_base_free(dns_base, 0); - regress_clean_dnsserver(); -} - -static void -http_autofree_connection_test(void *arg) -{ - struct basic_test_data *data = arg; - ev_uint16_t port = 0; - struct evhttp_connection *evcon = NULL; - struct evhttp_request *req[2] = { NULL }; - - test_ok = 0; - http = http_setup(&port, data->base, 0); - - evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); - tt_assert(evcon); - - /* - * At this point, we want to schedule two request to the HTTP - * server using our make request method. - */ - req[0] = evhttp_request_new(http_request_empty_done, data->base); - req[1] = evhttp_request_new(http_request_empty_done, data->base); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Host", "somehost"); - evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Connection", "close"); - evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Empty", "itis"); - evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Host", "somehost"); - evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Connection", "close"); - evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Empty", "itis"); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req[0], EVHTTP_REQ_GET, "/test") == -1) { - tt_abort_msg("couldn't make request"); - } - if (evhttp_make_request(evcon, req[1], EVHTTP_REQ_GET, "/test") == -1) { - tt_abort_msg("couldn't make request"); - } - - /* - * Tell libevent to free the connection when the request completes - * We then set the evcon pointer to NULL since we don't want to free it - * when this function ends. - */ - evhttp_connection_free_on_completion(evcon); - evcon = NULL; - - event_base_dispatch(data->base); - - /* at this point, the http server should have no connection */ - tt_assert(TAILQ_FIRST(&http->connections) == NULL); - - end: - if (evcon) - evhttp_connection_free(evcon); - if (http) - evhttp_free(http); -} - -static void -http_request_never_call(struct evhttp_request *req, void *arg) -{ - fprintf(stdout, "FAILED\n"); - exit(1); -} - -static void -http_do_cancel(evutil_socket_t fd, short what, void *arg) -{ - struct evhttp_request *req = arg; - struct timeval tv; - struct event_base *base; - evutil_timerclear(&tv); - tv.tv_sec = 0; - tv.tv_usec = 500 * 1000; - - base = evhttp_connection_get_base(evhttp_request_get_connection(req)); - evhttp_cancel_request(req); - - event_base_loopexit(base, &tv); - - ++test_ok; -} - -static void -http_cancel_test(void *arg) -{ - struct basic_test_data *data = arg; - ev_uint16_t port = 0; - struct evhttp_connection *evcon = NULL; - struct evhttp_request *req = NULL; - struct timeval tv; - - exit_base = data->base; - - test_ok = 0; - - http = http_setup(&port, data->base, 0); - - evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); - tt_assert(evcon); - - /* - * At this point, we want to schedule a request to the HTTP - * server using our make request method. - */ - - req = evhttp_request_new(http_request_never_call, NULL); - evhttp_request_set_error_cb(req, http_request_error_cb_with_cancel_); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); - - /* We give ownership of the request to the connection */ - tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/delay"), - !=, -1); - - evutil_timerclear(&tv); - tv.tv_sec = 0; - tv.tv_usec = 100 * 1000; - - event_base_once(data->base, -1, EV_TIMEOUT, http_do_cancel, req, &tv); - - event_base_dispatch(data->base); - - tt_int_op(test_ok, ==, 3); - - /* try to make another request over the same connection */ - test_ok = 0; - - req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); - - /* We give ownership of the request to the connection */ - tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"), - !=, -1); - - event_base_dispatch(data->base); - - /* make another request: request empty reply */ - test_ok = 0; - - req = evhttp_request_new(http_request_empty_done, data->base); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis"); - - /* We give ownership of the request to the connection */ - tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"), - !=, -1); - - event_base_dispatch(data->base); - - end: - if (evcon) - evhttp_connection_free(evcon); - if (http) - evhttp_free(http); -} - -static void -http_request_no_action_done(struct evhttp_request *req, void *arg) -{ - EVUTIL_ASSERT(exit_base); - event_base_loopexit(exit_base, NULL); -} - -static void -http_request_done(struct evhttp_request *req, void *arg) -{ - const char *what = arg; - - if (evhttp_request_get_response_code(req) != HTTP_OK) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - test_ok = 1; - EVUTIL_ASSERT(exit_base); - event_base_loopexit(exit_base, NULL); -} - -static void -http_request_expect_error(struct evhttp_request *req, void *arg) -{ - if (evhttp_request_get_response_code(req) == HTTP_OK) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - test_ok = 1; - EVUTIL_ASSERT(arg); - event_base_loopexit(arg, NULL); -} - -/* test virtual hosts */ -static void -http_virtual_host_test(void *arg) -{ - struct basic_test_data *data = arg; - ev_uint16_t port = 0; - struct evhttp_connection *evcon = NULL; - struct evhttp_request *req = NULL; - struct evhttp *second = NULL, *third = NULL; - evutil_socket_t fd; - struct bufferevent *bev; - const char *http_request; - - exit_base = data->base; - - http = http_setup(&port, data->base, 0); - - /* virtual host */ - second = evhttp_new(NULL); - evhttp_set_cb(second, "/funnybunny", http_basic_cb, NULL); - third = evhttp_new(NULL); - evhttp_set_cb(third, "/blackcoffee", http_basic_cb, NULL); - - if (evhttp_add_virtual_host(http, "foo.com", second) == -1) { - tt_abort_msg("Couldn't add vhost"); - } - - if (evhttp_add_virtual_host(http, "bar.*.foo.com", third) == -1) { - tt_abort_msg("Couldn't add wildcarded vhost"); - } - - /* add some aliases to the vhosts */ - tt_assert(evhttp_add_server_alias(second, "manolito.info") == 0); - tt_assert(evhttp_add_server_alias(third, "bonkers.org") == 0); - - evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); - tt_assert(evcon); - - /* make a request with a different host and expect an error */ - req = evhttp_request_new(http_request_expect_error, data->base); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, - "/funnybunny") == -1) { - tt_abort_msg("Couldn't make request"); - } - - event_base_dispatch(data->base); - - tt_assert(test_ok == 1); - - test_ok = 0; - - /* make a request with the right host and expect a response */ - req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "foo.com"); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, - "/funnybunny") == -1) { - fprintf(stdout, "FAILED\n"); - exit(1); - } - - event_base_dispatch(data->base); - - tt_assert(test_ok == 1); - - test_ok = 0; - - /* make a request with the right host and expect a response */ - req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bar.magic.foo.com"); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, - "/blackcoffee") == -1) { - tt_abort_msg("Couldn't make request"); - } - - event_base_dispatch(data->base); - - tt_assert(test_ok == 1) - - test_ok = 0; - - /* make a request with the right host and expect a response */ - req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "manolito.info"); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, - "/funnybunny") == -1) { - tt_abort_msg("Couldn't make request"); - } - - event_base_dispatch(data->base); - - tt_assert(test_ok == 1) - - test_ok = 0; - - /* make a request with the right host and expect a response */ - req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); - - /* Add the Host header. This time with the optional port. */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bonkers.org:8000"); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, - "/blackcoffee") == -1) { - tt_abort_msg("Couldn't make request"); - } - - event_base_dispatch(data->base); - - tt_assert(test_ok == 1) - - test_ok = 0; - - /* Now make a raw request with an absolute URI. */ - fd = http_connect("127.0.0.1", port); - - /* Stupid thing to send a request */ - bev = bufferevent_socket_new(data->base, fd, 0); - bufferevent_setcb(bev, http_readcb, http_writecb, - http_errorcb, NULL); - - /* The host in the URI should override the Host: header */ - http_request = - "GET http://manolito.info/funnybunny HTTP/1.1\r\n" - "Host: somehost\r\n" - "Connection: close\r\n" - "\r\n"; - - bufferevent_write(bev, http_request, strlen(http_request)); - - event_base_dispatch(data->base); - - tt_int_op(test_ok, ==, 2); - - bufferevent_free(bev); - evutil_closesocket(fd); - - end: - if (evcon) - evhttp_connection_free(evcon); - if (http) - evhttp_free(http); -} - - -/* test date header and content length */ - -static void -http_request_empty_done(struct evhttp_request *req, void *arg) -{ - if (evhttp_request_get_response_code(req) != HTTP_OK) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - if (evhttp_find_header(evhttp_request_get_input_headers(req), "Date") == NULL) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - - if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length") == NULL) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - if (strcmp(evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length"), - "0")) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - test_ok = 1; - EVUTIL_ASSERT(arg); - event_base_loopexit(arg, NULL); -} - -/* - * HTTP DISPATCHER test - */ - -void -http_dispatcher_cb(struct evhttp_request *req, void *arg) -{ - - struct evbuffer *evb = evbuffer_new(); - event_debug(("%s: called\n", __func__)); - evbuffer_add_printf(evb, "DISPATCHER_TEST"); - - evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb); - - evbuffer_free(evb); -} - -static void -http_dispatcher_test_done(struct evhttp_request *req, void *arg) -{ - struct event_base *base = arg; - const char *what = "DISPATCHER_TEST"; - - if (!req) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - if (evhttp_request_get_response_code(req) != HTTP_OK) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) { - fprintf(stderr, "FAILED (content type)\n"); - exit(1); - } - - if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) { - fprintf(stderr, "FAILED (length %lu vs %lu)\n", - (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what)); - exit(1); - } - - if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) { - fprintf(stderr, "FAILED (data)\n"); - exit(1); - } - - test_ok = 1; - event_base_loopexit(base, NULL); -} - -static void -http_dispatcher_test(void *arg) -{ - struct basic_test_data *data = arg; - ev_uint16_t port = 0; - struct evhttp_connection *evcon = NULL; - struct evhttp_request *req = NULL; - - test_ok = 0; - - http = http_setup(&port, data->base, 0); - - evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); - tt_assert(evcon); - - /* also bind to local host */ - evhttp_connection_set_local_address(evcon, "127.0.0.1"); - - /* - * At this point, we want to schedule an HTTP GET request - * server using our make request method. - */ - - req = evhttp_request_new(http_dispatcher_test_done, data->base); - tt_assert(req); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); - - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) { - tt_abort_msg("Couldn't make request"); - } - - event_base_dispatch(data->base); - - end: - if (evcon) - evhttp_connection_free(evcon); - if (http) - evhttp_free(http); -} - -/* - * HTTP POST test. - */ - -void http_postrequest_done(struct evhttp_request *, void *); - -#define POST_DATA "Okay. Not really printf" - -static void -http_post_test(void *arg) -{ - struct basic_test_data *data = arg; - ev_uint16_t port = 0; - struct evhttp_connection *evcon = NULL; - struct evhttp_request *req = NULL; - - test_ok = 0; - - http = http_setup(&port, data->base, 0); - - evcon = evhttp_connection_base_new(data->base, NULL, "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(http_postrequest_done, data->base); - tt_assert(req); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); - evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA); - - if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) { - tt_abort_msg("Couldn't make request"); - } - - event_base_dispatch(data->base); - - tt_int_op(test_ok, ==, 1); - - test_ok = 0; - - req = evhttp_request_new(http_postrequest_done, data->base); - tt_assert(req); - - /* Now try with 100-continue. */ - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); - evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue"); - evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA); - - if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) { - tt_abort_msg("Couldn't make request"); - } - - event_base_dispatch(data->base); - - tt_int_op(test_ok, ==, 1); - - evhttp_connection_free(evcon); - evhttp_free(http); - - end: - ; -} - -void -http_post_cb(struct evhttp_request *req, void *arg) -{ - struct evbuffer *evb; - event_debug(("%s: called\n", __func__)); - - /* Yes, we are expecting a post request */ - if (evhttp_request_get_command(req) != EVHTTP_REQ_POST) { - fprintf(stdout, "FAILED (post type)\n"); - exit(1); - } - - if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(POST_DATA)) { - fprintf(stdout, "FAILED (length: %lu vs %lu)\n", - (unsigned long) evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long) strlen(POST_DATA)); - exit(1); - } - - if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), POST_DATA) != 0) { - fprintf(stdout, "FAILED (data)\n"); - fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1)); - fprintf(stdout, "Want:%s\n", POST_DATA); - exit(1); - } - - evb = evbuffer_new(); - evbuffer_add_printf(evb, BASIC_REQUEST_BODY); - - evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb); - - evbuffer_free(evb); -} - -void -http_postrequest_done(struct evhttp_request *req, void *arg) -{ - const char *what = BASIC_REQUEST_BODY; - struct event_base *base = arg; - - if (req == NULL) { - fprintf(stderr, "FAILED (timeout)\n"); - exit(1); - } - - if (evhttp_request_get_response_code(req) != HTTP_OK) { - - fprintf(stderr, "FAILED (response code)\n"); - exit(1); - } - - if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) { - fprintf(stderr, "FAILED (content type)\n"); - exit(1); - } - - if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) { - fprintf(stderr, "FAILED (length %lu vs %lu)\n", - (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what)); - exit(1); - } - - if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) { - fprintf(stderr, "FAILED (data)\n"); - exit(1); - } - - test_ok = 1; - event_base_loopexit(base, NULL); -} - -/* - * HTTP PUT test, basically just like POST, but ... - */ - -void http_putrequest_done(struct evhttp_request *, void *); - -#define PUT_DATA "Hi, I'm some PUT data" - -static void -http_put_test(void *arg) -{ - struct basic_test_data *data = arg; - ev_uint16_t port = 0; - struct evhttp_connection *evcon = NULL; - struct evhttp_request *req = NULL; - - test_ok = 0; - - http = http_setup(&port, data->base, 0); - - evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); - tt_assert(evcon); - - /* - * Schedule the HTTP PUT request - */ - - req = evhttp_request_new(http_putrequest_done, data->base); - tt_assert(req); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "someotherhost"); - evbuffer_add_printf(evhttp_request_get_output_buffer(req), PUT_DATA); - - if (evhttp_make_request(evcon, req, EVHTTP_REQ_PUT, "/putit") == -1) { - tt_abort_msg("Couldn't make request"); - } - - event_base_dispatch(data->base); - - evhttp_connection_free(evcon); - evhttp_free(http); - - tt_int_op(test_ok, ==, 1); - end: - ; -} - -void -http_put_cb(struct evhttp_request *req, void *arg) -{ - struct evbuffer *evb; - event_debug(("%s: called\n", __func__)); - - /* Expecting a PUT request */ - if (evhttp_request_get_command(req) != EVHTTP_REQ_PUT) { - fprintf(stdout, "FAILED (put type)\n"); - exit(1); - } - - if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(PUT_DATA)) { - fprintf(stdout, "FAILED (length: %lu vs %lu)\n", - (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(PUT_DATA)); - exit(1); - } - - if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), PUT_DATA) != 0) { - fprintf(stdout, "FAILED (data)\n"); - fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1)); - fprintf(stdout, "Want:%s\n", PUT_DATA); - exit(1); - } - - evb = evbuffer_new(); - evbuffer_add_printf(evb, "That ain't funny"); - - evhttp_send_reply(req, HTTP_OK, "Everything is great", evb); - - evbuffer_free(evb); -} - -void -http_putrequest_done(struct evhttp_request *req, void *arg) -{ - struct event_base *base = arg; - const char *what = "That ain't funny"; - - if (req == NULL) { - fprintf(stderr, "FAILED (timeout)\n"); - exit(1); - } - - if (evhttp_request_get_response_code(req) != HTTP_OK) { - - fprintf(stderr, "FAILED (response code)\n"); - exit(1); - } - - if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) { - fprintf(stderr, "FAILED (content type)\n"); - exit(1); - } - - if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) { - fprintf(stderr, "FAILED (length %lu vs %lu)\n", - (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what)); - exit(1); - } - - - if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) { - fprintf(stderr, "FAILED (data)\n"); - exit(1); - } - - test_ok = 1; - event_base_loopexit(base, NULL); -} - -static void -http_failure_readcb(struct bufferevent *bev, void *arg) -{ - const char *what = "400 Bad Request"; - if (evbuffer_contains(bufferevent_get_input(bev), what)) { - test_ok = 2; - bufferevent_disable(bev, EV_READ); - event_base_loopexit(arg, NULL); - } -} - -/* - * Testing that the HTTP server can deal with a malformed request. - */ -static void -http_failure_test(void *arg) -{ - struct basic_test_data *data = arg; - struct bufferevent *bev; - evutil_socket_t fd = -1; - const char *http_request; - ev_uint16_t port = 0; - - test_ok = 0; - - http = http_setup(&port, data->base, 0); - - fd = http_connect("127.0.0.1", port); - tt_int_op(fd, >=, 0); - - /* Stupid thing to send a request */ - bev = bufferevent_socket_new(data->base, fd, 0); - bufferevent_setcb(bev, http_failure_readcb, http_writecb, - http_errorcb, data->base); - - http_request = "illegal request\r\n"; - - bufferevent_write(bev, http_request, strlen(http_request)); - - event_base_dispatch(data->base); - - bufferevent_free(bev); - - evhttp_free(http); - - tt_int_op(test_ok, ==, 2); - end: - if (fd >= 0) - evutil_closesocket(fd); -} - -static void -close_detect_done(struct evhttp_request *req, void *arg) -{ - struct timeval tv; - tt_assert(req); - tt_assert(evhttp_request_get_response_code(req) == HTTP_OK); - - test_ok = 1; - - end: - evutil_timerclear(&tv); - tv.tv_usec = 150000; - event_base_loopexit(arg, &tv); -} - -static void -close_detect_launch(evutil_socket_t fd, short what, void *arg) -{ - struct evhttp_connection *evcon = arg; - struct event_base *base = evhttp_connection_get_base(evcon); - struct evhttp_request *req; - - req = evhttp_request_new(close_detect_done, base); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { - tt_fail_msg("Couldn't make request"); - } -} - -static void -close_detect_cb(struct evhttp_request *req, void *arg) -{ - struct evhttp_connection *evcon = arg; - struct event_base *base = evhttp_connection_get_base(evcon); - struct timeval tv; - - if (req != NULL && evhttp_request_get_response_code(req) != HTTP_OK) { - tt_abort_msg("Failed"); - } - - evutil_timerclear(&tv); - tv.tv_sec = 0; /* longer than the http time out */ - tv.tv_usec = 600000; /* longer than the http time out */ - - /* launch a new request on the persistent connection in .3 seconds */ - event_base_once(base, -1, EV_TIMEOUT, close_detect_launch, evcon, &tv); - end: - ; -} - - -static void -http_close_detection_(struct basic_test_data *data, int with_delay) -{ - ev_uint16_t port = 0; - struct evhttp_connection *evcon = NULL; - struct evhttp_request *req = NULL; - const struct timeval sec_tenth = { 0, 100000 }; - - test_ok = 0; - http = http_setup(&port, data->base, 0); - - /* .1 second timeout */ - evhttp_set_timeout_tv(http, &sec_tenth); - - evcon = evhttp_connection_base_new(data->base, NULL, - "127.0.0.1", port); - tt_assert(evcon); - evhttp_connection_set_timeout_tv(evcon, &sec_tenth); - - - tt_assert(evcon); - delayed_client = evcon; - - /* - * At this point, we want to schedule a request to the HTTP - * server using our make request method. - */ - - req = evhttp_request_new(close_detect_cb, evcon); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, - req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) { - tt_abort_msg("couldn't make request"); - } - - event_base_dispatch(data->base); - - /* at this point, the http server should have no connection */ - tt_assert(TAILQ_FIRST(&http->connections) == NULL); - - end: - if (evcon) - evhttp_connection_free(evcon); - if (http) - evhttp_free(http); -} -static void -http_close_detection_test(void *arg) -{ - http_close_detection_(arg, 0); -} -static void -http_close_detection_delay_test(void *arg) -{ - http_close_detection_(arg, 1); -} - -static void -http_highport_test(void *arg) -{ - struct basic_test_data *data = arg; - int i = -1; - struct evhttp *myhttp = NULL; - - /* Try a few different ports */ - for (i = 0; i < 50; ++i) { - myhttp = evhttp_new(data->base); - if (evhttp_bind_socket(myhttp, "127.0.0.1", 65535 - i) == 0) { - test_ok = 1; - evhttp_free(myhttp); - return; - } - evhttp_free(myhttp); - } - - tt_fail_msg("Couldn't get a high port"); -} - -static void -http_bad_header_test(void *ptr) -{ - struct evkeyvalq headers; - - TAILQ_INIT(&headers); - - tt_want(evhttp_add_header(&headers, "One", "Two") == 0); - tt_want(evhttp_add_header(&headers, "One", "Two\r\n Three") == 0); - tt_want(evhttp_add_header(&headers, "One\r", "Two") == -1); - tt_want(evhttp_add_header(&headers, "One\n", "Two") == -1); - tt_want(evhttp_add_header(&headers, "One", "Two\r") == -1); - tt_want(evhttp_add_header(&headers, "One", "Two\n") == -1); - - evhttp_clear_headers(&headers); -} - -static int validate_header( - const struct evkeyvalq* headers, - const char *key, const char *value) -{ - const char *real_val = evhttp_find_header(headers, key); - tt_assert(real_val != NULL); - tt_want(strcmp(real_val, value) == 0); -end: - return (0); -} - -static void -http_parse_query_test(void *ptr) -{ - struct evkeyvalq headers; - int r; - - TAILQ_INIT(&headers); - - r = evhttp_parse_query("http://www.test.com/?q=test", &headers); - tt_want(validate_header(&headers, "q", "test") == 0); - tt_int_op(r, ==, 0); - evhttp_clear_headers(&headers); - - r = evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers); - tt_want(validate_header(&headers, "q", "test") == 0); - tt_want(validate_header(&headers, "foo", "bar") == 0); - tt_int_op(r, ==, 0); - evhttp_clear_headers(&headers); - - r = evhttp_parse_query("http://www.test.com/?q=test+foo", &headers); - tt_want(validate_header(&headers, "q", "test foo") == 0); - tt_int_op(r, ==, 0); - evhttp_clear_headers(&headers); - - r = evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers); - tt_want(validate_header(&headers, "q", "test\nfoo") == 0); - tt_int_op(r, ==, 0); - evhttp_clear_headers(&headers); - - r = evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers); - tt_want(validate_header(&headers, "q", "test\rfoo") == 0); - tt_int_op(r, ==, 0); - evhttp_clear_headers(&headers); - - r = evhttp_parse_query("http://www.test.com/?q=test&&q2", &headers); - tt_int_op(r, ==, -1); - evhttp_clear_headers(&headers); - - r = evhttp_parse_query("http://www.test.com/?q=test+this", &headers); - tt_want(validate_header(&headers, "q", "test this") == 0); - tt_int_op(r, ==, 0); - evhttp_clear_headers(&headers); - - r = evhttp_parse_query("http://www.test.com/?q=test&q2=foo", &headers); - tt_int_op(r, ==, 0); - tt_want(validate_header(&headers, "q", "test") == 0); - tt_want(validate_header(&headers, "q2", "foo") == 0); - evhttp_clear_headers(&headers); - - r = evhttp_parse_query("http://www.test.com/?q&q2=foo", &headers); - tt_int_op(r, ==, -1); - evhttp_clear_headers(&headers); - - r = evhttp_parse_query("http://www.test.com/?q=foo&q2", &headers); - tt_int_op(r, ==, -1); - evhttp_clear_headers(&headers); - - r = evhttp_parse_query("http://www.test.com/?q=foo&q2&q3=x", &headers); - tt_int_op(r, ==, -1); - evhttp_clear_headers(&headers); - - r = evhttp_parse_query("http://www.test.com/?q=&q2=&q3=", &headers); - tt_int_op(r, ==, 0); - tt_want(validate_header(&headers, "q", "") == 0); - tt_want(validate_header(&headers, "q2", "") == 0); - tt_want(validate_header(&headers, "q3", "") == 0); - evhttp_clear_headers(&headers); - -end: - evhttp_clear_headers(&headers); -} - -static void -http_parse_uri_test(void *ptr) -{ - const int nonconform = (ptr != NULL); - const unsigned parse_flags = - nonconform ? EVHTTP_URI_NONCONFORMANT : 0; - struct evhttp_uri *uri = NULL; - char url_tmp[4096]; -#define URI_PARSE(uri) \ - evhttp_uri_parse_with_flags((uri), parse_flags) - -#define TT_URI(want) do { \ - char *ret = evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)); \ - tt_want(ret != NULL); \ - tt_want(ret == url_tmp); \ - if (strcmp(ret,want) != 0) \ - TT_FAIL(("\"%s\" != \"%s\"",ret,want)); \ - } while(0) - - tt_want(evhttp_uri_join(NULL, 0, 0) == NULL); - tt_want(evhttp_uri_join(NULL, url_tmp, 0) == NULL); - tt_want(evhttp_uri_join(NULL, url_tmp, sizeof(url_tmp)) == NULL); - - /* bad URIs: parsing */ -#define BAD(s) do { \ - if (URI_PARSE(s) != NULL) \ - TT_FAIL(("Expected error parsing \"%s\"",s)); \ - } while(0) - /* Nonconformant URIs we can parse: parsing */ -#define NCF(s) do { \ - uri = URI_PARSE(s); \ - if (uri != NULL && !nonconform) { \ - TT_FAIL(("Expected error parsing \"%s\"",s)); \ - } else if (uri == NULL && nonconform) { \ - TT_FAIL(("Couldn't parse nonconformant URI \"%s\"", \ - s)); \ - } \ - if (uri) { \ - tt_want(evhttp_uri_join(uri, url_tmp, \ - sizeof(url_tmp))); \ - evhttp_uri_free(uri); \ - } \ - } while(0) - - NCF("http://www.test.com/ why hello"); - NCF("http://www.test.com/why-hello\x01"); - NCF("http://www.test.com/why-hello?\x01"); - NCF("http://www.test.com/why-hello#\x01"); - BAD("http://www.\x01.test.com/why-hello"); - BAD("http://www.%7test.com/why-hello"); - NCF("http://www.test.com/why-hell%7o"); - BAD("h%3ttp://www.test.com/why-hello"); - NCF("http://www.test.com/why-hello%7"); - NCF("http://www.test.com/why-hell%7o"); - NCF("http://www.test.com/foo?ba%r"); - NCF("http://www.test.com/foo#ba%r"); - BAD("99:99/foo"); - BAD("http://www.test.com:999x/"); - BAD("http://www.test.com:x/"); - BAD("http://[hello-there]/"); - BAD("http://[::1]]/"); - BAD("http://[::1/"); - BAD("http://[foob/"); - BAD("http://[/"); - BAD("http://[ffff:ffff:ffff:ffff:Ffff:ffff:ffff:" - "ffff:ffff:ffff:ffff:ffff:ffff:ffff]/"); - BAD("http://[vX.foo]/"); - BAD("http://[vX.foo]/"); - BAD("http://[v.foo]/"); - BAD("http://[v5.fo%o]/"); - BAD("http://[v5X]/"); - BAD("http://[v5]/"); - BAD("http://[]/"); - BAD("http://f\x01red@www.example.com/"); - BAD("http://f%0red@www.example.com/"); - BAD("http://www.example.com:9999999999999999999999999999999999999/"); - BAD("http://www.example.com:hihi/"); - BAD("://www.example.com/"); - - /* bad URIs: joining */ - uri = evhttp_uri_new(); - tt_want(0==evhttp_uri_set_host(uri, "www.example.com")); - tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) != NULL); - /* not enough space: */ - tt_want(evhttp_uri_join(uri, url_tmp, 3) == NULL); - /* host is set, but path doesn't start with "/": */ - tt_want(0==evhttp_uri_set_path(uri, "hi_mom")); - tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) == NULL); - tt_want(evhttp_uri_join(uri, NULL, sizeof(url_tmp))==NULL); - tt_want(evhttp_uri_join(uri, url_tmp, 0)==NULL); - evhttp_uri_free(uri); - uri = URI_PARSE("mailto:foo@bar"); - tt_want(uri != NULL); - tt_want(evhttp_uri_get_host(uri) == NULL); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(!strcmp(evhttp_uri_get_scheme(uri), "mailto")); - tt_want(!strcmp(evhttp_uri_get_path(uri), "foo@bar")); - tt_want(evhttp_uri_get_query(uri) == NULL); - tt_want(evhttp_uri_get_fragment(uri) == NULL); - TT_URI("mailto:foo@bar"); - evhttp_uri_free(uri); - - uri = evhttp_uri_new(); - /* Bad URI usage: setting invalid values */ - tt_want(-1 == evhttp_uri_set_scheme(uri,"")); - tt_want(-1 == evhttp_uri_set_scheme(uri,"33")); - tt_want(-1 == evhttp_uri_set_scheme(uri,"hi!")); - tt_want(-1 == evhttp_uri_set_userinfo(uri,"hello@")); - tt_want(-1 == evhttp_uri_set_host(uri,"[1.2.3.4]")); - tt_want(-1 == evhttp_uri_set_host(uri,"[")); - tt_want(-1 == evhttp_uri_set_host(uri,"www.[foo].com")); - tt_want(-1 == evhttp_uri_set_port(uri,-3)); - tt_want(-1 == evhttp_uri_set_path(uri,"hello?world")); - tt_want(-1 == evhttp_uri_set_query(uri,"hello#world")); - tt_want(-1 == evhttp_uri_set_fragment(uri,"hello#world")); - /* Valid URI usage: setting valid values */ - tt_want(0 == evhttp_uri_set_scheme(uri,"http")); - tt_want(0 == evhttp_uri_set_scheme(uri,NULL)); - tt_want(0 == evhttp_uri_set_userinfo(uri,"username:pass")); - tt_want(0 == evhttp_uri_set_userinfo(uri,NULL)); - tt_want(0 == evhttp_uri_set_host(uri,"www.example.com")); - tt_want(0 == evhttp_uri_set_host(uri,"1.2.3.4")); - tt_want(0 == evhttp_uri_set_host(uri,"[1:2:3:4::]")); - tt_want(0 == evhttp_uri_set_host(uri,"[v7.wobblewobble]")); - tt_want(0 == evhttp_uri_set_host(uri,NULL)); - tt_want(0 == evhttp_uri_set_host(uri,"")); - tt_want(0 == evhttp_uri_set_port(uri, -1)); - tt_want(0 == evhttp_uri_set_port(uri, 80)); - tt_want(0 == evhttp_uri_set_port(uri, 65535)); - tt_want(0 == evhttp_uri_set_path(uri, "")); - tt_want(0 == evhttp_uri_set_path(uri, "/documents/public/index.html")); - tt_want(0 == evhttp_uri_set_path(uri, NULL)); - tt_want(0 == evhttp_uri_set_query(uri, "key=val&key2=val2")); - tt_want(0 == evhttp_uri_set_query(uri, "keyvalblarg")); - tt_want(0 == evhttp_uri_set_query(uri, "")); - tt_want(0 == evhttp_uri_set_query(uri, NULL)); - tt_want(0 == evhttp_uri_set_fragment(uri, "")); - tt_want(0 == evhttp_uri_set_fragment(uri, "here?i?am")); - tt_want(0 == evhttp_uri_set_fragment(uri, NULL)); - evhttp_uri_free(uri); - - /* Valid parsing */ - uri = URI_PARSE("http://www.test.com/?q=t%33est"); - tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0); - tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0); - tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); - tt_want(strcmp(evhttp_uri_get_query(uri), "q=t%33est") == 0); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(evhttp_uri_get_fragment(uri) == NULL); - TT_URI("http://www.test.com/?q=t%33est"); - evhttp_uri_free(uri); - - uri = URI_PARSE("http://%77ww.test.com"); - tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0); - tt_want(strcmp(evhttp_uri_get_host(uri), "%77ww.test.com") == 0); - tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0); - tt_want(evhttp_uri_get_query(uri) == NULL); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(evhttp_uri_get_fragment(uri) == NULL); - TT_URI("http://%77ww.test.com"); - evhttp_uri_free(uri); - - uri = URI_PARSE("http://www.test.com?q=test"); - tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0); - tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0); - tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0); - tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(evhttp_uri_get_fragment(uri) == NULL); - TT_URI("http://www.test.com?q=test"); - evhttp_uri_free(uri); - - uri = URI_PARSE("http://www.test.com#fragment"); - tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0); - tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0); - tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0); - tt_want(evhttp_uri_get_query(uri) == NULL); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want_str_op(evhttp_uri_get_fragment(uri), ==, "fragment"); - TT_URI("http://www.test.com#fragment"); - evhttp_uri_free(uri); - - uri = URI_PARSE("http://8000/"); - tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0); - tt_want(strcmp(evhttp_uri_get_host(uri), "8000") == 0); - tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); - tt_want(evhttp_uri_get_query(uri) == NULL); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(evhttp_uri_get_fragment(uri) == NULL); - TT_URI("http://8000/"); - evhttp_uri_free(uri); - - uri = URI_PARSE("http://:8000/"); - tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0); - tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0); - tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); - tt_want(evhttp_uri_get_query(uri) == NULL); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(evhttp_uri_get_port(uri) == 8000); - tt_want(evhttp_uri_get_fragment(uri) == NULL); - TT_URI("http://:8000/"); - evhttp_uri_free(uri); - - uri = URI_PARSE("http://www.test.com:/"); /* empty port */ - tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0); - tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0); - tt_want_str_op(evhttp_uri_get_path(uri), ==, "/"); - tt_want(evhttp_uri_get_query(uri) == NULL); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(evhttp_uri_get_fragment(uri) == NULL); - TT_URI("http://www.test.com/"); - evhttp_uri_free(uri); - - uri = URI_PARSE("http://www.test.com:"); /* empty port 2 */ - tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0); - tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0); - tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0); - tt_want(evhttp_uri_get_query(uri) == NULL); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(evhttp_uri_get_fragment(uri) == NULL); - TT_URI("http://www.test.com"); - evhttp_uri_free(uri); - - uri = URI_PARSE("ftp://www.test.com/?q=test"); - tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0); - tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0); - tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); - tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(evhttp_uri_get_fragment(uri) == NULL); - TT_URI("ftp://www.test.com/?q=test"); - evhttp_uri_free(uri); - - uri = URI_PARSE("ftp://[::1]:999/?q=test"); - tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0); - tt_want(strcmp(evhttp_uri_get_host(uri), "[::1]") == 0); - tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); - tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(evhttp_uri_get_port(uri) == 999); - tt_want(evhttp_uri_get_fragment(uri) == NULL); - TT_URI("ftp://[::1]:999/?q=test"); - evhttp_uri_free(uri); - - uri = URI_PARSE("ftp://[ff00::127.0.0.1]/?q=test"); - tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0); - tt_want(strcmp(evhttp_uri_get_host(uri), "[ff00::127.0.0.1]") == 0); - tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); - tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(evhttp_uri_get_fragment(uri) == NULL); - TT_URI("ftp://[ff00::127.0.0.1]/?q=test"); - evhttp_uri_free(uri); - - uri = URI_PARSE("ftp://[v99.not_(any:time)_soon]/?q=test"); - tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0); - tt_want(strcmp(evhttp_uri_get_host(uri), "[v99.not_(any:time)_soon]") == 0); - tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); - tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(evhttp_uri_get_fragment(uri) == NULL); - TT_URI("ftp://[v99.not_(any:time)_soon]/?q=test"); - evhttp_uri_free(uri); - - uri = URI_PARSE("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment"); - tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0); - tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user:pass") == 0); - tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0); - tt_want(evhttp_uri_get_port(uri) == 42); - tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); - tt_want(strcmp(evhttp_uri_get_query(uri), "q=test&s=some+thing") == 0); - tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0); - TT_URI("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment"); - evhttp_uri_free(uri); - - uri = URI_PARSE("scheme://user@foo.com/#fragment"); - tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0); - tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user") == 0); - tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); - tt_want(evhttp_uri_get_query(uri) == NULL); - tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0); - TT_URI("scheme://user@foo.com/#fragment"); - evhttp_uri_free(uri); - - uri = URI_PARSE("scheme://%75ser@foo.com/#frag@ment"); - tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0); - tt_want(strcmp(evhttp_uri_get_userinfo(uri), "%75ser") == 0); - tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); - tt_want(evhttp_uri_get_query(uri) == NULL); - tt_want(strcmp(evhttp_uri_get_fragment(uri), "frag@ment") == 0); - TT_URI("scheme://%75ser@foo.com/#frag@ment"); - evhttp_uri_free(uri); - - uri = URI_PARSE("file:///some/path/to/the/file"); - tt_want(strcmp(evhttp_uri_get_scheme(uri), "file") == 0); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the/file") == 0); - tt_want(evhttp_uri_get_query(uri) == NULL); - tt_want(evhttp_uri_get_fragment(uri) == NULL); - TT_URI("file:///some/path/to/the/file"); - evhttp_uri_free(uri); - - uri = URI_PARSE("///some/path/to/the-file"); - tt_want(uri != NULL); - tt_want(evhttp_uri_get_scheme(uri) == NULL); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the-file") == 0); - tt_want(evhttp_uri_get_query(uri) == NULL); - tt_want(evhttp_uri_get_fragment(uri) == NULL); - TT_URI("///some/path/to/the-file"); - evhttp_uri_free(uri); - - uri = URI_PARSE("/s:ome/path/to/the-file?q=99#fred"); - tt_want(uri != NULL); - tt_want(evhttp_uri_get_scheme(uri) == NULL); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(evhttp_uri_get_host(uri) == NULL); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(strcmp(evhttp_uri_get_path(uri), "/s:ome/path/to/the-file") == 0); - tt_want(strcmp(evhttp_uri_get_query(uri), "q=99") == 0); - tt_want(strcmp(evhttp_uri_get_fragment(uri), "fred") == 0); - TT_URI("/s:ome/path/to/the-file?q=99#fred"); - evhttp_uri_free(uri); - - uri = URI_PARSE("relative/path/with/co:lon"); - tt_want(uri != NULL); - tt_want(evhttp_uri_get_scheme(uri) == NULL); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(evhttp_uri_get_host(uri) == NULL); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(strcmp(evhttp_uri_get_path(uri), "relative/path/with/co:lon") == 0); - tt_want(evhttp_uri_get_query(uri) == NULL); - tt_want(evhttp_uri_get_fragment(uri) == NULL); - TT_URI("relative/path/with/co:lon"); - evhttp_uri_free(uri); - - uri = URI_PARSE("bob?q=99&q2=q?33#fr?ed"); - tt_want(uri != NULL); - tt_want(evhttp_uri_get_scheme(uri) == NULL); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(evhttp_uri_get_host(uri) == NULL); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(strcmp(evhttp_uri_get_path(uri), "bob") == 0); - tt_want(strcmp(evhttp_uri_get_query(uri), "q=99&q2=q?33") == 0); - tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0); - TT_URI("bob?q=99&q2=q?33#fr?ed"); - evhttp_uri_free(uri); - - uri = URI_PARSE("#fr?ed"); - tt_want(uri != NULL); - tt_want(evhttp_uri_get_scheme(uri) == NULL); - tt_want(evhttp_uri_get_userinfo(uri) == NULL); - tt_want(evhttp_uri_get_host(uri) == NULL); - tt_want(evhttp_uri_get_port(uri) == -1); - tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0); - tt_want(evhttp_uri_get_query(uri) == NULL); - tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0); - TT_URI("#fr?ed"); - evhttp_uri_free(uri); -#undef URI_PARSE -#undef TT_URI -#undef BAD -} - -static void -http_uriencode_test(void *ptr) -{ - char *s=NULL, *s2=NULL; - size_t sz; - int bytes_decoded; - -#define ENC(from,want,plus) do { \ - s = evhttp_uriencode((from), -1, (plus)); \ - tt_assert(s); \ - tt_str_op(s,==,(want)); \ - sz = -1; \ - s2 = evhttp_uridecode((s), (plus), &sz); \ - tt_assert(s2); \ - tt_str_op(s2,==,(from)); \ - tt_int_op(sz,==,strlen(from)); \ - free(s); \ - free(s2); \ - s = s2 = NULL; \ - } while (0) - -#define DEC(from,want,dp) do { \ - s = evhttp_uridecode((from),(dp),&sz); \ - tt_assert(s); \ - tt_str_op(s,==,(want)); \ - tt_int_op(sz,==,strlen(want)); \ - free(s); \ - s = NULL; \ - } while (0) - -#define OLD_DEC(from,want) do { \ - s = evhttp_decode_uri((from)); \ - tt_assert(s); \ - tt_str_op(s,==,(want)); \ - free(s); \ - s = NULL; \ - } while (0) - - - ENC("Hello", "Hello",0); - ENC("99", "99",0); - ENC("", "",0); - ENC( - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_", - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",0); - ENC(" ", "%20",0); - ENC(" ", "+",1); - ENC("\xff\xf0\xe0", "%FF%F0%E0",0); - ENC("\x01\x19", "%01%19",1); - ENC("http://www.ietf.org/rfc/rfc3986.txt", - "http%3A%2F%2Fwww.ietf.org%2Frfc%2Frfc3986.txt",1); - - ENC("1+2=3", "1%2B2%3D3",1); - ENC("1+2=3", "1%2B2%3D3",0); - - /* Now try encoding with internal NULs. */ - s = evhttp_uriencode("hello\0world", 11, 0); - tt_assert(s); - tt_str_op(s,==,"hello%00world"); - free(s); - s = NULL; - - /* Now try decoding just part of string. */ - s = malloc(6 + 1 /* NUL byte */); - bytes_decoded = evhttp_decode_uri_internal("hello%20%20", 6, s, 0); - tt_assert(s); - tt_int_op(bytes_decoded,==,6); - tt_str_op(s,==,"hello%"); - free(s); - s = NULL; - - /* Now try out some decoding cases that we don't generate with - * encode_uri: Make sure that malformed stuff doesn't crash... */ - DEC("%%xhello th+ere \xff", - "%%xhello th+ere \xff", 0); - /* Make sure plus decoding works */ - DEC("plus+should%20work+", "plus should work ",1); - /* Try some lowercase hex */ - DEC("%f0%a0%b0", "\xf0\xa0\xb0",1); - - /* Try an internal NUL. */ - sz = 0; - s = evhttp_uridecode("%00%00x%00%00", 1, &sz); - tt_int_op(sz,==,5); - tt_assert(!memcmp(s, "\0\0x\0\0", 5)); - free(s); - s = NULL; - - /* Try with size == NULL */ - sz = 0; - s = evhttp_uridecode("%00%00x%00%00", 1, NULL); - tt_assert(!memcmp(s, "\0\0x\0\0", 5)); - free(s); - s = NULL; - - /* Test out the crazy old behavior of the deprecated - * evhttp_decode_uri */ - OLD_DEC("http://example.com/normal+path/?key=val+with+spaces", - "http://example.com/normal+path/?key=val with spaces"); - -end: - if (s) - free(s); - if (s2) - free(s2); -#undef ENC -#undef DEC -#undef OLD_DEC -} - -static void -http_base_test(void *ptr) -{ - struct event_base *base = NULL; - struct bufferevent *bev; - evutil_socket_t fd; - const char *http_request; - ev_uint16_t port = 0; - - test_ok = 0; - base = event_base_new(); - tt_assert(base); - http = http_setup(&port, base, 0); - - fd = http_connect("127.0.0.1", port); - tt_int_op(fd, >=, 0); - - /* Stupid thing to send a request */ - bev = bufferevent_socket_new(base, fd, 0); - bufferevent_setcb(bev, http_readcb, http_writecb, - http_errorcb, base); - bufferevent_base_set(base, bev); - - http_request = - "GET /test HTTP/1.1\r\n" - "Host: somehost\r\n" - "Connection: close\r\n" - "\r\n"; - - bufferevent_write(bev, http_request, strlen(http_request)); - - event_base_dispatch(base); - - bufferevent_free(bev); - evutil_closesocket(fd); - - evhttp_free(http); - - tt_int_op(test_ok, ==, 2); - -end: - if (base) - event_base_free(base); -} - -/* - * the server is just going to close the connection if it times out during - * reading the headers. - */ - -static void -http_incomplete_readcb(struct bufferevent *bev, void *arg) -{ - test_ok = -1; - event_base_loopexit(exit_base,NULL); -} - -static void -http_incomplete_errorcb(struct bufferevent *bev, short what, void *arg) -{ - /** For ssl */ - if (what & BEV_EVENT_CONNECTED) - return; - - if (what == (BEV_EVENT_READING|BEV_EVENT_EOF)) - test_ok++; - else - test_ok = -2; - event_base_loopexit(exit_base,NULL); -} - -static void -http_incomplete_writecb(struct bufferevent *bev, void *arg) -{ - if (arg != NULL) { - evutil_socket_t fd = *(evutil_socket_t *)arg; - /* terminate the write side to simulate EOF */ - shutdown(fd, SHUT_WR); - } - if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) { - /* enable reading of the reply */ - bufferevent_enable(bev, EV_READ); - test_ok++; - } -} - -static void -http_incomplete_test_(struct basic_test_data *data, int use_timeout, int ssl) -{ - struct bufferevent *bev; - evutil_socket_t fd; - const char *http_request; - ev_uint16_t port = 0; - struct timeval tv_start, tv_end; - - exit_base = data->base; - - test_ok = 0; - - http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0); - evhttp_set_timeout(http, 1); - - fd = http_connect("127.0.0.1", port); - tt_int_op(fd, >=, 0); - - /* Stupid thing to send a request */ - bev = create_bev(data->base, fd, ssl); - bufferevent_setcb(bev, - http_incomplete_readcb, http_incomplete_writecb, - http_incomplete_errorcb, use_timeout ? NULL : &fd); - - http_request = - "GET /test HTTP/1.1\r\n" - "Host: somehost\r\n"; - - bufferevent_write(bev, http_request, strlen(http_request)); - - evutil_gettimeofday(&tv_start, NULL); - - event_base_dispatch(data->base); - - evutil_gettimeofday(&tv_end, NULL); - evutil_timersub(&tv_end, &tv_start, &tv_end); - - bufferevent_free(bev); - if (use_timeout) { - evutil_closesocket(fd); - fd = -1; - } - - evhttp_free(http); - - if (use_timeout && tv_end.tv_sec >= 3) { - tt_abort_msg("time"); - } else if (!use_timeout && tv_end.tv_sec >= 1) { - /* we should be done immediately */ - tt_abort_msg("time"); - } - - tt_int_op(test_ok, ==, 2); - end: - if (fd >= 0) - evutil_closesocket(fd); -} -static void http_incomplete_test(void *arg) -{ http_incomplete_test_(arg, 0, 0); } -static void http_incomplete_timeout_test(void *arg) -{ http_incomplete_test_(arg, 1, 0); } - - -/* - * the server is going to reply with chunked data. - */ - -static void -http_chunked_readcb(struct bufferevent *bev, void *arg) -{ - /* nothing here */ -} - -static void -http_chunked_errorcb(struct bufferevent *bev, short what, void *arg) -{ - struct evhttp_request *req = NULL; - - /** SSL */ - if (what & BEV_EVENT_CONNECTED) - return; - - if (!test_ok) - goto out; - - test_ok = -1; - - if ((what & BEV_EVENT_EOF) != 0) { - const char *header; - enum message_read_status done; - req = evhttp_request_new(NULL, NULL); - - /* req->kind = EVHTTP_RESPONSE; */ - done = evhttp_parse_firstline_(req, bufferevent_get_input(bev)); - if (done != ALL_DATA_READ) - goto out; - - done = evhttp_parse_headers_(req, bufferevent_get_input(bev)); - if (done != ALL_DATA_READ) - goto out; - - header = evhttp_find_header(evhttp_request_get_input_headers(req), "Transfer-Encoding"); - if (header == NULL || strcmp(header, "chunked")) - goto out; - - header = evhttp_find_header(evhttp_request_get_input_headers(req), "Connection"); - if (header == NULL || strcmp(header, "close")) - goto out; - - header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF); - if (header == NULL) - goto out; - /* 13 chars */ - if (strcmp(header, "d")) { - free((void*)header); - goto out; - } - free((void*)header); - - if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 13), - "This is funny", 13)) - goto out; - - evbuffer_drain(bufferevent_get_input(bev), 13 + 2); - - header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF); - if (header == NULL) - goto out; - /* 18 chars */ - if (strcmp(header, "12")) - goto out; - free((char *)header); - - if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 18), - "but not hilarious.", 18)) - goto out; - - evbuffer_drain(bufferevent_get_input(bev), 18 + 2); - - header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF); - if (header == NULL) - goto out; - /* 8 chars */ - if (strcmp(header, "8")) { - free((void*)header); - goto out; - } - free((char *)header); - - if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 8), - "bwv 1052.", 8)) - goto out; - - evbuffer_drain(bufferevent_get_input(bev), 8 + 2); - - header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF); - if (header == NULL) - goto out; - /* 0 chars */ - if (strcmp(header, "0")) { - free((void*)header); - goto out; - } - free((void *)header); - - test_ok = 2; - } - -out: - if (req) - evhttp_request_free(req); - - event_base_loopexit(arg, NULL); -} - -static void -http_chunked_writecb(struct bufferevent *bev, void *arg) -{ - if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) { - /* enable reading of the reply */ - bufferevent_enable(bev, EV_READ); - test_ok++; - } -} - -static void -http_chunked_request_done(struct evhttp_request *req, void *arg) -{ - if (evhttp_request_get_response_code(req) != HTTP_OK) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - if (evhttp_find_header(evhttp_request_get_input_headers(req), - "Transfer-Encoding") == NULL) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 13 + 18 + 8) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - if (strncmp((char *)evbuffer_pullup(evhttp_request_get_input_buffer(req), 13 + 18 + 8), - "This is funnybut not hilarious.bwv 1052", - 13 + 18 + 8)) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - test_ok = 1; - event_base_loopexit(arg, NULL); -} - -static void -http_chunk_out_test_impl(void *arg, int ssl) -{ - struct basic_test_data *data = arg; - struct bufferevent *bev; - evutil_socket_t fd; - const char *http_request; - ev_uint16_t port = 0; - struct timeval tv_start, tv_end; - struct evhttp_connection *evcon = NULL; - struct evhttp_request *req = NULL; - int i; - - exit_base = data->base; - test_ok = 0; - - http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0); - - fd = http_connect("127.0.0.1", port); - - /* Stupid thing to send a request */ - bev = create_bev(data->base, fd, ssl); - bufferevent_setcb(bev, - http_chunked_readcb, http_chunked_writecb, - http_chunked_errorcb, data->base); - - http_request = - "GET /chunked HTTP/1.1\r\n" - "Host: somehost\r\n" - "Connection: close\r\n" - "\r\n"; - - bufferevent_write(bev, http_request, strlen(http_request)); - - evutil_gettimeofday(&tv_start, NULL); - - event_base_dispatch(data->base); - - bufferevent_free(bev); - - evutil_gettimeofday(&tv_end, NULL); - evutil_timersub(&tv_end, &tv_start, &tv_end); - - tt_int_op(tv_end.tv_sec, <, 1); - - tt_int_op(test_ok, ==, 2); - - /* now try again with the regular connection object */ - bev = create_bev(data->base, -1, ssl); - evcon = evhttp_connection_base_bufferevent_new( - data->base, NULL, bev, "127.0.0.1", port); - tt_assert(evcon); - - /* make two requests to check the keepalive behavior */ - for (i = 0; i < 2; i++) { - test_ok = 0; - req = evhttp_request_new(http_chunked_request_done,data->base); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req, - EVHTTP_REQ_GET, "/chunked") == -1) { - tt_abort_msg("Couldn't make request"); - } - - event_base_dispatch(data->base); - - tt_assert(test_ok == 1); - } - - end: - if (evcon) - evhttp_connection_free(evcon); - if (http) - evhttp_free(http); -} -static void http_chunk_out_test(void *arg) -{ return http_chunk_out_test_impl(arg, 0); } - -static void -http_stream_out_test_impl(void *arg, int ssl) -{ - struct basic_test_data *data = arg; - ev_uint16_t port = 0; - struct evhttp_connection *evcon = NULL; - struct evhttp_request *req = NULL; - struct bufferevent *bev; - - test_ok = 0; - exit_base = data->base; - - http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0); - - bev = create_bev(data->base, -1, ssl); - evcon = evhttp_connection_base_bufferevent_new( - data->base, NULL, bev, "127.0.0.1", port); - tt_assert(evcon); - - /* - * At this point, we want to schedule a request to the HTTP - * server using our make request method. - */ - - req = evhttp_request_new(http_request_done, - (void *)"This is funnybut not hilarious.bwv 1052"); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/streamed") - == -1) { - tt_abort_msg("Couldn't make request"); - } - - event_base_dispatch(data->base); - - end: - if (evcon) - evhttp_connection_free(evcon); - if (http) - evhttp_free(http); -} -static void http_stream_out_test(void *arg) -{ return http_stream_out_test_impl(arg, 0); } - -static void -http_stream_in_chunk(struct evhttp_request *req, void *arg) -{ - struct evbuffer *reply = arg; - - if (evhttp_request_get_response_code(req) != HTTP_OK) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - evbuffer_add_buffer(reply, evhttp_request_get_input_buffer(req)); -} - -static void -http_stream_in_done(struct evhttp_request *req, void *arg) -{ - if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) { - fprintf(stderr, "FAILED\n"); - exit(1); - } - - event_base_loopexit(exit_base, NULL); -} - -/** - * Makes a request and reads the response in chunks. - */ -static void -http_stream_in_test_(struct basic_test_data *data, char const *url, - size_t expected_len, char const *expected) -{ - struct evhttp_connection *evcon; - struct evbuffer *reply = evbuffer_new(); - struct evhttp_request *req = NULL; - ev_uint16_t port = 0; - - exit_base = data->base; - http = http_setup(&port, data->base, 0); - - evcon = evhttp_connection_base_new(data->base, NULL,"127.0.0.1", port); - tt_assert(evcon); - - req = evhttp_request_new(http_stream_in_done, reply); - evhttp_request_set_chunked_cb(req, http_stream_in_chunk); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, url) == -1) { - tt_abort_msg("Couldn't make request"); - } - - event_base_dispatch(data->base); - - if (evbuffer_get_length(reply) != expected_len) { - TT_DIE(("reply length %lu; expected %lu; FAILED (%s)\n", - (unsigned long)evbuffer_get_length(reply), - (unsigned long)expected_len, - (char*)evbuffer_pullup(reply, -1))); - } - - if (memcmp(evbuffer_pullup(reply, -1), expected, expected_len) != 0) { - tt_abort_msg("Memory mismatch"); - } - - test_ok = 1; - end: - if (reply) - evbuffer_free(reply); - if (evcon) - evhttp_connection_free(evcon); - if (http) - evhttp_free(http); -} - -static void -http_stream_in_test(void *arg) -{ - http_stream_in_test_(arg, "/chunked", 13 + 18 + 8, - "This is funnybut not hilarious.bwv 1052"); - - http_stream_in_test_(arg, "/test", strlen(BASIC_REQUEST_BODY), - BASIC_REQUEST_BODY); -} - -static void -http_stream_in_cancel_chunk(struct evhttp_request *req, void *arg) -{ - tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_OK); - - end: - evhttp_cancel_request(req); - event_base_loopexit(arg, NULL); -} - -static void -http_stream_in_cancel_done(struct evhttp_request *req, void *arg) -{ - /* should never be called */ - tt_fail_msg("In cancel done"); -} - -static void -http_stream_in_cancel_test(void *arg) -{ - struct basic_test_data *data = arg; - struct evhttp_connection *evcon; - struct evhttp_request *req = NULL; - ev_uint16_t port = 0; - - http = http_setup(&port, data->base, 0); - - evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); - tt_assert(evcon); - - req = evhttp_request_new(http_stream_in_cancel_done, data->base); - evhttp_request_set_chunked_cb(req, http_stream_in_cancel_chunk); - - /* We give ownership of the request to the connection */ - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/chunked") == -1) { - tt_abort_msg("Couldn't make request"); - } - - event_base_dispatch(data->base); - - test_ok = 1; - end: - evhttp_connection_free(evcon); - evhttp_free(http); - -} - -static void -http_connection_fail_done(struct evhttp_request *req, void *arg) -{ - struct evhttp_connection *evcon = arg; - struct event_base *base = evhttp_connection_get_base(evcon); - - /* An ENETUNREACH error results in an unrecoverable - * evhttp_connection error (see evhttp_connection_fail_()). The - * connection will be reset, and the user will be notified with a NULL - * req parameter. */ - tt_assert(!req); - - evhttp_connection_free(evcon); - - test_ok = 1; - - end: - event_base_loopexit(base, NULL); -} - -/* Test unrecoverable evhttp_connection errors by generating an ENETUNREACH - * error on connection. */ -static void -http_connection_fail_test_impl(void *arg, int ssl) -{ - struct basic_test_data *data = arg; - ev_uint16_t port = 0; - struct evhttp_connection *evcon = NULL; - struct evhttp_request *req = NULL; - struct bufferevent *bev; - - exit_base = data->base; - test_ok = 0; - - /* auto detect a port */ - http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0); - evhttp_free(http); - http = NULL; - - bev = create_bev(data->base, -1, ssl); - /* Pick an unroutable address. This administratively scoped multicast - * address should do when working with TCP. */ - evcon = evhttp_connection_base_bufferevent_new( - data->base, NULL, bev, "239.10.20.30", 80); - tt_assert(evcon); - - /* - * At this point, we want to schedule an HTTP GET request - * server using our make request method. - */ - - req = evhttp_request_new(http_connection_fail_done, evcon); - tt_assert(req); - - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/") == -1) { - tt_abort_msg("Couldn't make request"); - } - - event_base_dispatch(data->base); - - tt_int_op(test_ok, ==, 1); - - end: - ; -} -static void http_connection_fail_test(void *arg) -{ return http_connection_fail_test_impl(arg, 0); } - -static void -http_connection_retry_done(struct evhttp_request *req, void *arg) -{ - tt_assert(req); - tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK); - if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") != NULL) { - tt_abort_msg("(content type)\n"); - } - - tt_uint_op(evbuffer_get_length(evhttp_request_get_input_buffer(req)), ==, 0); - - test_ok = 1; - end: - event_base_loopexit(arg,NULL); -} - -struct http_server -{ - ev_uint16_t port; - int ssl; -}; -static struct event_base *http_make_web_server_base=NULL; -static void -http_make_web_server(evutil_socket_t fd, short what, void *arg) -{ - struct http_server *hs = (struct http_server *)arg; - http = http_setup(&hs->port, http_make_web_server_base, hs->ssl ? HTTP_BIND_SSL : 0); -} - -static void -http_simple_test_impl(void *arg, int ssl, int dirty) -{ - struct basic_test_data *data = arg; - struct evhttp_connection *evcon = NULL; - struct evhttp_request *req = NULL; - struct bufferevent *bev; - struct http_server hs = { .port = 0, .ssl = ssl, }; - - exit_base = data->base; - test_ok = 0; - - http = http_setup(&hs.port, data->base, ssl ? HTTP_BIND_SSL : 0); - - bev = create_bev(data->base, -1, ssl); - evcon = evhttp_connection_base_bufferevent_new( - data->base, NULL, bev, "127.0.0.1", hs.port); - tt_assert(evcon); - evhttp_connection_set_local_address(evcon, "127.0.0.1"); - - req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); - tt_assert(req); - - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { - tt_abort_msg("Couldn't make request"); - } - - event_base_dispatch(data->base); - tt_int_op(test_ok, ==, 1); - - end: - if (evcon) - evhttp_connection_free(evcon); - if (http) - evhttp_free(http); -} -static void http_simple_test(void *arg) -{ return http_simple_test_impl(arg, 0, 0); } - -static void -http_connection_retry_test_basic(void *arg, const char *addr, struct evdns_base *dns_base, int ssl) -{ - struct basic_test_data *data = arg; - struct evhttp_connection *evcon = NULL; - struct evhttp_request *req = NULL; - struct timeval tv, tv_start, tv_end; - struct bufferevent *bev; - struct http_server hs = { .port = 0, .ssl = ssl, }; - - exit_base = data->base; - test_ok = 0; - - /* auto detect a port */ - http = http_setup(&hs.port, data->base, ssl ? HTTP_BIND_SSL : 0); - evhttp_free(http); - http = NULL; - - bev = create_bev(data->base, -1, ssl); - evcon = evhttp_connection_base_bufferevent_new(data->base, dns_base, bev, addr, hs.port); - tt_assert(evcon); - if (dns_base) - tt_assert(!evhttp_connection_set_flags(evcon, EVHTTP_CON_REUSE_CONNECTED_ADDR)); - - evhttp_connection_set_timeout(evcon, 1); - /* also bind to local host */ - evhttp_connection_set_local_address(evcon, "127.0.0.1"); - - /* - * At this point, we want to schedule an HTTP GET request - * server using our make request method. - */ - - req = evhttp_request_new(http_connection_retry_done, data->base); - tt_assert(req); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); - - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, - "/?arg=val") == -1) { - tt_abort_msg("Couldn't make request"); - } - - evutil_gettimeofday(&tv_start, NULL); - event_base_dispatch(data->base); - evutil_gettimeofday(&tv_end, NULL); - evutil_timersub(&tv_end, &tv_start, &tv_end); - tt_int_op(tv_end.tv_sec, <, 1); - - tt_int_op(test_ok, ==, 1); - - /* - * now test the same but with retries - */ - test_ok = 0; - /** Shutdown dns server, to test conn_address reusing */ - if (dns_base) - regress_clean_dnsserver(); - - { - const struct timeval tv_timeout = { 0, 500000 }; - const struct timeval tv_retry = { 0, 500000 }; - evhttp_connection_set_timeout_tv(evcon, &tv_timeout); - evhttp_connection_set_initial_retry_tv(evcon, &tv_retry); - } - evhttp_connection_set_retries(evcon, 1); - - req = evhttp_request_new(http_connection_retry_done, data->base); - tt_assert(req); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); - - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, - "/?arg=val") == -1) { - tt_abort_msg("Couldn't make request"); - } - - evutil_gettimeofday(&tv_start, NULL); - event_base_dispatch(data->base); - evutil_gettimeofday(&tv_end, NULL); - - /* fails fast, .5 sec to wait to retry, fails fast again. */ - test_timeval_diff_leq(&tv_start, &tv_end, 500, 200); - - tt_assert(test_ok == 1); - - /* - * now test the same but with retries and give it a web server - * at the end - */ - test_ok = 0; - - evhttp_connection_set_timeout(evcon, 1); - evhttp_connection_set_retries(evcon, 3); - - req = evhttp_request_new(http_dispatcher_test_done, data->base); - tt_assert(req); - - /* Add the information that we care about */ - evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); - - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, - "/?arg=val") == -1) { - tt_abort_msg("Couldn't make request"); - } - - /* start up a web server .2 seconds after the connection tried - * to send a request - */ - evutil_timerclear(&tv); - tv.tv_usec = 200000; - http_make_web_server_base = data->base; - event_base_once(data->base, -1, EV_TIMEOUT, http_make_web_server, &hs, &tv); - - evutil_gettimeofday(&tv_start, NULL); - event_base_dispatch(data->base); - evutil_gettimeofday(&tv_end, NULL); - /* We'll wait twice as long as we did last time. */ - test_timeval_diff_leq(&tv_start, &tv_end, 1000, 400); - - tt_int_op(test_ok, ==, 1); - - end: - if (evcon) - evhttp_connection_free(evcon); - if (http) - evhttp_free(http); -} - -static void -http_connection_retry_conn_address_test_impl(void *arg, int ssl) -{ - struct basic_test_data *data = arg; - ev_uint16_t portnum = 0; - struct evdns_base *dns_base = NULL; - char address[64]; - - tt_assert(regress_dnsserver(data->base, &portnum, search_table)); - dns_base = evdns_base_new(data->base, 0/* init name servers */); - tt_assert(dns_base); - - /* Add ourself as the only nameserver, and make sure we really are - * the only nameserver. */ - evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum); - evdns_base_nameserver_ip_add(dns_base, address); - - http_connection_retry_test_basic(arg, "localhost", dns_base, ssl); - - end: - if (dns_base) - evdns_base_free(dns_base, 0); - /** dnsserver will be cleaned in http_connection_retry_test_basic() */ -} -static void http_connection_retry_conn_address_test(void *arg) -{ return http_connection_retry_conn_address_test_impl(arg, 0); } - -static void -http_connection_retry_test_impl(void *arg, int ssl) -{ - return http_connection_retry_test_basic(arg, "127.0.0.1", NULL, ssl); -} -static void -http_connection_retry_test(void *arg) -{ return http_connection_retry_test_impl(arg, 0); } - -static void -http_primitives(void *ptr) -{ - char *escaped = NULL; - struct evhttp *http = NULL; - - escaped = evhttp_htmlescape("