diff --git a/test/regress_ssl.c b/test/regress_ssl.c index c772de21..5872c729 100644 --- a/test/regress_ssl.c +++ b/test/regress_ssl.c @@ -43,6 +43,7 @@ #include "event2/util.h" #include "event2/event.h" #include "event2/bufferevent_ssl.h" +#include "event2/bufferevent_struct.h" #include "event2/buffer.h" #include "event2/listener.h" @@ -177,17 +178,63 @@ static int test_is_done = 0; static int n_connected = 0; static int got_close = 0; static int got_error = 0; +static int got_timeout = 0; static int renegotiate_at = -1; static int stop_when_connected = 0; static int pending_connect_events = 0; static struct event_base *exit_base = NULL; +enum regress_openssl_type +{ + REGRESS_OPENSSL_SOCKETPAIR = 1, + REGRESS_OPENSSL_FILTER = 2, + REGRESS_OPENSSL_RENEGOTIATE = 4, + REGRESS_OPENSSL_OPEN = 8, + REGRESS_OPENSSL_DIRTY_SHUTDOWN = 16, + REGRESS_OPENSSL_FD = 32, + + REGRESS_OPENSSL_CLIENT = 64, + REGRESS_OPENSSL_SERVER = 128, + + REGRESS_OPENSSL_FREED = 256, + REGRESS_OPENSSL_TIMEOUT = 512, +}; + +static void +bufferevent_openssl_check_fd(struct bufferevent *bev, int filter) +{ + if (filter) { + tt_int_op(bufferevent_getfd(bev), ==, -1); + tt_int_op(bufferevent_setfd(bev, -1), ==, -1); + } else { + tt_int_op(bufferevent_getfd(bev), !=, -1); + tt_int_op(bufferevent_setfd(bev, -1), ==, 0); + } + tt_int_op(bufferevent_getfd(bev), ==, -1); + +end: + ; +} +static void +bufferevent_openssl_check_freed(struct bufferevent *bev) +{ + tt_int_op(event_pending(&bev->ev_read, EVLIST_ALL, NULL), ==, 0); + tt_int_op(event_pending(&bev->ev_write, EVLIST_ALL, NULL), ==, 0); + +end: + ; +} + static void respond_to_number(struct bufferevent *bev, void *ctx) { struct evbuffer *b = bufferevent_get_input(bev); char *line; int n; + + enum regress_openssl_type type; + type = (enum regress_openssl_type)ctx; + line = evbuffer_readln(b, NULL, EVBUFFER_EOL_LF); if (! line) return; @@ -201,7 +248,7 @@ respond_to_number(struct bufferevent *bev, void *ctx) bufferevent_free(bev); /* Should trigger close on other side. */ return; } - if (!strcmp(ctx, "client") && n == renegotiate_at) { + if ((type & REGRESS_OPENSSL_CLIENT) && n == renegotiate_at) { SSL_renegotiate(bufferevent_openssl_get_ssl(bev)); } ++n; @@ -226,6 +273,9 @@ done_writing_cb(struct bufferevent *bev, void *ctx) static void eventcb(struct bufferevent *bev, short what, void *ctx) { + enum regress_openssl_type type; + type = (enum regress_openssl_type)ctx; + TT_BLATHER(("Got event %d", (int)what)); if (what & BEV_EVENT_CONNECTED) { SSL *ssl; @@ -234,7 +284,7 @@ eventcb(struct bufferevent *bev, short what, void *ctx) ssl = bufferevent_openssl_get_ssl(bev); tt_assert(ssl); peer_cert = SSL_get_peer_certificate(ssl); - if (0==strcmp(ctx, "server")) { + if (type & REGRESS_OPENSSL_SERVER) { tt_assert(peer_cert == NULL); } else { tt_assert(peer_cert != NULL); @@ -246,10 +296,32 @@ eventcb(struct bufferevent *bev, short what, void *ctx) } else if (what & BEV_EVENT_EOF) { TT_BLATHER(("Got a good EOF")); ++got_close; + if (type & REGRESS_OPENSSL_FD) { + bufferevent_openssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER); + } + if (type & REGRESS_OPENSSL_FREED) { + bufferevent_openssl_check_freed(bev); + } bufferevent_free(bev); } else if (what & BEV_EVENT_ERROR) { TT_BLATHER(("Got an error.")); ++got_error; + if (type & REGRESS_OPENSSL_FD) { + bufferevent_openssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER); + } + if (type & REGRESS_OPENSSL_FREED) { + bufferevent_openssl_check_freed(bev); + } + bufferevent_free(bev); + } else if (what & BEV_EVENT_TIMEOUT) { + TT_BLATHER(("Got timeout.")); + ++got_timeout; + if (type & REGRESS_OPENSSL_FD) { + bufferevent_openssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER); + } + if (type & REGRESS_OPENSSL_FREED) { + bufferevent_openssl_check_freed(bev); + } bufferevent_free(bev); } end: @@ -259,7 +331,8 @@ end: static void open_ssl_bufevs(struct bufferevent **bev1_out, struct bufferevent **bev2_out, struct event_base *base, int is_open, int flags, SSL *ssl1, SSL *ssl2, - evutil_socket_t *fd_pair, struct bufferevent **underlying_pair) + evutil_socket_t *fd_pair, struct bufferevent **underlying_pair, + enum regress_openssl_type type) { int state1 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_CONNECTING; int state2 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_ACCEPTING; @@ -276,9 +349,13 @@ open_ssl_bufevs(struct bufferevent **bev1_out, struct bufferevent **bev2_out, } bufferevent_setcb(*bev1_out, respond_to_number, done_writing_cb, - eventcb, (void*)"client"); + eventcb, (void*)(REGRESS_OPENSSL_CLIENT | (long)type)); bufferevent_setcb(*bev2_out, respond_to_number, done_writing_cb, - eventcb, (void*)"server"); + eventcb, (void*)(REGRESS_OPENSSL_SERVER | (long)type)); + + int dirty_shutdown = type & REGRESS_OPENSSL_DIRTY_SHUTDOWN; + bufferevent_openssl_set_allow_dirty_shutdown(*bev1_out, dirty_shutdown); + bufferevent_openssl_set_allow_dirty_shutdown(*bev2_out, dirty_shutdown); } static void @@ -290,18 +367,19 @@ regress_bufferevent_openssl(void *arg) SSL *ssl1, *ssl2; X509 *cert = getcert(); EVP_PKEY *key = getkey(); - const int start_open = strstr((char*)data->setup_data, "open")!=NULL; - const int filter = strstr((char*)data->setup_data, "filter")!=NULL; int flags = BEV_OPT_DEFER_CALLBACKS; struct bufferevent *bev_ll[2] = { NULL, NULL }; evutil_socket_t *fd_pair = NULL; + enum regress_openssl_type type; + type = (enum regress_openssl_type)data->setup_data; + tt_assert(cert); tt_assert(key); init_ssl(); - if (strstr((char*)data->setup_data, "renegotiate")) { + if (type & REGRESS_OPENSSL_RENEGOTIATE) { if (SSLeay() >= 0x10001000 && SSLeay() < 0x1000104f) { /* 1.0.1 up to 1.0.1c has a bug where TLS1.1 and 1.2 @@ -317,11 +395,11 @@ regress_bufferevent_openssl(void *arg) SSL_use_certificate(ssl2, cert); SSL_use_PrivateKey(ssl2, key); - if (! start_open) + if (!(type & REGRESS_OPENSSL_OPEN)) flags |= BEV_OPT_CLOSE_ON_FREE; - if (!filter) { - tt_assert(strstr((char*)data->setup_data, "socketpair")); + if (!(type & REGRESS_OPENSSL_FILTER)) { + tt_assert(type & REGRESS_OPENSSL_SOCKETPAIR); fd_pair = data->pair; } else { bev_ll[0] = bufferevent_socket_new(data->base, data->pair[0], @@ -331,15 +409,15 @@ regress_bufferevent_openssl(void *arg) } open_ssl_bufevs(&bev1, &bev2, data->base, 0, flags, ssl1, ssl2, - fd_pair, bev_ll); + fd_pair, bev_ll, type); - if (!filter) { + if (!(type & REGRESS_OPENSSL_FILTER)) { tt_int_op(bufferevent_getfd(bev1), ==, data->pair[0]); } else { tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev_ll[0]); } - if (start_open) { + if (type & REGRESS_OPENSSL_OPEN) { pending_connect_events = 2; stop_when_connected = 1; exit_base = data->base; @@ -351,23 +429,47 @@ regress_bufferevent_openssl(void *arg) bufferevent_free(bev2); bev1 = bev2 = NULL; open_ssl_bufevs(&bev1, &bev2, data->base, 1, flags, ssl1, ssl2, - fd_pair, bev_ll); + fd_pair, bev_ll, type); } - bufferevent_enable(bev1, EV_READ|EV_WRITE); - bufferevent_enable(bev2, EV_READ|EV_WRITE); + if (!(type & REGRESS_OPENSSL_TIMEOUT)) { + bufferevent_enable(bev1, EV_READ|EV_WRITE); + bufferevent_enable(bev2, EV_READ|EV_WRITE); - evbuffer_add_printf(bufferevent_get_output(bev1), "1\n"); + evbuffer_add_printf(bufferevent_get_output(bev1), "1\n"); - event_base_dispatch(data->base); + event_base_dispatch(data->base); - tt_assert(test_is_done == 1); - tt_assert(n_connected == 2); + tt_assert(test_is_done == 1); + tt_assert(n_connected == 2); - /* We don't handle shutdown properly yet. - tt_int_op(got_close, ==, 1); - tt_int_op(got_error, ==, 0); - */ + /* We don't handle shutdown properly yet */ + if (type & REGRESS_OPENSSL_DIRTY_SHUTDOWN) { + tt_int_op(got_close, ==, 1); + tt_int_op(got_error, ==, 0); + } else { + tt_int_op(got_error, ==, 1); + } + tt_int_op(got_timeout, ==, 0); + } else { + struct timeval t = { 2 }; + + bufferevent_enable(bev1, EV_READ|EV_WRITE); + bufferevent_disable(bev2, EV_READ|EV_WRITE); + + bufferevent_set_timeouts(bev1, &t, &t); + + evbuffer_add_printf(bufferevent_get_output(bev1), "1\n"); + + event_base_dispatch(data->base); + + tt_assert(test_is_done == 0); + tt_assert(n_connected == 0); + + tt_int_op(got_close, ==, 0); + tt_int_op(got_error, ==, 0); + tt_int_op(got_timeout, ==, 1); + } end: return; } @@ -391,7 +493,7 @@ acceptcb(struct evconnlistener *listener, evutil_socket_t fd, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); bufferevent_setcb(bev, respond_to_number, NULL, eventcb, - (void*)"server"); + (void*)(REGRESS_OPENSSL_SERVER)); bufferevent_enable(bev, EV_READ|EV_WRITE); @@ -435,7 +537,7 @@ regress_bufferevent_openssl_connect(void *arg) tt_assert(bev); bufferevent_setcb(bev, respond_to_number, NULL, eventcb, - (void*)"client"); + (void*)(REGRESS_OPENSSL_CLIENT)); tt_assert(getsockname(evconnlistener_get_fd(listener), (struct sockaddr*)&ss, &slen) == 0); @@ -453,22 +555,69 @@ end: } struct testcase_t ssl_testcases[] = { - - { "bufferevent_socketpair", regress_bufferevent_openssl, TT_ISOLATED, - &basic_setup, (void*)"socketpair" }, +#define T(a) ((void *)(a)) + { "bufferevent_socketpair", regress_bufferevent_openssl, + TT_ISOLATED, &basic_setup, T(REGRESS_OPENSSL_SOCKETPAIR) }, { "bufferevent_filter", regress_bufferevent_openssl, - TT_ISOLATED, - &basic_setup, (void*)"filter" }, + TT_ISOLATED, &basic_setup, T(REGRESS_OPENSSL_FILTER) }, { "bufferevent_renegotiate_socketpair", regress_bufferevent_openssl, - TT_ISOLATED, - &basic_setup, (void*)"socketpair renegotiate" }, + TT_ISOLATED, &basic_setup, + T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_RENEGOTIATE) }, { "bufferevent_renegotiate_filter", regress_bufferevent_openssl, - TT_ISOLATED, - &basic_setup, (void*)"filter renegotiate" }, + TT_ISOLATED, &basic_setup, + T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_RENEGOTIATE) }, { "bufferevent_socketpair_startopen", regress_bufferevent_openssl, - TT_ISOLATED, &basic_setup, (void*)"socketpair open" }, + TT_ISOLATED, &basic_setup, + T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_OPEN) }, { "bufferevent_filter_startopen", regress_bufferevent_openssl, - TT_ISOLATED, &basic_setup, (void*)"filter open" }, + TT_ISOLATED, &basic_setup, + T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_OPEN) }, + + { "bufferevent_socketpair_dirty_shutdown", regress_bufferevent_openssl, + TT_ISOLATED, &basic_setup, + T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_DIRTY_SHUTDOWN) }, + { "bufferevent_filter_dirty_shutdown", regress_bufferevent_openssl, + TT_ISOLATED, &basic_setup, + T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_DIRTY_SHUTDOWN) }, + { "bufferevent_renegotiate_socketpair_dirty_shutdown", + regress_bufferevent_openssl, + TT_ISOLATED, + &basic_setup, + T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_RENEGOTIATE | REGRESS_OPENSSL_DIRTY_SHUTDOWN) }, + { "bufferevent_renegotiate_filter_dirty_shutdown", + regress_bufferevent_openssl, + TT_ISOLATED, + &basic_setup, + T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_RENEGOTIATE | REGRESS_OPENSSL_DIRTY_SHUTDOWN) }, + { "bufferevent_socketpair_startopen_dirty_shutdown", + regress_bufferevent_openssl, + TT_ISOLATED, &basic_setup, + T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_OPEN | REGRESS_OPENSSL_DIRTY_SHUTDOWN) }, + { "bufferevent_filter_startopen_dirty_shutdown", + regress_bufferevent_openssl, + TT_ISOLATED, &basic_setup, + T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_OPEN | REGRESS_OPENSSL_DIRTY_SHUTDOWN) }, + + { "bufferevent_socketpair_fd", regress_bufferevent_openssl, + TT_ISOLATED, &basic_setup, + T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_FD) }, + { "bufferevent_socketpair_freed", regress_bufferevent_openssl, + TT_ISOLATED, &basic_setup, + T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_FREED) }, + { "bufferevent_socketpair_freed_fd", regress_bufferevent_openssl, + TT_ISOLATED, &basic_setup, + T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_FREED | REGRESS_OPENSSL_FD) }, + { "bufferevent_filter_freed_fd", regress_bufferevent_openssl, + TT_ISOLATED, &basic_setup, + T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_FREED | REGRESS_OPENSSL_FD) }, + + { "bufferevent_socketpair_timeout", regress_bufferevent_openssl, + TT_ISOLATED, &basic_setup, + T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_TIMEOUT) }, + { "bufferevent_socketpair_timeout_freed_fd", regress_bufferevent_openssl, + TT_ISOLATED, &basic_setup, + T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_TIMEOUT | REGRESS_OPENSSL_FREED | REGRESS_OPENSSL_FD) }, +#undef T { "bufferevent_connect", regress_bufferevent_openssl_connect, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },