diff --git a/http-internal.h b/http-internal.h index 82dd402a..6f2f5b85 100644 --- a/http-internal.h +++ b/http-internal.h @@ -99,6 +99,7 @@ struct evhttp_connection { struct event_base *base; struct evdns_base *dns_base; + int ai_family; /* Saved conn_addr, to extract IP address from it. * diff --git a/http.c b/http.c index 093dd063..3941d179 100644 --- a/http.c +++ b/http.c @@ -2267,6 +2267,7 @@ evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_bas evhttp_deferred_read_cb, evcon); evcon->dns_base = dnsbase; + evcon->ai_family = AF_UNSPEC; return (evcon); @@ -2294,6 +2295,12 @@ evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase, return evhttp_connection_base_bufferevent_new(base, dnsbase, NULL, address, port); } +void evhttp_connection_set_family(struct evhttp_connection *evcon, + int family) +{ + evcon->ai_family = family; +} + void evhttp_connection_set_base(struct evhttp_connection *evcon, struct event_base *base) @@ -2419,7 +2426,7 @@ evhttp_connection_connect_(struct evhttp_connection *evcon) evcon->state = EVCON_CONNECTING; if (bufferevent_socket_connect_hostname(evcon->bufev, evcon->dns_base, - AF_UNSPEC, evcon->address, evcon->port) < 0) { + evcon->ai_family, evcon->address, evcon->port) < 0) { evcon->state = old_state; event_sock_warn(evcon->fd, "%s: connection to \"%s\" failed", __func__, evcon->address); diff --git a/include/event2/http.h b/include/event2/http.h index 81f44b85..7cade877 100644 --- a/include/event2/http.h +++ b/include/event2/http.h @@ -630,6 +630,12 @@ struct evhttp_connection *evhttp_connection_base_new( struct event_base *base, struct evdns_base *dnsbase, const char *address, unsigned short port); +/** + * Set family hint for DNS requests. + */ +void evhttp_connection_set_family(struct evhttp_connection *evcon, + int family); + /** Takes ownership of the request object * * Can be used in a request callback to keep onto the request until diff --git a/test/regress_http.c b/test/regress_http.c index 5658135f..363ebe67 100644 --- a/test/regress_http.c +++ b/test/regress_http.c @@ -958,7 +958,8 @@ static void http_request_done(struct evhttp_request *, void *); static void http_request_empty_done(struct evhttp_request *, void *); static void -http_connection_test_(struct basic_test_data *data, int persistent, const char *address, struct evdns_base *dnsbase, int ipv6) +http_connection_test_(struct basic_test_data *data, int persistent, + const char *address, struct evdns_base *dnsbase, int ipv6, int family) { ev_uint16_t port = 0; struct evhttp_connection *evcon = NULL; @@ -974,6 +975,7 @@ http_connection_test_(struct basic_test_data *data, int persistent, const char * evcon = evhttp_connection_base_new(data->base, dnsbase, address, port); tt_assert(evcon); + evhttp_connection_set_family(evcon, family); tt_assert(evhttp_connection_get_base(evcon) == data->base); @@ -1047,12 +1049,12 @@ http_connection_test_(struct basic_test_data *data, int persistent, const char * static void http_connection_test(void *arg) { - http_connection_test_(arg, 0, "127.0.0.1", NULL, 0); + http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC); } static void http_persist_connection_test(void *arg) { - http_connection_test_(arg, 1, "127.0.0.1", NULL, 0); + http_connection_test_(arg, 1, "127.0.0.1", NULL, 0, AF_UNSPEC); } static struct regress_dns_server_table search_table[] = { @@ -3758,7 +3760,7 @@ static struct regress_dns_server_table ipv6_search_table[] = { }; static void -http_ipv6_for_domain_test(void *arg) +http_ipv6_for_domain_test_impl(void *arg, int family) { struct basic_test_data *data = arg; struct evdns_base *dns_base = NULL; @@ -3775,13 +3777,19 @@ http_ipv6_for_domain_test(void *arg) evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum); evdns_base_nameserver_ip_add(dns_base, address); - http_connection_test_(arg, 0 /* not persistent */, "localhost", dns_base, 1 /* ipv6 */); + http_connection_test_(arg, 0 /* not persistent */, "localhost", dns_base, + 1 /* ipv6 */, family); end: if (dns_base) evdns_base_free(dns_base, 0); regress_clean_dnsserver(); } +static void +http_ipv6_for_domain_test(void *arg) +{ + http_ipv6_for_domain_test_impl(arg, AF_UNSPEC); +} static void http_request_get_addr_on_close(struct evhttp_connection *evcon, void *arg) @@ -3846,6 +3854,22 @@ http_get_addr_test(void *arg) evhttp_free(http); } +static void +http_set_family_test(void *arg) +{ + http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC); +} +static void +http_set_family_ipv4_test(void *arg) +{ + http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_INET); +} +static void +http_set_family_ipv6_test(void *arg) +{ + http_ipv6_for_domain_test_impl(arg, AF_INET6); +} + #define HTTP_LEGACY(name) \ { #name, run_legacy_test_fn, TT_ISOLATED|TT_LEGACY, &legacy_setup, \ http_##name##_test } @@ -3898,6 +3922,10 @@ struct testcase_t http_testcases[] = { HTTP(ipv6_for_domain), HTTP(get_addr), + HTTP(set_family), + HTTP(set_family_ipv4), + HTTP(set_family_ipv6), + END_OF_TESTCASES };