Merge "base: add network address parsing function from adb."
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 484e561..3005652 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -35,6 +35,7 @@
 
 #include <android-base/logging.h>
 #include <android-base/macros.h>
+#include <android-base/parsenetaddress.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 
@@ -1037,7 +1038,7 @@
         std::string host;
         int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
         std::string error;
-        if (!parse_host_and_port(address, &serial, &host, &port, &error)) {
+        if (!android::base::ParseNetAddress(address, &host, &port, &serial, &error)) {
             return SendFail(reply_fd, android::base::StringPrintf("couldn't parse '%s': %s",
                                                                   address.c_str(), error.c_str()));
         }
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index b132118..474d1b4 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -208,59 +208,6 @@
     return line;
 }
 
-bool parse_host_and_port(const std::string& address,
-                         std::string* canonical_address,
-                         std::string* host, int* port,
-                         std::string* error) {
-    host->clear();
-
-    bool ipv6 = true;
-    bool saw_port = false;
-    size_t colons = std::count(address.begin(), address.end(), ':');
-    size_t dots = std::count(address.begin(), address.end(), '.');
-    std::string port_str;
-    if (address[0] == '[') {
-      // [::1]:123
-      if (address.rfind("]:") == std::string::npos) {
-        *error = android::base::StringPrintf("bad IPv6 address '%s'", address.c_str());
-        return false;
-      }
-      *host = address.substr(1, (address.find("]:") - 1));
-      port_str = address.substr(address.rfind("]:") + 2);
-      saw_port = true;
-    } else if (dots == 0 && colons >= 2 && colons <= 7) {
-      // ::1
-      *host = address;
-    } else if (colons <= 1) {
-      // 1.2.3.4 or some.accidental.domain.com
-      ipv6 = false;
-      std::vector<std::string> pieces = android::base::Split(address, ":");
-      *host = pieces[0];
-      if (pieces.size() > 1) {
-        port_str = pieces[1];
-        saw_port = true;
-      }
-    }
-
-    if (host->empty()) {
-      *error = android::base::StringPrintf("no host in '%s'", address.c_str());
-      return false;
-    }
-
-    if (saw_port) {
-      if (sscanf(port_str.c_str(), "%d", port) != 1 || *port <= 0 || *port > 65535) {
-        *error = android::base::StringPrintf("bad port number '%s' in '%s'",
-                                             port_str.c_str(), address.c_str());
-        return false;
-      }
-    }
-
-    *canonical_address = android::base::StringPrintf(ipv6 ? "[%s]:%d" : "%s:%d", host->c_str(), *port);
-    LOG(DEBUG) << "parsed " << address << " as " << *host << " and " << *port
-               << " (" << *canonical_address << ")";
-    return true;
-}
-
 std::string perror_str(const char* msg) {
     return android::base::StringPrintf("%s: %s", msg, strerror(errno));
 }
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 388d7dd..f1149b3 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -35,17 +35,6 @@
 
 std::string dump_hex(const void* ptr, size_t byte_count);
 
-// Parses 'address' into 'host' and 'port'.
-// If no port is given, takes the default from *port.
-// 'canonical_address' then becomes "host:port" or "[host]:port" as appropriate.
-// Note that no real checking is done that 'host' or 'port' is valid; that's
-// left to getaddrinfo(3).
-// Returns false on failure and sets *error to an appropriate message.
-bool parse_host_and_port(const std::string& address,
-                         std::string* canonical_address,
-                         std::string* host, int* port,
-                         std::string* error);
-
 std::string perror_str(const char* msg);
 
 bool set_file_block_mode(int fd, bool block);
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index 4508bca..794dce6 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -111,88 +111,6 @@
   EXPECT_EQ("/system/bin", adb_dirname("/system/bin/sh/"));
 }
 
