diff --git a/http-internal.h b/http-internal.h index 49ee9bcb..5e6769f1 100644 --- a/http-internal.h +++ b/http-internal.h @@ -97,6 +97,7 @@ struct evhttp_connection { void *closecb_arg; struct event_base *base; + struct evdns_base *dns_base; }; struct evhttp_cb { diff --git a/http.c b/http.c index 8a919707..66cd0ad7 100644 --- a/http.c +++ b/http.c @@ -155,7 +155,6 @@ fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host, 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(const char *, ev_uint16_t, int reuse); 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 -evhttp_connection_cb(struct bufferevent *bufev, void *arg) +evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg) { struct evhttp_connection *evcon = arg; int 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 */ if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &errsz) == -1) { @@ -1784,6 +1793,14 @@ evhttp_connection_base_new(struct event_base *base, 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 evhttp_connection_set_base(struct evhttp_connection *evcon, struct event_base *base) @@ -1850,7 +1867,20 @@ evhttp_connection_connect(struct evhttp_connection *evcon) 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", __func__, evcon->address); /* some operating systems return ECONNREFUSED immediately @@ -1861,17 +1891,6 @@ evhttp_connection_connect(struct evhttp_connection *evcon) 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; return (0); @@ -3114,29 +3133,3 @@ bind_socket(const char *address, ev_uint16_t port, int reuse) 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); -} diff --git a/include/event2/http.h b/include/event2/http.h index 328eefae..cdbafeb8 100644 --- a/include/event2/http.h +++ b/include/event2/http.h @@ -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 - * connection object tries to establish the connection when it is given an - * http request object. + * connection object tries to resolve address and establish the connection + * when it is given an http request object. */ struct evhttp_connection *evhttp_connection_base_new( 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 * * Can be used in a request callback to keep onto the request until