Skip to content

Commit

Permalink
Report DNS error when lookup fails during bufferevent_socket_connect_…
Browse files Browse the repository at this point in the history
…hostname.
  • Loading branch information
chris-davis committed Apr 24, 2010
1 parent 25c442e commit 0ef4070
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 12 deletions.
3 changes: 3 additions & 0 deletions bufferevent-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
24 changes: 23 additions & 1 deletion bufferevent_sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -431,14 +431,16 @@ 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);

bufferevent_unsuspend_write(bev, BEV_SUSPEND_LOOKUP);
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)
Expand All @@ -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));
Expand All @@ -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.
*
Expand Down
10 changes: 10 additions & 0 deletions include/event2/bufferevent.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
38 changes: 27 additions & 11 deletions test/regress_dns.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}

Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 0ef4070

Please sign in to comment.