Merge "base: add network address parsing function from adb."
This commit is contained in:
commit
7fc87c9bc2
|
@ -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 \
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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 New Issue