From: Christopher Davis Date: Sat, 24 Apr 2010 07:06:38 +0000 (-0700) Subject: Report DNS error when lookup fails during bufferevent_socket_connect_hostname. X-Git-Tag: release-2.0.5-beta~21^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0ef407065e5fb98f704b426d1d4fc878a85a391d;p=libevent Report DNS error when lookup fails during bufferevent_socket_connect_hostname. --- diff --git a/bufferevent-internal.h b/bufferevent-internal.h index 1b56c432..b46de57c 100644 --- a/bufferevent-internal.h +++ b/bufferevent-internal.h @@ -165,6 +165,9 @@ struct bufferevent_private { * an events callback is pending. */ int errno_pending; + /** The DNS error code for bufferevent_socket_connect_hostname */ + int dns_error; + /** Used to implement deferred callbacks */ struct deferred_cb deferred; diff --git a/bufferevent_sock.c b/bufferevent_sock.c index f621e76d..28d36421 100644 --- a/bufferevent_sock.c +++ b/bufferevent_sock.c @@ -431,6 +431,8 @@ bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai, void *arg) { struct bufferevent *bev = arg; + struct bufferevent_private *bev_p = + EVUTIL_UPCAST(bev, struct bufferevent_private, bev); int r; BEV_LOCK(bev); @@ -438,7 +440,7 @@ bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai, bufferevent_unsuspend_read(bev, BEV_SUSPEND_LOOKUP); if (result != 0) { - /* XXX Communicate the error somehow. */ + bev_p->dns_error = result; _bufferevent_run_eventcb(bev, BEV_EVENT_ERROR); _bufferevent_decref_and_unlock(bev); if (ai) @@ -459,12 +461,18 @@ bufferevent_socket_connect_hostname(struct bufferevent *bev, char portbuf[10]; struct evutil_addrinfo hint; int err; + struct bufferevent_private *bev_p = + EVUTIL_UPCAST(bev, struct bufferevent_private, bev); if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC) return -1; if (port < 1 || port > 65535) return -1; + BEV_LOCK(bev); + bev_p->dns_error = 0; + BEV_UNLOCK(bev); + evutil_snprintf(portbuf, sizeof(portbuf), "%d", port); memset(&hint, 0, sizeof(hint)); @@ -488,6 +496,20 @@ bufferevent_socket_connect_hostname(struct bufferevent *bev, } } +int +bufferevent_socket_get_dns_error(struct bufferevent *bev) +{ + int rv; + struct bufferevent_private *bev_p = + EVUTIL_UPCAST(bev, struct bufferevent_private, bev); + + BEV_LOCK(bev); + rv = bev_p->dns_error; + BEV_LOCK(bev); + + return rv; +} + /* * Create a new buffered event object. * diff --git a/include/event2/bufferevent.h b/include/event2/bufferevent.h index b1d7e43a..9040cba9 100644 --- a/include/event2/bufferevent.h +++ b/include/event2/bufferevent.h @@ -185,6 +185,16 @@ struct evdns_base; int bufferevent_socket_connect_hostname(struct bufferevent *b, struct evdns_base *, int, const char *, int); +/** + Return the error code for the last failed DNS lookup attempt made by + bufferevent_socket_connect_hostname(). + + @param bev The bufferevent object. + @return DNS error code. + @see evutil_gai_strerror() +*/ +int bufferevent_socket_get_dns_error(struct bufferevent *bev); + /** Assign a bufferevent to a specific event_base. diff --git a/test/regress_dns.c b/test/regress_dns.c index a9310088..329dc80f 100644 --- a/test/regress_dns.c +++ b/test/regress_dns.c @@ -969,26 +969,37 @@ nil_accept_cb(struct evconnlistener *l, evutil_socket_t fd, struct sockaddr *s, /* don't do anything with the socket; let it close when we exit() */ } +struct be_conn_hostname_result { + int dnserr; + int what; +}; + /* Bufferevent event callback for the connect_hostname test: remembers what * event we got. */ static void be_connect_hostname_event_cb(struct bufferevent *bev, short what, void *ctx) { - int *got = ctx; - if (!*got) { + struct be_conn_hostname_result *got = ctx; + if (!got->what) { TT_BLATHER(("Got a bufferevent event %d", what)); - *got = what; + got->what = what; 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) event_base_loopexit(be_connect_hostname_base, NULL); } } else { TT_FAIL(("Two events on one bufferevent. %d,%d", - (int)*got, (int)what)); + got->what, (int)what)); } } @@ -998,8 +1009,8 @@ test_bufferevent_connect_hostname(void *arg) struct basic_test_data *data = arg; struct evconnlistener *listener = NULL; struct bufferevent *be1=NULL, *be2=NULL, *be3=NULL, *be4=NULL, *be5=NULL; - int be1_outcome=0, be2_outcome=0, be3_outcome=0, be4_outcome=0, - be5_outcome=0; + struct be_conn_hostname_result be1_outcome={0,0}, be2_outcome={0,0}, + be3_outcome={0,0}, be4_outcome={0,0}, be5_outcome={0,0}; struct evdns_base *dns=NULL; struct evdns_server_port *port=NULL; evutil_socket_t server_fd=-1; @@ -1072,11 +1083,16 @@ test_bufferevent_connect_hostname(void *arg) event_base_dispatch(data->base); - tt_int_op(be1_outcome, ==, BEV_EVENT_ERROR); - tt_int_op(be2_outcome, ==, BEV_EVENT_CONNECTED); - tt_int_op(be3_outcome, ==, BEV_EVENT_CONNECTED); - tt_int_op(be4_outcome, ==, BEV_EVENT_CONNECTED); - tt_int_op(be5_outcome, ==, BEV_EVENT_ERROR); + tt_int_op(be1_outcome.what, ==, BEV_EVENT_ERROR); + tt_int_op(be1_outcome.dnserr, ==, EVUTIL_EAI_NONAME); + tt_int_op(be2_outcome.what, ==, BEV_EVENT_CONNECTED); + tt_int_op(be2_outcome.dnserr, ==, 0); + tt_int_op(be3_outcome.what, ==, BEV_EVENT_CONNECTED); + tt_int_op(be3_outcome.dnserr, ==, 0); + tt_int_op(be4_outcome.what, ==, BEV_EVENT_CONNECTED); + tt_int_op(be4_outcome.dnserr, ==, 0); + tt_int_op(be5_outcome.what, ==, BEV_EVENT_ERROR); + tt_int_op(be5_outcome.dnserr, ==, EVUTIL_EAI_NONAME); tt_int_op(n_accept, ==, 3); tt_int_op(n_dns, ==, 2);