diff --git a/adb/adb.cpp b/adb/adb.cpp index 484e56165..30056528f 100644 --- a/adb/adb.cpp +++ b/adb/adb.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -1037,7 +1038,7 @@ int handle_host_request(const char* service, TransportType type, 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 b132118ac..474d1b403 100644 --- a/adb/adb_utils.cpp +++ b/adb/adb_utils.cpp @@ -208,59 +208,6 @@ std::string dump_hex(const void* data, size_t byte_count) { 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 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 388d7dde3..f1149b3d7 100644 --- a/adb/adb_utils.h +++ b/adb/adb_utils.h @@ -35,17 +35,6 @@ std::string escape_arg(const std::string& s); 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 4508bca2b..794dce63a 100644 --- a/adb/adb_utils_test.cpp +++ b/adb/adb_utils_test.cpp @@ -111,88 +111,6 @@ TEST(adb_utils, adb_dirname) { 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 cd33e7b7d..9cbf78794 100644 --- a/adb/services.cpp +++ b/adb/services.cpp @@ -32,6 +32,7 @@ #endif #include +#include #include #include #include @@ -396,7 +397,7 @@ static void connect_device(const std::string& address, std::string* response) { 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 cba70d4c9..18f86866d 100644 --- a/base/Android.mk +++ b/base/Android.mk @@ -19,6 +19,7 @@ LOCAL_PATH := $(call my-dir) libbase_src_files := \ file.cpp \ logging.cpp \ + parsenetaddress.cpp \ stringprintf.cpp \ strings.cpp \ test_utils.cpp \ @@ -30,6 +31,7 @@ libbase_test_src_files := \ 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 000000000..2de5ac93d --- /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 + +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 000000000..dd80f6da2 --- /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 + +#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 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 000000000..a3bfac860 --- /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 + +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)); +}