瀏覽代碼

ZOOKEEPER-677. c client doesn't allow ipv6 numeric connect string

git-svn-id: https://svn.apache.org/repos/asf/hadoop/zookeeper/trunk@921439 13f79535-47bb-0310-9956-ffa450edef68
Benjamin Reed 15 年之前
父節點
當前提交
0c9ba838da
共有 5 個文件被更改,包括 61 次插入8 次删除
  1. 2 0
      CHANGES.txt
  2. 5 1
      src/c/configure.ac
  3. 37 5
      src/c/src/zookeeper.c
  4. 16 1
      src/c/tests/TestClient.cc
  5. 1 1
      src/c/tests/TestZookeeperInit.cc

+ 2 - 0
CHANGES.txt

@@ -258,6 +258,8 @@ BUGFIXES:
 
   ZOOKEEPER-685.  Race in LENonTerminateTest (henry via breed)
 
+  ZOOKEEPER-677. c client doesn't allow ipv6 numeric connect string (breed & phunt & mahadev via breed)
+
 IMPROVEMENTS:
   ZOOKEEPER-473. cleanup junit tests to eliminate false positives due to
   "socket reuse" and failure to close client (phunt via mahadev)

+ 5 - 1
src/c/configure.ac

@@ -52,9 +52,13 @@ AC_PROG_LN_S
 # AC_DISABLE_SHARED
 AC_PROG_LIBTOOL
 
+#enable -D_GNU_SOURCE since the return code value of getaddrinfo
+#ifdefed with __USE_GNU
+#features.h header undef's __USE_GNU and defines it only if _GNU_SOURCE is defined
+#hence this define for gcc
 AC_ARG_ENABLE([debug],
  [AS_HELP_STRING([--enable-debug],[enable debug build [default=no]])],
- [CFLAGS="-g -O0";CXXFLAGS="-g -O0"],[CFLAGS="-g -O2";CXXFLAGS="-g -O2"])
+ [CFLAGS="-g -O0 -D_GNU_SOURCE";CXXFLAGS="-g -O0"],[CFLAGS="-g -O2 -D_GNU_SOURCE";CXXFLAGS="-g -O2"])
  
 AC_ARG_WITH([syncapi],
  [AS_HELP_STRING([--with-syncapi],[build with support for SyncAPI [default=yes]])],

+ 37 - 5
src/c/src/zookeeper.c

@@ -189,6 +189,7 @@ static __attribute__((unused)) void print_completion_queue(zhandle_t *zh);
 
 static void *SYNCHRONOUS_MARKER = (void*)&SYNCHRONOUS_MARKER;
 static int isValidPath(const char* path, const int flags);
+static int getaddrinfo_errno(int rc);
 
 const void *zoo_get_context(zhandle_t *zh) 
 {
@@ -402,6 +403,24 @@ static void setup_random()
     srandom(seed);
 }
 
+/**
+ * get the errno from the return code 
+ * of get addrinfo. Errno is not set
+ * with the call to getaddrinfo, so thats
+ * why we have to do this.
+ */
+static int getaddrinfo_errno(int rc) { 
+    switch(rc) {
+    case EAI_NONAME:
+    case EAI_NODATA:
+        return ENOENT;
+    case EAI_MEMORY:
+        return ENOMEM;
+    default:
+        return EINVAL;
+    }
+}
+
 /**
  * fill in the addrs array of the zookeeper servers in the zhandle. after filling
  * them in, we will permute them for load balancing.
@@ -430,7 +449,7 @@ int getaddrs(zhandle_t *zh)
     zh->addrs = 0;
     host=strtok_r(hosts, ",", &strtok_last);
     while(host) {
-        char *port_spec = strchr(host, ':');
+        char *port_spec = strrchr(host, ':');
         char *end_port_spec;
         int port;
         if (!port_spec) {
@@ -462,10 +481,23 @@ int getaddrs(zhandle_t *zh)
         while(isspace(*host) && host != strtok_last)
             host++;
 
-        if (getaddrinfo(host, port_spec, &hints, &res0) != 0) {
-            LOG_ERROR(("getaddrinfo: %s\n", strerror(errno)));
-            rc=ZSYSTEMERROR;
-            goto fail;
+        if ((rc = getaddrinfo(host, port_spec, &hints, &res0)) != 0) {
+            //bug in getaddrinfo implementation when it returns
+            //EAI_BADFLAGS or EAI_ADDRFAMILY with AF_UNSPEC and 
+            // ai_flags as AI_ADDRCONFIG
+            if ((hints.ai_flags == AI_ADDRCONFIG) && 
+                ((rc ==EAI_BADFLAGS) || (rc == EAI_ADDRFAMILY))) {
+                //reset ai_flags to null
+                hints.ai_flags = 0;
+                //retry getaddrinfo
+                rc = getaddrinfo(host, port_spec, &hints, &res0);
+            }
+            if (rc != 0) {
+                errno = getaddrinfo_errno(rc);
+                LOG_ERROR(("getaddrinfo: %s\n", strerror(errno)));
+                rc=ZSYSTEMERROR;
+                goto fail;
+            }
         }
 
         for (res = res0; res; res = res->ai_next) {

+ 16 - 1
src/c/tests/TestClient.cc

@@ -180,6 +180,7 @@ class Zookeeper_simpleSystem : public CPPUNIT_NS::TestFixture
     CPPUNIT_TEST(testAsyncWatcherAutoReset);
 #ifdef THREADED
     CPPUNIT_TEST(testNullData);
+    CPPUNIT_TEST(testIPV6);
     CPPUNIT_TEST(testPath);
     CPPUNIT_TEST(testPathValidation);
     CPPUNIT_TEST(testPing);
@@ -215,7 +216,11 @@ class Zookeeper_simpleSystem : public CPPUNIT_NS::TestFixture
     }
     
     zhandle_t *createClient(watchctx_t *ctx) {
-        zhandle_t *zk = zookeeper_init(hostPorts, watcher, 10000, 0, ctx, 0);
+        return createClient(hostPorts, ctx);
+    }
+
+    zhandle_t *createClient(const char *hp, watchctx_t *ctx) {
+        zhandle_t *zk = zookeeper_init(hp, watcher, 10000, 0, ctx, 0);
         ctx->zh = zk;
         sleep(1);
         return zk;
@@ -571,6 +576,16 @@ public:
         CPPUNIT_ASSERT(stat_a.numChildren == 4);
     }
 
+    void testIPV6() {
+        watchctx_t ctx;
+        zhandle_t *zk = createClient("::1:22181", &ctx);
+        CPPUNIT_ASSERT(zk);
+        int rc = 0;
+        rc = zoo_create(zk, "/ipv6", NULL, -1,
+                        &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);
+        CPPUNIT_ASSERT_EQUAL((int) ZOK, rc);
+    }
+
     void testNullData() {
         watchctx_t ctx;
         zhandle_t *zk = createClient(&ctx);

+ 1 - 1
src/c/tests/TestZookeeperInit.cc

@@ -228,7 +228,7 @@ public:
         const string INVALID_HOST("host1:1111+host:123");
         zh=zookeeper_init(INVALID_HOST.c_str(),0,0,0,0,0);
         CPPUNIT_ASSERT(zh==0);
-        CPPUNIT_ASSERT_EQUAL(EINVAL,errno);
+        CPPUNIT_ASSERT_EQUAL(ENOENT,errno);
     }
     void testNonexistentHost()
     {