Merge branch 'test-regress-be-openssl-v2'

This patchset is a bunch of regression tests for bufferevent openssl layer,
some of them already show some bugs, that bugs will be fixed in the next
patches.

* test-regress-be-openssl-v2:
  test/regress_ssl: check events fd/pending after timeout triggered
  test/regress_ssl: cover case when server didn't up (failed with timeout)
  test/regress_ssl: covert that we can't change fd with underlying
  test/regress_ssl: cover that events (read/write) at finish not pending
  test/regress_ssl: cover fd manipulations
  test/regress_ssl: convert open_ssl_bufevs() to mask
  test/regress_ssl: convert client/server to mask too
  test/regress_ssl: cover "allow_dirty_shutdown"
  test/regress_ssl: convert regress_bufferevent_openssl() to bitmask
This commit is contained in:
Azat Khuzhin 2015-09-02 19:18:08 +03:00
commit af85ecfccc

View File

@ -43,6 +43,7 @@
#include "event2/util.h" #include "event2/util.h"
#include "event2/event.h" #include "event2/event.h"
#include "event2/bufferevent_ssl.h" #include "event2/bufferevent_ssl.h"
#include "event2/bufferevent_struct.h"
#include "event2/buffer.h" #include "event2/buffer.h"
#include "event2/listener.h" #include "event2/listener.h"
@ -177,17 +178,63 @@ static int test_is_done = 0;
static int n_connected = 0; static int n_connected = 0;
static int got_close = 0; static int got_close = 0;
static int got_error = 0; static int got_error = 0;
static int got_timeout = 0;
static int renegotiate_at = -1; static int renegotiate_at = -1;
static int stop_when_connected = 0; static int stop_when_connected = 0;
static int pending_connect_events = 0; static int pending_connect_events = 0;
static struct event_base *exit_base = NULL; 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 static void
respond_to_number(struct bufferevent *bev, void *ctx) respond_to_number(struct bufferevent *bev, void *ctx)
{ {
struct evbuffer *b = bufferevent_get_input(bev); struct evbuffer *b = bufferevent_get_input(bev);
char *line; char *line;
int n; int n;
enum regress_openssl_type type;
type = (enum regress_openssl_type)ctx;
line = evbuffer_readln(b, NULL, EVBUFFER_EOL_LF); line = evbuffer_readln(b, NULL, EVBUFFER_EOL_LF);
if (! line) if (! line)
return; return;
@ -201,7 +248,7 @@ respond_to_number(struct bufferevent *bev, void *ctx)
bufferevent_free(bev); /* Should trigger close on other side. */ bufferevent_free(bev); /* Should trigger close on other side. */
return; return;
} }
if (!strcmp(ctx, "client") && n == renegotiate_at) { if ((type & REGRESS_OPENSSL_CLIENT) && n == renegotiate_at) {
SSL_renegotiate(bufferevent_openssl_get_ssl(bev)); SSL_renegotiate(bufferevent_openssl_get_ssl(bev));
} }
++n; ++n;
@ -226,6 +273,9 @@ done_writing_cb(struct bufferevent *bev, void *ctx)
static void static void
eventcb(struct bufferevent *bev, short what, void *ctx) 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)); TT_BLATHER(("Got event %d", (int)what));
if (what & BEV_EVENT_CONNECTED) { if (what & BEV_EVENT_CONNECTED) {
SSL *ssl; SSL *ssl;
@ -234,7 +284,7 @@ eventcb(struct bufferevent *bev, short what, void *ctx)
ssl = bufferevent_openssl_get_ssl(bev); ssl = bufferevent_openssl_get_ssl(bev);
tt_assert(ssl); tt_assert(ssl);
peer_cert = SSL_get_peer_certificate(ssl); peer_cert = SSL_get_peer_certificate(ssl);
if (0==strcmp(ctx, "server")) { if (type & REGRESS_OPENSSL_SERVER) {
tt_assert(peer_cert == NULL); tt_assert(peer_cert == NULL);
} else { } else {
tt_assert(peer_cert != NULL); tt_assert(peer_cert != NULL);
@ -246,10 +296,32 @@ eventcb(struct bufferevent *bev, short what, void *ctx)
} else if (what & BEV_EVENT_EOF) { } else if (what & BEV_EVENT_EOF) {
TT_BLATHER(("Got a good EOF")); TT_BLATHER(("Got a good EOF"));
++got_close; ++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); bufferevent_free(bev);
} else if (what & BEV_EVENT_ERROR) { } else if (what & BEV_EVENT_ERROR) {
TT_BLATHER(("Got an error.")); TT_BLATHER(("Got an error."));
++got_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); bufferevent_free(bev);
} }
end: end:
@ -259,7 +331,8 @@ end:
static void static void
open_ssl_bufevs(struct bufferevent **bev1_out, struct bufferevent **bev2_out, open_ssl_bufevs(struct bufferevent **bev1_out, struct bufferevent **bev2_out,
struct event_base *base, int is_open, int flags, SSL *ssl1, SSL *ssl2, 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 state1 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_CONNECTING;
int state2 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_ACCEPTING; 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, 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, 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 static void
@ -290,18 +367,19 @@ regress_bufferevent_openssl(void *arg)
SSL *ssl1, *ssl2; SSL *ssl1, *ssl2;
X509 *cert = getcert(); X509 *cert = getcert();
EVP_PKEY *key = getkey(); 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; int flags = BEV_OPT_DEFER_CALLBACKS;
struct bufferevent *bev_ll[2] = { NULL, NULL }; struct bufferevent *bev_ll[2] = { NULL, NULL };
evutil_socket_t *fd_pair = 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(cert);
tt_assert(key); tt_assert(key);
init_ssl(); init_ssl();
if (strstr((char*)data->setup_data, "renegotiate")) { if (type & REGRESS_OPENSSL_RENEGOTIATE) {
if (SSLeay() >= 0x10001000 && if (SSLeay() >= 0x10001000 &&
SSLeay() < 0x1000104f) { SSLeay() < 0x1000104f) {
/* 1.0.1 up to 1.0.1c has a bug where TLS1.1 and 1.2 /* 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_certificate(ssl2, cert);
SSL_use_PrivateKey(ssl2, key); SSL_use_PrivateKey(ssl2, key);
if (! start_open) if (!(type & REGRESS_OPENSSL_OPEN))
flags |= BEV_OPT_CLOSE_ON_FREE; flags |= BEV_OPT_CLOSE_ON_FREE;
if (!filter) { if (!(type & REGRESS_OPENSSL_FILTER)) {
tt_assert(strstr((char*)data->setup_data, "socketpair")); tt_assert(type & REGRESS_OPENSSL_SOCKETPAIR);
fd_pair = data->pair; fd_pair = data->pair;
} else { } else {
bev_ll[0] = bufferevent_socket_new(data->base, data->pair[0], 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, 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]); tt_int_op(bufferevent_getfd(bev1), ==, data->pair[0]);
} else { } else {
tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev_ll[0]); tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev_ll[0]);
} }
if (start_open) { if (type & REGRESS_OPENSSL_OPEN) {
pending_connect_events = 2; pending_connect_events = 2;
stop_when_connected = 1; stop_when_connected = 1;
exit_base = data->base; exit_base = data->base;
@ -351,23 +429,47 @@ regress_bufferevent_openssl(void *arg)
bufferevent_free(bev2); bufferevent_free(bev2);
bev1 = bev2 = NULL; bev1 = bev2 = NULL;
open_ssl_bufevs(&bev1, &bev2, data->base, 1, flags, ssl1, ssl2, 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); if (!(type & REGRESS_OPENSSL_TIMEOUT)) {
bufferevent_enable(bev2, EV_READ|EV_WRITE); 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(test_is_done == 1);
tt_assert(n_connected == 2); tt_assert(n_connected == 2);
/* We don't handle shutdown properly yet. /* We don't handle shutdown properly yet */
tt_int_op(got_close, ==, 1); if (type & REGRESS_OPENSSL_DIRTY_SHUTDOWN) {
tt_int_op(got_error, ==, 0); 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: end:
return; return;
} }
@ -391,7 +493,7 @@ acceptcb(struct evconnlistener *listener, evutil_socket_t fd,
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
bufferevent_setcb(bev, respond_to_number, NULL, eventcb, bufferevent_setcb(bev, respond_to_number, NULL, eventcb,
(void*)"server"); (void*)(REGRESS_OPENSSL_SERVER));
bufferevent_enable(bev, EV_READ|EV_WRITE); bufferevent_enable(bev, EV_READ|EV_WRITE);
@ -435,7 +537,7 @@ regress_bufferevent_openssl_connect(void *arg)
tt_assert(bev); tt_assert(bev);
bufferevent_setcb(bev, respond_to_number, NULL, eventcb, bufferevent_setcb(bev, respond_to_number, NULL, eventcb,
(void*)"client"); (void*)(REGRESS_OPENSSL_CLIENT));
tt_assert(getsockname(evconnlistener_get_fd(listener), tt_assert(getsockname(evconnlistener_get_fd(listener),
(struct sockaddr*)&ss, &slen) == 0); (struct sockaddr*)&ss, &slen) == 0);
@ -453,22 +555,69 @@ end:
} }
struct testcase_t ssl_testcases[] = { struct testcase_t ssl_testcases[] = {
#define T(a) ((void *)(a))
{ "bufferevent_socketpair", regress_bufferevent_openssl, TT_ISOLATED, { "bufferevent_socketpair", regress_bufferevent_openssl,
&basic_setup, (void*)"socketpair" }, TT_ISOLATED, &basic_setup, T(REGRESS_OPENSSL_SOCKETPAIR) },
{ "bufferevent_filter", regress_bufferevent_openssl, { "bufferevent_filter", regress_bufferevent_openssl,
TT_ISOLATED, TT_ISOLATED, &basic_setup, T(REGRESS_OPENSSL_FILTER) },
&basic_setup, (void*)"filter" },
{ "bufferevent_renegotiate_socketpair", regress_bufferevent_openssl, { "bufferevent_renegotiate_socketpair", regress_bufferevent_openssl,
TT_ISOLATED, TT_ISOLATED, &basic_setup,
&basic_setup, (void*)"socketpair renegotiate" }, T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_RENEGOTIATE) },
{ "bufferevent_renegotiate_filter", regress_bufferevent_openssl, { "bufferevent_renegotiate_filter", regress_bufferevent_openssl,
TT_ISOLATED, TT_ISOLATED, &basic_setup,
&basic_setup, (void*)"filter renegotiate" }, T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_RENEGOTIATE) },
{ "bufferevent_socketpair_startopen", regress_bufferevent_openssl, { "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, { "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, { "bufferevent_connect", regress_bufferevent_openssl_connect,
TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },