base: add network address parsing function from adb.
This CL moves the network address parsing function from adb to libbase so that it can be used by fastboot as well as adb. libbase seemed like the right choice because: 1. It already has some parsing functions (parseint) 2. The net address parsing function uses the libbase string functions so we have a libbase dependency anyway. The parsing function has been modified slightly to make the canonical address optional, and debug logging on success has been removed. For adb the only functional difference is that parsing a network address will no longer print the result to the debug log, which seemed unnecessary. Bug: http://b/26236380 Change-Id: Ife6df02937225fc66de87884d3572d79c092c522
This commit is contained in:
parent
bbedd9523f
commit
706955ff0d
9 changed files with 253 additions and 148 deletions
|
@ -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 @@ 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()));
|
||||
}
|
||||
|
|
|
@ -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<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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
38
base/include/android-base/parsenetaddress.h
Normal file
38
base/include/android-base/parsenetaddress.h
Normal file
|
@ -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
|
82
base/parsenetaddress.cpp
Normal file
82
base/parsenetaddress.cpp
Normal file
|
@ -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
|
127
base/parsenetaddress_test.cpp
Normal file
127
base/parsenetaddress_test.cpp
Normal file
|
@ -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));
|
||||
}
|
Loading…
Reference in a new issue