]> granicus.if.org Git - libevent/commitdiff
Implement bufferevent_socket_connect_hostname_hints()
authorJoseph Spadavecchia <jspadavecchia@bloxx.com>
Mon, 8 Dec 2014 17:32:07 +0000 (17:32 +0000)
committerAzat Khuzhin <azat@libevent.org>
Mon, 13 May 2019 08:13:04 +0000 (11:13 +0300)
So that ai_flags (such as AI_ADDRCONFIG) can be specified.

Closes: #193 (cherry-picked with conflicts resolved)
bufferevent_sock.c
include/event2/bufferevent.h
test/regress_dns.c

index f275b023809983302b0563897a322aaa015f741e..e92f46f3e0b8b4b9c7a1b29bf947e556ed4cedba 100644 (file)
@@ -494,31 +494,42 @@ int
 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;
index da4d3802c183abde75d519d247ff90ad78f9b4f5..1b54d5ca0b6f2edf4d48574ddb66764adec691fc 100644 (file)
@@ -227,6 +227,26 @@ struct evdns_base;
    @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)
@@ -239,8 +259,9 @@ struct evdns_base;
    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
index 76b0b86ae8d8e662cef3a9d71ac8bfb8bda9e3a1..6e6e59556b1a6869ad0ab94b41f1b5341eabf183 100644 (file)
@@ -1249,10 +1249,20 @@ be_connect_hostname_event_cb(struct bufferevent *bev, short what, void *ctx)
        }
 }
 
+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)];
@@ -1264,11 +1274,19 @@ test_bufferevent_connect_hostname(void *arg)
        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;
@@ -1335,10 +1353,10 @@ test_bufferevent_connect_hostname(void *arg)
 
        /* 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
@@ -1353,13 +1371,13 @@ test_bufferevent_connect_hostname(void *arg)
                        "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);
@@ -1407,7 +1425,6 @@ end:
        }
 }
 
-
 struct gai_outcome {
        int err;
        struct evutil_addrinfo *ai;
@@ -2380,6 +2397,8 @@ struct testcase_t dns_testcases[] = {
        { "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,