-TEST(adb_utils, parse_host_and_port) {
-  std::string canonical_address;
-  std::string host;
-  int port;
-  std::string error;
-
-  // Name, default port.
-  port = 123;
-  ASSERT_TRUE(parse_host_and_port("www.google.com", &canonical_address, &host, &port, &error));
-  ASSERT_EQ("www.google.com:123", canonical_address);
-  ASSERT_EQ("www.google.com", host);
-  ASSERT_EQ(123, port);
-
-  // Name, explicit port.
-  ASSERT_TRUE(parse_host_and_port("www.google.com:666", &canonical_address, &host, &port, &error));
-  ASSERT_EQ("www.google.com:666", canonical_address);
-  ASSERT_EQ("www.google.com", host);
-  ASSERT_EQ(666, port);
-
-  // IPv4, default port.
-  port = 123;
-  ASSERT_TRUE(parse_host_and_port("1.2.3.4", &canonical_address, &host, &port, &error));
-  ASSERT_EQ("1.2.3.4:123", canonical_address);
-  ASSERT_EQ("1.2.3.4", host);
-  ASSERT_EQ(123, port);
-
-  // IPv4, explicit port.
-  ASSERT_TRUE(parse_host_and_port("1.2.3.4:666", &canonical_address, &host, &port, &error));
-  ASSERT_EQ("1.2.3.4:666", canonical_address);
-  ASSERT_EQ("1.2.3.4", host);
-  ASSERT_EQ(666, port);
-
-  // Simple IPv6, default port.
-  port = 123;
-  ASSERT_TRUE(parse_host_and_port("::1", &canonical_address, &host, &port, &error));
-  ASSERT_EQ("[::1]:123", canonical_address);
-  ASSERT_EQ("::1", host);
-  ASSERT_EQ(123, port);
-
-  // Simple IPv6, explicit port.
-  ASSERT_TRUE(parse_host_and_port("[::1]:666", &canonical_address, &host, &port, &error));
-  ASSERT_EQ("[::1]:666", canonical_address);
-  ASSERT_EQ("::1", host);
-  ASSERT_EQ(666, port);
-
-  // Hairy IPv6, default port.
-  port = 123;
-  ASSERT_TRUE(parse_host_and_port("fe80::200:5aee:feaa:20a2", &canonical_address, &host, &port, &error));
-  ASSERT_EQ("[fe80::200:5aee:feaa:20a2]:123", canonical_address);
-  ASSERT_EQ("fe80::200:5aee:feaa:20a2", host);
-  ASSERT_EQ(123, port);
-
-  // Simple IPv6, explicit port.
-  ASSERT_TRUE(parse_host_and_port("[fe80::200:5aee:feaa:20a2]:666", &canonical_address, &host, &port, &error));
-  ASSERT_EQ("[fe80::200:5aee:feaa:20a2]:666", canonical_address);
-  ASSERT_EQ("fe80::200:5aee:feaa:20a2", host);
-  ASSERT_EQ(666, port);
-
-  // Invalid IPv4.
-  EXPECT_FALSE(parse_host_and_port("1.2.3.4:", &canonical_address, &host, &port, &error));
-  EXPECT_FALSE(parse_host_and_port("1.2.3.4::", &canonical_address, &host, &port, &error));
-  EXPECT_FALSE(parse_host_and_port("1.2.3.4:hello", &canonical_address, &host, &port, &error));
-  EXPECT_FALSE(parse_host_and_port(":123", &canonical_address, &host, &port, &error));
-
-  // Invalid IPv6.
-  EXPECT_FALSE(parse_host_and_port(":1", &canonical_address, &host, &port, &error));
-  EXPECT_FALSE(parse_host_and_port("::::::::1", &canonical_address, &host, &port, &error));
-  EXPECT_FALSE(parse_host_and_port("[::1", &canonical_address, &host, &port, &error));
-  EXPECT_FALSE(parse_host_and_port("[::1]", &canonical_address, &host, &port, &error));
-  EXPECT_FALSE(parse_host_and_port("[::1]:", &canonical_address, &host, &port, &error));
-  EXPECT_FALSE(parse_host_and_port("[::1]::", &canonical_address, &host, &port, &error));
-  EXPECT_FALSE(parse_host_and_port("[::1]:hello", &canonical_address, &host, &port, &error));
-
-  // Invalid ports.
-  EXPECT_FALSE(parse_host_and_port("[::1]:-1", &canonical_address, &host, &port, &error));
-  EXPECT_FALSE(parse_host_and_port("[::1]:0", &canonical_address, &host, &port, &error));
-  EXPECT_FALSE(parse_host_and_port("[::1]:65536", &canonical_address, &host, &port, &error));
-  EXPECT_FALSE(parse_host_and_port("1.2.3.4:-1", &canonical_address, &host, &port, &error));
-  EXPECT_FALSE(parse_host_and_port("1.2.3.4:0", &canonical_address, &host, &port, &error));
-  EXPECT_FALSE(parse_host_and_port("1.2.3.4:65536", &canonical_address, &host, &port, &error));
-}
-
 void test_mkdirs(const std::string basepath) {
   EXPECT_TRUE(mkdirs(basepath));
   EXPECT_NE(-1, adb_creat(basepath.c_str(), 0600));
diff --git a/adb/services.cpp b/adb/services.cpp
index cd33e7b..9cbf787 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -32,6 +32,7 @@
 #endif
 
 #include <android-base/file.h>
+#include <android-base/parsenetaddress.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <cutils/sockets.h>
@@ -396,7 +397,7 @@
     std::string serial;
     std::string host;
     int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
-    if (!parse_host_and_port(address, &serial, &host, &port, response)) {
+    if (!android::base::ParseNetAddress(address, &host, &port, &serial, response)) {
         return;
     }
 
diff --git a/base/Android.mk b/base/Android.mk
index cba70d4..18f8686 100644
--- a/base/Android.mk
+++ b/base/Android.mk
@@ -19,6 +19,7 @@
 libbase_src_files := \
     file.cpp \
     logging.cpp \
+    parsenetaddress.cpp \
     stringprintf.cpp \
     strings.cpp \
     test_utils.cpp \
@@ -30,6 +31,7 @@
     file_test.cpp \
     logging_test.cpp \
     parseint_test.cpp \
+    parsenetaddress_test.cpp \
     stringprintf_test.cpp \
     strings_test.cpp \
     test_main.cpp \
diff --git a/base/include/android-base/parsenetaddress.h b/base/include/android-base/parsenetaddress.h
new file mode 100644
index 0000000..2de5ac9
--- /dev/null
+++ b/base/include/android-base/parsenetaddress.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BASE_PARSENETADDRESS_H
+#define BASE_PARSENETADDRESS_H
+
+#include <string>
+
+namespace android {
+namespace base {
+
+// Parses |address| into |host| and |port|.
+//
+// If |address| doesn't contain a port number, the default value is taken from
+// |port|. If |canonical_address| is non-null it will be set to "host:port" or
+// "[host]:port" as appropriate.
+//
+// On failure, returns false and fills |error|.
+bool ParseNetAddress(const std::string& address, std::string* host, int* port,
+                     std::string* canonical_address, std::string* error);
+
+}  // namespace base
+}  // namespace android
+
+#endif  // BASE_PARSENETADDRESS_H
diff --git a/base/parsenetaddress.cpp b/base/parsenetaddress.cpp
new file mode 100644
index 0000000..dd80f6d
--- /dev/null
+++ b/base/parsenetaddress.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "android-base/parsenetaddress.h"
+
+#include <algorithm>
+
+#include "android-base/stringprintf.h"
+#include "android-base/strings.h"
+
+namespace android {
+namespace base {
+
+bool ParseNetAddress(const std::string& address, std::string* host, int* port,
+                     std::string* canonical_address, std::string* error) {
+  host->clear();
+
+  bool ipv6 = true;
+  bool saw_port = false;
+  size_t colons = std::count(address.begin(), address.end(), ':');
+  size_t dots = std::count(address.begin(), address.end(), '.');
+  std::string port_str;
+  if (address[0] == '[') {
+    // [::1]:123
+    if (address.rfind("]:") == std::string::npos) {
+      *error = StringPrintf("bad IPv6 address '%s'", address.c_str());
+      return false;
+    }
+    *host = address.substr(1, (address.find("]:") - 1));
+    port_str = address.substr(address.rfind("]:") + 2);
+    saw_port = true;
+  } else if (dots == 0 && colons >= 2 && colons <= 7) {
+    // ::1
+    *host = address;
+  } else if (colons <= 1) {
+    // 1.2.3.4 or some.accidental.domain.com
+    ipv6 = false;
+    std::vector<std::string> pieces = Split(address, ":");
+    *host = pieces[0];
+    if (pieces.size() > 1) {
+      port_str = pieces[1];
+      saw_port = true;
+    }
+  }
+
+  if (host->empty()) {
+    *error = StringPrintf("no host in '%s'", address.c_str());
+    return false;
+  }
+
+  if (saw_port) {
+    if (sscanf(port_str.c_str(), "%d", port) != 1 || *port <= 0 ||
+        *port > 65535) {
+      *error = StringPrintf("bad port number '%s' in '%s'", port_str.c_str(),
+                            address.c_str());
+      return false;
+    }
+  }
+
+  if (canonical_address != nullptr) {
+    *canonical_address =
+        StringPrintf(ipv6 ? "[%s]:%d" : "%s:%d", host->c_str(), *port);
+  }
+
+  return true;
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/base/parsenetaddress_test.cpp b/base/parsenetaddress_test.cpp
new file mode 100644
index 0000000..a3bfac8
--- /dev/null
+++ b/base/parsenetaddress_test.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "android-base/parsenetaddress.h"
+
+#include <gtest/gtest.h>
+
+using android::base::ParseNetAddress;
+
+TEST(ParseNetAddressTest, TestUrl) {
+  std::string canonical, host, error;
+  int port = 123;
+
+  EXPECT_TRUE(
+      ParseNetAddress("www.google.com", &host, &port, &canonical, &error));
+  EXPECT_EQ("www.google.com:123", canonical);
+  EXPECT_EQ("www.google.com", host);
+  EXPECT_EQ(123, port);
+
+  EXPECT_TRUE(
+      ParseNetAddress("www.google.com:666", &host, &port, &canonical, &error));
+  EXPECT_EQ("www.google.com:666", canonical);
+  EXPECT_EQ("www.google.com", host);
+  EXPECT_EQ(666, port);
+}
+
+TEST(ParseNetAddressTest, TestIpv4) {
+  std::string canonical, host, error;
+  int port = 123;
+
+  EXPECT_TRUE(ParseNetAddress("1.2.3.4", &host, &port, &canonical, &error));
+  EXPECT_EQ("1.2.3.4:123", canonical);
+  EXPECT_EQ("1.2.3.4", host);
+  EXPECT_EQ(123, port);
+
+  EXPECT_TRUE(ParseNetAddress("1.2.3.4:666", &host, &port, &canonical, &error));
+  EXPECT_EQ("1.2.3.4:666", canonical);
+  EXPECT_EQ("1.2.3.4", host);
+  EXPECT_EQ(666, port);
+}
+
+TEST(ParseNetAddressTest, TestIpv6) {
+  std::string canonical, host, error;
+  int port = 123;
+
+  EXPECT_TRUE(ParseNetAddress("::1", &host, &port, &canonical, &error));
+  EXPECT_EQ("[::1]:123", canonical);
+  EXPECT_EQ("::1", host);
+  EXPECT_EQ(123, port);
+
+  EXPECT_TRUE(ParseNetAddress("fe80::200:5aee:feaa:20a2", &host, &port,
+                              &canonical, &error));
+  EXPECT_EQ("[fe80::200:5aee:feaa:20a2]:123", canonical);
+  EXPECT_EQ("fe80::200:5aee:feaa:20a2", host);
+  EXPECT_EQ(123, port);
+
+  EXPECT_TRUE(ParseNetAddress("[::1]:666", &host, &port, &canonical, &error));
+  EXPECT_EQ("[::1]:666", canonical);
+  EXPECT_EQ("::1", host);
+  EXPECT_EQ(666, port);
+
+  EXPECT_TRUE(ParseNetAddress("[fe80::200:5aee:feaa:20a2]:666", &host, &port,
+                              &canonical, &error));
+  EXPECT_EQ("[fe80::200:5aee:feaa:20a2]:666", canonical);
+  EXPECT_EQ("fe80::200:5aee:feaa:20a2", host);
+  EXPECT_EQ(666, port);
+}
+
+TEST(ParseNetAddressTest, TestInvalidAddress) {
+  std::string canonical, host;
+  int port;
+
+  std::string failure_cases[] = {
+      // Invalid IPv4.
+      "1.2.3.4:",
+      "1.2.3.4::",
+      ":123",
+
+      // Invalid IPv6.
+      ":1",
+      "::::::::1",
+      "[::1",
+      "[::1]",
+      "[::1]:",
+      "[::1]::",
+
+      // Invalid port.
+      "1.2.3.4:-1",
+      "1.2.3.4:0",
+      "1.2.3.4:65536"
+      "1.2.3.4:hello",
+      "[::1]:-1",
+      "[::1]:0",
+      "[::1]:65536",
+      "[::1]:hello",
+  };
+
+  for (const auto& address : failure_cases) {
+    // Failure should give some non-empty error string.
+    std::string error;
+    EXPECT_FALSE(ParseNetAddress(address, &host, &port, &canonical, &error));
+    EXPECT_NE("", error);
+  }
+}
+
+// Null canonical address argument.
+TEST(ParseNetAddressTest, TestNullCanonicalAddress) {
+  std::string host, error;
+  int port = 42;
+
+  EXPECT_TRUE(ParseNetAddress("www.google.com", &host, &port, nullptr, &error));
+  EXPECT_TRUE(ParseNetAddress("1.2.3.4", &host, &port, nullptr, &error));
+  EXPECT_TRUE(ParseNetAddress("::1", &host, &port, nullptr, &error));
+}