Merge "base: add network address parsing function from adb." am: 7fc87c9bc2
am: cee5418fe4
* commit 'cee5418fe413ce966b20ed4e6f9c6de45629dece':
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));
+}