Recognize IPv6 addresses for "adb connect".
Bug: http://b/22559299 Change-Id: I32891d706b5010c38db84a056e76dd279b780f75
This commit is contained in:
parent
ff2016599d
commit
3d5f60dbba
6 changed files with 183 additions and 42 deletions
37
adb/adb.cpp
37
adb/adb.cpp
|
@ -41,6 +41,7 @@
|
|||
#include "adb_auth.h"
|
||||
#include "adb_io.h"
|
||||
#include "adb_listeners.h"
|
||||
#include "adb_utils.h"
|
||||
#include "transport.h"
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
@ -896,28 +897,28 @@ int handle_host_request(const char* service, TransportType type,
|
|||
|
||||
// remove TCP transport
|
||||
if (!strncmp(service, "disconnect:", 11)) {
|
||||
char buffer[4096];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
const char* serial = service + 11;
|
||||
if (serial[0] == 0) {
|
||||
const std::string address(service + 11);
|
||||
if (address.empty()) {
|
||||
// disconnect from all TCP devices
|
||||
unregister_all_tcp_transports();
|
||||
} else {
|
||||
char hostbuf[100];
|
||||
// assume port 5555 if no port is specified
|
||||
if (!strchr(serial, ':')) {
|
||||
snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial);
|
||||
serial = hostbuf;
|
||||
}
|
||||
atransport* t = find_transport(serial);
|
||||
if (t) {
|
||||
unregister_transport(t);
|
||||
} else {
|
||||
snprintf(buffer, sizeof(buffer), "No such device %s", serial);
|
||||
}
|
||||
return SendOkay(reply_fd, "disconnected everything");
|
||||
}
|
||||
|
||||
return SendOkay(reply_fd, buffer);
|
||||
std::string serial;
|
||||
std::string host;
|
||||
int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
|
||||
std::string error;
|
||||
if (!parse_host_and_port(address, &serial, &host, &port, &error)) {
|
||||
return SendFail(reply_fd, android::base::StringPrintf("couldn't parse '%s': %s",
|
||||
address.c_str(), error.c_str()));
|
||||
}
|
||||
atransport* t = find_transport(serial.c_str());
|
||||
if (t == nullptr) {
|
||||
return SendFail(reply_fd, android::base::StringPrintf("no such device '%s'",
|
||||
serial.c_str()));
|
||||
}
|
||||
unregister_transport(t);
|
||||
return SendOkay(reply_fd, android::base::StringPrintf("disconnected %s", address.c_str()));
|
||||
}
|
||||
|
||||
// returns our value for ADB_SERVER_VERSION
|
||||
|
|
|
@ -277,8 +277,7 @@ bool adb_query(const std::string& service, std::string* result, std::string* err
|
|||
D("adb_query: %s\n", service.c_str());
|
||||
int fd = adb_connect(service, error);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr,"error: %s\n", error->c_str());
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
result->clear();
|
||||
|
|
|
@ -25,7 +25,9 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
#include <base/logging.h>
|
||||
#include <base/stringprintf.h>
|
||||
#include <base/strings.h>
|
||||
|
||||
#include "adb_trace.h"
|
||||
#include "sysdeps.h"
|
||||
|
@ -103,3 +105,56 @@ void dump_hex(const void* data, size_t byte_count) {
|
|||
|
||||
DR("%s\n", line.c_str());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -28,4 +28,15 @@ std::string escape_arg(const std::string& s);
|
|||
|
||||
void 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);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -50,3 +50,85 @@ TEST(adb_utils, escape_arg) {
|
|||
ASSERT_EQ(R"('abc(')", escape_arg("abc("));
|
||||
ASSERT_EQ(R"('abc)')", escape_arg("abc)"));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
|
||||
#include "adb.h"
|
||||
#include "adb_io.h"
|
||||
#include "adb_utils.h"
|
||||
#include "file_sync_service.h"
|
||||
#include "remount_service.h"
|
||||
#include "transport.h"
|
||||
|
@ -541,35 +542,27 @@ static void wait_for_state(int fd, void* cookie)
|
|||
D("wait_for_state is done\n");
|
||||
}
|
||||
|
||||
static void connect_device(const std::string& host, std::string* response) {
|
||||
if (host.empty()) {
|
||||
*response = "empty host name";
|
||||
static void connect_device(const std::string& address, std::string* response) {
|
||||
if (address.empty()) {
|
||||
*response = "empty address";
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> pieces = android::base::Split(host, ":");
|
||||
const std::string& hostname = pieces[0];
|
||||
|
||||
std::string serial;
|
||||
std::string host;
|
||||
int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
|
||||
if (pieces.size() > 1) {
|
||||
if (sscanf(pieces[1].c_str(), "%d", &port) != 1) {
|
||||
*response = android::base::StringPrintf("bad port number %s", pieces[1].c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// This may look like we're putting 'host' back together,
|
||||
// but we're actually inserting the default port if necessary.
|
||||
std::string serial = android::base::StringPrintf("%s:%d", hostname.c_str(), port);
|
||||
|
||||
int fd = socket_network_client_timeout(hostname.c_str(), port, SOCK_STREAM, 10);
|
||||
if (fd < 0) {
|
||||
*response = android::base::StringPrintf("unable to connect to %s:%d",
|
||||
hostname.c_str(), port);
|
||||
if (!parse_host_and_port(address, &serial, &host, &port, response)) {
|
||||
return;
|
||||
}
|
||||
|
||||
D("client: connected on remote on fd %d\n", fd);
|
||||
int fd = socket_network_client_timeout(host.c_str(), port, SOCK_STREAM, 10);
|
||||
if (fd == -1) {
|
||||
*response = android::base::StringPrintf("unable to connect to %s: %s",
|
||||
serial.c_str(), strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
D("client: connected %s remote on fd %d\n", serial.c_str(), fd);
|
||||
close_on_exec(fd);
|
||||
disable_tcp_nagle(fd);
|
||||
|
||||
|
|
Loading…
Reference in a new issue