bufferevent_socket_connect_hostname(struct bufferevent *bev,
struct evdns_base *evdns_base, int family, const char *hostname, int port)
{
- char portbuf[10];
struct evutil_addrinfo hint;
- struct bufferevent_private *bev_p = BEV_UPCAST(bev);
-
- if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC)
- return -1;
- if (port < 1 || port > 65535)
- return -1;
-
memset(&hint, 0, sizeof(hint));
hint.ai_family = family;
hint.ai_protocol = IPPROTO_TCP;
hint.ai_socktype = SOCK_STREAM;
- evutil_snprintf(portbuf, sizeof(portbuf), "%d", port);
+ return bufferevent_socket_connect_hostname_hints(bev, evdns_base, &hint, hostname, port);
+}
+
+int
+bufferevent_socket_connect_hostname_hints(struct bufferevent *bev,
+ struct evdns_base *evdns_base, const struct evutil_addrinfo *hints_in,
+ const char *hostname, int port)
+{
+ char portbuf[10];
+ struct bufferevent_private *bev_p =
+ EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+
+ if (hints_in->ai_family != AF_INET && hints_in->ai_family != AF_INET6 &&
+ hints_in->ai_family != AF_UNSPEC)
+ return -1;
+ if (port < 1 || port > 65535)
+ return -1;
BEV_LOCK(bev);
bev_p->dns_error = 0;
+ evutil_snprintf(portbuf, sizeof(portbuf), "%d", port);
+
bufferevent_suspend_write_(bev, BEV_SUSPEND_LOOKUP);
bufferevent_suspend_read_(bev, BEV_SUSPEND_LOOKUP);
bufferevent_incref_(bev);
bev_p->dns_request = evutil_getaddrinfo_async_(evdns_base, hostname,
- portbuf, &hint, bufferevent_connect_getaddrinfo_cb, bev);
+ portbuf, hints_in, bufferevent_connect_getaddrinfo_cb, bev);
+
BEV_UNLOCK(bev);
return 0;
@param port The port to connect to on the resolved address.
@return 0 if successful, -1 on failure.
+ @see bufferevent_socket_connect_hostname_hints()
+ */
+EVENT2_EXPORT_SYMBOL
+int bufferevent_socket_connect_hostname(struct bufferevent *,
+ struct evdns_base *, int, const char *, int);
+
+/**
+ Resolve the hostname 'hostname' and connect to it as with
+ bufferevent_socket_connect().
+
+ @param bufev An existing bufferevent allocated with bufferevent_socket_new()
+ @param evdns_base Optionally, an evdns_base to use for resolving hostnames
+ asynchronously. May be set to NULL for a blocking resolve.
+ @param hints_in points to an addrinfo structure that specifies criteria for
+ selecting the socket address structures to be used
+ @param hostname The hostname to resolve; see below for notes on recognized
+ formats
+ @param port The port to connect to on the resolved address.
+ @return 0 if successful, -1 on failure.
+
Recognized hostname formats are:
www.example.com (hostname)
what you want.
*/
EVENT2_EXPORT_SYMBOL
-int bufferevent_socket_connect_hostname(struct bufferevent *,
- struct evdns_base *, int, const char *, int);
+int bufferevent_socket_connect_hostname_hints(struct bufferevent *,
+ struct evdns_base *, const struct evutil_addrinfo *, const char *, int);
+
/**
Return the error code for the last failed DNS lookup attempt made by
}
}
+int bev_connect_hostname(struct bufferevent *bev, struct evdns_base *dns,
+ struct evutil_addrinfo *hints, const char *host, int port)
+{
+ if (hints->ai_flags)
+ return bufferevent_socket_connect_hostname_hints(bev, dns, hints, host, port);
+ else
+ return bufferevent_socket_connect_hostname(bev, dns, AF_INET, host, port);
+}
static void
test_bufferevent_connect_hostname(void *arg)
{
struct basic_test_data *data = arg;
+ int emfile = data->setup_data && !strcmp(data->setup_data, "emfile");
+ int hints = data->setup_data && !strcmp(data->setup_data, "hints");
struct evconnlistener *listener = NULL;
struct bufferevent *be[5];
struct be_conn_hostname_result be_outcome[ARRAY_SIZE(be)];
ev_uint16_t dns_port=0;
int n_accept=0, n_dns=0;
char buf[128];
- int emfile = data->setup_data && !strcmp(data->setup_data, "emfile");
int success = BEV_EVENT_CONNECTED;
int default_error = 0;
unsigned i;
int ret;
+ struct evutil_addrinfo in_hints;
+
+ memset(&in_hints, 0, sizeof(in_hints));
+ if (hints) {
+ in_hints.ai_family = AF_INET;
+ in_hints.ai_protocol = IPPROTO_TCP;
+ in_hints.ai_socktype = SOCK_STREAM;
+ in_hints.ai_flags = EVUTIL_AI_ADDRCONFIG;
+ }
if (emfile) {
success = BEV_EVENT_ERROR;
/* Use the blocking resolver. This one will fail if your resolver
* can't resolve localhost to 127.0.0.1 */
- tt_assert(!bufferevent_socket_connect_hostname(be[3], NULL, AF_INET,
+ tt_assert(!bev_connect_hostname(be[3], NULL, &in_hints,
"localhost", listener_port));
/* Use the blocking resolver with a nonexistent hostname. */
- tt_assert(!bufferevent_socket_connect_hostname(be[4], NULL, AF_INET,
+ tt_assert(!bev_connect_hostname(be[4], NULL, &in_hints,
"nonesuch.nowhere.example.com", 80));
{
/* The blocking resolver will use the system nameserver, which
"nonesuch.nowhere.example.com", "80", &hints, &ai);
}
/* Launch an async resolve that will fail. */
- tt_assert(!bufferevent_socket_connect_hostname(be[0], dns, AF_INET,
+ tt_assert(!bev_connect_hostname(be[0], dns, &in_hints,
"nosuchplace.example.com", listener_port));
/* Connect to the IP without resolving. */
- tt_assert(!bufferevent_socket_connect_hostname(be[1], dns, AF_INET,
+ tt_assert(!bev_connect_hostname(be[1], dns, &in_hints,
"127.0.0.1", listener_port));
/* Launch an async resolve that will succeed. */
- tt_assert(!bufferevent_socket_connect_hostname(be[2], dns, AF_INET,
+ tt_assert(!bev_connect_hostname(be[2], dns, &in_hints,
"nobodaddy.example.com", listener_port));
ret = event_base_dispatch(data->base);
}
}
-
struct gai_outcome {
int err;
struct evutil_addrinfo *ai;
{ "bufferevent_connect_hostname_emfile", test_bufferevent_connect_hostname,
TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"emfile" },
#endif
+ { "bufferevent_connect_hostname_hints", test_bufferevent_connect_hostname,
+ TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"hints" },
{ "disable_when_inactive", dns_disable_when_inactive_test,
TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
{ "disable_when_inactive_no_ns", dns_disable_when_inactive_no_ns_test,