/* * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu> * 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"
staticvoid
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);
}
staticvoid
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, EVUTIL_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")
staticvoid
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));
}
staticvoid
test_simpleclose_rw(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);
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);
}
staticvoid
test_simpleclose(void *ptr)
{ struct basic_test_data *data = ptr; struct event_base *base = data->base;
evutil_socket_t *pair = data->pair; constchar *flags = (constchar *)data->setup_data; int et = !!strstr(flags, "ET"); int persist = !!strstr(flags, "persist"); short events = EV_CLOSED | (et ? EV_ET : 0) | (persist ? EV_PERSIST : 0); struct event *ev = NULL; short got_event;
if (!(event_base_get_features(data->base) & EV_FEATURE_EARLY_CLOSE))
tt_skip();
/* XXX: should this code moved to regress_et.c ? */ if (et && !(event_base_get_features(data->base) & EV_FEATURE_ET))
tt_skip();
ev = event_new(base, pair[0], events, record_event_cb, &got_event);
tt_assert(ev);
tt_assert(!event_add(ev, NULL));
staticvoid
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;
staticvoid
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;
staticvoid
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);
}
}
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;
}
/* 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 : TEST_FORK_EXIT_SUCCESS);
}
/** wait until client read first message */ if (read(child_pair[1], &c, 1) < 0) {
tt_fail_perror("read");
} if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
tt_fail_perror("write");
}
fork_wait_check(pid);
/* test that the current event loop still works */ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) {
fprintf(stderr, "%s: write\n", __func__);
}
staticvoid
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();
}
staticvoid
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.
*/ staticvoid
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);
}
test_ok = 0; /* can handle signal before loop is called */
kill(getpid(), 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;
/* * assert that a signal event removed from the event queue really is * removed - with no possibility of it's parent handler being fired.
*/ staticvoid
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);
kill(getpid(), 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.
*/ staticvoid
test_signal_restore(void)
{ struct event ev; struct event_base *base = event_init(); #ifdef EVENT__HAVE_SIGACTION struct sigaction sa; #endif
/* 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);
staticvoid
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;
staticvoid
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;
staticvoid
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:
;
}
staticint reentrant_cb_run = 0;
staticvoid
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:
;
}
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);
/* 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.
*/
tt_assert(readd_test_event_last_added); if (readd_test_event_last_added == &ev1) {
tt_assert(event_pending(&ev1, EV_READ, NULL) && !event_pending(&ev2, EV_READ, NULL));
} else {
tt_assert(event_pending(&ev2, EV_READ, NULL) && !event_pending(&ev1, EV_READ, NULL));
}
end: if (event_initialized(&ev1))
event_del(&ev1); if (event_initialized(&ev2))
event_del(&ev2);
}
struct test_pri_event { struct event ev; int count;
};
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;
} elseif (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;
}
}
staticvoid
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. */ staticint n_pai_calls = 0; staticstruct event pai_events[3];
staticvoid
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);
}
}
staticvoid
evtag_fuzz(void *ptr)
{ unsignedchar 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");
}
#ifdefined(SETENV_OK) && defined(UNSETENV_OK) constchar **basenames; int i, n_methods=0; char varbuf[128]; constchar *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));
--> --------------------
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.