diff options
author | Elliott Hughes <enh@google.com> | 2015-07-18 12:21:30 -0700 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2015-07-21 15:25:14 -0700 |
commit | a5268097f605452a362ec0d49f9b3dd9174c1e92 (patch) | |
tree | 2be312cbca0b49375c67d451a2648042d3efa370 | |
parent | ebf3aaf3477c75c6bbc4b2c49542e6fe7a91dce7 (diff) | |
download | adb-a5268097f605452a362ec0d49f9b3dd9174c1e92.tar.gz |
Recognize IPv6 addresses for "adb connect".
Bug: http://b/22559299
Change-Id: I32891d706b5010c38db84a056e76dd279b780f75
-rw-r--r-- | adb.cpp | 37 | ||||
-rw-r--r-- | adb_client.cpp | 3 | ||||
-rw-r--r-- | adb_utils.cpp | 55 | ||||
-rw-r--r-- | adb_utils.h | 11 | ||||
-rw-r--r-- | adb_utils_test.cpp | 82 | ||||
-rw-r--r-- | services.cpp | 33 |
6 files changed, 181 insertions, 40 deletions
@@ -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 diff --git a/adb_client.cpp b/adb_client.cpp index ef9a586..9a1b761 100644 --- a/adb_client.cpp +++ b/adb_client.cpp @@ -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(); diff --git a/adb_utils.cpp b/adb_utils.cpp index 4b97a14..e2af045 100644 --- a/adb_utils.cpp +++ b/adb_utils.cpp @@ -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; +} diff --git a/adb_utils.h b/adb_utils.h index c816d00..e0aa1ba 100644 --- a/adb_utils.h +++ b/adb_utils.h @@ -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 diff --git a/adb_utils_test.cpp b/adb_utils_test.cpp index 052aea5..7aa610a 100644 --- a/adb_utils_test.cpp +++ b/adb_utils_test.cpp @@ -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)); +} diff --git a/services.cpp b/services.cpp index 227f22a..678d57b 100644 --- a/services.cpp +++ b/services.cpp @@ -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; - } + if (!parse_host_and_port(address, &serial, &host, &port, response)) { + 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); + 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 on remote on fd %d\n", fd); + D("client: connected %s remote on fd %d\n", serial.c_str(), fd); close_on_exec(fd); disable_tcp_nagle(fd); |