X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libevent%2Ftest%2Fregress_dns.c;h=a566469b69e9bca144ce2a823220e2560fb27d0e;hb=3a84db87064922ad10ac10cc1d6833380e575995;hp=255f613a9b15e1ba91a120fb3312127d33a87499;hpb=cdb7047fb6897c1ad8b4ac264001d44154bf144d;p=netatalk.git diff --git a/libevent/test/regress_dns.c b/libevent/test/regress_dns.c index 255f613a..a566469b 100644 --- a/libevent/test/regress_dns.c +++ b/libevent/test/regress_dns.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2003-2007 Niels Provos - * Copyright (c) 2007-2010 Niels Provos and Nick Mathewson + * 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 @@ -71,6 +71,8 @@ #include "regress.h" #include "regress_testutils.h" +#include "../util-internal.h" + static int dns_ok = 0; static int dns_got_cancel = 0; static int dns_err = 0; @@ -493,6 +495,9 @@ static struct regress_dns_server_table search_table[] = { { "host2.a.example.com", "err", "3", 0 }, { "host2.b.example.com", "A", "200.100.0.100", 0 }, { "host2.c.example.com", "err", "3", 0 }, + { "hostn.a.example.com", "errsoa", "0", 0 }, + { "hostn.b.example.com", "errsoa", "3", 0 }, + { "hostn.c.example.com", "err", "0", 0 }, { "host", "err", "3", 0 }, { "host2", "err", "3", 0 }, @@ -509,7 +514,7 @@ dns_search_test(void *arg) ev_uint16_t portnum = 0; char buf[64]; - struct generic_dns_callback_result r1, r2, r3, r4, r5; + struct generic_dns_callback_result r[8]; tt_assert(regress_dnsserver(base, &portnum, search_table)); evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); @@ -521,26 +526,35 @@ dns_search_test(void *arg) evdns_base_search_add(dns, "b.example.com"); evdns_base_search_add(dns, "c.example.com"); - n_replies_left = 5; + n_replies_left = sizeof(r)/sizeof(r[0]); exit_base = base; - evdns_base_resolve_ipv4(dns, "host", 0, generic_dns_callback, &r1); - evdns_base_resolve_ipv4(dns, "host2", 0, generic_dns_callback, &r2); - evdns_base_resolve_ipv4(dns, "host", DNS_NO_SEARCH, generic_dns_callback, &r3); - evdns_base_resolve_ipv4(dns, "host2", DNS_NO_SEARCH, generic_dns_callback, &r4); - evdns_base_resolve_ipv4(dns, "host3", 0, generic_dns_callback, &r5); + 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(r1.type, ==, DNS_IPv4_A); - tt_int_op(r1.count, ==, 1); - tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x0b16212c)); - tt_int_op(r2.type, ==, DNS_IPv4_A); - tt_int_op(r2.count, ==, 1); - tt_int_op(((ev_uint32_t*)r2.addrs)[0], ==, htonl(0xc8640064)); - tt_int_op(r3.result, ==, DNS_ERR_NOTEXIST); - tt_int_op(r4.result, ==, DNS_ERR_NOTEXIST); - tt_int_op(r5.result, ==, DNS_ERR_NOTEXIST); + 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) @@ -848,6 +862,7 @@ end: /* === 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 @@ -981,7 +996,11 @@ nil_accept_cb(struct evconnlistener *l, evutil_socket_t fd, struct sockaddr *s, { 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 { @@ -1001,14 +1020,14 @@ be_connect_hostname_event_cb(struct bufferevent *bev, short what, void *ctx) if ((what & BEV_EVENT_CONNECTED) || (what & BEV_EVENT_ERROR)) { int r; - ++total_connected_or_failed; - TT_BLATHER(("Got %d connections or errors.", total_connected_or_failed)); if ((r = bufferevent_socket_get_dns_error(bev))) { got->dnserr = r; TT_BLATHER(("DNS error %d: %s", r, evutil_gai_strerror(r))); - } - if (total_connected_or_failed >= 5) + } ++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); } @@ -1623,11 +1642,134 @@ gaic_launch(struct event_base *base, struct evdns_base *dns_base) ++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 -test_getaddrinfo_async_cancel_stress(void *arg) +cnt_free(void *ptr) { - struct basic_test_data *data = arg; - struct event_base *base = data->base; + 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; + 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_; +#ifdef _EVENT_DISABLE_DEBUG_MODE + tt_int_op(allocated_chunks, ==, 0); +#else + /* FIXME: that's `1' because of event_debug_map_HT_GROW */ + tt_int_op(allocated_chunks, ==, 1); +#endif + ok = 1; +end: + if (env->dns_base) + evdns_base_free(env->dns_base, 0); + if (env->base) + event_base_free(env->base); + if (env) + 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 +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; @@ -1699,7 +1841,12 @@ struct testcase_t dns_testcases[] = { { "getaddrinfo_async", test_getaddrinfo_async, TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"" }, { "getaddrinfo_cancel_stress", test_getaddrinfo_async_cancel_stress, - TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"" }, + 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 }, +#endif END_OF_TESTCASES };