Allow http connections to use evdns for hostname looksups.

This was as simple as using bufferevent_connect_hostname instead of
calling connect() ourself, which already knows how to use an
evdns_base if it gets one.

Untangling the bind code might be a little trickier.
This commit is contained in:
Nick Mathewson 2009-12-30 00:11:27 -05:00
parent a334b31c6f
commit c698b77d19
3 changed files with 46 additions and 44 deletions

View File

@ -97,6 +97,7 @@ struct evhttp_connection {
void *closecb_arg; void *closecb_arg;
struct event_base *base; struct event_base *base;
struct evdns_base *dns_base;
}; };
struct evhttp_cb { struct evhttp_cb {

77
http.c
View File

@ -155,7 +155,6 @@ fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
extern int debug; extern int debug;
static int socket_connect(evutil_socket_t kefd, const char *address, unsigned short port);
static evutil_socket_t bind_socket_ai(struct evutil_addrinfo *, int reuse); static evutil_socket_t bind_socket_ai(struct evutil_addrinfo *, int reuse);
static evutil_socket_t bind_socket(const char *, ev_uint16_t, int reuse); static evutil_socket_t bind_socket(const char *, ev_uint16_t, int reuse);
static void name_from_addr(struct sockaddr *, ev_socklen_t, char **, char **); static void name_from_addr(struct sockaddr *, ev_socklen_t, char **, char **);
@ -1149,16 +1148,26 @@ evhttp_error_cb(struct bufferevent *bufev, short what, void *arg)
} }
/* /*
* Call back for asynchronous connection attempt. * Event callback for asynchronous connection attempt.
*/ */
static void static void
evhttp_connection_cb(struct bufferevent *bufev, void *arg) evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg)
{ {
struct evhttp_connection *evcon = arg; struct evhttp_connection *evcon = arg;
int error; int error;
ev_socklen_t errsz = sizeof(error); ev_socklen_t errsz = sizeof(error);
if (!(what & BEV_EVENT_CONNECTED)) {
/* some operating systems return ECONNREFUSED immediately
* when connecting to a local address. the cleanup is going
* to reschedule this function call.
*/
if (errno == ECONNREFUSED)
goto cleanup;
evhttp_error_cb(bufev, what, arg);
return;
}
/* Check if the connection completed */ /* Check if the connection completed */
if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error, if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error,
&errsz) == -1) { &errsz) == -1) {
@ -1784,6 +1793,14 @@ evhttp_connection_base_new(struct event_base *base,
return (NULL); return (NULL);
} }
void
evhttp_connection_set_evdns_base(struct evhttp_connection *evcon,
struct evdns_base *base)
{
EVUTIL_ASSERT(evcon->dns_base == NULL);
evcon->dns_base = base;
}
void void
evhttp_connection_set_base(struct evhttp_connection *evcon, evhttp_connection_set_base(struct evhttp_connection *evcon,
struct event_base *base) struct event_base *base)
@ -1850,7 +1867,20 @@ evhttp_connection_connect(struct evhttp_connection *evcon)
return (-1); return (-1);
} }
if (socket_connect(evcon->fd, evcon->address, evcon->port) == -1) { /* Set up a callback for successful connection setup */
bufferevent_setfd(evcon->bufev, evcon->fd);
bufferevent_setcb(evcon->bufev,
NULL /* evhttp_read_cb */,
NULL /* evhttp_write_cb */,
evhttp_connection_cb,
evcon);
bufferevent_settimeout(evcon->bufev, 0,
evcon->timeout != -1 ? evcon->timeout : HTTP_CONNECT_TIMEOUT);
/* make sure that we get a write callback */
bufferevent_enable(evcon->bufev, EV_WRITE);
if (bufferevent_socket_connect_hostname(evcon->bufev, evcon->dns_base,
AF_UNSPEC, evcon->address, evcon->port) < 0) {
event_sock_warn(evcon->fd, "%s: connection to \"%s\" failed", event_sock_warn(evcon->fd, "%s: connection to \"%s\" failed",
__func__, evcon->address); __func__, evcon->address);
/* some operating systems return ECONNREFUSED immediately /* some operating systems return ECONNREFUSED immediately
@ -1861,17 +1891,6 @@ evhttp_connection_connect(struct evhttp_connection *evcon)
return (0); return (0);
} }
/* Set up a callback for successful connection setup */
bufferevent_setfd(evcon->bufev, evcon->fd);
bufferevent_setcb(evcon->bufev,
NULL /* evhttp_read_cb */,
evhttp_connection_cb,
evhttp_error_cb, evcon);
bufferevent_settimeout(evcon->bufev, 0,
evcon->timeout != -1 ? evcon->timeout : HTTP_CONNECT_TIMEOUT);
/* make sure that we get a write callback */
bufferevent_enable(evcon->bufev, EV_WRITE);
evcon->state = EVCON_CONNECTING; evcon->state = EVCON_CONNECTING;
return (0); return (0);
@ -3114,29 +3133,3 @@ bind_socket(const char *address, ev_uint16_t port, int reuse)
return (fd); return (fd);
} }
static int
socket_connect(evutil_socket_t fd, const char *address, unsigned short port)
{
struct evutil_addrinfo *ai = make_addrinfo(address, port);
int res = -1;
if (ai == NULL) {
event_debug(("%s: make_addrinfo: \"%s:%d\"",
__func__, address, port));
return (-1);
}
if (connect(fd, ai->ai_addr, ai->ai_addrlen) == -1) {
int err = evutil_socket_geterror(fd);
if (! EVUTIL_ERR_CONNECT_RETRIABLE(err))
goto out;
}
/* everything is fine */
res = 0;
out:
evutil_freeaddrinfo(ai);
return (res);
}

View File

@ -355,12 +355,20 @@ void evhttp_request_free(struct evhttp_request *req);
/** /**
* A connection object that can be used to for making HTTP requests. The * A connection object that can be used to for making HTTP requests. The
* connection object tries to establish the connection when it is given an * connection object tries to resolve address and establish the connection
* http request object. * when it is given an http request object.
*/ */
struct evhttp_connection *evhttp_connection_base_new( struct evhttp_connection *evhttp_connection_base_new(
struct event_base *base, const char *address, unsigned short port); struct event_base *base, const char *address, unsigned short port);
struct evdns_base;
/**
* Tell the connection object to use evdns_base when resolving hostnames.
* If no base is set, it will block when resolving hostnames.
*/
void evhttp_connection_set_evdns_base(struct evhttp_connection *evcon,
struct evdns_base *base);
/** Takes ownership of the request object /** Takes ownership of the request object
* *
* Can be used in a request callback to keep onto the request until * Can be used in a request callback to keep onto the request until