From: Nick Mathewson Date: Mon, 6 Apr 2009 20:38:19 +0000 (+0000) Subject: Fix evdns_cancel to alert callback and free associated RAM. X-Git-Tag: release-2.0.1-alpha~50 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d2e9caa6fcff77d5f69e10ef3b24d5e3e65d961e;p=libevent Fix evdns_cancel to alert callback and free associated RAM. Also, we add a test to make sure evdns_cancel is working properly. svn:r1139 --- diff --git a/evdns.c b/evdns.c index bd8dbf3f..18e4b122 100644 --- a/evdns.c +++ b/evdns.c @@ -595,15 +595,19 @@ request_trans_id_set(struct evdns_request *const req, const u16 trans_id) { static void request_finished(struct evdns_request *const req, struct evdns_request **head) { struct evdns_base *base = req->base; + int was_inflight = (head != &base->req_waiting_head); if (head) evdns_request_remove(req, head); log(EVDNS_LOG_DEBUG, "Removing timeout for request %lx", (unsigned long) req); - evtimer_del(&req->timeout_event); - search_request_finished(req); - base->global_requests_inflight--; + if (was_inflight) { + evtimer_del(&req->timeout_event); + base->global_requests_inflight--; + } else { + base->global_requests_waiting--; + } if (!req->request_appended) { /* need to free the request data on it's own */ @@ -2471,15 +2475,16 @@ request_submit(struct evdns_request *const req) { void evdns_cancel_request(struct evdns_base *base, struct evdns_request *req) { - /* XXX Does anything ever free the request */ + if (!base) + base = req->base; + + reply_callback(req, 0, DNS_ERR_CANCEL, NULL); if (req->ns) { /* remove from inflight queue */ - evdns_request_remove(req, &REQ_HEAD(base, req->trans_id)); - --base->global_requests_inflight; + request_finished(req, &REQ_HEAD(base, req->trans_id)); } else { /* remove from global_waiting head */ - evdns_request_remove(req, &base->req_waiting_head); - --base->global_requests_waiting; + request_finished(req, &base->req_waiting_head); } } @@ -3374,6 +3379,7 @@ evdns_err_to_string(int err) case DNS_ERR_UNKNOWN: return "unknown"; case DNS_ERR_TIMEOUT: return "request timed out"; case DNS_ERR_SHUTDOWN: return "dns subsystem shut down"; + case DNS_ERR_CANCEL: return "dns request canceled"; default: return "[Unknown error code]"; } } diff --git a/include/event2/dns.h b/include/event2/dns.h index 7920c3e9..28f5c80b 100644 --- a/include/event2/dns.h +++ b/include/event2/dns.h @@ -187,8 +187,10 @@ extern "C" { #define DNS_ERR_UNKNOWN 66 /** Communication with the server timed out */ #define DNS_ERR_TIMEOUT 67 -/** The request was canceled because the DNS subsystem was shut down. */ +/** The request was cancelled because the DNS subsystem was shut down. */ #define DNS_ERR_SHUTDOWN 68 +/** The request was cancelled via a call to evdns_cancel_request */ +#define DNS_ERR_CANCEL 69 #define DNS_IPv4_A 1 #define DNS_PTR 2 diff --git a/test/regress_dns.c b/test/regress_dns.c index 02a46ceb..09994b90 100644 --- a/test/regress_dns.c +++ b/test/regress_dns.c @@ -66,6 +66,7 @@ #include "regress.h" static int dns_ok = 0; +static int dns_got_cancel = 0; static int dns_err = 0; static void @@ -244,6 +245,12 @@ dns_server_request_cb(struct evdns_server_request *req, void *data) "ZZ.EXAMPLE.COM", 54321); if (r<0) dns_ok = 0; + } else if (req->questions[i]->type == EVDNS_TYPE_A && + req->questions[i]->dns_question_class == EVDNS_CLASS_INET && + !strcasecmp(req->questions[i]->name, "drop.example.com")) { + if (evdns_server_request_drop(req)<0) + dns_ok = 0; + return; } else { fprintf(stdout, "Unexpected question %d %d \"%s\" ", req->questions[i]->type, @@ -261,8 +268,16 @@ dns_server_request_cb(struct evdns_server_request *req, void *data) static void dns_server_gethostbyname_cb(int result, char type, int count, int ttl, - void *addresses, void *arg) + void *addresses, void *arg) { + if (result == DNS_ERR_CANCEL) { + if (arg != (void*)(char*)90909) { + fprintf(stdout, "Unexpected cancelation"); + dns_ok = 0; + } + dns_got_cancel = 1; + goto out; + } if (result != DNS_ERR_NONE) { fprintf(stdout, "Unexpected result %d. ", result); dns_ok = 0; @@ -326,14 +341,18 @@ dns_server(void) struct sockaddr_in my_addr; struct evdns_server_port *port=NULL; struct in_addr resolve_addr; + struct evdns_base *base=NULL; + struct evdns_request *req=NULL; dns_ok = 1; + base = evdns_base_new(NULL, 0); + /* Add ourself as the only nameserver, and make sure we really are * the only nameserver. */ - evdns_nameserver_ip_add("127.0.0.1:35353"); + evdns_base_nameserver_ip_add(base, "127.0.0.1:35353"); - tt_int_op(evdns_count_nameservers(), ==, 1); + tt_int_op(evdns_base_count_nameservers(base), ==, 1); /* Now configure a nameserver port. */ sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock<=0) { @@ -351,17 +370,23 @@ dns_server(void) } port = evdns_add_server_port(sock, 0, dns_server_request_cb, NULL); - /* Send two queries. */ - evdns_resolve_ipv4("zz.example.com", DNS_QUERY_NO_SEARCH, + /* Send some queries. */ + evdns_base_resolve_ipv4(base, "zz.example.com", DNS_QUERY_NO_SEARCH, dns_server_gethostbyname_cb, NULL); - evdns_resolve_ipv6("zz.example.com", DNS_QUERY_NO_SEARCH, + 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_resolve_reverse(&resolve_addr, 0, + evdns_base_resolve_reverse(base, &resolve_addr, 0, dns_server_gethostbyname_cb, NULL); + 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: @@ -370,6 +395,8 @@ end: evdns_shutdown(0); /* remove ourself as nameserver. */ if (sock >= 0) EVUTIL_CLOSESOCKET(sock); + if (base) + evdns_base_free(base, 0); }