Loading adb/client/adb_client.cpp +12 −14 Original line number Original line Diff line number Diff line Loading @@ -144,53 +144,51 @@ static int _adb_connect(const std::string& service, std::string* error) { } } std::string reason; std::string reason; int fd = socket_spec_connect(__adb_server_socket_spec, &reason); unique_fd fd; if (fd < 0) { if (!socket_spec_connect(&fd, __adb_server_socket_spec, nullptr, nullptr, &reason)) { *error = android::base::StringPrintf("cannot connect to daemon at %s: %s", *error = android::base::StringPrintf("cannot connect to daemon at %s: %s", __adb_server_socket_spec, reason.c_str()); __adb_server_socket_spec, reason.c_str()); return -2; return -2; } } if (memcmp(&service[0], "host", 4) != 0 && switch_socket_transport(fd, error)) { if (memcmp(&service[0], "host", 4) != 0 && switch_socket_transport(fd.get(), error)) { return -1; return -1; } } if (!SendProtocolString(fd, service)) { if (!SendProtocolString(fd.get(), service)) { *error = perror_str("write failure during connection"); *error = perror_str("write failure during connection"); adb_close(fd); return -1; return -1; } } if (!adb_status(fd, error)) { if (!adb_status(fd.get(), error)) { adb_close(fd); return -1; return -1; } } D("_adb_connect: return fd %d", fd); D("_adb_connect: return fd %d", fd.get()); return fd; return fd.release(); } } bool adb_kill_server() { bool adb_kill_server() { D("adb_kill_server"); D("adb_kill_server"); std::string reason; std::string reason; int fd = socket_spec_connect(__adb_server_socket_spec, &reason); unique_fd fd; if (fd < 0) { if (!socket_spec_connect(&fd, __adb_server_socket_spec, nullptr, nullptr, &reason)) { fprintf(stderr, "cannot connect to daemon at %s: %s\n", __adb_server_socket_spec, fprintf(stderr, "cannot connect to daemon at %s: %s\n", __adb_server_socket_spec, reason.c_str()); reason.c_str()); return true; return true; } } if (!SendProtocolString(fd, "host:kill")) { if (!SendProtocolString(fd.get(), "host:kill")) { fprintf(stderr, "error: write failure during connection: %s\n", strerror(errno)); fprintf(stderr, "error: write failure during connection: %s\n", strerror(errno)); return false; return false; } } // The server might send OKAY, so consume that. // The server might send OKAY, so consume that. char buf[4]; char buf[4]; ReadFdExactly(fd, buf, 4); ReadFdExactly(fd.get(), buf, 4); // Now that no more data is expected, wait for socket orderly shutdown or error, indicating // Now that no more data is expected, wait for socket orderly shutdown or error, indicating // server death. // server death. ReadOrderlyShutdown(fd); ReadOrderlyShutdown(fd.get()); return true; return true; } } Loading adb/services.cpp +4 −5 Original line number Original line Diff line number Diff line Loading @@ -72,24 +72,23 @@ unique_fd create_service_thread(const char* service_name, std::function<void(uni } } int service_to_fd(std::string_view name, atransport* transport) { int service_to_fd(std::string_view name, atransport* transport) { int ret = -1; unique_fd ret; if (is_socket_spec(name)) { if (is_socket_spec(name)) { std::string error; std::string error; ret = socket_spec_connect(name, &error); if (!socket_spec_connect(&ret, name, nullptr, nullptr, &error)) { if (ret < 0) { LOG(ERROR) << "failed to connect to socket '" << name << "': " << error; LOG(ERROR) << "failed to connect to socket '" << name << "': " << error; } } } else { } else { #if !ADB_HOST #if !ADB_HOST ret = daemon_service_to_fd(name, transport).release(); ret = daemon_service_to_fd(name, transport); #endif #endif } } if (ret >= 0) { if (ret >= 0) { close_on_exec(ret); close_on_exec(ret); } } return ret; return ret.release(); } } #if ADB_HOST #if ADB_HOST Loading adb/socket_spec.cpp +27 −22 Original line number Original line Diff line number Diff line Loading @@ -67,7 +67,7 @@ static auto& kLocalSocketTypes = *new std::unordered_map<std::string, LocalSocke }); }); bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* port, bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* port, std::string* error) { std::string* serial, std::string* error) { if (!spec.starts_with("tcp:")) { if (!spec.starts_with("tcp:")) { *error = "specification is not tcp: "; *error = "specification is not tcp: "; *error += spec; *error += spec; Loading @@ -92,7 +92,7 @@ bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* po // FIXME: ParseNetAddress rejects port 0. This currently doesn't hurt, because listening // FIXME: ParseNetAddress rejects port 0. This currently doesn't hurt, because listening // on an address that isn't 'localhost' is unsupported. // on an address that isn't 'localhost' is unsupported. if (!android::base::ParseNetAddress(addr, &hostname_value, &port_value, nullptr, error)) { if (!android::base::ParseNetAddress(addr, &hostname_value, &port_value, serial, error)) { return false; return false; } } Loading Loading @@ -139,63 +139,68 @@ bool is_local_socket_spec(std::string_view spec) { std::string error; std::string error; std::string hostname; std::string hostname; if (!parse_tcp_socket_spec(spec, &hostname, nullptr, &error)) { if (!parse_tcp_socket_spec(spec, &hostname, nullptr, nullptr, &error)) { return false; return false; } } return tcp_host_is_local(hostname); return tcp_host_is_local(hostname); } } int socket_spec_connect(std::string_view spec, std::string* error) { bool socket_spec_connect(unique_fd* fd, std::string_view address, int* port, std::string* serial, if (spec.starts_with("tcp:")) { std::string* error) { if (address.starts_with("tcp:")) { std::string hostname; std::string hostname; int port; int port_value = port ? *port : 0; if (!parse_tcp_socket_spec(spec, &hostname, &port, error)) { if (!parse_tcp_socket_spec(address, &hostname, &port_value, serial, error)) { return -1; return false; } } int result; if (tcp_host_is_local(hostname)) { if (tcp_host_is_local(hostname)) { result = network_loopback_client(port, SOCK_STREAM, error); fd->reset(network_loopback_client(port_value, SOCK_STREAM, error)); } else { } else { #if ADB_HOST #if ADB_HOST result = network_connect(hostname, port, SOCK_STREAM, 0, error); fd->reset(network_connect(hostname, port_value, SOCK_STREAM, 0, error)); #else #else // Disallow arbitrary connections in adbd. // Disallow arbitrary connections in adbd. *error = "adbd does not support arbitrary tcp connections"; *error = "adbd does not support arbitrary tcp connections"; return -1; return false; #endif #endif } } if (result >= 0) { if (fd->get() > 0) { disable_tcp_nagle(result); disable_tcp_nagle(fd->get()); if (port) { *port = port_value; } } return result; return true; } return false; } } for (const auto& it : kLocalSocketTypes) { for (const auto& it : kLocalSocketTypes) { std::string prefix = it.first + ":"; std::string prefix = it.first + ":"; if (spec.starts_with(prefix)) { if (address.starts_with(prefix)) { if (!it.second.available) { if (!it.second.available) { *error = StringPrintf("socket type %s is unavailable on this platform", *error = StringPrintf("socket type %s is unavailable on this platform", it.first.c_str()); it.first.c_str()); return -1; return false; } } return network_local_client(&spec[prefix.length()], it.second.socket_namespace, fd->reset(network_local_client(&address[prefix.length()], it.second.socket_namespace, SOCK_STREAM, error); SOCK_STREAM, error)); return true; } } } } *error = "unknown socket specification: "; *error = "unknown socket specification: "; *error += spec; *error += address; return -1; return false; } } int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_tcp_port) { int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_tcp_port) { if (spec.starts_with("tcp:")) { if (spec.starts_with("tcp:")) { std::string hostname; std::string hostname; int port; int port; if (!parse_tcp_socket_spec(spec, &hostname, &port, error)) { if (!parse_tcp_socket_spec(spec, &hostname, &port, nullptr, error)) { return -1; return -1; } } Loading adb/socket_spec.h +6 −2 Original line number Original line Diff line number Diff line Loading @@ -17,14 +17,18 @@ #pragma once #pragma once #include <string> #include <string> #include <tuple> #include "adb_unique_fd.h" // Returns true if the argument starts with a plausible socket prefix. // Returns true if the argument starts with a plausible socket prefix. bool is_socket_spec(std::string_view spec); bool is_socket_spec(std::string_view spec); bool is_local_socket_spec(std::string_view spec); bool is_local_socket_spec(std::string_view spec); int socket_spec_connect(std::string_view spec, std::string* error); bool socket_spec_connect(unique_fd* fd, std::string_view address, int* port, std::string* serial, std::string* error); int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_tcp_port = nullptr); int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_tcp_port = nullptr); // Exposed for testing. // Exposed for testing. bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* port, bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* port, std::string* error); std::string* serial, std::string* error); adb/socket_spec_test.cpp +19 −16 Original line number Original line Diff line number Diff line Loading @@ -21,34 +21,37 @@ #include <gtest/gtest.h> #include <gtest/gtest.h> TEST(socket_spec, parse_tcp_socket_spec) { TEST(socket_spec, parse_tcp_socket_spec) { std::string hostname, error; std::string hostname, error, serial; int port; int port; EXPECT_TRUE(parse_tcp_socket_spec("tcp:5037", &hostname, &port, &error)); EXPECT_TRUE(parse_tcp_socket_spec("tcp:5037", &hostname, &port, &serial, &error)); EXPECT_EQ("", hostname); EXPECT_EQ("", hostname); EXPECT_EQ(5037, port); EXPECT_EQ(5037, port); EXPECT_EQ("", serial); // Bad ports: // Bad ports: EXPECT_FALSE(parse_tcp_socket_spec("tcp:", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:-1", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:-1", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:65536", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:65536", &hostname, &port, &serial, &error)); EXPECT_TRUE(parse_tcp_socket_spec("tcp:localhost:1234", &hostname, &port, &error)); EXPECT_TRUE(parse_tcp_socket_spec("tcp:localhost:1234", &hostname, &port, &serial, &error)); EXPECT_EQ("localhost", hostname); EXPECT_EQ("localhost", hostname); EXPECT_EQ(1234, port); EXPECT_EQ(1234, port); EXPECT_EQ("localhost:1234", serial); EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:-1", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:-1", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:65536", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:65536", &hostname, &port, &serial, &error)); // IPv6: // IPv6: EXPECT_TRUE(parse_tcp_socket_spec("tcp:[::1]:1234", &hostname, &port, &error)); EXPECT_TRUE(parse_tcp_socket_spec("tcp:[::1]:1234", &hostname, &port, &serial, &error)); EXPECT_EQ("::1", hostname); EXPECT_EQ("::1", hostname); EXPECT_EQ(1234, port); EXPECT_EQ(1234, port); EXPECT_EQ("[::1]:1234", serial); EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:-1", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:-1", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:::1", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:::1", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:::1:1234", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:::1:1234", &hostname, &port, &serial, &error)); } } Loading
adb/client/adb_client.cpp +12 −14 Original line number Original line Diff line number Diff line Loading @@ -144,53 +144,51 @@ static int _adb_connect(const std::string& service, std::string* error) { } } std::string reason; std::string reason; int fd = socket_spec_connect(__adb_server_socket_spec, &reason); unique_fd fd; if (fd < 0) { if (!socket_spec_connect(&fd, __adb_server_socket_spec, nullptr, nullptr, &reason)) { *error = android::base::StringPrintf("cannot connect to daemon at %s: %s", *error = android::base::StringPrintf("cannot connect to daemon at %s: %s", __adb_server_socket_spec, reason.c_str()); __adb_server_socket_spec, reason.c_str()); return -2; return -2; } } if (memcmp(&service[0], "host", 4) != 0 && switch_socket_transport(fd, error)) { if (memcmp(&service[0], "host", 4) != 0 && switch_socket_transport(fd.get(), error)) { return -1; return -1; } } if (!SendProtocolString(fd, service)) { if (!SendProtocolString(fd.get(), service)) { *error = perror_str("write failure during connection"); *error = perror_str("write failure during connection"); adb_close(fd); return -1; return -1; } } if (!adb_status(fd, error)) { if (!adb_status(fd.get(), error)) { adb_close(fd); return -1; return -1; } } D("_adb_connect: return fd %d", fd); D("_adb_connect: return fd %d", fd.get()); return fd; return fd.release(); } } bool adb_kill_server() { bool adb_kill_server() { D("adb_kill_server"); D("adb_kill_server"); std::string reason; std::string reason; int fd = socket_spec_connect(__adb_server_socket_spec, &reason); unique_fd fd; if (fd < 0) { if (!socket_spec_connect(&fd, __adb_server_socket_spec, nullptr, nullptr, &reason)) { fprintf(stderr, "cannot connect to daemon at %s: %s\n", __adb_server_socket_spec, fprintf(stderr, "cannot connect to daemon at %s: %s\n", __adb_server_socket_spec, reason.c_str()); reason.c_str()); return true; return true; } } if (!SendProtocolString(fd, "host:kill")) { if (!SendProtocolString(fd.get(), "host:kill")) { fprintf(stderr, "error: write failure during connection: %s\n", strerror(errno)); fprintf(stderr, "error: write failure during connection: %s\n", strerror(errno)); return false; return false; } } // The server might send OKAY, so consume that. // The server might send OKAY, so consume that. char buf[4]; char buf[4]; ReadFdExactly(fd, buf, 4); ReadFdExactly(fd.get(), buf, 4); // Now that no more data is expected, wait for socket orderly shutdown or error, indicating // Now that no more data is expected, wait for socket orderly shutdown or error, indicating // server death. // server death. ReadOrderlyShutdown(fd); ReadOrderlyShutdown(fd.get()); return true; return true; } } Loading
adb/services.cpp +4 −5 Original line number Original line Diff line number Diff line Loading @@ -72,24 +72,23 @@ unique_fd create_service_thread(const char* service_name, std::function<void(uni } } int service_to_fd(std::string_view name, atransport* transport) { int service_to_fd(std::string_view name, atransport* transport) { int ret = -1; unique_fd ret; if (is_socket_spec(name)) { if (is_socket_spec(name)) { std::string error; std::string error; ret = socket_spec_connect(name, &error); if (!socket_spec_connect(&ret, name, nullptr, nullptr, &error)) { if (ret < 0) { LOG(ERROR) << "failed to connect to socket '" << name << "': " << error; LOG(ERROR) << "failed to connect to socket '" << name << "': " << error; } } } else { } else { #if !ADB_HOST #if !ADB_HOST ret = daemon_service_to_fd(name, transport).release(); ret = daemon_service_to_fd(name, transport); #endif #endif } } if (ret >= 0) { if (ret >= 0) { close_on_exec(ret); close_on_exec(ret); } } return ret; return ret.release(); } } #if ADB_HOST #if ADB_HOST Loading
adb/socket_spec.cpp +27 −22 Original line number Original line Diff line number Diff line Loading @@ -67,7 +67,7 @@ static auto& kLocalSocketTypes = *new std::unordered_map<std::string, LocalSocke }); }); bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* port, bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* port, std::string* error) { std::string* serial, std::string* error) { if (!spec.starts_with("tcp:")) { if (!spec.starts_with("tcp:")) { *error = "specification is not tcp: "; *error = "specification is not tcp: "; *error += spec; *error += spec; Loading @@ -92,7 +92,7 @@ bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* po // FIXME: ParseNetAddress rejects port 0. This currently doesn't hurt, because listening // FIXME: ParseNetAddress rejects port 0. This currently doesn't hurt, because listening // on an address that isn't 'localhost' is unsupported. // on an address that isn't 'localhost' is unsupported. if (!android::base::ParseNetAddress(addr, &hostname_value, &port_value, nullptr, error)) { if (!android::base::ParseNetAddress(addr, &hostname_value, &port_value, serial, error)) { return false; return false; } } Loading Loading @@ -139,63 +139,68 @@ bool is_local_socket_spec(std::string_view spec) { std::string error; std::string error; std::string hostname; std::string hostname; if (!parse_tcp_socket_spec(spec, &hostname, nullptr, &error)) { if (!parse_tcp_socket_spec(spec, &hostname, nullptr, nullptr, &error)) { return false; return false; } } return tcp_host_is_local(hostname); return tcp_host_is_local(hostname); } } int socket_spec_connect(std::string_view spec, std::string* error) { bool socket_spec_connect(unique_fd* fd, std::string_view address, int* port, std::string* serial, if (spec.starts_with("tcp:")) { std::string* error) { if (address.starts_with("tcp:")) { std::string hostname; std::string hostname; int port; int port_value = port ? *port : 0; if (!parse_tcp_socket_spec(spec, &hostname, &port, error)) { if (!parse_tcp_socket_spec(address, &hostname, &port_value, serial, error)) { return -1; return false; } } int result; if (tcp_host_is_local(hostname)) { if (tcp_host_is_local(hostname)) { result = network_loopback_client(port, SOCK_STREAM, error); fd->reset(network_loopback_client(port_value, SOCK_STREAM, error)); } else { } else { #if ADB_HOST #if ADB_HOST result = network_connect(hostname, port, SOCK_STREAM, 0, error); fd->reset(network_connect(hostname, port_value, SOCK_STREAM, 0, error)); #else #else // Disallow arbitrary connections in adbd. // Disallow arbitrary connections in adbd. *error = "adbd does not support arbitrary tcp connections"; *error = "adbd does not support arbitrary tcp connections"; return -1; return false; #endif #endif } } if (result >= 0) { if (fd->get() > 0) { disable_tcp_nagle(result); disable_tcp_nagle(fd->get()); if (port) { *port = port_value; } } return result; return true; } return false; } } for (const auto& it : kLocalSocketTypes) { for (const auto& it : kLocalSocketTypes) { std::string prefix = it.first + ":"; std::string prefix = it.first + ":"; if (spec.starts_with(prefix)) { if (address.starts_with(prefix)) { if (!it.second.available) { if (!it.second.available) { *error = StringPrintf("socket type %s is unavailable on this platform", *error = StringPrintf("socket type %s is unavailable on this platform", it.first.c_str()); it.first.c_str()); return -1; return false; } } return network_local_client(&spec[prefix.length()], it.second.socket_namespace, fd->reset(network_local_client(&address[prefix.length()], it.second.socket_namespace, SOCK_STREAM, error); SOCK_STREAM, error)); return true; } } } } *error = "unknown socket specification: "; *error = "unknown socket specification: "; *error += spec; *error += address; return -1; return false; } } int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_tcp_port) { int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_tcp_port) { if (spec.starts_with("tcp:")) { if (spec.starts_with("tcp:")) { std::string hostname; std::string hostname; int port; int port; if (!parse_tcp_socket_spec(spec, &hostname, &port, error)) { if (!parse_tcp_socket_spec(spec, &hostname, &port, nullptr, error)) { return -1; return -1; } } Loading
adb/socket_spec.h +6 −2 Original line number Original line Diff line number Diff line Loading @@ -17,14 +17,18 @@ #pragma once #pragma once #include <string> #include <string> #include <tuple> #include "adb_unique_fd.h" // Returns true if the argument starts with a plausible socket prefix. // Returns true if the argument starts with a plausible socket prefix. bool is_socket_spec(std::string_view spec); bool is_socket_spec(std::string_view spec); bool is_local_socket_spec(std::string_view spec); bool is_local_socket_spec(std::string_view spec); int socket_spec_connect(std::string_view spec, std::string* error); bool socket_spec_connect(unique_fd* fd, std::string_view address, int* port, std::string* serial, std::string* error); int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_tcp_port = nullptr); int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_tcp_port = nullptr); // Exposed for testing. // Exposed for testing. bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* port, bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* port, std::string* error); std::string* serial, std::string* error);
adb/socket_spec_test.cpp +19 −16 Original line number Original line Diff line number Diff line Loading @@ -21,34 +21,37 @@ #include <gtest/gtest.h> #include <gtest/gtest.h> TEST(socket_spec, parse_tcp_socket_spec) { TEST(socket_spec, parse_tcp_socket_spec) { std::string hostname, error; std::string hostname, error, serial; int port; int port; EXPECT_TRUE(parse_tcp_socket_spec("tcp:5037", &hostname, &port, &error)); EXPECT_TRUE(parse_tcp_socket_spec("tcp:5037", &hostname, &port, &serial, &error)); EXPECT_EQ("", hostname); EXPECT_EQ("", hostname); EXPECT_EQ(5037, port); EXPECT_EQ(5037, port); EXPECT_EQ("", serial); // Bad ports: // Bad ports: EXPECT_FALSE(parse_tcp_socket_spec("tcp:", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:-1", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:-1", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:65536", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:65536", &hostname, &port, &serial, &error)); EXPECT_TRUE(parse_tcp_socket_spec("tcp:localhost:1234", &hostname, &port, &error)); EXPECT_TRUE(parse_tcp_socket_spec("tcp:localhost:1234", &hostname, &port, &serial, &error)); EXPECT_EQ("localhost", hostname); EXPECT_EQ("localhost", hostname); EXPECT_EQ(1234, port); EXPECT_EQ(1234, port); EXPECT_EQ("localhost:1234", serial); EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:-1", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:-1", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:65536", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:65536", &hostname, &port, &serial, &error)); // IPv6: // IPv6: EXPECT_TRUE(parse_tcp_socket_spec("tcp:[::1]:1234", &hostname, &port, &error)); EXPECT_TRUE(parse_tcp_socket_spec("tcp:[::1]:1234", &hostname, &port, &serial, &error)); EXPECT_EQ("::1", hostname); EXPECT_EQ("::1", hostname); EXPECT_EQ(1234, port); EXPECT_EQ(1234, port); EXPECT_EQ("[::1]:1234", serial); EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:-1", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:-1", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:::1", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:::1", &hostname, &port, &serial, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:::1:1234", &hostname, &port, &error)); EXPECT_FALSE(parse_tcp_socket_spec("tcp:::1:1234", &hostname, &port, &serial, &error)); } }